diff --git a/processing/src/main/java/org/apache/druid/timeline/partition/OvershadowableManager.java b/processing/src/main/java/org/apache/druid/timeline/partition/OvershadowableManager.java index 8d010cf43b67..86df6987d7b4 100644 --- a/processing/src/main/java/org/apache/druid/timeline/partition/OvershadowableManager.java +++ b/processing/src/main/java/org/apache/druid/timeline/partition/OvershadowableManager.java @@ -39,6 +39,7 @@ import it.unimi.dsi.fastutil.shorts.ShortSortedSets; import org.apache.druid.java.util.common.IAE; import org.apache.druid.java.util.common.ISE; +import org.apache.druid.java.util.common.logger.Logger; import org.apache.druid.timeline.Overshadowable; import javax.annotation.Nullable; @@ -85,6 +86,7 @@ enum State OVERSHADOWED } + private static final Logger log = new Logger(OvershadowableManager.class); private final Map> knownPartitionChunks; // served segments // (start partitionId, end partitionId) -> minorVersion -> atomicUpdateGroup @@ -418,9 +420,11 @@ private Iterator>> stateMap ) { - final RootPartitionRange lowFench = new RootPartitionRange(partitionId, partitionId); + // remediate submap `fromKey > toKey` issue when partitionId overflows + final short partitionIdLowFence = partitionId < 0 ? Short.MAX_VALUE : partitionId; + final RootPartitionRange lowFence = new RootPartitionRange(partitionIdLowFence, partitionIdLowFence); final RootPartitionRange highFence = new RootPartitionRange(Short.MAX_VALUE, Short.MAX_VALUE); - return stateMap.subMap(lowFench, false, highFence, false).entrySet().iterator(); + return stateMap.subMap(lowFence, false, highFence, false).entrySet().iterator(); } /** @@ -1054,6 +1058,13 @@ private static > RootPartitionRange of(AtomicUpdateG private RootPartitionRange(short startPartitionId, short endPartitionId) { + if (startPartitionId < 0 || endPartitionId < 0) { + log.error( + "PartitionId [%s],[%s] possibly out of range of Short.MAX_VALUE, please compact your segements or reduce number of segments in time peroid ", + startPartitionId, + endPartitionId + ); + } this.startPartitionId = startPartitionId; this.endPartitionId = endPartitionId; } diff --git a/processing/src/test/java/org/apache/druid/timeline/partition/OvershadowableManagerTest.java b/processing/src/test/java/org/apache/druid/timeline/partition/OvershadowableManagerTest.java index 92f0fed47b4a..6efc0329332c 100644 --- a/processing/src/test/java/org/apache/druid/timeline/partition/OvershadowableManagerTest.java +++ b/processing/src/test/java/org/apache/druid/timeline/partition/OvershadowableManagerTest.java @@ -165,6 +165,35 @@ public void testFindOvershadowedBy() ); } + @Test + public void testHandleOutOfRangeFindOvershadowedBy() + { + final List> expectedOvershadowedChunks = new ArrayList<>(); + PartitionChunk chunk = newNonRootChunk(32001, 32003, 1, 1); + manager.addChunk(chunk); + expectedOvershadowedChunks.add(chunk); + manager.addChunk(newNonRootChunk(32001, 32005, 2, 1)); + manager.addChunk(newNonRootChunk(32767, 32768, 3, 1)); + manager.addChunk(newNonRootChunk(32768, 32769, 3, 1)); + + List> overshadowedGroups = manager.findOvershadowedBy( + RootPartitionRange.of(32000, 32767), + (short) 4, + State.OVERSHADOWED + ); + Assert.assertEquals( + expectedOvershadowedChunks.stream().map(AtomicUpdateGroup::new).collect(Collectors.toList()), + overshadowedGroups + ); + + overshadowedGroups = manager.findOvershadowedBy( + RootPartitionRange.of(32769, 32769), + (short) 10, + State.VISIBLE + ); + Assert.assertTrue(overshadowedGroups.isEmpty()); + } + @Test public void testFindOvershadows() {