remote: Make ref_remove_duplicates faster for large numbers of refs
The ref_remove_duplicates function was very slow at dealing with very large numbers of refs. This is because it was using a linear search through all remaining refs to find any duplicates of the current ref. Rewriting it to use a string list to keep track of which refs have already been seen and removing duplicates when they are found is much more efficient. Signed-off-by: Julian Phillips <julian@quantumfyre.co.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Julian Phillips committed
Oct 25, 2009 at 21:28 UTC
73cf0822b2a4ffa7ad559d1f0772e39718fc7776
1 file changed
+22
-19
remote.c
+22
-19
@@ -6,6 +6,7 @@
6
#include "revision.h"
7
#include "dir.h"
8
#include "tag.h"
9
+#include "string-list.h"
10
11
static struct refspec s_tag_refspec = {
12
0,
@@ -734,29 +735,31 @@ int for_each_remote(each_remote_fn fn, void *priv)
735
736
void ref_remove_duplicates(struct ref *ref_map)
737
{
737
- struct ref **posn;
738
- struct ref *next;
739
- for (; ref_map; ref_map = ref_map->next) {
738
+ struct string_list refs = { NULL, 0, 0, 0 };
739
+ struct string_list_item *item = NULL;
740
+ struct ref *prev = NULL, *next = NULL;
741
+ for (; ref_map; prev = ref_map, ref_map = next) {
742
+ next = ref_map->next;
743
if (!ref_map->peer_ref)
744
continue;
742
- posn = &ref_map->next;
743
- while (*posn) {
744
- if ((*posn)->peer_ref &&
745
- !strcmp((*posn)->peer_ref->name,
746
- ref_map->peer_ref->name)) {
747
- if (strcmp((*posn)->name, ref_map->name))
748
- die("%s tracks both %s and %s",
749
- ref_map->peer_ref->name,
750
- (*posn)->name, ref_map->name);
751
- next = (*posn)->next;
752
- free((*posn)->peer_ref);
753
- free(*posn);
754
- *posn = next;
755
- } else {
756
- posn = &(*posn)->next;
757
- }
745
+
746
+ item = string_list_lookup(ref_map->peer_ref->name, &refs);
747
+ if (item) {
748
+ if (strcmp(((struct ref *)item->util)->name,
749
+ ref_map->name))
750
+ die("%s tracks both %s and %s",
751
+ ref_map->peer_ref->name,
752
+ ((struct ref *)item->util)->name,
753
+ ref_map->name);
754
+ prev->next = ref_map->next;
755
+ free(ref_map->peer_ref);
756
+ free(ref_map);
757
}
758
+
759
+ item = string_list_insert(ref_map->peer_ref->name, &refs);
760
+ item->util = ref_map;
761
}
762
+ string_list_clear(&refs, 0);
763
}
764
765
int remote_has_url(struct remote *remote, const char *url)