Browse Source

FuseVersionsIndex: use borghash.HashTableNT

Also:
- have a small wrapper class FuseVersionsIndex around HashTableNT to
  adapt API difference and add some special methods.
Thomas Waldmann 9 months ago
parent
commit
ca582b640c
2 changed files with 31 additions and 45 deletions
  1. 0 9
      src/borg/_hashindex.c
  2. 31 36
      src/borg/hashindex.pyx

+ 0 - 9
src/borg/_hashindex.c

@@ -875,12 +875,3 @@ hashindex_size(HashIndex *index)
 {
     return sizeof(HashHeader) + index->num_buckets * index->bucket_size;
 }
-
-/*
- * Used by the FuseVersionsIndex.
- */
-BORG_PACKED(
-typedef struct {
-    uint32_t version;
-    char hash[16];
-} ) FuseVersionsElement;

+ 31 - 36
src/borg/hashindex.pyx

@@ -2,8 +2,6 @@ from collections import namedtuple
 
 cimport cython
 from libc.stdint cimport uint32_t, UINT32_MAX, uint64_t
-from libc.string cimport memcpy
-from cpython.bytes cimport PyBytes_FromStringAndSize, PyBytes_CheckExact, PyBytes_GET_SIZE, PyBytes_AS_STRING
 
 from borghash cimport _borghash
 
@@ -14,10 +12,6 @@ cdef extern from "_hashindex.c":
     ctypedef struct HashIndex:
         pass
 
-    ctypedef struct FuseVersionsElement:
-        uint32_t version
-        char hash[16]
-
     HashIndex *hashindex_read(object file_py, int permit_compact, int legacy) except *
     HashIndex *hashindex_init(int capacity, int key_size, int value_size)
     void hashindex_free(HashIndex *index)
@@ -162,36 +156,6 @@ cdef class IndexBase:
         return hashindex_compact(self.index)
 
 
-cdef class FuseVersionsIndex(IndexBase):
-    # 4 byte version + 16 byte file contents hash
-    value_size = 20
-    _key_size = 16
-
-    def __getitem__(self, key):
-        cdef FuseVersionsElement *data
-        assert len(key) == self.key_size
-        data = <FuseVersionsElement *>hashindex_get(self.index, <unsigned char *>key)
-        if data == NULL:
-            raise KeyError(key)
-        return _le32toh(data.version), PyBytes_FromStringAndSize(data.hash, 16)
-
-    def __setitem__(self, key, value):
-        cdef FuseVersionsElement data
-        assert len(key) == self.key_size
-        data.version = value[0]
-        assert data.version <= _MAX_VALUE, "maximum number of versions reached"
-        if not PyBytes_CheckExact(value[1]) or PyBytes_GET_SIZE(value[1]) != 16:
-            raise TypeError("Expected bytes of length 16 for second value")
-        memcpy(data.hash, PyBytes_AS_STRING(value[1]), 16)
-        data.version = _htole32(data.version)
-        if not hashindex_set(self.index, <unsigned char *>key, <void *> &data):
-            raise Exception('hashindex_set failed')
-
-    def __contains__(self, key):
-        assert len(key) == self.key_size
-        return hashindex_get(self.index, <unsigned char *>key) != NULL
-
-
 NSIndexEntry = namedtuple('NSIndexEntry', 'segment offset size')
 
 
@@ -410,3 +374,34 @@ class ChunkIndex:
 
     def size(self):
         return self.ht.size()
+
+
+FuseVersionsIndexEntry = namedtuple('FuseVersionsEntry', 'version hash')
+
+
+class FuseVersionsIndex:
+    # key: 16 bytes, value: 4 byte version + 16 bytes file contents hash
+
+    def __init__(self):
+        self.ht = _borghash.HashTableNT(key_size=16, value_format="<I16s", namedtuple_type=FuseVersionsIndexEntry)
+
+    def __setitem__(self, key, value):
+        self.ht[key] = value
+
+    def __getitem__(self, key):
+        return self.ht[key]
+
+    def __delitem__(self, key):
+        del self.ht[key]
+
+    def __contains__(self, key):
+        return key in self.ht
+
+    def __len__(self):
+        return len(self.ht)
+
+    def get(self, key, default=None):
+        try:
+            return self[key]
+        except KeyError:
+            return default