You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by mi...@apache.org on 2026/01/27 15:21:53 UTC

(lucene) branch branch_10x updated: Clones of MMapDirectory's IndexInput (MemorySegmentIndexInput) now share one counter for throttling madvise calls for dynamic prefetch (#15585)

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

mikemccand pushed a commit to branch branch_10x
in repository https://gitbox.apache.org/repos/asf/lucene.git


The following commit(s) were added to refs/heads/branch_10x by this push:
     new 1f3bf03947b Clones of MMapDirectory's IndexInput (MemorySegmentIndexInput) now share one counter for throttling madvise calls for dynamic prefetch (#15585)
1f3bf03947b is described below

commit 1f3bf03947b48dca500c5862a3bdb0dad02fad91
Author: Shubham Sharma <sh...@gmail.com>
AuthorDate: Tue Jan 27 14:47:04 2026 +0000

    Clones of MMapDirectory's IndexInput (MemorySegmentIndexInput) now share one counter for throttling madvise calls for dynamic prefetch (#15585)
    
    * Added sharedPrefetchCounter
    
    * Minor
    
    * Added AtomicInteger and CHANGES.txt entry.
    
    * Removed SharedPrefetchCounter completely and replaced with AtomicInteger.
    
    * Empty space
    
    * Replaced incrementAndGet() with getAndIncrement()
    
    ---------
    
    Co-authored-by: shubharm <sh...@amazon.com>
---
 lucene/CHANGES.txt                                 |  2 +
 .../lucene/store/MemorySegmentIndexInput.java      | 62 +++++++++++++++++-----
 2 files changed, 50 insertions(+), 14 deletions(-)

diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 88ae2d2f816..cdede0a2cad 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -167,6 +167,8 @@ Optimizations
 
 * GITHUB#15618: SegmentTermsEnumFrame: avoid unnecessary array allocations that waste memory (Misha Dmitriev)
 
+* GITHUB#15585: Added shared prefetch counter to maintain count across clones and slices of MemorySegmentIndexInput. (Shubham Sharma)
+
 Bug Fixes
 ---------------------
 * GITHUB#14161: PointInSetQuery's constructor now throws IllegalArgumentException
diff --git a/lucene/core/src/java21/org/apache/lucene/store/MemorySegmentIndexInput.java b/lucene/core/src/java21/org/apache/lucene/store/MemorySegmentIndexInput.java
index e45d7d8f25b..b1c993f193d 100644
--- a/lucene/core/src/java21/org/apache/lucene/store/MemorySegmentIndexInput.java
+++ b/lucene/core/src/java21/org/apache/lucene/store/MemorySegmentIndexInput.java
@@ -25,6 +25,7 @@ import java.nio.ByteOrder;
 import java.util.Arrays;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Function;
 import org.apache.lucene.util.ArrayUtil;
 import org.apache.lucene.util.BitUtil;
@@ -57,12 +58,12 @@ abstract class MemorySegmentIndexInput extends IndexInput implements MemorySegme
   final Arena arena;
   final MemorySegment[] segments;
   final Function<IOContext, ReadAdvice> toReadAdvice;
+  final AtomicInteger sharedPrefetchCounter;
 
   int curSegmentIndex = -1;
   MemorySegment
       curSegment; // redundant for speed: segments[curSegmentIndex], also marker if closed!
   long curPosition; // relative to curSegment, not globally
-  int consecutivePrefetchHitCount;
 
   public static MemorySegmentIndexInput newInstance(
       String resourceDescription,
@@ -73,12 +74,28 @@ abstract class MemorySegmentIndexInput extends IndexInput implements MemorySegme
       boolean confined,
       Function<IOContext, ReadAdvice> toReadAdvice) {
     assert Arrays.stream(segments).map(MemorySegment::scope).allMatch(arena.scope()::equals);
+    AtomicInteger sharedPrefetchCounter = new AtomicInteger();
     if (segments.length == 1) {
       return new SingleSegmentImpl(
-          resourceDescription, arena, segments[0], length, chunkSizePower, confined, toReadAdvice);
+          resourceDescription,
+          arena,
+          segments[0],
+          length,
+          chunkSizePower,
+          confined,
+          toReadAdvice,
+          sharedPrefetchCounter);
     } else {
       return new MultiSegmentImpl(
-          resourceDescription, arena, segments, 0, length, chunkSizePower, confined, toReadAdvice);
+          resourceDescription,
+          arena,
+          segments,
+          0,
+          length,
+          chunkSizePower,
+          confined,
+          toReadAdvice,
+          sharedPrefetchCounter);
     }
   }
 
