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 d767fdaa53e Use upsert snapshot view in hasNoQueryableDocs to fix 
consistency-mode pruning (#18478)
d767fdaa53e is described below

commit d767fdaa53e02b268e074606a24639d64e2b0d78
Author: Chaitanya Deepthi <[email protected]>
AuthorDate: Fri May 15 12:32:32 2026 -0700

    Use upsert snapshot view in hasNoQueryableDocs to fix consistency-mode 
pruning (#18478)
---
 .../core/query/pruner/SegmentPrunerService.java    |   3 +-
 .../query/pruner/SegmentPrunerServiceTest.java     |  22 ++--
 .../immutable/ImmutableSegmentImpl.java            |  22 ++++
 .../indexsegment/mutable/MutableSegmentImpl.java   |  22 ++++
 .../upsert/BasePartitionUpsertMetadataManager.java |   2 +
 .../upsert/PartitionUpsertMetadataManager.java     |   8 ++
 .../pinot/segment/local/upsert/UpsertUtils.java    |  13 --
 .../segment/local/upsert/UpsertViewManager.java    |   9 ++
 .../segment/local/upsert/UpsertUtilsTest.java      | 144 +++++++++++++++++++++
 .../org/apache/pinot/segment/spi/IndexSegment.java |   4 +
 10 files changed, 224 insertions(+), 25 deletions(-)

diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/query/pruner/SegmentPrunerService.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/query/pruner/SegmentPrunerService.java
index 5707ef698a0..07aa5601e50 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/query/pruner/SegmentPrunerService.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/query/pruner/SegmentPrunerService.java
@@ -28,7 +28,6 @@ import javax.annotation.Nullable;
 import org.apache.pinot.common.utils.config.QueryOptionsUtils;
 import org.apache.pinot.core.query.config.SegmentPrunerConfig;
 import org.apache.pinot.core.query.request.context.QueryContext;
-import org.apache.pinot.segment.local.upsert.UpsertUtils;
 import org.apache.pinot.segment.spi.IndexSegment;
 import org.apache.pinot.spi.trace.InvocationScope;
 import org.apache.pinot.spi.trace.Tracing;
@@ -157,6 +156,6 @@ public class SegmentPrunerService {
       return true;
     }
     // Check if the segment has 0 queryable docIds while skipUpsert=false
-    return !skipUpsert && UpsertUtils.hasNoQueryableDocs(segment);
+    return !skipUpsert && segment.hasNoQueryableDocs();
   }
 }
diff --git 
a/pinot-core/src/test/java/org/apache/pinot/core/query/pruner/SegmentPrunerServiceTest.java
 
b/pinot-core/src/test/java/org/apache/pinot/core/query/pruner/SegmentPrunerServiceTest.java
index 93e382b4765..9fce71e18aa 100644
--- 
a/pinot-core/src/test/java/org/apache/pinot/core/query/pruner/SegmentPrunerServiceTest.java
+++ 
b/pinot-core/src/test/java/org/apache/pinot/core/query/pruner/SegmentPrunerServiceTest.java
@@ -22,14 +22,19 @@ package org.apache.pinot.core.query.pruner;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import org.apache.pinot.core.query.config.SegmentPrunerConfig;
 import org.apache.pinot.core.query.request.context.QueryContext;
 import 
org.apache.pinot.core.query.request.context.utils.QueryContextConverterUtils;
+import 
org.apache.pinot.segment.local.indexsegment.immutable.ImmutableSegmentImpl;
+import org.apache.pinot.segment.local.upsert.PartitionUpsertMetadataManager;
 import org.apache.pinot.segment.spi.IndexSegment;
 import org.apache.pinot.segment.spi.SegmentMetadata;
+import org.apache.pinot.segment.spi.index.metadata.SegmentMetadataImpl;
 import 
org.apache.pinot.segment.spi.index.mutable.ThreadSafeMutableRoaringBitmap;
+import org.apache.pinot.segment.spi.store.SegmentDirectory;
 import org.apache.pinot.spi.env.PinotConfiguration;
 import org.apache.pinot.spi.utils.CommonConstants.Server;
 import org.testng.Assert;
@@ -226,18 +231,15 @@ public class SegmentPrunerServiceTest {
     return indexSegment;
   }
 
