refs/reftable: encapsulate reftable stack

The reftable ref store needs to keep track of multiple stacks, one for the main worktree and an arbitrary number of stacks for worktrees. This is done by storing pointers to `struct reftable_stack`, which we then access directly. Wrap the stack in a new `struct reftable_backend`. This will allow us to attach more data to each respective stack in subsequent commits. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Nov 26, 2024 at 07:42 UTC ad0986c6764eed4dd9f0302aa3b1c5367e5c16a3
1 file changed +76 -59
refs/reftable-backend.c
+76 -59
@@ -34,24 +34,41 @@
34 */
35 #define REF_UPDATE_VIA_HEAD (1 << 8)
36
37 +struct reftable_backend {
38 + struct reftable_stack *stack;
39 +};
40 +
41 +static int reftable_backend_init(struct reftable_backend *be,
42 + const char *path,
43 + const struct reftable_write_options *opts)
44 +{
45 + return reftable_new_stack(&be->stack, path, opts);
46 +}
47 +
48 +static void reftable_backend_release(struct reftable_backend *be)
49 +{
50 + reftable_stack_destroy(be->stack);
51 + be->stack = NULL;
52 +}
53 +
54 struct reftable_ref_store {
55 struct ref_store base;
56
57 /*
41 - * The main stack refers to the common dir and thus contains common
58 + * The main backend refers to the common dir and thus contains common
59 * refs as well as refs of the main repository.
60 */
44 - struct reftable_stack *main_stack;
61 + struct reftable_backend main_backend;
62 /*
46 - * The worktree stack refers to the gitdir in case the refdb is opened
63 + * The worktree backend refers to the gitdir in case the refdb is opened
64 * via a worktree. It thus contains the per-worktree refs.
65 */
49 - struct reftable_stack *worktree_stack;
66 + struct reftable_backend worktree_backend;
67 /*
51 - * Map of worktree stacks by their respective worktree names. The map
68 + * Map of worktree backends by their respective worktree names. The map
69 * is populated lazily when we try to resolve `worktrees/$worktree` refs.
70 */
54 - struct strmap worktree_stacks;
71 + struct strmap worktree_backends;
72 struct reftable_write_options write_options;
73
74 unsigned int store_flags;
@@ -97,21 +114,21 @@ static struct reftable_ref_store *reftable_be_downcast(struct ref_store *ref_sto
114 * like `worktrees/$worktree/refs/heads/foo` as worktree stacks will store
115 * those references in their normalized form.
116 */
100 -static struct reftable_stack *stack_for(struct reftable_ref_store *store,
101 - const char *refname,
102 - const char **rewritten_ref)
117 +static struct reftable_backend *backend_for(struct reftable_ref_store *store,
118 + const char *refname,
119 + const char **rewritten_ref)
120 {
121 const char *wtname;
122 int wtname_len;
123
124 if (!refname)
108 - return store->main_stack;
125 + return &store->main_backend;
126
127 switch (parse_worktree_ref(refname, &wtname, &wtname_len, rewritten_ref)) {
128 case REF_WORKTREE_OTHER: {
129 static struct strbuf wtname_buf = STRBUF_INIT;
130 struct strbuf wt_dir = STRBUF_INIT;
114 - struct reftable_stack *stack;
131 + struct reftable_backend *be;
132
133 /*
134 * We're using a static buffer here so that we don't need to
@@ -125,37 +142,39 @@ static struct reftable_stack *stack_for(struct reftable_ref_store *store,
142 /*
143 * There is an edge case here: when the worktree references the
144 * current worktree, then we set up the stack once via
128 - * `worktree_stacks` and once via `worktree_stack`. This is
145 + * `worktree_backends` and once via `worktree_backend`. This is
146 * wasteful, but in the reading case it shouldn't matter. And
147 * in the writing case we would notice that the stack is locked
148 * already and error out when trying to write a reference via
149 * both stacks.
150 */
134 - stack = strmap_get(&store->worktree_stacks, wtname_buf.buf);
135 - if (!stack) {
151 + be = strmap_get(&store->worktree_backends, wtname_buf.buf);
152 + if (!be) {
153 strbuf_addf(&wt_dir, "%s/worktrees/%s/reftable",
154 store->base.repo->commondir, wtname_buf.buf);
155
139 - store->err = reftable_new_stack(&stack, wt_dir.buf,
140 - &store->write_options);
156 + CALLOC_ARRAY(be, 1);
157 + store->err = reftable_backend_init(be, wt_dir.buf,
158 + &store->write_options);
159 assert(store->err != REFTABLE_API_ERROR);
142 - strmap_put(&store->worktree_stacks, wtname_buf.buf, stack);
160 +
161 + strmap_put(&store->worktree_backends, wtname_buf.buf, be);
162 }
163
164 strbuf_release(&wt_dir);
146 - return stack;
165 + return be;
166 }
167 case REF_WORKTREE_CURRENT:
168 /*
169 * If there is no worktree stack then we're currently in the
170 * main worktree. We thus return the main stack in that case.
171 */
153 - if (!store->worktree_stack)
154 - return store->main_stack;
155 - return store->worktree_stack;
172 + if (!store->worktree_backend.stack)
173 + return &store->main_backend;
174 + return &store->worktree_backend;
175 case REF_WORKTREE_MAIN:
176 case REF_WORKTREE_SHARED:
158 - return store->main_stack;
177 + return &store->main_backend;
178 default:
179 BUG("unhandled worktree reference type");
180 }
@@ -292,7 +311,7 @@ static struct ref_store *reftable_be_init(struct repository *repo,
311 umask(mask);
312
313 base_ref_store_init(&refs->base, repo, gitdir, &refs_be_reftable);
295 - strmap_init(&refs->worktree_stacks);
314 + strmap_init(&refs->worktree_backends);
315 refs->store_flags = store_flags;
316 refs->log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo);
317
@@ -337,8 +356,8 @@ static struct ref_store *reftable_be_init(struct repository *repo,
356 strbuf_realpath(&path, gitdir, 0);
357 }
358 strbuf_addstr(&path, "/reftable");
340 - refs->err = reftable_new_stack(&refs->main_stack, path.buf,
341 - &refs->write_options);
359 + refs->err = reftable_backend_init(&refs->main_backend, path.buf,
360 + &refs->write_options);
361 if (refs->err)
362 goto done;
363
@@ -354,8 +373,8 @@ static struct ref_store *reftable_be_init(struct repository *repo,
373 strbuf_reset(&path);
374 strbuf_addf(&path, "%s/reftable", gitdir);
375
357 - refs->err = reftable_new_stack(&refs->worktree_stack, path.buf,
358 - &refs->write_options);
376 + refs->err = reftable_backend_init(&refs->worktree_backend, path.buf,
377 + &refs->write_options);
378 if (refs->err)
379 goto done;
380 }
@@ -374,19 +393,17 @@ static void reftable_be_release(struct ref_store *ref_store)
393 struct strmap_entry *entry;
394 struct hashmap_iter iter;
395
377 - if (refs->main_stack) {
378 - reftable_stack_destroy(refs->main_stack);
379 - refs->main_stack = NULL;
380 - }
396 + if (refs->main_backend.stack)
397 + reftable_backend_release(&refs->main_backend);
398 + if (refs->worktree_backend.stack)
399 + reftable_backend_release(&refs->worktree_backend);
400
382 - if (refs->worktree_stack) {
383 - reftable_stack_destroy(refs->worktree_stack);
384 - refs->worktree_stack = NULL;
401 + strmap_for_each_entry(&refs->worktree_backends, &iter, entry) {
402 + struct reftable_backend *be = entry->value;
403 + reftable_backend_release(be);
404 + free(be);
405 }
386 -
387 - strmap_for_each_entry(&refs->worktree_stacks, &iter, entry)
388 - reftable_stack_destroy(entry->value);
389 - strmap_clear(&refs->worktree_stacks, 0);
406 + strmap_clear(&refs->worktree_backends, 0);
407 }
408
409 static int reftable_be_create_on_disk(struct ref_store *ref_store,
@@ -781,7 +798,7 @@ static struct ref_iterator *reftable_be_iterator_begin(struct ref_store *ref_sto
798 required_flags |= REF_STORE_ODB;
799 refs = reftable_be_downcast(ref_store, required_flags, "ref_iterator_begin");
800
784 - main_iter = ref_iterator_for_stack(refs, refs->main_stack, prefix,
801 + main_iter = ref_iterator_for_stack(refs, refs->main_backend.stack, prefix,
802 exclude_patterns, flags);
803
804 /*
@@ -789,14 +806,14 @@ static struct ref_iterator *reftable_be_iterator_begin(struct ref_store *ref_sto
806 * right now. If we aren't, then we return the common reftable
807 * iterator, only.
808 */
792 - if (!refs->worktree_stack)
809 + if (!refs->worktree_backend.stack)
810 return &main_iter->base;
811
812 /*
813 * Otherwise we merge both the common and the per-worktree refs into a
814 * single iterator.
815 */
799 - worktree_iter = ref_iterator_for_stack(refs, refs->worktree_stack, prefix,
816 + worktree_iter = ref_iterator_for_stack(refs, refs->worktree_backend.stack, prefix,
817 exclude_patterns, flags);
818 return merge_ref_iterator_begin(&worktree_iter->base, &main_iter->base,
819 ref_iterator_select, NULL);
@@ -811,7 +828,7 @@ static int reftable_be_read_raw_ref(struct ref_store *ref_store,
828 {
829 struct reftable_ref_store *refs =
830 reftable_be_downcast(ref_store, REF_STORE_READ, "read_raw_ref");
814 - struct reftable_stack *stack = stack_for(refs, refname, &refname);
831 + struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack;
832 int ret;
833
834 if (refs->err < 0)
@@ -838,7 +855,7 @@ static int reftable_be_read_symbolic_ref(struct ref_store *ref_store,
855 {
856 struct reftable_ref_store *refs =
857 reftable_be_downcast(ref_store, REF_STORE_READ, "read_symbolic_ref");
841 - struct reftable_stack *stack = stack_for(refs, refname, &refname);
858 + struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack;
859 struct reftable_ref_record ref = {0};
860 int ret;
861
@@ -898,7 +915,7 @@ static int prepare_transaction_update(struct write_transaction_table_arg **out,
915 struct ref_update *update,
916 struct strbuf *err)
917 {
901 - struct reftable_stack *stack = stack_for(refs, update->refname, NULL);
918 + struct reftable_stack *stack = backend_for(refs, update->refname, NULL)->stack;
919 struct write_transaction_table_arg *arg = NULL;
920 size_t i;
921 int ret;
@@ -1031,7 +1048,7 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
1048 goto done;
1049 }
1050
1034 - ret = read_ref_without_reload(refs, stack_for(refs, "HEAD", NULL), "HEAD",
1051 + ret = read_ref_without_reload(refs, backend_for(refs, "HEAD", NULL)->stack, "HEAD",
1052 &head_oid, &head_referent, &head_type);
1053 if (ret < 0)
1054 goto done;
@@ -1043,7 +1060,7 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
1060 struct reftable_stack *stack;
1061 const char *rewritten_ref;
1062
1046 - stack = stack_for(refs, u->refname, &rewritten_ref);
1063 + stack = backend_for(refs, u->refname, &rewritten_ref)->stack;
1064
1065 /* Verify that the new object ID is valid. */
1066 if ((u->flags & REF_HAVE_NEW) && !is_null_oid(&u->new_oid) &&
@@ -1525,9 +1542,9 @@ static int reftable_be_pack_refs(struct ref_store *ref_store,
1542 if (refs->err)
1543 return refs->err;
1544
1528 - stack = refs->worktree_stack;
1545 + stack = refs->worktree_backend.stack;
1546 if (!stack)
1530 - stack = refs->main_stack;
1547 + stack = refs->main_backend.stack;
1548
1549 if (opts->flags & PACK_REFS_AUTO)
1550 ret = reftable_stack_auto_compact(stack);
@@ -1782,7 +1799,7 @@ static int reftable_be_rename_ref(struct ref_store *ref_store,
1799 {
1800 struct reftable_ref_store *refs =
1801 reftable_be_downcast(ref_store, REF_STORE_WRITE, "rename_ref");
1785 - struct reftable_stack *stack = stack_for(refs, newrefname, &newrefname);
1802 + struct reftable_stack *stack = backend_for(refs, newrefname, &newrefname)->stack;
1803 struct write_copy_arg arg = {
1804 .refs = refs,
1805 .stack = stack,
@@ -1814,7 +1831,7 @@ static int reftable_be_copy_ref(struct ref_store *ref_store,
1831 {
1832 struct reftable_ref_store *refs =
1833 reftable_be_downcast(ref_store, REF_STORE_WRITE, "copy_ref");
1817 - struct reftable_stack *stack = stack_for(refs, newrefname, &newrefname);
1834 + struct reftable_stack *stack = backend_for(refs, newrefname, &newrefname)->stack;
1835 struct write_copy_arg arg = {
1836 .refs = refs,
1837 .stack = stack,
@@ -1952,11 +1969,11 @@ static struct ref_iterator *reftable_be_reflog_iterator_begin(struct ref_store *
1969 reftable_be_downcast(ref_store, REF_STORE_READ, "reflog_iterator_begin");
1970 struct reftable_reflog_iterator *main_iter, *worktree_iter;
1971
1955 - main_iter = reflog_iterator_for_stack(refs, refs->main_stack);
1956 - if (!refs->worktree_stack)
1972 + main_iter = reflog_iterator_for_stack(refs, refs->main_backend.stack);
1973 + if (!refs->worktree_backend.stack)
1974 return &main_iter->base;
1975
1959 - worktree_iter = reflog_iterator_for_stack(refs, refs->worktree_stack);
1976 + worktree_iter = reflog_iterator_for_stack(refs, refs->worktree_backend.stack);
1977
1978 return merge_ref_iterator_begin(&worktree_iter->base, &main_iter->base,
1979 ref_iterator_select, NULL);
@@ -1995,7 +2012,7 @@ static int reftable_be_for_each_reflog_ent_reverse(struct ref_store *ref_store,
2012 {
2013 struct reftable_ref_store *refs =
2014 reftable_be_downcast(ref_store, REF_STORE_READ, "for_each_reflog_ent_reverse");
1998 - struct reftable_stack *stack = stack_for(refs, refname, &refname);
2015 + struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack;
2016 struct reftable_log_record log = {0};
2017 struct reftable_iterator it = {0};
2018 int ret;
@@ -2035,7 +2052,7 @@ static int reftable_be_for_each_reflog_ent(struct ref_store *ref_store,
2052 {
2053 struct reftable_ref_store *refs =
2054 reftable_be_downcast(ref_store, REF_STORE_READ, "for_each_reflog_ent");
2038 - struct reftable_stack *stack = stack_for(refs, refname, &refname);
2055 + struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack;
2056 struct reftable_log_record *logs = NULL;
2057 struct reftable_iterator it = {0};
2058 size_t logs_alloc = 0, logs_nr = 0, i;
@@ -2084,7 +2101,7 @@ static int reftable_be_reflog_exists(struct ref_store *ref_store,
2101 {
2102 struct reftable_ref_store *refs =
2103 reftable_be_downcast(ref_store, REF_STORE_READ, "reflog_exists");
2087 - struct reftable_stack *stack = stack_for(refs, refname, &refname);
2104 + struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack;
2105 struct reftable_log_record log = {0};
2106 struct reftable_iterator it = {0};
2107 int ret;
@@ -2169,7 +2186,7 @@ static int reftable_be_create_reflog(struct ref_store *ref_store,
2186 {
2187 struct reftable_ref_store *refs =
2188 reftable_be_downcast(ref_store, REF_STORE_WRITE, "create_reflog");
2172 - struct reftable_stack *stack = stack_for(refs, refname, &refname);
2189 + struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack;
2190 struct write_reflog_existence_arg arg = {
2191 .refs = refs,
2192 .stack = stack,
@@ -2243,7 +2260,7 @@ static int reftable_be_delete_reflog(struct ref_store *ref_store,
2260 {
2261 struct reftable_ref_store *refs =
2262 reftable_be_downcast(ref_store, REF_STORE_WRITE, "delete_reflog");
2246 - struct reftable_stack *stack = stack_for(refs, refname, &refname);
2263 + struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack;
2264 struct write_reflog_delete_arg arg = {
2265 .stack = stack,
2266 .refname = refname,
@@ -2352,7 +2369,7 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
2369 */
2370 struct reftable_ref_store *refs =
2371 reftable_be_downcast(ref_store, REF_STORE_WRITE, "reflog_expire");
2355 - struct reftable_stack *stack = stack_for(refs, refname, &refname);
2372 + struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack;
2373 struct reftable_log_record *logs = NULL;
2374 struct reftable_log_record *rewritten = NULL;
2375 struct reftable_ref_record ref_record = {0};