This is an automated email from the ASF dual-hosted git repository.

Jackie-Jiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new 5771d6acea6 Defer TTL watermark bump until after segment 
add/preload/replace (upsert & dedup) (#19512)
5771d6acea6 is described below

commit 5771d6acea60cd72738116835111cf7c49965373
Author: Chaitanya Deepthi <[email protected]>
AuthorDate: Fri Sep 11 18:16:15 2026 -0700

    Defer TTL watermark bump until after segment add/preload/replace (upsert & 
dedup) (#19512)
---
 .../dedup/BasePartitionDedupMetadataManager.java   | 47 ++++++++++++-------
 ...ConcurrentMapPartitionDedupMetadataManager.java |  5 +-
 .../upsert/BasePartitionUpsertMetadataManager.java | 54 ++++++++++++++--------
 ...oncurrentMapPartitionUpsertMetadataManager.java |  9 ++--
 ...nUpsertMetadataManagerForConsistentDeletes.java | 10 ++--
 ...apPartitionDedupMetadataManagerWithTTLTest.java | 31 +++++++++++++
 ...rrentMapPartitionUpsertMetadataManagerTest.java | 33 +++++++++++++
 7 files changed, 141 insertions(+), 48 deletions(-)

diff --git 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/dedup/BasePartitionDedupMetadataManager.java
 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/dedup/BasePartitionDedupMetadataManager.java
index 693c085d91a..8765758da0b 100644
--- 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/dedup/BasePartitionDedupMetadataManager.java
+++ 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/dedup/BasePartitionDedupMetadataManager.java
@@ -167,16 +167,18 @@ public abstract class BasePartitionDedupMetadataManager 
implements PartitionDedu
       return;
     }
     try {
-      if (skipSegmentOutOfTTL(segment, true)) {
-        return;
-      }
-      try (DedupUtils.DedupRecordInfoReader dedupRecordInfoReader = new 
DedupUtils.DedupRecordInfoReader(segment,
-          _primaryKeyColumns, _dedupTimeColumn)) {
-        Iterator<DedupRecordInfo> dedupRecordInfoIterator =
-            DedupUtils.getDedupRecordInfoIterator(dedupRecordInfoReader, 
segment.getSegmentMetadata().getTotalDocs());
-        doPreloadSegment(segment, dedupRecordInfoIterator);
-        updatePrimaryKeyGauge();
+      // Bump watermark after doPreloadSegment; a concurrent 
removeExpiredPrimaryKeys sweep reading a pre-bumped
+      // watermark could expire keys this preload is about to insert.
+      if (!skipSegmentOutOfTTL(segment)) {
+        try (DedupUtils.DedupRecordInfoReader dedupRecordInfoReader = new 
DedupUtils.DedupRecordInfoReader(segment,
+            _primaryKeyColumns, _dedupTimeColumn)) {
+          Iterator<DedupRecordInfo> dedupRecordInfoIterator =
+              DedupUtils.getDedupRecordInfoIterator(dedupRecordInfoReader, 
segment.getSegmentMetadata().getTotalDocs());
+          doPreloadSegment(segment, dedupRecordInfoIterator);
+          updatePrimaryKeyGauge();
+        }
       }
+      updateLargestSeenTime(segment);
     } catch (Exception e) {
       throw new RuntimeException(
           String.format("Caught exception while preloading segment: %s of 
table: %s in %s", segmentName,
@@ -203,9 +205,11 @@ public abstract class BasePartitionDedupMetadataManager 
implements PartitionDedu
       return;
     }
     try {
-      if (!skipSegmentOutOfTTL(segment, true)) {
+      // Bump watermark after add; see preloadSegment.
+      if (!skipSegmentOutOfTTL(segment)) {
         addOrReplaceSegment(null, segment);
       }
+      updateLargestSeenTime(segment);
     } catch (Exception e) {
       throw new RuntimeException(
           String.format("Caught exception while adding segment: %s of table: 
%s to %s", segmentName, _tableNameWithType,
@@ -223,9 +227,11 @@ public abstract class BasePartitionDedupMetadataManager 
implements PartitionDedu
       return;
     }
     try {
-      if (!skipSegmentOutOfTTL(newSegment, true)) {
+      // Bump watermark after replace; see preloadSegment.
+      if (!skipSegmentOutOfTTL(newSegment)) {
         addOrReplaceSegment(oldSegment, newSegment);
       }
+      updateLargestSeenTime(newSegment);
     } catch (Exception e) {
       throw new RuntimeException(
           String.format("Caught exception while replacing segment: %s with 
segment: %s of table: %s in %s",
@@ -236,16 +242,13 @@ public abstract class BasePartitionDedupMetadataManager 
implements PartitionDedu
     }
   }
 
-  protected boolean skipSegmentOutOfTTL(IndexSegment segment, boolean 
updateWatermark) {
+  protected boolean skipSegmentOutOfTTL(IndexSegment segment) {
     if (_metadataTTL <= 0) {
       return false;
     }
     // If metadataTTL is enabled, we can skip adding dedup metadata for 
segment already out of the TTL. Different
     // from upsert table, there is no need to initialize things like 
validDocIds bitmap for those skipped segments.
     double maxDedupTime = getMaxDedupTime(segment);
-    if (updateWatermark) {
-      _largestSeenTime.getAndUpdate(time -> Math.max(time, maxDedupTime));
-    }
     if (!isOutOfMetadataTTL(maxDedupTime)) {
       return false;
     }
@@ -255,6 +258,18 @@ public abstract class BasePartitionDedupMetadataManager 
implements PartitionDedu
     return true;
   }
 
+  protected void updateLargestSeenTime(IndexSegment segment) {
+    if (_metadataTTL > 0) {
+      updateLargestSeenTime(getMaxDedupTime(segment));
+    }
+  }
+
+  protected void updateLargestSeenTime(double dedupTime) {
+    if (_metadataTTL > 0) {
+      _largestSeenTime.getAndUpdate(time -> Math.max(time, dedupTime));
+    }
+  }
+
   private void addOrReplaceSegment(@Nullable IndexSegment oldSegment, 
IndexSegment newSegment)
       throws IOException {
     try (DedupUtils.DedupRecordInfoReader dedupRecordInfoReader = new 
DedupUtils.DedupRecordInfoReader(newSegment,
@@ -281,7 +296,7 @@ public abstract class BasePartitionDedupMetadataManager 
implements PartitionDedu
       return;
     }
     try {
-      if (skipSegmentOutOfTTL(segment, false)) {
+      if (skipSegmentOutOfTTL(segment)) {
         return;
       }
       try (DedupUtils.DedupRecordInfoReader dedupRecordInfoReader = new 
DedupUtils.DedupRecordInfoReader(segment,
diff --git 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/dedup/ConcurrentMapPartitionDedupMetadataManager.java
 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/dedup/ConcurrentMapPartitionDedupMetadataManager.java
index 5a1c0440bd8..bb18c7320e0 100644
--- 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/dedup/ConcurrentMapPartitionDedupMetadataManager.java
+++ 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/dedup/ConcurrentMapPartitionDedupMetadataManager.java
@@ -116,9 +116,6 @@ class ConcurrentMapPartitionDedupMetadataManager extends 
BasePartitionDedupMetad
       return true;
     }
     try {
-      if (_metadataTTL > 0) {
-        _largestSeenTime.getAndUpdate(time -> Math.max(time, 
dedupRecordInfo.getDedupTime()));
-      }
       AtomicBoolean present = new AtomicBoolean(false);
       
_primaryKeyToSegmentAndTimeMap.compute(HashUtils.hashPrimaryKey(dedupRecordInfo.getPrimaryKey(),
 _hashFunction),
           (primaryKey, segmentAndTime) -> {
@@ -131,6 +128,8 @@ class ConcurrentMapPartitionDedupMetadataManager extends 
BasePartitionDedupMetad
             present.set(true);
             return segmentAndTime;
           });
+      // Bump after the map is updated to avoid racing 
removeExpiredPrimaryKeys.
+      updateLargestSeenTime(dedupRecordInfo.getDedupTime());
       if (!present.get()) {
         updatePrimaryKeyGauge();
       }
diff --git 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/BasePartitionUpsertMetadataManager.java
 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/BasePartitionUpsertMetadataManager.java
index 166ff082500..c6795111a8f 100644
--- 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/BasePartitionUpsertMetadataManager.java
+++ 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/BasePartitionUpsertMetadataManager.java
@@ -316,6 +316,12 @@ public abstract class BasePartitionUpsertMetadataManager 
implements PartitionUps
     return _metadataTTL > 0 || _deletedKeysTTL > 0;
   }
 
+  protected void updateLargestSeenComparisonValue(double comparisonValue) {
+    if (isTTLEnabled()) {
+      _largestSeenComparisonValue.getAndUpdate(v -> Math.max(v, 
comparisonValue));
+    }
+  }
+
   protected double getMaxComparisonValue(IndexSegment segment) {
     return ((Number) 
segment.getSegmentMetadata().getColumnMetadataMap().get(_comparisonColumns.get(0))
         .getMaxValue()).doubleValue();
@@ -364,12 +370,15 @@ public abstract class BasePartitionUpsertMetadataManager 
implements PartitionUps
   protected void doAddSegment(ImmutableSegmentImpl segment) {
     String segmentName = segment.getSegmentName();
     _logger.info("Adding segment: {}, current primary key count: {}", 
segmentName, getNumPrimaryKeys());
-    if (isTTLEnabled()) {
-      double maxComparisonValue = getMaxComparisonValue(segment);
-      _largestSeenComparisonValue.getAndUpdate(v -> Math.max(v, 
maxComparisonValue));
-      if (isOutOfMetadataTTL(maxComparisonValue) && 
skipAddSegmentOutOfTTL(segment)) {
-        return;
-      }
+    // Bump watermark after rows are added, otherwise a concurrent 
removeExpiredPrimaryKeys can expire keys we are
+    // about to insert. Per-partition state transitions are serialized by 
Helix, so concurrent doAddSegment on the
+    // same partition is not possible; the only concurrency here is with the 
sweep. If addSegment throws, the
+    // watermark stays unchanged - the segment's rows are not in the map, so 
recording their max would misrepresent
+    // what we have observed and let the sweep expire other keys against a 
phantom watermark.
+    double maxComparisonValue = isTTLEnabled() ? 
getMaxComparisonValue(segment) : TTL_WATERMARK_NOT_SET;
+    if (isTTLEnabled() && isOutOfMetadataTTL(maxComparisonValue) && 
skipAddSegmentOutOfTTL(segment)) {
+      updateLargestSeenComparisonValue(maxComparisonValue);
+      return;
     }
     long startTimeMs = System.currentTimeMillis();
     if (!_enableSnapshot) {
@@ -381,9 +390,14 @@ public abstract class BasePartitionUpsertMetadataManager 
implements PartitionUps
           UpsertUtils.getRecordInfoIterator(recordInfoReader, 
segment.getSegmentMetadata().getTotalDocs());
       addSegment(segment, null, null, recordInfoIterator);
     } catch (Exception e) {
+      // On failure, do not bump the watermark: the segment's rows are not in 
the map, and bumping would let the
+      // sweep expire other keys against a phantom watermark. Helix retries 
the transition and re-bumps.
       throw new RuntimeException(
           String.format("Caught exception while adding segment: %s, table: 
%s", segmentName, _tableNameWithType), e);
     }
+    if (isTTLEnabled()) {
+      updateLargestSeenComparisonValue(maxComparisonValue);
+    }
 
     // Update metrics
     long numPrimaryKeys = getNumPrimaryKeys();
@@ -442,12 +456,12 @@ public abstract class BasePartitionUpsertMetadataManager 
implements PartitionUps
       segment.enableUpsert(this, new ThreadSafeMutableRoaringBitmap(), 
queryableDocIds);
       return;
     }
-    if (isTTLEnabled()) {
-      double maxComparisonValue = getMaxComparisonValue(segment);
-      _largestSeenComparisonValue.getAndUpdate(v -> Math.max(v, 
maxComparisonValue));
-      if (isOutOfMetadataTTL(maxComparisonValue) && 
skipPreloadSegmentOutOfTTL(segment, validDocIds)) {
-        return;
-      }
+    // Bump watermark after rows are added; see doAddSegment.
+    double maxComparisonValue = isTTLEnabled() ? 
getMaxComparisonValue(segment) : TTL_WATERMARK_NOT_SET;
+    if (isTTLEnabled() && isOutOfMetadataTTL(maxComparisonValue)
+        && skipPreloadSegmentOutOfTTL(segment, validDocIds)) {
+      updateLargestSeenComparisonValue(maxComparisonValue);
+      return;
     }
     try (UpsertUtils.RecordInfoReader recordInfoReader = new 
UpsertUtils.RecordInfoReader(segment, _primaryKeyColumns,
         _comparisonColumns, _deleteRecordColumn)) {
@@ -457,6 +471,9 @@ public abstract class BasePartitionUpsertMetadataManager 
implements PartitionUps
           String.format("Caught exception while preloading segment: %s, table: 
%s", segmentName, _tableNameWithType),
           e);
     }
+    if (isTTLEnabled()) {
+      updateLargestSeenComparisonValue(maxComparisonValue);
+    }
 
     // Update metrics
     long numPrimaryKeys = getNumPrimaryKeys();
@@ -596,12 +613,10 @@ public abstract class BasePartitionUpsertMetadataManager 
implements PartitionUps
       replaceSegment(segment, null, null, null, oldSegment);
       return;
     }
-    if (isTTLEnabled()) {
-      double maxComparisonValue = getMaxComparisonValue(segment);
-      _largestSeenComparisonValue.getAndUpdate(v -> Math.max(v, 
maxComparisonValue));
-      // Segment might be uploaded directly to the table to replace an old 
segment. So update the TTL watermark but
-      // we can't skip segment even if it's out of TTL as its validDocIds 
bitmap is not updated yet.
-    }
+    // Bump watermark after replaceSegment; see doAddSegment. A segment may be 
uploaded directly to the table to
+    // replace an old one; the incoming validDocIds bitmap is not populated 
yet, so we cannot skip even if the
+    // segment is out of TTL.
+    double maxComparisonValue = isTTLEnabled() ? 
getMaxComparisonValue(segment) : TTL_WATERMARK_NOT_SET;
     try (UpsertUtils.RecordInfoReader recordInfoReader = new 
UpsertUtils.RecordInfoReader(segment, _primaryKeyColumns,
         _comparisonColumns, _deleteRecordColumn)) {
       // Reload-only fast path for an upsert + TTL table. The incoming segment 
carries a validDocIds snapshot ONLY when
@@ -633,6 +648,9 @@ public abstract class BasePartitionUpsertMetadataManager 
implements PartitionUps
           String.format("Caught exception while replacing segment: %s, table: 
%s, message: %s", segmentName,
               _tableNameWithType, e.getMessage()), e);
     }
+    if (isTTLEnabled()) {
+      updateLargestSeenComparisonValue(maxComparisonValue);
+    }
 
     // Update metrics
     long numPrimaryKeys = getNumPrimaryKeys();
diff --git 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/ConcurrentMapPartitionUpsertMetadataManager.java
 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/ConcurrentMapPartitionUpsertMetadataManager.java
index 57559b02069..f10ce13eead 100644
--- 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/ConcurrentMapPartitionUpsertMetadataManager.java
+++ 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/ConcurrentMapPartitionUpsertMetadataManager.java
@@ -369,11 +369,6 @@ public class ConcurrentMapPartitionUpsertMetadataManager 
extends BasePartitionUp
     int newDocId = recordInfo.getDocId();
     Comparable newComparisonValue = recordInfo.getComparisonValue();
 
-    // When TTL is enabled, update largestSeenComparisonValue when adding new 
record
-    if (isTTLEnabled()) {
-      double comparisonValue = ((Number) newComparisonValue).doubleValue();
-      _largestSeenComparisonValue.getAndUpdate(v -> Math.max(v, 
comparisonValue));
-    }
     
_primaryKeyToRecordLocationMap.compute(HashUtils.hashPrimaryKey(recordInfo.getPrimaryKey(),
 _hashFunction),
         (primaryKey, currentRecordLocation) -> {
           if (currentRecordLocation != null) {
@@ -409,6 +404,10 @@ public class ConcurrentMapPartitionUpsertMetadataManager 
extends BasePartitionUp
             return new RecordLocation(segment, newDocId, newComparisonValue);
           }
         });
+    // Bump after the record is installed to avoid racing 
removeExpiredPrimaryKeys.
+    if (isTTLEnabled()) {
+      updateLargestSeenComparisonValue(((Number) 
newComparisonValue).doubleValue());
+    }
 
     updatePrimaryKeyGauge();
     return !isOutOfOrderRecord.get();
diff --git 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/ConcurrentMapPartitionUpsertMetadataManagerForConsistentDeletes.java
 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/ConcurrentMapPartitionUpsertMetadataManagerForConsistentDeletes.java
index 32352f7a3b0..c54dac31056 100644
--- 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/ConcurrentMapPartitionUpsertMetadataManagerForConsistentDeletes.java
+++ 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/ConcurrentMapPartitionUpsertMetadataManagerForConsistentDeletes.java
@@ -490,12 +490,6 @@ public class 
ConcurrentMapPartitionUpsertMetadataManagerForConsistentDeletes
     int newDocId = recordInfo.getDocId();
     Comparable newComparisonValue = recordInfo.getComparisonValue();
 
-    // When TTL is enabled, update largestSeenComparisonValue when adding new 
record
-    if (_deletedKeysTTL > 0) {
-      double comparisonValue = ((Number) newComparisonValue).doubleValue();
-      _largestSeenComparisonValue.getAndUpdate(v -> Math.max(v, 
comparisonValue));
-    }
-
     
_primaryKeyToRecordLocationMap.compute(HashUtils.hashPrimaryKey(recordInfo.getPrimaryKey(),
 _hashFunction),
         (primaryKey, currentRecordLocation) -> {
           if (currentRecordLocation != null) {
@@ -540,6 +534,10 @@ public class 
ConcurrentMapPartitionUpsertMetadataManagerForConsistentDeletes
             return new RecordLocation(segment, newDocId, newComparisonValue, 
1);
           }
         });
+    // Bump after the record is installed; see 
ConcurrentMapPartitionUpsertMetadataManager#doAddRecord.
+    if (_deletedKeysTTL > 0) {
+      updateLargestSeenComparisonValue(((Number) 
newComparisonValue).doubleValue());
+    }
 
     updatePrimaryKeyGauge();
     return !isOutOfOrderRecord.get();
diff --git 
a/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/dedup/ConcurrentMapPartitionDedupMetadataManagerWithTTLTest.java
 
b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/dedup/ConcurrentMapPartitionDedupMetadataManagerWithTTLTest.java
index 678d0064af6..3d9ff6ee88e 100644
--- 
a/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/dedup/ConcurrentMapPartitionDedupMetadataManagerWithTTLTest.java
+++ 
b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/dedup/ConcurrentMapPartitionDedupMetadataManagerWithTTLTest.java
@@ -437,6 +437,37 @@ public class 
ConcurrentMapPartitionDedupMetadataManagerWithTTLTest {
     verifyAddSegmentAfterStop(HashFunction.MURMUR3);
   }
 
+  // skipSegmentOutOfTTL must not bump the watermark: caller does that after 
the rows are added, so a concurrent
+  // sweep cannot expire keys the in-flight add is about to insert.
+  @Test
+  public void testSkipSegmentOutOfTTLDoesNotBumpWatermark()
+      throws IOException {
+    _dedupContextBuilder.setHashFunction(HashFunction.NONE);
+    ConcurrentMapPartitionDedupMetadataManager metadataManager =
+        new 
ConcurrentMapPartitionDedupMetadataManager(DedupTestUtils.REALTIME_TABLE_NAME, 
0,
+            _dedupContextBuilder.build());
+
+    metadataManager._largestSeenTime.set(5000);
+
+    IndexSegment segment = DedupTestUtils.mockSegment(1, 10);
+    SegmentMetadataImpl segmentMetadata = mock(SegmentMetadataImpl.class);
+    ColumnMetadata columnMetadata = mock(ColumnMetadata.class);
+    when(segmentMetadata.getColumnMetadataMap()).thenReturn(new TreeMap<>() {{
+        this.put(DEDUP_TIME_COLUMN_NAME, columnMetadata);
+      }});
+    doReturn(10000.0).when(columnMetadata).getMaxValue();
+    when(segment.getSegmentMetadata()).thenReturn(segmentMetadata);
+
+    assertFalse(metadataManager.skipSegmentOutOfTTL(segment));
+    assertEquals(metadataManager._largestSeenTime.get(), 5000.0);
+
+    metadataManager.updateLargestSeenTime(segment);
+    assertEquals(metadataManager._largestSeenTime.get(), 10000.0);
+
+    metadataManager.stop();
+    metadataManager.close();
+  }
+
   private void verifyAddSegmentAfterStop(HashFunction hashFunction) {
     _dedupContextBuilder.setHashFunction(hashFunction);
     ConcurrentMapPartitionDedupMetadataManager metadataManager =
diff --git 
a/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/upsert/ConcurrentMapPartitionUpsertMetadataManagerTest.java
 
b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/upsert/ConcurrentMapPartitionUpsertMetadataManagerTest.java
index a3dcfb12821..06b97a2f1dc 100644
--- 
a/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/upsert/ConcurrentMapPartitionUpsertMetadataManagerTest.java
+++ 
b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/upsert/ConcurrentMapPartitionUpsertMetadataManagerTest.java
@@ -265,6 +265,39 @@ public class 
ConcurrentMapPartitionUpsertMetadataManagerTest {
     upsertMetadataManager.close();
   }
 
+  // Watermark must not advance before addSegment inserts rows, or a 
concurrent sweep can drop the incoming keys.
+  @Test
+  public void testDoAddSegmentBumpsWatermarkAfterRowInsert()
+      throws Exception {
+    _contextBuilder.setEnableSnapshot(true).setMetadataTTL(30);
+    double[] watermarkDuringAdd = {Double.NaN};
+    ConcurrentMapPartitionUpsertMetadataManager upsertMetadataManager =
+        new ConcurrentMapPartitionUpsertMetadataManager(REALTIME_TABLE_NAME, 
0, _contextBuilder.build()) {
+          @Override
+          public void addSegment(ImmutableSegmentImpl segment, @Nullable 
ThreadSafeMutableRoaringBitmap validDocIds,
+              @Nullable ThreadSafeMutableRoaringBitmap queryableDocIds, 
Iterator<RecordInfo> recordInfoIterator) {
+            watermarkDuringAdd[0] = getWatermark();
+            super.addSegment(segment, validDocIds, queryableDocIds, 
recordInfoIterator);
+          }
+        };
+
+    ThreadSafeMutableRoaringBitmap seedValidDocIds = new 
ThreadSafeMutableRoaringBitmap();
+    MutableSegment seedSegment = mockMutableSegment(1, seedValidDocIds, null);
+    upsertMetadataManager.addRecord(seedSegment, new 
RecordInfo(makePrimaryKey(999), 0, 100, false));
+    assertEquals(upsertMetadataManager.getWatermark(), 100.0);
+
+    ThreadSafeMutableRoaringBitmap validDocIds = new 
ThreadSafeMutableRoaringBitmap();
+    ImmutableSegmentImpl segment =
+        createRealSegment("deferred_bump_segment", new int[]{1, 2, 3}, new 
int[]{150, 180, 200}, validDocIds);
+    upsertMetadataManager.addSegment(segment);
+
+    assertEquals(watermarkDuringAdd[0], 100.0);
+    assertEquals(upsertMetadataManager.getWatermark(), 200.0);
+
+    upsertMetadataManager.stop();
+    upsertMetadataManager.close();
+  }
+
   @Test
   public void testManageWatermark()
       throws IOException {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to