This is an automated email from the ASF dual-hosted git repository. Caideyipi pushed a commit to branch time-partition-boundary-overflow-fix in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 375f1a65a0959d5daca35d721903abc08db64db1 Author: Caideyipi <[email protected]> AuthorDate: Tue Jun 9 19:20:18 2026 +0800 Fix time partition boundary overflow handling --- .../realtime/PipeRealtimeDataRegionSource.java | 4 +- .../queryengine/plan/analyze/AnalyzeVisitor.java | 16 ++-- .../iotdb/db/storageengine/StorageEngine.java | 2 + .../plan/analyze/QueryTimePartitionTest.java | 27 ++++++ .../commons/partition/SeriesPartitionTable.java | 22 ++++- .../iotdb/commons/utils/TimePartitionUtils.java | 101 ++++++++++++--------- .../partition/SeriesPartitionTableTest.java | 22 +++++ .../commons/utils/TimePartitionUtilsTest.java | 89 ++++++++++++++++++ 8 files changed, 229 insertions(+), 54 deletions(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/source/dataregion/realtime/PipeRealtimeDataRegionSource.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/source/dataregion/realtime/PipeRealtimeDataRegionSource.java index b13b2040016..2038766ded2 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/source/dataregion/realtime/PipeRealtimeDataRegionSource.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/source/dataregion/realtime/PipeRealtimeDataRegionSource.java @@ -251,11 +251,11 @@ public abstract class PipeRealtimeDataRegionSource implements PipeExtractor { } startTimePartitionIdLowerBound = - (realtimeDataExtractionStartTime % TimePartitionUtils.getTimePartitionInterval() == 0) + TimePartitionUtils.isTimePartitionStartTime(realtimeDataExtractionStartTime) ? TimePartitionUtils.getTimePartitionId(realtimeDataExtractionStartTime) : TimePartitionUtils.getTimePartitionId(realtimeDataExtractionStartTime) + 1; endTimePartitionIdUpperBound = - (realtimeDataExtractionEndTime % TimePartitionUtils.getTimePartitionInterval() == 0) + TimePartitionUtils.isTimePartitionStartTime(realtimeDataExtractionEndTime) ? TimePartitionUtils.getTimePartitionId(realtimeDataExtractionEndTime) : TimePartitionUtils.getTimePartitionId(realtimeDataExtractionEndTime) - 1; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java index 22d5b0518ac..d62ef26a3bc 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java @@ -2234,11 +2234,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> result.add(timePartitionSlot); // next init timePartitionSlot = new TTimePartitionSlot(endTime); - // beware of overflow - endTime = - endTime + TimePartitionUtils.getTimePartitionInterval() > endTime - ? endTime + TimePartitionUtils.getTimePartitionInterval() - : Long.MAX_VALUE; + endTime = TimePartitionUtils.getTimePartitionUpperBound(endTime); } else { index++; if (index < size) { @@ -2267,8 +2263,14 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext> return; } long size = TimePartitionUtils.getEstimateTimePartitionSize(minTime, maxTime); - context.reserveMemoryForFrontEnd( - RamUsageEstimator.shallowSizeOfInstance(TTimePartitionSlot.class) * size); + context.reserveMemoryForFrontEnd(estimateTimePartitionSlotMemory(size)); + } + + static long estimateTimePartitionSlotMemory(long timePartitionSlotCount) { + long timePartitionSlotSize = RamUsageEstimator.shallowSizeOfInstance(TTimePartitionSlot.class); + return timePartitionSlotCount > Long.MAX_VALUE / timePartitionSlotSize + ? Long.MAX_VALUE + : timePartitionSlotSize * timePartitionSlotCount; } private void analyzeInto( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/StorageEngine.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/StorageEngine.java index db51775281d..17717780307 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/StorageEngine.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/StorageEngine.java @@ -178,6 +178,8 @@ public class StorageEngine implements IService { } private static void initTimePartition() { + TimePartitionUtils.setTimePartitionOrigin( + CommonDescriptor.getInstance().getConfig().getTimePartitionOrigin()); TimePartitionUtils.setTimePartitionInterval( CommonDescriptor.getInstance().getConfig().getTimePartitionInterval()); } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/QueryTimePartitionTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/QueryTimePartitionTest.java index 1e85a1461ee..aa31e0ed376 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/QueryTimePartitionTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/QueryTimePartitionTest.java @@ -20,6 +20,7 @@ package org.apache.iotdb.db.queryengine.plan.analyze; import org.apache.iotdb.common.rpc.thrift.TTimePartitionSlot; import org.apache.iotdb.commons.conf.CommonDescriptor; +import org.apache.iotdb.commons.utils.TimePartitionUtils; import org.apache.iotdb.db.queryengine.common.MPPQueryContext; import org.apache.iotdb.db.queryengine.common.QueryId; @@ -575,4 +576,30 @@ public class QueryTimePartitionTest { assertFalse(res.right.left); assertFalse(res.right.right); } + + @Test + public void testEstimateTimePartitionSlotMemoryWithOverflow() { + assertEquals(Long.MAX_VALUE, AnalyzeVisitor.estimateTimePartitionSlotMemory(Long.MAX_VALUE)); + } + + @Test + public void testTimePartitionSlotListWithUpperOverflowPartition() { + MPPQueryContext context = new MPPQueryContext(new QueryId("test_query")); + long partitionStartTime = TimePartitionUtils.getTimePartitionSlot(Long.MAX_VALUE).startTime; + + Pair<List<TTimePartitionSlot>, Pair<Boolean, Boolean>> res = + getTimePartitionSlotList( + TimeFilterApi.between(partitionStartTime - 1, Long.MAX_VALUE - 1), context); + List<TTimePartitionSlot> expected = + Arrays.asList( + TimePartitionUtils.getTimePartitionSlot(partitionStartTime - 1), + new TTimePartitionSlot(partitionStartTime)); + + assertEquals(expected.size(), res.left.size()); + for (int i = 0; i < expected.size(); i++) { + assertEquals(expected.get(i), res.left.get(i)); + } + assertFalse(res.right.left); + assertFalse(res.right.right); + } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/partition/SeriesPartitionTable.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/partition/SeriesPartitionTable.java index b388121fcd0..28ec68baf8c 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/partition/SeriesPartitionTable.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/partition/SeriesPartitionTable.java @@ -265,8 +265,7 @@ public class SeriesPartitionTable { while (iterator.hasNext()) { Map.Entry<TTimePartitionSlot, List<TConsensusGroupId>> entry = iterator.next(); TTimePartitionSlot timePartitionSlot = entry.getKey(); - if (timePartitionSlot.getStartTime() + timePartitionInterval + TTL - <= currentTimeSlot.getStartTime()) { + if (isTimePartitionExpired(timePartitionSlot, timePartitionInterval, TTL, currentTimeSlot)) { removedTimePartitions.add(timePartitionSlot); iterator.remove(); } @@ -274,6 +273,25 @@ public class SeriesPartitionTable { return removedTimePartitions; } + private static boolean isTimePartitionExpired( + TTimePartitionSlot timePartitionSlot, + long timePartitionInterval, + long TTL, + TTimePartitionSlot currentTimeSlot) { + long partitionEndTime = + saturatingAdd(timePartitionSlot.getStartTime(), timePartitionInterval); + long expireTime = saturatingAdd(partitionEndTime, TTL); + return expireTime <= currentTimeSlot.getStartTime(); + } + + private static long saturatingAdd(long left, long right) { + long result = left + right; + if (((left ^ result) & (right ^ result)) < 0) { + return left < 0 ? Long.MIN_VALUE : Long.MAX_VALUE; + } + return result; + } + public void merge(SeriesPartitionTable sourceMap) { if (sourceMap == null) return; sourceMap.seriesPartitionMap.forEach( diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/TimePartitionUtils.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/TimePartitionUtils.java index 250a347d149..06a28bd0cd0 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/TimePartitionUtils.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/TimePartitionUtils.java @@ -31,44 +31,46 @@ public class TimePartitionUtils { * Time partition origin for dividing database, the time unit is the same with IoTDB's * TimestampPrecision */ - private static long timePartitionOrigin = + private static volatile long timePartitionOrigin = CommonDescriptor.getInstance().getConfig().getTimePartitionOrigin(); /** Time range for dividing database, the time unit is the same with IoTDB's TimestampPrecision */ - private static long timePartitionInterval = + private static volatile long timePartitionInterval = CommonDescriptor.getInstance().getConfig().getTimePartitionInterval(); - private static final BigInteger bigTimePartitionOrigin = BigInteger.valueOf(timePartitionOrigin); - private static final BigInteger bigTimePartitionInterval = - BigInteger.valueOf(timePartitionInterval); - private static final boolean originMayCauseOverflow = (timePartitionOrigin != 0); - private static final long timePartitionLowerBoundWithoutOverflow; - private static final long timePartitionUpperBoundWithoutOverflow; + private static volatile boolean originMayCauseOverflow; + private static volatile long timePartitionLowerBoundWithoutOverflow; + private static volatile long timePartitionUpperBoundWithoutOverflow; static { + updateTimePartitionBound(); + } + + private static void updateTimePartitionBound() { long minPartition = getTimePartitionIdWithoutOverflow(Long.MIN_VALUE); long maxPartition = getTimePartitionIdWithoutOverflow(Long.MAX_VALUE); BigInteger minPartitionStartTime = BigInteger.valueOf(minPartition) - .multiply(bigTimePartitionInterval) - .add(bigTimePartitionOrigin); + .multiply(BigInteger.valueOf(timePartitionInterval)) + .add(BigInteger.valueOf(timePartitionOrigin)); BigInteger maxPartitionEndTime = BigInteger.valueOf(maxPartition) - .multiply(bigTimePartitionInterval) - .add(bigTimePartitionInterval) - .add(bigTimePartitionOrigin); + .multiply(BigInteger.valueOf(timePartitionInterval)) + .add(BigInteger.valueOf(timePartitionInterval)) + .add(BigInteger.valueOf(timePartitionOrigin)); if (minPartitionStartTime.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0) { timePartitionLowerBoundWithoutOverflow = - minPartitionStartTime.add(bigTimePartitionInterval).longValue(); + minPartitionStartTime.add(BigInteger.valueOf(timePartitionInterval)).longValue(); } else { timePartitionLowerBoundWithoutOverflow = minPartitionStartTime.longValue(); } if (maxPartitionEndTime.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) { timePartitionUpperBoundWithoutOverflow = - maxPartitionEndTime.subtract(bigTimePartitionInterval).longValue(); + maxPartitionEndTime.subtract(BigInteger.valueOf(timePartitionInterval)).longValue(); } else { timePartitionUpperBoundWithoutOverflow = maxPartitionEndTime.longValue(); } + originMayCauseOverflow = (timePartitionOrigin != 0); } public static TTimePartitionSlot getTimePartitionSlot(long time) { @@ -86,10 +88,7 @@ public class TimePartitionUtils { return Long.MIN_VALUE; } if (originMayCauseOverflow) { - return BigInteger.valueOf(getTimePartitionIdWithoutOverflow(time)) - .multiply(bigTimePartitionInterval) - .add(bigTimePartitionOrigin) - .longValue(); + return getTimePartitionStartTime(getTimePartitionIdWithoutOverflow(time)); } else { return getTimePartitionId(time) * timePartitionInterval + timePartitionOrigin; } @@ -105,7 +104,14 @@ public class TimePartitionUtils { : lowerBound + timePartitionInterval; } + public static boolean isTimePartitionStartTime(long time) { + return getTimePartitionLowerBound(time) == time; + } + public static long getTimePartitionId(long time) { + if (originMayCauseOverflow) { + return getTimePartitionIdWithoutOverflow(time); + } time -= timePartitionOrigin; return time > 0 || time % timePartitionInterval == 0 ? time / timePartitionInterval @@ -113,7 +119,8 @@ public class TimePartitionUtils { } public static long getTimePartitionIdWithoutOverflow(long time) { - BigInteger bigTime = BigInteger.valueOf(time).subtract(bigTimePartitionOrigin); + BigInteger bigTime = BigInteger.valueOf(time).subtract(BigInteger.valueOf(timePartitionOrigin)); + BigInteger bigTimePartitionInterval = BigInteger.valueOf(timePartitionInterval); BigInteger partitionId = bigTime.compareTo(BigInteger.ZERO) > 0 || bigTime.remainder(bigTimePartitionInterval).equals(BigInteger.ZERO) @@ -123,7 +130,7 @@ public class TimePartitionUtils { } public static long getStartTimeByPartitionId(long partitionId) { - return (partitionId * timePartitionInterval) + timePartitionOrigin; + return getTimePartitionStartTime(partitionId); } public static boolean satisfyPartitionId(long startTime, long endTime, long partitionId) { @@ -142,40 +149,48 @@ public class TimePartitionUtils { if (timeFilter == null) { return true; } - - long partitionEndTime = - partitionStartTime >= timePartitionLowerBoundWithoutOverflow - ? Long.MAX_VALUE - : (partitionStartTime + timePartitionInterval - 1); + long partitionEndTime = getTimePartitionUpperBound(partitionStartTime); + partitionEndTime = partitionEndTime == Long.MAX_VALUE ? Long.MAX_VALUE : partitionEndTime - 1; return timeFilter.satisfyStartEndTime(partitionStartTime, partitionEndTime); } public static boolean satisfyTimePartition(Filter timeFilter, long partitionId) { - long partitionStartTime; - if (originMayCauseOverflow) { - partitionStartTime = - BigInteger.valueOf(partitionId) - .multiply(bigTimePartitionInterval) - .add(bigTimePartitionOrigin) - .longValue(); - } else { - partitionStartTime = partitionId * timePartitionInterval + timePartitionOrigin; + return satisfyPartitionStartTime(timeFilter, getTimePartitionStartTime(partitionId)); + } + + private static long getTimePartitionStartTime(long partitionId) { + BigInteger partitionStartTime = + BigInteger.valueOf(partitionId) + .multiply(BigInteger.valueOf(timePartitionInterval)) + .add(BigInteger.valueOf(timePartitionOrigin)); + if (partitionStartTime.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0) { + return Long.MIN_VALUE; + } + if (partitionStartTime.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) { + return Long.MAX_VALUE; } - return satisfyPartitionStartTime(timeFilter, partitionStartTime); + return partitionStartTime.longValue(); } public static void setTimePartitionInterval(long timePartitionInterval) { TimePartitionUtils.timePartitionInterval = timePartitionInterval; + updateTimePartitionBound(); + } + + public static void setTimePartitionOrigin(long timePartitionOrigin) { + TimePartitionUtils.timePartitionOrigin = timePartitionOrigin; + updateTimePartitionBound(); } public static long getEstimateTimePartitionSize(long startTime, long endTime) { - if (endTime > 0 && startTime < 0) { - return BigInteger.valueOf(endTime) - .subtract(BigInteger.valueOf(startTime)) - .divide(bigTimePartitionInterval) - .longValue() - + 1; + BigInteger estimateSize = + BigInteger.valueOf(endTime) + .subtract(BigInteger.valueOf(startTime)) + .divide(BigInteger.valueOf(timePartitionInterval)) + .add(BigInteger.ONE); + if (estimateSize.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) { + return Long.MAX_VALUE; } - return (endTime - startTime) / timePartitionInterval + 1; + return estimateSize.longValue(); } } diff --git a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/partition/SeriesPartitionTableTest.java b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/partition/SeriesPartitionTableTest.java index ab63deb3c68..4ef40a3b4df 100644 --- a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/partition/SeriesPartitionTableTest.java +++ b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/partition/SeriesPartitionTableTest.java @@ -108,4 +108,26 @@ public class SeriesPartitionTableTest { table1.deserialize(inputStream, protocol); Assert.assertEquals(table0, table1); } + + @Test + public void autoCleanPartitionTableShouldNotExpireOnOverflow() { + TConsensusGroupId consensusGroupId = new TConsensusGroupId(TConsensusGroupType.DataRegion, 0); + + SeriesPartitionTable table = new SeriesPartitionTable(); + TTimePartitionSlot nearMaxSlot = new TTimePartitionSlot(Long.MAX_VALUE - 1); + table.putDataPartition(nearMaxSlot, consensusGroupId); + Assert.assertTrue( + table.autoCleanPartitionTable(0, new TTimePartitionSlot(Long.MAX_VALUE - 1)).isEmpty()); + Assert.assertTrue(table.getSeriesPartitionMap().containsKey(nearMaxSlot)); + + table = new SeriesPartitionTable(); + TTimePartitionSlot normalSlot = new TTimePartitionSlot(0); + table.putDataPartition(normalSlot, consensusGroupId); + Assert.assertTrue( + table + .autoCleanPartitionTable( + Long.MAX_VALUE - 1, new TTimePartitionSlot(Long.MAX_VALUE - 1)) + .isEmpty()); + Assert.assertTrue(table.getSeriesPartitionMap().containsKey(normalSlot)); + } } diff --git a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/TimePartitionUtilsTest.java b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/TimePartitionUtilsTest.java index ea0eeda45d2..f6e37f949c6 100644 --- a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/TimePartitionUtilsTest.java +++ b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/TimePartitionUtilsTest.java @@ -22,6 +22,8 @@ package org.apache.iotdb.commons.utils; import org.apache.iotdb.common.rpc.thrift.TTimePartitionSlot; import org.apache.iotdb.commons.conf.CommonDescriptor; +import org.apache.tsfile.read.filter.factory.TimeFilterApi; +import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -33,12 +35,31 @@ public class TimePartitionUtilsTest { private static final long TEST_TIME_PARTITION_ORIGIN = 1000L; private static final long TEST_TIME_PARTITION_INTERVAL = 3600000L; + private long previousTimePartitionOrigin; + private long previousTimePartitionInterval; + @Before public void setUp() { + previousTimePartitionOrigin = + CommonDescriptor.getInstance().getConfig().getTimePartitionOrigin(); + previousTimePartitionInterval = + CommonDescriptor.getInstance().getConfig().getTimePartitionInterval(); CommonDescriptor.getInstance().getConfig().setTimePartitionOrigin(TEST_TIME_PARTITION_ORIGIN); CommonDescriptor.getInstance() .getConfig() .setTimePartitionInterval(TEST_TIME_PARTITION_INTERVAL); + TimePartitionUtils.setTimePartitionOrigin(TEST_TIME_PARTITION_ORIGIN); + TimePartitionUtils.setTimePartitionInterval(TEST_TIME_PARTITION_INTERVAL); + } + + @After + public void tearDown() { + CommonDescriptor.getInstance().getConfig().setTimePartitionOrigin(previousTimePartitionOrigin); + CommonDescriptor.getInstance() + .getConfig() + .setTimePartitionInterval(previousTimePartitionInterval); + TimePartitionUtils.setTimePartitionOrigin(previousTimePartitionOrigin); + TimePartitionUtils.setTimePartitionInterval(previousTimePartitionInterval); } @Test @@ -105,4 +126,72 @@ public class TimePartitionUtilsTest { long upperBound = TimePartitionUtils.getTimePartitionUpperBound(testTime); assertEquals(Long.MAX_VALUE, upperBound); } + + @Test + public void testIsTimePartitionStartTimeWithOrigin() { + Assert.assertTrue(TimePartitionUtils.isTimePartitionStartTime(TEST_TIME_PARTITION_ORIGIN)); + Assert.assertFalse(TimePartitionUtils.isTimePartitionStartTime(TEST_TIME_PARTITION_ORIGIN + 1)); + Assert.assertTrue( + TimePartitionUtils.isTimePartitionStartTime( + TEST_TIME_PARTITION_ORIGIN + TEST_TIME_PARTITION_INTERVAL)); + } + + @Test + public void testSatisfyPartitionStartTimeWithNormalPartitionEnd() { + Assert.assertFalse( + TimePartitionUtils.satisfyPartitionStartTime( + TimeFilterApi.gtEq(TEST_TIME_PARTITION_ORIGIN + TEST_TIME_PARTITION_INTERVAL), + TEST_TIME_PARTITION_ORIGIN)); + Assert.assertFalse( + TimePartitionUtils.satisfyTimePartition( + TimeFilterApi.gtEq(TEST_TIME_PARTITION_ORIGIN + TEST_TIME_PARTITION_INTERVAL), 0)); + Assert.assertTrue( + TimePartitionUtils.satisfyPartitionStartTime( + TimeFilterApi.gtEq(TEST_TIME_PARTITION_ORIGIN + TEST_TIME_PARTITION_INTERVAL - 1), + TEST_TIME_PARTITION_ORIGIN)); + } + + @Test + public void testSatisfyPartitionStartTimeWithOverflowPartitionEnd() { + long partitionStartTime = TimePartitionUtils.getTimePartitionSlot(Long.MAX_VALUE).startTime; + + Assert.assertTrue( + TimePartitionUtils.satisfyPartitionStartTime( + TimeFilterApi.eq(Long.MAX_VALUE), partitionStartTime)); + } + + @Test + public void testSatisfyTimePartitionWithOverflowPartitionStart() { + long partitionId = TimePartitionUtils.getTimePartitionIdWithoutOverflow(Long.MIN_VALUE); + long nextPartitionStartTime = TimePartitionUtils.getTimePartitionUpperBound(Long.MIN_VALUE); + + Assert.assertTrue( + TimePartitionUtils.satisfyTimePartition(TimeFilterApi.eq(Long.MIN_VALUE), partitionId)); + Assert.assertFalse( + TimePartitionUtils.satisfyTimePartition( + TimeFilterApi.eq(nextPartitionStartTime), partitionId)); + } + + @Test + public void testGetTimePartitionIdWithOverflowOrigin() { + assertEquals( + TimePartitionUtils.getTimePartitionIdWithoutOverflow(Long.MIN_VALUE), + TimePartitionUtils.getTimePartitionId(Long.MIN_VALUE)); + assertEquals( + TimePartitionUtils.getTimePartitionIdWithoutOverflow(Long.MAX_VALUE), + TimePartitionUtils.getTimePartitionId(Long.MAX_VALUE)); + } + + @Test + public void testGetEstimateTimePartitionSizeWithOverflow() { + long previousTimePartitionInterval = TimePartitionUtils.getTimePartitionInterval(); + try { + TimePartitionUtils.setTimePartitionInterval(1); + assertEquals( + Long.MAX_VALUE, + TimePartitionUtils.getEstimateTimePartitionSize(Long.MIN_VALUE, Long.MAX_VALUE)); + } finally { + TimePartitionUtils.setTimePartitionInterval(previousTimePartitionInterval); + } + } }
