@matheusbsbs / matheus-bagliano / commits / 0ae91be0e1
Fork 0

Optimize peel_ref for the current ref of a for_each_ref callback

Currently the only caller of peel_ref is show-ref, which is using this function to show the peeled tag information if it is available from an existing packed-refs file. The call happens during the for_each_ref callback function, so we have the proper struct ref_list already on the call stack but it is not easily available to return the peeled information to the caller. We now save the current struct ref_list item before calling back into the callback function so that future calls to peel_ref from within the callback function can quickly access the current ref. Doing so will save us an lstat() per ref processed as we no longer have to check the filesystem to see if the ref exists as a loose file or is packed. This current ref caching also saves a linear scan of the cached packed refs list. As a micro-optimization we test the address of the passed ref name against the current_ref->name before we go into the much more costly strcmp(). Nearly any caller of peel_ref will be passing us the same string do_for_each_ref passed them, which is current_ref->name. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Shawn O. Pearce committed Feb 24, 2008 at 03:07 UTC 0ae91be0e1fac3ff31675f0ec2c7ebf2bb5c1be6
1 file changed +20 -5
refs.c
+20 -5
@@ -157,6 +157,7 @@ static struct cached_refs {
157 struct ref_list *loose;
158 struct ref_list *packed;
159 } cached_refs;
160 +static struct ref_list *current_ref;
161
162 static void free_ref_list(struct ref_list *list)
163 {
@@ -476,6 +477,7 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim,
477 error("%s does not point to a valid object!", entry->name);
478 return 0;
479 }
480 + current_ref = entry;
481 return fn(entry->name + trim, entry->sha1, entry->flag, cb_data);
482 }
483
@@ -485,6 +487,16 @@ int peel_ref(const char *ref, unsigned char *sha1)
487 unsigned char base[20];
488 struct object *o;
489
490 + if (current_ref && (current_ref->name == ref
491 + || !strcmp(current_ref->name, ref))) {
492 + if (current_ref->flag & REF_KNOWS_PEELED) {
493 + hashcpy(sha1, current_ref->peeled);
494 + return 0;
495 + }
496 + hashcpy(base, current_ref->sha1);
497 + goto fallback;
498 + }
499 +
500 if (!resolve_ref(ref, base, 1, &flag))
501 return -1;
502
@@ -504,7 +516,7 @@ int peel_ref(const char *ref, unsigned char *sha1)
516 }
517 }
518
507 - /* fallback - callers should not call this for unpacked refs */
519 +fallback:
520 o = parse_object(base);
521 if (o && o->type == OBJ_TAG) {
522 o = deref_tag(o, ref, 0);
@@ -519,7 +531,7 @@ int peel_ref(const char *ref, unsigned char *sha1)
531 static int do_for_each_ref(const char *base, each_ref_fn fn, int trim,
532 void *cb_data)
533 {
522 - int retval;
534 + int retval = 0;
535 struct ref_list *packed = get_packed_refs();
536 struct ref_list *loose = get_loose_refs();
537
@@ -539,15 +551,18 @@ static int do_for_each_ref(const char *base, each_ref_fn fn, int trim,
551 }
552 retval = do_one_ref(base, fn, trim, cb_data, entry);
553 if (retval)
542 - return retval;
554 + goto end_each;
555 }
556
557 for (packed = packed ? packed : loose; packed; packed = packed->next) {
558 retval = do_one_ref(base, fn, trim, cb_data, packed);
559 if (retval)
548 - return retval;
560 + goto end_each;
561 }
550 - return 0;
562 +
563 +end_each:
564 + current_ref = NULL;
565 + return retval;
566 }
567
568 int head_ref(each_ref_fn fn, void *cb_data)