diff --git a/Duplicati/Library/Main/Controller.cs b/Duplicati/Library/Main/Controller.cs
index aee18ac5a..4d59fe2bc 100644
--- a/Duplicati/Library/Main/Controller.cs
+++ b/Duplicati/Library/Main/Controller.cs
@@ -82,6 +82,11 @@ namespace Duplicati.Library.Main
///
private ControllerMultiLogTarget m_logTarget;
+ ///
+ /// Time of last compact operation
+ ///
+ private DateTime m_lastcompact;
+
///
/// Constructs a new interface for performing backup and restore operations
///
@@ -111,7 +116,13 @@ namespace Duplicati.Library.Main
Library.UsageReporter.Reporter.Report("USE_BACKEND", new Library.Utility.Uri(m_backend).Scheme);
Library.UsageReporter.Reporter.Report("USE_COMPRESSION", m_options.CompressionModule);
Library.UsageReporter.Reporter.Report("USE_ENCRYPTION", m_options.EncryptionModule);
-
+
+ if (!m_options.NoAutoCompact && (m_lastcompact > DateTime.MinValue) && (m_lastcompact.Add(m_options.AutoCompactInterval) > DateTime.Now))
+ {
+ Logging.Log.WriteInformationMessage(LOGTAG, "CompactResults", "AutoCompactInterval not satisfied, skipping auto compaction for this backup");
+ m_options.RawOptions["no-auto-compact"] = "true";
+ }
+
return RunAction(new BackupResults(), ref inputsources, ref filter, (result) => {
using (var h = new Operation.BackupHandler(m_backend, m_options, result))
@@ -1097,6 +1108,12 @@ namespace Duplicati.Library.Main
set { m_options.MaxDownloadPrSecond = value; }
}
+ public DateTime LastCompact
+ {
+ get { return m_lastcompact; }
+ set { m_lastcompact = value; }
+ }
+
#region IDisposable Members
public void Dispose()
diff --git a/Duplicati/Library/Main/Options.cs b/Duplicati/Library/Main/Options.cs
index 7e0daa9e2..225cffa45 100644
--- a/Duplicati/Library/Main/Options.cs
+++ b/Duplicati/Library/Main/Options.cs
@@ -405,6 +405,7 @@ namespace Duplicati.Library.Main
new CommandLineArgument("restore-symlink-metadata", CommandLineArgument.ArgumentType.Boolean, Strings.Options.RestoresymlinkmetadataShort, Strings.Options.RestoresymlinkmetadataLong, "false"),
new CommandLineArgument("rebuild-missing-dblock-files", CommandLineArgument.ArgumentType.Boolean, Strings.Options.RebuildmissingdblockfilesShort, Strings.Options.RebuildmissingdblockfilesLong, "false"),
+ new CommandLineArgument("auto-compact-interval", CommandLineArgument.ArgumentType.Timespan, Strings.Options.AutoCompactIntervalShort, Strings.Options.AutoCompactIntervalLong, "0s"),
});
return lst;
@@ -1634,6 +1635,20 @@ namespace Duplicati.Library.Main
get { return Library.Utility.Utility.ParseBoolOption(m_options, "no-auto-compact"); }
}
+ ///
+ /// Gets the minimum time that must elapse after last compaction before running next automatic compaction
+ ///
+ public TimeSpan AutoCompactInterval
+ {
+ get
+ {
+ if (!m_options.ContainsKey("auto-compact-interval") || string.IsNullOrEmpty(m_options["auto-compact-interval"]))
+ return TimeSpan.Zero;
+ else
+ return Library.Utility.Timeparser.ParseTimeSpan(m_options["auto-compact-interval"]);
+ }
+ }
+
///
/// Gets a flag indicating if compacting should not be done automatically
///
diff --git a/Duplicati/Library/Main/Strings.cs b/Duplicati/Library/Main/Strings.cs
index b6bb5fecb..77ad42e45 100644
--- a/Duplicati/Library/Main/Strings.cs
+++ b/Duplicati/Library/Main/Strings.cs
@@ -279,6 +279,9 @@ namespace Duplicati.Library.Main.Strings
public static string ProfilealldatabasequeriesLong { get { return LC.L("To improve performance of the backups, frequent database queries are not logged by default. Enable this option to log all database queries, and remember to set either --{0}={2} or --{1}={2} to report the additional log data", "console-log-level", "log-file-log-level", nameof(Logging.LogMessageType.Profiling)); } }
public static string RebuildmissingdblockfilesShort { get { return "Rebuild dblock files when missing"; } }
public static string RebuildmissingdblockfilesLong { get { return "If dblock files are missing from the destination, you can attempt to rebuild them using local source data. However, since the local data may have changed, it may not be possible to retrieve all the required data and the process may be slow. Use this option to attempt to rebuild missing dblock files."; } }
+
+ public static string AutoCompactIntervalShort { get { return "Minimum time between auto compactions"; } }
+ public static string AutoCompactIntervalLong { get { return "The minimum amount of time that must elapse after the last compaction before another will be automatically triggered at the end of a backup job. Automatic compaction can be a long-running process and may not be desirable to run after every single backup."; } }
}
internal static class Common
diff --git a/Duplicati/Server/Runner.cs b/Duplicati/Server/Runner.cs
index 9e245c5d4..a1a279353 100644
--- a/Duplicati/Server/Runner.cs
+++ b/Duplicati/Server/Runner.cs
@@ -503,6 +503,9 @@ namespace Duplicati.Server
where !string.IsNullOrWhiteSpace(p)
select p).ToArray();
+ if (backup.Metadata.ContainsKey("LastCompactFinished"))
+ controller.LastCompact = Library.Utility.Utility.DeserializeDateTime(backup.Metadata["LastCompactFinished"]);
+
var r = controller.Backup(sources, filter);
UpdateMetadata(backup, r);
return r;
@@ -545,7 +548,7 @@ namespace Duplicati.Server
}
case DuplicatiOperation.Compact:
{
- var r = controller.Compact();
+ var r = controller.Compact();
UpdateMetadata(backup, r);
return r;
}
@@ -724,6 +727,14 @@ namespace Duplicati.Server
backup.Metadata["LastRestoreFinished"] = Library.Utility.Utility.SerializeDateTime(result.EndTime.ToUniversalTime());
}
+ if (result is Duplicati.Library.Interface.ICompactResults)
+ {
+ var r = (Duplicati.Library.Interface.ICompactResults)result;
+ backup.Metadata["LastCompactDuration"] = r.Duration.ToString();
+ backup.Metadata["LastCompactStarted"] = Library.Utility.Utility.SerializeDateTime(r.BeginTime.ToUniversalTime());
+ backup.Metadata["LastCompactFinished"] = Library.Utility.Utility.SerializeDateTime(r.EndTime.ToUniversalTime());
+ }
+
if (result is Duplicati.Library.Interface.IParsedBackendStatistics)
{
var r = (Duplicati.Library.Interface.IParsedBackendStatistics)result;
@@ -747,6 +758,9 @@ namespace Duplicati.Server
backup.Metadata["LastBackupFinished"] = Library.Utility.Utility.SerializeDateTime(result.EndTime.ToUniversalTime());
backup.Metadata["LastBackupDuration"] = r.Duration.ToString();
+ if (r.CompactResults != null)
+ UpdateMetadata(backup, r.CompactResults);
+
if (r.FilesWithError > 0 || r.Warnings.Any() || r.Errors.Any())
{
Program.DataConnection.RegisterNotification(