Skip to content

Commit b19e831

Browse files
committed
Fix additional time boundary overflow cases
1 parent 8acf656 commit b19e831

75 files changed

Lines changed: 2199 additions & 332 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎iotdb-core/calc-commons/src/main/java/org/apache/iotdb/calc/execution/operator/process/fill/filter/FixedIntervalFillFilter.java‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ public FixedIntervalFillFilter(long timeInterval) {
3434
public boolean needFill(long time, long previousTime) {
3535
// the reason that we use Math.abs is that we may use order by time desc which will cause
3636
// previousTime is larger than time
37-
return Math.abs(time - previousTime) <= timeInterval;
37+
return !isTimeDistanceGreaterThan(time, previousTime, timeInterval);
38+
}
39+
40+
private static boolean isTimeDistanceGreaterThan(long left, long right, long distance) {
41+
if (distance < 0) {
42+
return true;
43+
}
44+
long difference = left >= right ? left - right : right - left;
45+
return difference < 0 || difference > distance;
3846
}
3947
}

‎iotdb-core/calc-commons/src/main/java/org/apache/iotdb/calc/execution/operator/process/fill/linear/LinearFill.java‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,8 @@ private boolean fill(
156156
}
157157

158158
private double getFactor(long currentTime) {
159-
return nextTimeInCurrentColumn - previousTime == 0
160-
? 0.0
161-
: ((double) (currentTime - previousTime)) / (nextTimeInCurrentColumn - previousTime);
159+
double timeRange = (double) nextTimeInCurrentColumn - (double) previousTime;
160+
return timeRange == 0 ? 0.0 : ((double) currentTime - (double) previousTime) / timeRange;
162161
}
163162

