fix(vault): atomic streamed write via temp→rename, suppress OCE log noise
AddEntryStreamingAsync now writes to a temp file in the same vault directory, renames it into place (POSIX rename(2) — atomic on Linux), and updates the index only after the rename succeeds. A client disconnect or I/O fault during the write leaves the original backing file intact and the index unchanged; the temp file is cleaned up best-effort on failure. Fixes the data-corruption regression on the replace path where a cancelled write could truncate the live backing file after the index update and FileMode.Create already ran. Also filters OperationCanceledException from error-level logging in RegisterResourceStreamingAsync — a normal client disconnect is not an error. Two tests added to AudioStoreStreamingTests covering cancel and fault on the replace path.
This commit is contained in:
@@ -206,9 +206,13 @@ public class FileDatabase : DirectoryIndexDirectory, IDisposable
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Swallow and return false, matching RegisterResourceAsync. Logged (unlike the buffered
|
||||
// path) because a streamed write failure can leave a partial backing file worth noticing.
|
||||
_logger.LogError(ex, "RegisterResourceStreamingAsync failed for vault {VaultId} entry {EntryId}", vaultId, entryId);
|
||||
// Swallow and return false, matching RegisterResourceAsync. Log at error for real failures
|
||||
// only — a normal client cancel (OperationCanceledException) is not an error condition and
|
||||
// would spam the error log on every client disconnect during a large upload or replace.
|
||||
if (ex is not OperationCanceledException)
|
||||
{
|
||||
_logger.LogError(ex, "RegisterResourceStreamingAsync failed for vault {VaultId} entry {EntryId}", vaultId, entryId);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user