Skip to content

Commit dbcf611

Browse files
ttaylorrgitster
authored andcommitted
pack-revindex: introduce pack.readReverseIndex
Since 1615c56 (Documentation/config/pack.txt: advertise 'pack.writeReverseIndex', 2021-01-25), we have had the `pack.writeReverseIndex` configuration option, which tells Git whether or not it is allowed to write a ".rev" file when indexing a pack. Introduce a complementary configuration knob, `pack.readReverseIndex` to control whether or not Git will read any ".rev" file(s) that may be available on disk. This option is useful for debugging, as well as disabling the effect of ".rev" files in certain instances. This is useful because of the trade-off[^1] between the time it takes to generate a reverse index (slow from scratch, fast when reading an existing ".rev" file), and the time it takes to access a record (the opposite). For example, even though it is faster to use the on-disk reverse index when computing the on-disk size of a packed object, it is slower to enumerate the same value for all objects. Here are a couple of examples from linux.git. When computing the above for a single object, using the on-disk reverse index is significantly faster: $ git rev-parse HEAD >in $ hyperfine -L v false,true 'git.compile -c pack.readReverseIndex={v} cat-file --batch-check="%(objectsize:disk)" <in' Benchmark 1: git.compile -c pack.readReverseIndex=false cat-file --batch-check="%(objectsize:disk)" <in Time (mean ± σ): 302.5 ms ± 12.5 ms [User: 258.7 ms, System: 43.6 ms] Range (min … max): 291.1 ms … 328.1 ms 10 runs Benchmark 2: git.compile -c pack.readReverseIndex=true cat-file --batch-check="%(objectsize:disk)" <in Time (mean ± σ): 3.9 ms ± 0.3 ms [User: 1.6 ms, System: 2.4 ms] Range (min … max): 2.0 ms … 4.4 ms 801 runs Summary 'git.compile -c pack.readReverseIndex=true cat-file --batch-check="%(objectsize:disk)" <in' ran 77.29 ± 7.14 times faster than 'git.compile -c pack.readReverseIndex=false cat-file --batch-check="%(objectsize:disk)" <in' , but when instead trying to compute the on-disk object size for all objects in the repository, using the ".rev" file is a disadvantage over creating the reverse index from scratch: $ hyperfine -L v false,true 'git.compile -c pack.readReverseIndex={v} cat-file --batch-check="%(objectsize:disk)" --batch-all-objects' Benchmark 1: git.compile -c pack.readReverseIndex=false cat-file --batch-check="%(objectsize:disk)" --batch-all-objects Time (mean ± σ): 8.258 s ± 0.035 s [User: 7.949 s, System: 0.308 s] Range (min … max): 8.199 s … 8.293 s 10 runs Benchmark 2: git.compile -c pack.readReverseIndex=true cat-file --batch-check="%(objectsize:disk)" --batch-all-objects Time (mean ± σ): 16.976 s ± 0.107 s [User: 16.706 s, System: 0.268 s] Range (min … max): 16.839 s … 17.105 s 10 runs Summary 'git.compile -c pack.readReverseIndex=false cat-file --batch-check="%(objectsize:disk)" --batch-all-objects' ran 2.06 ± 0.02 times faster than 'git.compile -c pack.readReverseIndex=true cat-file --batch-check="%(objectsize:disk)" --batch-all-objects' Luckily, the results when running `git cat-file` with `--unordered` are closer together: $ hyperfine -L v false,true 'git.compile -c pack.readReverseIndex={v} cat-file --unordered --batch-check="%(objectsize:disk)" --batch-all-objects' Benchmark 1: git.compile -c pack.readReverseIndex=false cat-file --unordered --batch-check="%(objectsize:disk)" --batch-all-objects Time (mean ± σ): 5.066 s ± 0.105 s [User: 4.792 s, System: 0.274 s] Range (min … max): 4.943 s … 5.220 s 10 runs Benchmark 2: git.compile -c pack.readReverseIndex=true cat-file --unordered --batch-check="%(objectsize:disk)" --batch-all-objects Time (mean ± σ): 6.193 s ± 0.069 s [User: 5.937 s, System: 0.255 s] Range (min … max): 6.145 s … 6.356 s 10 runs Summary 'git.compile -c pack.readReverseIndex=false cat-file --unordered --batch-check="%(objectsize:disk)" --batch-all-objects' ran 1.22 ± 0.03 times faster than 'git.compile -c pack.readReverseIndex=true cat-file --unordered --batch-check="%(objectsize:disk)" --batch-all-objects' Because the equilibrium point between these two is highly machine- and repository-dependent, allow users to configure whether or not they will read any ".rev" file(s) with this configuration knob. [^1]: Generating a reverse index in memory takes O(N) time (where N is the number of objects in the repository), since we use a radix sort. Reading an entry from an on-disk ".rev" file is slower since each operation is bound by disk I/O instead of memory I/O. In order to compute the on-disk size of a packed object, we need to find the offset of our object, and the adjacent object (the on-disk size difference of these two). Finding the first offset requires a binary search. Finding the latter involves a single .rev lookup. Signed-off-by: Taylor Blau <[email protected]> Acked-by: Derrick Stolee <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 2a250d6 commit dbcf611

