Skip to content
This repository was archived by the owner on Nov 9, 2017. It is now read-only.

Commit 28e6a34

Browse files
mhaggergitster
authored andcommitted
refs: read loose references lazily
Instead of reading the whole directory of loose references the first time any are needed, only read them on demand, one directory at a time. Use a new ref_entry flag bit REF_INCOMPLETE to indicate that the entry represents a REF_DIR that hasn't been read yet. Whenever any entries from such a directory are needed, read all of the loose references from that directory. Signed-off-by: Michael Haggerty <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 423a1af commit 28e6a34

File tree

1 file changed

+96
-29
lines changed

1 file changed

+96
-29
lines changed

refs.c

Lines changed: 96 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,45 @@ int check_refname_format(const char *refname, int flags)
101101

102102
struct ref_entry;
103103

104+
/*
105+
* Information used (along with the information in ref_entry) to
106+
* describe a single cached reference. This data structure only
107+
* occurs embedded in a union in struct ref_entry, and only when
108+
* (ref_entry->flag & REF_DIR) is zero.
109+
*/
104110
struct ref_value {
105111
unsigned char sha1[20];
106112
unsigned char peeled[20];
107113
};
108114

109115
struct ref_cache;
110116

117+
/*
118+
* Information used (along with the information in ref_entry) to
119+
* describe a level in the hierarchy of references. This data
120+
* structure only occurs embedded in a union in struct ref_entry, and
121+
* only when (ref_entry.flag & REF_DIR) is set. In that case,
122+
* (ref_entry.flag & REF_INCOMPLETE) determines whether the references
123+
* in the directory have already been read:
124+
*
125+
* (ref_entry.flag & REF_INCOMPLETE) unset -- a directory of loose
126+
* or packed references, already read.
127+
*
128+
* (ref_entry.flag & REF_INCOMPLETE) set -- a directory of loose
129+
* references that hasn't been read yet (nor has any of its
130+
* subdirectories).
131+
*
132+
* Entries within a directory are stored within a growable array of
133+
* pointers to ref_entries (entries, nr, alloc). Entries 0 <= i <
134+
* sorted are sorted by their component name in strcmp() order and the
135+
* remaining entries are unsorted.
136+
*
137+
* Loose references are read lazily, one directory at a time. When a
138+
* directory of loose references is read, then all of the references
139+
* in that directory are stored, and REF_INCOMPLETE stubs are created
140+
* for any subdirectories, but the subdirectories themselves are not
141+
* read. The reading is triggered by get_ref_dir().
142+
*/
111143
struct ref_dir {
112144
int nr, alloc;
113145

@@ -127,19 +159,33 @@ struct ref_dir {
127159

128160
/* ISSYMREF=0x01, ISPACKED=0x02, and ISBROKEN=0x04 are public interfaces */
129161
#define REF_KNOWS_PEELED 0x08
162+
163+
/* ref_entry represents a directory of references */
130164
#define REF_DIR 0x10
131165

166+
/*
167+
* Entry has not yet been read from disk (used only for REF_DIR
168+
* entries representing loose references)
169+
*/
170+
#define REF_INCOMPLETE 0x20
171+
132172
/*
133173
* A ref_entry represents either a reference or a "subdirectory" of
134-
* references. Each directory in the reference namespace is
135-
* represented by a ref_entry with (flags & REF_DIR) set and
136-
* containing a subdir member that holds the entries in that
137-
* directory. References are represented by a ref_entry with (flags &
138-
* REF_DIR) unset and a value member that describes the reference's
139-
* value. The flag member is at the ref_entry level, but it is also
140-
* needed to interpret the contents of the value field (in other
141-
* words, a ref_value object is not very much use without the
142-
* enclosing ref_entry).
174+
* references.
175+
*
176+
* Each directory in the reference namespace is represented by a
177+
* ref_entry with (flags & REF_DIR) set and containing a subdir member
178+
* that holds the entries in that directory that have been read so
179+
* far. If (flags & REF_INCOMPLETE) is set, then the directory and
180+
* its subdirectories haven't been read yet. REF_INCOMPLETE is only
181+
* used for loose reference directories.
182+
*
183+
* References are represented by a ref_entry with (flags & REF_DIR)
184+
* unset and a value member that describes the reference's value. The
185+
* flag member is at the ref_entry level, but it is also needed to
186+
* interpret the contents of the value field (in other words, a
187+
* ref_value object is not very much use without the enclosing
188+
* ref_entry).
143189
*
144190
* Reference names cannot end with slash and directories' names are
145191
* always stored with a trailing slash (except for the top-level
@@ -176,10 +222,18 @@ struct ref_entry {
176222
char name[FLEX_ARRAY];
177223
};
178224

225+
static void read_loose_refs(const char *dirname, struct ref_dir *dir);
226+
179227
static struct ref_dir *get_ref_dir(struct ref_entry *entry)
180228
{
229+
struct ref_dir *dir;
181230
assert(entry->flag & REF_DIR);
182-
return &entry->u.subdir;
231+
dir = &entry->u.subdir;
232+
if (entry->flag & REF_INCOMPLETE) {
233+
read_loose_refs(entry->name, dir);
234+
entry->flag &= ~REF_INCOMPLETE;
235+
}
236+
return dir;
183237
}
184238

185239
static struct ref_entry *create_ref_entry(const char *refname,
@@ -240,14 +294,14 @@ static void clear_ref_dir(struct ref_dir *dir)
240294
* "refs/heads/") or "" for the top-level directory.
241295
*/
242296
static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache,
243-
const char *dirname)
297+
const char *dirname, int incomplete)
244298
{
245299
struct ref_entry *direntry;
246300
int len = strlen(dirname);
247301
direntry = xcalloc(1, sizeof(struct ref_entry) + len + 1);
248302
memcpy(direntry->name, dirname, len + 1);
249303
direntry->u.subdir.ref_cache = ref_cache;
250-
direntry->flag = REF_DIR;
304+
direntry->flag = REF_DIR | (incomplete ? REF_INCOMPLETE : 0);
251305
return direntry;
252306
}
253307

