{"thread":{"id":"30329","subject":"[PATCH 03/30] get_ref_dir(): rename \"base\" parameter to \"dirname\"","startedAt":"2012-04-24T22:45:06Z","lastAt":"2012-04-26T21:33:58Z","messageCount":37,"participants":["mhagger@alum.mit.edu","Junio C Hamano","Michael Haggerty"],"isPatch":true,"patchVersion":1,"patchTotal":30},"messages":[{"id":"190003","messageId":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":null,"subject":"[PATCH 00/30] Read loose references lazily","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:06Z","receivedAt":"2012-04-24T22:45:06Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nThis is the next installment of the ref-api saga.  The main result of\nthis patch series is to teach git to read loose references one\ndirectory at a time, only when they are needed.\n\nThe first nine commits are not very interesting; they convert\nget_ref_dir() and do_for_each_reflog() to use strbufs and to tighten\nup their specifications.  The search_for_subdir() function extracted\nin patch 5 will be useful later.  Patch 6 slightly reduces the amount\nof work needed to read loose refs from disk, and also changes the\nfunction's API in a way that will be needed later when directories are\nread one at a time.\n\nPatches 10 - 25 mostly switch a lot of code from using ref_dir\npointers to using ref_entry pointers as arguments and return values.\nThis is important, because we want to be able to read directories of\nloose references on demand; this means that functions deep in the refs\ncode need access to the name of directories of references.  Since the\nname field is part of ref_entry but not ref_dir, this change has to\npercolate through many functions.  The three key patches are patch 18,\nwhich removes the \"dirname\" argument to get_ref_dir(), and patches 21\nand 25, which change search_ref_dir() and sort_ref_dir() to take\nref_entries as argument.  Together, these patches allow\nsearch_ref_dir() and sort_ref_dir() to call get_ref_dir() to fill\ndirectory entries on demand.\n\nPatch 26-28 makes it possible to get from a ref_entry to the ref_cache\nof which it is part, and teach get_ref_dir() (renamed to\nread_loose_refs()) to use this mechanism to access the name of the\nref_cache that it is to read.\n\nFinally, patches 29 and 30 teach the code to read loose references\nlazily.  This is done by adding a distinction between REF_DIR_COMPLETE\nand REF_DIR_INCOMPLETE; the latter is used to stub out directories of\nloose references that haven't been read yet.  The loose references are\nread transparently into a REF_DIR_INCOMPLETE only when they are\nneeded, at which time the directory entry is transformed into\nREF_DIR_COMPLETE.\n\nThis patch series has to be applied on top of mh/ref-api (or next).\nIt passes all tests.  It also includes quite a few assert()s to\nverify and document function preconditions.  The asserts should all be\npretty cheap, but if leaving them in is a problem please let me know.\n\nIt seems pretty overwhelming, but the changes are implemented in baby\nsteps and most of the patches are quite simple.\n\nMichael Haggerty (30):\n  get_ref_dir(): return early if directory cannot be read\n  get_ref_dir(): use a strbuf to hold refname\n  get_ref_dir(): rename \"base\" parameter to \"dirname\"\n  get_ref_dir(): require that the dirname argument ends in '/'\n  refs.c: extract function search_for_subdir()\n  get_ref_dir(): take the containing directory as argument\n  do_for_each_reflog(): return early on error\n  do_for_each_reflog(): use a strbuf to hold logfile name\n  do_for_each_reflog(): reuse strbuf across recursive function calls\n  refs: wrap top-level ref_dirs in ref_entries\n  get_packed_refs(): return (ref_entry *) instead of (ref_dir *)\n  get_loose_refs(): return (ref_entry *) instead of (ref_dir *)\n  is_refname_available(): take (ref_entry *) instead of (ref_dir *)\n  find_ref(): take (ref_entry *) instead of (ref_dir *)\n  read_packed_refs(): take (ref_entry *) instead of (ref_dir *)\n  add_ref(): take (ref_entry *) instead of (ref_dir *)\n  find_containing_direntry(): use (ref_entry *) instead of (ref_dir *)\n  get_ref_dir(): take (ref_entry *) instead of (ref_dir *)\n  get_ref_dir(): remove dirname argument\n  search_for_subdir(): take (ref_entry *) instead of (ref_dir *)\n  search_ref_dir(): take (ref_entry *) instead of (ref_dir *)\n  add_entry(): take (ref_entry *) instead of (ref_dir *)\n  do_for_each_ref_in_dirs(): take (ref_entry *) instead of (ref_dir *)\n  do_for_each_ref_in_dir(): take (ref_entry *) instead of (ref_dir *)\n  sort_ref_dir(): take (ref_entry *) instead of (ref_dir *)\n  struct ref_dir: store a reference to the enclosing ref_cache\n  read_loose_refs(): rename function from get_ref_dir()\n  read_loose_refs(): access ref_cache via the ref_dir field\n  create_dir_entry(): allow the flag value to be passed as an argument\n  refs: read loose references lazily\n\n refs.c |  550 +++++++++++++++++++++++++++++++++++++++-------------------------\n 1 file changed, 332 insertions(+), 218 deletions(-)\n\n-- \n1.7.10\n"},{"id":"190005","messageId":"1335307536-26914-2-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 01/30] get_ref_dir(): return early if directory cannot be read","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:07Z","receivedAt":"2012-04-24T22:45:07Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   85 +++++++++++++++++++++++++++++++++-------------------------------\n 1 file changed, 44 insertions(+), 41 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 09322fe..d539241 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -754,6 +754,9 @@ static void get_ref_dir(struct ref_cache *refs, const char *base,\n {\n \tDIR *d;\n \tconst char *path;\n+\tstruct dirent *de;\n+\tint baselen;\n+\tchar *refname;\n \n \tif (*refs->name)\n \t\tpath = git_path_submodule(refs->name, \"%s\", base);\n@@ -761,55 +764,55 @@ static void get_ref_dir(struct ref_cache *refs, const char *base,\n \t\tpath = git_path(\"%s\", base);\n \n \td = opendir(path);\n-\tif (d) {\n-\t\tstruct dirent *de;\n-\t\tint baselen = strlen(base);\n-\t\tchar *refname = xmalloc(baselen + 257);\n+\tif (!d)\n+\t\treturn;\n \n-\t\tmemcpy(refname, base, baselen);\n-\t\tif (baselen && base[baselen-1] != '/')\n-\t\t\trefname[baselen++] = '/';\n+\tbaselen = strlen(base);\n+\trefname = xmalloc(baselen + 257);\n \n-\t\twhile ((de = readdir(d)) != NULL) {\n-\t\t\tunsigned char sha1[20];\n-\t\t\tstruct stat st;\n-\t\t\tint flag;\n-\t\t\tint namelen;\n-\t\t\tconst char *refdir;\n+\tmemcpy(refname, base, baselen);\n+\tif (baselen && base[baselen-1] != '/')\n+\t\trefname[baselen++] = '/';\n \n-\t\t\tif (de->d_name[0] == '.')\n-\t\t\t\tcontinue;\n-\t\t\tnamelen = strlen(de->d_name);\n-\t\t\tif (namelen > 255)\n-\t\t\t\tcontinue;\n-\t\t\tif (has_extension(de->d_name, \".lock\"))\n-\t\t\t\tcontinue;\n-\t\t\tmemcpy(refname + baselen, de->d_name, namelen+1);\n-\t\t\trefdir = *refs->name\n-\t\t\t\t? git_path_submodule(refs->name, \"%s\", refname)\n-\t\t\t\t: git_path(\"%s\", refname);\n-\t\t\tif (stat(refdir, &st) < 0)\n-\t\t\t\tcontinue;\n-\t\t\tif (S_ISDIR(st.st_mode)) {\n-\t\t\t\tget_ref_dir(refs, refname, dir);\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tif (*refs->name) {\n-\t\t\t\thashclr(sha1);\n-\t\t\t\tflag = 0;\n-\t\t\t\tif (resolve_gitlink_ref(refs->name, refname, sha1) < 0) {\n-\t\t\t\t\thashclr(sha1);\n-\t\t\t\t\tflag |= REF_ISBROKEN;\n-\t\t\t\t}\n-\t\t\t} else if (read_ref_full(refname, sha1, 1, &flag)) {\n+\twhile ((de = readdir(d)) != NULL) {\n+\t\tunsigned char sha1[20];\n+\t\tstruct stat st;\n+\t\tint flag;\n+\t\tint namelen;\n+\t\tconst char *refdir;\n+\n+\t\tif (de->d_name[0] == '.')\n+\t\t\tcontinue;\n+\t\tnamelen = strlen(de->d_name);\n+\t\tif (namelen > 255)\n+\t\t\tcontinue;\n+\t\tif (has_extension(de->d_name, \".lock\"))\n+\t\t\tcontinue;\n+\t\tmemcpy(refname + baselen, de->d_name, namelen+1);\n+\t\trefdir = *refs->name\n+\t\t\t? git_path_submodule(refs->name, \"%s\", refname)\n+\t\t\t: git_path(\"%s\", refname);\n+\t\tif (stat(refdir, &st) < 0)\n+\t\t\tcontinue;\n+\t\tif (S_ISDIR(st.st_mode)) {\n+\t\t\tget_ref_dir(refs, refname, dir);\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (*refs->name) {\n+\t\t\thashclr(sha1);\n+\t\t\tflag = 0;\n+\t\t\tif (resolve_gitlink_ref(refs->name, refname, sha1) < 0) {\n \t\t\t\thashclr(sha1);\n \t\t\t\tflag |= REF_ISBROKEN;\n \t\t\t}\n-\t\t\tadd_ref(dir, create_ref_entry(refname, sha1, flag, 1));\n+\t\t} else if (read_ref_full(refname, sha1, 1, &flag)) {\n+\t\t\thashclr(sha1);\n+\t\t\tflag |= REF_ISBROKEN;\n \t\t}\n-\t\tfree(refname);\n-\t\tclosedir(d);\n+\t\tadd_ref(dir, create_ref_entry(refname, sha1, flag, 1));\n \t}\n+\tfree(refname);\n+\tclosedir(d);\n }\n \n static struct ref_dir *get_loose_refs(struct ref_cache *refs)\n-- \n1.7.10\n"},{"id":"190006","messageId":"1335307536-26914-3-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 02/30] get_ref_dir(): use a strbuf to hold refname","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:08Z","receivedAt":"2012-04-24T22:45:08Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nThis simplifies the bookkeeping and allows an (artificial) restriction\non refname component length to be removed.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   54 ++++++++++++++++++++++++++----------------------------\n 1 file changed, 26 insertions(+), 28 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex d539241..df98622 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -756,7 +756,7 @@ static void get_ref_dir(struct ref_cache *refs, const char *base,\n \tconst char *path;\n \tstruct dirent *de;\n \tint baselen;\n-\tchar *refname;\n+\tstruct strbuf refname;\n \n \tif (*refs->name)\n \t\tpath = git_path_submodule(refs->name, \"%s\", base);\n@@ -768,50 +768,48 @@ static void get_ref_dir(struct ref_cache *refs, const char *base,\n \t\treturn;\n \n \tbaselen = strlen(base);\n-\trefname = xmalloc(baselen + 257);\n-\n-\tmemcpy(refname, base, baselen);\n-\tif (baselen && base[baselen-1] != '/')\n-\t\trefname[baselen++] = '/';\n+\tstrbuf_init(&refname, baselen + 257);\n+\tstrbuf_add(&refname, base, baselen);\n+\tif (baselen && base[baselen-1] != '/') {\n+\t\tstrbuf_addch(&refname, '/');\n+\t\tbaselen++;\n+\t}\n \n \twhile ((de = readdir(d)) != NULL) {\n \t\tunsigned char sha1[20];\n \t\tstruct stat st;\n \t\tint flag;\n-\t\tint namelen;\n \t\tconst char *refdir;\n \n \t\tif (de->d_name[0] == '.')\n \t\t\tcontinue;\n-\t\tnamelen = strlen(de->d_name);\n-\t\tif (namelen > 255)\n-\t\t\tcontinue;\n \t\tif (has_extension(de->d_name, \".lock\"))\n \t\t\tcontinue;\n-\t\tmemcpy(refname + baselen, de->d_name, namelen+1);\n+\t\tstrbuf_addstr(&refname, de->d_name);\n \t\trefdir = *refs->name\n-\t\t\t? git_path_submodule(refs->name, \"%s\", refname)\n-\t\t\t: git_path(\"%s\", refname);\n-\t\tif (stat(refdir, &st) < 0)\n-\t\t\tcontinue;\n-\t\tif (S_ISDIR(st.st_mode)) {\n-\t\t\tget_ref_dir(refs, refname, dir);\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (*refs->name) {\n-\t\t\thashclr(sha1);\n-\t\t\tflag = 0;\n-\t\t\tif (resolve_gitlink_ref(refs->name, refname, sha1) < 0) {\n+\t\t\t? git_path_submodule(refs->name, \"%s\", refname.buf)\n+\t\t\t: git_path(\"%s\", refname.buf);\n+\t\tif (stat(refdir, &st) < 0) {\n+\t\t\t/* Silently ignore. */\n+\t\t} else if (S_ISDIR(st.st_mode)) {\n+\t\t\tget_ref_dir(refs, refname.buf, dir);\n+\t\t} else {\n+\t\t\tif (*refs->name) {\n+\t\t\t\thashclr(sha1);\n+\t\t\t\tflag = 0;\n+\t\t\t\tif (resolve_gitlink_ref(refs->name, refname.buf, sha1) < 0) {\n+\t\t\t\t\thashclr(sha1);\n+\t\t\t\t\tflag |= REF_ISBROKEN;\n+\t\t\t\t}\n+\t\t\t} else if (read_ref_full(refname.buf, sha1, 1, &flag)) {\n \t\t\t\thashclr(sha1);\n \t\t\t\tflag |= REF_ISBROKEN;\n \t\t\t}\n-\t\t} else if (read_ref_full(refname, sha1, 1, &flag)) {\n-\t\t\thashclr(sha1);\n-\t\t\tflag |= REF_ISBROKEN;\n+\t\t\tadd_ref(dir, create_ref_entry(refname.buf, sha1, flag, 1));\n \t\t}\n-\t\tadd_ref(dir, create_ref_entry(refname, sha1, flag, 1));\n+\t\tstrbuf_setlen(&refname, baselen);\n \t}\n-\tfree(refname);\n+\tstrbuf_release(&refname);\n \tclosedir(d);\n }\n \n-- \n1.7.10\n"},{"id":"190002","messageId":"1335307536-26914-4-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 03/30] get_ref_dir(): rename \"base\" parameter to \"dirname\"","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:09Z","receivedAt":"2012-04-24T22:45:09Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   20 ++++++++++----------\n 1 file changed, 10 insertions(+), 10 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex df98622..dc2b4df 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -749,30 +749,30 @@ void add_packed_ref(const char *refname, const unsigned char *sha1)\n \t\t\tcreate_ref_entry(refname, sha1, REF_ISPACKED, 1));\n }\n \n-static void get_ref_dir(struct ref_cache *refs, const char *base,\n+static void get_ref_dir(struct ref_cache *refs, const char *dirname,\n \t\t\tstruct ref_dir *dir)\n {\n \tDIR *d;\n \tconst char *path;\n \tstruct dirent *de;\n-\tint baselen;\n+\tint dirnamelen;\n \tstruct strbuf refname;\n \n \tif (*refs->name)\n-\t\tpath = git_path_submodule(refs->name, \"%s\", base);\n+\t\tpath = git_path_submodule(refs->name, \"%s\", dirname);\n \telse\n-\t\tpath = git_path(\"%s\", base);\n+\t\tpath = git_path(\"%s\", dirname);\n \n \td = opendir(path);\n \tif (!d)\n \t\treturn;\n \n-\tbaselen = strlen(base);\n-\tstrbuf_init(&refname, baselen + 257);\n-\tstrbuf_add(&refname, base, baselen);\n-\tif (baselen && base[baselen-1] != '/') {\n+\tdirnamelen = strlen(dirname);\n+\tstrbuf_init(&refname, dirnamelen + 257);\n+\tstrbuf_add(&refname, dirname, dirnamelen);\n+\tif (dirnamelen && dirname[dirnamelen-1] != '/') {\n \t\tstrbuf_addch(&refname, '/');\n-\t\tbaselen++;\n+\t\tdirnamelen++;\n \t}\n \n \twhile ((de = readdir(d)) != NULL) {\n@@ -807,7 +807,7 @@ static void get_ref_dir(struct ref_cache *refs, const char *base,\n \t\t\t}\n \t\t\tadd_ref(dir, create_ref_entry(refname.buf, sha1, flag, 1));\n \t\t}\n-\t\tstrbuf_setlen(&refname, baselen);\n+\t\tstrbuf_setlen(&refname, dirnamelen);\n \t}\n \tstrbuf_release(&refname);\n \tclosedir(d);\n-- \n1.7.10\n"},{"id":"190004","messageId":"1335307536-26914-5-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 04/30] get_ref_dir(): require that the dirname argument ends in '/'","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:10Z","receivedAt":"2012-04-24T22:45:10Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nThis removes some conditional code and makes it consistent with the\nway that direntry names are stored.  Please note that this function is\nnever used on the top-level .git directory; it is always called for\ndirectories at level .git/refs or deeper.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   14 +++++++-------\n 1 file changed, 7 insertions(+), 7 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex dc2b4df..01fcdc7 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -749,13 +749,17 @@ void add_packed_ref(const char *refname, const unsigned char *sha1)\n \t\t\tcreate_ref_entry(refname, sha1, REF_ISPACKED, 1));\n }\n \n+/*\n+ * Read the loose references for refs from the namespace dirname.\n+ * dirname must end with '/'.\n+ */\n static void get_ref_dir(struct ref_cache *refs, const char *dirname,\n \t\t\tstruct ref_dir *dir)\n {\n \tDIR *d;\n \tconst char *path;\n \tstruct dirent *de;\n-\tint dirnamelen;\n+\tint dirnamelen = strlen(dirname);\n \tstruct strbuf refname;\n \n \tif (*refs->name)\n@@ -767,13 +771,8 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname,\n \tif (!d)\n \t\treturn;\n \n-\tdirnamelen = strlen(dirname);\n \tstrbuf_init(&refname, dirnamelen + 257);\n \tstrbuf_add(&refname, dirname, dirnamelen);\n-\tif (dirnamelen && dirname[dirnamelen-1] != '/') {\n-\t\tstrbuf_addch(&refname, '/');\n-\t\tdirnamelen++;\n-\t}\n \n \twhile ((de = readdir(d)) != NULL) {\n \t\tunsigned char sha1[20];\n@@ -792,6 +791,7 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname,\n \t\tif (stat(refdir, &st) < 0) {\n \t\t\t/* Silently ignore. */\n \t\t} else if (S_ISDIR(st.st_mode)) {\n+\t\t\tstrbuf_addch(&refname, '/');\n \t\t\tget_ref_dir(refs, refname.buf, dir);\n \t\t} else {\n \t\t\tif (*refs->name) {\n@@ -816,7 +816,7 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname,\n static struct ref_dir *get_loose_refs(struct ref_cache *refs)\n {\n \tif (!refs->did_loose) {\n-\t\tget_ref_dir(refs, \"refs\", &refs->loose);\n+\t\tget_ref_dir(refs, \"refs/\", &refs->loose);\n \t\trefs->did_loose = 1;\n \t}\n \treturn &refs->loose;\n-- \n1.7.10\n"},{"id":"190016","messageId":"1335307536-26914-6-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 05/30] refs.c: extract function search_for_subdir()","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:11Z","receivedAt":"2012-04-24T22:45:11Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   34 ++++++++++++++++++++++++----------\n 1 file changed, 24 insertions(+), 10 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 01fcdc7..5e51c10 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -277,6 +277,27 @@ static struct ref_entry *search_ref_dir(struct ref_dir *dir, const char *refname\n }\n \n /*\n+ * Search for a directory entry directly within dir (without\n+ * recursing).  Sort dir if necessary.  subdirname must be a directory\n+ * name (i.e., end in '/').  If mkdir is set, then create the\n+ * directory if it is missing; otherwise, return NULL if the desired\n+ * directory cannot be found.\n+ */\n+static struct ref_entry *search_for_subdir(struct ref_dir *dir,\n+\t\t\t\t\t   const char *subdirname, int mkdir)\n+{\n+\tstruct ref_entry *entry = search_ref_dir(dir, subdirname);\n+\tif (!entry) {\n+\t\tif (!mkdir)\n+\t\t\treturn NULL;\n+\t\tentry = create_dir_entry(subdirname);\n+\t\tadd_entry_to_dir(dir, entry);\n+\t}\n+\tassert(entry->flag & REF_DIR);\n+\treturn entry;\n+}\n+\n+/*\n  * If refname is a reference name, find the ref_dir within the dir\n  * tree that should hold refname.  If refname is a directory name\n  * (i.e., ends in '/'), then return that ref_dir itself.  dir must\n@@ -294,17 +315,10 @@ static struct ref_dir *find_containing_dir(struct ref_dir *dir,\n \tfor (slash = strchr(refname_copy, '/'); slash; slash = strchr(slash + 1, '/')) {\n \t\tchar tmp = slash[1];\n \t\tslash[1] = '\\0';\n-\t\tentry = search_ref_dir(dir, refname_copy);\n-\t\tif (!entry) {\n-\t\t\tif (!mkdir) {\n-\t\t\t\tdir = NULL;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tentry = create_dir_entry(refname_copy);\n-\t\t\tadd_entry_to_dir(dir, entry);\n-\t\t}\n+\t\tentry = search_for_subdir(dir, refname_copy, mkdir);\n \t\tslash[1] = tmp;\n-\t\tassert(entry->flag & REF_DIR);\n+\t\tif (!entry)\n+\t\t\tbreak;\n \t\tdir = &entry->u.subdir;\n \t}\n \n-- \n1.7.10\n"},{"id":"190031","messageId":"1335307536-26914-7-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 06/30] get_ref_dir(): take the containing directory as argument","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:12Z","receivedAt":"2012-04-24T22:45:12Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nPreviously, the \"dir\" argument to get_ref_dir() was a pointer to the\ntop-level ref_dir.  Change the function to expect a pointer to the\nref_dir corresponding to dirname.  This allows entries to be added\ndirectly to dir, without having to recurse through the reference trie\neach time (i.e., we can use add_entry_to_dir() instead of add_ref()).\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   12 ++++++++----\n 1 file changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 5e51c10..8670c2e 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -765,7 +765,8 @@ void add_packed_ref(const char *refname, const unsigned char *sha1)\n \n /*\n  * Read the loose references for refs from the namespace dirname.\n- * dirname must end with '/'.\n+ * dirname must end with '/'.  dir must be the directory entry\n+ * corresponding to dirname.\n  */\n static void get_ref_dir(struct ref_cache *refs, const char *dirname,\n \t\t\tstruct ref_dir *dir)\n@@ -806,7 +807,8 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname,\n \t\t\t/* Silently ignore. */\n \t\t} else if (S_ISDIR(st.st_mode)) {\n \t\t\tstrbuf_addch(&refname, '/');\n-\t\t\tget_ref_dir(refs, refname.buf, dir);\n+\t\t\tget_ref_dir(refs, refname.buf,\n+\t\t\t\t    &search_for_subdir(dir, refname.buf, 1)->u.subdir);\n \t\t} else {\n \t\t\tif (*refs->name) {\n \t\t\t\thashclr(sha1);\n@@ -819,7 +821,8 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname,\n \t\t\t\thashclr(sha1);\n \t\t\t\tflag |= REF_ISBROKEN;\n \t\t\t}\n-\t\t\tadd_ref(dir, create_ref_entry(refname.buf, sha1, flag, 1));\n+\t\t\tadd_entry_to_dir(dir,\n+\t\t\t\t\t create_ref_entry(refname.buf, sha1, flag, 1));\n \t\t}\n \t\tstrbuf_setlen(&refname, dirnamelen);\n \t}\n@@ -830,7 +833,8 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname,\n static struct ref_dir *get_loose_refs(struct ref_cache *refs)\n {\n \tif (!refs->did_loose) {\n-\t\tget_ref_dir(refs, \"refs/\", &refs->loose);\n+\t\tget_ref_dir(refs, \"refs/\",\n+\t\t\t    &search_for_subdir(&refs->loose, \"refs/\", 1)->u.subdir);\n \t\trefs->did_loose = 1;\n \t}\n \treturn &refs->loose;\n-- \n1.7.10\n"},{"id":"190030","messageId":"1335307536-26914-8-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 07/30] do_for_each_reflog(): return early on error","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:13Z","receivedAt":"2012-04-24T22:45:13Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   70 ++++++++++++++++++++++++++++++++--------------------------------\n 1 file changed, 35 insertions(+), 35 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 8670c2e..1d25151 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -2246,47 +2246,47 @@ static int do_for_each_reflog(const char *base, each_ref_fn fn, void *cb_data)\n {\n \tDIR *d = opendir(git_path(\"logs/%s\", base));\n \tint retval = 0;\n+\tstruct dirent *de;\n+\tint baselen;\n+\tchar *log;\n \n-\tif (d) {\n-\t\tstruct dirent *de;\n-\t\tint baselen = strlen(base);\n-\t\tchar *log = xmalloc(baselen + 257);\n+\tif (!d)\n+\t\treturn *base ? errno : 0;\n \n-\t\tmemcpy(log, base, baselen);\n-\t\tif (baselen && base[baselen-1] != '/')\n-\t\t\tlog[baselen++] = '/';\n+\tbaselen = strlen(base);\n+\tlog = xmalloc(baselen + 257);\n+\tmemcpy(log, base, baselen);\n+\tif (baselen && base[baselen-1] != '/')\n+\t\tlog[baselen++] = '/';\n \n-\t\twhile ((de = readdir(d)) != NULL) {\n-\t\t\tstruct stat st;\n-\t\t\tint namelen;\n+\twhile ((de = readdir(d)) != NULL) {\n+\t\tstruct stat st;\n+\t\tint namelen;\n \n-\t\t\tif (de->d_name[0] == '.')\n-\t\t\t\tcontinue;\n-\t\t\tnamelen = strlen(de->d_name);\n-\t\t\tif (namelen > 255)\n-\t\t\t\tcontinue;\n-\t\t\tif (has_extension(de->d_name, \".lock\"))\n-\t\t\t\tcontinue;\n-\t\t\tmemcpy(log + baselen, de->d_name, namelen+1);\n-\t\t\tif (stat(git_path(\"logs/%s\", log), &st) < 0)\n-\t\t\t\tcontinue;\n-\t\t\tif (S_ISDIR(st.st_mode)) {\n-\t\t\t\tretval = do_for_each_reflog(log, fn, cb_data);\n-\t\t\t} else {\n-\t\t\t\tunsigned char sha1[20];\n-\t\t\t\tif (read_ref_full(log, sha1, 0, NULL))\n-\t\t\t\t\tretval = error(\"bad ref for %s\", log);\n-\t\t\t\telse\n-\t\t\t\t\tretval = fn(log, sha1, 0, cb_data);\n-\t\t\t}\n-\t\t\tif (retval)\n-\t\t\t\tbreak;\n+\t\tif (de->d_name[0] == '.')\n+\t\t\tcontinue;\n+\t\tnamelen = strlen(de->d_name);\n+\t\tif (namelen > 255)\n+\t\t\tcontinue;\n+\t\tif (has_extension(de->d_name, \".lock\"))\n+\t\t\tcontinue;\n+\t\tmemcpy(log + baselen, de->d_name, namelen+1);\n+\t\tif (stat(git_path(\"logs/%s\", log), &st) < 0)\n+\t\t\tcontinue;\n+\t\tif (S_ISDIR(st.st_mode)) {\n+\t\t\tretval = do_for_each_reflog(log, fn, cb_data);\n+\t\t} else {\n+\t\t\tunsigned char sha1[20];\n+\t\t\tif (read_ref_full(log, sha1, 0, NULL))\n+\t\t\t\tretval = error(\"bad ref for %s\", log);\n+\t\t\telse\n+\t\t\t\tretval = fn(log, sha1, 0, cb_data);\n \t\t}\n-\t\tfree(log);\n-\t\tclosedir(d);\n+\t\tif (retval)\n+\t\t\tbreak;\n \t}\n-\telse if (*base)\n-\t\treturn errno;\n+\tfree(log);\n+\tclosedir(d);\n \treturn retval;\n }\n \n-- \n1.7.10\n"},{"id":"190012","messageId":"1335307536-26914-9-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 08/30] do_for_each_reflog(): use a strbuf to hold logfile name","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:14Z","receivedAt":"2012-04-24T22:45:14Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nThis simplifies the bookkeeping and allows an (artificial) restriction\non refname component length to be removed.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   45 +++++++++++++++++++++++----------------------\n 1 file changed, 23 insertions(+), 22 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 1d25151..f43c255 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -2248,44 +2248,45 @@ static int do_for_each_reflog(const char *base, each_ref_fn fn, void *cb_data)\n \tint retval = 0;\n \tstruct dirent *de;\n \tint baselen;\n-\tchar *log;\n+\tstruct strbuf log;\n \n \tif (!d)\n \t\treturn *base ? errno : 0;\n \n \tbaselen = strlen(base);\n-\tlog = xmalloc(baselen + 257);\n-\tmemcpy(log, base, baselen);\n-\tif (baselen && base[baselen-1] != '/')\n-\t\tlog[baselen++] = '/';\n+\tstrbuf_init(&log, baselen + 257);\n+\tstrbuf_add(&log, base, baselen);\n+\tif (log.len && log.buf[log.len-1] != '/') {\n+\t\tstrbuf_addch(&log, '/');\n+\t\tbaselen++;\n+\t}\n \n \twhile ((de = readdir(d)) != NULL) {\n \t\tstruct stat st;\n-\t\tint namelen;\n \n \t\tif (de->d_name[0] == '.')\n \t\t\tcontinue;\n-\t\tnamelen = strlen(de->d_name);\n-\t\tif (namelen > 255)\n-\t\t\tcontinue;\n \t\tif (has_extension(de->d_name, \".lock\"))\n \t\t\tcontinue;\n-\t\tmemcpy(log + baselen, de->d_name, namelen+1);\n-\t\tif (stat(git_path(\"logs/%s\", log), &st) < 0)\n-\t\t\tcontinue;\n-\t\tif (S_ISDIR(st.st_mode)) {\n-\t\t\tretval = do_for_each_reflog(log, fn, cb_data);\n+\t\tstrbuf_addstr(&log, de->d_name);\n+\t\tif (stat(git_path(\"logs/%s\", log.buf), &st) < 0) {\n+\t\t\t/* Silently ignore. */\n \t\t} else {\n-\t\t\tunsigned char sha1[20];\n-\t\t\tif (read_ref_full(log, sha1, 0, NULL))\n-\t\t\t\tretval = error(\"bad ref for %s\", log);\n-\t\t\telse\n-\t\t\t\tretval = fn(log, sha1, 0, cb_data);\n+\t\t\tif (S_ISDIR(st.st_mode)) {\n+\t\t\t\tretval = do_for_each_reflog(log.buf, fn, cb_data);\n+\t\t\t} else {\n+\t\t\t\tunsigned char sha1[20];\n+\t\t\t\tif (read_ref_full(log.buf, sha1, 0, NULL))\n+\t\t\t\t\tretval = error(\"bad ref for %s\", log.buf);\n+\t\t\t\telse\n+\t\t\t\t\tretval = fn(log.buf, sha1, 0, cb_data);\n+\t\t\t}\n+\t\t\tif (retval)\n+\t\t\t\tbreak;\n \t\t}\n-\t\tif (retval)\n-\t\t\tbreak;\n+\t\tstrbuf_setlen(&log, baselen);\n \t}\n-\tfree(log);\n+\tstrbuf_release(&log);\n \tclosedir(d);\n \treturn retval;\n }\n-- \n1.7.10\n"},{"id":"190009","messageId":"1335307536-26914-10-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 09/30] do_for_each_reflog(): reuse strbuf across recursive function calls","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:15Z","receivedAt":"2012-04-24T22:45:15Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nThis saves some memory allocations.  Also require that the name\nargument end in slash, which removes some extra bookkeeping.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   45 +++++++++++++++++++++++----------------------\n 1 file changed, 23 insertions(+), 22 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex f43c255..989c10d 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -2242,24 +2242,20 @@ int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, void *cb_dat\n \treturn for_each_recent_reflog_ent(refname, fn, 0, cb_data);\n }\n \n-static int do_for_each_reflog(const char *base, each_ref_fn fn, void *cb_data)\n+/*\n+ * Call fn for each reflog in the namespace indicated by name.  name\n+ * must be empty or end with '/'.  Name will be used as a scratch\n+ * space, but its contents will be restored before return.\n+ */\n+static int do_for_each_reflog(struct strbuf *name, each_ref_fn fn, void *cb_data)\n {\n-\tDIR *d = opendir(git_path(\"logs/%s\", base));\n+\tDIR *d = opendir(git_path(\"logs/%s\", name->buf));\n \tint retval = 0;\n \tstruct dirent *de;\n-\tint baselen;\n-\tstruct strbuf log;\n+\tint oldlen = name->len;\n \n \tif (!d)\n-\t\treturn *base ? errno : 0;\n-\n-\tbaselen = strlen(base);\n-\tstrbuf_init(&log, baselen + 257);\n-\tstrbuf_add(&log, base, baselen);\n-\tif (log.len && log.buf[log.len-1] != '/') {\n-\t\tstrbuf_addch(&log, '/');\n-\t\tbaselen++;\n-\t}\n+\t\treturn name->len ? errno : 0;\n \n \twhile ((de = readdir(d)) != NULL) {\n \t\tstruct stat st;\n@@ -2268,32 +2264,37 @@ static int do_for_each_reflog(const char *base, each_ref_fn fn, void *cb_data)\n \t\t\tcontinue;\n \t\tif (has_extension(de->d_name, \".lock\"))\n \t\t\tcontinue;\n-\t\tstrbuf_addstr(&log, de->d_name);\n-\t\tif (stat(git_path(\"logs/%s\", log.buf), &st) < 0) {\n+\t\tstrbuf_addstr(name, de->d_name);\n+\t\tif (stat(git_path(\"logs/%s\", name->buf), &st) < 0) {\n \t\t\t/* Silently ignore. */\n \t\t} else {\n \t\t\tif (S_ISDIR(st.st_mode)) {\n-\t\t\t\tretval = do_for_each_reflog(log.buf, fn, cb_data);\n+\t\t\t\tstrbuf_addch(name, '/');\n+\t\t\t\tretval = do_for_each_reflog(name, fn, cb_data);\n \t\t\t} else {\n \t\t\t\tunsigned char sha1[20];\n-\t\t\t\tif (read_ref_full(log.buf, sha1, 0, NULL))\n-\t\t\t\t\tretval = error(\"bad ref for %s\", log.buf);\n+\t\t\t\tif (read_ref_full(name->buf, sha1, 0, NULL))\n+\t\t\t\t\tretval = error(\"bad ref for %s\", name->buf);\n \t\t\t\telse\n-\t\t\t\t\tretval = fn(log.buf, sha1, 0, cb_data);\n+\t\t\t\t\tretval = fn(name->buf, sha1, 0, cb_data);\n \t\t\t}\n \t\t\tif (retval)\n \t\t\t\tbreak;\n \t\t}\n-\t\tstrbuf_setlen(&log, baselen);\n+\t\tstrbuf_setlen(name, oldlen);\n \t}\n-\tstrbuf_release(&log);\n \tclosedir(d);\n \treturn retval;\n }\n \n int for_each_reflog(each_ref_fn fn, void *cb_data)\n {\n-\treturn do_for_each_reflog(\"\", fn, cb_data);\n+\tint retval;\n+\tstruct strbuf name;\n+\tstrbuf_init(&name, PATH_MAX);\n+\tretval = do_for_each_reflog(&name, fn, cb_data);\n+\tstrbuf_release(&name);\n+\treturn retval;\n }\n \n int update_ref(const char *action, const char *refname,\n-- \n1.7.10\n"},{"id":"190014","messageId":"1335307536-26914-11-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 10/30] refs: wrap top-level ref_dirs in ref_entries","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:16Z","receivedAt":"2012-04-24T22:45:16Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nWrap the top-level ref_dirs in REF_DIR style ref_entries so that we\nhave the flag and name available when dealing with them.  This\naffects:\n\n* cache_ref::loose\n* cache_ref::packed\n* extra_refs\n\nThe next several commits will expand the use of ref_entry as opposed\nto ref_dir, culminating in the ability of a ref_entry representing a\ndirectory of loose references to load itself only when used.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   37 +++++++++++++++++++------------------\n 1 file changed, 19 insertions(+), 18 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 989c10d..4c92dc9 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -606,26 +606,26 @@ static int is_refname_available(const char *refname, const char *oldrefname,\n  */\n static struct ref_cache {\n \tstruct ref_cache *next;\n-\tchar did_loose;\n-\tchar did_packed;\n-\tstruct ref_dir loose;\n-\tstruct ref_dir packed;\n+\tstruct ref_entry *loose;\n+\tstruct ref_entry *packed;\n \t/* The submodule name, or \"\" for the main repo. */\n \tchar name[FLEX_ARRAY];\n } *ref_cache;\n \n static void clear_packed_ref_cache(struct ref_cache *refs)\n {\n-\tif (refs->did_packed)\n-\t\tclear_ref_dir(&refs->packed);\n-\trefs->did_packed = 0;\n+\tif (refs->packed) {\n+\t\tfree_ref_entry(refs->packed);\n+\t\trefs->packed = NULL;\n+\t}\n }\n \n static void clear_loose_ref_cache(struct ref_cache *refs)\n {\n-\tif (refs->did_loose)\n-\t\tclear_ref_dir(&refs->loose);\n-\trefs->did_loose = 0;\n+\tif (refs->loose) {\n+\t\tfree_ref_entry(refs->loose);\n+\t\trefs->loose = NULL;\n+\t}\n }\n \n static struct ref_cache *create_ref_cache(const char *submodule)\n@@ -739,22 +739,22 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)\n \n static struct ref_dir *get_packed_refs(struct ref_cache *refs)\n {\n-\tif (!refs->did_packed) {\n+\tif (!refs->packed) {\n \t\tconst char *packed_refs_file;\n \t\tFILE *f;\n \n+\t\trefs->packed = create_dir_entry(\"\");\n \t\tif (*refs->name)\n \t\t\tpacked_refs_file = git_path_submodule(refs->name, \"packed-refs\");\n \t\telse\n \t\t\tpacked_refs_file = git_path(\"packed-refs\");\n \t\tf = fopen(packed_refs_file, \"r\");\n \t\tif (f) {\n-\t\t\tread_packed_refs(f, &refs->packed);\n+\t\t\tread_packed_refs(f, &refs->packed->u.subdir);\n \t\t\tfclose(f);\n \t\t}\n-\t\trefs->did_packed = 1;\n \t}\n-\treturn &refs->packed;\n+\treturn &refs->packed->u.subdir;\n }\n \n void add_packed_ref(const char *refname, const unsigned char *sha1)\n@@ -832,12 +832,13 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname,\n \n static struct ref_dir *get_loose_refs(struct ref_cache *refs)\n {\n-\tif (!refs->did_loose) {\n+\tif (!refs->loose) {\n+\t\trefs->loose = create_dir_entry(\"\");\n \t\tget_ref_dir(refs, \"refs/\",\n-\t\t\t    &search_for_subdir(&refs->loose, \"refs/\", 1)->u.subdir);\n-\t\trefs->did_loose = 1;\n+\t\t\t    &search_for_subdir(&refs->loose->u.subdir,\n+\t\t\t\t\t       \"refs/\", 1)->u.subdir);\n \t}\n-\treturn &refs->loose;\n+\treturn &refs->loose->u.subdir;\n }\n \n /* We allow \"recursive\" symbolic refs. Only within reason, though */\n-- \n1.7.10\n"},{"id":"190032","messageId":"1335307536-26914-12-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 11/30] get_packed_refs(): return (ref_entry *) instead of (ref_dir *)","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:17Z","receivedAt":"2012-04-24T22:45:17Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   35 +++++++++++++++++++----------------\n 1 file changed, 19 insertions(+), 16 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 4c92dc9..24930ab 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -737,7 +737,7 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)\n \t}\n }\n \n-static struct ref_dir *get_packed_refs(struct ref_cache *refs)\n+static struct ref_entry *get_packed_refs(struct ref_cache *refs)\n {\n \tif (!refs->packed) {\n \t\tconst char *packed_refs_file;\n@@ -754,13 +754,13 @@ static struct ref_dir *get_packed_refs(struct ref_cache *refs)\n \t\t\tfclose(f);\n \t\t}\n \t}\n-\treturn &refs->packed->u.subdir;\n+\treturn refs->packed;\n }\n \n void add_packed_ref(const char *refname, const unsigned char *sha1)\n {\n-\tadd_ref(get_packed_refs(get_ref_cache(NULL)),\n-\t\t\tcreate_ref_entry(refname, sha1, REF_ISPACKED, 1));\n+\tadd_ref(&get_packed_refs(get_ref_cache(NULL))->u.subdir,\n+\t\tcreate_ref_entry(refname, sha1, REF_ISPACKED, 1));\n }\n \n /*\n@@ -854,9 +854,9 @@ static int resolve_gitlink_packed_ref(struct ref_cache *refs,\n \t\t\t\t      const char *refname, unsigned char *sha1)\n {\n \tstruct ref_entry *ref;\n-\tstruct ref_dir *dir = get_packed_refs(refs);\n+\tstruct ref_entry *direntry = get_packed_refs(refs);\n \n-\tref = find_ref(dir, refname);\n+\tref = find_ref(&direntry->u.subdir, refname);\n \tif (ref == NULL)\n \t\treturn -1;\n \n@@ -927,8 +927,8 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh\n  */\n static int get_packed_ref(const char *refname, unsigned char *sha1)\n {\n-\tstruct ref_dir *packed = get_packed_refs(get_ref_cache(NULL));\n-\tstruct ref_entry *entry = find_ref(packed, refname);\n+\tstruct ref_entry *packed = get_packed_refs(get_ref_cache(NULL));\n+\tstruct ref_entry *entry = find_ref(&packed->u.subdir, refname);\n \tif (entry) {\n \t\thashcpy(sha1, entry->u.value.sha1);\n \t\treturn 0;\n@@ -1104,8 +1104,8 @@ int peel_ref(const char *refname, unsigned char *sha1)\n \t\treturn -1;\n \n \tif ((flag & REF_ISPACKED)) {\n-\t\tstruct ref_dir *dir = get_packed_refs(get_ref_cache(NULL));\n-\t\tstruct ref_entry *r = find_ref(dir, refname);\n+\t\tstruct ref_entry *direntry = get_packed_refs(get_ref_cache(NULL));\n+\t\tstruct ref_entry *r = find_ref(&direntry->u.subdir, refname);\n \n \t\tif (r != NULL && r->flag & REF_KNOWS_PEELED) {\n \t\t\thashcpy(sha1, r->u.value.peeled);\n@@ -1163,7 +1163,8 @@ static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn\n \t\t\t   int trim, int flags, void *cb_data)\n {\n \tstruct ref_cache *refs = get_ref_cache(submodule);\n-\tstruct ref_dir *packed_dir = get_packed_refs(refs);\n+\tstruct ref_entry *packed_direntry = get_packed_refs(refs);\n+\tstruct ref_dir *packed_dir = &packed_direntry->u.subdir;\n \tstruct ref_dir *loose_dir = get_loose_refs(refs);\n \tint retval = 0;\n \n@@ -1545,7 +1546,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,\n \t * name is a proper prefix of our refname.\n \t */\n \tif (missing &&\n-\t     !is_refname_available(refname, NULL, get_packed_refs(get_ref_cache(NULL)))) {\n+\t     !is_refname_available(refname, NULL,\n+\t\t\t\t   &get_packed_refs(get_ref_cache(NULL))->u.subdir)) {\n \t\tlast_errno = ENOTDIR;\n \t\tgoto error_return;\n \t}\n@@ -1625,8 +1627,8 @@ static struct lock_file packlock;\n static int repack_without_ref(const char *refname)\n {\n \tstruct repack_without_ref_sb data;\n-\tstruct ref_dir *packed = get_packed_refs(get_ref_cache(NULL));\n-\tif (find_ref(packed, refname) == NULL)\n+\tstruct ref_entry *packed = get_packed_refs(get_ref_cache(NULL));\n+\tif (find_ref(&packed->u.subdir, refname) == NULL)\n \t\treturn 0;\n \tdata.refname = refname;\n \tdata.fd = hold_lock_file_for_update(&packlock, git_path(\"packed-refs\"), 0);\n@@ -1634,7 +1636,8 @@ static int repack_without_ref(const char *refname)\n \t\tunable_to_lock_error(git_path(\"packed-refs\"), errno);\n \t\treturn error(\"cannot delete '%s' from packed refs\", refname);\n \t}\n-\tdo_for_each_ref_in_dir(packed, 0, \"\", repack_without_ref_fn, 0, 0, &data);\n+\tdo_for_each_ref_in_dir(&packed->u.subdir, 0,\n+\t\t\t       \"\", repack_without_ref_fn, 0, 0, &data);\n \treturn commit_lock_file(&packlock);\n }\n \n@@ -1705,7 +1708,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms\n \tif (!symref)\n \t\treturn error(\"refname %s not found\", oldrefname);\n \n-\tif (!is_refname_available(newrefname, oldrefname, get_packed_refs(refs)))\n+\tif (!is_refname_available(newrefname, oldrefname, &get_packed_refs(refs)->u.subdir))\n \t\treturn 1;\n \n \tif (!is_refname_available(newrefname, oldrefname, get_loose_refs(refs)))\n-- \n1.7.10\n"},{"id":"190028","messageId":"1335307536-26914-13-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 12/30] get_loose_refs(): return (ref_entry *) instead of (ref_dir *)","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:18Z","receivedAt":"2012-04-24T22:45:18Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |    9 +++++----\n 1 file changed, 5 insertions(+), 4 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 24930ab..0259ad1 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -830,7 +830,7 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname,\n \tclosedir(d);\n }\n \n-static struct ref_dir *get_loose_refs(struct ref_cache *refs)\n+static struct ref_entry *get_loose_refs(struct ref_cache *refs)\n {\n \tif (!refs->loose) {\n \t\trefs->loose = create_dir_entry(\"\");\n@@ -838,7 +838,7 @@ static struct ref_dir *get_loose_refs(struct ref_cache *refs)\n \t\t\t    &search_for_subdir(&refs->loose->u.subdir,\n \t\t\t\t\t       \"refs/\", 1)->u.subdir);\n \t}\n-\treturn &refs->loose->u.subdir;\n+\treturn refs->loose;\n }\n \n /* We allow \"recursive\" symbolic refs. Only within reason, though */\n@@ -1165,7 +1165,8 @@ static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn\n \tstruct ref_cache *refs = get_ref_cache(submodule);\n \tstruct ref_entry *packed_direntry = get_packed_refs(refs);\n \tstruct ref_dir *packed_dir = &packed_direntry->u.subdir;\n-\tstruct ref_dir *loose_dir = get_loose_refs(refs);\n+\tstruct ref_entry *loose_direntry = get_loose_refs(refs);\n+\tstruct ref_dir *loose_dir = &loose_direntry->u.subdir;\n \tint retval = 0;\n \n \tif (base && *base) {\n@@ -1711,7 +1712,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms\n \tif (!is_refname_available(newrefname, oldrefname, &get_packed_refs(refs)->u.subdir))\n \t\treturn 1;\n \n-\tif (!is_refname_available(newrefname, oldrefname, get_loose_refs(refs)))\n+\tif (!is_refname_available(newrefname, oldrefname, &get_loose_refs(refs)->u.subdir))\n \t\treturn 1;\n \n \tif (log && rename(git_path(\"logs/%s\", oldrefname), git_path(TMP_RENAMED_LOG)))\n-- \n1.7.10\n"},{"id":"190019","messageId":"1335307536-26914-14-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 13/30] is_refname_available(): take (ref_entry *) instead of (ref_dir *)","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:19Z","receivedAt":"2012-04-24T22:45:19Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   16 +++++++++-------\n 1 file changed, 9 insertions(+), 7 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 0259ad1..044dee9 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -576,21 +576,23 @@ static int name_conflict_fn(const char *existingrefname, const unsigned char *sh\n \n /*\n  * Return true iff a reference named refname could be created without\n- * conflicting with the name of an existing reference in array.  If\n+ * conflicting with the name of an existing reference in direntry.  If\n  * oldrefname is non-NULL, ignore potential conflicts with oldrefname\n  * (e.g., because oldrefname is scheduled for deletion in the same\n  * operation).\n  */\n static int is_refname_available(const char *refname, const char *oldrefname,\n-\t\t\t\tstruct ref_dir *dir)\n+\t\t\t\tstruct ref_entry *direntry)\n {\n \tstruct name_conflict_cb data;\n \tdata.refname = refname;\n \tdata.oldrefname = oldrefname;\n \tdata.conflicting_refname = NULL;\n \n-\tsort_ref_dir(dir);\n-\tif (do_for_each_ref_in_dir(dir, 0, \"\", name_conflict_fn,\n+\tassert(direntry->flag & REF_DIR);\n+\tsort_ref_dir(&direntry->u.subdir);\n+\n+\tif (do_for_each_ref_in_dir(&direntry->u.subdir, 0, \"\", name_conflict_fn,\n \t\t\t\t   0, DO_FOR_EACH_INCLUDE_BROKEN,\n \t\t\t\t   &data)) {\n \t\terror(\"'%s' exists; cannot create '%s'\",\n@@ -1548,7 +1550,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,\n \t */\n \tif (missing &&\n \t     !is_refname_available(refname, NULL,\n-\t\t\t\t   &get_packed_refs(get_ref_cache(NULL))->u.subdir)) {\n+\t\t\t\t   get_packed_refs(get_ref_cache(NULL)))) {\n \t\tlast_errno = ENOTDIR;\n \t\tgoto error_return;\n \t}\n@@ -1709,10 +1711,10 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms\n \tif (!symref)\n \t\treturn error(\"refname %s not found\", oldrefname);\n \n-\tif (!is_refname_available(newrefname, oldrefname, &get_packed_refs(refs)->u.subdir))\n+\tif (!is_refname_available(newrefname, oldrefname, get_packed_refs(refs)))\n \t\treturn 1;\n \n-\tif (!is_refname_available(newrefname, oldrefname, &get_loose_refs(refs)->u.subdir))\n+\tif (!is_refname_available(newrefname, oldrefname, get_loose_refs(refs)))\n \t\treturn 1;\n \n \tif (log && rename(git_path(\"logs/%s\", oldrefname), git_path(TMP_RENAMED_LOG)))\n-- \n1.7.10\n"},{"id":"190015","messageId":"1335307536-26914-15-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 14/30] find_ref(): take (ref_entry *) instead of (ref_dir *)","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:20Z","receivedAt":"2012-04-24T22:45:20Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   21 ++++++++++++---------\n 1 file changed, 12 insertions(+), 9 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 044dee9..c40cbd6 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -327,14 +327,17 @@ static struct ref_dir *find_containing_dir(struct ref_dir *dir,\n }\n \n /*\n- * Find the value entry with the given name in dir, sorting ref_dirs\n- * and recursing into subdirectories as necessary.  If the name is not\n- * found or it corresponds to a directory entry, return NULL.\n+ * Find the value entry with the given name in direntry, sorting\n+ * reference directories and recursing into subdirectories as\n+ * necessary.  If the name is not found or it corresponds to a\n+ * directory entry, return NULL.\n  */\n-static struct ref_entry *find_ref(struct ref_dir *dir, const char *refname)\n+static struct ref_entry *find_ref(struct ref_entry *direntry, const char *refname)\n {\n \tstruct ref_entry *entry;\n-\tdir = find_containing_dir(dir, refname, 0);\n+\tstruct ref_dir *dir;\n+\tassert(direntry->flag & REF_DIR);\n+\tdir = find_containing_dir(&direntry->u.subdir, refname, 0);\n \tif (!dir)\n \t\treturn NULL;\n \tentry = search_ref_dir(dir, refname);\n@@ -858,7 +861,7 @@ static int resolve_gitlink_packed_ref(struct ref_cache *refs,\n \tstruct ref_entry *ref;\n \tstruct ref_entry *direntry = get_packed_refs(refs);\n \n-\tref = find_ref(&direntry->u.subdir, refname);\n+\tref = find_ref(direntry, refname);\n \tif (ref == NULL)\n \t\treturn -1;\n \n@@ -930,7 +933,7 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh\n static int get_packed_ref(const char *refname, unsigned char *sha1)\n {\n \tstruct ref_entry *packed = get_packed_refs(get_ref_cache(NULL));\n-\tstruct ref_entry *entry = find_ref(&packed->u.subdir, refname);\n+\tstruct ref_entry *entry = find_ref(packed, refname);\n \tif (entry) {\n \t\thashcpy(sha1, entry->u.value.sha1);\n \t\treturn 0;\n@@ -1107,7 +1110,7 @@ int peel_ref(const char *refname, unsigned char *sha1)\n \n \tif ((flag & REF_ISPACKED)) {\n \t\tstruct ref_entry *direntry = get_packed_refs(get_ref_cache(NULL));\n-\t\tstruct ref_entry *r = find_ref(&direntry->u.subdir, refname);\n+\t\tstruct ref_entry *r = find_ref(direntry, refname);\n \n \t\tif (r != NULL && r->flag & REF_KNOWS_PEELED) {\n \t\t\thashcpy(sha1, r->u.value.peeled);\n@@ -1631,7 +1634,7 @@ static int repack_without_ref(const char *refname)\n {\n \tstruct repack_without_ref_sb data;\n \tstruct ref_entry *packed = get_packed_refs(get_ref_cache(NULL));\n-\tif (find_ref(&packed->u.subdir, refname) == NULL)\n+\tif (find_ref(packed, refname) == NULL)\n \t\treturn 0;\n \tdata.refname = refname;\n \tdata.fd = hold_lock_file_for_update(&packlock, git_path(\"packed-refs\"), 0);\n-- \n1.7.10\n"},{"id":"190010","messageId":"1335307536-26914-16-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 15/30] read_packed_refs(): take (ref_entry *) instead of (ref_dir *)","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:21Z","receivedAt":"2012-04-24T22:45:21Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |    7 ++++---\n 1 file changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex c40cbd6..694d802 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -708,12 +708,13 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)\n \treturn line;\n }\n \n-static void read_packed_refs(FILE *f, struct ref_dir *dir)\n+static void read_packed_refs(FILE *f, struct ref_entry *direntry)\n {\n \tstruct ref_entry *last = NULL;\n \tchar refline[PATH_MAX];\n \tint flag = REF_ISPACKED;\n \n+\tassert(direntry->flag & REF_DIR);\n \twhile (fgets(refline, sizeof(refline), f)) {\n \t\tunsigned char sha1[20];\n \t\tconst char *refname;\n@@ -730,7 +731,7 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)\n \t\trefname = parse_ref_line(refline, sha1);\n \t\tif (refname) {\n \t\t\tlast = create_ref_entry(refname, sha1, flag, 1);\n-\t\t\tadd_ref(dir, last);\n+\t\t\tadd_ref(&direntry->u.subdir, last);\n \t\t\tcontinue;\n \t\t}\n \t\tif (last &&\n@@ -755,7 +756,7 @@ static struct ref_entry *get_packed_refs(struct ref_cache *refs)\n \t\t\tpacked_refs_file = git_path(\"packed-refs\");\n \t\tf = fopen(packed_refs_file, \"r\");\n \t\tif (f) {\n-\t\t\tread_packed_refs(f, &refs->packed->u.subdir);\n+\t\t\tread_packed_refs(f, refs->packed);\n \t\t\tfclose(f);\n \t\t}\n \t}\n-- \n1.7.10\n"},{"id":"190011","messageId":"1335307536-26914-17-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 16/30] add_ref(): take (ref_entry *) instead of (ref_dir *)","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:22Z","receivedAt":"2012-04-24T22:45:22Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   16 +++++++++-------\n 1 file changed, 9 insertions(+), 7 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 694d802..6077cfb 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -345,13 +345,15 @@ static struct ref_entry *find_ref(struct ref_entry *direntry, const char *refnam\n }\n \n /*\n- * Add a ref_entry to the ref_dir (unsorted), recursing into\n- * subdirectories as necessary.  dir must represent the top-level\n- * directory.  Return 0 on success.\n+ * Add ref to the direntry (unsorted), recursing into subdirectories\n+ * as necessary.  direntry must represent the top-level directory.\n+ * Return 0 on success.\n  */\n-static int add_ref(struct ref_dir *dir, struct ref_entry *ref)\n+static int add_ref(struct ref_entry *direntry, struct ref_entry *ref)\n {\n-\tdir = find_containing_dir(dir, ref->name, 1);\n+\tstruct ref_dir *dir;\n+\tassert(direntry->flag & REF_DIR);\n+\tdir = find_containing_dir(&direntry->u.subdir, ref->name, 1);\n \tif (!dir)\n \t\treturn -1;\n \tadd_entry_to_dir(dir, ref);\n@@ -731,7 +733,7 @@ static void read_packed_refs(FILE *f, struct ref_entry *direntry)\n \t\trefname = parse_ref_line(refline, sha1);\n \t\tif (refname) {\n \t\t\tlast = create_ref_entry(refname, sha1, flag, 1);\n-\t\t\tadd_ref(&direntry->u.subdir, last);\n+\t\t\tadd_ref(direntry, last);\n \t\t\tcontinue;\n \t\t}\n \t\tif (last &&\n@@ -765,7 +767,7 @@ static struct ref_entry *get_packed_refs(struct ref_cache *refs)\n \n void add_packed_ref(const char *refname, const unsigned char *sha1)\n {\n-\tadd_ref(&get_packed_refs(get_ref_cache(NULL))->u.subdir,\n+\tadd_ref(get_packed_refs(get_ref_cache(NULL)),\n \t\tcreate_ref_entry(refname, sha1, REF_ISPACKED, 1));\n }\n \n-- \n1.7.10\n"},{"id":"190027","messageId":"1335307536-26914-18-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 17/30] find_containing_direntry(): use (ref_entry *) instead of (ref_dir *)","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:23Z","receivedAt":"2012-04-24T22:45:23Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nChange type of both argument and return value, and rename function\nfrom find_containing_dir() to find_containing_direntry().\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   67 ++++++++++++++++++++++++++++++----------------------------------\n 1 file changed, 31 insertions(+), 36 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 6077cfb..140fbe2 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -298,32 +298,30 @@ static struct ref_entry *search_for_subdir(struct ref_dir *dir,\n }\n \n /*\n- * If refname is a reference name, find the ref_dir within the dir\n- * tree that should hold refname.  If refname is a directory name\n- * (i.e., ends in '/'), then return that ref_dir itself.  dir must\n- * represent the top-level directory.  Sort ref_dirs and recurse into\n- * subdirectories as necessary.  If mkdir is set, then create any\n- * missing directories; otherwise, return NULL if the desired\n- * directory cannot be found.\n+ * If refname is a reference name, find the directory entry within the\n+ * direntry tree that should hold refname.  If refname is a directory\n+ * name (i.e., ends in '/'), then return that directory entry itself.\n+ * direntry must represent the top-level directory.  Sort directories\n+ * and recurse into subdirectories as necessary.  If mkdir is set,\n+ * then create any missing directories; otherwise, return NULL if the\n+ * desired directory cannot be found.\n  */\n-static struct ref_dir *find_containing_dir(struct ref_dir *dir,\n-\t\t\t\t\t   const char *refname, int mkdir)\n+static struct ref_entry *find_containing_direntry(struct ref_entry *direntry,\n+\t\t\t\t\t\t  const char *refname, int mkdir)\n {\n \tchar *refname_copy = xstrdup(refname);\n \tchar *slash;\n-\tstruct ref_entry *entry;\n \tfor (slash = strchr(refname_copy, '/'); slash; slash = strchr(slash + 1, '/')) {\n \t\tchar tmp = slash[1];\n \t\tslash[1] = '\\0';\n-\t\tentry = search_for_subdir(dir, refname_copy, mkdir);\n+\t\tdirentry = search_for_subdir(&direntry->u.subdir, refname_copy, mkdir);\n \t\tslash[1] = tmp;\n-\t\tif (!entry)\n+\t\tif (!direntry)\n \t\t\tbreak;\n-\t\tdir = &entry->u.subdir;\n \t}\n \n \tfree(refname_copy);\n-\treturn dir;\n+\treturn direntry;\n }\n \n /*\n@@ -335,12 +333,11 @@ static struct ref_dir *find_containing_dir(struct ref_dir *dir,\n static struct ref_entry *find_ref(struct ref_entry *direntry, const char *refname)\n {\n \tstruct ref_entry *entry;\n-\tstruct ref_dir *dir;\n \tassert(direntry->flag & REF_DIR);\n-\tdir = find_containing_dir(&direntry->u.subdir, refname, 0);\n-\tif (!dir)\n+\tdirentry = find_containing_direntry(direntry, refname, 0);\n+\tif (!direntry)\n \t\treturn NULL;\n-\tentry = search_ref_dir(dir, refname);\n+\tentry = search_ref_dir(&direntry->u.subdir, refname);\n \treturn (entry && !(entry->flag & REF_DIR)) ? entry : NULL;\n }\n \n@@ -351,12 +348,11 @@ static struct ref_entry *find_ref(struct ref_entry *direntry, const char *refnam\n  */\n static int add_ref(struct ref_entry *direntry, struct ref_entry *ref)\n {\n-\tstruct ref_dir *dir;\n \tassert(direntry->flag & REF_DIR);\n-\tdir = find_containing_dir(&direntry->u.subdir, ref->name, 1);\n-\tif (!dir)\n+\tdirentry = find_containing_direntry(direntry, ref->name, 1);\n+\tif (!direntry)\n \t\treturn -1;\n-\tadd_entry_to_dir(dir, ref);\n+\tadd_entry_to_dir(&direntry->u.subdir, ref);\n \treturn 0;\n }\n \n@@ -1172,31 +1168,30 @@ static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn\n {\n \tstruct ref_cache *refs = get_ref_cache(submodule);\n \tstruct ref_entry *packed_direntry = get_packed_refs(refs);\n-\tstruct ref_dir *packed_dir = &packed_direntry->u.subdir;\n \tstruct ref_entry *loose_direntry = get_loose_refs(refs);\n-\tstruct ref_dir *loose_dir = &loose_direntry->u.subdir;\n \tint retval = 0;\n \n \tif (base && *base) {\n-\t\tpacked_dir = find_containing_dir(packed_dir, base, 0);\n-\t\tloose_dir = find_containing_dir(loose_dir, base, 0);\n+\t\tpacked_direntry = find_containing_direntry(packed_direntry, base, 0);\n+\t\tloose_direntry = find_containing_direntry(loose_direntry, base, 0);\n \t}\n \n-\tif (packed_dir && loose_dir) {\n-\t\tsort_ref_dir(packed_dir);\n-\t\tsort_ref_dir(loose_dir);\n+\tif (packed_direntry && loose_direntry) {\n+\t\tsort_ref_dir(&packed_direntry->u.subdir);\n+\t\tsort_ref_dir(&loose_direntry->u.subdir);\n \t\tretval = do_for_each_ref_in_dirs(\n-\t\t\t\tpacked_dir, loose_dir,\n+\t\t\t\t&packed_direntry->u.subdir,\n+\t\t\t\t&loose_direntry->u.subdir,\n \t\t\t\tbase, fn, trim, flags, cb_data);\n-\t} else if (packed_dir) {\n-\t\tsort_ref_dir(packed_dir);\n+\t} else if (packed_direntry) {\n+\t\tsort_ref_dir(&packed_direntry->u.subdir);\n \t\tretval = do_for_each_ref_in_dir(\n-\t\t\t\tpacked_dir, 0,\n+\t\t\t\t&packed_direntry->u.subdir, 0,\n \t\t\t\tbase, fn, trim, flags, cb_data);\n-\t} else if (loose_dir) {\n-\t\tsort_ref_dir(loose_dir);\n+\t} else if (loose_direntry) {\n+\t\tsort_ref_dir(&loose_direntry->u.subdir);\n \t\tretval = do_for_each_ref_in_dir(\n-\t\t\t\tloose_dir, 0,\n+\t\t\t\t&loose_direntry->u.subdir, 0,\n \t\t\t\tbase, fn, trim, flags, cb_data);\n \t}\n \n-- \n1.7.10\n"},{"id":"190007","messageId":"1335307536-26914-19-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 18/30] get_ref_dir(): take (ref_entry *) instead of (ref_dir *)","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:24Z","receivedAt":"2012-04-24T22:45:24Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   15 +++++++++------\n 1 file changed, 9 insertions(+), 6 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 140fbe2..2057380 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -769,11 +769,11 @@ void add_packed_ref(const char *refname, const unsigned char *sha1)\n \n /*\n  * Read the loose references for refs from the namespace dirname.\n- * dirname must end with '/'.  dir must be the directory entry\n+ * dirname must end with '/'.  direntry must be the directory entry\n  * corresponding to dirname.\n  */\n static void get_ref_dir(struct ref_cache *refs, const char *dirname,\n-\t\t\tstruct ref_dir *dir)\n+\t\t\tstruct ref_entry *direntry)\n {\n \tDIR *d;\n \tconst char *path;\n@@ -781,6 +781,8 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname,\n \tint dirnamelen = strlen(dirname);\n \tstruct strbuf refname;\n \n+\tassert(direntry->flag & REF_DIR);\n+\n \tif (*refs->name)\n \t\tpath = git_path_submodule(refs->name, \"%s\", dirname);\n \telse\n@@ -812,7 +814,8 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname,\n \t\t} else if (S_ISDIR(st.st_mode)) {\n \t\t\tstrbuf_addch(&refname, '/');\n \t\t\tget_ref_dir(refs, refname.buf,\n-\t\t\t\t    &search_for_subdir(dir, refname.buf, 1)->u.subdir);\n+\t\t\t\t    search_for_subdir(&direntry->u.subdir,\n+\t\t\t\t\t\t      refname.buf, 1));\n \t\t} else {\n \t\t\tif (*refs->name) {\n \t\t\t\thashclr(sha1);\n@@ -825,7 +828,7 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname,\n \t\t\t\thashclr(sha1);\n \t\t\t\tflag |= REF_ISBROKEN;\n \t\t\t}\n-\t\t\tadd_entry_to_dir(dir,\n+\t\t\tadd_entry_to_dir(&direntry->u.subdir,\n \t\t\t\t\t create_ref_entry(refname.buf, sha1, flag, 1));\n \t\t}\n \t\tstrbuf_setlen(&refname, dirnamelen);\n@@ -839,8 +842,8 @@ static struct ref_entry *get_loose_refs(struct ref_cache *refs)\n \tif (!refs->loose) {\n \t\trefs->loose = create_dir_entry(\"\");\n \t\tget_ref_dir(refs, \"refs/\",\n-\t\t\t    &search_for_subdir(&refs->loose->u.subdir,\n-\t\t\t\t\t       \"refs/\", 1)->u.subdir);\n+\t\t\t    search_for_subdir(&refs->loose->u.subdir,\n+\t\t\t\t\t      \"refs/\", 1));\n \t}\n \treturn refs->loose;\n }\n-- \n1.7.10\n"},{"id":"190020","messageId":"1335307536-26914-20-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 19/30] get_ref_dir(): remove dirname argument","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:25Z","receivedAt":"2012-04-24T22:45:25Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nThe dirname can be determined from the direntry argument.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   12 +++++-------\n 1 file changed, 5 insertions(+), 7 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 2057380..bc4a69b 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -768,16 +768,14 @@ void add_packed_ref(const char *refname, const unsigned char *sha1)\n }\n \n /*\n- * Read the loose references for refs from the namespace dirname.\n- * dirname must end with '/'.  direntry must be the directory entry\n- * corresponding to dirname.\n+ * Read the loose references for direntry in refs.\n  */\n-static void get_ref_dir(struct ref_cache *refs, const char *dirname,\n-\t\t\tstruct ref_entry *direntry)\n+static void get_ref_dir(struct ref_cache *refs, struct ref_entry *direntry)\n {\n \tDIR *d;\n \tconst char *path;\n \tstruct dirent *de;\n+\tconst char *dirname = direntry->name;\n \tint dirnamelen = strlen(dirname);\n \tstruct strbuf refname;\n \n@@ -813,7 +811,7 @@ static void get_ref_dir(struct ref_cache *refs, const char *dirname,\n \t\t\t/* Silently ignore. */\n \t\t} else if (S_ISDIR(st.st_mode)) {\n \t\t\tstrbuf_addch(&refname, '/');\n-\t\t\tget_ref_dir(refs, refname.buf,\n+\t\t\tget_ref_dir(refs,\n \t\t\t\t    search_for_subdir(&direntry->u.subdir,\n \t\t\t\t\t\t      refname.buf, 1));\n \t\t} else {\n@@ -841,7 +839,7 @@ static struct ref_entry *get_loose_refs(struct ref_cache *refs)\n {\n \tif (!refs->loose) {\n \t\trefs->loose = create_dir_entry(\"\");\n-\t\tget_ref_dir(refs, \"refs/\",\n+\t\tget_ref_dir(refs,\n \t\t\t    search_for_subdir(&refs->loose->u.subdir,\n \t\t\t\t\t      \"refs/\", 1));\n \t}\n-- \n1.7.10\n"},{"id":"190008","messageId":"1335307536-26914-21-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 20/30] search_for_subdir(): take (ref_entry *) instead of (ref_dir *)","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:26Z","receivedAt":"2012-04-24T22:45:26Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   24 ++++++++++++------------\n 1 file changed, 12 insertions(+), 12 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex bc4a69b..4bea486 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -277,21 +277,22 @@ static struct ref_entry *search_ref_dir(struct ref_dir *dir, const char *refname\n }\n \n /*\n- * Search for a directory entry directly within dir (without\n- * recursing).  Sort dir if necessary.  subdirname must be a directory\n- * name (i.e., end in '/').  If mkdir is set, then create the\n- * directory if it is missing; otherwise, return NULL if the desired\n- * directory cannot be found.\n+ * Search for a directory entry directly within direntry (without\n+ * recursing).  Sort direntry if necessary.  subdirname must be a\n+ * directory name (i.e., end in '/').  If mkdir is set, then create\n+ * the directory if it is missing; otherwise, return NULL if the\n+ * desired directory cannot be found.\n  */\n-static struct ref_entry *search_for_subdir(struct ref_dir *dir,\n+static struct ref_entry *search_for_subdir(struct ref_entry *direntry,\n \t\t\t\t\t   const char *subdirname, int mkdir)\n {\n-\tstruct ref_entry *entry = search_ref_dir(dir, subdirname);\n+\tstruct ref_entry *entry = search_ref_dir(&direntry->u.subdir,\n+\t\t\t\t\t\t subdirname);\n \tif (!entry) {\n \t\tif (!mkdir)\n \t\t\treturn NULL;\n \t\tentry = create_dir_entry(subdirname);\n-\t\tadd_entry_to_dir(dir, entry);\n+\t\tadd_entry_to_dir(&direntry->u.subdir, entry);\n \t}\n \tassert(entry->flag & REF_DIR);\n \treturn entry;\n@@ -314,7 +315,7 @@ static struct ref_entry *find_containing_direntry(struct ref_entry *direntry,\n \tfor (slash = strchr(refname_copy, '/'); slash; slash = strchr(slash + 1, '/')) {\n \t\tchar tmp = slash[1];\n \t\tslash[1] = '\\0';\n-\t\tdirentry = search_for_subdir(&direntry->u.subdir, refname_copy, mkdir);\n+\t\tdirentry = search_for_subdir(direntry, refname_copy, mkdir);\n \t\tslash[1] = tmp;\n \t\tif (!direntry)\n \t\t\tbreak;\n@@ -812,7 +813,7 @@ static void get_ref_dir(struct ref_cache *refs, struct ref_entry *direntry)\n \t\t} else if (S_ISDIR(st.st_mode)) {\n \t\t\tstrbuf_addch(&refname, '/');\n \t\t\tget_ref_dir(refs,\n-\t\t\t\t    search_for_subdir(&direntry->u.subdir,\n+\t\t\t\t    search_for_subdir(direntry,\n \t\t\t\t\t\t      refname.buf, 1));\n \t\t} else {\n \t\t\tif (*refs->name) {\n@@ -840,8 +841,7 @@ static struct ref_entry *get_loose_refs(struct ref_cache *refs)\n \tif (!refs->loose) {\n \t\trefs->loose = create_dir_entry(\"\");\n \t\tget_ref_dir(refs,\n-\t\t\t    search_for_subdir(&refs->loose->u.subdir,\n-\t\t\t\t\t      \"refs/\", 1));\n+\t\t\t    search_for_subdir(refs->loose, \"refs/\", 1));\n \t}\n \treturn refs->loose;\n }\n-- \n1.7.10\n"},{"id":"190026","messageId":"1335307536-26914-22-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 21/30] search_ref_dir(): take (ref_entry *) instead of (ref_dir *)","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:27Z","receivedAt":"2012-04-24T22:45:27Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   17 ++++++++++-------\n 1 file changed, 10 insertions(+), 7 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 4bea486..07856fb 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -248,15 +248,19 @@ static int ref_entry_cmp(const void *a, const void *b)\n static void sort_ref_dir(struct ref_dir *dir);\n \n /*\n- * Return the entry with the given refname from the ref_dir\n- * (non-recursively), sorting dir if necessary.  Return NULL if no\n- * such entry is found.\n+ * Return the entry with the given refname from direntry\n+ * (non-recursively), sorting direntry if necessary.  Return NULL if\n+ * no such entry is found.\n  */\n-static struct ref_entry *search_ref_dir(struct ref_dir *dir, const char *refname)\n+static struct ref_entry *search_ref_dir(struct ref_entry *direntry,\n+\t\t\t\t\tconst char *refname)\n {\n \tstruct ref_entry *e, **r;\n \tint len;\n+\tstruct ref_dir *dir;\n \n+\tassert(direntry->flag & REF_DIR);\n+\tdir = &direntry->u.subdir;\n \tif (refname == NULL || !dir->nr)\n \t\treturn NULL;\n \n@@ -286,8 +290,7 @@ static struct ref_entry *search_ref_dir(struct ref_dir *dir, const char *refname\n static struct ref_entry *search_for_subdir(struct ref_entry *direntry,\n \t\t\t\t\t   const char *subdirname, int mkdir)\n {\n-\tstruct ref_entry *entry = search_ref_dir(&direntry->u.subdir,\n-\t\t\t\t\t\t subdirname);\n+\tstruct ref_entry *entry = search_ref_dir(direntry, subdirname);\n \tif (!entry) {\n \t\tif (!mkdir)\n \t\t\treturn NULL;\n@@ -338,7 +341,7 @@ static struct ref_entry *find_ref(struct ref_entry *direntry, const char *refnam\n \tdirentry = find_containing_direntry(direntry, refname, 0);\n \tif (!direntry)\n \t\treturn NULL;\n-\tentry = search_ref_dir(&direntry->u.subdir, refname);\n+\tentry = search_ref_dir(direntry, refname);\n \treturn (entry && !(entry->flag & REF_DIR)) ? entry : NULL;\n }\n \n-- \n1.7.10\n"},{"id":"190017","messageId":"1335307536-26914-23-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 22/30] add_entry(): take (ref_entry *) instead of (ref_dir *)","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:28Z","receivedAt":"2012-04-24T22:45:28Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nAnd rename function add_entry_to_dir() -> add_entry().\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   18 ++++++++++--------\n 1 file changed, 10 insertions(+), 8 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 07856fb..a794d3a 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -200,12 +200,14 @@ static void free_ref_entry(struct ref_entry *entry)\n }\n \n /*\n- * Add a ref_entry to the end of dir (unsorted).  Entry is always\n- * stored directly in dir; no recursion into subdirectories is\n- * done.\n+ * Add entry to the end of direntry, unsorted.  entry is always stored\n+ * directly in direntry; no recursion into subdirectories is done.\n  */\n-static void add_entry_to_dir(struct ref_dir *dir, struct ref_entry *entry)\n+static void add_entry(struct ref_entry *direntry, struct ref_entry *entry)\n {\n+\tstruct ref_dir *dir;\n+\tassert(direntry->flag & REF_DIR);\n+\tdir = &direntry->u.subdir;\n \tALLOC_GROW(dir->entries, dir->nr + 1, dir->alloc);\n \tdir->entries[dir->nr++] = entry;\n }\n@@ -295,7 +297,7 @@ static struct ref_entry *search_for_subdir(struct ref_entry *direntry,\n \t\tif (!mkdir)\n \t\t\treturn NULL;\n \t\tentry = create_dir_entry(subdirname);\n-\t\tadd_entry_to_dir(&direntry->u.subdir, entry);\n+\t\tadd_entry(direntry, entry);\n \t}\n \tassert(entry->flag & REF_DIR);\n \treturn entry;\n@@ -356,7 +358,7 @@ static int add_ref(struct ref_entry *direntry, struct ref_entry *ref)\n \tdirentry = find_containing_direntry(direntry, ref->name, 1);\n \tif (!direntry)\n \t\treturn -1;\n-\tadd_entry_to_dir(&direntry->u.subdir, ref);\n+\tadd_entry(direntry, ref);\n \treturn 0;\n }\n \n@@ -830,8 +832,8 @@ static void get_ref_dir(struct ref_cache *refs, struct ref_entry *direntry)\n \t\t\t\thashclr(sha1);\n \t\t\t\tflag |= REF_ISBROKEN;\n \t\t\t}\n-\t\t\tadd_entry_to_dir(&direntry->u.subdir,\n-\t\t\t\t\t create_ref_entry(refname.buf, sha1, flag, 1));\n+\t\t\tadd_entry(direntry,\n+\t\t\t\t  create_ref_entry(refname.buf, sha1, flag, 1));\n \t\t}\n \t\tstrbuf_setlen(&refname, dirnamelen);\n \t}\n-- \n1.7.10\n"},{"id":"190022","messageId":"1335307536-26914-24-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 23/30] do_for_each_ref_in_dirs(): take (ref_entry *) instead of (ref_dir *)","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:29Z","receivedAt":"2012-04-24T22:45:29Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   48 +++++++++++++++++++++++++-----------------------\n 1 file changed, 25 insertions(+), 23 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex a794d3a..4448b14 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -468,35 +468,38 @@ static int do_for_each_ref_in_dir(struct ref_dir *dir, int offset,\n }\n \n /*\n- * Call fn for each reference in the union of dir1 and dir2, in order\n- * by refname.  Recurse into subdirectories.  If a value entry appears\n- * in both dir1 and dir2, then only process the version that is in\n- * dir2.  The input dirs must already be sorted, but subdirs will be\n- * sorted as needed.\n+ * Call fn for each reference in the union of direntry1 and direntry2,\n+ * in order by refname.  Recurse into subdirectories.  If a value\n+ * entry appears in both direntry1 and direntry2, then only process\n+ * the version that is in direntry2.  The input direntries must\n+ * already be sorted, but subdirs will be sorted as needed.\n  */\n-static int do_for_each_ref_in_dirs(struct ref_dir *dir1,\n-\t\t\t\t   struct ref_dir *dir2,\n+static int do_for_each_ref_in_dirs(struct ref_entry *direntry1,\n+\t\t\t\t   struct ref_entry *direntry2,\n \t\t\t\t   const char *base, each_ref_fn fn, int trim,\n \t\t\t\t   int flags, void *cb_data)\n {\n \tint retval;\n \tint i1 = 0, i2 = 0;\n \n-\tassert(dir1->sorted == dir1->nr);\n-\tassert(dir2->sorted == dir2->nr);\n+\tassert(direntry1->flag & REF_DIR);\n+\tassert(direntry2->flag & REF_DIR);\n+\tassert(direntry1->u.subdir.sorted == direntry1->u.subdir.nr);\n+\tassert(direntry2->u.subdir.sorted == direntry2->u.subdir.nr);\n+\n \twhile (1) {\n \t\tstruct ref_entry *e1, *e2;\n \t\tint cmp;\n-\t\tif (i1 == dir1->nr) {\n-\t\t\treturn do_for_each_ref_in_dir(dir2, i2,\n+\t\tif (i1 == direntry1->u.subdir.nr) {\n+\t\t\treturn do_for_each_ref_in_dir(&direntry2->u.subdir, i2,\n \t\t\t\t\t\t      base, fn, trim, flags, cb_data);\n \t\t}\n-\t\tif (i2 == dir2->nr) {\n-\t\t\treturn do_for_each_ref_in_dir(dir1, i1,\n+\t\tif (i2 == direntry2->u.subdir.nr) {\n+\t\t\treturn do_for_each_ref_in_dir(&direntry1->u.subdir, i1,\n \t\t\t\t\t\t      base, fn, trim, flags, cb_data);\n \t\t}\n-\t\te1 = dir1->entries[i1];\n-\t\te2 = dir2->entries[i2];\n+\t\te1 = direntry1->u.subdir.entries[i1];\n+\t\te2 = direntry2->u.subdir.entries[i2];\n \t\tcmp = strcmp(e1->name, e2->name);\n \t\tif (cmp == 0) {\n \t\t\tif ((e1->flag & REF_DIR) && (e2->flag & REF_DIR)) {\n@@ -504,12 +507,12 @@ static int do_for_each_ref_in_dirs(struct ref_dir *dir1,\n \t\t\t\tsort_ref_dir(&e1->u.subdir);\n \t\t\t\tsort_ref_dir(&e2->u.subdir);\n \t\t\t\tretval = do_for_each_ref_in_dirs(\n-\t\t\t\t\t\t&e1->u.subdir, &e2->u.subdir,\n+\t\t\t\t\t\te1, e2,\n \t\t\t\t\t\tbase, fn, trim, flags, cb_data);\n \t\t\t\ti1++;\n \t\t\t\ti2++;\n \t\t\t} else if (!(e1->flag & REF_DIR) && !(e2->flag & REF_DIR)) {\n-\t\t\t\t/* Both are references; ignore the one from dir1. */\n+\t\t\t\t/* Both are references; ignore the one from direntry1. */\n \t\t\t\tretval = do_one_ref(base, fn, trim, flags, cb_data, e2);\n \t\t\t\ti1++;\n \t\t\t\ti2++;\n@@ -538,11 +541,11 @@ static int do_for_each_ref_in_dirs(struct ref_dir *dir1,\n \t\tif (retval)\n \t\t\treturn retval;\n \t}\n-\tif (i1 < dir1->nr)\n-\t\treturn do_for_each_ref_in_dir(dir1, i1,\n+\tif (i1 < direntry1->u.subdir.nr)\n+\t\treturn do_for_each_ref_in_dir(&direntry1->u.subdir, i1,\n \t\t\t\t\t      base, fn, trim, flags, cb_data);\n-\tif (i2 < dir2->nr)\n-\t\treturn do_for_each_ref_in_dir(dir2, i2,\n+\tif (i2 < direntry2->u.subdir.nr)\n+\t\treturn do_for_each_ref_in_dir(&direntry2->u.subdir, i2,\n \t\t\t\t\t      base, fn, trim, flags, cb_data);\n \treturn 0;\n }\n@@ -1186,8 +1189,7 @@ static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn\n \t\tsort_ref_dir(&packed_direntry->u.subdir);\n \t\tsort_ref_dir(&loose_direntry->u.subdir);\n \t\tretval = do_for_each_ref_in_dirs(\n-\t\t\t\t&packed_direntry->u.subdir,\n-\t\t\t\t&loose_direntry->u.subdir,\n+\t\t\t\tpacked_direntry, loose_direntry,\n \t\t\t\tbase, fn, trim, flags, cb_data);\n \t} else if (packed_direntry) {\n \t\tsort_ref_dir(&packed_direntry->u.subdir);\n-- \n1.7.10\n"},{"id":"190025","messageId":"1335307536-26914-25-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 24/30] do_for_each_ref_in_dir(): take (ref_entry *) instead of (ref_dir *)","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:30Z","receivedAt":"2012-04-24T22:45:30Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   33 +++++++++++++++++----------------\n 1 file changed, 17 insertions(+), 16 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 4448b14..722545f 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -440,23 +440,24 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim,\n }\n \n /*\n- * Call fn for each reference in dir that has index in the range\n+ * Call fn for each reference in direntry that has index in the range\n  * offset <= index < dir->nr.  Recurse into subdirectories that are in\n  * that index range, sorting them before iterating.  This function\n- * does not sort dir itself; it should be sorted beforehand.\n+ * does not sort direntry itself; it should be sorted beforehand.\n  */\n-static int do_for_each_ref_in_dir(struct ref_dir *dir, int offset,\n+static int do_for_each_ref_in_dir(struct ref_entry *direntry, int offset,\n \t\t\t\t  const char *base,\n \t\t\t\t  each_ref_fn fn, int trim, int flags, void *cb_data)\n {\n \tint i;\n-\tassert(dir->sorted == dir->nr);\n-\tfor (i = offset; i < dir->nr; i++) {\n-\t\tstruct ref_entry *entry = dir->entries[i];\n+\tassert(direntry->flag & REF_DIR);\n+\tassert(direntry->u.subdir.sorted == direntry->u.subdir.nr);\n+\tfor (i = offset; i < direntry->u.subdir.nr; i++) {\n+\t\tstruct ref_entry *entry = direntry->u.subdir.entries[i];\n \t\tint retval;\n \t\tif (entry->flag & REF_DIR) {\n \t\t\tsort_ref_dir(&entry->u.subdir);\n-\t\t\tretval = do_for_each_ref_in_dir(&entry->u.subdir, 0,\n+\t\t\tretval = do_for_each_ref_in_dir(entry, 0,\n \t\t\t\t\t\t\tbase, fn, trim, flags, cb_data);\n \t\t} else {\n \t\t\tretval = do_one_ref(base, fn, trim, flags, cb_data, entry);\n@@ -491,11 +492,11 @@ static int do_for_each_ref_in_dirs(struct ref_entry *direntry1,\n \t\tstruct ref_entry *e1, *e2;\n \t\tint cmp;\n \t\tif (i1 == direntry1->u.subdir.nr) {\n-\t\t\treturn do_for_each_ref_in_dir(&direntry2->u.subdir, i2,\n+\t\t\treturn do_for_each_ref_in_dir(direntry2, i2,\n \t\t\t\t\t\t      base, fn, trim, flags, cb_data);\n \t\t}\n \t\tif (i2 == direntry2->u.subdir.nr) {\n-\t\t\treturn do_for_each_ref_in_dir(&direntry1->u.subdir, i1,\n+\t\t\treturn do_for_each_ref_in_dir(direntry1, i1,\n \t\t\t\t\t\t      base, fn, trim, flags, cb_data);\n \t\t}\n \t\te1 = direntry1->u.subdir.entries[i1];\n@@ -532,7 +533,7 @@ static int do_for_each_ref_in_dirs(struct ref_entry *direntry1,\n \t\t\tif (e->flag & REF_DIR) {\n \t\t\t\tsort_ref_dir(&e->u.subdir);\n \t\t\t\tretval = do_for_each_ref_in_dir(\n-\t\t\t\t\t\t&e->u.subdir, 0,\n+\t\t\t\t\t\te, 0,\n \t\t\t\t\t\tbase, fn, trim, flags, cb_data);\n \t\t\t} else {\n \t\t\t\tretval = do_one_ref(base, fn, trim, flags, cb_data, e);\n@@ -542,10 +543,10 @@ static int do_for_each_ref_in_dirs(struct ref_entry *direntry1,\n \t\t\treturn retval;\n \t}\n \tif (i1 < direntry1->u.subdir.nr)\n-\t\treturn do_for_each_ref_in_dir(&direntry1->u.subdir, i1,\n+\t\treturn do_for_each_ref_in_dir(direntry1, i1,\n \t\t\t\t\t      base, fn, trim, flags, cb_data);\n \tif (i2 < direntry2->u.subdir.nr)\n-\t\treturn do_for_each_ref_in_dir(&direntry2->u.subdir, i2,\n+\t\treturn do_for_each_ref_in_dir(direntry2, i2,\n \t\t\t\t\t      base, fn, trim, flags, cb_data);\n \treturn 0;\n }\n@@ -602,7 +603,7 @@ static int is_refname_available(const char *refname, const char *oldrefname,\n \tassert(direntry->flag & REF_DIR);\n \tsort_ref_dir(&direntry->u.subdir);\n \n-\tif (do_for_each_ref_in_dir(&direntry->u.subdir, 0, \"\", name_conflict_fn,\n+\tif (do_for_each_ref_in_dir(direntry, 0, \"\", name_conflict_fn,\n \t\t\t\t   0, DO_FOR_EACH_INCLUDE_BROKEN,\n \t\t\t\t   &data)) {\n \t\terror(\"'%s' exists; cannot create '%s'\",\n@@ -1194,12 +1195,12 @@ static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn\n \t} else if (packed_direntry) {\n \t\tsort_ref_dir(&packed_direntry->u.subdir);\n \t\tretval = do_for_each_ref_in_dir(\n-\t\t\t\t&packed_direntry->u.subdir, 0,\n+\t\t\t\tpacked_direntry, 0,\n \t\t\t\tbase, fn, trim, flags, cb_data);\n \t} else if (loose_direntry) {\n \t\tsort_ref_dir(&loose_direntry->u.subdir);\n \t\tretval = do_for_each_ref_in_dir(\n-\t\t\t\t&loose_direntry->u.subdir, 0,\n+\t\t\t\tloose_direntry, 0,\n \t\t\t\tbase, fn, trim, flags, cb_data);\n \t}\n \n@@ -1648,7 +1649,7 @@ static int repack_without_ref(const char *refname)\n \t\tunable_to_lock_error(git_path(\"packed-refs\"), errno);\n \t\treturn error(\"cannot delete '%s' from packed refs\", refname);\n \t}\n-\tdo_for_each_ref_in_dir(&packed->u.subdir, 0,\n+\tdo_for_each_ref_in_dir(packed, 0,\n \t\t\t       \"\", repack_without_ref_fn, 0, 0, &data);\n \treturn commit_lock_file(&packlock);\n }\n-- \n1.7.10\n"},{"id":"190029","messageId":"1335307536-26914-26-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 25/30] sort_ref_dir(): take (ref_entry *) instead of (ref_dir *)","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:31Z","receivedAt":"2012-04-24T22:45:31Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   31 +++++++++++++++++--------------\n 1 file changed, 17 insertions(+), 14 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 722545f..90bdd7c 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -247,7 +247,7 @@ static int ref_entry_cmp(const void *a, const void *b)\n \treturn strcmp(one->name, two->name);\n }\n \n-static void sort_ref_dir(struct ref_dir *dir);\n+static void sort_ref_dir(struct ref_entry *direntry);\n \n /*\n  * Return the entry with the given refname from direntry\n@@ -266,7 +266,7 @@ static struct ref_entry *search_ref_dir(struct ref_entry *direntry,\n \tif (refname == NULL || !dir->nr)\n \t\treturn NULL;\n \n-\tsort_ref_dir(dir);\n+\tsort_ref_dir(direntry);\n \n \tlen = strlen(refname) + 1;\n \te = xmalloc(sizeof(struct ref_entry) + len);\n@@ -386,14 +386,17 @@ static int is_dup_ref(const struct ref_entry *ref1, const struct ref_entry *ref2\n }\n \n /*\n- * Sort the entries in dir non-recursively (if they are not already\n- * sorted) and remove any duplicate entries.\n+ * Sort the entries in direntry non-recursively (if they are not\n+ * already sorted) and remove any duplicate entries.\n  */\n-static void sort_ref_dir(struct ref_dir *dir)\n+static void sort_ref_dir(struct ref_entry *direntry)\n {\n \tint i, j;\n \tstruct ref_entry *last = NULL;\n+\tstruct ref_dir *dir;\n \n+\tassert(direntry->flag & REF_DIR);\n+\tdir = &direntry->u.subdir;\n \t/*\n \t * This check also prevents passing a zero-length array to qsort(),\n \t * which is a problem on some platforms.\n@@ -456,7 +459,7 @@ static int do_for_each_ref_in_dir(struct ref_entry *direntry, int offset,\n \t\tstruct ref_entry *entry = direntry->u.subdir.entries[i];\n \t\tint retval;\n \t\tif (entry->flag & REF_DIR) {\n-\t\t\tsort_ref_dir(&entry->u.subdir);\n+\t\t\tsort_ref_dir(entry);\n \t\t\tretval = do_for_each_ref_in_dir(entry, 0,\n \t\t\t\t\t\t\tbase, fn, trim, flags, cb_data);\n \t\t} else {\n@@ -505,8 +508,8 @@ static int do_for_each_ref_in_dirs(struct ref_entry *direntry1,\n \t\tif (cmp == 0) {\n \t\t\tif ((e1->flag & REF_DIR) && (e2->flag & REF_DIR)) {\n \t\t\t\t/* Both are directories; descend them in parallel. */\n-\t\t\t\tsort_ref_dir(&e1->u.subdir);\n-\t\t\t\tsort_ref_dir(&e2->u.subdir);\n+\t\t\t\tsort_ref_dir(e1);\n+\t\t\t\tsort_ref_dir(e2);\n \t\t\t\tretval = do_for_each_ref_in_dirs(\n \t\t\t\t\t\te1, e2,\n \t\t\t\t\t\tbase, fn, trim, flags, cb_data);\n@@ -531,7 +534,7 @@ static int do_for_each_ref_in_dirs(struct ref_entry *direntry1,\n \t\t\t\ti2++;\n \t\t\t}\n \t\t\tif (e->flag & REF_DIR) {\n-\t\t\t\tsort_ref_dir(&e->u.subdir);\n+\t\t\t\tsort_ref_dir(e);\n \t\t\t\tretval = do_for_each_ref_in_dir(\n \t\t\t\t\t\te, 0,\n \t\t\t\t\t\tbase, fn, trim, flags, cb_data);\n@@ -601,7 +604,7 @@ static int is_refname_available(const char *refname, const char *oldrefname,\n \tdata.conflicting_refname = NULL;\n \n \tassert(direntry->flag & REF_DIR);\n-\tsort_ref_dir(&direntry->u.subdir);\n+\tsort_ref_dir(direntry);\n \n \tif (do_for_each_ref_in_dir(direntry, 0, \"\", name_conflict_fn,\n \t\t\t\t   0, DO_FOR_EACH_INCLUDE_BROKEN,\n@@ -1187,18 +1190,18 @@ static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn\n \t}\n \n \tif (packed_direntry && loose_direntry) {\n-\t\tsort_ref_dir(&packed_direntry->u.subdir);\n-\t\tsort_ref_dir(&loose_direntry->u.subdir);\n+\t\tsort_ref_dir(packed_direntry);\n+\t\tsort_ref_dir(loose_direntry);\n \t\tretval = do_for_each_ref_in_dirs(\n \t\t\t\tpacked_direntry, loose_direntry,\n \t\t\t\tbase, fn, trim, flags, cb_data);\n \t} else if (packed_direntry) {\n-\t\tsort_ref_dir(&packed_direntry->u.subdir);\n+\t\tsort_ref_dir(packed_direntry);\n \t\tretval = do_for_each_ref_in_dir(\n \t\t\t\tpacked_direntry, 0,\n \t\t\t\tbase, fn, trim, flags, cb_data);\n \t} else if (loose_direntry) {\n-\t\tsort_ref_dir(&loose_direntry->u.subdir);\n+\t\tsort_ref_dir(loose_direntry);\n \t\tretval = do_for_each_ref_in_dir(\n \t\t\t\tloose_direntry, 0,\n \t\t\t\tbase, fn, trim, flags, cb_data);\n-- \n1.7.10\n"},{"id":"190021","messageId":"1335307536-26914-27-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 26/30] struct ref_dir: store a reference to the enclosing ref_cache","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:32Z","receivedAt":"2012-04-24T22:45:32Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nThis means that it contains enough information to serve as the sole\nargument to get_ref_dir(), which will be changed in a moment.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   16 ++++++++++++----\n 1 file changed, 12 insertions(+), 4 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 90bdd7c..11ebc02 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -106,6 +106,8 @@ struct ref_value {\n \tunsigned char peeled[20];\n };\n \n+struct ref_cache;\n+\n struct ref_dir {\n \tint nr, alloc;\n \n@@ -118,6 +120,9 @@ struct ref_dir {\n \tint sorted;\n \n \tstruct ref_entry **entries;\n+\n+\t/* A pointer to the ref_cache that contains this ref_dir. */\n+\tstruct ref_cache *ref_cache;\n };\n \n /* ISSYMREF=0x01, ISPACKED=0x02, and ISBROKEN=0x04 are public interfaces */\n@@ -230,13 +235,15 @@ static void clear_ref_dir(struct ref_dir *dir)\n  * dirname is the name of the directory with a trailing slash (e.g.,\n  * \"refs/heads/\") or \"\" for the top-level directory.\n  */\n-static struct ref_entry *create_dir_entry(const char *dirname)\n+static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache,\n+\t\t\t\t\t  const char *dirname)\n {\n \tstruct ref_entry *direntry;\n \tint len = strlen(dirname);\n \tdirentry = xcalloc(1, sizeof(struct ref_entry) + len + 1);\n \tmemcpy(direntry->name, dirname, len + 1);\n \tdirentry->flag = REF_DIR;\n+\tdirentry->u.subdir.ref_cache = ref_cache;\n \treturn direntry;\n }\n \n@@ -296,7 +303,8 @@ static struct ref_entry *search_for_subdir(struct ref_entry *direntry,\n \tif (!entry) {\n \t\tif (!mkdir)\n \t\t\treturn NULL;\n-\t\tentry = create_dir_entry(subdirname);\n+\t\tentry = create_dir_entry(direntry->u.subdir.ref_cache,\n+\t\t\t\t\t subdirname);\n \t\tadd_entry(direntry, entry);\n \t}\n \tassert(entry->flag & REF_DIR);\n@@ -760,7 +768,7 @@ static struct ref_entry *get_packed_refs(struct ref_cache *refs)\n \t\tconst char *packed_refs_file;\n \t\tFILE *f;\n \n-\t\trefs->packed = create_dir_entry(\"\");\n+\t\trefs->packed = create_dir_entry(refs, \"\");\n \t\tif (*refs->name)\n \t\t\tpacked_refs_file = git_path_submodule(refs->name, \"packed-refs\");\n \t\telse\n@@ -851,7 +859,7 @@ static void get_ref_dir(struct ref_cache *refs, struct ref_entry *direntry)\n static struct ref_entry *get_loose_refs(struct ref_cache *refs)\n {\n \tif (!refs->loose) {\n-\t\trefs->loose = create_dir_entry(\"\");\n+\t\trefs->loose = create_dir_entry(refs, \"\");\n \t\tget_ref_dir(refs,\n \t\t\t    search_for_subdir(refs->loose, \"refs/\", 1));\n \t}\n-- \n1.7.10\n"},{"id":"190018","messageId":"1335307536-26914-28-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 27/30] read_loose_refs(): rename function from get_ref_dir()","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:33Z","receivedAt":"2012-04-24T22:45:33Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 11ebc02..0f5aab2 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -791,7 +791,7 @@ void add_packed_ref(const char *refname, const unsigned char *sha1)\n /*\n  * Read the loose references for direntry in refs.\n  */\n-static void get_ref_dir(struct ref_cache *refs, struct ref_entry *direntry)\n+static void read_loose_refs(struct ref_cache *refs, struct ref_entry *direntry)\n {\n \tDIR *d;\n \tconst char *path;\n@@ -832,9 +832,9 @@ static void get_ref_dir(struct ref_cache *refs, struct ref_entry *direntry)\n \t\t\t/* Silently ignore. */\n \t\t} else if (S_ISDIR(st.st_mode)) {\n \t\t\tstrbuf_addch(&refname, '/');\n-\t\t\tget_ref_dir(refs,\n-\t\t\t\t    search_for_subdir(direntry,\n-\t\t\t\t\t\t      refname.buf, 1));\n+\t\t\tread_loose_refs(refs,\n+\t\t\t\t\tsearch_for_subdir(direntry,\n+\t\t\t\t\t\t\t  refname.buf, 1));\n \t\t} else {\n \t\t\tif (*refs->name) {\n \t\t\t\thashclr(sha1);\n@@ -860,8 +860,8 @@ static struct ref_entry *get_loose_refs(struct ref_cache *refs)\n {\n \tif (!refs->loose) {\n \t\trefs->loose = create_dir_entry(refs, \"\");\n-\t\tget_ref_dir(refs,\n-\t\t\t    search_for_subdir(refs->loose, \"refs/\", 1));\n+\t\tread_loose_refs(refs,\n+\t\t\t\tsearch_for_subdir(refs->loose, \"refs/\", 1));\n \t}\n \treturn refs->loose;\n }\n-- \n1.7.10\n"},{"id":"190013","messageId":"1335307536-26914-29-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 28/30] read_loose_refs(): access ref_cache via the ref_dir field","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:34Z","receivedAt":"2012-04-24T22:45:34Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nThis means that all we need to read loose references is the ref_entry\nthat will receive them.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 0f5aab2..4eca965 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -791,7 +791,7 @@ void add_packed_ref(const char *refname, const unsigned char *sha1)\n /*\n  * Read the loose references for direntry in refs.\n  */\n-static void read_loose_refs(struct ref_cache *refs, struct ref_entry *direntry)\n+static void read_loose_refs(struct ref_entry *direntry)\n {\n \tDIR *d;\n \tconst char *path;\n@@ -799,9 +799,11 @@ static void read_loose_refs(struct ref_cache *refs, struct ref_entry *direntry)\n \tconst char *dirname = direntry->name;\n \tint dirnamelen = strlen(dirname);\n \tstruct strbuf refname;\n+\tstruct ref_cache *refs;\n \n \tassert(direntry->flag & REF_DIR);\n \n+\trefs = direntry->u.subdir.ref_cache;\n \tif (*refs->name)\n \t\tpath = git_path_submodule(refs->name, \"%s\", dirname);\n \telse\n@@ -832,8 +834,7 @@ static void read_loose_refs(struct ref_cache *refs, struct ref_entry *direntry)\n \t\t\t/* Silently ignore. */\n \t\t} else if (S_ISDIR(st.st_mode)) {\n \t\t\tstrbuf_addch(&refname, '/');\n-\t\t\tread_loose_refs(refs,\n-\t\t\t\t\tsearch_for_subdir(direntry,\n+\t\t\tread_loose_refs(search_for_subdir(direntry,\n \t\t\t\t\t\t\t  refname.buf, 1));\n \t\t} else {\n \t\t\tif (*refs->name) {\n@@ -860,8 +861,7 @@ static struct ref_entry *get_loose_refs(struct ref_cache *refs)\n {\n \tif (!refs->loose) {\n \t\trefs->loose = create_dir_entry(refs, \"\");\n-\t\tread_loose_refs(refs,\n-\t\t\t\tsearch_for_subdir(refs->loose, \"refs/\", 1));\n+\t\tread_loose_refs(search_for_subdir(refs->loose, \"refs/\", 1));\n \t}\n \treturn refs->loose;\n }\n-- \n1.7.10\n"},{"id":"190024","messageId":"1335307536-26914-30-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 29/30] create_dir_entry(): allow the flag value to be passed as an argument","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:35Z","receivedAt":"2012-04-24T22:45:35Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nIn a moment we will support multiple flag values for directory entries.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |   12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 4eca965..869c9a7 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -231,18 +231,18 @@ static void clear_ref_dir(struct ref_dir *dir)\n }\n \n /*\n- * Create a struct ref_entry object for the specified dirname.\n+ * Create a struct ref_entry object for the specified dirname and flag.\n  * dirname is the name of the directory with a trailing slash (e.g.,\n  * \"refs/heads/\") or \"\" for the top-level directory.\n  */\n static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache,\n-\t\t\t\t\t  const char *dirname)\n+\t\t\t\t\t  const char *dirname, int flag)\n {\n \tstruct ref_entry *direntry;\n \tint len = strlen(dirname);\n \tdirentry = xcalloc(1, sizeof(struct ref_entry) + len + 1);\n \tmemcpy(direntry->name, dirname, len + 1);\n-\tdirentry->flag = REF_DIR;\n+\tdirentry->flag = flag;\n \tdirentry->u.subdir.ref_cache = ref_cache;\n \treturn direntry;\n }\n@@ -304,7 +304,7 @@ static struct ref_entry *search_for_subdir(struct ref_entry *direntry,\n \t\tif (!mkdir)\n \t\t\treturn NULL;\n \t\tentry = create_dir_entry(direntry->u.subdir.ref_cache,\n-\t\t\t\t\t subdirname);\n+\t\t\t\t\t subdirname, REF_DIR);\n \t\tadd_entry(direntry, entry);\n \t}\n \tassert(entry->flag & REF_DIR);\n@@ -768,7 +768,7 @@ static struct ref_entry *get_packed_refs(struct ref_cache *refs)\n \t\tconst char *packed_refs_file;\n \t\tFILE *f;\n \n-\t\trefs->packed = create_dir_entry(refs, \"\");\n+\t\trefs->packed = create_dir_entry(refs, \"\", REF_DIR);\n \t\tif (*refs->name)\n \t\t\tpacked_refs_file = git_path_submodule(refs->name, \"packed-refs\");\n \t\telse\n@@ -860,7 +860,7 @@ static void read_loose_refs(struct ref_entry *direntry)\n static struct ref_entry *get_loose_refs(struct ref_cache *refs)\n {\n \tif (!refs->loose) {\n-\t\trefs->loose = create_dir_entry(refs, \"\");\n+\t\trefs->loose = create_dir_entry(refs, \"\", REF_DIR);\n \t\tread_loose_refs(search_for_subdir(refs->loose, \"refs/\", 1));\n \t}\n \treturn refs->loose;\n-- \n1.7.10\n"},{"id":"190023","messageId":"1335307536-26914-31-git-send-email-mhagger@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH 30/30] refs: read loose references lazily","fromName":"","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-24T22:45:36Z","receivedAt":"2012-04-24T22:45:36Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Michael Haggerty <mhagger@alum.mit.edu>\n\nInstead of reading the whole directory of loose references the first\ntime any are needed, only read them on demand, one directory at a\ntime.\n\nUse a new ref_entry flag value REF_DIR_INCOMPLETE to indicate that the\nentry represents a REF_DIR that hasn't been read yet.  Whenever any\nentries from such a directory are needed, read all of the loose\nreferences from that directory.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n refs.c |  107 +++++++++++++++++++++++++++++++++++++++++++++++++++-------------\n 1 file changed, 86 insertions(+), 21 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 869c9a7..d72208a 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -101,6 +101,12 @@ int check_refname_format(const char *refname, int flags)\n \n struct ref_entry;\n \n+/*\n+ * Information used (along with the information in ref_entry) to\n+ * describe a single cached reference.  This data structure only\n+ * occurs embedded in a union in struct ref_entry, and only when\n+ * (ref_entry->flag & REF_DIR) is zero.\n+ */\n struct ref_value {\n \tunsigned char sha1[20];\n \tunsigned char peeled[20];\n@@ -108,6 +114,34 @@ struct ref_value {\n \n struct ref_cache;\n \n+/*\n+ * Information used (along with the information in ref_entry) to\n+ * describe a level in the hierarchy of references.  This data\n+ * structure only occurs embedded in a union in struct ref_entry, and\n+ * only when (ref_entry.flag & REF_DIR) is nonzero.  In that case,\n+ * (ref_entry.flag & REF_DIR) can take the following values:\n+ *\n+ *     REF_DIR_COMPLETE -- a directory of loose or packed references,\n+ *         already read.\n+ *\n+ *     REF_DIR_INCOMPLETE -- a directory of loose references that\n+ *         hasn't been read yet (nor has any of its subdirectories).\n+ *\n+ * Entries within a directory are stored within a growable array of\n+ * pointers to ref_entries (entries, nr, alloc).  Entries 0 <= i <\n+ * sorted are sorted by their component name in strcmp() order and the\n+ * remaining entries are unsorted.\n+ *\n+ * Loose references are read lazily, one directory at a time.  When a\n+ * directory of loose references is read, then all of the references\n+ * in that directory are stored, and REF_DIR_INCOMPLETE stubs are\n+ * created for any subdirectories, but the subdirectories themselves\n+ * are not read.  The reading is triggered either by search_ref_dir()\n+ * (called when single references are added or interrogated), by\n+ * sort_ref_dir(), or by iteration over a subdirectory of references\n+ * using one of the for_each_ref*() functions (because these functions\n+ * call sort_ref_dir() for each subdirectory).\n+ */\n struct ref_dir {\n \tint nr, alloc;\n \n@@ -127,19 +161,33 @@ struct ref_dir {\n \n /* ISSYMREF=0x01, ISPACKED=0x02, and ISBROKEN=0x04 are public interfaces */\n #define REF_KNOWS_PEELED 0x08\n-#define REF_DIR 0x10\n+\n+/* If any of these bits are set, the entry represents a directory: */\n+#define REF_DIR 0x30\n+\n+/* A directory that has already been fully read. */\n+#define REF_DIR_COMPLETE 0x10\n+\n+/* A directory of loose references that has not yet been fully read. */\n+#define REF_DIR_INCOMPLETE 0x20\n \n /*\n  * A ref_entry represents either a reference or a \"subdirectory\" of\n- * references.  Each directory in the reference namespace is\n- * represented by a ref_entry with (flags & REF_DIR) set and\n- * containing a subdir member that holds the entries in that\n- * directory.  References are represented by a ref_entry with (flags &\n- * REF_DIR) unset and a value member that describes the reference's\n- * value.  The flag member is at the ref_entry level, but it is also\n- * needed to interpret the contents of the value field (in other\n- * words, a ref_value object is not very much use without the\n- * enclosing ref_entry).\n+ * references.\n+ *\n+ * Each directory in the reference namespace is represented by a\n+ * ref_entry with (flags & REF_DIR) set and containing a subdir member\n+ * that holds the entries in that directory that have been read so\n+ * far.  If (flags & REF_DIR) == REF_DIR_INCOMPLETE, then the\n+ * directory and its subdirectories haven't been read yet.\n+ * REF_DIR_INCOMPLETE is only used for loose references.\n+ *\n+ * References are represented by a ref_entry with (flags & REF_DIR) ==\n+ * 0 and a value member that describes the reference's value.  The\n+ * flag member is at the ref_entry level, but it is also needed to\n+ * interpret the contents of the value field (in other words, a\n+ * ref_value object is not very much use without the enclosing\n+ * ref_entry).\n  *\n  * Reference names cannot end with slash and directories' names are\n  * always stored with a trailing slash (except for the top-level\n@@ -207,11 +255,13 @@ static void free_ref_entry(struct ref_entry *entry)\n /*\n  * Add entry to the end of direntry, unsorted.  entry is always stored\n  * directly in direntry; no recursion into subdirectories is done.\n+ * direntry must already be REF_DIR_COMPLETE.\n  */\n static void add_entry(struct ref_entry *direntry, struct ref_entry *entry)\n {\n \tstruct ref_dir *dir;\n \tassert(direntry->flag & REF_DIR);\n+\tassert((direntry->flag & REF_DIR) == REF_DIR_COMPLETE);\n \tdir = &direntry->u.subdir;\n \tALLOC_GROW(dir->entries, dir->nr + 1, dir->alloc);\n \tdir->entries[dir->nr++] = entry;\n@@ -256,10 +306,12 @@ static int ref_entry_cmp(const void *a, const void *b)\n \n static void sort_ref_dir(struct ref_entry *direntry);\n \n+static void read_loose_refs(struct ref_entry *direntry);\n+\n /*\n  * Return the entry with the given refname from direntry\n- * (non-recursively), sorting direntry if necessary.  Return NULL if\n- * no such entry is found.\n+ * (non-recursively), reading direntry if it is REF_DIR_INCOMPLETE and\n+ * sorting it if necessary.  Return NULL if no such entry is found.\n  */\n static struct ref_entry *search_ref_dir(struct ref_entry *direntry,\n \t\t\t\t\tconst char *refname)\n@@ -269,6 +321,7 @@ static struct ref_entry *search_ref_dir(struct ref_entry *direntry,\n \tstruct ref_dir *dir;\n \n \tassert(direntry->flag & REF_DIR);\n+\tread_loose_refs(direntry);\n \tdir = &direntry->u.subdir;\n \tif (refname == NULL || !dir->nr)\n \t\treturn NULL;\n@@ -303,8 +356,14 @@ static struct ref_entry *search_for_subdir(struct ref_entry *direntry,\n \tif (!entry) {\n \t\tif (!mkdir)\n \t\t\treturn NULL;\n+\t\t/*\n+\t\t * If search_ref_dir() above didn't make the\n+\t\t * entry spring into existence, then this must\n+\t\t * not be an unread loose reference tree, so\n+\t\t * the correct flag is REF_DIR_COMPLETE.\n+\t\t */\n \t\tentry = create_dir_entry(direntry->u.subdir.ref_cache,\n-\t\t\t\t\t subdirname, REF_DIR);\n+\t\t\t\t\t subdirname, REF_DIR_COMPLETE);\n \t\tadd_entry(direntry, entry);\n \t}\n \tassert(entry->flag & REF_DIR);\n@@ -395,7 +454,8 @@ static int is_dup_ref(const struct ref_entry *ref1, const struct ref_entry *ref2\n \n /*\n  * Sort the entries in direntry non-recursively (if they are not\n- * already sorted) and remove any duplicate entries.\n+ * already sorted) and remove any duplicate entries.  If direntry is\n+ * REF_DIR_INCOMPLETE, read it from disk first.\n  */\n static void sort_ref_dir(struct ref_entry *direntry)\n {\n@@ -404,6 +464,7 @@ static void sort_ref_dir(struct ref_entry *direntry)\n \tstruct ref_dir *dir;\n \n \tassert(direntry->flag & REF_DIR);\n+\tread_loose_refs(direntry);\n \tdir = &direntry->u.subdir;\n \t/*\n \t * This check also prevents passing a zero-length array to qsort(),\n@@ -768,7 +829,7 @@ static struct ref_entry *get_packed_refs(struct ref_cache *refs)\n \t\tconst char *packed_refs_file;\n \t\tFILE *f;\n \n-\t\trefs->packed = create_dir_entry(refs, \"\", REF_DIR);\n+\t\trefs->packed = create_dir_entry(refs, \"\", REF_DIR_COMPLETE);\n \t\tif (*refs->name)\n \t\t\tpacked_refs_file = git_path_submodule(refs->name, \"packed-refs\");\n \t\telse\n@@ -797,12 +858,15 @@ static void read_loose_refs(struct ref_entry *direntry)\n \tconst char *path;\n \tstruct dirent *de;\n \tconst char *dirname = direntry->name;\n-\tint dirnamelen = strlen(dirname);\n+\tint dirnamelen;\n \tstruct strbuf refname;\n \tstruct ref_cache *refs;\n \n \tassert(direntry->flag & REF_DIR);\n-\n+\tif ((direntry->flag & REF_DIR) != REF_DIR_INCOMPLETE)\n+\t\treturn;\n+\tdirentry->flag = REF_DIR_COMPLETE;\n+\tdirnamelen = strlen(dirname);\n \trefs = direntry->u.subdir.ref_cache;\n \tif (*refs->name)\n \t\tpath = git_path_submodule(refs->name, \"%s\", dirname);\n@@ -834,8 +898,9 @@ static void read_loose_refs(struct ref_entry *direntry)\n \t\t\t/* Silently ignore. */\n \t\t} else if (S_ISDIR(st.st_mode)) {\n \t\t\tstrbuf_addch(&refname, '/');\n-\t\t\tread_loose_refs(search_for_subdir(direntry,\n-\t\t\t\t\t\t\t  refname.buf, 1));\n+\t\t\tadd_entry(direntry,\n+\t\t\t\t  create_dir_entry(refs, refname.buf,\n+\t\t\t\t\t\t   REF_DIR_INCOMPLETE));\n \t\t} else {\n \t\t\tif (*refs->name) {\n \t\t\t\thashclr(sha1);\n@@ -860,8 +925,8 @@ static void read_loose_refs(struct ref_entry *direntry)\n static struct ref_entry *get_loose_refs(struct ref_cache *refs)\n {\n \tif (!refs->loose) {\n-\t\trefs->loose = create_dir_entry(refs, \"\", REF_DIR);\n-\t\tread_loose_refs(search_for_subdir(refs->loose, \"refs/\", 1));\n+\t\trefs->loose = create_dir_entry(refs, \"\", REF_DIR_COMPLETE);\n+\t\tadd_entry(refs->loose, create_dir_entry(refs, \"refs/\", REF_DIR_INCOMPLETE));\n \t}\n \treturn refs->loose;\n }\n-- \n1.7.10\n"},{"id":"190071","messageId":"xmqqfwbrd5ny.fsf@junio.mtv.corp.google.com","threadId":"30329","inReplyTo":"1335307536-26914-30-git-send-email-mhagger@alum.mit.edu","subject":"Re: [PATCH 29/30] create_dir_entry(): allow the flag value to be passed as an argument","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-25T18:31:45Z","receivedAt":"2012-04-25T18:31:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"mhagger@alum.mit.edu writes:\n\n> diff --git a/refs.c b/refs.c\n> index 4eca965..869c9a7 100644\n> --- a/refs.c\n> +++ b/refs.c\n> @@ -231,18 +231,18 @@ static void clear_ref_dir(struct ref_dir *dir)\n>  }\n>  \n>  /*\n> + * Create a struct ref_entry object for the specified dirname and flag.\n>   * dirname is the name of the directory with a trailing slash (e.g.,\n>   * \"refs/heads/\") or \"\" for the top-level directory.\n>   */\n>  static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache,\n> -\t\t\t\t\t  const char *dirname)\n> +\t\t\t\t\t  const char *dirname, int flag)\n>  {\n>  \tstruct ref_entry *direntry;\n>  \tint len = strlen(dirname);\n>  \tdirentry = xcalloc(1, sizeof(struct ref_entry) + len + 1);\n>  \tmemcpy(direntry->name, dirname, len + 1);\n> -\tdirentry->flag = REF_DIR;\n> +\tdirentry->flag = flag;\n>  \tdirentry->u.subdir.ref_cache = ref_cache;\n\nAs the returned structure will always represent a subdirectory and not a\nleaf node, i.e. you use u.subdir, I do not think it makes any sense to\nmake it responsibility for the caller of this function to include\nREF_DIR in the value of the flag.\n\nAlso shouldn't flag be of type \"unsigned\", not \"int\"?\n"},{"id":"190072","messageId":"xmqqbomfd5bt.fsf@junio.mtv.corp.google.com","threadId":"30329","inReplyTo":"1335307536-26914-1-git-send-email-mhagger@alum.mit.edu","subject":"Re: [PATCH 00/30] Read loose references lazily","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-25T18:39:02Z","receivedAt":"2012-04-25T18:39:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"mhagger@alum.mit.edu writes:\n\n> From: Michael Haggerty <mhagger@alum.mit.edu>\n>\n> This is the next installment of the ref-api saga.  The main result of\n> this patch series is to teach git to read loose references one\n> directory at a time, only when they are needed.\n>\n> The first nine commits are not very interesting; they convert\n> get_ref_dir() and do_for_each_reflog() to use strbufs and to tighten\n> up their specifications.  The search_for_subdir() function extracted\n> in patch 5 will be useful later.  Patch 6 slightly reduces the amount\n> of work needed to read loose refs from disk, and also changes the\n> function's API in a way that will be needed later when directories are\n> read one at a time.\n>\n> Patches 10 - 25 mostly switch a lot of code from using ref_dir\n> pointers to using ref_entry pointers as arguments and return values.\n> This is important, because ...\n\nThe earlier parts looked sane, but the ref_dir set of patches looked\nlike merely working around the fact that \"struct ref_dir\" does not have\nthe name field and you had to upcast it to ref_entry to access the full\nname.\n\nAll the places that used to take ref_dir never wanted to get an entry\nthat represents a leaf node (i.e. ref_value kind of ref_entry), but now\nbecause you made everybody to take ref_entry, the resulting code is much\nmore error prone and the static type checking done by the compiler helps\nus much less when updating the code.  It can already be seen that you\nhad to sprinkle a lot of assert(flag & REF_DIR), but at runtime in\nnon-debug build that will become no-op and it is not a substitute for\nthe static type checking we used to have.\n\nCan't we approach this differently so that we can keep the type safety?\n"},{"id":"190073","messageId":"xmqq62cnd4pv.fsf@junio.mtv.corp.google.com","threadId":"30329","inReplyTo":"xmqqfwbrd5ny.fsf@junio.mtv.corp.google.com","subject":"Re: [PATCH 29/30] create_dir_entry(): allow the flag value to be passed as an argument","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-25T18:52:12Z","receivedAt":"2012-04-25T18:52:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> mhagger@alum.mit.edu writes:\n>\n>> diff --git a/refs.c b/refs.c\n>> index 4eca965..869c9a7 100644\n>> --- a/refs.c\n>> +++ b/refs.c\n>> @@ -231,18 +231,18 @@ static void clear_ref_dir(struct ref_dir *dir)\n>>  }\n>>  \n>>  /*\n>> + * Create a struct ref_entry object for the specified dirname and flag.\n>>   * dirname is the name of the directory with a trailing slash (e.g.,\n>>   * \"refs/heads/\") or \"\" for the top-level directory.\n>>   */\n>>  static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache,\n>> -\t\t\t\t\t  const char *dirname)\n>> +\t\t\t\t\t  const char *dirname, int flag)\n>>  {\n>>  \tstruct ref_entry *direntry;\n>>  \tint len = strlen(dirname);\n>>  \tdirentry = xcalloc(1, sizeof(struct ref_entry) + len + 1);\n>>  \tmemcpy(direntry->name, dirname, len + 1);\n>> -\tdirentry->flag = REF_DIR;\n>> +\tdirentry->flag = flag;\n>>  \tdirentry->u.subdir.ref_cache = ref_cache;\n>\n> As the returned structure will always represent a subdirectory and not a\n> leaf node, i.e. you use u.subdir, I do not think it makes any sense to\n> make it responsibility for the caller of this function to include\n> REF_DIR in the value of the flag.\n\nForseeing a response \"But but but REF_DIR will become OR of two\nvariants\", my complaint is still valid ;-) and it is the bit assignment\nyou did in the final patch that is wrong.  If you make REF_DIR (or not)\nto differenticate between ref_dir vs ref_value, and use another bit\nREF_INCOMPLETE to remember that you still need to find out the actual\nvalue of it, the the above can still be\n\n\tcreate_dir_entry(struct ref_cache *ref_cache, const char *dirname, int lazy)\n\t{\n\t\t...\n\t\tdirentry->flag = REF_DIR | (lazy ? REF_INCOMPLETE : 0);\n                ...\n\t}\n\nI am OK with the following as well:\n\n\tcreate_dir_entry(struct ref_cache *ref_cache,\n        \t\tconst char *dirname, unsigned extra)\n\t{\n\t\t...\n\t\tdirentry->flag = REF_DIR | extra;\n\t}\n\nThe suggested bit assignment would also allow you to create ref_value\nleaf nodes, whose presence you know about (by iterating over readdir()\nresults) but not their values yet (because you haven't opened and read\nthem), by marking them with REF_INCOMPLETE to be extra lazy in the\nfuture, if necessary.  I do not know if that much laziness buys us a\nlot, though ;-).\n"},{"id":"190114","messageId":"4F995DFC.501@alum.mit.edu","threadId":"30329","inReplyTo":"1335307536-26914-11-git-send-email-mhagger@alum.mit.edu","subject":"Re: [PATCH 10/30] refs: wrap top-level ref_dirs in ref_entries","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-26T14:38:52Z","receivedAt":"2012-04-26T14:38:52Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 04/25/2012 12:45 AM, mhagger@alum.mit.edu wrote:\n> From: Michael Haggerty<mhagger@alum.mit.edu>\n>\n> Wrap the top-level ref_dirs in REF_DIR style ref_entries so that we\n> have the flag and name available when dealing with them.  This\n> affects:\n>\n> * cache_ref::loose\n> * cache_ref::packed\n> * extra_refs\n>\n> The next several commits will expand the use of ref_entry as opposed\n> to ref_dir, culminating in the ability of a ref_entry representing a\n> directory of loose references to load itself only when used.\n\nThe mention of \"extra_refs\" here is of course obsolete and should be \ndeleted.\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\nhttp://softwareswirl.blogspot.com/\n"},{"id":"190158","messageId":"4F99BA36.5070803@alum.mit.edu","threadId":"30329","inReplyTo":"xmqq62cnd4pv.fsf@junio.mtv.corp.google.com","subject":"Re: [PATCH 29/30] create_dir_entry(): allow the flag value to be passed as an argument","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-26T21:12:22Z","receivedAt":"2012-04-26T21:12:22Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 04/25/2012 08:52 PM, Junio C Hamano wrote:\n> Junio C Hamano<gitster@pobox.com>  writes:\n>\n>> mhagger@alum.mit.edu writes:\n>>\n>>> diff --git a/refs.c b/refs.c\n>>> index 4eca965..869c9a7 100644\n>>> --- a/refs.c\n>>> +++ b/refs.c\n>>> @@ -231,18 +231,18 @@ static void clear_ref_dir(struct ref_dir *dir)\n>>>   }\n>>>\n>>>   /*\n>>> + * Create a struct ref_entry object for the specified dirname and flag.\n>>>    * dirname is the name of the directory with a trailing slash (e.g.,\n>>>    * \"refs/heads/\") or \"\" for the top-level directory.\n>>>    */\n>>>   static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache,\n>>> -\t\t\t\t\t  const char *dirname)\n>>> +\t\t\t\t\t  const char *dirname, int flag)\n>>>   {\n>>>   \tstruct ref_entry *direntry;\n>>>   \tint len = strlen(dirname);\n>>>   \tdirentry = xcalloc(1, sizeof(struct ref_entry) + len + 1);\n>>>   \tmemcpy(direntry->name, dirname, len + 1);\n>>> -\tdirentry->flag = REF_DIR;\n>>> +\tdirentry->flag = flag;\n>>>   \tdirentry->u.subdir.ref_cache = ref_cache;\n>>\n>> As the returned structure will always represent a subdirectory and not a\n>> leaf node, i.e. you use u.subdir, I do not think it makes any sense to\n>> make it responsibility for the caller of this function to include\n>> REF_DIR in the value of the flag.\n>\n> Forseeing a response \"But but but REF_DIR will become OR of two\n> variants\", my complaint is still valid ;-) and it is the bit assignment\n> you did in the final patch that is wrong.  If you make REF_DIR (or not)\n> to differenticate between ref_dir vs ref_value, and use another bit\n> REF_INCOMPLETE to remember that you still need to find out the actual\n> value of it, the the above can still be\n\nIn an earlier design, there were three types of REF_DIR: packed, \nloose(read), and loose(unread), which could all be packed (along with \ndir/non-dir) into two bits.  The current bit assignment was left over \nfrom that design, plus a latent expectation that it would sometime be \nnecessary to distinguish between packed and loose(read) references.\n\nBut so far I haven't found a reason to distinguish between packed and \nloose(read), so your suggested bit assignment is simpler.  I will \ninclude it in the next version of the patch series.\n\n> The suggested bit assignment would also allow you to create ref_value\n> leaf nodes, whose presence you know about (by iterating over readdir()\n> results) but not their values yet (because you haven't opened and read\n> them), by marking them with REF_INCOMPLETE to be extra lazy in the\n> future, if necessary.  I do not know if that much laziness buys us a\n> lot, though ;-).\n\nThis would be pretty easy to implement.  Maybe I'll try it someday.\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\nhttp://softwareswirl.blogspot.com/\n"},{"id":"190159","messageId":"4F99BF46.9050501@alum.mit.edu","threadId":"30329","inReplyTo":"xmqqbomfd5bt.fsf@junio.mtv.corp.google.com","subject":"Re: [PATCH 00/30] Read loose references lazily","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-04-26T21:33:58Z","receivedAt":"2012-04-26T21:33:58Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 04/25/2012 08:39 PM, Junio C Hamano wrote:\n> mhagger@alum.mit.edu writes:\n>\n>> From: Michael Haggerty<mhagger@alum.mit.edu>\n>>\n>> Patches 10 - 25 mostly switch a lot of code from using ref_dir\n>> pointers to using ref_entry pointers as arguments and return values.\n>> This is important, because ...\n>\n> The earlier parts looked sane, but the ref_dir set of patches looked\n> like merely working around the fact that \"struct ref_dir\" does not have\n> the name field and you had to upcast it to ref_entry to access the full\n> name.\n\nYes, that plus the fact that the ref_entry::flag field is needed in \nref_entry (to distinguish between value and directory entries) but also \nto interpret the contents of the ref_value / ref_dir.\n\n> All the places that used to take ref_dir never wanted to get an entry\n> that represents a leaf node (i.e. ref_value kind of ref_entry), but now\n> because you made everybody to take ref_entry, the resulting code is much\n> more error prone and the static type checking done by the compiler helps\n> us much less when updating the code.  It can already be seen that you\n> had to sprinkle a lot of assert(flag&  REF_DIR), but at runtime in\n> non-debug build that will become no-op and it is not a substitute for\n> the static type checking we used to have.\n>\n> Can't we approach this differently so that we can keep the type safety?\n\nThanks for this comment.  I've obviously been ruined by OO languages, in \nwhich [name + flag + struct ref_value] and [name + flag + struct \nref_dir] (which *are* useful combinations of data) would be subclasses, \nand the downcasting from ref_entry would only have to occur in only one \nplace, while the compiler could guarantee consistency everywhere else.\n\nIn C, I don't see a way to implement the equivalent semantics that is \nless annoying than the code that I submitted.\n\nBut since [name + flag + struct ref_value] and [name + flag + struct \nref_dir] never leave the library as structs, it is indeed possible to \nwrite the code in a different way that leaves most functions working \nwith ref_dir instead of having to use ref_entry everywhere.  I have \nimplemented this and will submit it shortly.\n\nThanks again for your suggestion; the resulting code is indeed simpler.\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\nhttp://softwareswirl.blogspot.com/\n"}]}