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:
1 parent
c90f658bfe
commit
1202662afe
1 file changed
+19
-4
@@ -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
|
||||||
}
|
}
|
||||||
|
awaitGone(targetFile::exists)
|
||||||
} 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()
|
||||||
|
awaitGone(targetFile::exists)
|
||||||
|
}
|
||||||
|
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")
|
||||||
@@ -116,7 +130,7 @@ class FileStorageManager {
|
|||||||
for (attempt in 1..maxRetries) {
|
for (attempt in 1..maxRetries) {
|
||||||
try {
|
try {
|
||||||
if (file.delete()) {
|
if (file.delete()) {
|
||||||
waitForFileDeletion(file)
|
awaitGone(file::exists)
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
return@withContext true
|
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
|
var waitCount = 0
|
||||||
while (file.exists() && waitCount < MAX_DELETE_WAIT_COUNT) {
|
while (exists() && waitCount < MAX_DELETE_WAIT_COUNT) {
|
||||||
delay(DELETE_WAIT_INTERVAL.milliseconds)
|
delay(DELETE_WAIT_INTERVAL.milliseconds)
|
||||||
waitCount++
|
waitCount++
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user