From: Junio C Hamano Date: Mon, 10 Oct 2011 22:56:19 +0000 (-0700) Subject: Merge branch 'jp/get-ref-dir-unsorted' X-Git-Tag: v1.7.8-rc0~106 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=2c5c66be6ecdd10f5a88c3548a1494bf9edf483a;p=git.git Merge branch 'jp/get-ref-dir-unsorted' * jp/get-ref-dir-unsorted: refs.c: free duplicate entries in the ref array instead of leaking them refs.c: abort ref search if ref array is empty refs.c: ensure struct whose member may be passed to realloc is initialized refs: Use binary search to lookup refs faster Don't sort ref_list too early Conflicts: refs.c --- 2c5c66be6ecdd10f5a88c3548a1494bf9edf483a diff --cc refs.c index 8c69243b2,df3929760..9911c97b6 --- a/refs.c +++ b/refs.c @@@ -53,101 -57,75 +57,77 @@@ static void add_ref(const char *name, c /* Allocate it and add it in.. */ len = strlen(name) + 1; - entry = xmalloc(sizeof(struct ref_list) + len); + entry = xmalloc(sizeof(struct ref_entry) + len); hashcpy(entry->sha1, sha1); hashclr(entry->peeled); + if (check_refname_format(name, REFNAME_ALLOW_ONELEVEL|REFNAME_DOT_COMPONENT)) + die("Reference has invalid format: '%s'", name); memcpy(entry->name, name, len); entry->flag = flag; - entry->next = list; if (new_entry) *new_entry = entry; - return entry; + ALLOC_GROW(refs->refs, refs->nr + 1, refs->alloc); + refs->refs[refs->nr++] = entry; } - /* merge sort the ref list */ - static struct ref_list *sort_ref_list(struct ref_list *list) + static int ref_entry_cmp(const void *a, const void *b) { - int psize, qsize, last_merge_count, cmp; - struct ref_list *p, *q, *l, *e; - struct ref_list *new_list = list; - int k = 1; - int merge_count = 0; + struct ref_entry *one = *(struct ref_entry **)a; + struct ref_entry *two = *(struct ref_entry **)b; + return strcmp(one->name, two->name); + } - if (!list) - return list; + static void sort_ref_array(struct ref_array *array) + { + int i = 0, j = 1; - do { - last_merge_count = merge_count; - merge_count = 0; + /* Nothing to sort unless there are at least two entries */ + if (array->nr < 2) + return; - psize = 0; + qsort(array->refs, array->nr, sizeof(*array->refs), ref_entry_cmp); - p = new_list; - q = new_list; - new_list = NULL; - l = NULL; + /* Remove any duplicates from the ref_array */ + for (; j < array->nr; j++) { + struct ref_entry *a = array->refs[i]; + struct ref_entry *b = array->refs[j]; + if (!strcmp(a->name, b->name)) { + if (hashcmp(a->sha1, b->sha1)) + die("Duplicated ref, and SHA1s don't match: %s", + a->name); + warning("Duplicated ref: %s", a->name); + free(b); + continue; + } + i++; + array->refs[i] = array->refs[j]; + } + array->nr = i + 1; + } - while (p) { - merge_count++; + static struct ref_entry *search_ref_array(struct ref_array *array, const char *name) + { + struct ref_entry *e, **r; + int len; - while (psize < k && q->next) { - q = q->next; - psize++; - } - qsize = k; - - while ((psize > 0) || (qsize > 0 && q)) { - if (qsize == 0 || !q) { - e = p; - p = p->next; - psize--; - } else if (psize == 0) { - e = q; - q = q->next; - qsize--; - } else { - cmp = strcmp(q->name, p->name); - if (cmp < 0) { - e = q; - q = q->next; - qsize--; - } else if (cmp > 0) { - e = p; - p = p->next; - psize--; - } else { - if (hashcmp(q->sha1, p->sha1)) - die("Duplicated ref, and SHA1s don't match: %s", - q->name); - warning("Duplicated ref: %s", q->name); - e = q; - q = q->next; - qsize--; - free(e); - e = p; - p = p->next; - psize--; - } - } + if (name == NULL) + return NULL; - e->next = NULL; + if (!array->nr) + return NULL; - if (l) - l->next = e; - if (!new_list) - new_list = e; - l = e; - } + len = strlen(name) + 1; + e = xmalloc(sizeof(struct ref_entry) + len); + memcpy(e->name, name, len); + + r = bsearch(&e, array->refs, array->nr, sizeof(*array->refs), ref_entry_cmp); - p = q; - }; + free(e); - k = k * 2; - } while ((last_merge_count != merge_count) || (last_merge_count != 1)); + if (r == NULL) + return NULL; - return new_list; + return *r; } /* @@@ -155,89 -133,39 +135,85 @@@ * when doing a full libification. */ static struct cached_refs { + struct cached_refs *next; char did_loose; char did_packed; - struct ref_list *loose; - struct ref_list *packed; + struct ref_array loose; + struct ref_array packed; -} cached_refs, submodule_refs; + /* The submodule name, or "" for the main repo. */ + char name[FLEX_ARRAY]; +} *cached_refs; + - static struct ref_list *current_ref; + static struct ref_entry *current_ref; - static struct ref_list *extra_refs; + static struct ref_array extra_refs; - static void free_ref_list(struct ref_list *list) + static void free_ref_array(struct ref_array *array) { - struct ref_list *next; - for ( ; list; list = next) { - next = list->next; - free(list); - } + int i; + for (i = 0; i < array->nr; i++) + free(array->refs[i]); + free(array->refs); + array->nr = array->alloc = 0; + array->refs = NULL; } -static void invalidate_cached_refs(void) +static void clear_cached_refs(struct cached_refs *ca) { - if (ca->did_loose && ca->loose) - free_ref_list(ca->loose); - if (ca->did_packed && ca->packed) - free_ref_list(ca->packed); - ca->loose = ca->packed = NULL; - struct cached_refs *ca = &cached_refs; - + if (ca->did_loose) + free_ref_array(&ca->loose); + if (ca->did_packed) + free_ref_array(&ca->packed); ca->did_loose = ca->did_packed = 0; } -static void read_packed_refs(FILE *f, struct cached_refs *cached_refs) +static struct cached_refs *create_cached_refs(const char *submodule) +{ + int len; + struct cached_refs *refs; + if (!submodule) + submodule = ""; + len = strlen(submodule) + 1; - refs = xmalloc(sizeof(struct cached_refs) + len); - refs->next = NULL; - refs->did_loose = refs->did_packed = 0; - refs->loose = refs->packed = NULL; ++ refs = xcalloc(1, sizeof(struct cached_refs) + len); + memcpy(refs->name, submodule, len); + return refs; +} + +/* + * Return a pointer to a cached_refs for the specified submodule. For + * the main repository, use submodule==NULL. The returned structure + * will be allocated and initialized but not necessarily populated; it + * should not be freed. + */ +static struct cached_refs *get_cached_refs(const char *submodule) +{ + struct cached_refs *refs = cached_refs; + if (!submodule) + submodule = ""; + while (refs) { + if (!strcmp(submodule, refs->name)) + return refs; + refs = refs->next; + } + + refs = create_cached_refs(submodule); + refs->next = cached_refs; + cached_refs = refs; + return refs; +} + +static void invalidate_cached_refs(void) +{ + struct cached_refs *refs = cached_refs; + while (refs) { + clear_cached_refs(refs); + refs = refs->next; + } +} + - static struct ref_list *read_packed_refs(FILE *f) ++static void read_packed_refs(FILE *f, struct ref_array *array) { - struct ref_list *list = NULL; - struct ref_list *last = NULL; + struct ref_entry *last = NULL; char refline[PATH_MAX]; int flag = REF_ISPACKED; @@@ -256,7 -184,7 +232,7 @@@ name = parse_ref_line(refline, sha1); if (name) { - list = add_ref(name, sha1, flag, list, &last); - add_ref(name, sha1, flag, &cached_refs->packed, &last); ++ add_ref(name, sha1, flag, array, &last); continue; } if (last && @@@ -266,7 -194,7 +242,7 @@@ !get_sha1_hex(refline + 1, sha1)) hashcpy(last->peeled, sha1); } - return sort_ref_list(list); - sort_ref_array(&cached_refs->packed); ++ sort_ref_array(array); } void add_extra_ref(const char *name, const unsigned char *sha1, int flag) @@@ -276,26 -204,27 +252,24 @@@ void clear_extra_refs(void) { - free_ref_list(extra_refs); - extra_refs = NULL; + free_ref_array(&extra_refs); } - static struct ref_list *get_packed_refs(const char *submodule) + static struct ref_array *get_packed_refs(const char *submodule) { - const char *packed_refs_file; - struct cached_refs *refs; + struct cached_refs *refs = get_cached_refs(submodule); - if (submodule) { - packed_refs_file = git_path_submodule(submodule, "packed-refs"); - refs = &submodule_refs; - free_ref_array(&refs->packed); - } else { - packed_refs_file = git_path("packed-refs"); - refs = &cached_refs; - } + if (!refs->did_packed) { + const char *packed_refs_file; + FILE *f; - if (!refs->did_packed || submodule) { - FILE *f = fopen(packed_refs_file, "r"); + if (submodule) + packed_refs_file = git_path_submodule(submodule, "packed-refs"); + else + packed_refs_file = git_path("packed-refs"); + f = fopen(packed_refs_file, "r"); - refs->packed = NULL; if (f) { - refs->packed = read_packed_refs(f); - read_packed_refs(f, refs); ++ read_packed_refs(f, &refs->packed); fclose(f); } refs->did_packed = 1; @@@ -404,15 -332,21 +377,16 @@@ void warn_dangling_symref(FILE *fp, con for_each_rawref(warn_if_dangling_symref, &data); } - static struct ref_list *get_loose_refs(const char *submodule) + static struct ref_array *get_loose_refs(const char *submodule) { - if (submodule) { - free_ref_array(&submodule_refs.loose); - get_ref_dir(submodule, "refs", &submodule_refs.loose); - sort_ref_array(&submodule_refs.loose); - return &submodule_refs.loose; - } + struct cached_refs *refs = get_cached_refs(submodule); - if (!cached_refs.did_loose) { - get_ref_dir(NULL, "refs", &cached_refs.loose); - sort_ref_array(&cached_refs.loose); - cached_refs.did_loose = 1; + if (!refs->did_loose) { - refs->loose = get_ref_dir(submodule, "refs", NULL); ++ get_ref_dir(submodule, "refs", &refs->loose); ++ sort_ref_array(&refs->loose); + refs->did_loose = 1; } - return refs->loose; - return &cached_refs.loose; ++ return &refs->loose; } /* We allow "recursive" symbolic refs. Only within reason, though */ @@@ -421,28 -355,24 +395,15 @@@ static int resolve_gitlink_packed_ref(char *name, int pathlen, const char *refname, unsigned char *result) { -- FILE *f; - struct ref_list *packed_refs; - struct ref_list *ref; - int retval; - struct cached_refs refs; - struct ref_entry *ref; + int retval = -1; ++ struct ref_entry *ref; ++ struct ref_array *array = get_packed_refs(name); -- strcpy(name + pathlen, "packed-refs"); -- f = fopen(name, "r"); -- if (!f) -- return -1; - packed_refs = read_packed_refs(f); - memset(&refs, 0, sizeof(refs)); - read_packed_refs(f, &refs); -- fclose(f); - ref = packed_refs; - retval = -1; - while (ref) { - if (!strcmp(ref->name, refname)) { - retval = 0; - memcpy(result, ref->sha1, 20); - break; - } - ref = ref->next; - ref = search_ref_array(&refs.packed, refname); ++ ref = search_ref_array(array, refname); + if (ref != NULL) { + memcpy(result, ref->sha1, 20); + retval = 0; } - free_ref_list(packed_refs); - free_ref_array(&refs.packed); return retval; } @@@ -510,22 -440,17 +471,20 @@@ int resolve_gitlink_ref(const char *pat } /* - * If the "reading" argument is set, this function finds out what _object_ - * the ref points at by "reading" the ref. The ref, if it is not symbolic, - * has to exist, and if it is symbolic, it has to point at an existing ref, - * because the "read" goes through the symref to the ref it points at. - * - * The access that is not "reading" may often be "writing", but does not - * have to; it can be merely checking _where it leads to_. If it is a - * prelude to "writing" to the ref, a write to a symref that points at - * yet-to-be-born ref will create the real ref pointed by the symref. - * reading=0 allows the caller to check where such a symref leads to. + * Try to read ref from the packed references. On success, set sha1 + * and return 0; otherwise, return -1. */ +static int get_packed_ref(const char *ref, unsigned char *sha1) +{ - struct ref_list *list = get_packed_refs(NULL); - while (list) { - if (!strcmp(ref, list->name)) { - hashcpy(sha1, list->sha1); - return 0; - } - list = list->next; ++ struct ref_array *packed = get_packed_refs(NULL); ++ struct ref_entry *entry = search_ref_array(packed, ref); ++ if (entry) { ++ hashcpy(sha1, entry->sha1); ++ return 0; + } + return -1; +} + const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag) { int depth = MAXDEPTH; @@@ -649,9 -554,9 +608,9 @@@ int read_ref(const char *ref, unsigned #define DO_FOR_EACH_INCLUDE_BROKEN 01 static int do_one_ref(const char *base, each_ref_fn fn, int trim, - int flags, void *cb_data, struct ref_list *entry) + int flags, void *cb_data, struct ref_entry *entry) { - if (strncmp(base, entry->name, trim)) + if (prefixcmp(entry->name, base)) return 0; if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN)) { @@@ -1931,12 -1792,6 +1884,12 @@@ int update_ref(const char *action, cons return 0; } - int ref_exists(char *refname) ++int ref_exists(const char *refname) +{ + unsigned char sha1[20]; + return !!resolve_ref(refname, sha1, 1, NULL); +} + struct ref *find_ref_by_name(const struct ref *list, const char *name) { for ( ; list; list = list->next) diff --cc refs.h index d5ac13333,5e7a9a59f..0229c5713 --- a/refs.h +++ b/refs.h @@@ -57,7 -54,6 +57,7 @@@ extern void warn_dangling_symref(FILE * */ extern void add_extra_ref(const char *refname, const unsigned char *sha1, int flags); extern void clear_extra_refs(void); - extern int ref_exists(char *); ++extern int ref_exists(const char *); extern int peel_ref(const char *, unsigned char *);