← Back to team overview

duplicity-team team mailing list archive

[Merge] lp:~yajo/duplicity/duplicity into lp:duplicity/0.7-series

 

Yajo has proposed merging lp:~yajo/duplicity/duplicity into lp:duplicity/0.7-series.

Requested reviews:
  duplicity-team (duplicity-team)

For more details, see:
https://code.launchpad.net/~yajo/duplicity/duplicity/+merge/366358

Support partial metadata sync.

Fixes bug #1823858 by letting the user to choose partial syncing. Only the metadata for the target chain will be downloaded. If older (or newer) chains are encrypted with a different passphrase, the user will be able to restore to a given time by supplying only the passphrase for the chain selected by the `--restore-time` option when using this new option.

A side effect is that using this flag reduces dramatically the sync time when moving files from one to another location, in cases where big amounts of chains are found. 
-- 
Your team duplicity-team is requested to review the proposed merge of lp:~yajo/duplicity/duplicity into lp:duplicity/0.7-series.
=== modified file 'bin/duplicity'
--- bin/duplicity	2018-09-28 13:55:53 +0000
+++ bin/duplicity	2019-04-22 12:44:43 +0000
@@ -1020,7 +1020,7 @@
                    _("Rerun command with --force option to actually delete."))
 
 
-def sync_archive():
+def sync_archive(col_stats):
     """
     Synchronize local archive manifest file and sig chains to remote archives.
     Copy missing files from remote to local as needed to make sure the local
@@ -1031,6 +1031,27 @@
     """
     suffixes = [".g", ".gpg", ".z", ".gz", ".part"]
 
+    def is_needed(filename):
+        """Indicates if the metadata file should be synced.
+
+        In full sync mode, or if there's a collection misbehavior, all files
+        are needed.
+
+        Otherwise, only the metadata for the target chain needs sync.
+        """
+        if globals.metadata_sync_mode == "full":
+            return True
+        assert globals.metadata_sync_mode == "partial"
+        parsed = file_naming.parse(filename)
+        try:
+            target_chain = col_stats.get_backup_chain_at_time(
+                globals.restore_time or dup_time.curtime)
+        except collections.CollectionsError:
+            # With zero or multiple chains at this time, do a full sync
+            return True
+        return parsed.end_time >= target_chain.start_time and \
+            parsed.start_time <= target_chain.end_time
+
     def get_metafiles(filelist):
         """
         Return metafiles of interest from the file list.
@@ -1174,13 +1195,14 @@
 
     local_missing = []
     local_spurious = []
+    import pudb; pudb.set_trace()
 
     for key in remote_keys:
         # If we lost our cache, re-get the remote file.  But don't do it if we
         # already have a local partial.  The local partial will already be
         # complete in this case (seems we got interrupted before we could move
         # it to its final location).
-        if key not in local_keys and key not in local_partials:
+        if key not in local_keys and key not in local_partials and is_needed(key):
             local_missing.append(remote_metafiles[key])
 
     for key in local_keys:
@@ -1414,15 +1436,15 @@
     # check for disk space and available file handles
     check_resources(action)
 
-    # check archive synch with remote, fix if needed
-    if action not in ["collection-status"]:
-        sync_archive()
-
     # get current collection status
     col_stats = collections.CollectionsStatus(globals.backend,
                                               globals.archive_dir,
                                               action).set_values()
 
+    # check archive synch with remote, fix if needed
+    if action not in ["collection-status"]:
+        sync_archive(col_stats)
+
     while True:
         # if we have to clean up the last partial, then col_stats are invalidated
         # and we have to start the process all over again until clean.
@@ -1488,7 +1510,7 @@
     elif action == "remove-all-but-n-full" or action == "remove-all-inc-of-but-n-full":
         remove_all_but_n_full(col_stats)
     elif action == "sync":
-        sync_archive()
+        sync_archive(col_stats)
     else:
         assert action == "inc" or action == "full", action
         # the passphrase for full and inc is used by --sign-key

=== modified file 'bin/duplicity.1'
--- bin/duplicity.1	2019-01-26 16:37:54 +0000
+++ bin/duplicity.1	2019-04-22 12:44:43 +0000
@@ -882,6 +882,14 @@
 .BR "A NOTE ON SSL CERTIFICATE VERIFICATION" .
 
 .TP
+.BI "--metadata-sync-mode " mode
+This option defaults to 'full', but you can set it to 'partial'
+to avoid syncing metadata for backup chains that you are not going to use.
+This saves time when restoring for the first time, and lets you restore an
+old backup that was encrypted with a different passphrase by supplying only
+the target passphrase.
+
+.TP
 .BI "--tempdir " directory
 Use this existing directory for duplicity temporary files instead of
 the system default, which is usually the /tmp directory. This option

=== modified file 'duplicity/collections.py'
--- duplicity/collections.py	2018-02-01 21:17:08 +0000
+++ duplicity/collections.py	2019-04-22 12:44:43 +0000
@@ -24,7 +24,7 @@
 from future_builtins import filter, map
 
 import types
-import gettext
+from gettext import gettext as _
 
 
 from duplicity import log

=== modified file 'duplicity/commandline.py'
--- duplicity/commandline.py	2018-02-01 21:17:08 +0000
+++ duplicity/commandline.py	2019-04-22 12:44:43 +0000
@@ -491,6 +491,11 @@
                       callback=lambda o, s, v, p: (setattr(p.values, o.dest, True),
                                                    old_fn_deprecation(s)))
 
+    # Sync only required metadata
+    parser.add_option("--metadata-sync-mode",
+                      default="full",
+                      choices=("full", "partial"))
+
     # Level of Redundancy in % for Par2 files
     parser.add_option("--par2-redundancy", type="int", metavar=_("number"))
 

=== modified file 'duplicity/globals.py'
--- duplicity/globals.py	2018-02-01 21:17:08 +0000
+++ duplicity/globals.py	2019-04-22 12:44:43 +0000
@@ -225,6 +225,9 @@
 # Can be changed with a command line argument.
 imap_mailbox = "INBOX"
 
+# Sync all metadata by default
+metadata_sync_mode = "full"
+
 # Whether the old filename format is in effect.
 old_filenames = False
 


Follow ups