do_for_each_ref(): reimplement using reference iteration

Use the reference iterator interface to implement do_for_each_ref(). Delete a bunch of code supporting the old for_each_ref() implementation. And now that do_for_each_ref() is generic code (it is no longer tied to the files backend), move it to refs.c. The implementation is via a new function, do_for_each_ref_iterator(), which takes a reference iterator as argument and calls a callback function for each of the references in the iterator. This change requires the current_ref performance hack for peel_ref() to be implemented via ref_iterator_peel() rather than peel_entry() because we don't have a ref_entry handy (it is hidden under three layers: file_ref_iterator, merge_ref_iterator, and cache_ref_iterator). So: * do_for_each_ref_iterator() records the active iterator in current_ref_iter while it is running. * peel_ref() checks whether current_ref_iter is pointing at the requested reference. If so, it asks the iterator to peel the reference (which it can do efficiently via its "peel" virtual function). For extra safety, we do the optimization only if the refname *addresses* are the same, not only if the refname *strings* are the same, to forestall possible mixups between refnames that come from different ref_iterators. Please note that this optimization of peel_ref() is only available when iterating via do_for_each_ref_iterator() (including all of the for_each_ref() functions, which call it indirectly). It would be complicated to implement a similar optimization when iterating directly using a reference iterator, because multiple reference iterators can be in use at the same time, with interleaved calls to ref_iterator_advance(). (In fact we do exactly that in merge_ref_iterator.) But that is not necessary. peel_ref() is only called while iterating over references. Callers who iterate using the for_each_ref() functions benefit from the optimization described above. Callers who iterate using reference iterators directly have access to the ref_iterator, so they can call ref_iterator_peel() themselves to get an analogous optimization in a more straightforward manner. If we rewrite all callers to use the reference iteration API, then we can remove the current_ref_iter hack permanently. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michael Haggerty committed Jun 18, 2016 at 06:15 UTC 4c4de89573fa29b7f97e7a9a3d0674dbdb6f2a28
4 files changed +77 -213
refs.c
+20
@@ -1120,6 +1120,26 @@ int head_ref(each_ref_fn fn, void *cb_data)
1120 return head_ref_submodule(NULL, fn, cb_data);
1121 }
1122
1123 +/*
1124 + * Call fn for each reference in the specified submodule for which the
1125 + * refname begins with prefix. If trim is non-zero, then trim that
1126 + * many characters off the beginning of each refname before passing
1127 + * the refname to fn. flags can be DO_FOR_EACH_INCLUDE_BROKEN to
1128 + * include broken references in the iteration. If fn ever returns a
1129 + * non-zero value, stop the iteration and return that value;
1130 + * otherwise, return 0.
1131 + */
1132 +static int do_for_each_ref(const char *submodule, const char *prefix,
1133 + each_ref_fn fn, int trim, int flags, void *cb_data)
1134 +{
1135 + struct ref_iterator *iter;
1136 +
1137 + iter = files_ref_iterator_begin(submodule, prefix, flags);
1138 + iter = prefix_ref_iterator_begin(iter, prefix, trim);
1139 +
1140 + return do_for_each_ref_iterator(iter, fn, cb_data);
1141 +}
1142 +
1143 int for_each_ref(each_ref_fn fn, void *cb_data)
1144 {
1145 return do_for_each_ref(NULL, "", fn, 0, 0, cb_data);
refs/files-backend.c
+5 -201
@@ -542,53 +542,8 @@ static int entry_resolves_to_object(struct ref_entry *entry)
542 &entry->u.value.oid, entry->flag);
543 }
544
545 -/*
546 - * current_ref is a performance hack: when iterating over references
547 - * using the for_each_ref*() functions, current_ref is set to the
548 - * current reference's entry before calling the callback function. If
549 - * the callback function calls peel_ref(), then peel_ref() first
550 - * checks whether the reference to be peeled is the current reference
551 - * (it usually is) and if so, returns that reference's peeled version
552 - * if it is available. This avoids a refname lookup in a common case.
553 - */
554 -static struct ref_entry *current_ref;
555 -
545 typedef int each_ref_entry_fn(struct ref_entry *entry, void *cb_data);
546
558 -struct ref_entry_cb {
559 - const char *prefix;
560 - int trim;
561 - int flags;
562 - each_ref_fn *fn;
563 - void *cb_data;
564 -};
565 -
566 -/*
567 - * Handle one reference in a do_for_each_ref*()-style iteration,
568 - * calling an each_ref_fn for each entry.
569 - */
570 -static int do_one_ref(struct ref_entry *entry, void *cb_data)
571 -{
572 - struct ref_entry_cb *data = cb_data;
573 - struct ref_entry *old_current_ref;
574 - int retval;
575 -
576 - if (!starts_with(entry->name, data->prefix))
577 - return 0;
578 -
579 - if (!(data->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
580 - !entry_resolves_to_object(entry))
581 - return 0;
582 -
583 - /* Store the old value, in case this is a recursive call: */
584 - old_current_ref = current_ref;
585 - current_ref = entry;
586 - retval = data->fn(entry->name + data->trim, &entry->u.value.oid,
587 - entry->flag, data->cb_data);
588 - current_ref = old_current_ref;
589 - return retval;
590 -}
591 -
547 /*
548 * Call fn for each reference in dir that has index in the range
549 * offset <= index < dir->nr. Recurse into subdirectories that are in
@@ -617,78 +572,6 @@ static int do_for_each_entry_in_dir(struct ref_dir *dir, int offset,
572 return 0;
573 }
574
620 -/*
621 - * Call fn for each reference in the union of dir1 and dir2, in order
622 - * by refname. Recurse into subdirectories. If a value entry appears
623 - * in both dir1 and dir2, then only process the version that is in
624 - * dir2. The input dirs must already be sorted, but subdirs will be
625 - * sorted as needed. fn is called for all references, including
626 - * broken ones.
627 - */
628 -static int do_for_each_entry_in_dirs(struct ref_dir *dir1,
629 - struct ref_dir *dir2,
630 - each_ref_entry_fn fn, void *cb_data)
631 -{
632 - int retval;
633 - int i1 = 0, i2 = 0;
634 -
635 - assert(dir1->sorted == dir1->nr);
636 - assert(dir2->sorted == dir2->nr);
637 - while (1) {
638 - struct ref_entry *e1, *e2;
639 - int cmp;
640 - if (i1 == dir1->nr) {
641 - return do_for_each_entry_in_dir(dir2, i2, fn, cb_data);
642 - }
643 - if (i2 == dir2->nr) {
644 - return do_for_each_entry_in_dir(dir1, i1, fn, cb_data);
645 - }
646 - e1 = dir1->entries[i1];
647 - e2 = dir2->entries[i2];
648 - cmp = strcmp(e1->name, e2->name);
649 - if (cmp == 0) {
650 - if ((e1->flag & REF_DIR) && (e2->flag & REF_DIR)) {
651 - /* Both are directories; descend them in parallel. */
652 - struct ref_dir *subdir1 = get_ref_dir(e1);
653 - struct ref_dir *subdir2 = get_ref_dir(e2);
654 - sort_ref_dir(subdir1);
655 - sort_ref_dir(subdir2);
656 - retval = do_for_each_entry_in_dirs(
657 - subdir1, subdir2, fn, cb_data);
658 - i1++;
659 - i2++;
660 - } else if (!(e1->flag & REF_DIR) && !(e2->flag & REF_DIR)) {
661 - /* Both are references; ignore the one from dir1. */
662 - retval = fn(e2, cb_data);
663 - i1++;
664 - i2++;
665 - } else {
666 - die("conflict between reference and directory: %s",
667 - e1->name);
668 - }
669 - } else {
670 - struct ref_entry *e;
671 - if (cmp < 0) {
672 - e = e1;
673 - i1++;
674 - } else {
675 - e = e2;
676 - i2++;
677 - }
678 - if (e->flag & REF_DIR) {
679 - struct ref_dir *subdir = get_ref_dir(e);
680 - sort_ref_dir(subdir);
681 - retval = do_for_each_entry_in_dir(
682 - subdir, 0, fn, cb_data);
683 - } else {
684 - retval = fn(e, cb_data);
685 - }
686 - }
687 - if (retval)
688 - return retval;
689 - }
690 -}
691 -
575 /*
576 * Load all of the refs from the dir into our in-memory cache. The hard work
577 * of loading loose refs is done by get_ref_dir(), so we just need to recurse
@@ -1959,11 +1842,12 @@ int peel_ref(const char *refname, unsigned char *sha1)
1842 int flag;
1843 unsigned char base[20];
1844
1962 - if (current_ref && (current_ref->name == refname
1963 - || !strcmp(current_ref->name, refname))) {
1964 - if (peel_entry(current_ref, 0))
1845 + if (current_ref_iter && current_ref_iter->refname == refname) {
1846 + struct object_id peeled;
1847 +
1848 + if (ref_iterator_peel(current_ref_iter, &peeled))
1849 return -1;
1966 - hashcpy(sha1, current_ref->u.value.peeled.hash);
1850 + hashcpy(sha1, peeled.hash);
1851 return 0;
1852 }
1853
@@ -2124,86 +2008,6 @@ struct ref_iterator *files_ref_iterator_begin(
2008 return ref_iterator;
2009 }
2010
2127 -/*
2128 - * Call fn for each reference in the specified ref_cache, omitting
2129 - * references not in the containing_dir of prefix. Call fn for all
2130 - * references, including broken ones. If fn ever returns a non-zero
2131 - * value, stop the iteration and return that value; otherwise, return
2132 - * 0.
2133 - */
2134 -static int do_for_each_entry(struct ref_cache *refs, const char *prefix,
2135 - each_ref_entry_fn fn, void *cb_data)
2136 -{
2137 - struct packed_ref_cache *packed_ref_cache;
2138 - struct ref_dir *loose_dir;
2139 - struct ref_dir *packed_dir;
2140 - int retval = 0;
2141 -
2142 - /*
2143 - * We must make sure that all loose refs are read before accessing the
2144 - * packed-refs file; this avoids a race condition in which loose refs
2145 - * are migrated to the packed-refs file by a simultaneous process, but
2146 - * our in-memory view is from before the migration. get_packed_ref_cache()
2147 - * takes care of making sure our view is up to date with what is on
2148 - * disk.
2149 - */
2150 - loose_dir = get_loose_refs(refs);
2151 - if (prefix && *prefix) {
2152 - loose_dir = find_containing_dir(loose_dir, prefix, 0);
2153 - }
2154 - if (loose_dir)
2155 - prime_ref_dir(loose_dir);
2156 -
2157 - packed_ref_cache = get_packed_ref_cache(refs);
2158 - acquire_packed_ref_cache(packed_ref_cache);
2159 - packed_dir = get_packed_ref_dir(packed_ref_cache);
2160 - if (prefix && *prefix) {
2161 - packed_dir = find_containing_dir(packed_dir, prefix, 0);
2162 - }
2163 -
2164 - if (packed_dir && loose_dir) {
2165 - sort_ref_dir(packed_dir);
2166 - sort_ref_dir(loose_dir);
2167 - retval = do_for_each_entry_in_dirs(
2168 - packed_dir, loose_dir, fn, cb_data);
2169 - } else if (packed_dir) {
2170 - sort_ref_dir(packed_dir);
2171 - retval = do_for_each_entry_in_dir(
2172 - packed_dir, 0, fn, cb_data);
2173 - } else if (loose_dir) {
2174 - sort_ref_dir(loose_dir);
2175 - retval = do_for_each_entry_in_dir(
2176 - loose_dir, 0, fn, cb_data);
2177 - }
2178 -
2179 - release_packed_ref_cache(packed_ref_cache);
2180 - return retval;
2181 -}
2182 -
2183 -int do_for_each_ref(const char *submodule, const char *prefix,
2184 - each_ref_fn fn, int trim, int flags, void *cb_data)
2185 -{
2186 - struct ref_entry_cb data;
2187 - struct ref_cache *refs;
2188 -
2189 - refs = get_ref_cache(submodule);
2190 - if (!refs)
2191 - return 0;
2192 -
2193 - data.prefix = prefix;
2194 - data.trim = trim;
2195 - data.flags = flags;
2196 - data.fn = fn;
2197 - data.cb_data = cb_data;
2198 -
2199 - if (ref_paranoia < 0)
2200 - ref_paranoia = git_env_bool("GIT_REF_PARANOIA", 0);
2201 - if (ref_paranoia)
2202 - data.flags |= DO_FOR_EACH_INCLUDE_BROKEN;
2203 -
2204 - return do_for_each_entry(refs, prefix, do_one_ref, &data);
2205 -}
2206 -
2011 /*
2012 * Verify that the reference locked by lock has the value old_sha1.
2013 * Fail if the reference doesn't exist and mustexist is set. Return 0
refs/iterator.c
+29
@@ -353,3 +353,32 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,
353
354 return ref_iterator;
355 }
356 +
357 +struct ref_iterator *current_ref_iter = NULL;
358 +
359 +int do_for_each_ref_iterator(struct ref_iterator *iter,
360 + each_ref_fn fn, void *cb_data)
361 +{
362 + int retval = 0, ok;
363 + struct ref_iterator *old_ref_iter = current_ref_iter;
364 +
365 + current_ref_iter = iter;
366 + while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
367 + retval = fn(iter->refname, iter->oid, iter->flags, cb_data);
368 + if (retval) {
369 + /*
370 + * If ref_iterator_abort() returns ITER_ERROR,
371 + * we ignore that error in deference to the
372 + * callback function's return value.
373 + */
374 + ref_iterator_abort(iter);
375 + goto out;
376 + }
377 + }
378 +
379 +out:
380 + current_ref_iter = old_ref_iter;
381 + if (ok == ITER_ERROR)
382 + return -1;
383 + return retval;
384 +}
refs/refs-internal.h
+23 -12
@@ -443,18 +443,29 @@ struct ref_iterator_vtable {
443 };
444
445 /*
446 - * Call fn for each reference in the specified submodule for which the
447 - * refname begins with prefix. If trim is non-zero, then trim that
448 - * many characters off the beginning of each refname before passing
449 - * the refname to fn. flags can be DO_FOR_EACH_INCLUDE_BROKEN to
450 - * include broken references in the iteration. If fn ever returns a
451 - * non-zero value, stop the iteration and return that value;
452 - * otherwise, return 0.
453 - *
454 - * This is the common backend for the for_each_*ref* functions.
455 - */
456 -int do_for_each_ref(const char *submodule, const char *prefix,
457 - each_ref_fn fn, int trim, int flags, void *cb_data);
446 + * current_ref_iter is a performance hack: when iterating over
447 + * references using the for_each_ref*() functions, current_ref_iter is
448 + * set to the reference iterator before calling the callback function.
449 + * If the callback function calls peel_ref(), then peel_ref() first
450 + * checks whether the reference to be peeled is the one referred to by
451 + * the iterator (it usually is) and if so, asks the iterator for the
452 + * peeled version of the reference if it is available. This avoids a
453 + * refname lookup in a common case. current_ref_iter is set to NULL
454 + * when the iteration is over.
455 + */
456 +extern struct ref_iterator *current_ref_iter;
457 +
458 +/*
459 + * The common backend for the for_each_*ref* functions. Call fn for
460 + * each reference in iter. If the iterator itself ever returns
461 + * ITER_ERROR, return -1. If fn ever returns a non-zero value, stop
462 + * the iteration and return that value. Otherwise, return 0. In any
463 + * case, free the iterator when done. This function is basically an
464 + * adapter between the callback style of reference iteration and the
465 + * iterator style.
466 + */
467 +int do_for_each_ref_iterator(struct ref_iterator *iter,
468 + each_ref_fn fn, void *cb_data);
469
470 /*
471 * Read the specified reference from the filesystem or packed refs