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
This commit is contained in:
commit
6969ac64bf
@ -1146,7 +1146,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
|
||||
want_status <= FETCH_HEAD_IGNORE;
|
||||
want_status++) {
|
||||
for (rm = ref_map; rm; rm = rm->next) {
|
||||
struct commit *commit = NULL;
|
||||
struct ref *ref = NULL;
|
||||
|
||||
if (rm->status == REF_STATUS_REJECT_SHALLOW) {
|
||||
@ -1157,21 +1156,34 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
|
||||
}
|
||||
|
||||
/*
|
||||
* References in "refs/tags/" are often going to point
|
||||
* to annotated tags, which are not part of the
|
||||
* commit-graph. We thus only try to look up refs in
|
||||
* the graph which are not in that namespace to not
|
||||
* regress performance in repositories with many
|
||||
* annotated tags.
|
||||
* When writing FETCH_HEAD we need to determine whether
|
||||
* we already have the commit or not. If not, then the
|
||||
* reference is not for merge and needs to be written
|
||||
* to the reflog after other commits which we already
|
||||
* have. We're not interested in this property though
|
||||
* in case FETCH_HEAD is not to be updated, so we can
|
||||
* skip the classification in that case.
|
||||
*/
|
||||
if (!starts_with(rm->name, "refs/tags/"))
|
||||
commit = lookup_commit_in_graph(the_repository, &rm->old_oid);
|
||||
if (!commit) {
|
||||
commit = lookup_commit_reference_gently(the_repository,
|
||||
&rm->old_oid,
|
||||
1);
|
||||
if (!commit)
|
||||
rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
|
||||
if (fetch_head->fp) {
|
||||
struct commit *commit = NULL;
|
||||
|
||||
/*
|
||||
* References in "refs/tags/" are often going to point
|
||||
* to annotated tags, which are not part of the
|
||||
* commit-graph. We thus only try to look up refs in
|
||||
* the graph which are not in that namespace to not
|
||||
* regress performance in repositories with many
|
||||
* annotated tags.
|
||||
*/
|
||||
if (!starts_with(rm->name, "refs/tags/"))
|
||||
commit = lookup_commit_in_graph(the_repository, &rm->old_oid);
|
||||
if (!commit) {
|
||||
commit = lookup_commit_reference_gently(the_repository,
|
||||
&rm->old_oid,
|
||||
1);
|
||||
if (!commit)
|
||||
rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
|
||||
}
|
||||
}
|
||||
|
||||
if (rm->fetch_head_status != want_status)
|
||||
|
@ -766,13 +766,15 @@ static int mv(int argc, const char **argv)
|
||||
for_each_ref(read_remote_branches, &rename);
|
||||
for (i = 0; i < remote_branches.nr; i++) {
|
||||
struct string_list_item *item = remote_branches.items + i;
|
||||
int flag = 0;
|
||||
struct strbuf referent = STRBUF_INIT;
|
||||
|
||||
read_ref_full(item->string, RESOLVE_REF_READING, NULL, &flag);
|
||||
if (!(flag & REF_ISSYMREF))
|
||||
if (refs_read_symbolic_ref(get_main_ref_store(the_repository), item->string,
|
||||
&referent))
|
||||
continue;
|
||||
if (delete_ref(NULL, item->string, NULL, REF_NO_DEREF))
|
||||
die(_("deleting '%s' failed"), item->string);
|
||||
|
||||
strbuf_release(&referent);
|
||||
}
|
||||
for (i = 0; i < remote_branches.nr; i++) {
|
||||
struct string_list_item *item = remote_branches.items + i;
|
||||
|
17
refs.c
17
refs.c
@ -1673,6 +1673,23 @@ int refs_read_raw_ref(struct ref_store *ref_store, const char *refname,
|
||||
type, failure_errno);
|
||||
}
|
||||
|
||||
int refs_read_symbolic_ref(struct ref_store *ref_store, const char *refname,
|
||||
struct strbuf *referent)
|
||||
{
|
||||
struct object_id oid;
|
||||
int ret, failure_errno = 0;
|
||||
unsigned int type = 0;
|
||||
|
||||
if (ref_store->be->read_symbolic_ref)
|
||||
return ref_store->be->read_symbolic_ref(ref_store, refname, referent);
|
||||
|
||||
ret = refs_read_raw_ref(ref_store, refname, &oid, referent, &type, &failure_errno);
|
||||
if (ret || !(type & REF_ISSYMREF))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *refs_resolve_ref_unsafe(struct ref_store *refs,
|
||||
const char *refname,
|
||||
int resolve_flags,
|
||||
|
3
refs.h
3
refs.h
@ -82,6 +82,9 @@ int read_ref_full(const char *refname, int resolve_flags,
|
||||
struct object_id *oid, int *flags);
|
||||
int read_ref(const char *refname, struct object_id *oid);
|
||||
|
||||
int refs_read_symbolic_ref(struct ref_store *ref_store, const char *refname,
|
||||
struct strbuf *referent);
|
||||
|
||||
/*
|
||||
* Return 0 if a reference named refname could be created without
|
||||
* conflicting with the name of an existing reference. Otherwise,
|
||||
|
@ -435,6 +435,7 @@ struct ref_storage_be refs_be_debug = {
|
||||
|
||||
debug_ref_iterator_begin,
|
||||
debug_read_raw_ref,
|
||||
NULL,
|
||||
|
||||
debug_reflog_iterator_begin,
|
||||
debug_for_each_reflog_ent,
|
||||
|
@ -338,9 +338,9 @@ static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs)
|
||||
return refs->loose;
|
||||
}
|
||||
|
||||
static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
|
||||
struct object_id *oid, struct strbuf *referent,
|
||||
unsigned int *type, int *failure_errno)
|
||||
static int read_ref_internal(struct ref_store *ref_store, const char *refname,
|
||||
struct object_id *oid, struct strbuf *referent,
|
||||
unsigned int *type, int *failure_errno, int skip_packed_refs)
|
||||
{
|
||||
struct files_ref_store *refs =
|
||||
files_downcast(ref_store, REF_STORE_READ, "read_raw_ref");
|
||||
@ -381,7 +381,7 @@ stat_ref:
|
||||
if (lstat(path, &st) < 0) {
|
||||
int ignore_errno;
|
||||
myerr = errno;
|
||||
if (myerr != ENOENT)
|
||||
if (myerr != ENOENT || skip_packed_refs)
|
||||
goto out;
|
||||
if (refs_read_raw_ref(refs->packed_ref_store, refname, oid,
|
||||
referent, type, &ignore_errno)) {
|
||||
@ -425,7 +425,8 @@ stat_ref:
|
||||
* ref is supposed to be, there could still be a
|
||||
* packed ref:
|
||||
*/
|
||||
if (refs_read_raw_ref(refs->packed_ref_store, refname, oid,
|
||||
if (skip_packed_refs ||
|
||||
refs_read_raw_ref(refs->packed_ref_store, refname, oid,
|
||||
referent, type, &ignore_errno)) {
|
||||
myerr = EISDIR;
|
||||
goto out;
|
||||
@ -470,6 +471,27 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
|
||||
struct object_id *oid, struct strbuf *referent,
|
||||
unsigned int *type, int *failure_errno)
|
||||
{
|
||||
return read_ref_internal(ref_store, refname, oid, referent, type, failure_errno, 0);
|
||||
}
|
||||
|
||||
static int files_read_symbolic_ref(struct ref_store *ref_store, const char *refname,
|
||||
struct strbuf *referent)
|
||||
{
|
||||
struct object_id oid;
|
||||
int failure_errno, ret;
|
||||
unsigned int type;
|
||||
|
||||
ret = read_ref_internal(ref_store, refname, &oid, referent, &type, &failure_errno, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return !(type & REF_ISSYMREF);
|
||||
}
|
||||
|
||||
int parse_loose_ref_contents(const char *buf, struct object_id *oid,
|
||||
struct strbuf *referent, unsigned int *type,
|
||||
int *failure_errno)
|
||||
@ -3286,6 +3308,7 @@ struct ref_storage_be refs_be_files = {
|
||||
|
||||
files_ref_iterator_begin,
|
||||
files_read_raw_ref,
|
||||
files_read_symbolic_ref,
|
||||
|
||||
files_reflog_iterator_begin,
|
||||
files_for_each_reflog_ent,
|
||||
|
@ -1684,6 +1684,7 @@ struct ref_storage_be refs_be_packed = {
|
||||
|
||||
packed_ref_iterator_begin,
|
||||
packed_read_raw_ref,
|
||||
NULL,
|
||||
|
||||
packed_reflog_iterator_begin,
|
||||
packed_for_each_reflog_ent,
|
||||
|
@ -649,6 +649,21 @@ typedef int read_raw_ref_fn(struct ref_store *ref_store, const char *refname,
|
||||
struct object_id *oid, struct strbuf *referent,
|
||||
unsigned int *type, int *failure_errno);
|
||||
|
||||
/*
|
||||
* Read a symbolic reference from the specified reference store. This function
|
||||
* is optional: if not implemented by a backend, then `read_raw_ref_fn` is used
|
||||
* to read the symbolcic reference instead. It is intended to be implemented
|
||||
* only in case the backend can optimize the reading of symbolic references.
|
||||
*
|
||||
* Return 0 on success, or -1 on failure. `referent` will be set to the target
|
||||
* of the symbolic reference on success. This function explicitly does not
|
||||
* distinguish between error cases and the reference not being a symbolic
|
||||
* reference to allow backends to optimize this operation in case symbolic and
|
||||
* non-symbolic references are treated differently.
|
||||
*/
|
||||
typedef int read_symbolic_ref_fn(struct ref_store *ref_store, const char *refname,
|
||||
struct strbuf *referent);
|
||||
|
||||
struct ref_storage_be {
|
||||
struct ref_storage_be *next;
|
||||
const char *name;
|
||||
@ -668,6 +683,7 @@ struct ref_storage_be {
|
||||
|
||||
ref_iterator_begin_fn *iterator_begin;
|
||||
read_raw_ref_fn *read_raw_ref;
|
||||
read_symbolic_ref_fn *read_symbolic_ref;
|
||||
|
||||
reflog_iterator_begin_fn *reflog_iterator_begin;
|
||||
for_each_reflog_ent_fn *for_each_reflog_ent;
|
||||
|
14
remote.c
14
remote.c
@ -1945,13 +1945,9 @@ const char *branch_get_push(struct branch *branch, struct strbuf *err)
|
||||
return branch->push_tracking_ref;
|
||||
}
|
||||
|
||||
static int ignore_symref_update(const char *refname)
|
||||
static int ignore_symref_update(const char *refname, struct strbuf *scratch)
|
||||
{
|
||||
int flag;
|
||||
|
||||
if (!resolve_ref_unsafe(refname, 0, NULL, &flag))
|
||||
return 0; /* non-existing refs are OK */
|
||||
return (flag & REF_ISSYMREF);
|
||||
return !refs_read_symbolic_ref(get_main_ref_store(the_repository), refname, scratch);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1964,6 +1960,7 @@ static int ignore_symref_update(const char *refname)
|
||||
static struct ref *get_expanded_map(const struct ref *remote_refs,
|
||||
const struct refspec_item *refspec)
|
||||
{
|
||||
struct strbuf scratch = STRBUF_INIT;
|
||||
const struct ref *ref;
|
||||
struct ref *ret = NULL;
|
||||
struct ref **tail = &ret;
|
||||
@ -1971,11 +1968,13 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
|
||||
for (ref = remote_refs; ref; ref = ref->next) {
|
||||
char *expn_name = NULL;
|
||||
|
||||
strbuf_reset(&scratch);
|
||||
|
||||
if (strchr(ref->name, '^'))
|
||||
continue; /* a dereference item */
|
||||
if (match_name_with_pattern(refspec->src, ref->name,
|
||||
refspec->dst, &expn_name) &&
|
||||
!ignore_symref_update(expn_name)) {
|
||||
!ignore_symref_update(expn_name, &scratch)) {
|
||||
struct ref *cpy = copy_ref(ref);
|
||||
|
||||
cpy->peer_ref = alloc_ref(expn_name);
|
||||
@ -1987,6 +1986,7 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
|
||||
free(expn_name);
|
||||
}
|
||||
|
||||
strbuf_release(&scratch);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1400,13 +1400,19 @@ static int parse_want(struct packet_writer *writer, const char *line,
|
||||
const char *arg;
|
||||
if (skip_prefix(line, "want ", &arg)) {
|
||||
struct object_id oid;
|
||||
struct commit *commit;
|
||||
struct object *o;
|
||||
|
||||
if (get_oid_hex(arg, &oid))
|
||||
die("git upload-pack: protocol error, "
|
||||
"expected to get oid, not '%s'", line);
|
||||
|
||||
o = parse_object(the_repository, &oid);
|
||||
commit = lookup_commit_in_graph(the_repository, &oid);
|
||||
if (commit)
|
||||
o = &commit->object;
|
||||
else
|
||||
o = parse_object(the_repository, &oid);
|
||||
|
||||
if (!o) {
|
||||
packet_writer_error(writer,
|
||||
"upload-pack: not our ref %s",
|
||||
@ -1434,7 +1440,7 @@ static int parse_want_ref(struct packet_writer *writer, const char *line,
|
||||
if (skip_prefix(line, "want-ref ", &refname_nons)) {
|
||||
struct object_id oid;
|
||||
struct string_list_item *item;
|
||||
struct object *o;
|
||||
struct object *o = NULL;
|
||||
struct strbuf refname = STRBUF_INIT;
|
||||
|
||||
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,
|
||||
item = string_list_append(wanted_refs, refname_nons);
|
||||
item->util = oiddup(&oid);
|
||||
|
||||
o = parse_object_or_die(&oid, refname_nons);
|
||||
if (!starts_with(refname_nons, "refs/tags/")) {
|
||||
struct commit *commit = lookup_commit_in_graph(the_repository, &oid);
|
||||
if (commit)
|
||||
o = &commit->object;
|
||||
}
|
||||
|
||||
if (!o)
|
||||
o = parse_object_or_die(&oid, refname_nons);
|
||||
|
||||
if (!(o->flags & WANTED)) {
|
||||
o->flags |= WANTED;
|
||||
add_object_array(o, NULL, want_obj);
|
||||
|
Loading…
Reference in New Issue
Block a user