clone: do faster object check for partial clones

For partial clones, doing a full connectivity check is wasteful; we skip promisor objects (which, for a partial clone, is all known objects), and enumerating them all to exclude them from the connectivity check can take a significant amount of time on large repos. At most, we want to make sure that we get the objects referred to by any wanted refs. For partial clones, just check that these objects were transferred. Signed-off-by: Josh Steadmon <steadmon@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Josh Steadmon committed Apr 19, 2019 at 14:00 UTC dfa33a298de2ab724d4812633bb009a90d1df790
3 files changed +29 -2
builtin/clone.c
+4 -2
@@ -657,7 +657,8 @@ static void update_remote_refs(const struct ref *refs,
657 const char *branch_top,
658 const char *msg,
659 struct transport *transport,
660 - int check_connectivity)
660 + int check_connectivity,
661 + int check_refs_only)
662 {
663 const struct ref *rm = mapped_refs;
664
@@ -666,6 +667,7 @@ static void update_remote_refs(const struct ref *refs,
667
668 opt.transport = transport;
669 opt.progress = transport->progress;
670 + opt.check_refs_only = !!check_refs_only;
671
672 if (check_connected(iterate_ref_map, &rm, &opt))
673 die(_("remote did not send all necessary objects"));
@@ -1224,7 +1226,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
1226
1227 update_remote_refs(refs, mapped_refs, remote_head_points_at,
1228 branch_top.buf, reflog_msg.buf, transport,
1227 - !is_local);
1229 + !is_local, filter_options.choice);
1230
1231 update_head(our_head_points_at, remote_head, reflog_msg.buf);
1232
connected.c
+17
@@ -1,4 +1,5 @@
1 #include "cache.h"
2 +#include "object-store.h"
3 #include "run-command.h"
4 #include "sigchain.h"
5 #include "connected.h"
@@ -49,6 +50,22 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
50 strbuf_release(&idx_file);
51 }
52
53 + if (opt->check_refs_only) {
54 + /*
55 + * For partial clones, we don't want to have to do a regular
56 + * connectivity check because we have to enumerate and exclude
57 + * all promisor objects (slow), and then the connectivity check
58 + * itself becomes a no-op because in a partial clone every
59 + * object is a promisor object. Instead, just make sure we
60 + * received the objects pointed to by each wanted ref.
61 + */
62 + do {
63 + if (!repo_has_object_file(the_repository, &oid))
64 + return 1;
65 + } while (!fn(cb_data, &oid));
66 + return 0;
67 + }
68 +
69 if (opt->shallow_file) {
70 argv_array_push(&rev_list.args, "--shallow-file");
71 argv_array_push(&rev_list.args, opt->shallow_file);
connected.h
+8
@@ -46,6 +46,14 @@ struct check_connected_options {
46 * during a fetch.
47 */
48 unsigned is_deepening_fetch : 1;
49 +
50 + /*
51 + * If non-zero, only check the top-level objects referenced by the
52 + * wanted refs (passed in as cb_data). This is useful for partial
53 + * clones, where enumerating and excluding all promisor objects is very
54 + * slow and the commit-walk itself becomes a no-op.
55 + */
56 + unsigned check_refs_only : 1;
57 };
58
59 #define CHECK_CONNECTED_INIT { 0 }