fetch: use oidset to keep the want OIDs for faster lookup

During git-fetch, the client checks if the advertised tags' OIDs are already in the fetch request's want OID set. This check is done in a linear scan. For a repository that has a lot of refs, repeating this scan takes 15+ minutes. In order to speed this up, create a oid_set for other refs' OIDs. Signed-off-by: Masaya Suzuki <masayasuzuki@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Masaya Suzuki committed Sep 15, 2019 at 14:18 UTC b7e2d8bca5412db7b1bd3a711db3693ca6674dd2
1 file changed +10 -8
builtin/fetch.c
+10 -8
@@ -7,6 +7,7 @@
7 #include "refs.h"
8 #include "refspec.h"
9 #include "object-store.h"
10 +#include "oidset.h"
11 #include "commit.h"
12 #include "builtin.h"
13 #include "string-list.h"
@@ -239,15 +240,13 @@ static void add_merge_config(struct ref **head,
240 }
241 }
242
242 -static int will_fetch(struct ref **head, const unsigned char *sha1)
243 +static void create_fetch_oidset(struct ref **head, struct oidset *out)
244 {
245 struct ref *rm = *head;
246 while (rm) {
246 - if (hasheq(rm->old_oid.hash, sha1))
247 - return 1;
247 + oidset_insert(out, &rm->old_oid);
248 rm = rm->next;
249 }
250 - return 0;
250 }
251
252 struct refname_hash_entry {
@@ -313,6 +312,7 @@ static void find_non_local_tags(const struct ref *refs,
312 {
313 struct hashmap existing_refs;
314 struct hashmap remote_refs;
315 + struct oidset fetch_oids = OIDSET_INIT;
316 struct string_list remote_refs_list = STRING_LIST_INIT_NODUP;
317 struct string_list_item *remote_ref_item;
318 const struct ref *ref;
@@ -320,6 +320,7 @@ static void find_non_local_tags(const struct ref *refs,
320
321 refname_hash_init(&existing_refs);
322 refname_hash_init(&remote_refs);
323 + create_fetch_oidset(head, &fetch_oids);
324
325 for_each_ref(add_one_refname, &existing_refs);
326 for (ref = refs; ref; ref = ref->next) {
@@ -336,9 +337,9 @@ static void find_non_local_tags(const struct ref *refs,
337 if (item &&
338 !has_object_file_with_flags(&ref->old_oid,
339 OBJECT_INFO_QUICK) &&
339 - !will_fetch(head, ref->old_oid.hash) &&
340 + !oidset_contains(&fetch_oids, &ref->old_oid) &&
341 !has_object_file_with_flags(&item->oid, OBJECT_INFO_QUICK) &&
341 - !will_fetch(head, item->oid.hash))
342 + !oidset_contains(&fetch_oids, &item->oid))
343 clear_item(item);
344 item = NULL;
345 continue;
@@ -352,7 +353,7 @@ static void find_non_local_tags(const struct ref *refs,
353 */
354 if (item &&
355 !has_object_file_with_flags(&item->oid, OBJECT_INFO_QUICK) &&
355 - !will_fetch(head, item->oid.hash))
356 + !oidset_contains(&fetch_oids, &item->oid))
357 clear_item(item);
358
359 item = NULL;
@@ -373,7 +374,7 @@ static void find_non_local_tags(const struct ref *refs,
374 */
375 if (item &&
376 !has_object_file_with_flags(&item->oid, OBJECT_INFO_QUICK) &&
376 - !will_fetch(head, item->oid.hash))
377 + !oidset_contains(&fetch_oids, &item->oid))
378 clear_item(item);
379
380 /*
@@ -400,6 +401,7 @@ static void find_non_local_tags(const struct ref *refs,
401 }
402 hashmap_free(&remote_refs, 1);
403 string_list_clear(&remote_refs_list, 0);
404 + oidset_clear(&fetch_oids);
405 }
406
407 static struct ref *get_ref_map(struct remote *remote,