164163
/**

‎iotdb-core/calc-commons/src/main/java/org/apache/iotdb/calc/execution/operator/process/gapfill/AbstractGapFillOperator.java‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import java.util.List;
3939

4040
import static com.google.common.base.Preconditions.checkArgument;
41+
import static org.apache.iotdb.calc.transformation.dag.column.unary.scalar.DateBinFunctionColumnTransformer.saturatingAdd;
4142

4243
abstract class AbstractGapFillOperator implements ProcessOperator {
4344

@@ -125,7 +126,9 @@ public TsBlock next() throws Exception {
125126
// -1 because we should not include current row, current row will be appended in
126127
// writeCurrentRow
127128
long currentEndTime =
128-
timeColumn.isNull(i) ? endTime : block.getColumn(timeColumnIndex).getLong(i) - 1;
129+
timeColumn.isNull(i)
130+
? endTime
131+
: saturatingAdd(block.getColumn(timeColumnIndex).getLong(i), -1);
129132
fillGaps(block, i, currentEndTime);
130133
writeCurrentRow(block, i);
131134
}
@@ -155,8 +158,12 @@ private void writeCurrentRow(TsBlock block, int rowIndex) {
155158

156159
private void fillGaps(TsBlock block, int rowIndex, long currentEndTime) {
157160
while (currentTime <= currentEndTime) {
161+
long previousTime = currentTime;
158162
gapFillRow(currentTime, block, rowIndex);
159163
nextTime();
164+
if (currentTime <= previousTime) {
165+
break;
166+
}
160167
}
161168
}
162169

‎iotdb-core/calc-commons/src/main/java/org/apache/iotdb/calc/transformation/dag/column/unary/scalar/DateBinFunctionColumnTransformer.java‎

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.apache.tsfile.block.column.ColumnBuilder;
2828
import org.apache.tsfile.read.common.type.Type;
2929

30+
import java.math.BigInteger;
3031
import java.time.Instant;
3132
import java.time.LocalDateTime;
3233
import java.time.ZoneId;
@@ -37,6 +38,8 @@ public class DateBinFunctionColumnTransformer extends UnaryColumnTransformer {
3738

3839
private static final long NANOSECONDS_IN_MILLISECOND = 1_000_000;
3940
private static final long NANOSECONDS_IN_MICROSECOND = 1_000;
41+
private static final BigInteger BIG_LONG_MIN = BigInteger.valueOf(Long.MIN_VALUE);
42+
private static final BigInteger BIG_LONG_MAX = BigInteger.valueOf(Long.MAX_VALUE);
4043

4144
private final int monthDuration;
4245
private final long nonMonthDuration;
@@ -149,12 +152,18 @@ public static long dateBin(
149152
return convertToTimestamp(binStart, zoneId);
150153
}
151154

152-
long diff = source - origin;
153-
long n = diff >= 0 ? diff / nonMonthDuration : (diff - nonMonthDuration + 1) / nonMonthDuration;
154-
return origin + (n * nonMonthDuration);
155+
return saturateToLong(getNonMonthDateBinStart(source, origin, nonMonthDuration));
155156
}
156157

157158
public long[] dateBinStartEnd(long source) {
159+
return dateBinStartEnd(source, false);
160+
}
161+
162+
public long[] dateBinStartEndClosed(long source) {
163+
return dateBinStartEnd(source, true);
164+
}
165+
166+
private long[] dateBinStartEnd(long source, boolean closedEnd) {
158167
// return source if interval is 0
159168
if (monthDuration == 0 && nonMonthDuration == 0) {
160169
return new long[] {source, source};
@@ -180,17 +189,17 @@ public long[] dateBinStartEnd(long source) {
180189
binStart.minusMonths(monthDuration).minusNanos(getNanoTimeStamp(nonMonthDuration));
181190
}
182191

183-
return new long[] {
184-
convertToTimestamp(binStart, zoneId),
185-
convertToTimestamp(binStart.plusMonths(monthDuration), zoneId)
186-
};
192+
long startTime = convertToTimestamp(binStart, zoneId);
193+
long endTime = convertToTimestamp(binStart.plusMonths(monthDuration), zoneId);
194+
return new long[] {startTime, closedEnd ? saturatingAdd(endTime, -1) : endTime};
187195
}
188196

189-
long diff = source - origin;
190-
long n = diff >= 0 ? diff / nonMonthDuration : (diff - nonMonthDuration + 1) / nonMonthDuration;
191-
return new long[] {
192-
origin + (n * nonMonthDuration), origin + (n * nonMonthDuration) + nonMonthDuration
193-
};
197+
BigInteger startTime = getNonMonthDateBinStart(source, origin, nonMonthDuration);
198+
BigInteger endTime = startTime.add(BigInteger.valueOf(nonMonthDuration));
199+
if (closedEnd) {
200+
endTime = endTime.subtract(BigInteger.ONE);
201+
}
202+
return new long[] {saturateToLong(startTime), saturateToLong(endTime)};
194203
}
195204

196205
public static long nextDateBin(int monthDuration, ZoneId zoneId, long currentTime) {
@@ -200,7 +209,33 @@ public static long nextDateBin(int monthDuration, ZoneId zoneId, long currentTim
200209
}
201210

202211
public static long nextDateBin(long nonMonthDuration, long currentTime) {
203-
return currentTime + nonMonthDuration;
212+
return saturatingAdd(currentTime, nonMonthDuration);
213+
}
214+
215+
public static long saturatingAdd(long left, long right) {
216+
return saturateToLong(BigInteger.valueOf(left).add(BigInteger.valueOf(right)));
217+
}
218+
219+
private static BigInteger getNonMonthDateBinStart(
220+
long source, long origin, long nonMonthDuration) {
221+
BigInteger diff = BigInteger.valueOf(source).subtract(BigInteger.valueOf(origin));
222+
BigInteger duration = BigInteger.valueOf(nonMonthDuration);
223+
BigInteger[] quotientAndRemainder = diff.divideAndRemainder(duration);
224+
BigInteger n = quotientAndRemainder[0];
225+
if (diff.signum() < 0 && quotientAndRemainder[1].signum() != 0) {
226+
n = n.subtract(BigInteger.ONE);
227+
}
228+
return BigInteger.valueOf(origin).add(n.multiply(duration));
229+
}
230+
231+
private static long saturateToLong(BigInteger value) {
232+
if (value.compareTo(BIG_LONG_MAX) > 0) {
233+
return Long.MAX_VALUE;
234+
}
235+
if (value.compareTo(BIG_LONG_MIN) < 0) {
236+
return Long.MIN_VALUE;
237+
}
238+
return value.longValue();
204239
}
205240

206241
@Override

‎iotdb-core/datanode/src/main/java/org/apache/iotdb/db/exception/query/QueryTimeoutRuntimeException.java‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,23 @@ public class QueryTimeoutRuntimeException extends IoTDBRuntimeException {
3030

3131
public QueryTimeoutRuntimeException(long startTime, long currentTime, long timeout) {
3232
super(
33-
String.format(QUERY_TIMEOUT_EXCEPTION_MESSAGE, startTime, startTime + timeout, currentTime),
33+
String.format(
34+
QUERY_TIMEOUT_EXCEPTION_MESSAGE,
35+
startTime,
36+
saturatingAdd(startTime, timeout),
37+
currentTime),
3438
QUERY_TIMEOUT.getStatusCode(),
3539
true);
3640
}
41+
42+
private static long saturatingAdd(long left, long right) {
43+
long result = left + right;
44+
if (right > 0 && result < left) {
45+
return Long.MAX_VALUE;
46+
}
47+
if (right < 0 && result > left) {
48+
return Long.MIN_VALUE;
49+
}
50+
return result;
51+
}
3752
}

‎iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/window/processor/TumblingWindowingProcessor.java‎

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
import org.apache.tsfile.utils.Pair;
3333

34+
import java.math.BigInteger;
3435
import java.util.Collections;
3536
import java.util.List;
3637
import java.util.Set;
@@ -80,10 +81,12 @@ public Set<TimeSeriesWindow> mayAddWindow(
8081
? slidingBoundaryTime
8182
: windowList.get(windowList.size() - 1).getTimestamp();
8283

83-
if (timeStamp >= (windowList.isEmpty() ? lastTime : lastTime + slidingInterval)) {
84+
if (windowList.isEmpty()
85+
? timeStamp >= lastTime
86+
: isTimestampAtOrAfterWindowEnd(timeStamp, lastTime, slidingInterval)) {
8487
final TimeSeriesWindow window = new TimeSeriesWindow(this, null);
8588
// Align to the last time + k * slidingInterval, k is a natural number
86-
window.setTimestamp(((timeStamp - lastTime) / slidingInterval) * slidingInterval + lastTime);
89+
window.setTimestamp(alignWindowStart(timeStamp, lastTime, slidingInterval));
8790
windowList.add(window);
8891
return Collections.singleton(window);
8992
}
@@ -96,12 +99,12 @@ public Pair<WindowState, WindowOutput> updateAndMaySetWindowState(
9699
if (timeStamp < window.getTimestamp()) {
97100
return new Pair<>(WindowState.IGNORE_VALUE, null);
98101
}
99-
if (timeStamp >= window.getTimestamp() + slidingInterval) {
102+
if (isTimestampAtOrAfterWindowEnd(timeStamp, window.getTimestamp(), slidingInterval)) {
100103
return new Pair<>(
101104
WindowState.EMIT_AND_PURGE_WITHOUT_COMPUTE,
102105
new WindowOutput()
103106
.setTimestamp(window.getTimestamp())
104-
.setProgressTime(window.getTimestamp() + slidingInterval));
107+
.setProgressTime(saturatingAdd(window.getTimestamp(), slidingInterval)));
105108
}
106109
return new Pair<>(WindowState.COMPUTE, null);
107110
}
@@ -110,6 +113,33 @@ public Pair<WindowState, WindowOutput> updateAndMaySetWindowState(
110113
public WindowOutput forceOutput(final TimeSeriesWindow window) {
111114
return new WindowOutput()
112115
.setTimestamp(window.getTimestamp())
113-
.setProgressTime(window.getTimestamp() + slidingInterval);
116+
.setProgressTime(saturatingAdd(window.getTimestamp(), slidingInterval));
117+
}
118+
119+
private static boolean isTimestampAtOrAfterWindowEnd(
120+
final long timestamp, final long windowStart, final long interval) {
121+
return windowStart <= Long.MAX_VALUE - interval && timestamp >= windowStart + interval;
122+
}
123+
124+
private static long alignWindowStart(
125+
final long timestamp, final long baseTime, final long interval) {
126+
final BigInteger base = BigInteger.valueOf(baseTime);
127+
final BigInteger intervalValue = BigInteger.valueOf(interval);
128+
return base.add(
129+
BigInteger.valueOf(timestamp)
130+
.subtract(base)
131+
.divide(intervalValue)
132+
.multiply(intervalValue))
133+
.longValueExact();
134+
}
135+
136+
private static long saturatingAdd(final long left, final long right) {
137+
if (right > 0 && left > Long.MAX_VALUE - right) {
138+
return Long.MAX_VALUE;
139+
}
140+
if (right < 0 && left < Long.MIN_VALUE - right) {
141+
return Long.MIN_VALUE;
142+
}
143+
return left + right;
114144
}
115145
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.iotdb.db.pipe.processor.downsampling;
21+
22+
public class DownSamplingTimeUtils {
23+
24+
private DownSamplingTimeUtils() {
25+
// Utility class.
26+
}
27+
28+
public static boolean isTimeDistanceLessThanOrEqualTo(long left, long right, long distance) {
29+
if (distance < 0) {
30+
return false;
31+
}
32+
long difference = left >= right ? left - right : right - left;
33+
return difference >= 0 && difference <= distance;
34+
}
35+
36+
public static boolean isTimeDistanceGreaterThanOrEqualTo(long left, long right, long distance) {
37+
if (distance < 0) {
38+
return true;
39+
}
40+
long difference = left >= right ? left - right : right - left;
41+
return difference < 0 || difference >= distance;
42+
}
43+
44+
public static double timeDifferenceAsDouble(long left, long right) {
45+
return (double) left - (double) right;
46+
}
47+
}

‎iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/downsampling/changing/ChangingValueFilter.java‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
import java.time.LocalDate;
2525
import java.util.Objects;
2626

27+
import static org.apache.iotdb.db.pipe.processor.downsampling.DownSamplingTimeUtils.isTimeDistanceGreaterThanOrEqualTo;
28+
import static org.apache.iotdb.db.pipe.processor.downsampling.DownSamplingTimeUtils.isTimeDistanceLessThanOrEqualTo;
29+
2730
public class ChangingValueFilter<T> {
2831

2932
private final ChangingValueSamplingProcessor processor;
@@ -59,13 +62,13 @@ public boolean filter(final long timestamp, final T value) {
5962
}
6063

6164
private boolean tryFilter(final long timestamp, final T value) {
62-
final long timeDiff = Math.abs(timestamp - lastStoredTimestamp);
63-
64-
if (timeDiff <= processor.getCompressionMinTimeInterval()) {
65+
if (isTimeDistanceLessThanOrEqualTo(
66+
timestamp, lastStoredTimestamp, processor.getCompressionMinTimeInterval())) {
6567
return false;
6668
}
6769

68-
if (timeDiff >= processor.getCompressionMaxTimeInterval()) {
70+
if (isTimeDistanceGreaterThanOrEqualTo(
71+
timestamp, lastStoredTimestamp, processor.getCompressionMaxTimeInterval())) {
6972
reset(timestamp, value);
7073
return true;
7174
}

‎iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/downsampling/sdt/SwingingDoorTrendingFilter.java‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
import java.time.LocalDate;
2525
import java.util.Objects;
2626

27+
import static org.apache.iotdb.db.pipe.processor.downsampling.DownSamplingTimeUtils.isTimeDistanceGreaterThanOrEqualTo;
28+
import static org.apache.iotdb.db.pipe.processor.downsampling.DownSamplingTimeUtils.isTimeDistanceLessThanOrEqualTo;
29+
import static org.apache.iotdb.db.pipe.processor.downsampling.DownSamplingTimeUtils.timeDifferenceAsDouble;
30+
2731
public class SwingingDoorTrendingFilter<T> {
2832

2933
private final SwingingDoorTrendingSamplingProcessor processor;
@@ -85,14 +89,13 @@ public boolean filter(final long timestamp, final T value) {
8589
}
8690

8791
private boolean tryFilter(final long timestamp, final T value) {
88-
final long timeDiff = timestamp - lastStoredTimestamp;
89-
final long absTimeDiff = Math.abs(timeDiff);
90-
91-
if (absTimeDiff <= processor.getCompressionMinTimeInterval()) {
92+
if (isTimeDistanceLessThanOrEqualTo(
93+
timestamp, lastStoredTimestamp, processor.getCompressionMinTimeInterval())) {
9294
return false;
9395
}
9496

95-
if (absTimeDiff >= processor.getCompressionMaxTimeInterval()) {
97+
if (isTimeDistanceGreaterThanOrEqualTo(
98+
timestamp, lastStoredTimestamp, processor.getCompressionMaxTimeInterval())) {
9699
reset(timestamp, value);
97100
return true;
98101
}
@@ -114,6 +117,7 @@ private boolean tryFilter(final long timestamp, final T value) {
114117
final double doubleValue = Double.parseDouble(value.toString());
115118
final double lastStoredDoubleValue = Double.parseDouble(lastStoredValue.toString());
116119
final double valueDiff = doubleValue - lastStoredDoubleValue;
120+
final double timeDiff = timeDifferenceAsDouble(timestamp, lastStoredTimestamp);
117121

118122
final double currentUpperSlope = (valueDiff - processor.getCompressionDeviation()) / timeDiff;
119123
if (currentUpperSlope > upperDoor) {

‎iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/downsampling/tumbling/TumblingTimeSamplingProcessor.java‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import static org.apache.iotdb.commons.pipe.config.constant.PipeProcessorConstant.PROCESSOR_DOWN_SAMPLING_SPLIT_FILE_KEY;
4242
import static org.apache.iotdb.commons.pipe.config.constant.PipeProcessorConstant.PROCESSOR_TUMBLING_TIME_INTERVAL_SECONDS_DEFAULT_VALUE;
4343
import static org.apache.iotdb.commons.pipe.config.constant.PipeProcessorConstant.PROCESSOR_TUMBLING_TIME_INTERVAL_SECONDS_KEY;
44+
import static org.apache.iotdb.db.pipe.processor.downsampling.DownSamplingTimeUtils.isTimeDistanceGreaterThanOrEqualTo;
4445

4546
@TreeModel
4647
public class TumblingTimeSamplingProcessor extends DownSamplingProcessor {
@@ -116,7 +117,8 @@ protected void processRow(
116117
final Long lastSampleTime = pathLastObjectCache.getPartialPathLastObject(timeSeriesSuffix);
117118

118119
if (lastSampleTime == null
119-
|| Math.abs(currentRowTime - lastSampleTime) >= intervalInCurrentPrecision) {
120+
|| isTimeDistanceGreaterThanOrEqualTo(
121+
currentRowTime, lastSampleTime, intervalInCurrentPrecision)) {
120122
try {
121123
rowCollector.collectRow(row);
122124

0 commit comments

Comments
 (0)