File tree

5 files changed

+23
-1
lines changed

5 files changed

+23
-1
lines changed

Documentation/config/pack.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,12 @@ pack.writeBitmapLookupTable::
171171
beneficial in repositories that have relatively large bitmap
172172
indexes. Defaults to false.
173173

174+
pack.readReverseIndex::
175+
When true, git will read any .rev file(s) that may be available
176+
(see: linkgit:gitformat-pack[5]). When false, the reverse index
177+
will be generated from scratch and stored in memory. Defaults to
178+
true.
179+
174180
pack.writeReverseIndex::
175181
When true, git will write a corresponding .rev file (see:
176182
linkgit:gitformat-pack[5])

pack-revindex.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,10 @@ int load_pack_revindex(struct repository *r, struct packed_git *p)
291291
if (p->revindex || p->revindex_data)
292292
return 0;
293293

294-
if (!load_pack_revindex_from_disk(p))
294+
prepare_repo_settings(r);
295+
296+
if (r->settings.pack_read_reverse_index &&
297+
!load_pack_revindex_from_disk(p))
295298
return 0;
296299
else if (!create_pack_revindex_in_memory(p))
297300
return 0;

repo-settings.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ void prepare_repo_settings(struct repository *r)
6363
repo_cfg_bool(r, "core.multipackindex", &r->settings.core_multi_pack_index, 1);
6464
repo_cfg_bool(r, "index.sparse", &r->settings.sparse_index, 0);
6565
repo_cfg_bool(r, "index.skiphash", &r->settings.index_skip_hash, r->settings.index_skip_hash);
66+
repo_cfg_bool(r, "pack.readreverseindex", &r->settings.pack_read_reverse_index, 1);
6667

6768
/*
6869
* The GIT_TEST_MULTI_PACK_INDEX variable is special in that

repository.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ struct repo_settings {
3737
int fetch_write_commit_graph;
3838
int command_requires_full_index;
3939
int sparse_index;
40+
int pack_read_reverse_index;
4041

4142
struct fsmonitor_settings *fsmonitor; /* lazily loaded */
4243

t/t5325-reverse-index.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,17 @@ test_expect_success 'reverse index is not generated when available on disk' '
9696
--batch-check="%(objectsize:disk)" <tip
9797
'
9898

99+
test_expect_success 'reverse index is ignored when pack.readReverseIndex is false' '
100+
test_index_pack true &&
101+
test_path_is_file $rev &&
102+
103+
test_config pack.readReverseIndex false &&
104+
105+
git rev-parse HEAD >tip &&
106+
GIT_TEST_REV_INDEX_DIE_ON_DISK=1 git cat-file \
107+
--batch-check="%(objectsize:disk)" <tip
108+
'
109+
99110
test_expect_success 'revindex in-memory vs on-disk' '
100111
git init repo &&
101112
test_when_finished "rm -fr repo" &&

0 commit comments

Comments
 (0)