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 <= FETCH_HEAD_IGNORE;
|
||||||
want_status++) {
|
want_status++) {
|
||||||
for (rm = ref_map; rm; rm = rm->next) {
|
for (rm = ref_map; rm; rm = rm->next) {
|
||||||
struct commit *commit = NULL;
|
|
||||||
struct ref *ref = NULL;
|
struct ref *ref = NULL;
|
||||||
|
|
||||||
if (rm->status == REF_STATUS_REJECT_SHALLOW) {
|
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
|
* When writing FETCH_HEAD we need to determine whether
|
||||||
* to annotated tags, which are not part of the
|
* we already have the commit or not. If not, then the
|
||||||
* commit-graph. We thus only try to look up refs in
|
* reference is not for merge and needs to be written
|
||||||
* the graph which are not in that namespace to not
|
* to the reflog after other commits which we already
|
||||||
* regress performance in repositories with many
|
* have. We're not interested in this property though
|
||||||
* annotated tags.
|
* 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/"))
|
if (fetch_head->fp) {
|
||||||
commit = lookup_commit_in_graph(the_repository, &rm->old_oid);
|
struct commit *commit = NULL;
|
||||||
if (!commit) {
|
|
||||||
commit = lookup_commit_reference_gently(the_repository,
|
/*
|
||||||
&rm->old_oid,
|
* References in "refs/tags/" are often going to point
|
||||||
1);
|
* to annotated tags, which are not part of the
|
||||||
if (!commit)
|
* commit-graph. We thus only try to look up refs in
|
||||||
rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
|
* 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)
|
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_each_ref(read_remote_branches, &rename);
|
||||||
for (i = 0; i < remote_branches.nr; i++) {
|
for (i = 0; i < remote_branches.nr; i++) {
|
||||||
struct string_list_item *item = remote_branches.items + 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 (refs_read_symbolic_ref(get_main_ref_store(the_repository), item->string,
|
||||||
if (!(flag & REF_ISSYMREF))
|
&referent))
|
||||||
continue;
|
continue;
|
||||||
if (delete_ref(NULL, item->string, NULL, REF_NO_DEREF))
|
if (delete_ref(NULL, item->string, NULL, REF_NO_DEREF))
|
||||||
die(_("deleting '%s' failed"), item->string);
|
die(_("deleting '%s' failed"), item->string);
|
||||||
|
|
||||||
|
strbuf_release(&referent);
|
||||||
}
|
}
|
||||||
for (i = 0; i < remote_branches.nr; i++) {
|
for (i = 0; i < remote_branches.nr; i++) {
|
||||||
struct string_list_item *item = remote_branches.items + 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);
|
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 *refs_resolve_ref_unsafe(struct ref_store *refs,
|
||||||
const char *refname,
|
const char *refname,
|
||||||
int resolve_flags,
|
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);
|
struct object_id *oid, int *flags);
|
||||||
int read_ref(const char *refname, struct object_id *oid);
|
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
|
* Return 0 if a reference named refname could be created without
|
||||||
* conflicting with the name of an existing reference. Otherwise,
|
* 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_ref_iterator_begin,
|
||||||
debug_read_raw_ref,
|
debug_read_raw_ref,
|
||||||
|
NULL,
|
||||||
|
|
||||||
debug_reflog_iterator_begin,
|
debug_reflog_iterator_begin,
|
||||||
debug_for_each_reflog_ent,
|
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;
|
return refs->loose;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
|
static int read_ref_internal(struct ref_store *ref_store, const char *refname,
|
||||||
struct object_id *oid, struct strbuf *referent,
|
struct object_id *oid, struct strbuf *referent,
|
||||||
unsigned int *type, int *failure_errno)
|
unsigned int *type, int *failure_errno, int skip_packed_refs)
|
||||||
{
|
{
|
||||||
struct files_ref_store *refs =
|
struct files_ref_store *refs =
|
||||||
files_downcast(ref_store, REF_STORE_READ, "read_raw_ref");
|
files_downcast(ref_store, REF_STORE_READ, "read_raw_ref");
|
||||||
@ -381,7 +381,7 @@ stat_ref:
|
|||||||
if (lstat(path, &st) < 0) {
|
if (lstat(path, &st) < 0) {
|
||||||
int ignore_errno;
|
int ignore_errno;
|
||||||
myerr = errno;
|
myerr = errno;
|
||||||
if (myerr != ENOENT)
|
if (myerr != ENOENT || skip_packed_refs)
|
||||||
goto out;
|
goto out;
|
||||||
if (refs_read_raw_ref(refs->packed_ref_store, refname, oid,
|
if (refs_read_raw_ref(refs->packed_ref_store, refname, oid,
|
||||||
referent, type, &ignore_errno)) {
|
referent, type, &ignore_errno)) {
|
||||||
@ -425,7 +425,8 @@ stat_ref:
|
|||||||
* ref is supposed to be, there could still be a
|
* ref is supposed to be, there could still be a
|
||||||
* packed ref:
|
* 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)) {
|
referent, type, &ignore_errno)) {
|
||||||
myerr = EISDIR;
|
myerr = EISDIR;
|
||||||
goto out;
|
goto out;
|
||||||
@ -470,6 +471,27 @@ out:
|
|||||||
return ret;
|
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,
|
int parse_loose_ref_contents(const char *buf, struct object_id *oid,
|
||||||
struct strbuf *referent, unsigned int *type,
|
struct strbuf *referent, unsigned int *type,
|
||||||
int *failure_errno)
|
int *failure_errno)
|
||||||
@ -3286,6 +3308,7 @@ struct ref_storage_be refs_be_files = {
|
|||||||
|
|
||||||
files_ref_iterator_begin,
|
files_ref_iterator_begin,
|
||||||
files_read_raw_ref,
|
files_read_raw_ref,
|
||||||
|
files_read_symbolic_ref,
|
||||||
|
|
||||||
files_reflog_iterator_begin,
|
files_reflog_iterator_begin,
|
||||||
files_for_each_reflog_ent,
|
files_for_each_reflog_ent,
|
||||||
|
@ -1684,6 +1684,7 @@ struct ref_storage_be refs_be_packed = {
|
|||||||
|
|
||||||
packed_ref_iterator_begin,
|
packed_ref_iterator_begin,
|
||||||
packed_read_raw_ref,
|
packed_read_raw_ref,
|
||||||
|
NULL,
|
||||||
|
|
||||||
packed_reflog_iterator_begin,
|
packed_reflog_iterator_begin,
|
||||||
packed_for_each_reflog_ent,
|
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,
|
struct object_id *oid, struct strbuf *referent,
|
||||||
unsigned int *type, int *failure_errno);
|
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 {
|
||||||
struct ref_storage_be *next;
|
struct ref_storage_be *next;
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -668,6 +683,7 @@ struct ref_storage_be {
|
|||||||
|
|
||||||
ref_iterator_begin_fn *iterator_begin;
|
ref_iterator_begin_fn *iterator_begin;
|
||||||
read_raw_ref_fn *read_raw_ref;
|
read_raw_ref_fn *read_raw_ref;
|
||||||
|
read_symbolic_ref_fn *read_symbolic_ref;
|
||||||
|
|
||||||
reflog_iterator_begin_fn *reflog_iterator_begin;
|
reflog_iterator_begin_fn *reflog_iterator_begin;
|
||||||
for_each_reflog_ent_fn *for_each_reflog_ent;
|
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;
|
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;
|
return !refs_read_symbolic_ref(get_main_ref_store(the_repository), refname, scratch);
|
||||||
|
|
||||||
if (!resolve_ref_unsafe(refname, 0, NULL, &flag))
|
|
||||||
return 0; /* non-existing refs are OK */
|
|
||||||
return (flag & REF_ISSYMREF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1964,6 +1960,7 @@ static int ignore_symref_update(const char *refname)
|
|||||||
static struct ref *get_expanded_map(const struct ref *remote_refs,
|
static struct ref *get_expanded_map(const struct ref *remote_refs,
|
||||||
const struct refspec_item *refspec)
|
const struct refspec_item *refspec)
|
||||||
{
|
{
|
||||||
|
struct strbuf scratch = STRBUF_INIT;
|
||||||
const struct ref *ref;
|
const struct ref *ref;
|
||||||
struct ref *ret = NULL;
|
struct ref *ret = NULL;
|
||||||
struct ref **tail = &ret;
|
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) {
|
for (ref = remote_refs; ref; ref = ref->next) {
|
||||||
char *expn_name = NULL;
|
char *expn_name = NULL;
|
||||||
|
|
||||||
|
strbuf_reset(&scratch);
|
||||||
|
|
||||||
if (strchr(ref->name, '^'))
|
if (strchr(ref->name, '^'))
|
||||||
continue; /* a dereference item */
|
continue; /* a dereference item */
|
||||||
if (match_name_with_pattern(refspec->src, ref->name,
|
if (match_name_with_pattern(refspec->src, ref->name,
|
||||||
refspec->dst, &expn_name) &&
|
refspec->dst, &expn_name) &&
|
||||||
!ignore_symref_update(expn_name)) {
|
!ignore_symref_update(expn_name, &scratch)) {
|
||||||
struct ref *cpy = copy_ref(ref);
|
struct ref *cpy = copy_ref(ref);
|
||||||
|
|
||||||
cpy->peer_ref = alloc_ref(expn_name);
|
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);
|
free(expn_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strbuf_release(&scratch);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1400,13 +1400,19 @@ static int parse_want(struct packet_writer *writer, const char *line,
|
|||||||
const char *arg;
|
const char *arg;
|
||||||
if (skip_prefix(line, "want ", &arg)) {
|
if (skip_prefix(line, "want ", &arg)) {
|
||||||
struct object_id oid;
|
struct object_id oid;
|
||||||
|
struct commit *commit;
|
||||||
struct object *o;
|
struct object *o;
|
||||||
|
|
||||||
if (get_oid_hex(arg, &oid))
|
if (get_oid_hex(arg, &oid))
|
||||||
die("git upload-pack: protocol error, "
|
die("git upload-pack: protocol error, "
|
||||||
"expected to get oid, not '%s'", line);
|
"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) {
|
if (!o) {
|
||||||
packet_writer_error(writer,
|
packet_writer_error(writer,
|
||||||
"upload-pack: not our ref %s",
|
"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)) {
|
if (skip_prefix(line, "want-ref ", &refname_nons)) {
|
||||||
struct object_id oid;
|
struct object_id oid;
|
||||||
struct string_list_item *item;
|
struct string_list_item *item;
|
||||||
struct object *o;
|
struct object *o = NULL;
|
||||||
struct strbuf refname = STRBUF_INIT;
|
struct strbuf refname = STRBUF_INIT;
|
||||||
|
|
||||||
strbuf_addf(&refname, "%s%s", get_git_namespace(), refname_nons);
|
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 = string_list_append(wanted_refs, refname_nons);
|
||||||
item->util = oiddup(&oid);
|
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)) {
|
if (!(o->flags & WANTED)) {
|
||||||
o->flags |= WANTED;
|
o->flags |= WANTED;
|
||||||
add_object_array(o, NULL, want_obj);
|
add_object_array(o, NULL, want_obj);
|
||||||
|
Loading…
Reference in New Issue
Block a user