fetch-pack: make negotiation-related vars local

Reduce the number of global variables by making the priority queue and
the count of non-common commits in it local, passing them as a struct to
various functions where necessary.

This also helps in the case that fetch_pack() is invoked twice in the
same process (when tag following is required when using a transport that
does not support tag following), in that different priority queues will
now be used in each invocation, instead of reusing the possibly
non-empty one.

Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jonathan Tan 2018-06-14 15:54:26 -07:00 committed by Junio C Hamano
parent af1c90d13e
commit d30fe89c37

View File

@ -50,8 +50,12 @@ static int marked;
*/
#define MAX_IN_VAIN 256
static struct prio_queue rev_list = { compare_commits_by_commit_date };
static int non_common_revs, multi_ack, use_sideband;
struct negotiation_state {
struct prio_queue rev_list;
int non_common_revs;
};
static int multi_ack, use_sideband;
/* Allow specifying sha1 if it is a ref tip. */
#define ALLOW_TIP_SHA1 01
/* Allow request of a sha1 if it is reachable from a ref (possibly hidden ref). */
@ -93,7 +97,9 @@ static void cache_one_alternate(const char *refname,
cache->items[cache->nr++] = obj;
}
static void for_each_cached_alternate(void (*cb)(struct object *))
static void for_each_cached_alternate(struct negotiation_state *ns,
void (*cb)(struct negotiation_state *,
struct object *))
{
static int initialized;
static struct alternate_object_cache cache;
@ -105,10 +111,11 @@ static void for_each_cached_alternate(void (*cb)(struct object *))
}
for (i = 0; i < cache.nr; i++)
cb(cache.items[i]);
cb(ns, cache.items[i]);
}
static void rev_list_push(struct commit *commit, int mark)
static void rev_list_push(struct negotiation_state *ns,
struct commit *commit, int mark)
{
if (!(commit->object.flags & mark)) {
commit->object.flags |= mark;
@ -116,19 +123,21 @@ static void rev_list_push(struct commit *commit, int mark)
if (parse_commit(commit))
return;
prio_queue_put(&rev_list, commit);
prio_queue_put(&ns->rev_list, commit);
if (!(commit->object.flags & COMMON))
non_common_revs++;
ns->non_common_revs++;
}
}
static int rev_list_insert_ref(const char *refname, const struct object_id *oid)
static int rev_list_insert_ref(struct negotiation_state *ns,
const char *refname,
const struct object_id *oid)
{
struct object *o = deref_tag(parse_object(oid), refname, 0);
if (o && o->type == OBJ_COMMIT)
rev_list_push((struct commit *)o, SEEN);
rev_list_push(ns, (struct commit *)o, SEEN);
return 0;
}
@ -136,7 +145,7 @@ static int rev_list_insert_ref(const char *refname, const struct object_id *oid)
static int rev_list_insert_ref_oid(const char *refname, const struct object_id *oid,
int flag, void *cb_data)
{
return rev_list_insert_ref(refname, oid);
return rev_list_insert_ref(cb_data, refname, oid);
}
static int clear_marks(const char *refname, const struct object_id *oid,
@ -156,7 +165,7 @@ static int clear_marks(const char *refname, const struct object_id *oid,
when only the server does not yet know that they are common).
*/
static void mark_common(struct commit *commit,
static void mark_common(struct negotiation_state *ns, struct commit *commit,
int ancestors_only, int dont_parse)
{
if (commit != NULL && !(commit->object.flags & COMMON)) {
@ -166,12 +175,12 @@ static void mark_common(struct commit *commit,
o->flags |= COMMON;
if (!(o->flags & SEEN))
rev_list_push(commit, SEEN);
rev_list_push(ns, commit, SEEN);
else {
struct commit_list *parents;
if (!ancestors_only && !(o->flags & POPPED))
non_common_revs--;
ns->non_common_revs--;
if (!o->parsed && !dont_parse)
if (parse_commit(commit))
return;
@ -179,7 +188,8 @@ static void mark_common(struct commit *commit,
for (parents = commit->parents;
parents;
parents = parents->next)
mark_common(parents->item, 0, dont_parse);
mark_common(ns, parents->item, 0,
dont_parse);
}
}
}
@ -188,7 +198,7 @@ static void mark_common(struct commit *commit,
Get the next rev to send, ignoring the common.
*/
static const struct object_id *get_rev(void)
static const struct object_id *get_rev(struct negotiation_state *ns)
{
struct commit *commit = NULL;
@ -196,16 +206,16 @@ static const struct object_id *get_rev(void)
unsigned int mark;
struct commit_list *parents;
if (rev_list.nr == 0 || non_common_revs == 0)
if (ns->rev_list.nr == 0 || ns->non_common_revs == 0)
return NULL;
commit = prio_queue_get(&rev_list);
commit = prio_queue_get(&ns->rev_list);
parse_commit(commit);
parents = commit->parents;
commit->object.flags |= POPPED;
if (!(commit->object.flags & COMMON))
non_common_revs--;
ns->non_common_revs--;
if (commit->object.flags & COMMON) {
/* do not send "have", and ignore ancestors */
@ -220,9 +230,9 @@ static const struct object_id *get_rev(void)
while (parents) {
if (!(parents->item->object.flags & SEEN))
rev_list_push(parents->item, mark);
rev_list_push(ns, parents->item, mark);
if (mark & COMMON)
mark_common(parents->item, 1, 0);
mark_common(ns, parents->item, 1, 0);
parents = parents->next;
}
}
@ -296,9 +306,10 @@ static void send_request(struct fetch_pack_args *args,
write_or_die(fd, buf->buf, buf->len);
}
static void insert_one_alternate_object(struct object *obj)
static void insert_one_alternate_object(struct negotiation_state *ns,
struct object *obj)
{
rev_list_insert_ref(NULL, &obj->oid);
rev_list_insert_ref(ns, NULL, &obj->oid);
}
#define INITIAL_FLUSH 16
@ -321,7 +332,8 @@ static int next_flush(int stateless_rpc, int count)
return count;
}
static int find_common(struct fetch_pack_args *args,
static int find_common(struct negotiation_state *ns,
struct fetch_pack_args *args,
int fd[2], struct object_id *result_oid,
struct ref *refs)
{
@ -337,8 +349,8 @@ static int find_common(struct fetch_pack_args *args,
if (args->stateless_rpc && multi_ack == 1)
die(_("--stateless-rpc requires multi_ack_detailed"));
for_each_ref(rev_list_insert_ref_oid, NULL);
for_each_cached_alternate(insert_one_alternate_object);
for_each_ref(rev_list_insert_ref_oid, ns);
for_each_cached_alternate(ns, insert_one_alternate_object);
fetching = 0;
for ( ; refs ; refs = refs->next) {
@ -456,7 +468,7 @@ static int find_common(struct fetch_pack_args *args,
retval = -1;
if (args->no_dependents)
goto done;
while ((oid = get_rev())) {
while ((oid = get_rev(ns))) {
packet_buf_write(&req_buf, "have %s\n", oid_to_hex(oid));
print_verbose(args, "have %s", oid_to_hex(oid));
in_vain++;
@ -514,7 +526,7 @@ static int find_common(struct fetch_pack_args *args,
} else if (!args->stateless_rpc
|| ack != ACK_common)
in_vain = 0;
mark_common(commit, 0, 1);
mark_common(ns, commit, 0, 1);
retval = 0;
got_continue = 1;
if (ack == ACK_ready)
@ -704,7 +716,8 @@ static void filter_refs(struct fetch_pack_args *args,
*refs = newlist;
}
static void mark_alternate_complete(struct object *obj)
static void mark_alternate_complete(struct negotiation_state *unused,
struct object *obj)
{
mark_complete(&obj->oid);
}
@ -741,7 +754,8 @@ static int add_loose_objects_to_set(const struct object_id *oid,
* earliest commit time of the objects in refs that are commits and that we know
* the commit time of.
*/
static void mark_complete_and_common_ref(struct fetch_pack_args *args,
static void mark_complete_and_common_ref(struct negotiation_state *ns,
struct fetch_pack_args *args,
struct ref **refs)
{
struct ref *ref;
@ -792,7 +806,7 @@ static void mark_complete_and_common_ref(struct fetch_pack_args *args,
if (!args->no_dependents) {
if (!args->deepen) {
for_each_ref(mark_complete_oid, NULL);
for_each_cached_alternate(mark_alternate_complete);
for_each_cached_alternate(NULL, mark_alternate_complete);
commit_list_sort_by_date(&complete);
if (cutoff)
mark_recent_complete_commits(args, cutoff);
@ -810,9 +824,10 @@ static void mark_complete_and_common_ref(struct fetch_pack_args *args,
continue;
if (!(o->flags & SEEN)) {
rev_list_push((struct commit *)o, COMMON_REF | SEEN);
rev_list_push(ns, (struct commit *)o,
COMMON_REF | SEEN);
mark_common((struct commit *)o, 1, 1);
mark_common(ns, (struct commit *)o, 1, 1);
}
}
}
@ -995,6 +1010,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
struct object_id oid;
const char *agent_feature;
int agent_len;
struct negotiation_state ns = { { compare_commits_by_commit_date } };
sort_ref_list(&ref, ref_compare_name);
QSORT(sought, nr_sought, cmp_ref_by_name);
@ -1070,13 +1086,13 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
if (marked)
for_each_ref(clear_marks, NULL);
marked = 1;
mark_complete_and_common_ref(args, &ref);
mark_complete_and_common_ref(&ns, args, &ref);
filter_refs(args, &ref, sought, nr_sought);
if (everything_local(args, &ref)) {
packet_flush(fd[1]);
goto all_done;
}
if (find_common(args, fd, &oid, ref) < 0)
if (find_common(&ns, args, fd, &oid, ref) < 0)
if (!args->keep_pack)
/* When cloning, it is not unusual to have
* no common commit.
@ -1096,7 +1112,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
die(_("git fetch-pack: fetch failed."));
all_done:
clear_prio_queue(&rev_list);
clear_prio_queue(&ns.rev_list);
return ref;
}
@ -1158,13 +1174,14 @@ static void add_common(struct strbuf *req_buf, struct oidset *common)
}
}
static int add_haves(struct strbuf *req_buf, int *haves_to_send, int *in_vain)
static int add_haves(struct negotiation_state *ns, struct strbuf *req_buf,
int *haves_to_send, int *in_vain)
{
int ret = 0;
int haves_added = 0;
const struct object_id *oid;
while ((oid = get_rev())) {
while ((oid = get_rev(ns))) {
packet_buf_write(req_buf, "have %s\n", oid_to_hex(oid));
if (++haves_added >= *haves_to_send)
break;
@ -1183,7 +1200,8 @@ static int add_haves(struct strbuf *req_buf, int *haves_to_send, int *in_vain)
return ret;
}
static int send_fetch_request(int fd_out, const struct fetch_pack_args *args,
static int send_fetch_request(struct negotiation_state *ns, int fd_out,
const struct fetch_pack_args *args,
const struct ref *wants, struct oidset *common,
int *haves_to_send, int *in_vain)
{
@ -1239,7 +1257,7 @@ static int send_fetch_request(int fd_out, const struct fetch_pack_args *args,
add_common(&req_buf, common);
/* Add initial haves */
ret = add_haves(&req_buf, haves_to_send, in_vain);
ret = add_haves(ns, &req_buf, haves_to_send, in_vain);
}
/* Send request */
@ -1276,7 +1294,9 @@ static int process_section_header(struct packet_reader *reader,
return ret;
}
static int process_acks(struct packet_reader *reader, struct oidset *common)
static int process_acks(struct negotiation_state *ns,
struct packet_reader *reader,
struct oidset *common)
{
/* received */
int received_ready = 0;
@ -1295,7 +1315,7 @@ static int process_acks(struct packet_reader *reader, struct oidset *common)
struct commit *commit;
oidset_insert(common, &oid);
commit = lookup_commit(&oid);
mark_common(commit, 0, 1);
mark_common(ns, commit, 0, 1);
}
continue;
}
@ -1373,6 +1393,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
struct packet_reader reader;
int in_vain = 0;
int haves_to_send = INITIAL_FLUSH;
struct negotiation_state ns = { { compare_commits_by_commit_date } };
packet_reader_init(&reader, fd[0], NULL, 0,
PACKET_READ_CHOMP_NEWLINE);
@ -1393,18 +1414,19 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
marked = 1;
/* Filter 'ref' by 'sought' and those that aren't local */
mark_complete_and_common_ref(args, &ref);
mark_complete_and_common_ref(&ns, args, &ref);
filter_refs(args, &ref, sought, nr_sought);
if (everything_local(args, &ref))
state = FETCH_DONE;
else
state = FETCH_SEND_REQUEST;
for_each_ref(rev_list_insert_ref_oid, NULL);
for_each_cached_alternate(insert_one_alternate_object);
for_each_ref(rev_list_insert_ref_oid, &ns);
for_each_cached_alternate(&ns,
insert_one_alternate_object);
break;
case FETCH_SEND_REQUEST:
if (send_fetch_request(fd[1], args, ref, &common,
if (send_fetch_request(&ns, fd[1], args, ref, &common,
&haves_to_send, &in_vain))
state = FETCH_GET_PACK;
else
@ -1412,7 +1434,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
break;
case FETCH_PROCESS_ACKS:
/* Process ACKs/NAKs */
switch (process_acks(&reader, &common)) {
switch (process_acks(&ns, &reader, &common)) {
case 2:
state = FETCH_GET_PACK;
break;
@ -1441,7 +1463,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
}
}
clear_prio_queue(&rev_list);
clear_prio_queue(&ns.rev_list);
oidset_clear(&common);
return ref;
}