diff --git a/Duplicati/Library/Main/Database/LocalDatabase.cs b/Duplicati/Library/Main/Database/LocalDatabase.cs index 1209511fc..abd0a3f93 100644 --- a/Duplicati/Library/Main/Database/LocalDatabase.cs +++ b/Duplicati/Library/Main/Database/LocalDatabase.cs @@ -533,7 +533,7 @@ namespace Duplicati.Library.Main.Database .ExecuteScalarInt64Async(-1); } - public async IAsyncEnumerable> GetRemoteVolumeIDs(IEnumerable files, SqliteTransaction transaction) + public async IAsyncEnumerable> GetRemoteVolumeIDs(IEnumerable files) { using var cmd = await m_connection.CreateCommandAsync(@" SELECT @@ -542,7 +542,7 @@ namespace Duplicati.Library.Main.Database FROM ""RemoteVolume"" WHERE ""Name"" IN (@Name) "); - cmd.SetTransaction(transaction); + cmd.SetTransaction(m_rtr); using var tmptable = await TemporaryDbValueList.CreateAsync(this, files); await cmd.ExpandInClauseParameterAsync("@Name", tmptable); @@ -573,9 +573,9 @@ namespace Duplicati.Library.Main.Database return RemoteVolumeEntry.Empty; } - public async IAsyncEnumerable> DuplicateRemoteVolumes(SqliteTransaction transaction) + public async IAsyncEnumerable> DuplicateRemoteVolumes() { - m_selectduplicateRemoteVolumesCommand.SetTransaction(transaction); + m_selectduplicateRemoteVolumesCommand.SetTransaction(m_rtr); await foreach (var rd in m_selectduplicateRemoteVolumesCommand.ExecuteReaderEnumerableAsync()) { @@ -586,9 +586,9 @@ namespace Duplicati.Library.Main.Database } } - public async IAsyncEnumerable GetRemoteVolumes(SqliteTransaction transaction) + public async IAsyncEnumerable GetRemoteVolumes() { - m_selectremotevolumesCommand.SetTransaction(transaction); + m_selectremotevolumesCommand.SetTransaction(m_rtr); using var rd = await m_selectremotevolumesCommand.ExecuteReaderAsync(); while (await rd.ReadAsync()) { @@ -611,10 +611,10 @@ namespace Duplicati.Library.Main.Database /// The operation performed /// The path involved /// Any data relating to the operation - public async Task LogRemoteOperation(string operation, string path, string? data, SqliteTransaction transaction) + public async Task LogRemoteOperation(string operation, string path, string? data) { await m_insertremotelogCommand - .SetTransaction(transaction) + .SetTransaction(m_rtr) .SetParameterValue("@OperationID", m_operationid) .SetParameterValue("@Timestamp", Library.Utility.Utility.NormalizeDateTimeToEpochSeconds(DateTime.UtcNow)) .SetParameterValue("@Operation", operation) @@ -641,7 +641,7 @@ namespace Duplicati.Library.Main.Database .ExecuteNonQueryAsync(); } - public async Task UnlinkRemoteVolume(string name, RemoteVolumeState state, SqliteTransaction transaction) + public async Task UnlinkRemoteVolume(string name, RemoteVolumeState state) { using var cmd = await m_connection.CreateCommandAsync(@" DELETE FROM ""RemoteVolume"" @@ -649,7 +649,7 @@ namespace Duplicati.Library.Main.Database ""Name"" = @Name AND ""State"" = @State "); - var c = await cmd.SetTransaction(transaction) + var c = await cmd.SetTransaction(m_rtr) .SetParameterValue("@Name", name) .SetParameterValue("@State", state.ToString()) .ExecuteNonQueryAsync(); @@ -657,7 +657,7 @@ namespace Duplicati.Library.Main.Database if (c != 1) throw new Exception($"Unexpected number of remote volumes deleted: {c}, expected {1}"); - await transaction.CommitAsync(); + await m_rtr.CommitAsync(); } public async Task RemoveRemoteVolume(string name) @@ -1049,7 +1049,7 @@ namespace Duplicati.Library.Main.Database return res; } - public async Task IsFilesetFullBackup(DateTime filesetTime, SqliteTransaction transaction) + public async Task IsFilesetFullBackup(DateTime filesetTime) { using var cmd = m_connection.CreateCommand(); cmd.SetCommandAndParameters($@" @@ -1057,7 +1057,7 @@ namespace Duplicati.Library.Main.Database FROM ""Fileset"" WHERE ""Timestamp"" = @Timestamp ") - .SetTransaction(transaction) + .SetTransaction(m_rtr) .SetParameterValue("@Timestamp", Library.Utility.Utility.NormalizeDateTimeToEpochSeconds(filesetTime)); using var rd = await cmd.ExecuteReaderAsync(); @@ -1067,7 +1067,7 @@ namespace Duplicati.Library.Main.Database return isFullBackup == BackupType.FULL_BACKUP; } - private async IAsyncEnumerable> GetDbOptionList(SqliteTransaction transaction) + private async IAsyncEnumerable> GetDbOptionList() { using var cmd = m_connection.CreateCommand(@" SELECT @@ -1075,19 +1075,19 @@ namespace Duplicati.Library.Main.Database ""Value"" FROM ""Configuration"" ") - .SetTransaction(transaction); + .SetTransaction(m_rtr); using var rd = await cmd.ExecuteReaderAsync(); while (await rd.ReadAsync()) yield return new KeyValuePair(rd.ConvertValueToString(0) ?? "", rd.ConvertValueToString(1) ?? ""); } - public async Task> GetDbOptions(SqliteTransaction transaction) + public async Task> GetDbOptions() { - var res = await GetDbOptionList(transaction) + var res = await GetDbOptionList() .ToDictionaryAsync(x => x.Key, x => x.Value); - await transaction.CommitAsync(); + await m_rtr.CommitAsync(); return res; } @@ -1098,22 +1098,21 @@ namespace Duplicati.Library.Main.Database /// The value to set private async Task UpdateDbOption(string key, bool value) { - var transaction = m_connection.BeginTransaction(); - var opts = await GetDbOptions(transaction); + var opts = await GetDbOptions(); if (value) opts[key] = "true"; else opts.Remove(key); - await SetDbOptions(opts, transaction); - await transaction.CommitAsync(); + await SetDbOptions(opts); + await m_rtr.CommitAsync(); } /// /// Flag indicating if a repair is in progress /// - public async Task RepairInProgress(SqliteTransaction transaction, bool? value = null) + public async Task RepairInProgress(bool? value = null) { if (value is bool v) { @@ -1121,14 +1120,14 @@ namespace Duplicati.Library.Main.Database return v; } - var opts = await GetDbOptions(transaction); + var opts = await GetDbOptions(); return opts.ContainsKey("repair-in-progress"); } /// /// Flag indicating if a repair is in progress /// - public async Task PartiallyRecreated(SqliteTransaction transaction, bool? value = null) + public async Task PartiallyRecreated(bool? value = null) { if (value is bool v) { @@ -1136,14 +1135,14 @@ namespace Duplicati.Library.Main.Database return v; } - var opts = await GetDbOptions(transaction); + var opts = await GetDbOptions(); return opts.ContainsKey("partially-recreated"); } /// /// Flag indicating if the database can contain partial uploads /// - public async Task TerminatedWithActiveUploads(SqliteTransaction transaction, bool? value = null) + public async Task TerminatedWithActiveUploads(bool? value = null) { if (value is bool v) { @@ -1151,7 +1150,7 @@ namespace Duplicati.Library.Main.Database return v; } - var opts = await GetDbOptions(transaction); + var opts = await GetDbOptions(); return opts.ContainsKey("terminated-with-active-uploads"); } @@ -1160,7 +1159,7 @@ namespace Duplicati.Library.Main.Database /// /// The options to set /// An optional transaction - public async Task SetDbOptions(IDictionary options, SqliteTransaction transaction) + public async Task SetDbOptions(IDictionary options) { using var cmd = m_connection.CreateCommand(); await cmd.ExecuteNonQueryAsync(@" @@ -1184,7 +1183,7 @@ namespace Duplicati.Library.Main.Database .ExecuteNonQueryAsync(); } - await transaction.CommitAsync(); + await m_rtr.CommitAsync(); } public async Task GetBlocksLargerThan(long fhblocksize) @@ -1206,8 +1205,8 @@ namespace Duplicati.Library.Main.Database /// The hash size in byts /// Also verify filelists (can be slow) /// The transaction to run in - public async Task VerifyConsistency(long blocksize, long hashsize, bool verifyfilelists, SqliteTransaction transaction) - => await VerifyConsistencyInner(blocksize, hashsize, verifyfilelists, false, transaction); + public async Task VerifyConsistency(long blocksize, long hashsize, bool verifyfilelists) + => await VerifyConsistencyInner(blocksize, hashsize, verifyfilelists, false); /// /// Verifies the consistency of the database prior to repair @@ -1216,8 +1215,8 @@ namespace Duplicati.Library.Main.Database /// The hash size in byts /// Also verify filelists (can be slow) /// The transaction to run in - public async Task VerifyConsistencyForRepair(long blocksize, long hashsize, bool verifyfilelists, SqliteTransaction transaction) - => await VerifyConsistencyInner(blocksize, hashsize, verifyfilelists, true, transaction); + public async Task VerifyConsistencyForRepair(long blocksize, long hashsize, bool verifyfilelists) + => await VerifyConsistencyInner(blocksize, hashsize, verifyfilelists, true); /// /// Verifies the consistency of the database @@ -1227,10 +1226,10 @@ namespace Duplicati.Library.Main.Database /// Also verify filelists (can be slow) /// Disable verify for errors that will be fixed by repair /// The transaction to run in - private async Task VerifyConsistencyInner(long blocksize, long hashsize, bool verifyfilelists, bool laxVerifyForRepair, SqliteTransaction transaction) + private async Task VerifyConsistencyInner(long blocksize, long hashsize, bool verifyfilelists, bool laxVerifyForRepair) { - using var cmd = m_connection.CreateCommand(); - cmd.Transaction = transaction; + using var cmd = m_connection.CreateCommand() + .SetTransaction(m_rtr); // Calculate the lengths for each blockset var combinedLengths = @" SELECT @@ -1504,7 +1503,7 @@ namespace Duplicati.Library.Main.Database var anyError = new List(); using (var cmd2 = m_connection.CreateCommand()) { - cmd2.SetTransaction(transaction); + cmd2.SetTransaction(m_rtr); cmd.SetCommandAndParameters(@" SELECT ""ID"" FROM ""Fileset"" @@ -1566,7 +1565,7 @@ namespace Duplicati.Library.Main.Database public long Size { get; private set; } = size; } - public async IAsyncEnumerable GetBlocks(long volumeid, SqliteTransaction transaction) + public async IAsyncEnumerable GetBlocks(long volumeid) { using var cmd = await m_connection.CreateCommandAsync(@" SELECT DISTINCT @@ -1575,7 +1574,7 @@ namespace Duplicati.Library.Main.Database FROM ""Block"" WHERE ""VolumeID"" = @VolumeId "); - cmd.SetTransaction(transaction) + cmd.SetTransaction(m_rtr) .SetParameterValue("@VolumeId", volumeid); using var rd = await cmd.ExecuteReaderAsync(); while (await rd.ReadAsync()) @@ -1799,11 +1798,11 @@ namespace Duplicati.Library.Main.Database ""H"".""Index"" "; - public async Task WriteFileset(Volumes.FilesetVolumeWriter filesetvolume, long filesetId, SqliteTransaction transaction) + public async Task WriteFileset(Volumes.FilesetVolumeWriter filesetvolume, long filesetId) { using var cmd = m_connection.CreateCommand() .SetCommandAndParameters(LIST_FOLDERS_AND_SYMLINKS) - .SetTransaction(transaction) + .SetTransaction(m_rtr) .SetParameterValue("@FilesetId", filesetId) .SetParameterValue("@FolderBlocksetId", FOLDER_BLOCKSET_ID) .SetParameterValue("@SymlinkBlocksetId", SYMLINK_BLOCKSET_ID); @@ -1871,14 +1870,14 @@ namespace Duplicati.Library.Main.Database } } - public async Task LinkFilesetToVolume(long filesetid, long volumeid, SqliteTransaction transaction) + public async Task LinkFilesetToVolume(long filesetid, long volumeid) { using var cmd = await m_connection.CreateCommandAsync(@" UPDATE ""Fileset"" SET ""VolumeID"" = @VolumeId WHERE ""ID"" = @FilesetId "); - var c = await cmd.SetTransaction(transaction) + var c = await cmd.SetTransaction(m_rtr) .SetParameterValue("@VolumeId", volumeid) .SetParameterValue("@FilesetId", filesetid) .ExecuteNonQueryAsync(); @@ -1887,7 +1886,7 @@ namespace Duplicati.Library.Main.Database throw new Exception($"Failed to link filesetid {filesetid} to volumeid {volumeid}"); } - public async Task PushTimestampChangesToPreviousVersion(long filesetId, SqliteTransaction transaction) + public async Task PushTimestampChangesToPreviousVersion(long filesetId) { var query = @" UPDATE FilesetEntry AS oldVersion @@ -1906,7 +1905,7 @@ namespace Duplicati.Library.Main.Database "; using var cmd = await m_connection.CreateCommandAsync(query); - await cmd.SetTransaction(transaction) + await cmd.SetTransaction(m_rtr) .SetParameterValue("@FilesetId", filesetId) .ExecuteNonQueryAsync(); } @@ -1926,7 +1925,7 @@ namespace Duplicati.Library.Main.Database } [Obsolete("Calling this constructor will throw an exception. Use the Create method instead.")] - public FilteredFilenameTable(SqliteConnection connection, IFilter filter, SqliteTransaction transaction) + public FilteredFilenameTable(SqliteConnection connection, IFilter filter) { throw new NotImplementedException("Use the Create method instead."); } @@ -2128,14 +2127,14 @@ namespace Duplicati.Library.Main.Database /// The ID of the index volume. /// The ID of the block volume. /// An optional transaction. - public async Task AddIndexBlockLink(long indexVolumeID, long blockVolumeID, SqliteTransaction transaction) + public async Task AddIndexBlockLink(long indexVolumeID, long blockVolumeID) { if (indexVolumeID <= 0) throw new ArgumentOutOfRangeException(nameof(indexVolumeID), "Index volume ID must be greater than 0."); if (blockVolumeID <= 0) throw new ArgumentOutOfRangeException(nameof(blockVolumeID), "Block volume ID must be greater than 0."); - await m_insertIndexBlockLink.SetTransaction(transaction) + await m_insertIndexBlockLink.SetTransaction(m_rtr) .SetParameterValue("@IndexVolumeId", indexVolumeID) .SetParameterValue("@BlockVolumeId", blockVolumeID) .ExecuteNonQueryAsync(); @@ -2149,7 +2148,7 @@ namespace Duplicati.Library.Main.Database /// The size of the hash /// An optional external transaction /// An enumerable of tuples containing the blocklist hash, the blocklist data and the length of the data - public async IAsyncEnumerable> GetBlocklists(long volumeid, long blocksize, int hashsize, SqliteTransaction transaction) + public async IAsyncEnumerable> GetBlocklists(long volumeid, long blocksize, int hashsize) { // Group subquery by hash to ensure that each blocklist hash appears only once in the result using var cmd = await m_connection.CreateCommandAsync($@" @@ -2187,7 +2186,7 @@ namespace Duplicati.Library.Main.Database var count = 0; var buffer = new byte[blocksize]; - cmd.SetTransaction(transaction) + cmd.SetTransaction(m_rtr) .SetParameterValue("@VolumeId", volumeid); using (var rd = await cmd.ExecuteReaderAsync()) while (await rd.ReadAsync()) @@ -2236,13 +2235,13 @@ namespace Duplicati.Library.Main.Database /// /// The fileset ID to clear /// The transaction to use - public async Task ClearFilesetEntries(long filesetId, SqliteTransaction transaction) + public async Task ClearFilesetEntries(long filesetId) { using var cmd = await m_connection.CreateCommandAsync(@" DELETE FROM ""FilesetEntry"" WHERE ""FilesetID"" = @FilesetId "); - await cmd.SetTransaction(transaction) + await cmd.SetTransaction(m_rtr) .SetParameterValue("@FilesetId", filesetId) .ExecuteNonQueryAsync(); }