Reduce contention in CacheFile.fileLock() method (#55662)

The CacheFile.fileLock() method is used to acquire a lock 
on a cache file so that the file can't be deleted (or its file 
handle closed) during the execution of a read or a write 
operation.

Today this lock is obtained by first acquiring the eviction 
lock (the write lock of the readwrite lock), then by checking 
if the cache file is evicted and the file channel still open, 
and finally by obtaining the file lock (the read lock of the 
readwrite lock). Acquiring the read lock while the eviction 
lock is held ensures that the cache file eviction cannot 
start in the meanwhile. But eviction starts (and terminations) 
also acquire the eviction lock; and this lock cannot be 
obtained while a read lock is held (the write lock of a 
readwrite lock is exclusive).

If we were acquiring a read lock and checking the eviction 
flag and file channel existence while holding the read lock 
we know that no eviction can start or finish until the 
read lock is released.
This commit is contained in:
Tanguy Leroux 2020-04-23 14:39:34 +02:00
parent ed0ced9290
commit 8669766a81
1 changed files with 10 additions and 6 deletions

View File

@ -85,16 +85,20 @@ public class CacheFile {
}
ReleasableLock fileLock() {
try (ReleasableLock ignored = evictionLock.acquire()) {
boolean success = false;
final ReleasableLock fileLock = readLock.acquire();
try {
ensureOpen();
// check if we have a channel under eviction lock
// check if we have a channel while holding the read lock
if (channel == null) {
throw new AlreadyClosedException("Cache file channel has been released and closed");
}
// acquire next read lock while holding the eviction lock
// makes sure that channel won't be closed until this
// read lock is released
return readLock.acquire();
success = true;
return fileLock;
} finally {
if (success == false) {
fileLock.close();
}
}
}