author | Junio C Hamano <gitster@pobox.com> | |
Mon, 10 Oct 2011 22:56:19 +0000 (15:56 -0700) | ||
committer | Junio C Hamano <gitster@pobox.com> | |
Mon, 10 Oct 2011 22:56:19 +0000 (15:56 -0700) |
* 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
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
1 | 2 | |||
---|---|---|---|---|
refs.c | patch | | diff1 | | diff2 | | blob | history |
refs.h | patch | | diff1 | | diff2 | | blob | history |
diff --cc refs.c
index 8c69243b2a04224e75ca34bed404782fbb4b9885,df392976043c9ef025b3c55469810d768eddf794..9911c97b69a66ba0a4c7d3aff33b9d7b1d006796
+++ b/refs.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;
}
/*
* 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;
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 &&
!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)
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;
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 */
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;
}
}
/*
- * 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.
*/
- struct ref_list *list = get_packed_refs(NULL);
- while (list) {
- if (!strcmp(ref, list->name)) {
- hashcpy(sha1, list->sha1);
- return 0;
- }
- list = list->next;
+static int get_packed_ref(const char *ref, unsigned char *sha1)
+{
++ 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;
#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)) {
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 d5ac133336dc0da45cd916207d12a5e0e4237ae3,5e7a9a59f5f6b687d15eb37a11696433bdc8f15c..0229c57132f53b85e4d6af8b62627383a49527ac
+++ b/refs.h
*/
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 *);