Skip to content

Commit 2db1a43

Browse files
vmggitster
authored andcommitted
add ignore_missing_links mode to revwalk
When pack-objects is computing the reachability bitmap to serve a fetch request, it can erroneously die() if some of the UNINTERESTING objects are not present. Upload-pack throws away HAVE lines from the client for objects we do not have, but we may have a tip object without all of its ancestors (e.g., if the tip is no longer reachable and was new enough to survive a `git prune`, but some of its reachable objects did get pruned). In the non-bitmap case, we do a revision walk with the HAVE objects marked as UNINTERESTING. The revision walker explicitly ignores errors in accessing UNINTERESTING commits to handle this case (and we do not bother looking at UNINTERESTING trees or blobs at all). When we have bitmaps, however, the process is quite different. The bitmap index for a pack-objects run is calculated in two separate steps: First, we perform an extensive walk from all the HAVEs to find the full set of objects reachable from them. This walk is usually optimized away because we are expected to hit an object with a bitmap during the traversal, which allows us to terminate early. Secondly, we perform an extensive walk from all the WANTs, which usually also terminates early because we hit a commit with an existing bitmap. Once we have the resulting bitmaps from the two walks, we AND-NOT them together to obtain the resulting set of objects we need to pack. When we are walking the HAVE objects, the revision walker does not know that we are walking it only to mark the results as uninteresting. We strip out the UNINTERESTING flag, because those objects _are_ interesting to us during the first walk. We want to keep going to get a complete set of reachable objects if we can. We need some way to tell the revision walker that it's OK to silently truncate the HAVE walk, just like it does for the UNINTERESTING case. This patch introduces a new `ignore_missing_links` flag to the `rev_info` struct, which we set only for the HAVE walk. It also adds tests to cover UNINTERESTING objects missing from several positions: a missing blob, a missing tree, and a missing parent commit. The missing blob already worked (as we do not care about its contents at all), but the other two cases caused us to die(). Note that there are a few cases we do not need to test: 1. We do not need to test a missing tree, with the blob still present. Without the tree that refers to it, we would not know that the blob is relevant to our walk. 2. We do not need to test a tip commit that is missing. Upload-pack omits these for us (and in fact, we complain even in the non-bitmap case if it fails to do so). Reported-by: Siddharth Agarwal <[email protected]> Signed-off-by: Vicent Marti <[email protected]> Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 373c67d commit 2db1a43

File tree

5 files changed

+44
-5
lines changed

5 files changed

+44
-5
lines changed

list-objects.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,11 @@ static void process_tree(struct rev_info *revs,
8181
die("bad tree object");
8282
if (obj->flags & (UNINTERESTING | SEEN))
8383
return;
84-
if (parse_tree(tree) < 0)
84+
if (parse_tree(tree) < 0) {
85+
if (revs->ignore_missing_links)
86+
return;
8587
die("bad tree object %s", sha1_to_hex(obj->sha1));
88+
}
8689
obj->flags |= SEEN;
8790
show(obj, path, name, cb_data);
8891
me.up = path;

pack-bitmap.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,8 +727,10 @@ int prepare_bitmap_walk(struct rev_info *revs)
727727
revs->pending.objects = NULL;
728728

729729
if (haves) {
730+
revs->ignore_missing_links = 1;
730731
haves_bitmap = find_objects(revs, haves, NULL);
731732
reset_revision_walk();
733+
revs->ignore_missing_links = 0;
732734

733735
if (haves_bitmap == NULL)
734736
die("BUG: failed to perform bitmap walk");

revision.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2866,9 +2866,11 @@ static struct commit *get_revision_1(struct rev_info *revs)
28662866
if (revs->max_age != -1 &&
28672867
(commit->date < revs->max_age))
28682868
continue;
2869-
if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0)
2870-
die("Failed to traverse parents of commit %s",
2871-
sha1_to_hex(commit->object.sha1));
2869+
if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0) {
2870+
if (!revs->ignore_missing_links)
2871+
die("Failed to traverse parents of commit %s",
2872+
sha1_to_hex(commit->object.sha1));
2873+
}
28722874
}
28732875

28742876
switch (simplify_commit(revs, commit)) {

revision.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ struct rev_info {
6969
enum rev_sort_order sort_order;
7070

7171
unsigned int early_output:1,
72-
ignore_missing:1;
72+
ignore_missing:1,
73+
ignore_missing_links:1;
7374

7475
/* Traversal flags */
7576
unsigned int dense:1,

t/t5310-pack-bitmaps.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
test_description='exercise basic bitmap functionality'
44
. ./test-lib.sh
55

6+
objpath () {
7+
echo ".git/objects/$(echo "$1" | sed -e 's|\(..\)|\1/|')"
8+
}
9+
610
test_expect_success 'setup repo with moderate-sized history' '
711
for i in $(test_seq 1 10); do
812
test_commit $i
@@ -115,6 +119,33 @@ test_expect_success 'fetch (full bitmap)' '
115119
test_cmp expect actual
116120
'
117121

122+
test_expect_success 'create objects for missing-HAVE tests' '
123+
blob=$(echo "missing have" | git hash-object -w --stdin) &&
124+
tree=$(printf "100644 blob $blob\tfile\n" | git mktree) &&
125+
parent=$(echo parent | git commit-tree $tree) &&
126+
commit=$(echo commit | git commit-tree $tree -p $parent) &&
127+
cat >revs <<-EOF
128+
HEAD
129+
^HEAD^
130+
^$commit
131+
EOF
132+
'
133+
134+
test_expect_success 'pack with missing blob' '
135+
rm $(objpath $blob) &&
136+
git pack-objects --stdout --revs <revs >/dev/null
137+
'
138+
139+
test_expect_success 'pack with missing tree' '
140+
rm $(objpath $tree) &&
141+
git pack-objects --stdout --revs <revs >/dev/null
142+
'
143+
144+
test_expect_success 'pack with missing parent' '
145+
rm $(objpath $parent) &&
146+
git pack-objects --stdout --revs <revs >/dev/null
147+
'
148+
118149
test_lazy_prereq JGIT '
119150
type jgit
120151
'

0 commit comments

Comments
 (0)