diff options
Diffstat (limited to 'fetch-pack.c')
-rw-r--r-- | fetch-pack.c | 145 |
1 files changed, 91 insertions, 54 deletions
diff --git a/fetch-pack.c b/fetch-pack.c index afb8b05024..cd86865beb 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -15,6 +15,7 @@ #include "version.h" #include "prio-queue.h" #include "sha1-array.h" +#include "oidset.h" static int transfer_unpack_limit = -1; static int fetch_unpack_limit = -1; @@ -78,7 +79,7 @@ static void cache_one_alternate(const char *refname, void *vcache) { struct alternate_object_cache *cache = vcache; - struct object *obj = parse_object(oid->hash); + struct object *obj = parse_object(oid); if (!obj || (obj->flags & ALTERNATE)) return; @@ -118,9 +119,9 @@ static void rev_list_push(struct commit *commit, int mark) } } -static int rev_list_insert_ref(const char *refname, const unsigned char *sha1) +static int rev_list_insert_ref(const char *refname, const struct object_id *oid) { - struct object *o = deref_tag(parse_object(sha1), refname, 0); + struct object *o = deref_tag(parse_object(oid), refname, 0); if (o && o->type == OBJ_COMMIT) rev_list_push((struct commit *)o, SEEN); @@ -131,13 +132,13 @@ static int rev_list_insert_ref(const char *refname, const unsigned char *sha1) 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->hash); + return rev_list_insert_ref(refname, oid); } static int clear_marks(const char *refname, const struct object_id *oid, int flag, void *cb_data) { - struct object *o = deref_tag(parse_object(oid->hash), refname, 0); + struct object *o = deref_tag(parse_object(oid), refname, 0); if (o && o->type == OBJ_COMMIT) clear_commit_marks((struct commit *)o, @@ -183,7 +184,7 @@ static void mark_common(struct commit *commit, Get the next rev to send, ignoring the common. */ -static const unsigned char *get_rev(void) +static const struct object_id *get_rev(void) { struct commit *commit = NULL; @@ -222,7 +223,7 @@ static const unsigned char *get_rev(void) } } - return commit->object.oid.hash; + return &commit->object.oid; } enum ack_type { @@ -251,7 +252,7 @@ static void consume_shallow_list(struct fetch_pack_args *args, int fd) } } -static enum ack_type get_ack(int fd, unsigned char *result_sha1) +static enum ack_type get_ack(int fd, struct object_id *result_oid) { int len; char *line = packet_read_line(fd, &len); @@ -262,7 +263,7 @@ static enum ack_type get_ack(int fd, unsigned char *result_sha1) if (!strcmp(line, "NAK")) return NAK; if (skip_prefix(line, "ACK ", &arg)) { - if (!get_sha1_hex(arg, result_sha1)) { + if (!get_oid_hex(arg, result_oid)) { arg += 40; len -= arg - line; if (len < 1) @@ -293,7 +294,7 @@ static void send_request(struct fetch_pack_args *args, static void insert_one_alternate_object(struct object *obj) { - rev_list_insert_ref(NULL, obj->oid.hash); + rev_list_insert_ref(NULL, &obj->oid); } #define INITIAL_FLUSH 16 @@ -317,12 +318,12 @@ static int next_flush(struct fetch_pack_args *args, int count) } static int find_common(struct fetch_pack_args *args, - int fd[2], unsigned char *result_sha1, + int fd[2], struct object_id *result_oid, struct ref *refs) { int fetching; int count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval; - const unsigned char *sha1; + const struct object_id *oid; unsigned in_vain = 0; int got_continue = 0; int got_ready = 0; @@ -340,7 +341,7 @@ static int find_common(struct fetch_pack_args *args, fetching = 0; for ( ; refs ; refs = refs->next) { - unsigned char *remote = refs->old_oid.hash; + struct object_id *remote = &refs->old_oid; const char *remote_hex; struct object *o; @@ -354,12 +355,12 @@ static int find_common(struct fetch_pack_args *args, * interested in the case we *know* the object is * reachable and we have already scanned it. */ - if (((o = lookup_object(remote)) != NULL) && + if (((o = lookup_object(remote->hash)) != NULL) && (o->flags & COMPLETE)) { continue; } - remote_hex = sha1_to_hex(remote); + remote_hex = oid_to_hex(remote); if (!fetching) { struct strbuf c = STRBUF_INIT; if (multi_ack == 2) strbuf_addstr(&c, " multi_ack_detailed"); @@ -394,8 +395,8 @@ static int find_common(struct fetch_pack_args *args, if (args->depth > 0) packet_buf_write(&req_buf, "deepen %d", args->depth); if (args->deepen_since) { - unsigned long max_age = approxidate(args->deepen_since); - packet_buf_write(&req_buf, "deepen-since %lu", max_age); + timestamp_t max_age = approxidate(args->deepen_since); + packet_buf_write(&req_buf, "deepen-since %"PRItime, max_age); } if (args->deepen_not) { int i; @@ -410,25 +411,25 @@ static int find_common(struct fetch_pack_args *args, if (args->deepen) { char *line; const char *arg; - unsigned char sha1[20]; + struct object_id oid; send_request(args, fd[1], &req_buf); while ((line = packet_read_line(fd[0], NULL))) { if (skip_prefix(line, "shallow ", &arg)) { - if (get_sha1_hex(arg, sha1)) + if (get_oid_hex(arg, &oid)) die(_("invalid shallow line: %s"), line); - register_shallow(sha1); + register_shallow(&oid); continue; } if (skip_prefix(line, "unshallow ", &arg)) { - if (get_sha1_hex(arg, sha1)) + if (get_oid_hex(arg, &oid)) die(_("invalid unshallow line: %s"), line); - if (!lookup_object(sha1)) + if (!lookup_object(oid.hash)) die(_("object not found: %s"), line); /* make sure that it is parsed as shallow */ - if (!parse_object(sha1)) + if (!parse_object(&oid)) die(_("error in object: %s"), line); - if (unregister_shallow(sha1)) + if (unregister_shallow(&oid)) die(_("no shallow found: %s"), line); continue; } @@ -447,9 +448,9 @@ static int find_common(struct fetch_pack_args *args, flushes = 0; retval = -1; - while ((sha1 = get_rev())) { - packet_buf_write(&req_buf, "have %s\n", sha1_to_hex(sha1)); - print_verbose(args, "have %s", sha1_to_hex(sha1)); + while ((oid = get_rev())) { + packet_buf_write(&req_buf, "have %s\n", oid_to_hex(oid)); + print_verbose(args, "have %s", oid_to_hex(oid)); in_vain++; if (flush_at <= ++count) { int ack; @@ -469,10 +470,10 @@ static int find_common(struct fetch_pack_args *args, consume_shallow_list(args, fd[0]); do { - ack = get_ack(fd[0], result_sha1); + ack = get_ack(fd[0], result_oid); if (ack) print_verbose(args, _("got %s %d %s"), "ack", - ack, sha1_to_hex(result_sha1)); + ack, oid_to_hex(result_oid)); switch (ack) { case ACK: flushes = 0; @@ -483,9 +484,9 @@ static int find_common(struct fetch_pack_args *args, case ACK_ready: case ACK_continue: { struct commit *commit = - lookup_commit(result_sha1); + lookup_commit(result_oid); if (!commit) - die(_("invalid commit %s"), sha1_to_hex(result_sha1)); + die(_("invalid commit %s"), oid_to_hex(result_oid)); if (args->stateless_rpc && ack == ACK_common && !(commit->object.flags & COMMON)) { @@ -493,7 +494,7 @@ static int find_common(struct fetch_pack_args *args, * on the next RPC request so the peer knows * it is in common with us. */ - const char *hex = sha1_to_hex(result_sha1); + const char *hex = oid_to_hex(result_oid); packet_buf_write(&req_buf, "have %s\n", hex); state_len = req_buf.len; /* @@ -538,10 +539,10 @@ done: if (!got_ready || !no_done) consume_shallow_list(args, fd[0]); while (flushes || multi_ack) { - int ack = get_ack(fd[0], result_sha1); + int ack = get_ack(fd[0], result_oid); if (ack) { print_verbose(args, _("got %s (%d) %s"), "ack", - ack, sha1_to_hex(result_sha1)); + ack, oid_to_hex(result_oid)); if (ack == ACK) return 0; multi_ack = 1; @@ -555,16 +556,16 @@ done: static struct commit_list *complete; -static int mark_complete(const unsigned char *sha1) +static int mark_complete(const struct object_id *oid) { - struct object *o = parse_object(sha1); + struct object *o = parse_object(oid); while (o && o->type == OBJ_TAG) { struct tag *t = (struct tag *) o; if (!t->tagged) break; /* broken repository */ o->flags |= COMPLETE; - o = parse_object(t->tagged->oid.hash); + o = parse_object(&t->tagged->oid); } if (o && o->type == OBJ_COMMIT) { struct commit *commit = (struct commit *)o; @@ -579,11 +580,11 @@ static int mark_complete(const unsigned char *sha1) static int mark_complete_oid(const char *refname, const struct object_id *oid, int flag, void *cb_data) { - return mark_complete(oid->hash); + return mark_complete(oid); } static void mark_recent_complete_commits(struct fetch_pack_args *args, - unsigned long cutoff) + timestamp_t cutoff) { while (complete && cutoff <= complete->item->date) { print_verbose(args, _("Marking %s as complete"), @@ -592,13 +593,38 @@ static void mark_recent_complete_commits(struct fetch_pack_args *args, } } +static void add_refs_to_oidset(struct oidset *oids, struct ref *refs) +{ + for (; refs; refs = refs->next) + oidset_insert(oids, &refs->old_oid); +} + +static int tip_oids_contain(struct oidset *tip_oids, + struct ref *unmatched, struct ref *newlist, + const struct object_id *id) +{ + /* + * Note that this only looks at the ref lists the first time it's + * called. This works out in filter_refs() because even though it may + * add to "newlist" between calls, the additions will always be for + * oids that are already in the set. + */ + if (!tip_oids->map.tablesize) { + add_refs_to_oidset(tip_oids, unmatched); + add_refs_to_oidset(tip_oids, newlist); + } + return oidset_contains(tip_oids, id); +} + static void filter_refs(struct fetch_pack_args *args, struct ref **refs, struct ref **sought, int nr_sought) { struct ref *newlist = NULL; struct ref **newtail = &newlist; + struct ref *unmatched = NULL; struct ref *ref, *next; + struct oidset tip_oids = OIDSET_INIT; int i; i = 0; @@ -631,24 +657,28 @@ static void filter_refs(struct fetch_pack_args *args, ref->next = NULL; newtail = &ref->next; } else { - free(ref); + ref->next = unmatched; + unmatched = ref; } } /* Append unmatched requests to the list */ for (i = 0; i < nr_sought; i++) { - unsigned char sha1[20]; + struct object_id oid; + const char *p; ref = sought[i]; if (ref->match_status != REF_NOT_MATCHED) continue; - if (get_sha1_hex(ref->name, sha1) || - ref->name[40] != '\0' || - hashcmp(sha1, ref->old_oid.hash)) + if (parse_oid_hex(ref->name, &oid, &p) || + *p != '\0' || + oidcmp(&oid, &ref->old_oid)) continue; if ((allow_unadvertised_object_request & - (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1))) { + (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1)) || + tip_oids_contain(&tip_oids, unmatched, newlist, + &ref->old_oid)) { ref->match_status = REF_MATCHED; *newtail = copy_ref(ref); newtail = &(*newtail)->next; @@ -656,12 +686,19 @@ static void filter_refs(struct fetch_pack_args *args, ref->match_status = REF_UNADVERTISED_NOT_ALLOWED; } } + + oidset_clear(&tip_oids); + for (ref = unmatched; ref; ref = next) { + next = ref->next; + free(ref); + } + *refs = newlist; } static void mark_alternate_complete(struct object *obj) { - mark_complete(obj->oid.hash); + mark_complete(&obj->oid); } static int everything_local(struct fetch_pack_args *args, @@ -670,7 +707,7 @@ static int everything_local(struct fetch_pack_args *args, { struct ref *ref; int retval; - unsigned long cutoff = 0; + timestamp_t cutoff = 0; save_commit_buffer = 0; @@ -680,7 +717,7 @@ static int everything_local(struct fetch_pack_args *args, if (!has_object_file(&ref->old_oid)) continue; - o = parse_object(ref->old_oid.hash); + o = parse_object(&ref->old_oid); if (!o) continue; @@ -724,17 +761,17 @@ static int everything_local(struct fetch_pack_args *args, filter_refs(args, refs, sought, nr_sought); for (retval = 1, ref = *refs; ref ; ref = ref->next) { - const unsigned char *remote = ref->old_oid.hash; + const struct object_id *remote = &ref->old_oid; struct object *o; - o = lookup_object(remote); + o = lookup_object(remote->hash); if (!o || !(o->flags & COMPLETE)) { retval = 0; - print_verbose(args, "want %s (%s)", sha1_to_hex(remote), + print_verbose(args, "want %s (%s)", oid_to_hex(remote), ref->name); continue; } - print_verbose(args, _("already have %s (%s)"), sha1_to_hex(remote), + print_verbose(args, _("already have %s (%s)"), oid_to_hex(remote), ref->name); } return retval; @@ -873,7 +910,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, char **pack_lockfile) { struct ref *ref = copy_ref_list(orig_ref); - unsigned char sha1[20]; + struct object_id oid; const char *agent_feature; int agent_len; @@ -945,7 +982,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, packet_flush(fd[1]); goto all_done; } - if (find_common(args, fd, sha1, ref) < 0) + if (find_common(args, fd, &oid, ref) < 0) if (!args->keep_pack) /* When cloning, it is not unusual to have * no common commit. |