]> git.ipfire.org Git - thirdparty/git.git/commitdiff
reftable: a generic binary tree implementation
authorHan-Wen Nienhuys <hanwen@google.com>
Thu, 7 Oct 2021 20:25:05 +0000 (20:25 +0000)
committerJunio C Hamano <gitster@pobox.com>
Fri, 8 Oct 2021 17:45:48 +0000 (10:45 -0700)
The reftable format includes support for an (OID => ref) map. This map can speed
up visibility and reachability checks. In particular, various operations along
the fetch/push path within Gerrit have ben sped up by using this structure.

The map is constructed with help of a binary tree. Object IDs are hashes, so
they are uniformly distributed. Hence, the tree does not attempt forced
rebalancing.

Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Makefile
reftable/tree.c [new file with mode: 0644]
reftable/tree.h [new file with mode: 0644]
reftable/tree_test.c [new file with mode: 0644]
t/helper/test-reftable.c

index 65bd39ecdc0923f6a04ad376a9a4eea260bc3082..2e5a9f40ed1365db515fafaae7f2dfdf163961a5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2462,11 +2462,13 @@ REFTABLE_OBJS += reftable/block.o
 REFTABLE_OBJS += reftable/blocksource.o
 REFTABLE_OBJS += reftable/publicbasics.o
 REFTABLE_OBJS += reftable/record.o
+REFTABLE_OBJS += reftable/tree.o
 
+REFTABLE_TEST_OBJS += reftable/basics_test.o
 REFTABLE_TEST_OBJS += reftable/block_test.o
 REFTABLE_TEST_OBJS += reftable/record_test.o
 REFTABLE_TEST_OBJS += reftable/test_framework.o
-REFTABLE_TEST_OBJS += reftable/basics_test.o
+REFTABLE_TEST_OBJS += reftable/tree_test.o
 
 TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
 
diff --git a/reftable/tree.c b/reftable/tree.c
new file mode 100644 (file)
index 0000000..82db799
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+Copyright 2020 Google LLC
+
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file or at
+https://developers.google.com/open-source/licenses/bsd
+*/
+
+#include "tree.h"
+
+#include "basics.h"
+#include "system.h"
+
+struct tree_node *tree_search(void *key, struct tree_node **rootp,
+                             int (*compare)(const void *, const void *),
+                             int insert)
+{
+       int res;
+       if (*rootp == NULL) {
+               if (!insert) {
+                       return NULL;
+               } else {
+                       struct tree_node *n =
+                               reftable_calloc(sizeof(struct tree_node));
+                       n->key = key;
+                       *rootp = n;
+                       return *rootp;
+               }
+       }
+
+       res = compare(key, (*rootp)->key);
+       if (res < 0)
+               return tree_search(key, &(*rootp)->left, compare, insert);
+       else if (res > 0)
+               return tree_search(key, &(*rootp)->right, compare, insert);
+       return *rootp;
+}
+
+void infix_walk(struct tree_node *t, void (*action)(void *arg, void *key),
+               void *arg)
+{
+       if (t->left) {
+               infix_walk(t->left, action, arg);
+       }
+       action(arg, t->key);
+       if (t->right) {
+               infix_walk(t->right, action, arg);
+       }
+}
+
+void tree_free(struct tree_node *t)
+{
+       if (t == NULL) {
+               return;
+       }
+       if (t->left) {
+               tree_free(t->left);
+       }
+       if (t->right) {
+               tree_free(t->right);
+       }
+       reftable_free(t);
+}
diff --git a/reftable/tree.h b/reftable/tree.h
new file mode 100644 (file)
index 0000000..fbdd002
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+Copyright 2020 Google LLC
+
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file or at
+https://developers.google.com/open-source/licenses/bsd
+*/
+
+#ifndef TREE_H
+#define TREE_H
+
+/* tree_node is a generic binary search tree. */
+struct tree_node {
+       void *key;
+       struct tree_node *left, *right;
+};
+
+/* looks for `key` in `rootp` using `compare` as comparison function. If insert
+ * is set, insert the key if it's not found. Else, return NULL.
+ */
+struct tree_node *tree_search(void *key, struct tree_node **rootp,
+                             int (*compare)(const void *, const void *),
+                             int insert);
+
+/* performs an infix walk of the tree. */
+void infix_walk(struct tree_node *t, void (*action)(void *arg, void *key),
+               void *arg);
+
+/*
+ * deallocates the tree nodes recursively. Keys should be deallocated separately
+ * by walking over the tree. */
+void tree_free(struct tree_node *t);
+
+#endif
diff --git a/reftable/tree_test.c b/reftable/tree_test.c
new file mode 100644 (file)
index 0000000..cbff125
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+Copyright 2020 Google LLC
+
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file or at
+https://developers.google.com/open-source/licenses/bsd
+*/
+
+#include "tree.h"
+
+#include "basics.h"
+#include "record.h"
+#include "test_framework.h"
+#include "reftable-tests.h"
+
+static int test_compare(const void *a, const void *b)
+{
+       return (char *)a - (char *)b;
+}
+
+struct curry {
+       void *last;
+};
+
+static void check_increasing(void *arg, void *key)
+{
+       struct curry *c = arg;
+       if (c->last) {
+               EXPECT(test_compare(c->last, key) < 0);
+       }
+       c->last = key;
+}
+
+static void test_tree(void)
+{
+       struct tree_node *root = NULL;
+
+       void *values[11] = { NULL };
+       struct tree_node *nodes[11] = { NULL };
+       int i = 1;
+       struct curry c = { NULL };
+       do {
+               nodes[i] = tree_search(values + i, &root, &test_compare, 1);
+               i = (i * 7) % 11;
+       } while (i != 1);
+
+       for (i = 1; i < ARRAY_SIZE(nodes); i++) {
+               EXPECT(values + i == nodes[i]->key);
+               EXPECT(nodes[i] ==
+                      tree_search(values + i, &root, &test_compare, 0));
+       }
+
+       infix_walk(root, check_increasing, &c);
+       tree_free(root);
+}
+
+int tree_test_main(int argc, const char *argv[])
+{
+       RUN_TEST(test_tree);
+       return 0;
+}
index c9deeaf08c7a2c86c6d315ea90fc3dcf7a104dfd..050551fa69858d5369697a5a9bec2d8af8281f2b 100644 (file)
@@ -6,5 +6,6 @@ int cmd__reftable(int argc, const char **argv)
        basics_test_main(argc, argv);
        block_test_main(argc, argv);
        record_test_main(argc, argv);
+       tree_test_main(argc, argv);
        return 0;
 }