@@ -89,7 +106,8 @@ abstract class MemorySegmentIndexInput extends IndexInput implements MemorySegme
       long length,
       int chunkSizePower,
       boolean confined,
-      Function<IOContext, ReadAdvice> toReadAdvice) {
+      Function<IOContext, ReadAdvice> toReadAdvice,
+      AtomicInteger sharedPrefetchCounter) {
     super(resourceDescription);
     this.arena = arena;
     this.segments = segments;
@@ -99,6 +117,7 @@ abstract class MemorySegmentIndexInput extends IndexInput implements MemorySegme
     this.chunkSizeMask = (1L << chunkSizePower) - 1L;
     this.curSegment = segments[0];
     this.toReadAdvice = toReadAdvice;
+    this.sharedPrefetchCounter = sharedPrefetchCounter;
   }
 
   void ensureOpen() {
@@ -340,7 +359,7 @@ abstract class MemorySegmentIndexInput extends IndexInput implements MemorySegme
 
     ensureOpen();
 
-    if (BitUtil.isZeroOrPowerOfTwo(consecutivePrefetchHitCount++) == false) {
+    if (BitUtil.isZeroOrPowerOfTwo(sharedPrefetchCounter.getAndIncrement()) == false) {
       // We've had enough consecutive hits on the page cache that this number is neither zero nor a
       // power of two. There is a good chance that a good chunk of this index input is cached in
       // physical memory. Let's skip the overhead of the madvise system call, we'll be trying again
@@ -355,7 +374,7 @@ abstract class MemorySegmentIndexInput extends IndexInput implements MemorySegme
         segment -> {
           if (segment.isLoaded() == false) {
             // We have a cache miss on at least one page, let's reset the counter.
-            consecutivePrefetchHitCount = 0;
+            sharedPrefetchCounter.set(0);
             nativeAccess.madviseWillNeed(segment);
           }
         });
@@ -561,7 +580,8 @@ abstract class MemorySegmentIndexInput extends IndexInput implements MemorySegme
               length,
               chunkSizePower,
               confined,
-              toReadAdvice);
+              toReadAdvice,
+              sharedPrefetchCounter);
     } else {
       clone =
           new MultiSegmentImpl(
@@ -572,7 +592,8 @@ abstract class MemorySegmentIndexInput extends IndexInput implements MemorySegme
               length,
               chunkSizePower,
               confined,
-              toReadAdvice);
+              toReadAdvice,
+              sharedPrefetchCounter);
     }
     try {
       clone.seek(getFilePointer());
@@ -663,7 +684,8 @@ abstract class MemorySegmentIndexInput extends IndexInput implements MemorySegme
           length,
           chunkSizePower,
           confined,
-          toReadAdvice);
+          toReadAdvice,
+          sharedPrefetchCounter);
     } else {
       return new MultiSegmentImpl(
           newResourceDescription,
@@ -673,7 +695,8 @@ abstract class MemorySegmentIndexInput extends IndexInput implements MemorySegme
           length,
           chunkSizePower,
           confined,
-          toReadAdvice);
+          toReadAdvice,
+          sharedPrefetchCounter);
     }
   }
 
@@ -719,7 +742,8 @@ abstract class MemorySegmentIndexInput extends IndexInput implements MemorySegme
         long length,
         int chunkSizePower,
         boolean confined,
-        Function<IOContext, ReadAdvice> toReadAdvice) {
+        Function<IOContext, ReadAdvice> toReadAdvice,
+        AtomicInteger sharedPrefetchCounter) {
       super(
           resourceDescription,
           arena,
@@ -727,7 +751,8 @@ abstract class MemorySegmentIndexInput extends IndexInput implements MemorySegme
           length,
           chunkSizePower,
           confined,
-          toReadAdvice);
+          toReadAdvice,
+          sharedPrefetchCounter);
       this.curSegmentIndex = 0;
     }
 
@@ -831,8 +856,17 @@ abstract class MemorySegmentIndexInput extends IndexInput implements MemorySegme
         long length,
         int chunkSizePower,
         boolean confined,
-        Function<IOContext, ReadAdvice> toReadAdvice) {
-      super(resourceDescription, arena, segments, length, chunkSizePower, confined, toReadAdvice);
+        Function<IOContext, ReadAdvice> toReadAdvice,
+        AtomicInteger sharedPrefetchCounter) {
+      super(
+          resourceDescription,
+          arena,
+          segments,
+          length,
+          chunkSizePower,
+          confined,
+          toReadAdvice,
+          sharedPrefetchCounter);
       this.offset = offset;
       try {
         seek(0L);