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:
Junio C Hamano
2025-02-14 17:53:48 -08:00
9 changed files with 118 additions and 46 deletions

24
refs.c
View File

@@ -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
View File

@@ -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

View File

@@ -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;
};
/*

View File

@@ -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};

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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)

View File

@@ -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");