Skip to content

Commit 611986f

Browse files
KarthikNayakgitster
authored andcommitted
refs/files: add count field to ref_lock
When refs are updated in the files-backend, a lock is obtained for the corresponding file path. This is the case even for reflogs, i.e. a lock is obtained on the reference path instead of the reflog path. This works, since generally, reflogs are updated alongside the ref. The upcoming patches will add support for reflog updates in ref transaction. This means, in a particular transaction we want to have ref updates and reflog updates. For a given ref in a given transaction there can be at most one update. But we can theoretically have multiple reflog updates for a given ref in a given transaction. A great example of this would be when migrating reflogs from one backend to another. There we would batch all the reflog updates for a given reference in a single transaction. The current flow does not support this, because currently refs & reflogs are treated as a single entity and capture the lock together. To separate this, add a count field to ref_lock. With this, multiple updates can hold onto a single ref_lock and the lock will only be released when all of them release the lock. This patch only adds the `count` field to `ref_lock` and adds the logic to increment and decrement the lock. In a follow up commit, we'll separate the reflog update logic from ref updates and utilize this functionality. Signed-off-by: Karthik Nayak <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent a3582e2 commit 611986f

File tree

1 file changed

+39
-19
lines changed

1 file changed

+39
-19
lines changed

refs/files-backend.c

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ struct ref_lock {
7171
char *ref_name;
7272
struct lock_file lk;
7373
struct object_id old_oid;
74+
unsigned int count; /* track users of the lock (ref update + reflog updates) */
7475
};
7576

7677
struct files_ref_store {
@@ -638,9 +639,12 @@ int parse_loose_ref_contents(const struct git_hash_algo *algop,
638639

639640
static void unlock_ref(struct ref_lock *lock)
640641
{
641-
rollback_lock_file(&lock->lk);
642-
free(lock->ref_name);
643-
free(lock);
642+
lock->count--;
643+
if (!lock->count) {
644+
rollback_lock_file(&lock->lk);
645+
free(lock->ref_name);
646+
free(lock);
647+
}
644648
}
645649

646650
/*
@@ -696,6 +700,7 @@ static int lock_raw_ref(struct files_ref_store *refs,
696700
*lock_p = CALLOC_ARRAY(lock, 1);
697701

698702
lock->ref_name = xstrdup(refname);
703+
lock->count = 1;
699704
files_ref_path(refs, &ref_file, refname);
700705

701706
retry:
@@ -1169,6 +1174,7 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs,
11691174
goto error_return;
11701175

11711176
lock->ref_name = xstrdup(refname);
1177+
lock->count = 1;
11721178

11731179
if (raceproof_create_file(ref_file.buf, create_reflock, &lock->lk)) {
11741180
unable_to_lock_message(ref_file.buf, errno, err);
@@ -2535,6 +2541,12 @@ static int check_old_oid(struct ref_update *update, struct object_id *oid,
25352541
return -1;
25362542
}
25372543

2544+
struct files_transaction_backend_data {
2545+
struct ref_transaction *packed_transaction;
2546+
int packed_refs_locked;
2547+
struct strmap ref_locks;
2548+
};
2549+
25382550
/*
25392551
* Prepare for carrying out update:
25402552
* - Lock the reference referred to by update.
@@ -2557,11 +2569,14 @@ static int lock_ref_for_update(struct files_ref_store *refs,
25572569
{
25582570
struct strbuf referent = STRBUF_INIT;
25592571
int mustexist = ref_update_expects_existing_old_ref(update);
2572+
struct files_transaction_backend_data *backend_data;
25602573
int ret = 0;
25612574
struct ref_lock *lock;
25622575

25632576
files_assert_main_repository(refs, "lock_ref_for_update");
25642577

2578+
backend_data = transaction->backend_data;
2579+
25652580
if ((update->flags & REF_HAVE_NEW) && ref_update_has_null_new_value(update))
25662581
update->flags |= REF_DELETING;
25672582

@@ -2572,18 +2587,25 @@ static int lock_ref_for_update(struct files_ref_store *refs,
25722587
goto out;
25732588
}
25742589

2575-
ret = lock_raw_ref(refs, update->refname, mustexist,
2576-
affected_refnames,
2577-
&lock, &referent,
2578-
&update->type, err);
2579-
if (ret) {
2580-
char *reason;
2590+
lock = strmap_get(&backend_data->ref_locks, update->refname);
2591+
if (lock) {
2592+
lock->count++;
2593+
} else {
2594+
ret = lock_raw_ref(refs, update->refname, mustexist,
2595+
affected_refnames,
2596+
&lock, &referent,
2597+
&update->type, err);
2598+
if (ret) {
2599+
char *reason;
2600+
2601+
reason = strbuf_detach(err, NULL);
2602+
strbuf_addf(err, "cannot lock ref '%s': %s",
2603+
ref_update_original_update_refname(update), reason);
2604+
free(reason);
2605+
goto out;
2606+
}
25812607

2582-
reason = strbuf_detach(err, NULL);
2583-
strbuf_addf(err, "cannot lock ref '%s': %s",
2584-
ref_update_original_update_refname(update), reason);
2585-
free(reason);
2586-
goto out;
2608+
strmap_put(&backend_data->ref_locks, update->refname, lock);
25872609
}
25882610

25892611
update->backend_data = lock;
@@ -2730,11 +2752,6 @@ static int lock_ref_for_update(struct files_ref_store *refs,
27302752
return ret;
27312753
}
27322754

2733-
struct files_transaction_backend_data {
2734-
struct ref_transaction *packed_transaction;
2735-
int packed_refs_locked;
2736-
};
2737-
27382755
/*
27392756
* Unlock any references in `transaction` that are still locked, and
27402757
* mark the transaction closed.
@@ -2767,6 +2784,8 @@ static void files_transaction_cleanup(struct files_ref_store *refs,
27672784
if (backend_data->packed_refs_locked)
27682785
packed_refs_unlock(refs->packed_ref_store);
27692786

2787+
strmap_clear(&backend_data->ref_locks, 0);
2788+
27702789
free(backend_data);
27712790
}
27722791

@@ -2796,6 +2815,7 @@ static int files_transaction_prepare(struct ref_store *ref_store,
27962815
goto cleanup;
27972816

27982817
CALLOC_ARRAY(backend_data, 1);
2818+
strmap_init(&backend_data->ref_locks);
27992819
transaction->backend_data = backend_data;
28002820

28012821
/*

0 commit comments

Comments
 (0)