Skip to content

Commit 297c09e

Browse files
KarthikNayakgitster
authored andcommitted
refs: allow multiple reflog entries for the same refname
The reference transaction only allows a single update for a given reference to avoid conflicts. This, however, isn't an issue for reflogs. There are no conflicts to be resolved in reflogs and when migrating reflogs between backends we'd have multiple reflog entries for the same refname. So allow multiple reflog updates within a single transaction. Also the reflog creation logic isn't exposed to the end user. While this might change in the future, currently, this reduces the scope of issues to think about. In the reftable backend, the writer sorts all updates based on the update_index before writing to the block. When there are multiple reflogs for a given refname, it is essential that the order of the reflogs is maintained. So add the `index` value to the `update_index`. The `index` field is only set when multiple reflog entries for a given refname are added and as such in most scenarios the old behavior remains. This is required to add reflog migration support to `git refs migrate`. Signed-off-by: Karthik Nayak <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 84675fa commit 297c09e

File tree

2 files changed

+30
-7
lines changed

2 files changed

+30
-7
lines changed

refs/files-backend.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2611,6 +2611,9 @@ static int lock_ref_for_update(struct files_ref_store *refs,
26112611

26122612
update->backend_data = lock;
26132613

2614+
if (update->flags & REF_LOG_ONLY)
2615+
goto out;
2616+
26142617
if (update->type & REF_ISSYMREF) {
26152618
if (update->flags & REF_NO_DEREF) {
26162619
/*
@@ -2829,13 +2832,16 @@ static int files_transaction_prepare(struct ref_store *ref_store,
28292832
*/
28302833
for (i = 0; i < transaction->nr; i++) {
28312834
struct ref_update *update = transaction->updates[i];
2832-
struct string_list_item *item =
2833-
string_list_append(&affected_refnames, update->refname);
2835+
struct string_list_item *item;
28342836

28352837
if ((update->flags & REF_IS_PRUNING) &&
28362838
!(update->flags & REF_NO_DEREF))
28372839
BUG("REF_IS_PRUNING set without REF_NO_DEREF");
28382840

2841+
if (update->flags & REF_LOG_ONLY)
2842+
continue;
2843+
2844+
item = string_list_append(&affected_refnames, update->refname);
28392845
/*
28402846
* We store a pointer to update in item->util, but at
28412847
* the moment we never use the value of this field
@@ -3035,8 +3041,9 @@ static int files_transaction_finish_initial(struct files_ref_store *refs,
30353041

30363042
/* Fail if a refname appears more than once in the transaction: */
30373043
for (i = 0; i < transaction->nr; i++)
3038-
string_list_append(&affected_refnames,
3039-
transaction->updates[i]->refname);
3044+
if (!(transaction->updates[i]->flags & REF_LOG_ONLY))
3045+
string_list_append(&affected_refnames,
3046+
transaction->updates[i]->refname);
30403047
string_list_sort(&affected_refnames);
30413048
if (ref_update_reject_duplicates(&affected_refnames, err)) {
30423049
ret = TRANSACTION_GENERIC_ERROR;

refs/reftable-backend.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -990,8 +990,9 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
990990
if (ret)
991991
goto done;
992992

993-
string_list_append(&affected_refnames,
994-
transaction->updates[i]->refname);
993+
if (!(transaction->updates[i]->flags & REF_LOG_ONLY))
994+
string_list_append(&affected_refnames,
995+
transaction->updates[i]->refname);
995996
}
996997

997998
/*
@@ -1301,6 +1302,7 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
13011302
struct reftable_log_record *logs = NULL;
13021303
struct ident_split committer_ident = {0};
13031304
size_t logs_nr = 0, logs_alloc = 0, i;
1305+
uint64_t max_update_index = ts;
13041306
const char *committer_info;
13051307
int ret = 0;
13061308

@@ -1405,7 +1407,19 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
14051407
}
14061408

14071409
fill_reftable_log_record(log, &c);
1408-
log->update_index = ts;
1410+
1411+
/*
1412+
* Updates are sorted by the writer. So updates for the same
1413+
* refname need to contain different update indices.
1414+
*/
1415+
log->update_index = ts + u->index;
1416+
1417+
/*
1418+
* Note the max update_index so the limit can be set later on.
1419+
*/
1420+
if (log->update_index > max_update_index)
1421+
max_update_index = log->update_index;
1422+
14091423
log->refname = xstrdup(u->refname);
14101424
memcpy(log->value.update.new_hash,
14111425
u->new_oid.hash, GIT_MAX_RAWSZ);
@@ -1469,6 +1483,8 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
14691483
* and log blocks.
14701484
*/
14711485
if (logs) {
1486+
reftable_writer_set_limits(writer, ts, max_update_index);
1487+
14721488
ret = reftable_writer_add_logs(writer, logs, logs_nr);
14731489
if (ret < 0)
14741490
goto done;

0 commit comments

Comments
 (0)