refs/reftable: always reload stacks when creating lock

When creating a new addition via either `reftable_stack_new_addition()` or its convenince wrapper `reftable_stack_add()` we: 1. Create the "tables.list.lock" file. 2. Verify that the current version of the "tables.list" file is up-to-date. 3. Write the new table records if so. By default, the second step would cause us to bail out if we see that there has been a concurrent write to the stack that made our in-memory copy of the stack out-of-date. This is a safety mechanism to not write records to the stack based on outdated information. The downside though is that concurrent writes may now cause us to bail out, which is not a good user experience. In addition, this isn't even necessary for us, as Git knows to perform all checks for the old state of references under the lock. (Well, in all except one case: when we expire the reflog we first create the log iterator before we create the lock, but this ordering is fixed as part of this commit.) Consequently, most writers pass the `REFTABLE_STACK_NEW_ADDITION_RELOAD` flag. The effect of this flag is that we reload the stack after having acquired the lock in case the stack is out-of-date. This plugs the race with concurrent writers, but we continue performing the verifications of the expected old state to catch actual conflicts in the references we are about to write. Adapt the remaining callsites that don't yet pass this flag to do so. While at it, drop a needless manual reload. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Aug 12, 2025 at 11:54 UTC 16684b6fae43b45309f0a75d7e0cc207954e98c8
1 file changed +12 -11
refs/reftable-backend.c
+12 -11
@@ -1006,10 +1006,6 @@ static int prepare_transaction_update(struct write_transaction_table_arg **out,
1006 if (!arg) {
1007 struct reftable_addition *addition;
1008
1009 - ret = reftable_stack_reload(be->stack);
1010 - if (ret)
1011 - return ret;
1012 -
1009 ret = reftable_stack_new_addition(&addition, be->stack,
1010 REFTABLE_STACK_NEW_ADDITION_RELOAD);
1011 if (ret) {
@@ -1960,7 +1956,8 @@ static int reftable_be_rename_ref(struct ref_store *ref_store,
1956 ret = backend_for(&arg.be, refs, newrefname, &newrefname, 1);
1957 if (ret)
1958 goto done;
1963 - ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg, 0);
1959 + ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg,
1960 + REFTABLE_STACK_NEW_ADDITION_RELOAD);
1961
1962 done:
1963 assert(ret != REFTABLE_API_ERROR);
@@ -1989,7 +1986,8 @@ static int reftable_be_copy_ref(struct ref_store *ref_store,
1986 ret = backend_for(&arg.be, refs, newrefname, &newrefname, 1);
1987 if (ret)
1988 goto done;
1992 - ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg, 0);
1989 + ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg,
1990 + REFTABLE_STACK_NEW_ADDITION_RELOAD);
1991
1992 done:
1993 assert(ret != REFTABLE_API_ERROR);
@@ -2360,7 +2358,8 @@ static int reftable_be_create_reflog(struct ref_store *ref_store,
2358 goto done;
2359 arg.stack = be->stack;
2360
2363 - ret = reftable_stack_add(be->stack, &write_reflog_existence_table, &arg, 0);
2361 + ret = reftable_stack_add(be->stack, &write_reflog_existence_table, &arg,
2362 + REFTABLE_STACK_NEW_ADDITION_RELOAD);
2363
2364 done:
2365 return ret;
@@ -2431,7 +2430,8 @@ static int reftable_be_delete_reflog(struct ref_store *ref_store,
2430 return ret;
2431 arg.stack = be->stack;
2432
2434 - ret = reftable_stack_add(be->stack, &write_reflog_delete_table, &arg, 0);
2433 + ret = reftable_stack_add(be->stack, &write_reflog_delete_table, &arg,
2434 + REFTABLE_STACK_NEW_ADDITION_RELOAD);
2435
2436 assert(ret != REFTABLE_API_ERROR);
2437 return ret;
@@ -2552,15 +2552,16 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
2552 if (ret < 0)
2553 goto done;
2554
2555 - ret = reftable_stack_init_log_iterator(be->stack, &it);
2555 + ret = reftable_stack_new_addition(&add, be->stack,
2556 + REFTABLE_STACK_NEW_ADDITION_RELOAD);
2557 if (ret < 0)
2558 goto done;
2559
2559 - ret = reftable_iterator_seek_log(&it, refname);
2560 + ret = reftable_stack_init_log_iterator(be->stack, &it);
2561 if (ret < 0)
2562 goto done;
2563
2563 - ret = reftable_stack_new_addition(&add, be->stack, 0);
2564 + ret = reftable_iterator_seek_log(&it, refname);
2565 if (ret < 0)
2566 goto done;
2567