Implement rounding optimization for fixed offset timezones (#46809)

Fixes #45702 with date_histogram aggregation when using fixed_interval.
Optimization has been implemented for both fixed and calendar intervals
This commit is contained in:
Christos Soulios 2019-09-18 15:56:34 +03:00 committed by GitHub
parent e59be0354a
commit 0076083b35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 27 additions and 9 deletions

View File

@ -219,17 +219,21 @@ public abstract class Rounding implements Writeable {
static class TimeUnitRounding extends Rounding {
static final byte ID = 1;
/** Since, there is no offset of -1 ms, it is safe to use -1 for non-fixed timezones */
static final long TZ_OFFSET_NON_FIXED = -1;
private final DateTimeUnit unit;
private final ZoneId timeZone;
private final boolean unitRoundsToMidnight;
private final boolean isUtcTimeZone;
/** For fixed offset timezones, this is the offset in milliseconds, otherwise TZ_OFFSET_NON_FIXED */
private final long fixedOffsetMillis;
TimeUnitRounding(DateTimeUnit unit, ZoneId timeZone) {
this.unit = unit;
this.timeZone = timeZone;
this.unitRoundsToMidnight = this.unit.field.getBaseUnit().getDuration().toMillis() > 3600000L;
this.isUtcTimeZone = timeZone.normalized().equals(ZoneOffset.UTC);
this.fixedOffsetMillis = timeZone.getRules().isFixedOffset() == true ?
timeZone.getRules().getOffset(Instant.EPOCH).getTotalSeconds() * 1000 : TZ_OFFSET_NON_FIXED;
}
TimeUnitRounding(StreamInput in) throws IOException {
@ -277,11 +281,12 @@ public abstract class Rounding implements Writeable {
@Override
public long round(long utcMillis) {
// this works as long as the offset doesn't change. It is worth getting this case out of the way first, as
// the calculations for fixing things near to offset changes are a little expensive and are unnecessary in the common case
// of working in UTC.
if (isUtcTimeZone) {
return unit.roundFloor(utcMillis);
// This works as long as the tz offset doesn't change. It is worth getting this case out of the way first,
// as the calculations for fixing things near to offset changes are a little expensive and unnecessary
// in the common case of working with fixed offset timezones (such as UTC).
if (fixedOffsetMillis != TZ_OFFSET_NON_FIXED) {
long localMillis = utcMillis + fixedOffsetMillis;
return unit.roundFloor(localMillis) - fixedOffsetMillis;
}
Instant instant = Instant.ofEpochMilli(utcMillis);
@ -437,20 +442,25 @@ public abstract class Rounding implements Writeable {
}
static final byte ID = 2;
/** Since, there is no offset of -1 ms, it is safe to use -1 for non-fixed timezones */
private static final long TZ_OFFSET_NON_FIXED = -1;
private final long interval;
private final ZoneId timeZone;
/** For fixed offset timezones, this is the offset in milliseconds, otherwise TZ_OFFSET_NON_FIXED */
private final long fixedOffsetMillis;
TimeIntervalRounding(long interval, ZoneId timeZone) {
if (interval < 1)
throw new IllegalArgumentException("Zero or negative time interval not supported");
this.interval = interval;
this.timeZone = timeZone;
this.fixedOffsetMillis = timeZone.getRules().isFixedOffset() == true ?
timeZone.getRules().getOffset(Instant.EPOCH).getTotalSeconds() * 1000 : TZ_OFFSET_NON_FIXED;
}
TimeIntervalRounding(StreamInput in) throws IOException {
interval = in.readVLong();
timeZone = DateUtils.of(in.readString());
this(in.readVLong(), DateUtils.of(in.readString()));
}
@Override
@ -460,6 +470,14 @@ public abstract class Rounding implements Writeable {
@Override
public long round(final long utcMillis) {
// This works as long as the tz offset doesn't change. It is worth getting this case out of the way first,
// as the calculations for fixing things near to offset changes are a little expensive and unnecessary
// in the common case of working with fixed offset timezones (such as UTC).
if (fixedOffsetMillis != TZ_OFFSET_NON_FIXED) {
long localMillis = utcMillis + fixedOffsetMillis;
return (roundKey(localMillis, interval) * interval) - fixedOffsetMillis;
}
final Instant utcInstant = Instant.ofEpochMilli(utcMillis);
final LocalDateTime rawLocalDateTime = LocalDateTime.ofInstant(utcInstant, timeZone);