Skip to content

Commit 6241ce2

Browse files
pks-tgitster
authored andcommitted
refs/reftable: reload locked stack when preparing transaction
When starting a reftable transaction we lock all stacks we are about to modify. While it may happen that the stack is out-of-date at this point in time we don't really care: transactional updates encode the expected state of a certain reference, so all that we really want to verify is that the _current_ value matches that expected state. Pass `REFTABLE_STACK_NEW_ADDITION_RELOAD` when locking the stack such that an out-of-date stack will be reloaded after having been locked. This change is safe because all verifications of the expected state happen after this step anyway. Add a testcase that verifies that many writers are now able to write to the stack concurrently without failures and with a deterministic end result. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 80e7342 commit 6241ce2

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

refs/reftable-backend.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,8 @@ static int prepare_transaction_update(struct write_transaction_table_arg **out,
770770
if (ret)
771771
return ret;
772772

773-
ret = reftable_stack_new_addition(&addition, stack, 0);
773+
ret = reftable_stack_new_addition(&addition, stack,
774+
REFTABLE_STACK_NEW_ADDITION_RELOAD);
774775
if (ret) {
775776
if (ret == REFTABLE_LOCK_ERROR)
776777
strbuf_addstr(err, "cannot lock references");

t/t0610-reftable-basics.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,37 @@ test_expect_success 'ref transaction: retry acquiring tables.list lock' '
450450
)
451451
'
452452

453+
test_expect_success 'ref transaction: many concurrent writers' '
454+
test_when_finished "rm -rf repo" &&
455+
git init repo &&
456+
(
457+
cd repo &&
458+
# Set a high timeout such that a busy CI machine will not abort
459+
# early. 10 seconds should hopefully be ample of time to make
460+
# this non-flaky.
461+
git config set reftable.lockTimeout 10000 &&
462+
test_commit --no-tag initial &&
463+
464+
head=$(git rev-parse HEAD) &&
465+
for i in $(test_seq 100)
466+
do
467+
printf "%s commit\trefs/heads/branch-%s\n" "$head" "$i" ||
468+
return 1
469+
done >expect &&
470+
printf "%s commit\trefs/heads/main\n" "$head" >>expect &&
471+
472+
for i in $(test_seq 100)
473+
do
474+
{ git update-ref refs/heads/branch-$i HEAD& } ||
475+
return 1
476+
done &&
477+
478+
wait &&
479+
git for-each-ref --sort=v:refname >actual &&
480+
test_cmp expect actual
481+
)
482+
'
483+
453484
test_expect_success 'pack-refs: compacts tables' '
454485
test_when_finished "rm -rf repo" &&
455486
git init repo &&

0 commit comments

Comments
 (0)