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

cwylie pushed a commit to branch 31.0.1
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/31.0.1 by this push:
     new 6c56794ebcc QueryableIndexSegment: Re-use time boundary inspector. 
(#17397) (#17506)
6c56794ebcc is described below

commit 6c56794ebccac0e166ab2b5e16e2d59377e17a3b
Author: Clint Wylie <[email protected]>
AuthorDate: Sat Nov 23 23:07:30 2024 -0800

    QueryableIndexSegment: Re-use time boundary inspector. (#17397) (#17506)
    
    This patch re-uses timeBoundaryInspector for each cursor holder, which
    enables caching of minDataTimestamp and maxDataTimestamp.
    
    Fixes a performance regression introduced in #16533, where these fields
    stopped being cached across cursors. Prior to that patch, they were
    cached in the QueryableIndexStorageAdapter.
    
    Co-authored-by: Gian Merlino <[email protected]>
---
 .../druid/segment/QueryableIndexCursorFactory.java | 24 +++++++--
 .../druid/segment/QueryableIndexCursorHolder.java  | 60 ++++++++++++----------
 .../druid/segment/QueryableIndexSegment.java       |  2 +-
 3 files changed, 55 insertions(+), 31 deletions(-)

diff --git 
a/processing/src/main/java/org/apache/druid/segment/QueryableIndexCursorFactory.java
 
b/processing/src/main/java/org/apache/druid/segment/QueryableIndexCursorFactory.java
index 8745761c183..d3aa95685aa 100644
--- 
a/processing/src/main/java/org/apache/druid/segment/QueryableIndexCursorFactory.java
+++ 
b/processing/src/main/java/org/apache/druid/segment/QueryableIndexCursorFactory.java
@@ -37,10 +37,24 @@ import java.util.List;
 public class QueryableIndexCursorFactory implements CursorFactory
 {
   private final QueryableIndex index;
+  private final TimeBoundaryInspector timeBoundaryInspector;
 
-  public QueryableIndexCursorFactory(QueryableIndex index)
+  /**
+   * Constructor that accepts a {@link QueryableIndexTimeBoundaryInspector} 
that is in use elsewhere, promoting
+   * efficient re-use.
+   */
+  public QueryableIndexCursorFactory(QueryableIndex index, 
TimeBoundaryInspector timeBoundaryInspector)
   {
     this.index = index;
+    this.timeBoundaryInspector = timeBoundaryInspector;
+  }
+
+  /**
+   * Constructor that creates a new {@link 
QueryableIndexTimeBoundaryInspector}.
+   */
+  public QueryableIndexCursorFactory(QueryableIndex index)
+  {
+    this(index, QueryableIndexTimeBoundaryInspector.create(index));
   }
 
   @Override
@@ -48,7 +62,11 @@ public class QueryableIndexCursorFactory implements 
CursorFactory
   {
     QueryableProjection<QueryableIndex> projection = index.getProjection(spec);
     if (projection != null) {
-      return new QueryableIndexCursorHolder(projection.getRowSelector(), 
projection.getCursorBuildSpec())
+      return new QueryableIndexCursorHolder(
+          projection.getRowSelector(),
+          projection.getCursorBuildSpec(),
+          timeBoundaryInspector
+      )
       {
         @Override
         protected ColumnSelectorFactory makeColumnSelectorFactoryForOffset(
@@ -86,7 +104,7 @@ public class QueryableIndexCursorFactory implements 
CursorFactory
         }
       };
     }
-    return new QueryableIndexCursorHolder(index, 
CursorBuildSpec.builder(spec).build());
+    return new QueryableIndexCursorHolder(index, 
CursorBuildSpec.builder(spec).build(), timeBoundaryInspector);
   }
 
   @Override
diff --git 
a/processing/src/main/java/org/apache/druid/segment/QueryableIndexCursorHolder.java
 
b/processing/src/main/java/org/apache/druid/segment/QueryableIndexCursorHolder.java
index 54e482051ae..8683e65a068 100644
--- 
a/processing/src/main/java/org/apache/druid/segment/QueryableIndexCursorHolder.java
+++ 
b/processing/src/main/java/org/apache/druid/segment/QueryableIndexCursorHolder.java
@@ -24,7 +24,6 @@ import com.google.common.base.Supplier;
 import com.google.common.base.Suppliers;
 import com.google.common.collect.ImmutableList;
 import org.apache.druid.collections.bitmap.BitmapFactory;
-import org.apache.druid.java.util.common.DateTimes;
 import org.apache.druid.java.util.common.io.Closer;
 import org.apache.druid.java.util.common.logger.Logger;
 import org.apache.druid.query.BaseQuery;
@@ -58,6 +57,7 @@ import 
org.apache.druid.segment.vector.VectorColumnSelectorFactory;
 import org.apache.druid.segment.vector.VectorCursor;
 import org.apache.druid.segment.vector.VectorOffset;
 import org.apache.druid.utils.CloseableUtils;
+import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
 import org.joda.time.Interval;
 
 import javax.annotation.Nullable;
@@ -86,7 +86,8 @@ public class QueryableIndexCursorHolder implements 
CursorHolder
 
   public QueryableIndexCursorHolder(
       QueryableIndex index,
-      CursorBuildSpec cursorBuildSpec
+      CursorBuildSpec cursorBuildSpec,
+      TimeBoundaryInspector timeBoundaryInspector
   )
   {
     this.index = index;
@@ -109,6 +110,7 @@ public class QueryableIndexCursorHolder implements 
CursorHolder
     this.resourcesSupplier = Suppliers.memoize(
         () -> new CursorResources(
             index,
+            timeBoundaryInspector,
             virtualColumns,
             Cursors.getTimeOrdering(ordering),
             interval,
@@ -159,9 +161,8 @@ public class QueryableIndexCursorHolder implements 
CursorHolder
     final CursorResources resources = resourcesSupplier.get();
     final FilterBundle filterBundle = resources.filterBundle;
     final int numRows = resources.numRows;
-    final long minDataTimestamp = resources.minDataTimestamp;
-    final long maxDataTimestamp = resources.maxDataTimestamp;
-    final NumericColumn timestamps = resources.timestamps;
+    final long minDataTimestamp = 
resources.timeBoundaryInspector.getMinTime().getMillis();
+    final long maxDataTimestamp = 
resources.timeBoundaryInspector.getMaxTime().getMillis();
     final ColumnCache columnCache = resources.columnCache;
     final Order timeOrder = resources.timeOrder;
 
@@ -180,13 +181,13 @@ public class QueryableIndexCursorHolder implements 
CursorHolder
 
     if (timeOrder == Order.ASCENDING) {
       for (; baseOffset.withinBounds(); baseOffset.increment()) {
-        if (timestamps.getLongSingleValueRow(baseOffset.getOffset()) >= 
timeStart) {
+        if 
(resources.getTimestampsColumn().getLongSingleValueRow(baseOffset.getOffset()) 
>= timeStart) {
           break;
         }
       }
     } else if (timeOrder == Order.DESCENDING) {
       for (; baseOffset.withinBounds(); baseOffset.increment()) {
-        if (timestamps.getLongSingleValueRow(baseOffset.getOffset()) < 
timeEnd) {
+        if 
(resources.getTimestampsColumn().getLongSingleValueRow(baseOffset.getOffset()) 
< timeEnd) {
           break;
         }
       }
@@ -197,14 +198,14 @@ public class QueryableIndexCursorHolder implements 
CursorHolder
     if (timeOrder == Order.ASCENDING) {
       offset = new AscendingTimestampCheckingOffset(
           baseOffset,
-          timestamps,
+          resources.getTimestampsColumn(),
           timeEnd,
           maxDataTimestamp < timeEnd
       );
     } else if (timeOrder == Order.DESCENDING) {
       offset = new DescendingTimestampCheckingOffset(
           baseOffset,
-          timestamps,
+          resources.getTimestampsColumn(),
           timeStart,
           minDataTimestamp >= timeStart
       );
@@ -244,9 +245,8 @@ public class QueryableIndexCursorHolder implements 
CursorHolder
   {
     final CursorResources resources = resourcesSupplier.get();
     final FilterBundle filterBundle = resources.filterBundle;
-    final long minDataTimestamp = resources.minDataTimestamp;
-    final long maxDataTimestamp = resources.maxDataTimestamp;
-    final NumericColumn timestamps = resources.timestamps;
+    final long minDataTimestamp = 
resources.timeBoundaryInspector.getMinTime().getMillis();
+    final long maxDataTimestamp = 
resources.timeBoundaryInspector.getMaxTime().getMillis();
     final ColumnCache columnCache = resources.columnCache;
     final Order timeOrder = resources.timeOrder;
     // Wrap the remainder of cursor setup in a try, so if an error is 
encountered while setting it up, we don't
@@ -267,13 +267,13 @@ public class QueryableIndexCursorHolder implements 
CursorHolder
     final int endOffset;
 
     if (timeOrder != Order.NONE && interval.getStartMillis() > 
minDataTimestamp) {
-      startOffset = timeSearch(timestamps, interval.getStartMillis(), 0, 
index.getNumRows());
+      startOffset = timeSearch(resources.getTimestampsColumn(), 
interval.getStartMillis(), 0, index.getNumRows());
     } else {
       startOffset = 0;
     }
 
     if (timeOrder != Order.NONE && interval.getEndMillis() <= 
maxDataTimestamp) {
-      endOffset = timeSearch(timestamps, interval.getEndMillis(), startOffset, 
index.getNumRows());
+      endOffset = timeSearch(resources.getTimestampsColumn(), 
interval.getEndMillis(), startOffset, index.getNumRows());
     } else {
       endOffset = index.getNumRows();
     }
@@ -662,17 +662,18 @@ public class QueryableIndexCursorHolder implements 
CursorHolder
   private static final class CursorResources implements Closeable
   {
     private final Closer closer;
-    private final long minDataTimestamp;
-    private final long maxDataTimestamp;
+    private final TimeBoundaryInspector timeBoundaryInspector;
     private final int numRows;
     @Nullable
     private final FilterBundle filterBundle;
-    private final NumericColumn timestamps;
     private final Order timeOrder;
     private final ColumnCache columnCache;
+    @MonotonicNonNull
+    private NumericColumn timestamps;
 
     private CursorResources(
         QueryableIndex index,
+        TimeBoundaryInspector timeBoundaryInspector,
         VirtualColumns virtualColumns,
         Order timeOrder,
         Interval interval,
@@ -683,6 +684,7 @@ public class QueryableIndexCursorHolder implements 
CursorHolder
     {
       this.closer = Closer.create();
       this.columnCache = new ColumnCache(index, closer);
+      this.timeBoundaryInspector = timeBoundaryInspector;
       final ColumnSelectorColumnIndexSelector bitmapIndexSelector = new 
ColumnSelectorColumnIndexSelector(
           index.getBitmapFactoryForDimensions(),
           virtualColumns,
@@ -690,14 +692,10 @@ public class QueryableIndexCursorHolder implements 
CursorHolder
       );
       try {
         this.numRows = index.getNumRows();
-        this.timestamps = (NumericColumn) 
columnCache.getColumn(ColumnHolder.TIME_COLUMN_NAME);
-        this.minDataTimestamp = 
DateTimes.utc(timestamps.getLongSingleValueRow(0)).getMillis();
-        this.maxDataTimestamp = 
DateTimes.utc(timestamps.getLongSingleValueRow(timestamps.length() - 
1)).getMillis();
         this.filterBundle = makeFilterBundle(
             computeFilterWithIntervalIfNeeded(
+                timeBoundaryInspector,
                 timeOrder,
-                this.minDataTimestamp,
-                this.maxDataTimestamp,
                 interval,
                 filter
             ),
@@ -713,6 +711,14 @@ public class QueryableIndexCursorHolder implements 
CursorHolder
       }
     }
 
+    public NumericColumn getTimestampsColumn()
+    {
+      if (timestamps == null) {
+        timestamps = (NumericColumn) 
columnCache.getColumn(ColumnHolder.TIME_COLUMN_NAME);
+      }
+      return timestamps;
+    }
+
     @Override
     public void close() throws IOException
     {
@@ -783,20 +789,20 @@ public class QueryableIndexCursorHolder implements 
CursorHolder
    */
   @Nullable
   private static Filter computeFilterWithIntervalIfNeeded(
+      final TimeBoundaryInspector timeBoundaryInspector,
       final Order timeOrder,
-      final long minDataTimestamp,
-      final long maxDataTimestamp,
       final Interval interval,
       @Nullable final Filter filter
   )
   {
     if (timeOrder == Order.NONE
-        && (minDataTimestamp < interval.getStartMillis() || maxDataTimestamp 
>= interval.getEndMillis())) {
+        && (timeBoundaryInspector.getMinTime().getMillis() < 
interval.getStartMillis()
+            || timeBoundaryInspector.getMaxTime().getMillis() >= 
interval.getEndMillis())) {
       final RangeFilter timeFilter = new RangeFilter(
           ColumnHolder.TIME_COLUMN_NAME,
           ColumnType.LONG,
-          minDataTimestamp < interval.getStartMillis() ? 
interval.getStartMillis() : null,
-          maxDataTimestamp >= interval.getEndMillis() ? 
interval.getEndMillis() : null,
+          timeBoundaryInspector.getMinTime().getMillis() < 
interval.getStartMillis() ? interval.getStartMillis() : null,
+          timeBoundaryInspector.getMaxTime().getMillis() >= 
interval.getEndMillis() ? interval.getEndMillis() : null,
           false,
           true,
           null
diff --git 
a/processing/src/main/java/org/apache/druid/segment/QueryableIndexSegment.java 
b/processing/src/main/java/org/apache/druid/segment/QueryableIndexSegment.java
index ece082a0b33..7c39c8ea240 100644
--- 
a/processing/src/main/java/org/apache/druid/segment/QueryableIndexSegment.java
+++ 
b/processing/src/main/java/org/apache/druid/segment/QueryableIndexSegment.java
@@ -46,8 +46,8 @@ public class QueryableIndexSegment implements Segment
   public QueryableIndexSegment(QueryableIndex index, final SegmentId segmentId)
   {
     this.index = index;
-    this.cursorFactory = new QueryableIndexCursorFactory(index);
     this.timeBoundaryInspector = 
QueryableIndexTimeBoundaryInspector.create(index);
+    this.cursorFactory = new QueryableIndexCursorFactory(index, 
timeBoundaryInspector);
     this.segmentId = segmentId;
   }
 


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

Reply via email to