]>
Commit | Line | Data |
---|---|---|
4cf2143e JK |
1 | #!/bin/sh |
2 | ||
3 | test_description='test handling of inter-pack delta cycles during repack | |
4 | ||
5 | The goal here is to create a situation where we have two blobs, A and B, with A | |
6 | as a delta against B in one pack, and vice versa in the other. Then if we can | |
7 | persuade a full repack to find A from one pack and B from the other, that will | |
8 | give us a cycle when we attempt to reuse those deltas. | |
9 | ||
10 | The trick is in the "persuade" step, as it depends on the internals of how | |
11 | pack-objects picks which pack to reuse the deltas from. But we can assume | |
12 | that it does so in one of two general strategies: | |
13 | ||
14 | 1. Using a static ordering of packs. In this case, no inter-pack cycles can | |
15 | happen. Any objects with a delta relationship must be present in the same | |
16 | pack (i.e., no "--thin" packs on disk), so we will find all related objects | |
17 | from that pack. So assuming there are no cycles within a single pack (and | |
18 | we avoid generating them via pack-objects or importing them via | |
19 | index-pack), then our result will have no cycles. | |
20 | ||
21 | So this case should pass the tests no matter how we arrange things. | |
22 | ||
23 | 2. Picking the next pack to examine based on locality (i.e., where we found | |
24 | something else recently). | |
25 | ||
26 | In this case, we want to make sure that we find the delta versions of A and | |
27 | B and not their base versions. We can do this by putting two blobs in each | |
28 | pack. The first is a "dummy" blob that can only be found in the pack in | |
29 | question. And then the second is the actual delta we want to find. | |
30 | ||
31 | The two blobs must be present in the same tree, not present in other trees, | |
32 | and the dummy pathname must sort before the delta path. | |
33 | ||
34 | The setup below focuses on case 2. We have two commits HEAD and HEAD^, each | |
35 | which has two files: "dummy" and "file". Then we can make two packs which | |
36 | contain: | |
37 | ||
38 | [pack one] | |
39 | HEAD:dummy | |
40 | HEAD:file (as delta against HEAD^:file) | |
41 | HEAD^:file (as base) | |
42 | ||
43 | [pack two] | |
44 | HEAD^:dummy | |
45 | HEAD^:file (as delta against HEAD:file) | |
46 | HEAD:file (as base) | |
47 | ||
48 | Then no matter which order we start looking at the packs in, we know that we | |
49 | will always find a delta for "file", because its lookup will always come | |
50 | immediately after the lookup for "dummy". | |
51 | ' | |
52 | . ./test-lib.sh | |
53 | ||
54 | ||
55 | ||
56 | # Create a pack containing the the tree $1 and blob $1:file, with | |
57 | # the latter stored as a delta against $2:file. | |
58 | # | |
59 | # We convince pack-objects to make the delta in the direction of our choosing | |
60 | # by marking $2 as a preferred-base edge. That results in $1:file as a thin | |
61 | # delta, and index-pack completes it by adding $2:file as a base. | |
62 | # | |
63 | # Note that the two variants of "file" must be similar enough to convince git | |
64 | # to create the delta. | |
65 | make_pack () { | |
66 | { | |
67 | printf '%s\n' "-$(git rev-parse $2)" | |
68 | printf '%s dummy\n' "$(git rev-parse $1:dummy)" | |
69 | printf '%s file\n' "$(git rev-parse $1:file)" | |
70 | } | | |
71 | git pack-objects --stdout | | |
72 | git index-pack --stdin --fix-thin | |
73 | } | |
74 | ||
75 | test_expect_success 'setup' ' | |
c680668d | 76 | test-tool genrandom base 4096 >base && |
4cf2143e JK |
77 | for i in one two |
78 | do | |
79 | # we want shared content here to encourage deltas... | |
80 | cp base file && | |
81 | echo $i >>file && | |
82 | ||
83 | # ...whereas dummy should be short, because we do not want | |
84 | # deltas that would create duplicates when we --fix-thin | |
85 | echo $i >dummy && | |
86 | ||
87 | git add file dummy && | |
88 | test_tick && | |
89 | git commit -m $i || | |
90 | return 1 | |
91 | done && | |
92 | ||
93 | make_pack HEAD^ HEAD && | |
94 | make_pack HEAD HEAD^ | |
95 | ' | |
96 | ||
97 | test_expect_success 'repack' ' | |
98 | # We first want to check that we do not have any internal errors, | |
99 | # and also that we do not hit the last-ditch cycle-breaking code | |
100 | # in write_object(), which will issue a warning to stderr. | |
4cf2143e | 101 | git repack -ad 2>stderr && |
1c5e94f4 | 102 | test_must_be_empty stderr && |
4cf2143e JK |
103 | |
104 | # And then double-check that the resulting pack is usable (i.e., | |
105 | # we did not fail to notice any cycles). We know we are accessing | |
106 | # the objects via the new pack here, because "repack -d" will have | |
107 | # removed the others. | |
108 | git cat-file blob HEAD:file >/dev/null && | |
109 | git cat-file blob HEAD^:file >/dev/null | |
110 | ' | |
111 | ||
112 | test_done |