{"thread":{"id":"12285","subject":"[PATCH 2/6] Optimize peel_ref for the current ref of a for_each_ref callback","startedAt":"2008-02-24T08:07:22Z","lastAt":"2008-02-24T08:07:22Z","messageCount":1,"participants":["Shawn O. Pearce"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"69765","messageId":"20080224080722.GB22587@spearce.org","threadId":"12285","inReplyTo":null,"subject":"[PATCH 2/6] Optimize peel_ref for the current ref of a for_each_ref callback","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-02-24T08:07:22Z","receivedAt":"2008-02-24T08:07:22Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Currently the only caller of peel_ref is show-ref, which is using\nthis function to show the peeled tag information if it is available\nfrom an existing packed-refs file.  The call happens during the\nfor_each_ref callback function, so we have the proper struct ref_list\nalready on the call stack but it is not easily available to return\nthe peeled information to the caller.\n\nWe now save the current struct ref_list item before calling back\ninto the callback function so that future calls to peel_ref from\nwithin the callback function can quickly access the current ref.\nDoing so will save us an lstat() per ref processed as we no longer\nhave to check the filesystem to see if the ref exists as a loose\nfile or is packed.  This current ref caching also saves a linear\nscan of the cached packed refs list.\n\nAs a micro-optimization we test the address of the passed ref name\nagainst the current_ref->name before we go into the much more costly\nstrcmp().  Nearly any caller of peel_ref will be passing us the same\nstring do_for_each_ref passed them, which is current_ref->name.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n refs.c |   25 ++++++++++++++++++++-----\n 1 files changed, 20 insertions(+), 5 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex fb33da1..c979fb1 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -157,6 +157,7 @@ static struct cached_refs {\n \tstruct ref_list *loose;\n \tstruct ref_list *packed;\n } cached_refs;\n+static struct ref_list *current_ref;\n \n static void free_ref_list(struct ref_list *list)\n {\n@@ -476,6 +477,7 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim,\n \t\terror(\"%s does not point to a valid object!\", entry->name);\n \t\treturn 0;\n \t}\n+\tcurrent_ref = entry;\n \treturn fn(entry->name + trim, entry->sha1, entry->flag, cb_data);\n }\n \n@@ -485,6 +487,16 @@ int peel_ref(const char *ref, unsigned char *sha1)\n \tunsigned char base[20];\n \tstruct object *o;\n \n+\tif (current_ref && (current_ref->name == ref\n+\t\t|| !strcmp(current_ref->name, ref))) {\n+\t\tif (current_ref->flag & REF_KNOWS_PEELED) {\n+\t\t\thashcpy(sha1, current_ref->peeled);\n+\t\t\treturn 0;\n+\t\t}\n+\t\thashcpy(base, current_ref->sha1);\n+\t\tgoto fallback;\n+\t}\n+\n \tif (!resolve_ref(ref, base, 1, &flag))\n \t\treturn -1;\n \n@@ -504,7 +516,7 @@ int peel_ref(const char *ref, unsigned char *sha1)\n \t\t}\n \t}\n \n-\t/* fallback - callers should not call this for unpacked refs */\n+fallback:\n \to = parse_object(base);\n \tif (o && o->type == OBJ_TAG) {\n \t\to = deref_tag(o, ref, 0);\n@@ -519,7 +531,7 @@ int peel_ref(const char *ref, unsigned char *sha1)\n static int do_for_each_ref(const char *base, each_ref_fn fn, int trim,\n \t\t\t   void *cb_data)\n {\n-\tint retval;\n+\tint retval = 0;\n \tstruct ref_list *packed = get_packed_refs();\n \tstruct ref_list *loose = get_loose_refs();\n \n@@ -539,15 +551,18 @@ static int do_for_each_ref(const char *base, each_ref_fn fn, int trim,\n \t\t}\n \t\tretval = do_one_ref(base, fn, trim, cb_data, entry);\n \t\tif (retval)\n-\t\t\treturn retval;\n+\t\t\tgoto end_each;\n \t}\n \n \tfor (packed = packed ? packed : loose; packed; packed = packed->next) {\n \t\tretval = do_one_ref(base, fn, trim, cb_data, packed);\n \t\tif (retval)\n-\t\t\treturn retval;\n+\t\t\tgoto end_each;\n \t}\n-\treturn 0;\n+\n+end_each:\n+\tcurrent_ref = NULL;\n+\treturn retval;\n }\n \n int head_ref(each_ref_fn fn, void *cb_data)\n-- \n1.5.4.3.295.g6b554\n"}]}