Skip to content

Commit 6969ac6

Browse files
committed
Merge branch 'ps/fetch-mirror-optim'
Various optimization for "git fetch". * ps/fetch-mirror-optim: refs/files-backend: optimize reading of symbolic refs remote: read symbolic refs via `refs_read_symbolic_ref()` refs: add ability for backends to special-case reading of symbolic refs fetch: avoid lookup of commits when not appending to FETCH_HEAD upload-pack: look up "want" lines via commit-graph
2 parents 47e0380 + 0a7b387 commit 6969ac6

File tree

10 files changed

+122
-33
lines changed

10 files changed

+122
-33
lines changed

builtin/fetch.c

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,7 +1146,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
11461146
want_status <= FETCH_HEAD_IGNORE;
11471147
want_status++) {
11481148
for (rm = ref_map; rm; rm = rm->next) {
1149-
struct commit *commit = NULL;
11501149
struct ref *ref = NULL;
11511150

11521151
if (rm->status == REF_STATUS_REJECT_SHALLOW) {
@@ -1157,21 +1156,34 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
11571156
}
11581157

11591158
/*
1160-
* References in "refs/tags/" are often going to point
1161-
* to annotated tags, which are not part of the
1162-
* commit-graph. We thus only try to look up refs in
1163-
* the graph which are not in that namespace to not
1164-
* regress performance in repositories with many
1165-
* annotated tags.
1159+
* When writing FETCH_HEAD we need to determine whether
1160+
* we already have the commit or not. If not, then the
1161+
* reference is not for merge and needs to be written
1162+
* to the reflog after other commits which we already
1163+
* have. We're not interested in this property though
1164+
* in case FETCH_HEAD is not to be updated, so we can
1165+
* skip the classification in that case.
11661166
*/
1167-
if (!starts_with(rm->name, "refs/tags/"))
1168-
commit = lookup_commit_in_graph(the_repository, &rm->old_oid);
1169-
if (!commit) {
1170-
commit = lookup_commit_reference_gently(the_repository,
1171-
&rm->old_oid,
1172-
1);
1173-
if (!commit)
1174-
rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
1167+
if (fetch_head->fp) {
1168+
struct commit *commit = NULL;
1169+
1170+
/*
1171+
* References in "refs/tags/" are often going to point
1172+
* to annotated tags, which are not part of the
1173+
* commit-graph. We thus only try to look up refs in
1174+
* the graph which are not in that namespace to not
1175+
* regress performance in repositories with many
1176+
* annotated tags.
1177+
*/
1178+
if (!starts_with(rm->name, "refs/tags/"))
1179+
commit = lookup_commit_in_graph(the_repository, &rm->old_oid);
1180+
if (!commit) {
1181+
commit = lookup_commit_reference_gently(the_repository,
1182+
&rm->old_oid,
1183+
1);
1184+
if (!commit)
1185+
rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
1186+
}
11751187
}
11761188

11771189
if (rm->fetch_head_status != want_status)

builtin/remote.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -766,13 +766,15 @@ static int mv(int argc, const char **argv)
766766
for_each_ref(read_remote_branches, &rename);
767767
for (i = 0; i < remote_branches.nr; i++) {
768768
struct string_list_item *item = remote_branches.items + i;
769-
int flag = 0;
769+
struct strbuf referent = STRBUF_INIT;
770770

771-
read_ref_full(item->string, RESOLVE_REF_READING, NULL, &flag);
772-
if (!(flag & REF_ISSYMREF))
771+
if (refs_read_symbolic_ref(get_main_ref_store(the_repository), item->string,
772+
&referent))
773773
continue;
774774
if (delete_ref(NULL, item->string, NULL, REF_NO_DEREF))
775775
die(_("deleting '%s' failed"), item->string);
776+
777+
strbuf_release(&referent);
776778
}
777779
for (i = 0; i < remote_branches.nr; i++) {
778780
struct string_list_item *item = remote_branches.items + i;

refs.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1673,6 +1673,23 @@ int refs_read_raw_ref(struct ref_store *ref_store, const char *refname,
16731673
type, failure_errno);
16741674
}
16751675

1676+
int refs_read_symbolic_ref(struct ref_store *ref_store, const char *refname,
1677+
struct strbuf *referent)
1678+
{
1679+
struct object_id oid;
1680+
int ret, failure_errno = 0;
1681+
unsigned int type = 0;
1682+
1683+
if (ref_store->be->read_symbolic_ref)
1684+
return ref_store->be->read_symbolic_ref(ref_store, refname, referent);
1685+
1686+
ret = refs_read_raw_ref(ref_store, refname, &oid, referent, &type, &failure_errno);
1687+
if (ret || !(type & REF_ISSYMREF))
1688+
return -1;
1689+
1690+
return 0;
1691+
}
1692+
16761693
const char *refs_resolve_ref_unsafe(struct ref_store *refs,
16771694
const char *refname,
16781695
int resolve_flags,

refs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ int read_ref_full(const char *refname, int resolve_flags,
8282
struct object_id *oid, int *flags);
8383
int read_ref(const char *refname, struct object_id *oid);
8484

85+
int refs_read_symbolic_ref(struct ref_store *ref_store, const char *refname,
86+
struct strbuf *referent);
87+
8588
/*
8689
* Return 0 if a reference named refname could be created without
8790
* conflicting with the name of an existing reference. Otherwise,

refs/debug.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ struct ref_storage_be refs_be_debug = {
435435

436436
debug_ref_iterator_begin,
437437
debug_read_raw_ref,
438+
NULL,
438439

439440
debug_reflog_iterator_begin,
440441
debug_for_each_reflog_ent,

refs/files-backend.c

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -338,9 +338,9 @@ static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs)
338338
return refs->loose;
339339
}
340340

341-
static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
342-
struct object_id *oid, struct strbuf *referent,
343-
unsigned int *type, int *failure_errno)
341+
static int read_ref_internal(struct ref_store *ref_store, const char *refname,
342+
struct object_id *oid, struct strbuf *referent,
343+
unsigned int *type, int *failure_errno, int skip_packed_refs)
344344
{
345345
struct files_ref_store *refs =
346346
files_downcast(ref_store, REF_STORE_READ, "read_raw_ref");
@@ -381,7 +381,7 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
381381
if (lstat(path, &st) < 0) {
382382
int ignore_errno;
383383
myerr = errno;
384-
if (myerr != ENOENT)
384+
if (myerr != ENOENT || skip_packed_refs)
385385
goto out;
386386
if (refs_read_raw_ref(refs->packed_ref_store, refname, oid,
387387
referent, type, &ignore_errno)) {
@@ -425,7 +425,8 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
425425
* ref is supposed to be, there could still be a
426426
* packed ref:
427427
*/
428-
if (refs_read_raw_ref(refs->packed_ref_store, refname, oid,
428+
if (skip_packed_refs ||
429+
refs_read_raw_ref(refs->packed_ref_store, refname, oid,
429430
referent, type, &ignore_errno)) {
430431
myerr = EISDIR;
431432
goto out;
@@ -470,6 +471,27 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
470471
return ret;
471472
}
472473

474+
static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
475+
struct object_id *oid, struct strbuf *referent,
476+
unsigned int *type, int *failure_errno)
477+
{
478+
return read_ref_internal(ref_store, refname, oid, referent, type, failure_errno, 0);
479+
}
480+
481+
static int files_read_symbolic_ref(struct ref_store *ref_store, const char *refname,
482+
struct strbuf *referent)
483+
{
484+
struct object_id oid;
485+
int failure_errno, ret;
486+
unsigned int type;
487+
488+
ret = read_ref_internal(ref_store, refname, &oid, referent, &type, &failure_errno, 1);
489+
if (ret)
490+
return ret;
491+
492+
return !(type & REF_ISSYMREF);
493+
}
494+
473495
int parse_loose_ref_contents(const char *buf, struct object_id *oid,
474496
struct strbuf *referent, unsigned int *type,
475497
int *failure_errno)
@@ -3286,6 +3308,7 @@ struct ref_storage_be refs_be_files = {
32863308

32873309
files_ref_iterator_begin,
32883310
files_read_raw_ref,
3311+
files_read_symbolic_ref,
32893312

32903313
files_reflog_iterator_begin,
32913314
files_for_each_reflog_ent,

refs/packed-backend.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,6 +1684,7 @@ struct ref_storage_be refs_be_packed = {
16841684

16851685
packed_ref_iterator_begin,
16861686
packed_read_raw_ref,
1687+
NULL,
16871688

16881689
packed_reflog_iterator_begin,
16891690
packed_for_each_reflog_ent,

refs/refs-internal.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,21 @@ typedef int read_raw_ref_fn(struct ref_store *ref_store, const char *refname,
649649
struct object_id *oid, struct strbuf *referent,
650650
unsigned int *type, int *failure_errno);
651651

652+
/*
653+
* Read a symbolic reference from the specified reference store. This function
654+
* is optional: if not implemented by a backend, then `read_raw_ref_fn` is used
655+
* to read the symbolcic reference instead. It is intended to be implemented
656+
* only in case the backend can optimize the reading of symbolic references.
657+
*
658+
* Return 0 on success, or -1 on failure. `referent` will be set to the target
659+
* of the symbolic reference on success. This function explicitly does not
660+
* distinguish between error cases and the reference not being a symbolic
661+
* reference to allow backends to optimize this operation in case symbolic and
662+
* non-symbolic references are treated differently.
663+
*/
664+
typedef int read_symbolic_ref_fn(struct ref_store *ref_store, const char *refname,
665+
struct strbuf *referent);
666+
652667
struct ref_storage_be {
653668
struct ref_storage_be *next;
654669
const char *name;
@@ -668,6 +683,7 @@ struct ref_storage_be {
668683

669684
ref_iterator_begin_fn *iterator_begin;
670685
read_raw_ref_fn *read_raw_ref;
686+
read_symbolic_ref_fn *read_symbolic_ref;
671687

672688
reflog_iterator_begin_fn *reflog_iterator_begin;
673689
for_each_reflog_ent_fn *for_each_reflog_ent;

remote.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1945,13 +1945,9 @@ const char *branch_get_push(struct branch *branch, struct strbuf *err)
19451945
return branch->push_tracking_ref;
19461946
}
19471947

1948-
static int ignore_symref_update(const char *refname)
1948+
static int ignore_symref_update(const char *refname, struct strbuf *scratch)
19491949
{
1950-
int flag;
1951-
1952-
if (!resolve_ref_unsafe(refname, 0, NULL, &flag))
1953-
return 0; /* non-existing refs are OK */
1954-
return (flag & REF_ISSYMREF);
1950+
return !refs_read_symbolic_ref(get_main_ref_store(the_repository), refname, scratch);
19551951
}
19561952

19571953
/*
@@ -1964,18 +1960,21 @@ static int ignore_symref_update(const char *refname)
19641960
static struct ref *get_expanded_map(const struct ref *remote_refs,
19651961
const struct refspec_item *refspec)
19661962
{
1963+
struct strbuf scratch = STRBUF_INIT;
19671964
const struct ref *ref;
19681965
struct ref *ret = NULL;
19691966
struct ref **tail = &ret;
19701967

19711968
for (ref = remote_refs; ref; ref = ref->next) {
19721969
char *expn_name = NULL;
19731970

1971+
strbuf_reset(&scratch);
1972+
19741973
if (strchr(ref->name, '^'))
19751974
continue; /* a dereference item */
19761975
if (match_name_with_pattern(refspec->src, ref->name,
19771976
refspec->dst, &expn_name) &&
1978-
!ignore_symref_update(expn_name)) {
1977+
!ignore_symref_update(expn_name, &scratch)) {
19791978
struct ref *cpy = copy_ref(ref);
19801979

19811980
cpy->peer_ref = alloc_ref(expn_name);
@@ -1987,6 +1986,7 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
19871986
free(expn_name);
19881987
}
19891988

1989+
strbuf_release(&scratch);
19901990
return ret;
19911991
}
19921992

upload-pack.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,13 +1400,19 @@ static int parse_want(struct packet_writer *writer, const char *line,
14001400
const char *arg;
14011401
if (skip_prefix(line, "want ", &arg)) {
14021402
struct object_id oid;
1403+
struct commit *commit;
14031404
struct object *o;
14041405

14051406
if (get_oid_hex(arg, &oid))
14061407
die("git upload-pack: protocol error, "
14071408
"expected to get oid, not '%s'", line);
14081409

1409-
o = parse_object(the_repository, &oid);
1410+
commit = lookup_commit_in_graph(the_repository, &oid);
1411+
if (commit)
1412+
o = &commit->object;
1413+
else
1414+
o = parse_object(the_repository, &oid);
1415+
14101416
if (!o) {
14111417
packet_writer_error(writer,
14121418
"upload-pack: not our ref %s",
@@ -1434,7 +1440,7 @@ static int parse_want_ref(struct packet_writer *writer, const char *line,
14341440
if (skip_prefix(line, "want-ref ", &refname_nons)) {
14351441
struct object_id oid;
14361442
struct string_list_item *item;
1437-
struct object *o;
1443+
struct object *o = NULL;
14381444
struct strbuf refname = STRBUF_INIT;
14391445

14401446
strbuf_addf(&refname, "%s%s", get_git_namespace(), refname_nons);
@@ -1448,7 +1454,15 @@ static int parse_want_ref(struct packet_writer *writer, const char *line,
14481454
item = string_list_append(wanted_refs, refname_nons);
14491455
item->util = oiddup(&oid);
14501456

1451-
o = parse_object_or_die(&oid, refname_nons);
1457+
if (!starts_with(refname_nons, "refs/tags/")) {
1458+
struct commit *commit = lookup_commit_in_graph(the_repository, &oid);
1459+
if (commit)
1460+
o = &commit->object;
1461+
}
1462+
1463+
if (!o)
1464+
o = parse_object_or_die(&oid, refname_nons);
1465+
14521466
if (!(o->flags & WANTED)) {
14531467
o->flags |= WANTED;
14541468
add_object_array(o, NULL, want_obj);

0 commit comments

Comments
 (0)