Skip to content

Commit

Permalink
connected: always use partial clone optimization
Browse files Browse the repository at this point in the history
With 5003377 ("connected: verify promisor-ness of partial clone",
2020-01-30), the fast path (checking promisor packs) in
check_connected() now passes a subset of the slow path (rev-list) - if
all objects to be checked are found in promisor packs, both the fast
path and the slow path will pass; otherwise, the fast path will
definitely not pass. This means that we can always attempt the fast path
whenever we need to do the slow path.

The fast path is currently guarded by a flag; therefore, remove that
flag. Also, make the fast path fallback to the slow path - if the fast
path fails, the failing OID and all remaining OIDs will be passed to
rev-list.

The main user-visible benefit is the performance of fetch from a partial
clone - specifically, the speedup of the connectivity check done before
the fetch. In particular, a no-op fetch into a partial clone on my
computer was sped up from 7 seconds to 0.01 seconds. This is a
complement to the work in 2df1aa2 ("fetch: forgo full
connectivity check if --filter", 2020-01-30), which is the child of the
aforementioned 5003377. In that commit, the connectivity check
*after* the fetch was sped up.

The addition of the fast path might cause performance reductions in
these cases:

 - If a partial clone or a fetch into a partial clone fails, Git will
   fruitlessly run rev-list (it is expected that everything fetched
   would go into promisor packs, so if that didn't happen, it is most
   likely that rev-list will fail too).

 - Any connectivity checks done by receive-pack, in the (in my opinion,
   unlikely) event that a partial clone serves receive-pack.

I think that these cases are rare enough, and the performance reduction
in this case minor enough (additional object DB access), that the
benefit of avoiding a flag outweighs these.

Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Reviewed-by: Josh Steadmon <steadmon@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
jonathantanmy authored and gitster committed Mar 29, 2020
1 parent 2df1aa2 commit 2b98478
Show file tree
Hide file tree
Showing 4 changed files with 9 additions and 23 deletions.
7 changes: 2 additions & 5 deletions builtin/clone.c
Expand Up @@ -672,8 +672,7 @@ static void update_remote_refs(const struct ref *refs,
const char *branch_top,
const char *msg,
struct transport *transport,
int check_connectivity,
int check_refs_are_promisor_objects_only)
int check_connectivity)
{
const struct ref *rm = mapped_refs;

Expand All @@ -682,8 +681,6 @@ static void update_remote_refs(const struct ref *refs,

opt.transport = transport;
opt.progress = transport->progress;
opt.check_refs_are_promisor_objects_only =
!!check_refs_are_promisor_objects_only;

if (check_connected(iterate_ref_map, &rm, &opt))
die(_("remote did not send all necessary objects"));
Expand Down Expand Up @@ -1270,7 +1267,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)

update_remote_refs(refs, mapped_refs, remote_head_points_at,
branch_top.buf, reflog_msg.buf, transport,
!is_local, filter_options.choice);
!is_local);

update_head(our_head_points_at, remote_head, reflog_msg.buf);

Expand Down
7 changes: 0 additions & 7 deletions builtin/fetch.c
Expand Up @@ -908,13 +908,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
if (!connectivity_checked) {
struct check_connected_options opt = CHECK_CONNECTED_INIT;

if (filter_options.choice)
/*
* Since a filter is specified, objects indirectly
* referenced by refs are allowed to be absent.
*/
opt.check_refs_are_promisor_objects_only = 1;

rm = ref_map;
if (check_connected(iterate_ref_map, &rm, &opt)) {
rc = error(_("%s did not send all necessary objects\n"), url);
Expand Down
9 changes: 7 additions & 2 deletions connected.c
Expand Up @@ -52,7 +52,7 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
strbuf_release(&idx_file);
}

if (opt->check_refs_are_promisor_objects_only) {
if (has_promisor_remote()) {
/*
* For partial clones, we don't want to have to do a regular
* connectivity check because we have to enumerate and exclude
Expand All @@ -71,13 +71,18 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
if (find_pack_entry_one(oid.hash, p))
goto promisor_pack_found;
}
return 1;
/*
* Fallback to rev-list with oid and the rest of the
* object IDs provided by fn.
*/
goto no_promisor_pack_found;
promisor_pack_found:
;
} while (!fn(cb_data, &oid));
return 0;
}

no_promisor_pack_found:
if (opt->shallow_file) {
argv_array_push(&rev_list.args, "--shallow-file");
argv_array_push(&rev_list.args, opt->shallow_file);
Expand Down
9 changes: 0 additions & 9 deletions connected.h
Expand Up @@ -46,15 +46,6 @@ struct check_connected_options {
* during a fetch.
*/
unsigned is_deepening_fetch : 1;

/*
* If non-zero, only check that the top-level objects referenced by the
* wanted refs (passed in as cb_data) are promisor objects. This is
* useful for partial clones, where enumerating and excluding all
* promisor objects is very slow and the commit-walk itself becomes a
* no-op.
*/
unsigned check_refs_are_promisor_objects_only : 1;
};

#define CHECK_CONNECTED_INIT { 0 }
Expand Down

0 comments on commit 2b98478

Please sign in to comment.