35
35
import java .util .OptionalInt ;
36
36
import java .util .concurrent .locks .ReentrantLock ;
37
37
import java .util .concurrent .locks .ReentrantReadWriteLock ;
38
- import java .util .function .Supplier ;
39
38
40
39
/**
41
40
* The abstract index class which holds entry format agnostic methods.
@@ -48,7 +47,15 @@ private enum SearchResultType {
48
47
49
48
private static final Logger log = LoggerFactory .getLogger (AbstractIndex .class );
50
49
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.
52
59
private final ReentrantLock lock = new ReentrantLock ();
53
60
// Allows concurrent read operations while ensuring exclusive access if the underlying mmap is changed
54
61
private final ReentrantReadWriteLock remapLock = new ReentrantReadWriteLock ();
@@ -191,8 +198,8 @@ public void updateParentDir(File parentDir) {
191
198
* @return a boolean indicating whether the size of the memory map and the underneath file is changed or not.
192
199
*/
193
200
public boolean resize (int newSize ) throws IOException {
194
- return inLockThrows (() ->
195
- inRemapWriteLockThrows (() -> {
201
+ return inLock (() ->
202
+ inRemapWriteLock (() -> {
196
203
int roundedNewSize = roundDownToExactMultiple (newSize , entrySize ());
197
204
198
205
if (length == roundedNewSize ) {
@@ -258,7 +265,7 @@ public boolean deleteIfExists() throws IOException {
258
265
* the file.
259
266
*/
260
267
public void trimToValidSize () throws IOException {
261
- inLockThrows (() -> {
268
+ inLock (() -> {
262
269
if (mmap != null ) {
263
270
resize (entrySize () * entries );
264
271
}
@@ -282,10 +289,7 @@ public void closeHandler() {
282
289
// However, in some cases it can pause application threads(STW) for a long moment reading metadata from a physical disk.
283
290
// To prevent this, we forcefully cleanup memory mapping within proper execution which never affects API responsiveness.
284
291
// See https://issues.apache.org/jira/browse/KAFKA-4614 for the details.
285
- inLockThrows (() ->
286
- inRemapWriteLockThrows (() -> {
287
- safeForceUnmap ();
288
- }));
292
+ inLock (() -> inRemapWriteLock (this ::safeForceUnmap ));
289
293
}
290
294
291
295
/**
@@ -412,36 +416,28 @@ protected void truncateToEntries0(int entries) {
412
416
mmap .position (entries * entrySize ());
413
417
}
414
418
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 {
416
420
return LockUtils .inLock (lock , action );
417
421
}
418
422
419
- protected final void inLock (Runnable action ) {
423
+ protected final < E extends Exception > void inLock (LockUtils . ThrowingRunnable < E > action ) throws E {
420
424
LockUtils .inLock (lock , action );
421
425
}
422
426
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 {
432
428
return LockUtils .inLock (remapLock .readLock (), action );
433
429
}
434
430
435
- protected final void inRemapReadLock (Runnable action ) {
431
+ protected final < E extends Exception > void inRemapReadLock (LockUtils . ThrowingRunnable < E > action ) throws E {
436
432
LockUtils .inLock (remapLock .readLock (), action );
437
433
}
438
434
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 );
441
437
}
442
438
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 );
445
441
}
446
442
447
443
/**
0 commit comments