From cebf1e7259c1fcf1021d0b1148a9bea4c1a72ed9 Mon Sep 17 00:00:00 2001 From: Armin Braun Date: Tue, 15 Oct 2024 20:53:54 +0200 Subject: [PATCH] Avoid slicing memory segments unnecessarily (#13906) No point in copying the memory segment instances when slicing, they are stateless. --- .../lucene/store/MemorySegmentIndexInput.java | 52 ++++++++++++++----- 1 file changed, 39 insertions(+), 13 deletions(-) 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 70fc1eb9488..832fa5f98e6 100644 --- a/lucene/core/src/java21/org/apache/lucene/store/MemorySegmentIndexInput.java +++ b/lucene/core/src/java21/org/apache/lucene/store/MemorySegmentIndexInput.java @@ -530,7 +530,29 @@ abstract class MemorySegmentIndexInput extends IndexInput @Override public final MemorySegmentIndexInput clone() { - final MemorySegmentIndexInput clone = buildSlice((String) null, 0L, this.length); + ensureOpen(); + ensureAccessible(); + final MemorySegmentIndexInput clone; + if (segments.length == 1) { + clone = + new SingleSegmentImpl( + toString(), + null, // clones don't have an Arena, as they can't close) + segments[0], + length, + chunkSizePower, + confined); + } else { + clone = + new MultiSegmentImpl( + toString(), + null, // clones don't have an Arena, as they can't close) + segments, + ((MultiSegmentImpl) this).offset, + length, + chunkSizePower, + confined); + } try { clone.seek(getFilePointer()); } catch (IOException ioe) { @@ -592,26 +614,30 @@ abstract class MemorySegmentIndexInput extends IndexInput MemorySegmentIndexInput buildSlice(String sliceDescription, long offset, long length) { ensureOpen(); ensureAccessible(); + final MemorySegment[] slices; + final boolean isClone = offset == 0 && length == this.length; + if (isClone) { + slices = segments; + } else { + final long sliceEnd = offset + length; + final int startIndex = (int) (offset >>> chunkSizePower); + final int endIndex = (int) (sliceEnd >>> chunkSizePower); + // we always allocate one more slice, the last one may be a 0 byte one after truncating with + // asSlice(): + slices = ArrayUtil.copyOfSubArray(segments, startIndex, endIndex + 1); - final long sliceEnd = offset + length; - final int startIndex = (int) (offset >>> chunkSizePower); - final int endIndex = (int) (sliceEnd >>> chunkSizePower); + // set the last segment's limit for the sliced view. + slices[slices.length - 1] = slices[slices.length - 1].asSlice(0L, sliceEnd & chunkSizeMask); - // we always allocate one more slice, the last one may be a 0 byte one after truncating with - // asSlice(): - final MemorySegment slices[] = ArrayUtil.copyOfSubArray(segments, startIndex, endIndex + 1); - - // set the last segment's limit for the sliced view. - slices[slices.length - 1] = slices[slices.length - 1].asSlice(0L, sliceEnd & chunkSizeMask); - - offset = offset & chunkSizeMask; + offset = offset & chunkSizeMask; + } final String newResourceDescription = getFullSliceDescription(sliceDescription); if (slices.length == 1) { return new SingleSegmentImpl( newResourceDescription, null, // clones don't have an Arena, as they can't close) - slices[0].asSlice(offset, length), + isClone ? slices[0] : slices[0].asSlice(offset, length), length, chunkSizePower, confined);