From: Junio C Hamano Date: Tue, 29 May 2012 20:09:02 +0000 (-0700) Subject: Merge branch 'rs/refs-string-slice' X-Git-Tag: v1.7.11-rc1~17 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/a7060009e1272aa43c8fb941f039cff9e9a0459b?hp=-c Merge branch 'rs/refs-string-slice' Avoid unnecessary temporary allocations while looking for matching refs inside refs API. By René Scharfe (3) and Junio C Hamano (1) * rs/refs-string-slice: refs: do not create ref_entry when searching refs: use strings directly in find_containing_dir() refs: convert parameter of create_dir_entry() to length-limited string refs: convert parameter of search_ref_dir() to length-limited string --- a7060009e1272aa43c8fb941f039cff9e9a0459b diff --combined refs.c index 51c8825acf,52709ab7fc..da74a2b29a --- a/refs.c +++ b/refs.c @@@ -259,13 -259,8 +259,13 @@@ static void clear_ref_dir(struct ref_di static void free_ref_entry(struct ref_entry *entry) { - if (entry->flag & REF_DIR) - clear_ref_dir(get_ref_dir(entry)); + if (entry->flag & REF_DIR) { + /* + * Do not use get_ref_dir() here, as that might + * trigger the reading of loose refs. + */ + clear_ref_dir(&entry->u.subdir); + } free(entry); } @@@ -278,12 -273,6 +278,12 @@@ static void add_entry_to_dir(struct ref { ALLOC_GROW(dir->entries, dir->nr + 1, dir->alloc); dir->entries[dir->nr++] = entry; + /* optimize for the case that entries are added in order */ + if (dir->nr == 1 || + (dir->nr == dir->sorted + 1 && + strcmp(dir->entries[dir->nr - 2]->name, + dir->entries[dir->nr - 1]->name) < 0)) + dir->sorted = dir->nr; } /* @@@ -305,12 -294,13 +305,13 @@@ static void clear_ref_dir(struct ref_di * "refs/heads/") or "" for the top-level directory. */ static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache, - const char *dirname, int incomplete) + const char *dirname, size_t len, + int incomplete) { struct ref_entry *direntry; - int len = strlen(dirname); direntry = xcalloc(1, sizeof(struct ref_entry) + len + 1); - memcpy(direntry->name, dirname, len + 1); + memcpy(direntry->name, dirname, len); + direntry->name[len] = '\0'; direntry->u.subdir.ref_cache = ref_cache; direntry->flag = REF_DIR | (incomplete ? REF_INCOMPLETE : 0); return direntry; @@@ -325,28 -315,42 +326,42 @@@ static int ref_entry_cmp(const void *a static void sort_ref_dir(struct ref_dir *dir); + struct string_slice { + size_t len; + const char *str; + }; + + static int ref_entry_cmp_sslice(const void *key_, const void *ent_) + { + struct string_slice *key = (struct string_slice *)key_; + struct ref_entry *ent = *(struct ref_entry **)ent_; + int entlen = strlen(ent->name); + int cmplen = key->len < entlen ? key->len : entlen; + int cmp = memcmp(key->str, ent->name, cmplen); + if (cmp) + return cmp; + return key->len - entlen; + } + /* * Return the entry with the given refname from the ref_dir * (non-recursively), sorting dir if necessary. Return NULL if no * such entry is found. dir must already be complete. */ - static struct ref_entry *search_ref_dir(struct ref_dir *dir, const char *refname) + static struct ref_entry *search_ref_dir(struct ref_dir *dir, + const char *refname, size_t len) { - struct ref_entry *e, **r; - int len; + struct ref_entry **r; + struct string_slice key; if (refname == NULL || !dir->nr) return NULL; sort_ref_dir(dir); - - len = strlen(refname) + 1; - e = xmalloc(sizeof(struct ref_entry) + len); - memcpy(e->name, refname, len); - - r = bsearch(&e, dir->entries, dir->nr, sizeof(*dir->entries), ref_entry_cmp); - - free(e); + key.len = len; + key.str = refname; + r = bsearch(&key, dir->entries, dir->nr, sizeof(*dir->entries), + ref_entry_cmp_sslice); if (r == NULL) return NULL; @@@ -362,9 -366,10 +377,10 @@@ * directory cannot be found. dir must already be complete. */ static struct ref_dir *search_for_subdir(struct ref_dir *dir, - const char *subdirname, int mkdir) + const char *subdirname, size_t len, + int mkdir) { - struct ref_entry *entry = search_ref_dir(dir, subdirname); + struct ref_entry *entry = search_ref_dir(dir, subdirname, len); if (!entry) { if (!mkdir) return NULL; @@@ -374,7 -379,7 +390,7 @@@ * therefore, create an empty record for it but mark * the record complete. */ - entry = create_dir_entry(dir->ref_cache, subdirname, 0); + entry = create_dir_entry(dir->ref_cache, subdirname, len, 0); add_entry_to_dir(dir, entry); } return get_ref_dir(entry); @@@ -392,15 -397,11 +408,11 @@@ static struct ref_dir *find_containing_dir(struct ref_dir *dir, const char *refname, int mkdir) { - struct strbuf dirname; const char *slash; - strbuf_init(&dirname, PATH_MAX); for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) { + size_t dirnamelen = slash - refname + 1; struct ref_dir *subdir; - strbuf_add(&dirname, - refname + dirname.len, - (slash + 1) - (refname + dirname.len)); - subdir = search_for_subdir(dir, dirname.buf, mkdir); + subdir = search_for_subdir(dir, refname, dirnamelen, mkdir); if (!subdir) { dir = NULL; break; @@@ -408,7 -409,6 +420,6 @@@ dir = subdir; } - strbuf_release(&dirname); return dir; } @@@ -423,7 -423,7 +434,7 @@@ static struct ref_entry *find_ref(struc dir = find_containing_dir(dir, refname, 0); if (!dir) return NULL; - entry = search_ref_dir(dir, refname); + entry = search_ref_dir(dir, refname, strlen(refname)); return (entry && !(entry->flag & REF_DIR)) ? entry : NULL; } @@@ -833,7 -833,7 +844,7 @@@ static struct ref_dir *get_packed_refs( const char *packed_refs_file; FILE *f; - refs->packed = create_dir_entry(refs, "", 0); + refs->packed = create_dir_entry(refs, "", 0, 0); if (*refs->name) packed_refs_file = git_path_submodule(refs->name, "packed-refs"); else @@@ -898,7 -898,8 +909,8 @@@ static void read_loose_refs(const char } else if (S_ISDIR(st.st_mode)) { strbuf_addch(&refname, '/'); add_entry_to_dir(dir, - create_dir_entry(refs, refname.buf, 1)); + create_dir_entry(refs, refname.buf, + refname.len, 1)); } else { if (*refs->name) { hashclr(sha1); @@@ -928,12 -929,12 +940,12 @@@ static struct ref_dir *get_loose_refs(s * are about to read the only subdirectory that can * hold references: */ - refs->loose = create_dir_entry(refs, "", 0); + refs->loose = create_dir_entry(refs, "", 0, 0); /* * Create an incomplete entry for "refs/": */ add_entry_to_dir(get_ref_dir(refs->loose), - create_dir_entry(refs, "refs/", 1)); + create_dir_entry(refs, "refs/", 5, 1)); } return get_ref_dir(refs->loose); }