Browse Source

transfer: all hardlinks have chunks, maybe chunks_healty, hlid

Item.hlid: same id, same hardlink (xxh64 digest)
Item.hardlink_master: not used for new archives any more
Item.source: not used for hardlink slaves any more
Thomas Waldmann 3 years ago
parent
commit
e4a97ea8cc
3 changed files with 18 additions and 2 deletions
  1. 15 0
      src/borg/archiver.py
  2. 1 1
      src/borg/constants.py
  3. 2 1
      src/borg/item.pyx

+ 15 - 0
src/borg/archiver.py

@@ -347,6 +347,20 @@ class Archiver:
 
 
         def upgrade_item(item):
         def upgrade_item(item):
             """upgrade item as needed, get rid of legacy crap"""
             """upgrade item as needed, get rid of legacy crap"""
+            if item.get('hardlink_master', True) and 'source' not in item and hardlinkable(item.mode):
+                item._dict['hlid'] = hlid = hashlib.sha256(item._dict['path'])
+                hardlink_masters[hlid] = (item._dict.get('chunks'), item._dict.get('chunks_healthy'))
+            elif 'source' in item and hardlinkable(item.mode):
+                item._dict['hlid'] = hlid = hashlib.sha256(item._dict['source'])
+                chunks, chunks_healthy = hardlink_masters.get(hlid, (None, None))
+                if chunks is not None:
+                    item._dict['chunks'] = chunks
+                    for chunk_id, _, _ in chunks:
+                        cache.chunk_incref(chunk_id, archive.stats)
+                if chunks_healthy is not None:
+                    item._dict['chunks_healthy'] = chunks
+                item._dict.pop('source')  # not used for hardlinks any more, replaced by hlid
+            item._dict.pop('hardlink_master', None)  # not used for hardlinks any more, replaced by hlid
             item._dict.pop('acl', None)  # remove remnants of bug in attic <= 0.13
             item._dict.pop('acl', None)  # remove remnants of bug in attic <= 0.13
             item.get_size(memorize=True)  # if not already present: compute+remember size for items with chunks
             item.get_size(memorize=True)  # if not already present: compute+remember size for items with chunks
             return item
             return item
@@ -371,6 +385,7 @@ class Archiver:
             else:
             else:
                 if not dry_run:
                 if not dry_run:
                     print(f"{name}: copying archive to destination repo...")
                     print(f"{name}: copying archive to destination repo...")
+                hardlink_masters = {}
                 other_archive = Archive(other_repository, other_key, other_manifest, name)
                 other_archive = Archive(other_repository, other_key, other_manifest, name)
                 archive = Archive(repository, key, manifest, name, cache=cache, create=True) if not dry_run else None
                 archive = Archive(repository, key, manifest, name, cache=cache, create=True) if not dry_run else None
                 for item in other_archive.iter_items():
                 for item in other_archive.iter_items():

+ 1 - 1
src/borg/constants.py

@@ -1,5 +1,5 @@
 # this set must be kept complete, otherwise the RobustUnpacker might malfunction:
 # this set must be kept complete, otherwise the RobustUnpacker might malfunction:
-ITEM_KEYS = frozenset(['path', 'source', 'rdev', 'chunks', 'chunks_healthy', 'hardlink_master',
+ITEM_KEYS = frozenset(['path', 'source', 'rdev', 'chunks', 'chunks_healthy', 'hardlink_master', 'hlid',
                        'mode', 'user', 'group', 'uid', 'gid', 'mtime', 'atime', 'ctime', 'birthtime', 'size',
                        'mode', 'user', 'group', 'uid', 'gid', 'mtime', 'atime', 'ctime', 'birthtime', 'size',
                        'xattrs', 'bsdflags', 'acl_nfs4', 'acl_access', 'acl_default', 'acl_extended',
                        'xattrs', 'bsdflags', 'acl_nfs4', 'acl_access', 'acl_default', 'acl_extended',
                        'part'])
                        'part'])

+ 2 - 1
src/borg/item.pyx

@@ -181,7 +181,8 @@ class Item(PropDict):
     # compatibility note: this is a new feature, in old archives size will be missing.
     # compatibility note: this is a new feature, in old archives size will be missing.
     size = PropDict._make_property('size', int)
     size = PropDict._make_property('size', int)
 
 
-    hardlink_master = PropDict._make_property('hardlink_master', bool)
+    hlid = PropDict._make_property('hlid', bytes)  # hard link id: same value means same hard link.
+    hardlink_master = PropDict._make_property('hardlink_master', bool)  # legacy
 
 
     chunks = PropDict._make_property('chunks', (list, type(None)), 'list or None')
     chunks = PropDict._make_property('chunks', (list, type(None)), 'list or None')
     chunks_healthy = PropDict._make_property('chunks_healthy', (list, type(None)), 'list or None')
     chunks_healthy = PropDict._make_property('chunks_healthy', (list, type(None)), 'list or None')