Merge branch 'kn/reflog-migration-fix-followup'
Code clean-up. * kn/reflog-migration-fix-followup: reftable: prevent 'update_index' changes after adding records refs: use 'uint64_t' for 'ref_update.index' refs: mark `ref_transaction_update_reflog()` as static
This commit is contained in:
24
refs.c
24
refs.c
@@ -1318,13 +1318,21 @@ int ref_transaction_update(struct ref_transaction *transaction,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ref_transaction_update_reflog(struct ref_transaction *transaction,
|
||||
const char *refname,
|
||||
const struct object_id *new_oid,
|
||||
const struct object_id *old_oid,
|
||||
const char *committer_info, unsigned int flags,
|
||||
const char *msg, unsigned int index,
|
||||
struct strbuf *err)
|
||||
/*
|
||||
* Similar to`ref_transaction_update`, but this function is only for adding
|
||||
* a reflog update. Supports providing custom committer information. The index
|
||||
* field can be utiltized to order updates as desired. When not used, the
|
||||
* updates default to being ordered by refname.
|
||||
*/
|
||||
static int ref_transaction_update_reflog(struct ref_transaction *transaction,
|
||||
const char *refname,
|
||||
const struct object_id *new_oid,
|
||||
const struct object_id *old_oid,
|
||||
const char *committer_info,
|
||||
unsigned int flags,
|
||||
const char *msg,
|
||||
uint64_t index,
|
||||
struct strbuf *err)
|
||||
{
|
||||
struct ref_update *update;
|
||||
|
||||
@@ -2805,7 +2813,7 @@ done:
|
||||
}
|
||||
|
||||
struct reflog_migration_data {
|
||||
unsigned int index;
|
||||
uint64_t index;
|
||||
const char *refname;
|
||||
struct ref_store *old_refs;
|
||||
struct ref_transaction *transaction;
|
||||
|
||||
14
refs.h
14
refs.h
@@ -771,20 +771,6 @@ int ref_transaction_update(struct ref_transaction *transaction,
|
||||
unsigned int flags, const char *msg,
|
||||
struct strbuf *err);
|
||||
|
||||
/*
|
||||
* Similar to`ref_transaction_update`, but this function is only for adding
|
||||
* a reflog update. Supports providing custom committer information. The index
|
||||
* field can be utiltized to order updates as desired. When not used, the
|
||||
* updates default to being ordered by refname.
|
||||
*/
|
||||
int ref_transaction_update_reflog(struct ref_transaction *transaction,
|
||||
const char *refname,
|
||||
const struct object_id *new_oid,
|
||||
const struct object_id *old_oid,
|
||||
const char *committer_info, unsigned int flags,
|
||||
const char *msg, unsigned int index,
|
||||
struct strbuf *err);
|
||||
|
||||
/*
|
||||
* Add a reference creation to transaction. new_oid is the value that
|
||||
* the reference should have after the update; it must not be
|
||||
|
||||
@@ -120,7 +120,7 @@ struct ref_update {
|
||||
* when migrating reflogs and we want to ensure we carry over the
|
||||
* same order.
|
||||
*/
|
||||
unsigned int index;
|
||||
uint64_t index;
|
||||
|
||||
/*
|
||||
* If this ref_update was split off of a symref update via
|
||||
@@ -203,7 +203,7 @@ struct ref_transaction {
|
||||
enum ref_transaction_state state;
|
||||
void *backend_data;
|
||||
unsigned int flags;
|
||||
unsigned int max_index;
|
||||
uint64_t max_index;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -942,7 +942,7 @@ struct write_transaction_table_arg {
|
||||
size_t updates_nr;
|
||||
size_t updates_alloc;
|
||||
size_t updates_expected;
|
||||
unsigned int max_index;
|
||||
uint64_t max_index;
|
||||
};
|
||||
|
||||
struct reftable_transaction_data {
|
||||
@@ -1444,7 +1444,9 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
|
||||
* multiple entries. Each entry will contain a different update_index,
|
||||
* so set the limits accordingly.
|
||||
*/
|
||||
reftable_writer_set_limits(writer, ts, ts + arg->max_index);
|
||||
ret = reftable_writer_set_limits(writer, ts, ts + arg->max_index);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
for (i = 0; i < arg->updates_nr; i++) {
|
||||
struct reftable_transaction_update *tx_update = &arg->updates[i];
|
||||
@@ -1766,7 +1768,9 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
|
||||
deletion_ts = creation_ts = reftable_stack_next_update_index(arg->be->stack);
|
||||
if (arg->delete_old)
|
||||
creation_ts++;
|
||||
reftable_writer_set_limits(writer, deletion_ts, creation_ts);
|
||||
ret = reftable_writer_set_limits(writer, deletion_ts, creation_ts);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* Add the new reference. If this is a rename then we also delete the
|
||||
@@ -2298,7 +2302,9 @@ static int write_reflog_existence_table(struct reftable_writer *writer,
|
||||
if (ret <= 0)
|
||||
goto done;
|
||||
|
||||
reftable_writer_set_limits(writer, ts, ts);
|
||||
ret = reftable_writer_set_limits(writer, ts, ts);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* The existence entry has both old and new object ID set to the
|
||||
@@ -2357,7 +2363,9 @@ static int write_reflog_delete_table(struct reftable_writer *writer, void *cb_da
|
||||
uint64_t ts = reftable_stack_next_update_index(arg->stack);
|
||||
int ret;
|
||||
|
||||
reftable_writer_set_limits(writer, ts, ts);
|
||||
ret = reftable_writer_set_limits(writer, ts, ts);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = reftable_stack_init_log_iterator(arg->stack, &it);
|
||||
if (ret < 0)
|
||||
@@ -2434,7 +2442,9 @@ static int write_reflog_expiry_table(struct reftable_writer *writer, void *cb_da
|
||||
if (arg->records[i].value_type == REFTABLE_LOG_UPDATE)
|
||||
live_records++;
|
||||
|
||||
reftable_writer_set_limits(writer, ts, ts);
|
||||
ret = reftable_writer_set_limits(writer, ts, ts);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!is_null_oid(&arg->update_oid)) {
|
||||
struct reftable_ref_record ref = {0};
|
||||
|
||||
@@ -30,6 +30,7 @@ enum reftable_error {
|
||||
|
||||
/* Misuse of the API:
|
||||
* - on writing a record with NULL refname.
|
||||
* - on writing a record before setting the writer limits.
|
||||
* - on writing a reftable_ref_record outside the table limits
|
||||
* - on writing a ref or log record before the stack's
|
||||
* next_update_inde*x
|
||||
|
||||
@@ -124,17 +124,21 @@ int reftable_writer_new(struct reftable_writer **out,
|
||||
int (*flush_func)(void *),
|
||||
void *writer_arg, const struct reftable_write_options *opts);
|
||||
|
||||
/* Set the range of update indices for the records we will add. When writing a
|
||||
table into a stack, the min should be at least
|
||||
reftable_stack_next_update_index(), or REFTABLE_API_ERROR is returned.
|
||||
|
||||
For transactional updates to a stack, typically min==max, and the
|
||||
update_index can be obtained by inspeciting the stack. When converting an
|
||||
existing ref database into a single reftable, this would be a range of
|
||||
update-index timestamps.
|
||||
/*
|
||||
* Set the range of update indices for the records we will add. When writing a
|
||||
* table into a stack, the min should be at least
|
||||
* reftable_stack_next_update_index(), or REFTABLE_API_ERROR is returned.
|
||||
*
|
||||
* For transactional updates to a stack, typically min==max, and the
|
||||
* update_index can be obtained by inspeciting the stack. When converting an
|
||||
* existing ref database into a single reftable, this would be a range of
|
||||
* update-index timestamps.
|
||||
*
|
||||
* The function should be called before adding any records to the writer. If not
|
||||
* it will fail with REFTABLE_API_ERROR.
|
||||
*/
|
||||
void reftable_writer_set_limits(struct reftable_writer *w, uint64_t min,
|
||||
uint64_t max);
|
||||
int reftable_writer_set_limits(struct reftable_writer *w, uint64_t min,
|
||||
uint64_t max);
|
||||
|
||||
/*
|
||||
Add a reftable_ref_record. The record should have names that come after
|
||||
|
||||
@@ -1058,8 +1058,10 @@ static int stack_write_compact(struct reftable_stack *st,
|
||||
|
||||
for (size_t i = first; i <= last; i++)
|
||||
st->stats.bytes += st->readers[i]->size;
|
||||
reftable_writer_set_limits(wr, st->readers[first]->min_update_index,
|
||||
st->readers[last]->max_update_index);
|
||||
err = reftable_writer_set_limits(wr, st->readers[first]->min_update_index,
|
||||
st->readers[last]->max_update_index);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
err = reftable_merged_table_new(&mt, st->readers + first, subtabs_len,
|
||||
st->opts.hash_id);
|
||||
|
||||
@@ -179,11 +179,24 @@ int reftable_writer_new(struct reftable_writer **out,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reftable_writer_set_limits(struct reftable_writer *w, uint64_t min,
|
||||
int reftable_writer_set_limits(struct reftable_writer *w, uint64_t min,
|
||||
uint64_t max)
|
||||
{
|
||||
/*
|
||||
* Set the min/max update index limits for the reftable writer.
|
||||
* This must be called before adding any records, since:
|
||||
* - The 'next' field gets set after writing the first block.
|
||||
* - The 'last_key' field updates with each new record (but resets
|
||||
* after sections).
|
||||
* Returns REFTABLE_API_ERROR if called after writing has begun.
|
||||
*/
|
||||
if (w->next || w->last_key.len)
|
||||
return REFTABLE_API_ERROR;
|
||||
|
||||
w->min_update_index = min;
|
||||
w->max_update_index = max;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void writer_release(struct reftable_writer *w)
|
||||
|
||||
@@ -103,7 +103,8 @@ static void t_read_file(void)
|
||||
static int write_test_ref(struct reftable_writer *wr, void *arg)
|
||||
{
|
||||
struct reftable_ref_record *ref = arg;
|
||||
reftable_writer_set_limits(wr, ref->update_index, ref->update_index);
|
||||
check(!reftable_writer_set_limits(wr, ref->update_index,
|
||||
ref->update_index));
|
||||
return reftable_writer_add_ref(wr, ref);
|
||||
}
|
||||
|
||||
@@ -143,7 +144,8 @@ static int write_test_log(struct reftable_writer *wr, void *arg)
|
||||
{
|
||||
struct write_log_arg *wla = arg;
|
||||
|
||||
reftable_writer_set_limits(wr, wla->update_index, wla->update_index);
|
||||
check(!reftable_writer_set_limits(wr, wla->update_index,
|
||||
wla->update_index));
|
||||
return reftable_writer_add_log(wr, wla->log);
|
||||
}
|
||||
|
||||
@@ -961,7 +963,7 @@ static void t_reflog_expire(void)
|
||||
|
||||
static int write_nothing(struct reftable_writer *wr, void *arg UNUSED)
|
||||
{
|
||||
reftable_writer_set_limits(wr, 1, 1);
|
||||
check(!reftable_writer_set_limits(wr, 1, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1369,11 +1371,57 @@ static void t_reftable_stack_reload_with_missing_table(void)
|
||||
clear_dir(dir);
|
||||
}
|
||||
|
||||
static int write_limits_after_ref(struct reftable_writer *wr, void *arg)
|
||||
{
|
||||
struct reftable_ref_record *ref = arg;
|
||||
check(!reftable_writer_set_limits(wr, ref->update_index, ref->update_index));
|
||||
check(!reftable_writer_add_ref(wr, ref));
|
||||
return reftable_writer_set_limits(wr, ref->update_index, ref->update_index);
|
||||
}
|
||||
|
||||
static void t_reftable_invalid_limit_updates(void)
|
||||
{
|
||||
struct reftable_ref_record ref = {
|
||||
.refname = (char *) "HEAD",
|
||||
.update_index = 1,
|
||||
.value_type = REFTABLE_REF_SYMREF,
|
||||
.value.symref = (char *) "master",
|
||||
};
|
||||
struct reftable_write_options opts = {
|
||||
.default_permissions = 0660,
|
||||
};
|
||||
struct reftable_addition *add = NULL;
|
||||
char *dir = get_tmp_dir(__LINE__);
|
||||
struct reftable_stack *st = NULL;
|
||||
int err;
|
||||
|
||||
err = reftable_new_stack(&st, dir, &opts);
|
||||
check(!err);
|
||||
|
||||
reftable_addition_destroy(add);
|
||||
|
||||
err = reftable_stack_new_addition(&add, st, 0);
|
||||
check(!err);
|
||||
|
||||
/*
|
||||
* write_limits_after_ref also updates the update indexes after adding
|
||||
* the record. This should cause an err to be returned, since the limits
|
||||
* must be set at the start.
|
||||
*/
|
||||
err = reftable_addition_add(add, write_limits_after_ref, &ref);
|
||||
check_int(err, ==, REFTABLE_API_ERROR);
|
||||
|
||||
reftable_addition_destroy(add);
|
||||
reftable_stack_destroy(st);
|
||||
clear_dir(dir);
|
||||
}
|
||||
|
||||
int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
|
||||
{
|
||||
TEST(t_empty_add(), "empty addition to stack");
|
||||
TEST(t_read_file(), "read_lines works");
|
||||
TEST(t_reflog_expire(), "expire reflog entries");
|
||||
TEST(t_reftable_invalid_limit_updates(), "prevent limit updates after adding records");
|
||||
TEST(t_reftable_stack_add(), "add multiple refs and logs to stack");
|
||||
TEST(t_reftable_stack_add_one(), "add a single ref record to stack");
|
||||
TEST(t_reftable_stack_add_performs_auto_compaction(), "addition to stack triggers auto-compaction");
|
||||
|
||||
Reference in New Issue
Block a user