diff --git a/Duplicati/Library/Main/Database/LocalDatabase.cs b/Duplicati/Library/Main/Database/LocalDatabase.cs
index d009722e1..a03c71dcd 100644
--- a/Duplicati/Library/Main/Database/LocalDatabase.cs
+++ b/Duplicati/Library/Main/Database/LocalDatabase.cs
@@ -769,7 +769,35 @@ AND Fileset.ID NOT IN
.ExecuteScalarInt64(-1);
}
+ ///
+ /// Verifies the consistency of the database
+ ///
+ /// The block size in bytes
+ /// The hash size in byts
+ /// Also verify filelists (can be slow)
+ /// The transaction to run in
public void VerifyConsistency(long blocksize, long hashsize, bool verifyfilelists, IDbTransaction transaction)
+ => VerifyConsistencyInner(blocksize, hashsize, verifyfilelists, false, transaction);
+
+ ///
+ /// Verifies the consistency of the database prior to repair
+ ///
+ /// The block size in bytes
+ /// The hash size in byts
+ /// Also verify filelists (can be slow)
+ /// The transaction to run in
+ public void VerifyConsistencyForRepair(long blocksize, long hashsize, bool verifyfilelists, IDbTransaction transaction)
+ => VerifyConsistencyInner(blocksize, hashsize, verifyfilelists, true, transaction);
+
+ ///
+ /// Verifies the consistency of the database
+ ///
+ /// The block size in bytes
+ /// The hash size in byts
+ /// Also verify filelists (can be slow)
+ /// Disable verify for errors that will be fixed by repair
+ /// The transaction to run in
+ private void VerifyConsistencyInner(long blocksize, long hashsize, bool verifyfilelists, bool laxVerifyForRepair, IDbTransaction transaction)
{
using (var cmd = m_connection.CreateCommand(transaction))
{
@@ -841,39 +869,42 @@ ON
.ExecuteScalarInt64(0) != 0)
throw new DatabaseInconsistencyException("Detected files associated with non-existing blocksets!");
- var filesetsMissingVolumes = cmd.SetCommandAndParameters(@"SELECT COUNT(*) FROM ""Fileset"" WHERE ""VolumeID"" NOT IN (SELECT ""ID"" FROM ""RemoteVolume"" WHERE ""Type"" = @Type AND ""State"" != @State)")
+ if (!laxVerifyForRepair)
+ {
+ var filesetsMissingVolumes = cmd.SetCommandAndParameters(@"SELECT COUNT(*) FROM ""Fileset"" WHERE ""VolumeID"" NOT IN (SELECT ""ID"" FROM ""RemoteVolume"" WHERE ""Type"" = @Type AND ""State"" != @State)")
.SetParameterValue("@Type", RemoteVolumeType.Files.ToString())
.SetParameterValue("@State", RemoteVolumeState.Deleted.ToString())
.ExecuteScalarInt64(0);
- if (filesetsMissingVolumes != 0)
- {
- if (filesetsMissingVolumes == 1)
- using (var reader = cmd.SetCommandAndParameters(@"SELECT ""ID"", ""Timestamp"", ""VolumeID"" FROM ""Fileset"" WHERE ""VolumeID"" NOT IN (SELECT ""ID"" FROM ""RemoteVolume"" WHERE ""Type"" = @Type AND ""State"" != @State)")
- .SetParameterValue("@Type", RemoteVolumeType.Files.ToString())
- .SetParameterValue("@State", RemoteVolumeState.Deleted.ToString())
- .ExecuteReader())
- if (reader.Read())
- throw new DatabaseInconsistencyException($"Detected 1 fileset with missing volume: FilesetId = {reader.ConvertValueToInt64(0)}, Time = ({ParseFromEpochSeconds(reader.ConvertValueToInt64(1))}), unmatched VolumeID {reader.ConvertValueToInt64(2)}");
+ if (filesetsMissingVolumes != 0)
+ {
+ if (filesetsMissingVolumes == 1)
+ using (var reader = cmd.SetCommandAndParameters(@"SELECT ""ID"", ""Timestamp"", ""VolumeID"" FROM ""Fileset"" WHERE ""VolumeID"" NOT IN (SELECT ""ID"" FROM ""RemoteVolume"" WHERE ""Type"" = @Type AND ""State"" != @State)")
+ .SetParameterValue("@Type", RemoteVolumeType.Files.ToString())
+ .SetParameterValue("@State", RemoteVolumeState.Deleted.ToString())
+ .ExecuteReader())
+ if (reader.Read())
+ throw new DatabaseInconsistencyException($"Detected 1 fileset with missing volume: FilesetId = {reader.ConvertValueToInt64(0)}, Time = ({ParseFromEpochSeconds(reader.ConvertValueToInt64(1))}), unmatched VolumeID {reader.ConvertValueToInt64(2)}");
- throw new DatabaseInconsistencyException($"Detected {filesetsMissingVolumes} filesets with missing volumes");
- }
+ throw new DatabaseInconsistencyException($"Detected {filesetsMissingVolumes} filesets with missing volumes");
+ }
- var volumesMissingFilests = cmd.SetCommandAndParameters(@"SELECT COUNT(*) FROM ""RemoteVolume"" WHERE ""Type"" = @Type AND ""State"" != @State AND ""ID"" NOT IN (SELECT ""VolumeID"" FROM ""Fileset"")")
- .SetParameterValue("@Type", RemoteVolumeType.Files.ToString())
- .SetParameterValue("@State", RemoteVolumeState.Deleted.ToString())
- .ExecuteScalarInt64(0);
- if (volumesMissingFilests != 0)
- {
- if (volumesMissingFilests == 1)
- using (var reader = cmd.SetCommandAndParameters(@"SELECT ""ID"", ""Name"", ""State"" FROM ""RemoteVolume"" WHERE ""Type"" = @Type AND ""State"" != @State AND ""ID"" NOT IN (SELECT ""VolumeID"" FROM ""Fileset"")")
- .SetParameterValue("@Type", RemoteVolumeType.Files.ToString())
- .SetParameterValue("@State", RemoteVolumeState.Deleted.ToString())
- .ExecuteReader())
- if (reader.Read())
- throw new DatabaseInconsistencyException($"Detected 1 volume with missing filesets: VolumeId = {reader.ConvertValueToInt64(0)}, Name = {reader.ConvertValueToString(1)}, State = {reader.ConvertValueToString(2)}");
+ var volumesMissingFilests = cmd.SetCommandAndParameters(@"SELECT COUNT(*) FROM ""RemoteVolume"" WHERE ""Type"" = @Type AND ""State"" != @State AND ""ID"" NOT IN (SELECT ""VolumeID"" FROM ""Fileset"")")
+ .SetParameterValue("@Type", RemoteVolumeType.Files.ToString())
+ .SetParameterValue("@State", RemoteVolumeState.Deleted.ToString())
+ .ExecuteScalarInt64(0);
+ if (volumesMissingFilests != 0)
+ {
+ if (volumesMissingFilests == 1)
+ using (var reader = cmd.SetCommandAndParameters(@"SELECT ""ID"", ""Name"", ""State"" FROM ""RemoteVolume"" WHERE ""Type"" = @Type AND ""State"" != @State AND ""ID"" NOT IN (SELECT ""VolumeID"" FROM ""Fileset"")")
+ .SetParameterValue("@Type", RemoteVolumeType.Files.ToString())
+ .SetParameterValue("@State", RemoteVolumeState.Deleted.ToString())
+ .ExecuteReader())
+ if (reader.Read())
+ throw new DatabaseInconsistencyException($"Detected 1 volume with missing filesets: VolumeId = {reader.ConvertValueToInt64(0)}, Name = {reader.ConvertValueToString(1)}, State = {reader.ConvertValueToString(2)}");
- throw new DatabaseInconsistencyException($"Detected {volumesMissingFilests} volumes with missing filesets");
+ throw new DatabaseInconsistencyException($"Detected {volumesMissingFilests} volumes with missing filesets");
+ }
}
var nonAttachedFiles = cmd.ExecuteScalarInt64(@"SELECT COUNT(*) FROM ""FilesetEntry"" WHERE ""FileID"" NOT IN (SELECT ""ID"" FROM ""FileLookup"")");
diff --git a/Duplicati/Library/Main/Operation/RepairHandler.cs b/Duplicati/Library/Main/Operation/RepairHandler.cs
index 98e051a50..612cfb0c9 100644
--- a/Duplicati/Library/Main/Operation/RepairHandler.cs
+++ b/Duplicati/Library/Main/Operation/RepairHandler.cs
@@ -137,7 +137,7 @@ namespace Duplicati.Library.Main.Operation
throw new UserInformationException("The database was attempted repaired, but the repair did not complete. This database may be incomplete and the repair process is not allowed to alter remote files as that could result in data loss.", "DatabaseIsInRepairState");
// Ensure the database is consistent before we start fixing the remote
- db.VerifyConsistency(m_options.Blocksize, m_options.BlockhashSize, true, null);
+ db.VerifyConsistencyForRepair(m_options.Blocksize, m_options.BlockhashSize, true, null);
// If the last backup failed, guard the incomplete fileset, so we can create a synthetic filelist
var lastTempFilelist = db.GetLastIncompleteFilesetVolume(null);
diff --git a/Duplicati/UnitTest/RepairHandlerTests.cs b/Duplicati/UnitTest/RepairHandlerTests.cs
index c4c77ad9a..4f07d119b 100644
--- a/Duplicati/UnitTest/RepairHandlerTests.cs
+++ b/Duplicati/UnitTest/RepairHandlerTests.cs
@@ -597,7 +597,7 @@ namespace Duplicati.UnitTest
using (Controller c = new Controller("file://" + this.TARGETFOLDER, options, null))
{
- IRepairResults repairResults = c.Repair();
+ var repairResults = c.Repair();
Assert.AreEqual(0, repairResults.Errors.Count());
Assert.AreEqual(0, repairResults.Warnings.Where(x => x.IndexOf("RemoteFilesNewerThanLocalDatabase", StringComparison.OrdinalIgnoreCase) < 0).Count());
Assert.AreEqual(2, Directory.EnumerateFiles(this.TARGETFOLDER, "*.dlist.*").Count());