Skip to content

Commit 5f5e2a8

Browse files
mhaggergitster
authored andcommitted
refs: manage lifetime of packed refs cache via reference counting
In struct packed_ref_cache, keep a count of the number of users of the data structure. Only free the packed ref cache when the reference count goes to zero rather than when the packed ref cache is cleared. This mechanism will be used to prevent the cache data structure from being freed while it is being iterated over. So far, only the reference in struct ref_cache::packed is counted; other users will be adjusted in separate commits. Signed-off-by: Michael Haggerty <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 9f69d29 commit 5f5e2a8

File tree

1 file changed

+36
-3
lines changed

1 file changed

+36
-3
lines changed

refs.c

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,14 @@ static int is_refname_available(const char *refname, const char *oldrefname,
809809
struct packed_ref_cache {
810810
struct ref_entry *root;
811811

812+
/*
813+
* Count of references to the data structure in this instance,
814+
* including the pointer from ref_cache::packed if any. The
815+
* data will not be freed as long as the reference count is
816+
* nonzero.
817+
*/
818+
unsigned int referrers;
819+
812820
/*
813821
* Iff the packed-refs file associated with this instance is
814822
* currently locked for writing, this points at the associated
@@ -836,14 +844,38 @@ static struct ref_cache {
836844
/* Lock used for the main packed-refs file: */
837845
static struct lock_file packlock;
838846

847+
/*
848+
* Increment the reference count of *packed_refs.
849+
*/
850+
static void acquire_packed_ref_cache(struct packed_ref_cache *packed_refs)
851+
{
852+
packed_refs->referrers++;
853+
}
854+
855+
/*
856+
* Decrease the reference count of *packed_refs. If it goes to zero,
857+
* free *packed_refs and return true; otherwise return false.
858+
*/
859+
static int release_packed_ref_cache(struct packed_ref_cache *packed_refs)
860+
{
861+
if (!--packed_refs->referrers) {
862+
free_ref_entry(packed_refs->root);
863+
free(packed_refs);
864+
return 1;
865+
} else {
866+
return 0;
867+
}
868+
}
869+
839870
static void clear_packed_ref_cache(struct ref_cache *refs)
840871
{
841872
if (refs->packed) {
842-
if (refs->packed->lock)
873+
struct packed_ref_cache *packed_refs = refs->packed;
874+
875+
if (packed_refs->lock)
843876
die("internal error: packed-ref cache cleared while locked");
844-
free_ref_entry(refs->packed->root);
845-
free(refs->packed);
846877
refs->packed = NULL;
878+
release_packed_ref_cache(packed_refs);
847879
}
848880
}
849881

@@ -1024,6 +1056,7 @@ static struct packed_ref_cache *get_packed_ref_cache(struct ref_cache *refs)
10241056
FILE *f;
10251057

10261058
refs->packed = xcalloc(1, sizeof(*refs->packed));
1059+
acquire_packed_ref_cache(refs->packed);
10271060
refs->packed->root = create_dir_entry(refs, "", 0, 0);
10281061
if (*refs->name)
10291062
packed_refs_file = git_path_submodule(refs->name, "packed-refs");

0 commit comments

Comments
 (0)