-  /**
-   * Segment with upsert-style doc id bitmaps (valid and optional queryable).
-   */
   private IndexSegment mockUpsertIndexSegment(int totalDocs,
       ThreadSafeMutableRoaringBitmap validDocIds, 
ThreadSafeMutableRoaringBitmap queryableDocIds) {
-    IndexSegment indexSegment = mock(IndexSegment.class);
-    when(indexSegment.getColumnNames()).thenReturn(new 
HashSet<>(Arrays.asList("col1")));
-    SegmentMetadata segmentMetadata = mock(SegmentMetadata.class);
+    SegmentMetadataImpl segmentMetadata = mock(SegmentMetadataImpl.class);
     when(segmentMetadata.getTotalDocs()).thenReturn(totalDocs);
-    when(indexSegment.getSegmentMetadata()).thenReturn(segmentMetadata);
-    when(indexSegment.getValidDocIds()).thenReturn(validDocIds);
-    when(indexSegment.getQueryableDocIds()).thenReturn(queryableDocIds);
-    return indexSegment;
+    ImmutableSegmentImpl segment = new ImmutableSegmentImpl(
+        mock(SegmentDirectory.class), segmentMetadata, new HashMap<>(), null);
+    PartitionUpsertMetadataManager manager = 
mock(PartitionUpsertMetadataManager.class);
+    when(manager.getUpsertViewManager()).thenReturn(null);
+    segment.enableUpsert(manager, validDocIds, queryableDocIds);
+    return segment;
   }
 }
diff --git 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/indexsegment/immutable/ImmutableSegmentImpl.java
 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/indexsegment/immutable/ImmutableSegmentImpl.java
index ea746139e90..9436a49ee35 100644
--- 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/indexsegment/immutable/ImmutableSegmentImpl.java
+++ 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/indexsegment/immutable/ImmutableSegmentImpl.java
@@ -40,6 +40,7 @@ import 
org.apache.pinot.segment.local.segment.readers.PinotSegmentRecordReader;
 import 
org.apache.pinot.segment.local.segment.virtualcolumn.VirtualColumnContext;
 import org.apache.pinot.segment.local.startree.v2.store.StarTreeIndexContainer;
 import org.apache.pinot.segment.local.upsert.PartitionUpsertMetadataManager;
+import org.apache.pinot.segment.local.upsert.UpsertViewManager;
 import org.apache.pinot.segment.spi.ColumnMetadata;
 import org.apache.pinot.segment.spi.FetchContext;
 import org.apache.pinot.segment.spi.ImmutableSegment;
@@ -360,6 +361,27 @@ public class ImmutableSegmentImpl implements 
ImmutableSegment {
     return _queryableDocIds;
   }
 
