Skip to content

Commit d3da223

Browse files
jonathantanmygitster
authored andcommitted
cache-tree: prefetch in partial clone read-tree
"git read-tree" checks the existence of the blobs referenced by the given tree, but does not bulk prefetch them. Add a bulk prefetch. The lack of prefetch here was noticed at $DAYJOB during a merge involving some specific commits, but I couldn't find a minimal merge that didn't also trigger the prefetch in check_updates() in unpack-trees.c (and in all these cases, the lack of prefetch in cache-tree.c didn't matter because all the relevant blobs would have already been prefetched by then). This is why I used read-tree here to exercise this code path. Signed-off-by: Jonathan Tan <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent b2896d2 commit d3da223

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

cache-tree.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,11 @@ int cache_tree_fully_valid(struct cache_tree *it)
237237
return 1;
238238
}
239239

240+
static int must_check_existence(const struct cache_entry *ce)
241+
{
242+
return !(has_promisor_remote() && ce_skip_worktree(ce));
243+
}
244+
240245
static int update_one(struct cache_tree *it,
241246
struct cache_entry **cache,
242247
int entries,
@@ -378,8 +383,7 @@ static int update_one(struct cache_tree *it,
378383
}
379384

380385
ce_missing_ok = mode == S_IFGITLINK || missing_ok ||
381-
(has_promisor_remote() &&
382-
ce_skip_worktree(ce));
386+
!must_check_existence(ce);
383387
if (is_null_oid(oid) ||
384388
(!ce_missing_ok && !has_object_file(oid))) {
385389
strbuf_release(&buffer);
@@ -466,6 +470,9 @@ int cache_tree_update(struct index_state *istate, int flags)
466470
if (!istate->cache_tree)
467471
istate->cache_tree = cache_tree();
468472

473+
if (!(flags & WRITE_TREE_MISSING_OK) && has_promisor_remote())
474+
prefetch_cache_entries(istate, must_check_existence);
475+
469476
trace_performance_enter();
470477
trace2_region_enter("cache_tree", "update", the_repository);
471478
i = update_one(istate->cache_tree, istate->cache, istate->cache_nr,

t/t1022-read-tree-partial-clone.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/bin/sh
2+
3+
test_description='git read-tree in partial clones'
4+
5+
TEST_NO_CREATE_REPO=1
6+
7+
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
8+
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
9+
10+
. ./test-lib.sh
11+
12+
test_expect_success 'read-tree in partial clone prefetches in one batch' '
13+
test_when_finished "rm -rf server client trace" &&
14+
15+
git init server &&
16+
echo foo >server/one &&
17+
echo bar >server/two &&
18+
git -C server add one two &&
19+
git -C server commit -m "initial commit" &&
20+
TREE=$(git -C server rev-parse HEAD^{tree}) &&
21+
22+
git -C server config uploadpack.allowfilter 1 &&
23+
git -C server config uploadpack.allowanysha1inwant 1 &&
24+
git clone --bare --filter=blob:none "file://$(pwd)/server" client &&
25+
GIT_TRACE_PACKET="$(pwd)/trace" git -C client read-tree $TREE &&
26+
27+
# "done" marks the end of negotiation (once per fetch). Expect that
28+
# only one fetch occurs.
29+
grep "fetch> done" trace >donelines &&
30+
test_line_count = 1 donelines
31+
'
32+
33+
test_done

0 commit comments

Comments
 (0)