Pārlūkot izejas kodu

remove csize from ChunkIndexEntry

Thomas Waldmann 3 gadi atpakaļ
vecāks
revīzija
2c1f7951c4

+ 9 - 5
src/borg/archive.py

@@ -483,6 +483,10 @@ class Archive:
     def duration_from_meta(self):
         return format_timedelta(self.ts_end - self.ts)
 
+    def _archive_csize(self):
+        cdata = self.repository.get(self.id)
+        return len(cdata)
+
     def info(self):
         if self.create:
             stats = self.stats
@@ -500,7 +504,7 @@ class Archive:
             'duration': (end - start).total_seconds(),
             'stats': stats.as_dict(),
             'limits': {
-                'max_archive_size': self.cache.chunks[self.id].csize / MAX_DATA_SIZE,
+                'max_archive_size': self._archive_csize() / MAX_DATA_SIZE,
             },
         }
         if self.create:
@@ -529,7 +533,7 @@ Utilization of max. archive size: {csize_max:.0%}
             self,
             start=OutputTimestamp(self.start.replace(tzinfo=timezone.utc)),
             end=OutputTimestamp(self.end.replace(tzinfo=timezone.utc)),
-            csize_max=self.cache.chunks[self.id].csize / MAX_DATA_SIZE,
+            csize_max=self._archive_csize() / MAX_DATA_SIZE,
             location=self.repository._location.canonical_path()
 )
 
@@ -1561,7 +1565,7 @@ class ArchiveChecker:
             if not result:
                 break
             marker = result[-1]
-            init_entry = ChunkIndexEntry(refcount=0, size=0, csize=0)
+            init_entry = ChunkIndexEntry(refcount=0, size=0)
             for id_ in result:
                 self.chunks[id_] = init_entry
 
@@ -1718,7 +1722,7 @@ class ArchiveChecker:
         self.chunks.pop(Manifest.MANIFEST_ID, None)
 
         def mark_as_possibly_superseded(id_):
-            if self.chunks.get(id_, ChunkIndexEntry(0, 0, 0)).refcount == 0:
+            if self.chunks.get(id_, ChunkIndexEntry(0, 0)).refcount == 0:
                 self.possibly_superseded.add(id_)
 
         def add_callback(chunk):
@@ -1732,7 +1736,7 @@ class ArchiveChecker:
                 self.chunks.incref(id_)
             except KeyError:
                 assert cdata is not None
-                self.chunks[id_] = ChunkIndexEntry(refcount=1, size=size, csize=0)  # was: csize=csize
+                self.chunks[id_] = ChunkIndexEntry(refcount=1, size=size)
                 if self.repair:
                     self.repository.put(id_, cdata)
 

+ 11 - 13
src/borg/cache.py

@@ -713,13 +713,13 @@ class LocalCache(CacheStatsMixin):
             nonlocal processed_item_metadata_bytes
             nonlocal processed_item_metadata_chunks
             csize, data = decrypted_repository.get(archive_id)
-            chunk_idx.add(archive_id, 1, len(data), csize)
+            chunk_idx.add(archive_id, 1, len(data))
             archive = ArchiveItem(internal_dict=msgpack.unpackb(data))
             if archive.version not in (1, 2):  # legacy
                 raise Exception('Unknown archive metadata version')
             sync = CacheSynchronizer(chunk_idx)
             for item_id, (csize, data) in zip(archive.items, decrypted_repository.get_many(archive.items)):
-                chunk_idx.add(item_id, 1, len(data), csize)
+                chunk_idx.add(item_id, 1, len(data))
                 processed_item_metadata_bytes += len(data)
                 processed_item_metadata_chunks += 1
                 sync.feed(data)
@@ -903,14 +903,13 @@ class LocalCache(CacheStatsMixin):
         if size is None:
             raise ValueError("when giving compressed data for a new chunk, the uncompressed size must be given also")
         data = self.key.encrypt(id, chunk, compress=compress)
-        csize = 0  # len(data)
         self.repository.put(id, data, wait=wait)
-        self.chunks.add(id, 1, size, csize)
+        self.chunks.add(id, 1, size)
         stats.update(size)
         return ChunkListEntry(id, size)
 
     def seen_chunk(self, id, size=None):