@@ -263,7 +317,7 @@ static void sort_ref_dir(struct ref_dir *dir);
263317
/*
264318
* Return the entry with the given refname from the ref_dir
265319
* (non-recursively), sorting dir if necessary. Return NULL if no
266-
* such entry is found.
320+
* such entry is found. dir must already be complete.
267321
*/
268322
static struct ref_entry *search_ref_dir(struct ref_dir *dir, const char *refname)
269323
{
@@ -294,7 +348,7 @@ static struct ref_entry *search_ref_dir(struct ref_dir *dir, const char *refname
294348
* recursing). Sort dir if necessary. subdirname must be a directory
295349
* name (i.e., end in '/'). If mkdir is set, then create the
296350
* directory if it is missing; otherwise, return NULL if the desired
297-
* directory cannot be found.
351+
* directory cannot be found. dir must already be complete.
298352
*/
299353
static struct ref_dir *search_for_subdir(struct ref_dir *dir,
300354
const char *subdirname, int mkdir)
@@ -303,7 +357,13 @@ static struct ref_dir *search_for_subdir(struct ref_dir *dir,
303357
if (!entry) {
304358
if (!mkdir)
305359
return NULL;
306-
entry = create_dir_entry(dir->ref_cache, subdirname);
360+
/*
361+
* Since dir is complete, the absence of a subdir
362+
* means that the subdir really doesn't exist;
363+
* therefore, create an empty record for it but mark
364+
* the record complete.
365+
*/
366+
entry = create_dir_entry(dir->ref_cache, subdirname, 0);
307367
add_entry_to_dir(dir, entry);
308368
}
309369
return get_ref_dir(entry);
@@ -313,10 +373,10 @@ static struct ref_dir *search_for_subdir(struct ref_dir *dir,
313373
* If refname is a reference name, find the ref_dir within the dir
314374
* tree that should hold refname. If refname is a directory name
315375
* (i.e., ends in '/'), then return that ref_dir itself. dir must
316-
* represent the top-level directory. Sort ref_dirs and recurse into
317-
* subdirectories as necessary. If mkdir is set, then create any
318-
* missing directories; otherwise, return NULL if the desired
319-
* directory cannot be found.
376+
* represent the top-level directory and must already be complete.
377+
* Sort ref_dirs and recurse into subdirectories as necessary. If
378+
* mkdir is set, then create any missing directories; otherwise,
379+
* return NULL if the desired directory cannot be found.
320380
*/
321381
static struct ref_dir *find_containing_dir(struct ref_dir *dir,
322382
const char *refname, int mkdir)
@@ -760,7 +820,7 @@ static struct ref_dir *get_packed_refs(struct ref_cache *refs)
760820
const char *packed_refs_file;
761821
FILE *f;
762822

763-
refs->packed = create_dir_entry(refs, "");
823+
refs->packed = create_dir_entry(refs, "", 0);
764824
if (*refs->name)
765825
packed_refs_file = git_path_submodule(refs->name, "packed-refs");
766826
else
@@ -781,9 +841,9 @@ void add_packed_ref(const char *refname, const unsigned char *sha1)
781841
}
782842

783843
/*
784-
* Read the loose references for refs from the namespace dirname.
785-
* dirname must end with '/'. dir must be the directory entry
786-
* corresponding to dirname.
844+
* Read the loose references from the namespace dirname into dir
845+
* (without recursing). dirname must end with '/'. dir must be the
846+
* directory entry corresponding to dirname.
787847
*/
788848
static void read_loose_refs(const char *dirname, struct ref_dir *dir)
789849
{
@@ -824,8 +884,8 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
824884
; /* silently ignore */
825885
} else if (S_ISDIR(st.st_mode)) {
826886
strbuf_addch(&refname, '/');
827-
read_loose_refs(refname.buf,
828-
search_for_subdir(dir, refname.buf, 1));
887+
add_entry_to_dir(dir,
888+
create_dir_entry(refs, refname.buf, 1));
829889
} else {
830890
if (*refs->name) {
831891
hashclr(sha1);
@@ -850,10 +910,17 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
850910
static struct ref_dir *get_loose_refs(struct ref_cache *refs)
851911
{
852912
if (!refs->loose) {
853-
refs->loose = create_dir_entry(refs, "");
854-
read_loose_refs("refs/",
855-
search_for_subdir(get_ref_dir(refs->loose),
856-
"refs/", 1));
913+
/*
914+
* Mark the top-level directory complete because we
915+
* are about to read the only subdirectory that can
916+
* hold references:
917+
*/
918+
refs->loose = create_dir_entry(refs, "", 0);
919+
/*
920+
* Create an incomplete entry for "refs/":
921+
*/
922+
add_entry_to_dir(get_ref_dir(refs->loose),
923+
create_dir_entry(refs, "refs/", 1));
857924
}
858925
return get_ref_dir(refs->loose);
859926
}

0 commit comments

Comments
 (0)