refs/reftable: allow configuring restart interval

Add a new option `reftable.restartInterval` that allows the user to control the restart interval when writing reftable records used by the reftable library. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed May 13, 2024 at 10:18 UTC 90db611c2a1f4ca2123ef5a8d7e592fa348bb23b
3 files changed +66
Documentation/config/reftable.txt
+18
@@ -12,3 +12,21 @@ readers during access.
12 +
13 The largest block size is `16777215` bytes (15.99 MiB). The default value is
14 `4096` bytes (4kB). A value of `0` will use the default value.
15 +
16 +reftable.restartInterval::
17 + The interval at which to create restart points. The reftable backend
18 + determines the restart points at file creation. Every 16 may be
19 + more suitable for smaller block sizes (4k or 8k), every 64 for larger
20 + block sizes (64k).
21 ++
22 +More frequent restart points reduces prefix compression and increases
23 +space consumed by the restart table, both of which increase file size.
24 ++
25 +Less frequent restart points makes prefix compression more effective,
26 +decreasing overall file size, with increased penalties for readers
27 +walking through more records after the binary search step.
28 ++
29 +A maximum of `65535` restart points per block is supported.
30 ++
31 +The default value is to create restart points every 16 records. A value of `0`
32 +will use the default value.
refs/reftable-backend.c
+5
@@ -240,6 +240,11 @@ static int reftable_be_config(const char *var, const char *value,
240 if (block_size > 16777215)
241 die("reftable block size cannot exceed 16MB");
242 opts->block_size = block_size;
243 + } else if (!strcmp(var, "reftable.restartinterval")) {
244 + unsigned long restart_interval = git_config_ulong(var, value, ctx->kvi);
245 + if (restart_interval > UINT16_MAX)
246 + die("reftable block size cannot exceed %u", (unsigned)UINT16_MAX);
247 + opts->restart_interval = restart_interval;
248 }
249
250 return 0;
t/t0613-reftable-write-options.sh
+43
@@ -171,4 +171,47 @@ test_expect_success 'block size exceeding maximum supported size' '
171 )
172 '
173
174 +test_expect_success 'restart interval at every single record' '
175 + test_when_finished "rm -rf repo" &&
176 + git init repo &&
177 + (
178 + cd repo &&
179 + test_commit initial &&
180 + for i in $(test_seq 10)
181 + do
182 + printf "update refs/heads/branch-%d HEAD\n" "$i" ||
183 + return 1
184 + done >input &&
185 + git update-ref --stdin <input &&
186 + git -c reftable.restartInterval=1 pack-refs &&
187 +
188 + cat >expect <<-EOF &&
189 + header:
190 + block_size: 4096
191 + ref:
192 + - length: 566
193 + restarts: 13
194 + log:
195 + - length: 1393
196 + restarts: 12
197 + EOF
198 + test-tool dump-reftable -b .git/reftable/*.ref >actual &&
199 + test_cmp expect actual
200 + )
201 +'
202 +
203 +test_expect_success 'restart interval exceeding maximum supported interval' '
204 + test_when_finished "rm -rf repo" &&
205 + git init repo &&
206 + (
207 + cd repo &&
208 + test_commit initial &&
209 + cat >expect <<-EOF &&
210 + fatal: reftable block size cannot exceed 65535
211 + EOF
212 + test_must_fail git -c reftable.restartInterval=65536 pack-refs 2>err &&
213 + test_cmp expect err
214 + )
215 +'
216 +
217 test_done