Merge branch 'jk/fetch-pack-remove-dups-optim'

The way "fetch-pack" that is given multiple references to fetch tried to
remove duplicates was very inefficient.

By Jeff King
* jk/fetch-pack-remove-dups-optim:
  fetch-pack: sort incoming heads list earlier
  fetch-pack: avoid quadratic loop in filter_refs
  fetch-pack: sort the list of incoming refs
  add sorting infrastructure for list refs
  fetch-pack: avoid quadratic behavior in remove_duplicates
  fetch-pack: sort incoming heads
This commit is contained in:
Junio C Hamano 2012-05-29 13:09:08 -07:00
Родитель a7060009e1 3d2a33e57f
Коммит 12d7d15074
3 изменённых файлов: 54 добавлений и 22 удалений

Просмотреть файл

@ -528,6 +528,7 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
struct ref **newtail = &newlist; struct ref **newtail = &newlist;
struct ref *ref, *next; struct ref *ref, *next;
struct ref *fastarray[32]; struct ref *fastarray[32];
int match_pos;
if (nr_match && !args.fetch_all) { if (nr_match && !args.fetch_all) {
if (ARRAY_SIZE(fastarray) < nr_match) if (ARRAY_SIZE(fastarray) < nr_match)
@ -540,6 +541,7 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
else else
return_refs = NULL; return_refs = NULL;
match_pos = 0;
for (ref = *refs; ref; ref = next) { for (ref = *refs; ref; ref = next) {
next = ref->next; next = ref->next;
if (!memcmp(ref->name, "refs/", 5) && if (!memcmp(ref->name, "refs/", 5) &&
@ -553,15 +555,20 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
continue; continue;
} }
else { else {
int i; int cmp = -1;
for (i = 0; i < nr_match; i++) { while (match_pos < nr_match) {
if (!strcmp(ref->name, match[i])) { cmp = strcmp(ref->name, match[match_pos]);
match[i][0] = '\0'; if (cmp < 0) /* definitely do not have it */
return_refs[i] = ref; break;
else if (cmp == 0) { /* definitely have it */
match[match_pos][0] = '\0';
return_refs[match_pos] = ref;
break; break;
} }
else /* might have it; keep looking */
match_pos++;
} }
if (i < nr_match) if (!cmp)
continue; /* we will link it later */ continue; /* we will link it later */
} }
free(ref); free(ref);
@ -777,6 +784,8 @@ static struct ref *do_fetch_pack(int fd[2],
struct ref *ref = copy_ref_list(orig_ref); struct ref *ref = copy_ref_list(orig_ref);
unsigned char sha1[20]; unsigned char sha1[20];
sort_ref_list(&ref, ref_compare_name);
if (is_repository_shallow() && !server_supports("shallow")) if (is_repository_shallow() && !server_supports("shallow"))
die("Server does not support shallow clients"); die("Server does not support shallow clients");
if (server_supports("multi_ack_detailed")) { if (server_supports("multi_ack_detailed")) {
@ -834,21 +843,12 @@ static int remove_duplicates(int nr_heads, char **heads)
{ {
int src, dst; int src, dst;
for (src = dst = 0; src < nr_heads; src++) { if (!nr_heads)
/* If heads[src] is different from any of return 0;
* heads[0..dst], push it in.
*/ for (src = dst = 1; src < nr_heads; src++)
int i; if (strcmp(heads[src], heads[dst-1]))
for (i = 0; i < dst; i++) { heads[dst++] = heads[src];
if (!strcmp(heads[i], heads[src]))
break;
}
if (i < dst)
continue;
if (src != dst)
heads[dst] = heads[src];
dst++;
}
return dst; return dst;
} }
@ -1054,6 +1054,11 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
return ret; return ret;
} }
static int compare_heads(const void *a, const void *b)
{
return strcmp(*(const char **)a, *(const char **)b);
}
struct ref *fetch_pack(struct fetch_pack_args *my_args, struct ref *fetch_pack(struct fetch_pack_args *my_args,
int fd[], struct child_process *conn, int fd[], struct child_process *conn,
const struct ref *ref, const struct ref *ref,
@ -1073,8 +1078,11 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
st.st_mtime = 0; st.st_mtime = 0;
} }
if (heads && nr_heads) if (heads && nr_heads) {
qsort(heads, nr_heads, sizeof(*heads), compare_heads);
nr_heads = remove_duplicates(nr_heads, heads); nr_heads = remove_duplicates(nr_heads, heads);
}
if (!ref) { if (!ref) {
packet_flush(fd[1]); packet_flush(fd[1]);
die("no matching remote head"); die("no matching remote head");

Просмотреть файл

@ -7,6 +7,7 @@
#include "dir.h" #include "dir.h"
#include "tag.h" #include "tag.h"
#include "string-list.h" #include "string-list.h"
#include "mergesort.h"
enum map_direction { FROM_SRC, FROM_DST }; enum map_direction { FROM_SRC, FROM_DST };
@ -918,6 +919,27 @@ void free_refs(struct ref *ref)
} }
} }
int ref_compare_name(const void *va, const void *vb)
{
const struct ref *a = va, *b = vb;
return strcmp(a->name, b->name);
}
static void *ref_list_get_next(const void *a)
{
return ((const struct ref *)a)->next;
}
static void ref_list_set_next(void *a, void *next)
{
((struct ref *)a)->next = next;
}
void sort_ref_list(struct ref **l, int (*cmp)(const void *, const void *))
{
*l = llist_mergesort(*l, ref_list_get_next, ref_list_set_next, cmp);
}
static int count_refspec_match(const char *pattern, static int count_refspec_match(const char *pattern,
struct ref *refs, struct ref *refs,
struct ref **matched_ref) struct ref **matched_ref)

Просмотреть файл

@ -72,6 +72,8 @@ extern const struct refspec *tag_refspec;
struct ref *alloc_ref(const char *name); struct ref *alloc_ref(const char *name);
struct ref *copy_ref(const struct ref *ref); struct ref *copy_ref(const struct ref *ref);
struct ref *copy_ref_list(const struct ref *ref); struct ref *copy_ref_list(const struct ref *ref);
void sort_ref_list(struct ref **, int (*cmp)(const void *, const void *));
int ref_compare_name(const void *, const void *);
int check_ref_type(const struct ref *ref, int flags); int check_ref_type(const struct ref *ref, int flags);