mirror of
https://github.com/git/git
synced 2024-07-16 18:48:26 +00:00
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 <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
33358350eb
commit
a2f711ade0
|
@ -680,8 +680,19 @@ int reftable_addition_commit(struct reftable_addition *add)
|
||||||
if (err)
|
if (err)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (!add->stack->disable_auto_compact)
|
if (!add->stack->disable_auto_compact) {
|
||||||
|
/*
|
||||||
|
* Auto-compact the stack to keep the number of tables in
|
||||||
|
* control. It is possible that a concurrent writer is already
|
||||||
|
* trying to compact parts of the stack, which would lead to a
|
||||||
|
* `REFTABLE_LOCK_ERROR` because parts of the stack are locked
|
||||||
|
* already. This is a benign error though, so we ignore it.
|
||||||
|
*/
|
||||||
err = reftable_stack_auto_compact(add->stack);
|
err = reftable_stack_auto_compact(add->stack);
|
||||||
|
if (err < 0 && err != REFTABLE_LOCK_ERROR)
|
||||||
|
goto done;
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
reftable_addition_close(add);
|
reftable_addition_close(add);
|
||||||
|
|
|
@ -343,6 +343,49 @@ static void test_reftable_stack_transaction_api_performs_auto_compaction(void)
|
||||||
clear_dir(dir);
|
clear_dir(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_reftable_stack_auto_compaction_fails_gracefully(void)
|
||||||
|
{
|
||||||
|
struct reftable_ref_record ref = {
|
||||||
|
.refname = "refs/heads/master",
|
||||||
|
.update_index = 1,
|
||||||
|
.value_type = REFTABLE_REF_VAL1,
|
||||||
|
.value.val1 = {0x01},
|
||||||
|
};
|
||||||
|
struct reftable_write_options cfg = {0};
|
||||||
|
struct reftable_stack *st;
|
||||||
|
struct strbuf table_path = STRBUF_INIT;
|
||||||
|
char *dir = get_tmp_dir(__LINE__);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = reftable_new_stack(&st, dir, cfg);
|
||||||
|
EXPECT_ERR(err);
|
||||||
|
|
||||||
|
err = reftable_stack_add(st, write_test_ref, &ref);
|
||||||
|
EXPECT_ERR(err);
|
||||||
|
EXPECT(st->merged->stack_len == 1);
|
||||||
|
EXPECT(st->stats.attempts == 0);
|
||||||
|
EXPECT(st->stats.failures == 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lock the newly written table such that it cannot be compacted.
|
||||||
|
* Adding a new table to the stack should not be impacted by this, even
|
||||||
|
* though auto-compaction will now fail.
|
||||||
|
*/
|
||||||
|
strbuf_addf(&table_path, "%s/%s.lock", dir, st->readers[0]->name);
|
||||||
|
write_file_buf(table_path.buf, "", 0);
|
||||||
|
|
||||||
|
ref.update_index = 2;
|
||||||
|
err = reftable_stack_add(st, write_test_ref, &ref);
|
||||||
|
EXPECT_ERR(err);
|
||||||
|
EXPECT(st->merged->stack_len == 2);
|
||||||
|
EXPECT(st->stats.attempts == 1);
|
||||||
|
EXPECT(st->stats.failures == 1);
|
||||||
|
|
||||||
|
reftable_stack_destroy(st);
|
||||||
|
strbuf_release(&table_path);
|
||||||
|
clear_dir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_reftable_stack_validate_refname(void)
|
static void test_reftable_stack_validate_refname(void)
|
||||||
{
|
{
|
||||||
struct reftable_write_options cfg = { 0 };
|
struct reftable_write_options cfg = { 0 };
|
||||||
|
@ -1089,6 +1132,7 @@ int stack_test_main(int argc, const char *argv[])
|
||||||
RUN_TEST(test_reftable_stack_tombstone);
|
RUN_TEST(test_reftable_stack_tombstone);
|
||||||
RUN_TEST(test_reftable_stack_transaction_api);
|
RUN_TEST(test_reftable_stack_transaction_api);
|
||||||
RUN_TEST(test_reftable_stack_transaction_api_performs_auto_compaction);
|
RUN_TEST(test_reftable_stack_transaction_api_performs_auto_compaction);
|
||||||
|
RUN_TEST(test_reftable_stack_auto_compaction_fails_gracefully);
|
||||||
RUN_TEST(test_reftable_stack_update_index_check);
|
RUN_TEST(test_reftable_stack_update_index_check);
|
||||||
RUN_TEST(test_reftable_stack_uptodate);
|
RUN_TEST(test_reftable_stack_uptodate);
|
||||||
RUN_TEST(test_reftable_stack_validate_refname);
|
RUN_TEST(test_reftable_stack_validate_refname);
|
||||||
|
|
|
@ -340,6 +340,26 @@ test_expect_success 'ref transaction: empty transaction in empty repo' '
|
||||||
EOF
|
EOF
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ref transaction: fails gracefully when auto compaction fails' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
|
||||||
|
test_commit A &&
|
||||||
|
for i in $(test_seq 10)
|
||||||
|
do
|
||||||
|
git branch branch-$i &&
|
||||||
|
for table in .git/reftable/*.ref
|
||||||
|
do
|
||||||
|
touch "$table.lock" || exit 1
|
||||||
|
done ||
|
||||||
|
exit 1
|
||||||
|
done &&
|
||||||
|
test_line_count = 13 .git/reftable/tables.list
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'pack-refs: compacts tables' '
|
test_expect_success 'pack-refs: compacts tables' '
|
||||||
test_when_finished "rm -rf repo" &&
|
test_when_finished "rm -rf repo" &&
|
||||||
git init repo &&
|
git init repo &&
|
||||||
|
|
Loading…
Reference in a new issue