Skip to content

Commit

Permalink
Added grace-period for incomplete uploads to avoid backups stopping d…
Browse files Browse the repository at this point in the history
…ue to the Apache WebDAV issues.

This fixes #1243.
  • Loading branch information
kenkendk committed Apr 5, 2015
1 parent 61a959a commit 0de9adc
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 14 deletions.
@@ -0,0 +1,18 @@

CREATE TABLE "RemoteVolume_Temp" (
"ID" INTEGER PRIMARY KEY,
"OperationID" INTEGER NOT NULL,
"Name" TEXT NOT NULL,
"Type" TEXT NOT NULL,
"Size" INTEGER NULL,
"Hash" TEXT NULL,
"State" TEXT NOT NULL,
"VerificationCount" INTEGER NOT NULL,
"DeleteGraceTime" INTEGER NOT NULL
);

INSERT INTO "RemoteVolume_Temp" SELECT "ID", "OperationID", "Name", "Type", "Size", "Hash", "State", "VerificationCount", 0 FROM "RemoteVolume";
DROP TABLE "RemoteVolume";
ALTER TABLE "RemoteVolume_Temp" RENAME TO "RemoteVolume";

UPDATE "Version" SET "Version" = 3;
5 changes: 3 additions & 2 deletions Duplicati/Library/Main/Database/Database schema/Schema.sql
Expand Up @@ -22,7 +22,8 @@ CREATE TABLE "Remotevolume" (
"Size" INTEGER NULL,
"Hash" TEXT NULL,
"State" TEXT NOT NULL,
"VerificationCount" INTEGER NOT NULL
"VerificationCount" INTEGER NOT NULL,
"DeleteGraceTime" INTEGER NOT NULL
);

/* Index for detecting broken states */
Expand Down Expand Up @@ -219,4 +220,4 @@ CREATE TABLE "Configuration" (
"Value" TEXT NOT NULL
);

INSERT INTO "Version" ("Version") VALUES (2);
INSERT INTO "Version" ("Version") VALUES (3);
4 changes: 2 additions & 2 deletions Duplicati/Library/Main/Database/LocalBackupDatabase.cs
Expand Up @@ -763,15 +763,15 @@ public IRemoteVolume GetRemoteVolumeFromName(string name)
using(var cmd = m_connection.CreateCommand())
using(var rd = cmd.ExecuteReader(@"SELECT ""Name"", ""Hash"", ""Size"" FROM ""RemoteVolume"" WHERE ""Name"" = ?", name))
if (rd.Read())
return new RemoteVolume(rd.GetValue(0).ToString(), rd.GetValue(1).ToString(), rd.GetInt64(2));
return new RemoteVolume(rd.GetValue(0).ToString(), rd.GetValue(1).ToString(), rd.ConvertValueToInt64(2));
else
return null;
}

public IEnumerable<string> GetMissingIndexFiles()
{
using(var cmd = m_connection.CreateCommand())
using(var rd = cmd.ExecuteReader(@"SELECT ""Name"" FROM ""RemoteVolume"" WHERE ""Type"" = ""Blocks"" AND NOT ""ID"" IN (SELECT ""BlockVolumeID"" FROM ""IndexBlockLink"")"))
using(var rd = cmd.ExecuteReader(@"SELECT ""Name"" FROM ""RemoteVolume"" WHERE ""Type"" = ? AND NOT ""ID"" IN (SELECT ""BlockVolumeID"" FROM ""IndexBlockLink"") AND ""State"" IN (?,?)", RemoteVolumeType.Blocks.ToString(), RemoteVolumeState.Uploaded.ToString(), RemoteVolumeState.Verified.ToString()))
while (rd.Read())
yield return rd.GetValue(0).ToString();
}
Expand Down
29 changes: 23 additions & 6 deletions Duplicati/Library/Main/Database/LocalDatabase.cs
Expand Up @@ -108,7 +108,7 @@ private LocalDatabase(System.Data.IDbConnection connection)
m_updateremotevolumeCommand.CommandText = @"UPDATE ""Remotevolume"" SET ""OperationID"" = ?, ""State"" = ?, ""Hash"" = ?, ""Size"" = ? WHERE ""Name"" = ?";
m_updateremotevolumeCommand.AddParameters(5);

