From 8674a8bdaddb62e2c150783bfc06eb4fd33138a8 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 20 Jan 2024 13:48:18 +0000 Subject: [PATCH] Cache Lock --- .../okhttp3/internal/cache/CacheLock.kt | 44 +++++++++++++++++++ .../okhttp3/internal/cache/DiskLruCache.kt | 7 +++ 2 files changed, 51 insertions(+) create mode 100644 okhttp/src/main/kotlin/okhttp3/internal/cache/CacheLock.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheLock.kt b/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheLock.kt new file mode 100644 index 000000000000..44f06c3985df --- /dev/null +++ b/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheLock.kt @@ -0,0 +1,44 @@ +package okhttp3.internal.cache + +import android.annotation.SuppressLint +import java.io.Closeable +import java.nio.channels.FileChannel +import java.nio.file.StandardOpenOption +import java.util.Collections +import okhttp3.internal.platform.Platform +import okio.FileSystem +import okio.Path + +internal object CacheLock { + private val openCaches = Collections.synchronizedMap(mutableMapOf()) + + fun openLock(fileSystem: FileSystem, directory: Path): Closeable { + return if (fileSystem == FileSystem.SYSTEM && !Platform.isAndroid) { + fileSystemLock(directory) + } else { + inMemoryLock(directory) + } + } + + @SuppressLint("NewApi") + fun inMemoryLock(directory: Path): Closeable { + // TODO solution for Android N? + val existing = openCaches.putIfAbsent(directory, Exception("CacheLock($directory)")) + if (existing != null) { + throw IllegalStateException("Cache already open at '$directory'", existing) + } + return okio.Closeable { + openCaches.remove(directory) + } + } + + @SuppressLint("NewApi") + fun fileSystemLock(directory: Path): Closeable { + val lockFile = directory / "lock" + val channel = FileChannel.open(lockFile.toNioPath(), StandardOpenOption.APPEND) + + return okio.Closeable { + channel.close() + } + } +} diff --git a/okhttp/src/main/kotlin/okhttp3/internal/cache/DiskLruCache.kt b/okhttp/src/main/kotlin/okhttp3/internal/cache/DiskLruCache.kt index e581cd068b90..605eaf233314 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/cache/DiskLruCache.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/cache/DiskLruCache.kt @@ -20,6 +20,7 @@ import java.io.EOFException import java.io.Flushable import java.io.IOException import okhttp3.internal.assertThreadHoldsLock +import okhttp3.internal.cache.CacheLock.openLock import okhttp3.internal.cache.DiskLruCache.Editor import okhttp3.internal.closeQuietly import okhttp3.internal.concurrent.Task @@ -95,6 +96,8 @@ class DiskLruCache( /** Used for asynchronous journal rebuilds. */ taskRunner: TaskRunner, ) : Closeable, Flushable { + lateinit var cacheLock: Closeable + internal val fileSystem: FileSystem = object : ForwardingFileSystem(fileSystem) { override fun sink( @@ -242,6 +245,8 @@ class DiskLruCache( civilizedFileSystem = fileSystem.isCivilized(journalFileBackup) + cacheLock = openLock(fileSystem, directory) + // Prefer to pick up where we left off. if (fileSystem.exists(journalFile)) { try { @@ -705,6 +710,8 @@ class DiskLruCache( return } + cacheLock.close() + // Copying for concurrent iteration. for (entry in lruEntries.values.toTypedArray()) { if (entry.currentEditor != null) {