cache_ref_iterator_begin(): make function smarter

Change `cache_ref_iterator_begin()` to take two new arguments:

* `prefix` -- to iterate only over references with the specified
  prefix.

* `prime_dir` -- to "prime" (i.e., pre-load) the cache before starting
  the iteration.

The new functionality makes it possible for
`files_ref_iterator_begin()` to be made more ignorant of the internals
of `ref_cache`, and `find_containing_dir()` and `prime_ref_dir()` to
be made private.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Michael Haggerty 2017-04-16 08:41:39 +02:00 committed by Junio C Hamano
parent a714b19ca8
commit 059ae35a48
3 changed files with 56 additions and 53 deletions

View File

@ -1082,7 +1082,6 @@ static struct ref_iterator *files_ref_iterator_begin(
const char *prefix, unsigned int flags) const char *prefix, unsigned int flags)
{ {
struct files_ref_store *refs; struct files_ref_store *refs;
struct ref_dir *loose_dir, *packed_dir;
struct ref_iterator *loose_iter, *packed_iter; struct ref_iterator *loose_iter, *packed_iter;
struct files_ref_iterator *iter; struct files_ref_iterator *iter;
struct ref_iterator *ref_iterator; struct ref_iterator *ref_iterator;
@ -1106,41 +1105,24 @@ static struct ref_iterator *files_ref_iterator_begin(
* condition if loose refs are migrated to the packed-refs * condition if loose refs are migrated to the packed-refs
* file by a simultaneous process, but our in-memory view is * file by a simultaneous process, but our in-memory view is
* from before the migration. We ensure this as follows: * from before the migration. We ensure this as follows:
* First, we call prime_ref_dir(), which pre-reads the loose * First, we call start the loose refs iteration with its
* references for the subtree into the cache. (If they've * `prime_ref` argument set to true. This causes the loose
* already been read, that's OK; we only need to guarantee * references in the subtree to be pre-read into the cache.
* that they're read before the packed refs, not *how much* * (If they've already been read, that's OK; we only need to
* before.) After that, we call get_packed_ref_cache(), which * guarantee that they're read before the packed refs, not
* internally checks whether the packed-ref cache is up to * *how much* before.) After that, we call
* date with what is on disk, and re-reads it if not. * get_packed_ref_cache(), which internally checks whether the
* packed-ref cache is up to date with what is on disk, and
* re-reads it if not.
*/ */


loose_dir = get_loose_ref_dir(refs); loose_iter = cache_ref_iterator_begin(get_loose_ref_cache(refs),

prefix, 1);
if (prefix && *prefix)
loose_dir = find_containing_dir(loose_dir, prefix, 0);

if (loose_dir) {
prime_ref_dir(loose_dir);
loose_iter = cache_ref_iterator_begin(loose_dir);
} else {
/* There's nothing to iterate over. */
loose_iter = empty_ref_iterator_begin();
}


iter->packed_ref_cache = get_packed_ref_cache(refs); iter->packed_ref_cache = get_packed_ref_cache(refs);
acquire_packed_ref_cache(iter->packed_ref_cache); acquire_packed_ref_cache(iter->packed_ref_cache);
packed_dir = get_packed_ref_dir(iter->packed_ref_cache); packed_iter = cache_ref_iterator_begin(iter->packed_ref_cache->cache,

prefix, 0);
if (prefix && *prefix)
packed_dir = find_containing_dir(packed_dir, prefix, 0);

if (packed_dir) {
packed_iter = cache_ref_iterator_begin(packed_dir);
} else {
/* There's nothing to iterate over. */
packed_iter = empty_ref_iterator_begin();
}


iter->iter0 = overlay_ref_iterator_begin(loose_iter, packed_iter); iter->iter0 = overlay_ref_iterator_begin(loose_iter, packed_iter);
iter->flags = flags; iter->flags = flags;

View File

@ -177,8 +177,17 @@ static struct ref_dir *search_for_subdir(struct ref_dir *dir,
return get_ref_dir(entry); return get_ref_dir(entry);
} }


struct ref_dir *find_containing_dir(struct ref_dir *dir, /*
const char *refname, int mkdir) * If refname is a reference name, find the ref_dir within the dir
* tree that should hold refname. If refname is a directory name
* (i.e., it ends in '/'), then return that ref_dir itself. dir must
* represent the top-level directory and must already be complete.
* Sort ref_dirs and recurse into subdirectories as necessary. If
* mkdir is set, then create any missing directories; otherwise,
* return NULL if the desired directory cannot be found.
*/
static struct ref_dir *find_containing_dir(struct ref_dir *dir,
const char *refname, int mkdir)
{ {
const char *slash; const char *slash;
for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) { for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) {
@ -328,7 +337,11 @@ int do_for_each_entry_in_dir(struct ref_dir *dir,
return 0; return 0;
} }


void prime_ref_dir(struct ref_dir *dir) /*
* Load all of the refs from `dir` (recursively) into our in-memory
* cache.
*/
static void prime_ref_dir(struct ref_dir *dir)
{ {
/* /*
* The hard work of loading loose refs is done by get_ref_dir(), so we * The hard work of loading loose refs is done by get_ref_dir(), so we
@ -494,12 +507,25 @@ static struct ref_iterator_vtable cache_ref_iterator_vtable = {
cache_ref_iterator_abort cache_ref_iterator_abort
}; };


struct ref_iterator *cache_ref_iterator_begin(struct ref_dir *dir) struct ref_iterator *cache_ref_iterator_begin(struct ref_cache *cache,
const char *prefix,
int prime_dir)
{ {
struct ref_dir *dir;
struct cache_ref_iterator *iter; struct cache_ref_iterator *iter;
struct ref_iterator *ref_iterator; struct ref_iterator *ref_iterator;
struct cache_ref_iterator_level *level; struct cache_ref_iterator_level *level;


dir = get_ref_dir(cache->root);
if (prefix && *prefix)
dir = find_containing_dir(dir, prefix, 0);
if (!dir)
/* There's nothing to iterate over. */
return empty_ref_iterator_begin();

if (prime_dir)
prime_ref_dir(dir);

iter = xcalloc(1, sizeof(*iter)); iter = xcalloc(1, sizeof(*iter));
ref_iterator = &iter->base; ref_iterator = &iter->base;
base_ref_iterator_init(ref_iterator, &cache_ref_iterator_vtable); base_ref_iterator_init(ref_iterator, &cache_ref_iterator_vtable);
@ -510,5 +536,9 @@ struct ref_iterator *cache_ref_iterator_begin(struct ref_dir *dir)
level->index = -1; level->index = -1;
level->dir = dir; level->dir = dir;


if (prefix && *prefix)
ref_iterator = prefix_ref_iterator_begin(ref_iterator,
prefix, 0);

return ref_iterator; return ref_iterator;
} }

View File

@ -234,18 +234,6 @@ int remove_entry_from_dir(struct ref_dir *dir, const char *refname);
*/ */
int add_ref_entry(struct ref_dir *dir, struct ref_entry *ref); int add_ref_entry(struct ref_dir *dir, struct ref_entry *ref);


/*
* If refname is a reference name, find the ref_dir within the dir
* tree that should hold refname. If refname is a directory name
* (i.e., it ends in '/'), then return that ref_dir itself. dir must
* represent the top-level directory and must already be complete.
* Sort ref_dirs and recurse into subdirectories as necessary. If
* mkdir is set, then create any missing directories; otherwise,
* return NULL if the desired directory cannot be found.
*/
struct ref_dir *find_containing_dir(struct ref_dir *dir,
const char *refname, int mkdir);

/* /*
* Find the value entry with the given name in dir, sorting ref_dirs * Find the value entry with the given name in dir, sorting ref_dirs
* and recursing into subdirectories as necessary. If the name is not * and recursing into subdirectories as necessary. If the name is not
@ -253,7 +241,15 @@ struct ref_dir *find_containing_dir(struct ref_dir *dir,
*/ */
struct ref_entry *find_ref_entry(struct ref_dir *dir, const char *refname); struct ref_entry *find_ref_entry(struct ref_dir *dir, const char *refname);


struct ref_iterator *cache_ref_iterator_begin(struct ref_dir *dir); /*
* Start iterating over references in `cache`. If `prefix` is
* specified, only include references whose names start with that
* prefix. If `prime_dir` is true, then fill any incomplete
* directories before beginning the iteration.
*/
struct ref_iterator *cache_ref_iterator_begin(struct ref_cache *cache,
const char *prefix,
int prime_dir);


typedef int each_ref_entry_fn(struct ref_entry *entry, void *cb_data); typedef int each_ref_entry_fn(struct ref_entry *entry, void *cb_data);


@ -279,9 +275,4 @@ int do_for_each_entry_in_dir(struct ref_dir *dir,
*/ */
enum peel_status peel_entry(struct ref_entry *entry, int repeel); enum peel_status peel_entry(struct ref_entry *entry, int repeel);


/*
* Load all of the refs from `dir` into our in-memory cache.
*/
void prime_ref_dir(struct ref_dir *dir);

#endif /* REFS_REF_CACHE_H */ #endif /* REFS_REF_CACHE_H */