aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--refs/reftable-backend.c4
-rw-r--r--reftable/reftable-stack.h13
-rw-r--r--reftable/stack.c20
-rw-r--r--t/unit-tests/t-reftable-stack.c67
4 files changed, 91 insertions, 13 deletions
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index ca281e39a2..6ca00627dd 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -770,7 +770,7 @@ static int prepare_transaction_update(struct write_transaction_table_arg **out,
if (ret)
return ret;
- ret = reftable_stack_new_addition(&addition, stack);
+ ret = reftable_stack_new_addition(&addition, stack, 0);
if (ret) {
if (ret == REFTABLE_LOCK_ERROR)
strbuf_addstr(err, "cannot lock references");
@@ -2207,7 +2207,7 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
if (ret < 0)
goto done;
- ret = reftable_stack_new_addition(&add, stack);
+ ret = reftable_stack_new_addition(&add, stack, 0);
if (ret < 0)
goto done;
diff --git a/reftable/reftable-stack.h b/reftable/reftable-stack.h
index f4f8cabc7f..6370fe45dd 100644
--- a/reftable/reftable-stack.h
+++ b/reftable/reftable-stack.h
@@ -37,12 +37,21 @@ uint64_t reftable_stack_next_update_index(struct reftable_stack *st);
/* holds a transaction to add tables at the top of a stack. */
struct reftable_addition;
+enum {
+ /*
+ * Reload the stack when the stack is out-of-date after locking it.
+ */
+ REFTABLE_STACK_NEW_ADDITION_RELOAD = (1 << 0),
+};
+
/*
* returns a new transaction to add reftables to the given stack. As a side
- * effect, the ref database is locked.
+ * effect, the ref database is locked. Accepts REFTABLE_STACK_NEW_ADDITION_*
+ * flags.
*/
int reftable_stack_new_addition(struct reftable_addition **dest,
- struct reftable_stack *st);
+ struct reftable_stack *st,
+ unsigned int flags);
/* Adds a reftable to transaction. */
int reftable_addition_add(struct reftable_addition *add,
diff --git a/reftable/stack.c b/reftable/stack.c
index 5ccad2cff3..84cf37a2ad 100644
--- a/reftable/stack.c
+++ b/reftable/stack.c
@@ -596,7 +596,8 @@ struct reftable_addition {
#define REFTABLE_ADDITION_INIT {0}
static int reftable_stack_init_addition(struct reftable_addition *add,
- struct reftable_stack *st)
+ struct reftable_stack *st,
+ unsigned int flags)
{
struct strbuf lock_file_name = STRBUF_INIT;
int err;
@@ -626,6 +627,11 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
err = stack_uptodate(st);
if (err < 0)
goto done;
+ if (err > 0 && flags & REFTABLE_STACK_NEW_ADDITION_RELOAD) {
+ err = reftable_stack_reload_maybe_reuse(add->stack, 1);
+ if (err)
+ goto done;
+ }
if (err > 0) {
err = REFTABLE_OUTDATED_ERROR;
goto done;
@@ -633,9 +639,8 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
add->next_update_index = reftable_stack_next_update_index(st);
done:
- if (err) {
+ if (err)
reftable_addition_close(add);
- }
strbuf_release(&lock_file_name);
return err;
}
@@ -739,13 +744,14 @@ done:
}
int reftable_stack_new_addition(struct reftable_addition **dest,
- struct reftable_stack *st)
+ struct reftable_stack *st,
+ unsigned int flags)
{
int err = 0;
struct reftable_addition empty = REFTABLE_ADDITION_INIT;
REFTABLE_CALLOC_ARRAY(*dest, 1);
**dest = empty;
- err = reftable_stack_init_addition(*dest, st);
+ err = reftable_stack_init_addition(*dest, st, flags);
if (err) {
reftable_free(*dest);
*dest = NULL;
@@ -759,7 +765,7 @@ static int stack_try_add(struct reftable_stack *st,
void *arg)
{
struct reftable_addition add = REFTABLE_ADDITION_INIT;
- int err = reftable_stack_init_addition(&add, st);
+ int err = reftable_stack_init_addition(&add, st, 0);
if (err < 0)
goto done;
@@ -1608,7 +1614,7 @@ static int reftable_stack_clean_locked(struct reftable_stack *st)
int reftable_stack_clean(struct reftable_stack *st)
{
struct reftable_addition *add = NULL;
- int err = reftable_stack_new_addition(&add, st);
+ int err = reftable_stack_new_addition(&add, st, 0);
if (err < 0) {
goto done;
}
diff --git a/t/unit-tests/t-reftable-stack.c b/t/unit-tests/t-reftable-stack.c
index d62a9c1bed..a37cc698d8 100644
--- a/t/unit-tests/t-reftable-stack.c
+++ b/t/unit-tests/t-reftable-stack.c
@@ -271,7 +271,7 @@ static void t_reftable_stack_transaction_api(void)
reftable_addition_destroy(add);
- err = reftable_stack_new_addition(&add, st);
+ err = reftable_stack_new_addition(&add, st, 0);
check(!err);
err = reftable_addition_add(add, write_test_ref, &ref);
@@ -292,6 +292,68 @@ static void t_reftable_stack_transaction_api(void)
clear_dir(dir);
}
+static void t_reftable_stack_transaction_with_reload(void)
+{
+ char *dir = get_tmp_dir(__LINE__);
+ struct reftable_stack *st1 = NULL, *st2 = NULL;
+ int err;
+ struct reftable_addition *add = NULL;
+ struct reftable_ref_record refs[2] = {
+ {
+ .refname = (char *) "refs/heads/a",
+ .update_index = 1,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { '1' },
+ },
+ {
+ .refname = (char *) "refs/heads/b",
+ .update_index = 2,
+ .value_type = REFTABLE_REF_VAL1,
+ .value.val1 = { '1' },
+ },
+ };
+ struct reftable_ref_record ref = { 0 };
+
+ err = reftable_new_stack(&st1, dir, NULL);
+ check(!err);
+ err = reftable_new_stack(&st2, dir, NULL);
+ check(!err);
+
+ err = reftable_stack_new_addition(&add, st1, 0);
+ check(!err);
+ err = reftable_addition_add(add, write_test_ref, &refs[0]);
+ check(!err);
+ err = reftable_addition_commit(add);
+ check(!err);
+ reftable_addition_destroy(add);
+
+ /*
+ * The second stack is now outdated, which we should notice. We do not
+ * create the addition and lock the stack by default, but allow the
+ * reload to happen when REFTABLE_STACK_NEW_ADDITION_RELOAD is set.
+ */
+ err = reftable_stack_new_addition(&add, st2, 0);
+ check_int(err, ==, REFTABLE_OUTDATED_ERROR);
+ err = reftable_stack_new_addition(&add, st2, REFTABLE_STACK_NEW_ADDITION_RELOAD);
+ check(!err);
+ err = reftable_addition_add(add, write_test_ref, &refs[1]);
+ check(!err);
+ err = reftable_addition_commit(add);
+ check(!err);
+ reftable_addition_destroy(add);
+
+ for (size_t i = 0; i < ARRAY_SIZE(refs); i++) {
+ err = reftable_stack_read_ref(st2, refs[i].refname, &ref);
+ check(!err);
+ check(reftable_ref_record_equal(&refs[i], &ref, GIT_SHA1_RAWSZ));
+ }
+
+ reftable_ref_record_release(&ref);
+ reftable_stack_destroy(st1);
+ reftable_stack_destroy(st2);
+ clear_dir(dir);
+}
+
static void t_reftable_stack_transaction_api_performs_auto_compaction(void)
{
char *dir = get_tmp_dir(__LINE__);
@@ -322,7 +384,7 @@ static void t_reftable_stack_transaction_api_performs_auto_compaction(void)
*/
st->opts.disable_auto_compact = i != n;
- err = reftable_stack_new_addition(&add, st);
+ err = reftable_stack_new_addition(&add, st, 0);
check(!err);
err = reftable_addition_add(add, write_test_ref, &ref);
@@ -1314,6 +1376,7 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
TEST(t_reftable_stack_reload_with_missing_table(), "stack iteration with garbage tables");
TEST(t_reftable_stack_tombstone(), "'tombstone' refs in stack");
TEST(t_reftable_stack_transaction_api(), "update transaction to stack");
+ TEST(t_reftable_stack_transaction_with_reload(), "transaction with reload");
TEST(t_reftable_stack_transaction_api_performs_auto_compaction(), "update transaction triggers auto-compaction");
TEST(t_reftable_stack_update_index_check(), "update transactions with equal update indices");
TEST(t_reftable_stack_uptodate(), "stack must be reloaded before ref update");