refs.c: add a function to sort a ref list, rather then sorting on add

Rather than sorting the refs list while building it, sort in one
go after it is built using a merge sort.  This has a large
performance boost with large numbers of refs.

It shouldn't happen that we read duplicate entries into the same
list, but just in case sort_ref_list drops them if the SHA1s are
the same, or dies, as we have no way of knowing which one is the
correct one.

Signed-off-by: Julian Phillips <julian@quantumfyre.co.uk>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
Julian Phillips 2007-04-17 02:42:50 +01:00 коммит произвёл Junio C Hamano
Родитель 6fb8e8f401
Коммит c774aab98c
1 изменённых файлов: 89 добавлений и 21 удалений

110
refs.c
Просмотреть файл

@ -47,22 +47,7 @@ static struct ref_list *add_ref(const char *name, const unsigned char *sha1,
struct ref_list **new_entry)
{
int len;
struct ref_list **p = &list, *entry;
/* Find the place to insert the ref into.. */
while ((entry = *p) != NULL) {
int cmp = strcmp(entry->name, name);
if (cmp > 0)
break;
/* Same as existing entry? */
if (!cmp) {
if (new_entry)
*new_entry = entry;
return list;
}
p = &entry->next;
}
struct ref_list *entry;
/* Allocate it and add it in.. */
len = strlen(name) + 1;
@ -71,11 +56,94 @@ static struct ref_list *add_ref(const char *name, const unsigned char *sha1,
hashclr(entry->peeled);
memcpy(entry->name, name, len);
entry->flag = flag;
entry->next = *p;
*p = entry;
entry->next = list;
if (new_entry)
*new_entry = entry;
return list;
return entry;
}
/* merge sort the ref list */
static struct ref_list *sort_ref_list(struct ref_list *list)
{
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;
if (!list)
return list;
do {
last_merge_count = merge_count;
merge_count = 0;
psize = 0;
p = new_list;
q = new_list;
new_list = NULL;
l = NULL;
while (p) {
merge_count++;
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--;
}
}
e->next = NULL;
if (l)
l->next = e;
if (!new_list)
new_list = e;
l = e;
}
p = q;
};
k = k * 2;
} while ((last_merge_count != merge_count) || (last_merge_count != 1));
return new_list;
}
/*
@ -142,7 +210,7 @@ static void read_packed_refs(FILE *f, struct cached_refs *cached_refs)
!get_sha1_hex(refline + 1, sha1))
hashcpy(last->peeled, sha1);
}
cached_refs->packed = list;
cached_refs->packed = sort_ref_list(list);
}
static struct ref_list *get_packed_refs(void)
@ -201,7 +269,7 @@ static struct ref_list *get_ref_dir(const char *base, struct ref_list *list)
free(ref);
closedir(dir);
}
return list;
return sort_ref_list(list);
}
static struct ref_list *get_loose_refs(void)