-        refcount, stored_size, _ = self.chunks.get(id, ChunkIndexEntry(0, None, None))
+        refcount, stored_size = self.chunks.get(id, ChunkIndexEntry(0, None))
         if size is not None and stored_size is not None and size != stored_size:
             # we already have a chunk with that id, but different size.
             # this is either a hash collision (unlikely) or corruption or a bug.
@@ -921,14 +920,14 @@ class LocalCache(CacheStatsMixin):
     def chunk_incref(self, id, stats, size=None, part=False):
         if not self.txn_active:
             self.begin_txn()
-        count, _size, _ = self.chunks.incref(id)
+        count, _size = self.chunks.incref(id)
         stats.update(_size, part=part)
         return ChunkListEntry(id, _size)
 
     def chunk_decref(self, id, stats, wait=True, part=False):
         if not self.txn_active:
             self.begin_txn()
-        count, size, _ = self.chunks.decref(id)
+        count, size = self.chunks.decref(id)
         if count == 0:
             del self.chunks[id]
             self.repository.delete(id, wait=wait)
@@ -1071,16 +1070,15 @@ Chunk index:    {0.total_unique_chunks:20d}             unknown"""
         if refcount:
             return self.chunk_incref(id, stats, size=size)
         data = self.key.encrypt(id, chunk, compress=compress)
-        csize = len(data)
         self.repository.put(id, data, wait=wait)
-        self.chunks.add(id, 1, size, csize)
+        self.chunks.add(id, 1, size)
         stats.update(size)
         return ChunkListEntry(id, size)
 
     def seen_chunk(self, id, size=None):
         if not self._txn_active:
             self.begin_txn()
-        entry = self.chunks.get(id, ChunkIndexEntry(0, None, None))
+        entry = self.chunks.get(id, ChunkIndexEntry(0, None))
         if entry.refcount and size and not entry.size:
             # The LocalCache has existing size information and uses *size* to make an effort at detecting collisions.
             # This is of course not possible for the AdHocCache.
@@ -1091,7 +1089,7 @@ Chunk index:    {0.total_unique_chunks:20d}             unknown"""
     def chunk_incref(self, id, stats, size=None, part=False):
         if not self._txn_active:
             self.begin_txn()
-        count, _size, csize = self.chunks.incref(id)
+        count, _size = self.chunks.incref(id)
         # When _size is 0 and size is not given, then this chunk has not been locally visited yet (seen_chunk with
         # size or add_chunk); we can't add references to those (size=0 is invalid) and generally don't try to.
         size = _size or size
@@ -1102,7 +1100,7 @@ Chunk index:    {0.total_unique_chunks:20d}             unknown"""
     def chunk_decref(self, id, stats, wait=True, part=False):
         if not self._txn_active:
             self.begin_txn()
-        count, size, csize = self.chunks.decref(id)
+        count, size = self.chunks.decref(id)
         if count == 0:
             del self.chunks[id]
             self.repository.delete(id, wait=wait)
@@ -1142,7 +1140,7 @@ Chunk index:    {0.total_unique_chunks:20d}             unknown"""
             # All chunks from the repository have a refcount of MAX_VALUE, which is sticky,
             # therefore we can't/won't delete them. Chunks we added ourselves in this transaction
             # (e.g. checkpoint archives) are tracked correctly.
-            init_entry = ChunkIndexEntry(refcount=ChunkIndex.MAX_VALUE, size=0, csize=0)
+            init_entry = ChunkIndexEntry(refcount=ChunkIndex.MAX_VALUE, size=0)
             for id_ in result:
                 self.chunks[id_] = init_entry
         assert len(self.chunks) == num_chunks

+ 0 - 1
src/borg/cache_sync/unpack.h

@@ -279,7 +279,6 @@ static inline int unpack_callback_array_end(unpack_user* u)
             /* refcount, size */
             cache_values[0] = _htole32(1);
             cache_values[1] = _htole32(u->current.size);
