Thanks for reopening that issue
About the null-object reference, I think I have collected some additional information. Sometimes sqlite3 throws an ‘disk i/o error’ (not to be confused with a general ‘i/o error’), and this is the actual stacktrace:
at System.Data.SQLite.SQLite3.Reset(SQLiteStatement stmt)
at System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt)
at System.Data.SQLite.SQLiteDataReader.NextResult()
at System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
at System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery(CommandBehavior behavior)
at System.Data.SQLite.SQLiteTransaction.Commit()
at Duplicati.Library.Main.Operation.BackupHandler.AddBlockToOutput(BackendManager backend, String key, Byte[] data, Int32 offset, Int32 len, CompressionHint hint, Boolean isBlocklistData) in C:\Users\maarten\source\repos\duplicati\Duplicati\Library\Main\Operation\BackupHandler.cs:line 1280
at Duplicati.Library.Main.Operation.BackupHandler.ProcessStream(Stream stream, CompressionHint hint, BackendManager backend, FileBackedStringList blocklisthashes, FileBackedStringList hashcollector, Boolean skipfilehash) in C:\Users\maarten\source\repos\duplicati\Duplicati\Library\Main\Operation\BackupHandler.cs:line 1177
at Duplicati.Library.Main.Operation.BackupHandler.HandleFilesystemEntry(ISnapshotService snapshot, BackendManager backend, String path, FileAttributes attributes) in C:\Users\maarten\source\repos\duplicati\Duplicati\Library\Main\Operation\BackupHandler.cs:line 1064
Because in BackupHandler.cs
on line 1273 we close the block-writer, we also dispose the m_compression handler. Because the commit()
fails, we don’t have any way to compress blocks anymore, but our exception handler just handles it like a temporary error even though the internal state is slightly broken at that point.
After this error, m_compression
of BlockVolumeWriter.cs
is null
which will start generating the null-object reference exceptions.
So I think we have two issues:
-
The error in this case is irrecoverable the way we code is currently written. I think we might be better of making the exception handler of
HandleFileSystemEntry
be a bit more specific (eg: catchUnauthorizedAccessException
explicitly and perhaps other errors as well) and if we get an unknown error, perhaps just close down the backup and exit as it is unreliable at that part? -
Because this error happens very irregulary, I suspect some sort of race-condition in accessing SQLite library perhaps? When I try to interpret the code, I see we lock in
FlushDbMessages
but we only lock a single statement if I understand correctly – could it be that we are committing twice because of a race?