Skip to content

Commit db1a848

Browse files
committed
Merge branch 'bc/push-match-many-refs'
Pushing to repositories with many refs employed O(m*n) algorithm where n is the number of refs on the receiving end. * bc/push-match-many-refs: remote.c: avoid O(m*n) behavior in match_push_refs
2 parents afbfcaa + f1bd15a commit db1a848

File tree

1 file changed

+25
-2
lines changed

1 file changed

+25
-2
lines changed

remote.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,14 @@ static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***ds
13021302
free(sent_tips.tip);
13031303
}
13041304

1305+
static void prepare_ref_index(struct string_list *ref_index, struct ref *ref)
1306+
{
1307+
for ( ; ref; ref = ref->next)
1308+
string_list_append_nodup(ref_index, ref->name)->util = ref;
1309+
1310+
sort_string_list(ref_index);
1311+
}
1312+
13051313
/*
13061314
* Given the set of refs the local repository has, the set of refs the
13071315
* remote repository has, and the refspec used for push, determine
@@ -1320,6 +1328,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
13201328
int errs;
13211329
static const char *default_refspec[] = { ":", NULL };
13221330
struct ref *ref, **dst_tail = tail_ref(dst);
1331+
struct string_list dst_ref_index = STRING_LIST_INIT_NODUP;
13231332

13241333
if (!nr_refspec) {
13251334
nr_refspec = 1;
@@ -1330,6 +1339,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
13301339

13311340
/* pick the remainder */
13321341
for (ref = src; ref; ref = ref->next) {
1342+
struct string_list_item *dst_item;
13331343
struct ref *dst_peer;
13341344
const struct refspec *pat = NULL;
13351345
char *dst_name;
@@ -1338,7 +1348,11 @@ int match_push_refs(struct ref *src, struct ref **dst,
13381348
if (!dst_name)
13391349
continue;
13401350

1341-
dst_peer = find_ref_by_name(*dst, dst_name);
1351+
if (!dst_ref_index.nr)
1352+
prepare_ref_index(&dst_ref_index, *dst);
1353+
1354+
dst_item = string_list_lookup(&dst_ref_index, dst_name);
1355+
dst_peer = dst_item ? dst_item->util : NULL;
13421356
if (dst_peer) {
13431357
if (dst_peer->peer_ref)
13441358
/* We're already sending something to this ref. */
@@ -1355,17 +1369,22 @@ int match_push_refs(struct ref *src, struct ref **dst,
13551369
/* Create a new one and link it */
13561370
dst_peer = make_linked_ref(dst_name, &dst_tail);
13571371
hashcpy(dst_peer->new_sha1, ref->new_sha1);
1372+
string_list_insert(&dst_ref_index,
1373+
dst_peer->name)->util = dst_peer;
13581374
}
13591375
dst_peer->peer_ref = copy_ref(ref);
13601376
dst_peer->force = pat->force;
13611377
free_name:
13621378
free(dst_name);
13631379
}
13641380

1381+
string_list_clear(&dst_ref_index, 0);
1382+
13651383
if (flags & MATCH_REFS_FOLLOW_TAGS)
13661384
add_missing_tags(src, dst, &dst_tail);
13671385

13681386
if (send_prune) {
1387+
struct string_list src_ref_index = STRING_LIST_INIT_NODUP;
13691388
/* check for missing refs on the remote */
13701389
for (ref = *dst; ref; ref = ref->next) {
13711390
char *src_name;
@@ -1376,11 +1395,15 @@ int match_push_refs(struct ref *src, struct ref **dst,
13761395

13771396
src_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_DST, NULL);
13781397
if (src_name) {
1379-
if (!find_ref_by_name(src, src_name))
1398+
if (!src_ref_index.nr)
1399+
prepare_ref_index(&src_ref_index, src);
1400+
if (!string_list_has_string(&src_ref_index,
1401+
src_name))
13801402
ref->peer_ref = alloc_delete_ref();
13811403
free(src_name);
13821404
}
13831405
}
1406+
string_list_clear(&src_ref_index, 0);
13841407
}
13851408
if (errs)
13861409
return -1;

0 commit comments

Comments
 (0)