m_selectremotevolumesCommand.CommandText = @"SELECT ""Name"", ""Type"", ""Size"", ""Hash"", ""State"" FROM ""Remotevolume""";
m_selectremotevolumesCommand.CommandText = @"SELECT ""Name"", ""Type"", ""Size"", ""Hash"", ""State"", ""DeleteGraceTime"" FROM ""Remotevolume""";

m_selectremotevolumeCommand.CommandText = @"SELECT ""Type"", ""Size"", ""Hash"", ""State"" FROM ""Remotevolume"" WHERE ""Name"" = ?";
m_selectremotevolumeCommand.AddParameter();
Expand All @@ -118,8 +118,8 @@ private LocalDatabase(System.Data.IDbConnection connection)

m_selectremotevolumeIdCommand.CommandText = @"SELECT ""ID"" FROM ""Remotevolume"" WHERE ""Name"" = ?";

m_createremotevolumeCommand.CommandText = @"INSERT INTO ""Remotevolume"" (""OperationID"", ""Name"", ""Type"", ""State"", ""VerificationCount"") VALUES (?, ?, ?, ?, ?); SELECT last_insert_rowid();";
m_createremotevolumeCommand.AddParameters(5);
m_createremotevolumeCommand.CommandText = @"INSERT INTO ""Remotevolume"" (""OperationID"", ""Name"", ""Type"", ""State"", ""VerificationCount"", ""DeleteGraceTime"") VALUES (?, ?, ?, ?, ?, ?); SELECT last_insert_rowid();";
m_createremotevolumeCommand.AddParameters(6);

m_insertIndexBlockLink.CommandText = @"INSERT INTO ""IndexBlockLink"" (""IndexVolumeID"", ""BlockVolumeID"") VALUES (?, ?)";
m_insertIndexBlockLink.AddParameters(2);
Expand Down Expand Up @@ -269,9 +269,10 @@ public IEnumerable<RemoteVolumeEntry> GetRemoteVolumes()
yield return new RemoteVolumeEntry(
rd.GetValue(0).ToString(),
(rd.GetValue(3) == null || rd.GetValue(3) == DBNull.Value) ? null : rd.GetValue(3).ToString(),
(rd.GetValue(2) == null || rd.GetValue(2) == DBNull.Value) ? -1 : rd.GetInt64(2),
rd.ConvertValueToInt64(2, -1),
(RemoteVolumeType)Enum.Parse(typeof(RemoteVolumeType), rd.GetValue(1).ToString()),
(RemoteVolumeState)Enum.Parse(typeof(RemoteVolumeState), rd.GetValue(4).ToString())
(RemoteVolumeState)Enum.Parse(typeof(RemoteVolumeState), rd.GetValue(4).ToString()),
new DateTime(rd.ConvertValueToInt64(5, 0), DateTimeKind.Utc)
);
}
}
Expand Down Expand Up @@ -351,7 +352,17 @@ public void Vacuum()
cmd.ExecuteNonQuery("VACUUM");
}

public long RegisterRemoteVolume(string name, RemoteVolumeType type, RemoteVolumeState state, System.Data.IDbTransaction transaction = null)
public long RegisterRemoteVolume(string name, RemoteVolumeType type, RemoteVolumeState state)
{
return RegisterRemoteVolume(name, type, state, new TimeSpan(0), null);
}

public long RegisterRemoteVolume(string name, RemoteVolumeType type, RemoteVolumeState state, System.Data.IDbTransaction transaction)
{
return RegisterRemoteVolume(name, type, state, new TimeSpan(0), transaction);
}

