From 7584704d22c33672e8518fa6f3057310981c7758 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Thu, 26 Oct 2023 23:34:16 +0800 Subject: [PATCH] Avoid race condition when updating tag database `updateInternal` and `issueUpdateInMemoryData` will try to create tag database directory at the same time on first launch and one of them will fail, causing app crash --- .../com/hippo/ehviewer/EhApplication.kt | 2 +- .../hippo/ehviewer/client/EhTagDatabase.kt | 51 +++++++++---------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt b/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt index 60556e51a..19f143982 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt @@ -91,7 +91,7 @@ class EhApplication : Application(), ImageLoaderFactory { migrateCookies() } launchIO { - EhTagDatabase.update() + EhTagDatabase } launchIO { EhDB diff --git a/app/src/main/kotlin/com/hippo/ehviewer/client/EhTagDatabase.kt b/app/src/main/kotlin/com/hippo/ehviewer/client/EhTagDatabase.kt index a9251c810..4f6946ff2 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/client/EhTagDatabase.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/client/EhTagDatabase.kt @@ -55,7 +55,6 @@ object EhTagDatabase : CoroutineScope { ) private lateinit var tagGroups: Map> private val updateLock = Mutex() - private val dbLock = Mutex() override val coroutineContext = Dispatchers.IO + Job() var initialized by mutableStateOf(false) @@ -202,42 +201,42 @@ object EhTagDatabase : CoroutineScope { } } - private suspend fun issueUpdateInMemoryData() { - dbLock.withLock { - getMetadata(appCtx)?.let { urls -> - val dataName = urls[2] - val dir = AppConfig.getFilesDir("tag-translations") - val dataFile = File(dir, dataName).takeIf { it.exists() } ?: return - runSuspendCatching { - tagGroups = dataFile.source().buffer().use(BufferedSource::parseAs) - initialized = true - }.onFailure { - it.printStackTrace() - } - } - } + private fun issueUpdateInMemoryData(file: File? = null) { + val dataFile = file ?: getMetadata(appCtx)?.let { metadata -> + val dataName = metadata[2] + val dir = AppConfig.getFilesDir("tag-translations") + File(dir, dataName).takeIf { it.exists() } + } ?: return + tagGroups = dataFile.source().buffer().use(BufferedSource::parseAs) + initialized = true } init { launch { - issueUpdateInMemoryData() + updateLock.withLock { + runSuspendCatching { + issueUpdateInMemoryData() + }.onFailure { + it.printStackTrace() + } + updateInternal() + } } } private suspend fun updateInternal() { - val urls = getMetadata(appCtx) - urls?.let { - val sha1Name = urls[0] - val sha1Url = urls[1] - val dataName = urls[2] - val dataUrl = urls[3] + getMetadata(appCtx)?.let { metadata -> + val sha1Name = metadata[0] + val sha1Url = metadata[1] + val dataName = metadata[2] + val dataUrl = metadata[3] val dir = AppConfig.getFilesDir("tag-translations") checkNotNull(dir) val sha1File = File(dir, sha1Name) val dataFile = File(dir, dataName) - runCatching { + runSuspendCatching { // Check current sha1 and current data val sha1 = getFileContent(sha1File) if (!checkData(sha1, dataFile)) { @@ -254,7 +253,7 @@ object EhTagDatabase : CoroutineScope { if (tempSha1 == sha1) { // The data is the same FileUtils.delete(tempSha1File) - return@runCatching + return } // Save new data @@ -265,7 +264,7 @@ object EhTagDatabase : CoroutineScope { if (!checkData(tempSha1, tempDataFile)) { FileUtils.delete(tempSha1File) FileUtils.delete(tempDataFile) - return@runCatching + return } // Replace current sha1 and current data with new sha1 and new data @@ -275,7 +274,7 @@ object EhTagDatabase : CoroutineScope { tempDataFile.renameTo(dataFile) // Read new EhTagDatabase - issueUpdateInMemoryData() + issueUpdateInMemoryData(dataFile) }.onFailure { it.printStackTrace() }