+  @Override
+  public boolean hasNoQueryableDocs() {
+    if (_partitionUpsertMetadataManager == null) {
+      return false;
+    }
+    UpsertViewManager viewManager = 
_partitionUpsertMetadataManager.getUpsertViewManager();
+    if (viewManager != null) {
+      MutableRoaringBitmap queryableDocIdsSnapshot = 
viewManager.getQueryableDocIdsSnapshot(this);
+      if (queryableDocIdsSnapshot != null) {
+        return queryableDocIdsSnapshot.isEmpty();
+      }
+      return false;
+    }
+    ThreadSafeMutableRoaringBitmap queryableDocIds = getQueryableDocIds();
+    if (queryableDocIds != null) {
+      return queryableDocIds.isEmpty();
+    }
+    ThreadSafeMutableRoaringBitmap validDocIds = getValidDocIds();
+    return validDocIds != null && validDocIds.isEmpty();
+  }
+
   @Override
   public GenericRow getRecord(int docId, GenericRow reuse) {
     try (PinotSegmentRecordReader recordReader = new 
PinotSegmentRecordReader()) {
diff --git 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/indexsegment/mutable/MutableSegmentImpl.java
 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/indexsegment/mutable/MutableSegmentImpl.java
index 118d3b9f2bf..edf4909a4bb 100644
--- 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/indexsegment/mutable/MutableSegmentImpl.java
+++ 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/indexsegment/mutable/MutableSegmentImpl.java
@@ -74,6 +74,7 @@ import 
org.apache.pinot.segment.local.upsert.ComparisonColumns;
 import org.apache.pinot.segment.local.upsert.PartitionUpsertMetadataManager;
 import org.apache.pinot.segment.local.upsert.RecordInfo;
 import org.apache.pinot.segment.local.upsert.UpsertContext;
+import org.apache.pinot.segment.local.upsert.UpsertViewManager;
 import org.apache.pinot.segment.local.utils.FixedIntArrayOffHeapIdMap;
 import org.apache.pinot.segment.local.utils.IdMap;
 import org.apache.pinot.segment.local.utils.IngestionUtils;
@@ -1250,6 +1251,27 @@ public class MutableSegmentImpl implements 
MutableSegment {
     return _queryableDocIds;
   }
 
+  @Override
+  public boolean hasNoQueryableDocs() {
+    if (_partitionUpsertMetadataManager == null) {
+      return false;
+    }
+    UpsertViewManager viewManager = 
_partitionUpsertMetadataManager.getUpsertViewManager();
+    if (viewManager != null) {
+      MutableRoaringBitmap queryableDocIdsSnapshot = 
viewManager.getQueryableDocIdsSnapshot(this);
+      if (queryableDocIdsSnapshot != null) {
+        return queryableDocIdsSnapshot.isEmpty();
+      }
+      return false;
+    }
+    ThreadSafeMutableRoaringBitmap queryableDocIds = getQueryableDocIds();
+    if (queryableDocIds != null) {
+      return queryableDocIds.isEmpty();
+    }
+    ThreadSafeMutableRoaringBitmap validDocIds = getValidDocIds();
+    return validDocIds != null && validDocIds.isEmpty();
+  }
+
   @Override
   public GenericRow getRecord(int docId, GenericRow reuse) {
     try (PinotSegmentRecordReader recordReader = new 
PinotSegmentRecordReader()) {
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 1381e4e2ab0..6df010ae0e8 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
@@ -1239,6 +1239,8 @@ public abstract class BasePartitionUpsertMetadataManager 
implements PartitionUps
       throws IOException {
   }
 
+  @Nullable
+  @Override
   public UpsertViewManager getUpsertViewManager() {
     return _upsertViewManager;
   }
diff --git 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/PartitionUpsertMetadataManager.java
 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/PartitionUpsertMetadataManager.java
index 3fca85ea0ef..59f06311e28 100644
--- 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/PartitionUpsertMetadataManager.java
+++ 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/PartitionUpsertMetadataManager.java
@@ -20,6 +20,7 @@ package org.apache.pinot.segment.local.upsert;
 
 import java.io.Closeable;
 import java.util.List;
+import javax.annotation.Nullable;
 import javax.annotation.concurrent.ThreadSafe;
 import org.apache.pinot.segment.local.segment.index.loader.IndexLoadingConfig;
 import org.apache.pinot.segment.spi.ImmutableSegment;
@@ -138,4 +139,11 @@ public interface PartitionUpsertMetadataManager extends 
Closeable {
    * segments can be processed by the server even before they get included in 
the broker's routing table.
    */
   void trackNewlyAddedSegment(String segmentName);
+
+  /**
+   * Returns the upsert view manager that maintains the per-segment 
queryable-doc-id snapshot for consistency-mode
+   * upsert tables, or null when consistency mode is not enabled for this 
partition.
+   */
+  @Nullable
+  UpsertViewManager getUpsertViewManager();
 }
diff --git 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/UpsertUtils.java
 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/UpsertUtils.java
index 990dadb9074..3978044b878 100644
--- 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/UpsertUtils.java
+++ 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/UpsertUtils.java
@@ -57,19 +57,6 @@ public class UpsertUtils {
         : (useEmptyForNull ? new MutableRoaringBitmap() : null);
   }
 
-  /**
-   * Returns whether the segment has no queryable documents, when no delete 
record column we look into validDocIds
-   * for an upsert table
-   */
-  public static boolean hasNoQueryableDocs(IndexSegment segment) {
-    ThreadSafeMutableRoaringBitmap queryableDocIds = 
segment.getQueryableDocIds();
-    if (queryableDocIds != null) {
-      return queryableDocIds.isEmpty();
-    }
-    ThreadSafeMutableRoaringBitmap validDocIds = segment.getValidDocIds();
-    return validDocIds != null && validDocIds.isEmpty();
-  }
-
   public static void doReplaceDocId(ThreadSafeMutableRoaringBitmap validDocIds,
       @Nullable ThreadSafeMutableRoaringBitmap queryableDocIds, int oldDocId, 
int newDocId, RecordInfo recordInfo) {
     validDocIds.replace(oldDocId, newDocId);
diff --git 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/UpsertViewManager.java
 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/UpsertViewManager.java
index 2fb7d706e9d..9b9d52ce2c2 100644
--- 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/UpsertViewManager.java
+++ 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/upsert/UpsertViewManager.java
@@ -26,6 +26,7 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
+import javax.annotation.Nullable;
 import org.apache.pinot.common.utils.config.QueryOptionsUtils;
 import org.apache.pinot.segment.spi.ImmutableSegment;
 import org.apache.pinot.segment.spi.IndexSegment;
@@ -306,6 +307,14 @@ public class UpsertViewManager {
     return _segmentQueryableDocIdsMap;
   }
 
+  // Returns the queryable doc-id snapshot for the given segment from the most 
recent refresh, or
+  // null if no refresh has happened yet or the segment is not in the current 
view.
+  @Nullable
+  public MutableRoaringBitmap getQueryableDocIdsSnapshot(IndexSegment segment) 
{
+    Map<IndexSegment, MutableRoaringBitmap> view = _segmentQueryableDocIdsMap;
+    return view == null ? null : view.get(segment);
+  }
+
   @VisibleForTesting
   Set<IndexSegment> getUpdatedSegmentsSinceLastRefresh() {
     return _updatedSegmentsSinceLastRefresh;
diff --git 
a/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/upsert/UpsertUtilsTest.java
 
b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/upsert/UpsertUtilsTest.java
new file mode 100644
index 00000000000..de88a5b27d3
--- /dev/null
+++ 
b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/upsert/UpsertUtilsTest.java
@@ -0,0 +1,144 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pinot.segment.local.upsert;
+
+import java.util.HashMap;
+import 
org.apache.pinot.segment.local.indexsegment.immutable.ImmutableSegmentImpl;
+import org.apache.pinot.segment.spi.index.metadata.SegmentMetadataImpl;
+import 
org.apache.pinot.segment.spi.index.mutable.ThreadSafeMutableRoaringBitmap;
+import org.apache.pinot.segment.spi.store.SegmentDirectory;
+import org.roaringbitmap.buffer.MutableRoaringBitmap;
+import org.testng.annotations.Test;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+
+public class UpsertUtilsTest {
+
+  /// Non-upsert table: `_partitionUpsertMetadataManager` is never set, so 
`hasNoQueryableDocs`
+  /// short-circuits to `false`.
+  @Test
+  public void testHasNoQueryableDocsNonUpsert() {
+    ImmutableSegmentImpl segment = newSegment();
+    assertFalse(segment.hasNoQueryableDocs());
+  }
+
+  // -------- Non-consistency upsert: fall back to live queryable / valid 
bitmaps. --------
+
+  @Test
+  public void testHasNoQueryableDocsLiveQueryableEmpty() {
+    ImmutableSegmentImpl segment = newSegment();
+    PartitionUpsertMetadataManager manager = 
mock(PartitionUpsertMetadataManager.class);
+    when(manager.getUpsertViewManager()).thenReturn(null);
+    ThreadSafeMutableRoaringBitmap queryable = 
mock(ThreadSafeMutableRoaringBitmap.class);
+    when(queryable.isEmpty()).thenReturn(true);
+    segment.enableUpsert(manager, mock(ThreadSafeMutableRoaringBitmap.class), 
queryable);
+    assertTrue(segment.hasNoQueryableDocs());
+  }
+
+  @Test
+  public void testHasNoQueryableDocsLiveQueryableNonEmpty() {
+    ImmutableSegmentImpl segment = newSegment();
+    PartitionUpsertMetadataManager manager = 
mock(PartitionUpsertMetadataManager.class);
+    when(manager.getUpsertViewManager()).thenReturn(null);
+    ThreadSafeMutableRoaringBitmap queryable = 
mock(ThreadSafeMutableRoaringBitmap.class);
+    when(queryable.isEmpty()).thenReturn(false);
+    segment.enableUpsert(manager, mock(ThreadSafeMutableRoaringBitmap.class), 
queryable);
+    assertFalse(segment.hasNoQueryableDocs());
+  }
+
+  @Test
+  public void 
testHasNoQueryableDocsFallsBackToValidDocIdsWhenQueryableMissing() {
+    ImmutableSegmentImpl segment = newSegment();
+    PartitionUpsertMetadataManager manager = 
mock(PartitionUpsertMetadataManager.class);
+    when(manager.getUpsertViewManager()).thenReturn(null);
+    ThreadSafeMutableRoaringBitmap valid = 
mock(ThreadSafeMutableRoaringBitmap.class);
+    when(valid.isEmpty()).thenReturn(true);
+    segment.enableUpsert(manager, valid, null);
+    assertTrue(segment.hasNoQueryableDocs());
+  }
+
+  @Test
+  public void testHasNoQueryableDocsReturnsFalseWhenBothBitmapsMissing() {
+    ImmutableSegmentImpl segment = newSegment();
+    PartitionUpsertMetadataManager manager = 
mock(PartitionUpsertMetadataManager.class);
+    when(manager.getUpsertViewManager()).thenReturn(null);
+    segment.enableUpsert(manager, null, null);
+    assertFalse(segment.hasNoQueryableDocs());
+  }
+
+  // -------- Consistency-mode upsert: snapshot is the source of truth. 
--------
+
+  @Test
+  public void testHasNoQueryableDocsConsistencyModeSnapshotEmpty() {
+    // Even if the live bitmap has docs, the snapshot's view (empty) is what 
the query will scan.
+    ImmutableSegmentImpl segment = newSegment();
+    PartitionUpsertMetadataManager manager = 
mock(PartitionUpsertMetadataManager.class);
+    UpsertViewManager viewManager = mock(UpsertViewManager.class);
+    when(manager.getUpsertViewManager()).thenReturn(viewManager);
+    when(viewManager.getQueryableDocIdsSnapshot(any())).thenReturn(new 
MutableRoaringBitmap());
+    ThreadSafeMutableRoaringBitmap liveQueryable = 
mock(ThreadSafeMutableRoaringBitmap.class);
+    when(liveQueryable.isEmpty()).thenReturn(false);
+    segment.enableUpsert(manager, mock(ThreadSafeMutableRoaringBitmap.class), 
liveQueryable);
+    assertTrue(segment.hasNoQueryableDocs());
+  }
+
+  @Test
+  public void testHasNoQueryableDocsConsistencyModeSnapshotNonEmpty() {
+    // Even if the live bitmap is empty, the snapshot has docs the query will 
scan.
+    ImmutableSegmentImpl segment = newSegment();
+    PartitionUpsertMetadataManager manager = 
mock(PartitionUpsertMetadataManager.class);
+    UpsertViewManager viewManager = mock(UpsertViewManager.class);
+    MutableRoaringBitmap snapshot = new MutableRoaringBitmap();
+    snapshot.add(0);
+    when(manager.getUpsertViewManager()).thenReturn(viewManager);
+    when(viewManager.getQueryableDocIdsSnapshot(any())).thenReturn(snapshot);
+    ThreadSafeMutableRoaringBitmap liveQueryable = 
mock(ThreadSafeMutableRoaringBitmap.class);
+    when(liveQueryable.isEmpty()).thenReturn(true);
+    segment.enableUpsert(manager, mock(ThreadSafeMutableRoaringBitmap.class), 
liveQueryable);
+    assertFalse(segment.hasNoQueryableDocs());
+  }
+
+  @Test
+  public void testHasNoQueryableDocsConsistencyModeSnapshotAbsent() {
+    // Consistency mode on, but this segment is not in the current refresh 
(first refresh hasn't
+    // run, or the segment was just tracked). Live bitmap might disagree with 
the upcoming
+    // snapshot, so do not claim empty.
+    ImmutableSegmentImpl segment = newSegment();
+    PartitionUpsertMetadataManager manager = 
mock(PartitionUpsertMetadataManager.class);
+    UpsertViewManager viewManager = mock(UpsertViewManager.class);
+    when(manager.getUpsertViewManager()).thenReturn(viewManager);
+    when(viewManager.getQueryableDocIdsSnapshot(any())).thenReturn(null);
+    ThreadSafeMutableRoaringBitmap liveQueryable = 
mock(ThreadSafeMutableRoaringBitmap.class);
+    when(liveQueryable.isEmpty()).thenReturn(true);
+    segment.enableUpsert(manager, mock(ThreadSafeMutableRoaringBitmap.class), 
liveQueryable);
+    assertFalse(segment.hasNoQueryableDocs());
+  }
+
+  /// Returns a minimal {@link ImmutableSegmentImpl} usable for testing the 
upsert-aware methods.
+  /// Mirrors the pattern used in {@code 
BasePartitionUpsertMetadataManagerTest#createImmutableSegment}.
+  private static ImmutableSegmentImpl newSegment() {
+    return new ImmutableSegmentImpl(
+        mock(SegmentDirectory.class), mock(SegmentMetadataImpl.class), new 
HashMap<>(), null);
+  }
+}
diff --git 
a/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/IndexSegment.java
 
b/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/IndexSegment.java
index 2f6e58205b5..a491d79457c 100644
--- 
a/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/IndexSegment.java
+++ 
b/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/IndexSegment.java
@@ -106,6 +106,10 @@ public interface IndexSegment {
   @Nullable
   ThreadSafeMutableRoaringBitmap getQueryableDocIds();
 
+  default boolean hasNoQueryableDocs() {
+    return false;
+  }
+
   /**
    * Returns the record for the given document id. Virtual column values are 
not returned.
    * <p>NOTE: don't use this method for high performance code. Use 
PinotSegmentRecordReader when reading multiple


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

Reply via email to