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.
This commit is contained in:
OneWay committed 2026-10-04 12:03:00 +00:00
1 parent b5bb605665
commit 7c87f20ace
1 file changed
+24 -1
@@ -19,6 +19,8 @@ class FileStorageManager {
private const val DELETE_WAIT_INTERVAL = 50L private const val DELETE_WAIT_INTERVAL = 50L
private const val MAX_DELETE_WAIT_COUNT = 10 private const val MAX_DELETE_WAIT_COUNT = 10
private const val DEFAULT_MAX_RETRIES = 5 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" private const val TAG = "FileStorageManager"
} }
@@ -87,6 +89,7 @@ class FileStorageManager {
Log.e(TAG, "Could not delete existing file: $fileName") Log.e(TAG, "Could not delete existing file: $fileName")
return@withContext null return@withContext null
} }
waitForDeletion(targetFile)
} else { } else {
return@withContext Uri.fromFile(targetFile) return@withContext Uri.fromFile(targetFile)
} }
@@ -95,7 +98,18 @@ class FileStorageManager {
if (tempBinFile.exists()) { if (tempBinFile.exists()) {
tempBinFile.delete() 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()
waitForDeletion(targetFile)
}
created = targetFile.createNewFile()
createAttempt++
}
if (created) {
Uri.fromFile(targetFile) Uri.fromFile(targetFile)
} else { } else {
Log.e(TAG, "Failed to create file: $fileName") Log.e(TAG, "Failed to create file: $fileName")
@@ -141,6 +155,15 @@ class FileStorageManager {
} }
} }
// FUSE-backed storage keeps a just-deleted file visible to stat/open for a short window
private suspend fun waitForDeletion(file: File) {
var waitCount = 0
while (file.exists() && waitCount < MAX_DELETE_WAIT_COUNT) {
delay(DELETE_WAIT_INTERVAL.milliseconds)
waitCount++
}
}
private suspend fun waitForFileDeletion(file: DocumentFile) { private suspend fun waitForFileDeletion(file: DocumentFile) {
var waitCount = 0 var waitCount = 0
while (file.exists() && waitCount < MAX_DELETE_WAIT_COUNT) { while (file.exists() && waitCount < MAX_DELETE_WAIT_COUNT) {