refs/reftable: read references via `struct reftable_backend`

Refactor `read_ref_without_reload()` to accept `struct reftable_backend` as parameter instead of `struct reftable_stack`. Rename the function to `reftable_backend_read_ref()` to clarify its scope and move it close to other functions operating on `struct reftable_backend`. This change allows us to implement an additional caching layer when reading refs where we can reuse reftable iterators. 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 27fdf8f4ed0b76f4c21c6ee1f95886c731c4e196
1 file changed +59 -63
refs/reftable-backend.c
+59 -63
@@ -51,6 +51,50 @@ static void reftable_backend_release(struct reftable_backend *be)
51 be->stack = NULL;
52 }
53
54 +static int reftable_backend_read_ref(struct reftable_backend *be,
55 + const char *refname,
56 + struct object_id *oid,
57 + struct strbuf *referent,
58 + unsigned int *type)
59 +{
60 + struct reftable_ref_record ref = {0};
61 + int ret;
62 +
63 + ret = reftable_stack_read_ref(be->stack, refname, &ref);
64 + if (ret)
65 + goto done;
66 +
67 + if (ref.value_type == REFTABLE_REF_SYMREF) {
68 + strbuf_reset(referent);
69 + strbuf_addstr(referent, ref.value.symref);
70 + *type |= REF_ISSYMREF;
71 + } else if (reftable_ref_record_val1(&ref)) {
72 + unsigned int hash_id;
73 +
74 + switch (reftable_stack_hash_id(be->stack)) {
75 + case REFTABLE_HASH_SHA1:
76 + hash_id = GIT_HASH_SHA1;
77 + break;
78 + case REFTABLE_HASH_SHA256:
79 + hash_id = GIT_HASH_SHA256;
80 + break;
81 + default:
82 + BUG("unhandled hash ID %d", reftable_stack_hash_id(be->stack));
83 + }
84 +
85 + oidread(oid, reftable_ref_record_val1(&ref),
86 + &hash_algos[hash_id]);
87 + } else {
88 + /* We got a tombstone, which should not happen. */
89 + BUG("unhandled reference value type %d", ref.value_type);
90 + }
91 +
92 +done:
93 + assert(ret != REFTABLE_API_ERROR);
94 + reftable_ref_record_release(&ref);
95 + return ret;
96 +}
97 +
98 struct reftable_ref_store {
99 struct ref_store base;
100
@@ -243,50 +287,6 @@ static void fill_reftable_log_record(struct reftable_log_record *log, const stru
287 log->value.update.tz_offset = sign * atoi(tz_begin);
288 }
289
246 -static int read_ref_without_reload(struct reftable_stack *stack,
247 - const char *refname,
248 - struct object_id *oid,
249 - struct strbuf *referent,
250 - unsigned int *type)
251 -{
252 - struct reftable_ref_record ref = {0};
253 - int ret;
254 -
255 - ret = reftable_stack_read_ref(stack, refname, &ref);
256 - if (ret)
257 - goto done;
258 -
259 - if (ref.value_type == REFTABLE_REF_SYMREF) {
260 - strbuf_reset(referent);
261 - strbuf_addstr(referent, ref.value.symref);
262 - *type |= REF_ISSYMREF;
263 - } else if (reftable_ref_record_val1(&ref)) {
264 - unsigned int hash_id;
265 -
266 - switch (reftable_stack_hash_id(stack)) {
267 - case REFTABLE_HASH_SHA1:
268 - hash_id = GIT_HASH_SHA1;
269 - break;
270 - case REFTABLE_HASH_SHA256:
271 - hash_id = GIT_HASH_SHA256;
272 - break;
273 - default:
274 - BUG("unhandled hash ID %d", reftable_stack_hash_id(stack));
275 - }
276 -
277 - oidread(oid, reftable_ref_record_val1(&ref),
278 - &hash_algos[hash_id]);
279 - } else {
280 - /* We got a tombstone, which should not happen. */
281 - BUG("unhandled reference value type %d", ref.value_type);
282 - }
283 -
284 -done:
285 - assert(ret != REFTABLE_API_ERROR);
286 - reftable_ref_record_release(&ref);
287 - return ret;
288 -}
289 -
290 static int reftable_be_config(const char *var, const char *value,
291 const struct config_context *ctx,
292 void *_opts)
@@ -867,7 +867,7 @@ static int reftable_be_read_raw_ref(struct ref_store *ref_store,
867 if (ret)
868 return ret;
869
870 - ret = read_ref_without_reload(be->stack, refname, oid, referent, type);
870 + ret = reftable_backend_read_ref(be, refname, oid, referent, type);
871 if (ret < 0)
872 return ret;
873 if (ret > 0) {
@@ -1103,8 +1103,8 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
1103 if (ret)
1104 goto done;
1105
1106 - ret = read_ref_without_reload(be->stack, "HEAD",
1107 - &head_oid, &head_referent, &head_type);
1106 + ret = reftable_backend_read_ref(be, "HEAD", &head_oid,
1107 + &head_referent, &head_type);
1108 if (ret < 0)
1109 goto done;
1110 ret = 0;
@@ -1179,8 +1179,8 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
1179 string_list_insert(&affected_refnames, new_update->refname);
1180 }
1181
1182 - ret = read_ref_without_reload(be->stack, rewritten_ref,
1183 - &current_oid, &referent, &u->type);
1182 + ret = reftable_backend_read_ref(be, rewritten_ref,
1183 + &current_oid, &referent, &u->type);
1184 if (ret < 0)
1185 goto done;
1186 if (ret > 0 && !ref_update_expects_existing_old_ref(u)) {
@@ -1638,7 +1638,7 @@ struct write_create_symref_arg {
1638
1639 struct write_copy_arg {
1640 struct reftable_ref_store *refs;
1641 - struct reftable_stack *stack;
1641 + struct reftable_backend *be;
1642 const char *oldname;
1643 const char *newname;
1644 const char *logmsg;
@@ -1663,7 +1663,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
1663 if (split_ident_line(&committer_ident, committer_info, strlen(committer_info)))
1664 BUG("failed splitting committer info");
1665
1666 - if (reftable_stack_read_ref(arg->stack, arg->oldname, &old_ref)) {
1666 + if (reftable_stack_read_ref(arg->be->stack, arg->oldname, &old_ref)) {
1667 ret = error(_("refname %s not found"), arg->oldname);
1668 goto done;
1669 }
@@ -1702,7 +1702,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
1702 * the old branch and the creation of the new branch, and we cannot do
1703 * two changes to a reflog in a single update.
1704 */
1705 - deletion_ts = creation_ts = reftable_stack_next_update_index(arg->stack);
1705 + deletion_ts = creation_ts = reftable_stack_next_update_index(arg->be->stack);
1706 if (arg->delete_old)
1707 creation_ts++;
1708 reftable_writer_set_limits(writer, deletion_ts, creation_ts);
@@ -1745,8 +1745,8 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
1745 memcpy(logs[logs_nr].value.update.old_hash, old_ref.value.val1, GIT_MAX_RAWSZ);
1746 logs_nr++;
1747
1748 - ret = read_ref_without_reload(arg->stack, "HEAD", &head_oid,
1749 - &head_referent, &head_type);
1748 + ret = reftable_backend_read_ref(arg->be, "HEAD", &head_oid,
1749 + &head_referent, &head_type);
1750 if (ret < 0)
1751 goto done;
1752 append_head_reflog = (head_type & REF_ISSYMREF) && !strcmp(head_referent.buf, arg->oldname);
@@ -1789,7 +1789,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
1789 * copy over all log entries from the old reflog. Last but not least,
1790 * when renaming we also have to delete all the old reflog entries.
1791 */
1792 - ret = reftable_stack_init_log_iterator(arg->stack, &it);
1792 + ret = reftable_stack_init_log_iterator(arg->be->stack, &it);
1793 if (ret < 0)
1794 goto done;
1795
@@ -1862,7 +1862,6 @@ static int reftable_be_rename_ref(struct ref_store *ref_store,
1862 {
1863 struct reftable_ref_store *refs =
1864 reftable_be_downcast(ref_store, REF_STORE_WRITE, "rename_ref");
1865 - struct reftable_backend *be;
1865 struct write_copy_arg arg = {
1866 .refs = refs,
1867 .oldname = oldrefname,
@@ -1876,11 +1875,10 @@ static int reftable_be_rename_ref(struct ref_store *ref_store,
1875 if (ret < 0)
1876 goto done;
1877
1879 - ret = backend_for(&be, refs, newrefname, &newrefname, 1);
1878 + ret = backend_for(&arg.be, refs, newrefname, &newrefname, 1);
1879 if (ret)
1880 goto done;
1882 - arg.stack = be->stack;
1883 - ret = reftable_stack_add(be->stack, &write_copy_table, &arg);
1881 + ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg);
1882
1883 done:
1884 assert(ret != REFTABLE_API_ERROR);
@@ -1894,7 +1892,6 @@ static int reftable_be_copy_ref(struct ref_store *ref_store,
1892 {
1893 struct reftable_ref_store *refs =
1894 reftable_be_downcast(ref_store, REF_STORE_WRITE, "copy_ref");
1897 - struct reftable_backend *be;
1895 struct write_copy_arg arg = {
1896 .refs = refs,
1897 .oldname = oldrefname,
@@ -1907,11 +1904,10 @@ static int reftable_be_copy_ref(struct ref_store *ref_store,
1904 if (ret < 0)
1905 goto done;
1906
1910 - ret = backend_for(&be, refs, newrefname, &newrefname, 1);
1907 + ret = backend_for(&arg.be, refs, newrefname, &newrefname, 1);
1908 if (ret)
1909 goto done;
1913 - arg.stack = be->stack;
1914 - ret = reftable_stack_add(be->stack, &write_copy_table, &arg);
1910 + ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg);
1911
1912 done:
1913 assert(ret != REFTABLE_API_ERROR);