Skip to content

Commit a2f711a

Browse files
pks-tgitster
authored andcommitted
reftable/stack: gracefully handle failed auto-compaction due to locks
Whenever we commit a new table to the reftable stack we will end up invoking auto-compaction of the stack to keep the total number of tables at bay. This auto-compaction may fail though in case at least one of the tables which we are about to compact is locked. This is indicated by the compaction function returning `REFTABLE_LOCK_ERROR`. We do not handle this case though, and thus bubble that return value up the calling chain, which will ultimately cause a failure. Fix this bug by ignoring `REFTABLE_LOCK_ERROR`. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 3335835 commit a2f711a

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

reftable/stack.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -680,8 +680,19 @@ int reftable_addition_commit(struct reftable_addition *add)
680680
if (err)
681681
goto done;
682682

683-
if (!add->stack->disable_auto_compact)
683+
if (!add->stack->disable_auto_compact) {
684+
/*
685+
* Auto-compact the stack to keep the number of tables in
686+
* control. It is possible that a concurrent writer is already
687+
* trying to compact parts of the stack, which would lead to a
688+
* `REFTABLE_LOCK_ERROR` because parts of the stack are locked
689+
* already. This is a benign error though, so we ignore it.
690+
*/
684691
err = reftable_stack_auto_compact(add->stack);
692+
if (err < 0 && err != REFTABLE_LOCK_ERROR)
693+
goto done;
694+
err = 0;
695+
}
685696

686697
done:
687698
reftable_addition_close(add);

reftable/stack_test.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,49 @@ static void test_reftable_stack_transaction_api_performs_auto_compaction(void)
343343
clear_dir(dir);
344344
}
345345

346+
static void test_reftable_stack_auto_compaction_fails_gracefully(void)
347+
{
348+
struct reftable_ref_record ref = {
349+
.refname = "refs/heads/master",
350+
.update_index = 1,
351+
.value_type = REFTABLE_REF_VAL1,
352+
.value.val1 = {0x01},
353+
};
354+
struct reftable_write_options cfg = {0};
355+
struct reftable_stack *st;
356+
struct strbuf table_path = STRBUF_INIT;
357+
char *dir = get_tmp_dir(__LINE__);
358+
int err;
359+
360+
err = reftable_new_stack(&st, dir, cfg);
361+
EXPECT_ERR(err);
362+
363+
err = reftable_stack_add(st, write_test_ref, &ref);
364+
EXPECT_ERR(err);
365+
EXPECT(st->merged->stack_len == 1);
366+
EXPECT(st->stats.attempts == 0);
367+
EXPECT(st->stats.failures == 0);
368+
369+
/*
370+
* Lock the newly written table such that it cannot be compacted.
371+
* Adding a new table to the stack should not be impacted by this, even
372+
* though auto-compaction will now fail.
373+
*/
374+
strbuf_addf(&table_path, "%s/%s.lock", dir, st->readers[0]->name);
375+
write_file_buf(table_path.buf, "", 0);
376+
377+
ref.update_index = 2;
378+
err = reftable_stack_add(st, write_test_ref, &ref);
379+
EXPECT_ERR(err);
380+
EXPECT(st->merged->stack_len == 2);
381+
EXPECT(st->stats.attempts == 1);
382+
EXPECT(st->stats.failures == 1);
383+
384+
reftable_stack_destroy(st);
385+
strbuf_release(&table_path);
386+
clear_dir(dir);
387+
}
388+
346389
static void test_reftable_stack_validate_refname(void)
347390
{
348391
struct reftable_write_options cfg = { 0 };
@@ -1089,6 +1132,7 @@ int stack_test_main(int argc, const char *argv[])
10891132
RUN_TEST(test_reftable_stack_tombstone);
10901133
RUN_TEST(test_reftable_stack_transaction_api);
10911134
RUN_TEST(test_reftable_stack_transaction_api_performs_auto_compaction);
1135+
RUN_TEST(test_reftable_stack_auto_compaction_fails_gracefully);
10921136
RUN_TEST(test_reftable_stack_update_index_check);
10931137
RUN_TEST(test_reftable_stack_uptodate);
10941138
RUN_TEST(test_reftable_stack_validate_refname);

t/t0610-reftable-basics.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,26 @@ test_expect_success 'ref transaction: empty transaction in empty repo' '
340340
EOF
341341
'
342342

343+
test_expect_success 'ref transaction: fails gracefully when auto compaction fails' '
344+
test_when_finished "rm -rf repo" &&
345+
git init repo &&
346+
(
347+
cd repo &&
348+
349+
test_commit A &&
350+
for i in $(test_seq 10)
351+
do
352+
git branch branch-$i &&
353+
for table in .git/reftable/*.ref
354+
do
355+
touch "$table.lock" || exit 1
356+
done ||
357+
exit 1
358+
done &&
359+
test_line_count = 13 .git/reftable/tables.list
360+
)
361+
'
362+
343363
test_expect_success 'pack-refs: compacts tables' '
344364
test_when_finished "rm -rf repo" &&
345365
git init repo &&

0 commit comments

Comments
 (0)