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

xiangfu0 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 52d9c8027b8 Add scoped buffer reads for compressed forward indexes 
(#20069)
52d9c8027b8 is described below

commit 52d9c8027b829cddaf590b34abea3ed2bdbae5db
Author: Xiang Fu <[email protected]>
AuthorDate: Wed Oct 28 16:54:12 2026 -0700

    Add scoped buffer reads for compressed forward indexes (#20069)
    
    * Add scoped buffer reads for compressed forward indexes
    
    * Use the existing IOFunction type for scoped reads
    
    * Use Commons IO transitively from pinot-spi
    
    * Clarify scoped buffer access and name it withByteBuffer
    
    * Name the scoped buffer API readWithByteBuffer
---
 .../readers/forward/BaseChunkForwardIndexReader.java      | 10 +++++++---
 .../readers/forward/VarByteChunkForwardIndexReaderV4.java | 15 ++++++++-------
 .../apache/pinot/segment/spi/memory/PinotDataBuffer.java  | 12 ++++++++++++
 3 files changed, 27 insertions(+), 10 deletions(-)

diff --git 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/readers/forward/BaseChunkForwardIndexReader.java
 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/readers/forward/BaseChunkForwardIndexReader.java
index 0e837cd48eb..571c9ee60f1 100644
--- 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/readers/forward/BaseChunkForwardIndexReader.java
+++ 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/readers/forward/BaseChunkForwardIndexReader.java
@@ -209,19 +209,23 @@ public abstract class BaseChunkForwardIndexReader 
implements ForwardIndexReader<
       chunkSize = (int) (nextChunkOffset - chunkPosition);
     }
 
-    ByteBuffer decompressedBuffer = context.getChunkBuffer();
-    decompressedBuffer.clear();
+    ByteBuffer chunkBuffer = context.getChunkBuffer();
+    chunkBuffer.clear();
     // Invalidate the cached chunk before decoding. If decompression fails, a 
subsequent read must
     // retry instead of returning a partially-mutated buffer as a cache hit.
     context.setChunkId(-1);
 
+    ByteBuffer decompressedBuffer;
     try {
       // ChunkReaderContext is sized for a full decoded chunk. Decode every 
compression type into
       // that owned buffer so the buffer returned on the first read is also 
the one cached for
       // subsequent reads in the same chunk. The old DELTA/DELTADELTA branch 
allocated a separate
       // buffer without installing it in the context, causing all same-chunk 
reads after the first
       // one to observe the untouched context buffer.
-      
_chunkDecompressor.decompress(_dataBuffer.toDirectByteBuffer(chunkPosition, 
chunkSize), decompressedBuffer);
+      decompressedBuffer = _dataBuffer.readWithByteBuffer(chunkPosition, 
chunkSize, compressedBuffer -> {
+        _chunkDecompressor.decompress(compressedBuffer, chunkBuffer);
+        return chunkBuffer;
+      });
     } catch (IOException e) {
       LOGGER.error("Exception caught while decompressing data chunk", e);
       throw new RuntimeException(e);
diff --git 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/readers/forward/VarByteChunkForwardIndexReaderV4.java
 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/readers/forward/VarByteChunkForwardIndexReaderV4.java
index b3a74be0378..57deb8e8878 100644
--- 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/readers/forward/VarByteChunkForwardIndexReaderV4.java
+++ 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/readers/forward/VarByteChunkForwardIndexReaderV4.java
@@ -427,13 +427,14 @@ public class VarByteChunkForwardIndexReaderV4
     protected byte[] processChunkAndReadFirstValue(int docId, long offset, 
long limit)
         throws IOException {
       _decompressedBuffer.clear();
-      ByteBuffer compressed = _chunks.toDirectByteBuffer(offset, (int) (limit 
- offset));
-      if (_regularChunk) {
-        decompressChunk(compressed);
-        return readSmallUncompressedValue(docId);
-      }
-      // huge value, no benefit from buffering, return the whole thing
-      return readHugeCompressedValue(compressed, 
_chunkDecompressor.decompressedLength(compressed));
+      return _chunks.readWithByteBuffer(offset, (int) (limit - offset), 
compressed -> {
+        if (_regularChunk) {
+          decompressChunk(compressed);
+          return readSmallUncompressedValue(docId);
+        }
+        // huge value, no benefit from buffering, return the whole thing
+        return readHugeCompressedValue(compressed, 
_chunkDecompressor.decompressedLength(compressed));
+      });
     }
 
     /// Decompresses a regular chunk and reads the number of docs. Subclasses 
(e.g. V6) can override
diff --git 
a/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/memory/PinotDataBuffer.java
 
b/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/memory/PinotDataBuffer.java
index ed60deb1e4d..b929082b965 100644
--- 
a/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/memory/PinotDataBuffer.java
+++ 
b/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/memory/PinotDataBuffer.java
@@ -32,6 +32,7 @@ import java.util.Map;
 import java.util.concurrent.atomic.AtomicLong;
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.ThreadSafe;
+import org.apache.commons.io.function.IOFunction;
 import org.apache.pinot.segment.spi.memory.unsafe.UnsafePinotBufferFactory;
 import org.apache.pinot.segment.spi.utils.JavaVersion;
 import org.apache.pinot.spi.env.PinotConfiguration;
@@ -649,6 +650,17 @@ public abstract class PinotDataBuffer implements 
DataBuffer {
     return toDirectByteBuffer(offset, size, order());
   }
 
+  /// Reads a range synchronously through a borrowed ByteBuffer with this 
receiver's byte order.
+  /// The buffer may be heap-backed or direct, depending on the receiver.
+  /// The callback receives a buffer positioned at zero with its limit set to 
`size`. It may change the position
+  /// and limit, but must not modify the contents, release the buffer, or 
retain or return the buffer or any alias.
+  /// The callback must not recursively access or release this receiver or its 
views. The borrowed buffer is only
+  /// valid during the callback; the result must be independent of it.
+  public <T> T readWithByteBuffer(long offset, int size, 
IOFunction<ByteBuffer, T> reader)
+      throws IOException {
+    return reader.apply(toDirectByteBuffer(offset, size));
+  }
+
   @Override
   public ByteBuffer copyOrView(long offset, int size, ByteOrder byteOrder) {
     return toDirectByteBuffer(offset, size, byteOrder);


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

Reply via email to