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:
parent
e59be0354a
commit
0076083b35
|
@ -219,17 +219,21 @@ public abstract class Rounding implements Writeable {
|
||||||
static class TimeUnitRounding extends Rounding {
|
static class TimeUnitRounding extends Rounding {
|
||||||
|
|
||||||
static final byte ID = 1;
|
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 DateTimeUnit unit;
|
||||||
private final ZoneId timeZone;
|
private final ZoneId timeZone;
|
||||||
private final boolean unitRoundsToMidnight;
|
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) {
|
TimeUnitRounding(DateTimeUnit unit, ZoneId timeZone) {
|
||||||
this.unit = unit;
|
this.unit = unit;
|
||||||
this.timeZone = timeZone;
|
this.timeZone = timeZone;
|
||||||
this.unitRoundsToMidnight = this.unit.field.getBaseUnit().getDuration().toMillis() > 3600000L;
|
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 {
|
TimeUnitRounding(StreamInput in) throws IOException {
|
||||||
|
@ -277,11 +281,12 @@ public abstract class Rounding implements Writeable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long round(long utcMillis) {
|
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
|
// This works as long as the tz offset doesn't change. It is worth getting this case out of the way first,
|
||||||
// the calculations for fixing things near to offset changes are a little expensive and are unnecessary in the common case
|
// as the calculations for fixing things near to offset changes are a little expensive and unnecessary
|
||||||
// of working in UTC.
|
// in the common case of working with fixed offset timezones (such as UTC).
|
||||||
if (isUtcTimeZone) {
|
if (fixedOffsetMillis != TZ_OFFSET_NON_FIXED) {
|
||||||
return unit.roundFloor(utcMillis);
|
long localMillis = utcMillis + fixedOffsetMillis;
|
||||||
|
return unit.roundFloor(localMillis) - fixedOffsetMillis;
|
||||||
}
|
}
|
||||||
|
|
||||||
Instant instant = Instant.ofEpochMilli(utcMillis);
|
Instant instant = Instant.ofEpochMilli(utcMillis);
|
||||||
|
@ -437,20 +442,25 @@ public abstract class Rounding implements Writeable {
|
||||||
}
|
}
|
||||||
|
|
||||||
static final byte ID = 2;
|
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 long interval;
|
||||||
private final ZoneId timeZone;
|
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) {
|
TimeIntervalRounding(long interval, ZoneId timeZone) {
|
||||||
if (interval < 1)
|
if (interval < 1)
|
||||||
throw new IllegalArgumentException("Zero or negative time interval not supported");
|
throw new IllegalArgumentException("Zero or negative time interval not supported");
|
||||||
this.interval = interval;
|
this.interval = interval;
|
||||||
this.timeZone = timeZone;
|
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 {
|
TimeIntervalRounding(StreamInput in) throws IOException {
|
||||||
interval = in.readVLong();
|
this(in.readVLong(), DateUtils.of(in.readString()));
|
||||||
timeZone = DateUtils.of(in.readString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -460,6 +470,14 @@ public abstract class Rounding implements Writeable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long round(final long utcMillis) {
|
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 Instant utcInstant = Instant.ofEpochMilli(utcMillis);
|
||||||
final LocalDateTime rawLocalDateTime = LocalDateTime.ofInstant(utcInstant, timeZone);
|
final LocalDateTime rawLocalDateTime = LocalDateTime.ofInstant(utcInstant, timeZone);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue