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);