public long RegisterRemoteVolume(string name, RemoteVolumeType type, RemoteVolumeState state, TimeSpan deleteGraceTime, System.Data.IDbTransaction transaction)
{
using(var tr = new TemporaryTransactionWrapper(m_connection, transaction))
{
Expand All @@ -360,6 +371,12 @@ public long RegisterRemoteVolume(string name, RemoteVolumeType type, RemoteVolum
m_createremotevolumeCommand.SetParameterValue(2, type.ToString());
m_createremotevolumeCommand.SetParameterValue(3, state.ToString());
m_createremotevolumeCommand.SetParameterValue(4, 0);

if (deleteGraceTime.Ticks <= 0)
m_createremotevolumeCommand.SetParameterValue(5, 0);
else
m_createremotevolumeCommand.SetParameterValue(5, (DateTime.UtcNow + deleteGraceTime).Ticks);

m_createremotevolumeCommand.Transaction = tr.Parent;
var r = m_createremotevolumeCommand.ExecuteScalarInt64();
tr.Commit();
Expand Down
5 changes: 4 additions & 1 deletion Duplicati/Library/Main/Database/RemoteVolumeEntry.cs
Expand Up @@ -12,20 +12,23 @@ public struct RemoteVolumeEntry : IRemoteVolume
private readonly long m_size;
private readonly RemoteVolumeType m_type;
private readonly RemoteVolumeState m_state;
private readonly DateTime m_deleteGracePeriod;

public string Name { get { return m_name; } }
public string Hash { get { return m_hash; } }
public long Size { get { return m_size; } }
public RemoteVolumeType Type { get { return m_type; } }
public RemoteVolumeState State { get { return m_state; } }
public DateTime deleteGracePeriod { get { return m_deleteGracePeriod; } }

public RemoteVolumeEntry(string name, string hash, long size, RemoteVolumeType type, RemoteVolumeState state)
public RemoteVolumeEntry(string name, string hash, long size, RemoteVolumeType type, RemoteVolumeState state, DateTime deleteGracePeriod)
{
m_name = name;
m_size = size;
m_type = type;
m_state = state;
m_hash = hash;
m_deleteGracePeriod = deleteGracePeriod;
}
}
}
1 change: 1 addition & 0 deletions Duplicati/Library/Main/Duplicati.Library.Main.csproj
Expand Up @@ -151,6 +151,7 @@
<EmbeddedResource Include="Database\Database schema\Schema.sql" />
<EmbeddedResource Include="Database\Database schema\1. Add index.sql" />
<EmbeddedResource Include="Database\Database schema\2. Use Lastmodified.sql" />
<EmbeddedResource Include="Database\Database schema\3. Add grace delete period.sql" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Expand Down
1 change: 1 addition & 0 deletions Duplicati/Library/Main/Operation/BackupHandler.cs
Expand Up @@ -397,6 +397,7 @@ orderby n.Key

foreach(var blockfile in m_database.GetMissingIndexFiles())
{
m_result.AddMessage(string.Format("Re-creating missing index file for {0}", blockfile));
var w = new IndexVolumeWriter(m_options);
w.VolumeID = m_database.RegisterRemoteVolume(w.RemoteFilename, RemoteVolumeType.Index, RemoteVolumeState.Temporary, null);

Expand Down
14 changes: 11 additions & 3 deletions Duplicati/Library/Main/Operation/FilelistProcessor.cs
Expand Up @@ -242,8 +242,15 @@ public static RemoteAnalysisResult RemoteListAnalysis(BackendManager backend, Op
}
else
{
log.AddMessage(string.Format("removing file listed as {0}: {1}", i.State, i.Name));
database.RemoveRemoteVolume(i.Name, null);
if (i.deleteGracePeriod > DateTime.UtcNow)
{
log.AddMessage(string.Format("keeping delete request for {0} until {1}", i.Name, i.deleteGracePeriod.ToLocalTime()));
}
else
{
log.AddMessage(string.Format("removing file listed as {0}: {1}", i.State, i.Name));
database.RemoveRemoteVolume(i.Name, null);
}
}
break;
case RemoteVolumeState.Uploading:
Expand All @@ -256,7 +263,8 @@ public static RemoteAnalysisResult RemoteListAnalysis(BackendManager backend, Op
{
log.AddMessage(string.Format("scheduling missing file for deletion, currently listed as {0}: {1}", i.State, i.Name));
database.RemoveRemoteVolume(i.Name, null);
database.RegisterRemoteVolume(i.Name, i.Type, RemoteVolumeState.Deleting, null);
database.RegisterRemoteVolume(i.Name, i.Type, RemoteVolumeState.Deleting, TimeSpan.FromHours(2), null);
database.UpdateRemoteVolume(i.Name, RemoteVolumeState.Deleting, i.Size, i.Hash, null);
}
else
{
Expand Down

1 comment on commit 0de9adc

@duplicatibot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit has been mentioned on Duplicati. There might be relevant details there:

https://forum.duplicati.com/t/client-verification-file-contains-expired-files/13459/2

Please sign in to comment.