-            cache_values[2] = _htole32(0);  /* fake csize for now */
             if(!hashindex_set(u->chunks, u->current.key, cache_values)) {
                 SET_LAST_ERROR("hashindex_set failed");
                 return -1;

+ 13 - 32
src/borg/hashindex.pyx

@@ -269,12 +269,12 @@ cdef class NSKeyIterator:
         return (<char *>self.key)[:self.key_size], (segment, _le32toh(value[1]))
 
 
-ChunkIndexEntry = namedtuple('ChunkIndexEntry', 'refcount size csize')
+ChunkIndexEntry = namedtuple('ChunkIndexEntry', 'refcount size')
 
 
 cdef class ChunkIndex(IndexBase):
     """
-    Mapping of 32 byte keys to (refcount, size, csize), which are all 32-bit unsigned.
+    Mapping of 32 byte keys to (refcount, size), which are all 32-bit unsigned.
 
     The reference count cannot overflow. If an overflow would occur, the refcount
     is fixed to MAX_VALUE and will neither increase nor decrease by incref(), decref()
@@ -289,7 +289,7 @@ cdef class ChunkIndex(IndexBase):
     Assigning refcounts in this reserved range is an invalid operation and raises AssertionError.
     """
 
-    value_size = 12
+    value_size = 8
 
     def __getitem__(self, key):
         assert len(key) == self.key_size
@@ -298,16 +298,15 @@ cdef class ChunkIndex(IndexBase):
             raise KeyError(key)
         cdef uint32_t refcount = _le32toh(data[0])
         assert refcount <= _MAX_VALUE, "invalid reference count"
-        return ChunkIndexEntry(refcount, _le32toh(data[1]), _le32toh(data[2]))
+        return ChunkIndexEntry(refcount, _le32toh(data[1]))
 
     def __setitem__(self, key, value):
         assert len(key) == self.key_size
-        cdef uint32_t[3] data
+        cdef uint32_t[2] data
         cdef uint32_t refcount = value[0]
         assert refcount <= _MAX_VALUE, "invalid reference count"
         data[0] = _htole32(refcount)
         data[1] = _htole32(value[1])
-        data[2] = _htole32(value[2])
         if not hashindex_set(self.index, <unsigned char *>key, data):
             raise Exception('hashindex_set failed')
 
@@ -319,7 +318,7 @@ cdef class ChunkIndex(IndexBase):
         return data != NULL
 
     def incref(self, key):
-        """Increase refcount for 'key', return (refcount, size, csize)"""
+        """Increase refcount for 'key', return (refcount, size)"""
         assert len(key) == self.key_size
         data = <uint32_t *>hashindex_get(self.index, <unsigned char *>key)
         if not data:
@@ -329,10 +328,10 @@ cdef class ChunkIndex(IndexBase):
         if refcount != _MAX_VALUE:
             refcount += 1
         data[0] = _htole32(refcount)
-        return refcount, _le32toh(data[1]), _le32toh(data[2])
+        return refcount, _le32toh(data[1])
 
     def decref(self, key):
-        """Decrease refcount for 'key', return (refcount, size, csize)"""
+        """Decrease refcount for 'key', return (refcount, size)"""
         assert len(key) == self.key_size
         data = <uint32_t *>hashindex_get(self.index, <unsigned char *>key)
         if not data:
@@ -343,7 +342,7 @@ cdef class ChunkIndex(IndexBase):
         if refcount != _MAX_VALUE:
             refcount -= 1
         data[0] = _htole32(refcount)
-        return refcount, _le32toh(data[1]), _le32toh(data[2])
+        return refcount, _le32toh(data[1])
 
     def iteritems(self, marker=None):
         cdef const unsigned char *key
@@ -390,7 +389,7 @@ cdef class ChunkIndex(IndexBase):
         size, unique_size, unique_chunks, chunks.
         """
         cdef uint64_t size = 0, unique_size = 0, chunks = 0, unique_chunks = 0
-        cdef uint32_t our_refcount, chunk_size, chunk_csize
+        cdef uint32_t our_refcount, chunk_size
         cdef const uint32_t *our_values
         cdef const uint32_t *master_values
         cdef const unsigned char *key = NULL
@@ -416,12 +415,11 @@ cdef class ChunkIndex(IndexBase):
 
         return size, unique_size, unique_chunks, chunks
 
-    def add(self, key, refs, size, csize):
+    def add(self, key, refs, size):
         assert len(key) == self.key_size
-        cdef uint32_t[3] data
+        cdef uint32_t[2] data
         data[0] = _htole32(refs)
         data[1] = _htole32(size)
-        data[2] = _htole32(csize)
         self._add(<unsigned char*> key, data)
 
     cdef _add(self, unsigned char *key, uint32_t *data):
@@ -435,7 +433,6 @@ cdef class ChunkIndex(IndexBase):
             result64 = refcount1 + refcount2
             values[0] = _htole32(min(result64, _MAX_VALUE))
             values[1] = data[1]
-            values[2] = data[2]
         else:
             if not hashindex_set(self.index, key, data):
                 raise Exception('hashindex_set failed')
@@ -449,22 +446,6 @@ cdef class ChunkIndex(IndexBase):
                 break
             self._add(key, <uint32_t*> (key + self.key_size))
 
-    def zero_csize_ids(self):
-        cdef unsigned char *key = NULL
-        cdef uint32_t *values
-        entries = []
-        while True:
-            key = hashindex_next_key(self.index, key)
-            if not key:
-                break
-            values = <uint32_t*> (key + self.key_size)
-            refcount = _le32toh(values[0])
-            assert refcount <= _MAX_VALUE, "invalid reference count"
-            if _le32toh(values[2]) == 0:
-                # csize == 0
-                entries.append(PyBytes_FromStringAndSize(<char*> key, self.key_size))
-        return entries
-
 
 cdef class ChunkKeyIterator:
     cdef ChunkIndex idx
@@ -491,7 +472,7 @@ cdef class ChunkKeyIterator:
         cdef uint32_t *value = <uint32_t *>(self.key + self.key_size)
         cdef uint32_t refcount = _le32toh(value[0])
         assert refcount <= _MAX_VALUE, "invalid reference count"
-        return (<char *>self.key)[:self.key_size], ChunkIndexEntry(refcount, _le32toh(value[1]), _le32toh(value[2]))
+        return (<char *>self.key)[:self.key_size], ChunkIndexEntry(refcount, _le32toh(value[1]))
 
 
 cdef Py_buffer ro_buffer(object data) except *:

+ 3 - 3
src/borg/testsuite/archiver.py

@@ -2885,12 +2885,12 @@ class ArchiverTestCase(ArchiverTestCaseBase):
                 correct_chunks = cache.chunks
         assert original_chunks is not correct_chunks
         seen = set()
-        for id, (refcount, size, _) in correct_chunks.iteritems():
-            o_refcount, o_size, _ = original_chunks[id]
+        for id, (refcount, size) in correct_chunks.iteritems():
+            o_refcount, o_size = original_chunks[id]
             assert refcount == o_refcount
             assert size == o_size
             seen.add(id)
-        for id, (refcount, size, _) in original_chunks.iteritems():
+        for id, (refcount, size) in original_chunks.iteritems():
             assert id in seen
 
     def test_check_cache(self):

+ 8 - 8
src/borg/testsuite/cache.py

@@ -49,8 +49,8 @@ class TestCacheSynchronizer:
         })
         sync.feed(data)
         assert len(index) == 2
-        assert index[H(1)] == (1, 1, 0)
-        assert index[H(2)] == (1, 2, 0)
+        assert index[H(1)] == (1, 1)
+        assert index[H(2)] == (1, 2)
 
     def test_multiple(self, index, sync):
         data = packb({
@@ -103,9 +103,9 @@ class TestCacheSynchronizer:
         sync.feed(part2)
         sync.feed(part3)
         assert len(index) == 3
-        assert index[H(1)] == (3, 1, 0)
-        assert index[H(2)] == (2, 2, 0)
-        assert index[H(3)] == (1, 1, 0)
+        assert index[H(1)] == (3, 1)
+        assert index[H(2)] == (2, 2)
+        assert index[H(3)] == (1, 1)
 
     @pytest.mark.parametrize('elem,error', (
         ({1: 2}, 'Unexpected object: map'),
@@ -189,7 +189,7 @@ class TestCacheSynchronizer:
             ]
         })
         sync.feed(data)
-        assert index[H(0)] == (ChunkIndex.MAX_VALUE, 1234, 5678)
+        assert index[H(0)] == (ChunkIndex.MAX_VALUE, 1234)
 
     def test_refcount_one_below_max_value(self):
         index = self.make_index_with_refcount(ChunkIndex.MAX_VALUE - 1)
@@ -201,9 +201,9 @@ class TestCacheSynchronizer:
         })
         sync.feed(data)
         # Incremented to maximum
-        assert index[H(0)] == (ChunkIndex.MAX_VALUE, 1234, 5678)
+        assert index[H(0)] == (ChunkIndex.MAX_VALUE, 1234)
         sync.feed(data)
-        assert index[H(0)] == (ChunkIndex.MAX_VALUE, 1234, 5678)
+        assert index[H(0)] == (ChunkIndex.MAX_VALUE, 1234)
 
 
 class TestAdHocCache:

+ 56 - 55
src/borg/testsuite/hashindex.py

@@ -91,8 +91,8 @@ class HashIndexTestCase(BaseTestCase):
                            '85f72b036c692c8266e4f51ccf0cff2147204282b5e316ae508d30a448d88fef')
 
     def test_chunkindex(self):
-        self._generic_test(ChunkIndex, lambda x: (x, x, x),
-                           'c83fdf33755fc37879285f2ecfc5d1f63b97577494902126b6fb6f3e4d852488')
+        self._generic_test(ChunkIndex, lambda x: (x, x),
+                           '85f72b036c692c8266e4f51ccf0cff2147204282b5e316ae508d30a448d88fef')
 
     def test_resize(self):
         n = 2000  # Must be >= MIN_BUCKETS
@@ -126,26 +126,26 @@ class HashIndexTestCase(BaseTestCase):
 
     def test_chunkindex_merge(self):
         idx1 = ChunkIndex()
-        idx1[H(1)] = 1, 100, 100
-        idx1[H(2)] = 2, 200, 200
-        idx1[H(3)] = 3, 300, 300
+        idx1[H(1)] = 1, 100
+        idx1[H(2)] = 2, 200
+        idx1[H(3)] = 3, 300
         # no H(4) entry
         idx2 = ChunkIndex()
-        idx2[H(1)] = 4, 100, 100
-        idx2[H(2)] = 5, 200, 200
+        idx2[H(1)] = 4, 100
+        idx2[H(2)] = 5, 200
         # no H(3) entry
-        idx2[H(4)] = 6, 400, 400
+        idx2[H(4)] = 6, 400
         idx1.merge(idx2)
-        assert idx1[H(1)] == (5, 100, 100)
-        assert idx1[H(2)] == (7, 200, 200)
-        assert idx1[H(3)] == (3, 300, 300)
-        assert idx1[H(4)] == (6, 400, 400)
+        assert idx1[H(1)] == (5, 100)
+        assert idx1[H(2)] == (7, 200)
+        assert idx1[H(3)] == (3, 300)
+        assert idx1[H(4)] == (6, 400)
 
     def test_chunkindex_summarize(self):
         idx = ChunkIndex()
-        idx[H(1)] = 1, 1000, 100
-        idx[H(2)] = 2, 2000, 200
-        idx[H(3)] = 3, 3000, 300
+        idx[H(1)] = 1, 1000
+        idx[H(2)] = 2, 2000
+        idx[H(3)] = 3, 3000
 
         size, unique_size, unique_chunks, chunks = idx.summarize()
         assert size == 1000 + 2 * 2000 + 3 * 3000
@@ -167,14 +167,14 @@ class HashIndexExtraTestCase(BaseTestCase):
         keys, to_delete_keys = all_keys[0:(2*key_count//3)], all_keys[(2*key_count//3):]
 
         for i, key in enumerate(keys):
-            index[key] = (i, i, i)
+            index[key] = (i, i)
         for i, key in enumerate(to_delete_keys):
-            index[key] = (i, i, i)
+            index[key] = (i, i)
 
         for key in to_delete_keys:
             del index[key]
         for i, key in enumerate(keys):
-            assert index[key] == (i, i, i)
+            assert index[key] == (i, i)
         for key in to_delete_keys:
             assert index.get(key) is None
 
@@ -188,12 +188,12 @@ class HashIndexExtraTestCase(BaseTestCase):
 class HashIndexSizeTestCase(BaseTestCase):
     def test_size_on_disk(self):
         idx = ChunkIndex()
-        assert idx.size() == 18 + 1031 * (32 + 3 * 4)
+        assert idx.size() == 18 + 1031 * (32 + 2 * 4)
 
     def test_size_on_disk_accurate(self):
         idx = ChunkIndex()
         for i in range(1234):
-            idx[H(i)] = i, i**2, i**3
+            idx[H(i)] = i, i**2
         with tempfile.NamedTemporaryFile() as file:
             idx.write(file.name)
             size = os.path.getsize(file.name)
@@ -203,7 +203,7 @@ class HashIndexSizeTestCase(BaseTestCase):
 class HashIndexRefcountingTestCase(BaseTestCase):
     def test_chunkindex_limit(self):
         idx = ChunkIndex()
-        idx[H(1)] = ChunkIndex.MAX_VALUE - 1, 1, 2
+        idx[H(1)] = ChunkIndex.MAX_VALUE - 1, 1
 
         # 5 is arbitrary, any number of incref/decrefs shouldn't move it once it's limited
         for i in range(5):
@@ -217,9 +217,9 @@ class HashIndexRefcountingTestCase(BaseTestCase):
     def _merge(self, refcounta, refcountb):
         def merge(refcount1, refcount2):
             idx1 = ChunkIndex()
-            idx1[H(1)] = refcount1, 1, 2
+            idx1[H(1)] = refcount1, 1
             idx2 = ChunkIndex()
-            idx2[H(1)] = refcount2, 1, 2
+            idx2[H(1)] = refcount2, 1
             idx1.merge(idx2)
             refcount, *_ = idx1[H(1)]
             return refcount
@@ -251,44 +251,44 @@ class HashIndexRefcountingTestCase(BaseTestCase):
 
     def test_chunkindex_add(self):
         idx1 = ChunkIndex()
-        idx1.add(H(1), 5, 6, 7)
-        assert idx1[H(1)] == (5, 6, 7)
-        idx1.add(H(1), 1, 2, 3)
-        assert idx1[H(1)] == (6, 2, 3)
+        idx1.add(H(1), 5, 6)
+        assert idx1[H(1)] == (5, 6)
+        idx1.add(H(1), 1, 2)
+        assert idx1[H(1)] == (6, 2)
 
     def test_incref_limit(self):
         idx1 = ChunkIndex()
-        idx1[H(1)] = (ChunkIndex.MAX_VALUE, 6, 7)
+        idx1[H(1)] = ChunkIndex.MAX_VALUE, 6
         idx1.incref(H(1))
         refcount, *_ = idx1[H(1)]
         assert refcount == ChunkIndex.MAX_VALUE
 
     def test_decref_limit(self):
         idx1 = ChunkIndex()
-        idx1[H(1)] = ChunkIndex.MAX_VALUE, 6, 7
+        idx1[H(1)] = ChunkIndex.MAX_VALUE, 6
         idx1.decref(H(1))
         refcount, *_ = idx1[H(1)]
         assert refcount == ChunkIndex.MAX_VALUE
 
     def test_decref_zero(self):
         idx1 = ChunkIndex()
-        idx1[H(1)] = 0, 0, 0
+        idx1[H(1)] = 0, 0
         with self.assert_raises(AssertionError):
             idx1.decref(H(1))
 
     def test_incref_decref(self):
         idx1 = ChunkIndex()
-        idx1.add(H(1), 5, 6, 7)
-        assert idx1[H(1)] == (5, 6, 7)
+        idx1.add(H(1), 5, 6)
+        assert idx1[H(1)] == (5, 6)
         idx1.incref(H(1))
-        assert idx1[H(1)] == (6, 6, 7)
+        assert idx1[H(1)] == (6, 6)
         idx1.decref(H(1))
-        assert idx1[H(1)] == (5, 6, 7)
+        assert idx1[H(1)] == (5, 6)
 
     def test_setitem_raises(self):
         idx1 = ChunkIndex()
         with self.assert_raises(AssertionError):
-            idx1[H(1)] = ChunkIndex.MAX_VALUE + 1, 0, 0
+            idx1[H(1)] = ChunkIndex.MAX_VALUE + 1, 0
 
     def test_keyerror(self):
         idx = ChunkIndex()
@@ -299,14 +299,15 @@ class HashIndexRefcountingTestCase(BaseTestCase):
         with self.assert_raises(KeyError):
             idx[H(1)]
         with self.assert_raises(OverflowError):
-            idx.add(H(1), -1, 0, 0)
+            idx.add(H(1), -1, 0)
 
 
 class HashIndexDataTestCase(BaseTestCase):
-    # This bytestring was created with 1.0-maint at c2f9533
-    HASHINDEX = b'eJzt0L0NgmAUhtHLT0LDEI6AuAEhMVYmVnSuYefC7AB3Aj9KNedJbnfyFne6P67P27w0EdG1Eac+Cm1ZybAsy7Isy7Isy7Isy7I' \
-                b'sy7Isy7Isy7Isy7Isy7Isy7Isy7Isy7Isy7Isy7Isy7Isy7Isy7Isy7Isy7Isy7Isy7Isy7Isy7Isy7Isy7Isy7LsL9nhc+cqTZ' \
-                b'3XlO2Ys++Du5fX+l1/YFmWZVmWZVmWZVmWZVmWZVmWZVmWZVmWZVmWZVmWZVmWZVmWZVmWZVmWZVmWZVmWZVn2/+0O2rYccw=='
+    # This bytestring was created with borg2-pre 2022-06-10
+    HASHINDEX = b'eJzt0LEJg1AYhdE/JqBjOEJMNhBBrAQrO9ewc+HsoG+CPMsEz1cfbnHbceqXoZvvEVE+IuoqMu2pnOE4' \
+                b'juM4juM4juM4juM4juM4juM4juM4juM4juM4juM4juM4juM4juM4juM4juM4juM4juM4juM4juM4juM4' \
+                b'juM4juM4juM4jruie36vuSVT5N0rzW0n9t7r5z9+4TiO4ziO4ziO4ziO4ziO4ziO4ziO4ziO4ziO4ziO' \
+                b'4ziO4ziO4ziO4ziO4ziO437LHbSVHGw='
 
     def _serialize_hashindex(self, idx):
         with tempfile.TemporaryDirectory() as tempdir:
@@ -330,23 +331,23 @@ class HashIndexDataTestCase(BaseTestCase):
 
     def test_identical_creation(self):
         idx1 = ChunkIndex()
-        idx1[H(1)] = 1, 2, 3
-        idx1[H(2)] = 2**31 - 1, 0, 0
-        idx1[H(3)] = 4294962296, 0, 0  # 4294962296 is -5000 interpreted as an uint32_t
+        idx1[H(1)] = 1, 2
+        idx1[H(2)] = 2**31 - 1, 0
+        idx1[H(3)] = 4294962296, 0  # 4294962296 is -5000 interpreted as an uint32_t
 
         serialized = self._serialize_hashindex(idx1)
         assert self._unpack(serialized) == self._unpack(self.HASHINDEX)
 
     def test_read_known_good(self):
         idx1 = self._deserialize_hashindex(self.HASHINDEX)
-        assert idx1[H(1)] == (1, 2, 3)
-        assert idx1[H(2)] == (2**31 - 1, 0, 0)
-        assert idx1[H(3)] == (4294962296, 0, 0)
+        assert idx1[H(1)] == (1, 2)
+        assert idx1[H(2)] == (2**31 - 1, 0)
+        assert idx1[H(3)] == (4294962296, 0)
 
         idx2 = ChunkIndex()
-        idx2[H(3)] = 2**32 - 123456, 6, 7
+        idx2[H(3)] = 2**32 - 123456, 6
         idx1.merge(idx2)
-        assert idx1[H(3)] == (ChunkIndex.MAX_VALUE, 6, 7)
+        assert idx1[H(3)] == (ChunkIndex.MAX_VALUE, 6)
 
 
 class HashIndexIntegrityTestCase(HashIndexDataTestCase):
@@ -497,16 +498,16 @@ class HashIndexCompactTestCase(HashIndexDataTestCase):
     def test_merge(self):
         master = ChunkIndex()
         idx1 = ChunkIndex()
-        idx1[H(1)] = 1, 100, 100
-        idx1[H(2)] = 2, 200, 200
-        idx1[H(3)] = 3, 300, 300
+        idx1[H(1)] = 1, 100
+        idx1[H(2)] = 2, 200
+        idx1[H(3)] = 3, 300
         idx1.compact()
-        assert idx1.size() == 18 + 3 * (32 + 3 * 4)
+        assert idx1.size() == 18 + 3 * (32 + 2 * 4)
 
         master.merge(idx1)
-        assert master[H(1)] == (1, 100, 100)
-        assert master[H(2)] == (2, 200, 200)
-        assert master[H(3)] == (3, 300, 300)
+        assert master[H(1)] == (1, 100)
+        assert master[H(2)] == (2, 200)
+        assert master[H(3)] == (3, 300)
 
 
 class NSIndexTestCase(BaseTestCase):