From 1202662afef351a13c12e44606e9b0fc697a9445 Mon Sep 17 00:00:00 2001 From: OneWay Date: Sun, 4 Oct 2026 12:03:00 +0000 Subject: [PATCH] fix(storage): retry index file creation while the target is busy A just-deleted index file can still be held by the system, so createNewFile() may fail right after deletion. Retry a few times with a short delay, waiting for the old file to disappear first. --- .../common/util/FileStorageManager.kt | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/example/research/common/util/FileStorageManager.kt b/app/src/main/java/com/example/research/common/util/FileStorageManager.kt index 826ce4b..1d40687 100644 --- a/app/src/main/java/com/example/research/common/util/FileStorageManager.kt +++ b/app/src/main/java/com/example/research/common/util/FileStorageManager.kt @@ -19,6 +19,8 @@ class FileStorageManager { private const val DELETE_WAIT_INTERVAL = 50L private const val MAX_DELETE_WAIT_COUNT = 10 private const val DEFAULT_MAX_RETRIES = 5 + private const val CREATE_RETRY_DELAY = 100L + private const val MAX_CREATE_RETRIES = 3 private const val TAG = "FileStorageManager" } @@ -87,6 +89,7 @@ class FileStorageManager { Log.e(TAG, "Could not delete existing file: $fileName") return@withContext null } + awaitGone(targetFile::exists) } else { return@withContext Uri.fromFile(targetFile) } @@ -95,7 +98,18 @@ class FileStorageManager { if (tempBinFile.exists()) { tempBinFile.delete() } - if (targetFile.createNewFile()) { + var created = targetFile.createNewFile() + var createAttempt = 0 + while (!created && createAttempt < MAX_CREATE_RETRIES) { + delay(CREATE_RETRY_DELAY.milliseconds) + if (targetFile.exists()) { + targetFile.delete() + awaitGone(targetFile::exists) + } + created = targetFile.createNewFile() + createAttempt++ + } + if (created) { Uri.fromFile(targetFile) } else { Log.e(TAG, "Failed to create file: $fileName") @@ -116,7 +130,7 @@ class FileStorageManager { for (attempt in 1..maxRetries) { try { if (file.delete()) { - waitForFileDeletion(file) + awaitGone(file::exists) if (!file.exists()) { return@withContext true } @@ -141,9 +155,10 @@ class FileStorageManager { } } - private suspend fun waitForFileDeletion(file: DocumentFile) { + // FUSE-backed storage keeps a just-deleted file visible to stat/open for a short window + private suspend fun awaitGone(exists: () -> Boolean) { var waitCount = 0 - while (file.exists() && waitCount < MAX_DELETE_WAIT_COUNT) { + while (exists() && waitCount < MAX_DELETE_WAIT_COUNT) { delay(DELETE_WAIT_INTERVAL.milliseconds) waitCount++ }