diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt index c715e0604..9ce4ecd3e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt @@ -1,7 +1,9 @@ package eu.kanade.tachiyomi.data.download import android.content.Context +import android.util.AtomicFile import androidx.core.net.toUri +import androidx.core.util.writeBytes import com.hippo.unifile.UniFile import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.Inject @@ -25,7 +27,6 @@ import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withTimeoutOrNull @@ -88,25 +89,26 @@ class DownloadCache( */ private var lastRenew = 0L private var renewalJob: Job? = null + private val initJob: Job private val _isInitializing = MutableStateFlow(false) val isInitializing = _isInitializing .debounce(1.seconds) // Don't notify if it finishes quickly enough .stateIn(scope, SharingStarted.WhileSubscribed(), false) - private val diskCacheFile: File - get() = File(context.cacheDir, "dl_index_cache_v3") + private val diskCacheFile: AtomicFile + get() = AtomicFile(File(context.cacheDir, "dl_index_cache_v3")) private val rootDownloadsDirMutex = Mutex() private var rootDownloadsDir = RootDirectory(storageManager.getDownloadsDirectory()) init { // Attempt to read cache file - scope.launch { + initJob = scope.launchIO { rootDownloadsDirMutex.withLock { try { - if (diskCacheFile.exists()) { - val diskCache = diskCacheFile.inputStream().use { + if (diskCacheFile.baseFile.exists()) { + val diskCache = diskCacheFile.openRead().use { ProtoBuf.decodeFromByteArray(it.readBytes()) } rootDownloadsDir = diskCache @@ -360,6 +362,9 @@ class DownloadCache( } renewalJob = scope.launchIO { + // The disk index is older than this scan and would replace it if read afterwards + initJob.join() + if (lastRenew == 0L) { _isInitializing.emit(true) } @@ -445,8 +450,9 @@ class DownloadCache( updateDiskCacheJob?.cancel() updateDiskCacheJob = scope.launchIO { delay(1.seconds) - ensureActive() - val bytes = ProtoBuf.encodeToByteArray(rootDownloadsDir) + val bytes = rootDownloadsDirMutex.withLock { + ProtoBuf.encodeToByteArray(rootDownloadsDir) + } ensureActive() try { diskCacheFile.writeBytes(bytes)