3535import java .util .OptionalInt ;
3636import java .util .concurrent .locks .ReentrantLock ;
3737import java .util .concurrent .locks .ReentrantReadWriteLock ;
38- import java .util .function .Supplier ;
3938
4039/**
4140 * The abstract index class which holds entry format agnostic methods.
@@ -48,7 +47,15 @@ private enum SearchResultType {
4847
4948 private static final Logger log = LoggerFactory .getLogger (AbstractIndex .class );
5049
51- // Serializes all index operations that mutate internal state
50+ // Serializes all index operations that mutate internal state.
51+ // Readers do not need to acquire this lock because:
52+ // 1) MappedByteBuffer provides direct access to the OS-level buffer cache,
53+ // which allows concurrent reads in practice.
54+ // 2) Clients only read committed data and are not affected by concurrent appends/truncates.
55+ // In the rare case when the data is truncated, the follower could read inconsistent data.
56+ // The follower has the logic to ignore the inconsistent data through crc and leader epoch.
57+ // 3) Read and remap operations are coordinated via remapLock to ensure visibility of the
58+ // underlying mmap.
5259 private final ReentrantLock lock = new ReentrantLock ();
5360 // Allows concurrent read operations while ensuring exclusive access if the underlying mmap is changed
5461 private final ReentrantReadWriteLock remapLock = new ReentrantReadWriteLock ();
@@ -191,8 +198,8 @@ public void updateParentDir(File parentDir) {
191198 * @return a boolean indicating whether the size of the memory map and the underneath file is changed or not.
192199 */
193200 public boolean resize (int newSize ) throws IOException {
194- return inLockThrows (() ->
195- inRemapWriteLockThrows (() -> {
201+ return inLock (() ->
202+ inRemapWriteLock (() -> {
196203 int roundedNewSize = roundDownToExactMultiple (newSize , entrySize ());
197204
198205 if (length == roundedNewSize ) {
@@ -258,7 +265,7 @@ public boolean deleteIfExists() throws IOException {
258265 * the file.
259266 */
260267 public void trimToValidSize () throws IOException {
261- inLockThrows (() -> {
268+ inLock (() -> {
262269 if (mmap != null ) {
263270 resize (entrySize () * entries );
264271 }
@@ -282,10 +289,7 @@ public void closeHandler() {
282289 // However, in some cases it can pause application threads(STW) for a long moment reading metadata from a physical disk.
283290 // To prevent this, we forcefully cleanup memory mapping within proper execution which never affects API responsiveness.
284291 // See https://issues.apache.org/jira/browse/KAFKA-4614 for the details.
285- inLockThrows (() ->
286- inRemapWriteLockThrows (() -> {
287- safeForceUnmap ();
288- }));
292+ inLock (() -> inRemapWriteLock (this ::safeForceUnmap ));
289293 }
290294
291295 /**
@@ -412,36 +416,28 @@ protected void truncateToEntries0(int entries) {
412416 mmap .position (entries * entrySize ());
413417 }
414418
415- protected final <T > T inLock (Supplier < T > action ) {
419+ protected final <T , E extends Exception > T inLock (LockUtils . ThrowingSupplier < T , E > action ) throws E {
416420 return LockUtils .inLock (lock , action );
417421 }
418422
419- protected final void inLock (Runnable action ) {
423+ protected final < E extends Exception > void inLock (LockUtils . ThrowingRunnable < E > action ) throws E {
420424 LockUtils .inLock (lock , action );
421425 }
422426
423- protected final <T , E extends Exception > T inLockThrows (LockUtils .ThrowingSupplier <T , E > action ) throws E {
424- return LockUtils .inLockThrows (lock , action );
425- }
426-
427- protected final <E extends Exception > void inLockThrows (LockUtils .ThrowingRunnable <E > action ) throws E {
428- LockUtils .inLockThrows (lock , action );
429- }
430-
431- protected final <T > T inRemapReadLock (Supplier <T > action ) {
427+ protected final <T , E extends Exception > T inRemapReadLock (LockUtils .ThrowingSupplier <T , E > action ) throws E {
432428 return LockUtils .inLock (remapLock .readLock (), action );
433429 }
434430
435- protected final void inRemapReadLock (Runnable action ) {
431+ protected final < E extends Exception > void inRemapReadLock (LockUtils . ThrowingRunnable < E > action ) throws E {
436432 LockUtils .inLock (remapLock .readLock (), action );
437433 }
438434
439- protected final <T , E extends Exception > T inRemapWriteLockThrows (LockUtils .ThrowingSupplier <T , E > action ) throws E {
440- return LockUtils .inLockThrows (remapLock .writeLock (), action );
435+ protected final <T , E extends Exception > T inRemapWriteLock (LockUtils .ThrowingSupplier <T , E > action ) throws E {
436+ return LockUtils .inLock (remapLock .writeLock (), action );
441437 }
442438
443- protected final <E extends Exception > void inRemapWriteLockThrows (LockUtils .ThrowingRunnable <E > action ) throws E {
444- LockUtils .inLockThrows (remapLock .writeLock (), action );
439+ protected final <E extends Exception > void inRemapWriteLock (LockUtils .ThrowingRunnable <E > action ) throws E {
440+ LockUtils .inLock (remapLock .writeLock (), action );
445441 }
446442
447443 /**
0 commit comments