Skip to content

Commit 23528d3

Browse files
committed
Merge branch 'ps/reftable-write-options'
The knobs to tweak how reftable files are written have been made available as configuration variables. * ps/reftable-write-options: refs/reftable: allow configuring geometric factor reftable: make the compaction factor configurable refs/reftable: allow disabling writing the object index refs/reftable: allow configuring restart interval reftable: use `uint16_t` to track restart interval refs/reftable: allow configuring block size reftable/dump: support dumping a table's block structure reftable/writer: improve error when passed an invalid block size reftable/writer: drop static variable used to initialize strbuf reftable: pass opts as constant pointer reftable: consistently refer to `reftable_write_options` as `opts`
2 parents a60c21b + f518d91 commit 23528d3

File tree

15 files changed

+566
-115
lines changed

15 files changed

+566
-115
lines changed

Documentation/config.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,8 @@ include::config/rebase.txt[]
498498

499499
include::config/receive.txt[]
500500

501+
include::config/reftable.txt[]
502+
501503
include::config/remote.txt[]
502504

503505
include::config/remotes.txt[]

Documentation/config/reftable.txt

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
reftable.blockSize::
2+
The size in bytes used by the reftable backend when writing blocks.
3+
The block size is determined by the writer, and does not have to be a
4+
power of 2. The block size must be larger than the longest reference
5+
name or log entry used in the repository, as references cannot span
6+
blocks.
7+
+
8+
Powers of two that are friendly to the virtual memory system or
9+
filesystem (such as 4kB or 8kB) are recommended. Larger sizes (64kB) can
10+
yield better compression, with a possible increased cost incurred by
11+
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.
33+
34+
reftable.indexObjects::
35+
Whether the reftable backend shall write object blocks. Object blocks
36+
are a reverse mapping of object ID to the references pointing to them.
37+
+
38+
The default value is `true`.
39+
40+
reftable.geometricFactor::
41+
Whenever the reftable backend appends a new table to the stack, it
42+
performs auto compaction to ensure that there is only a handful of
43+
tables. The backend does this by ensuring that tables form a geometric
44+
sequence regarding the respective sizes of each table.
45+
+
46+
By default, the geometric sequence uses a factor of 2, meaning that for any
47+
table, the next-biggest table must at least be twice as big. A maximum factor
48+
of 256 is supported.

refs/reftable-backend.c

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "../git-compat-util.h"
22
#include "../abspath.h"
33
#include "../chdir-notify.h"
4+
#include "../config.h"
45
#include "../environment.h"
56
#include "../gettext.h"
67
#include "../hash.h"
@@ -129,7 +130,7 @@ static struct reftable_stack *stack_for(struct reftable_ref_store *store,
129130
store->base.repo->commondir, wtname_buf.buf);
130131

131132
store->err = reftable_new_stack(&stack, wt_dir.buf,
132-
store->write_options);
133+
&store->write_options);
133134
assert(store->err != REFTABLE_API_ERROR);
134135
strmap_put(&store->worktree_stacks, wtname_buf.buf, stack);
135136
}
@@ -228,6 +229,34 @@ static int read_ref_without_reload(struct reftable_stack *stack,
228229
return ret;
229230
}
230231

232+
static int reftable_be_config(const char *var, const char *value,
233+
const struct config_context *ctx,
234+
void *_opts)
235+
{
236+
struct reftable_write_options *opts = _opts;
237+
238+
if (!strcmp(var, "reftable.blocksize")) {
239+
unsigned long block_size = git_config_ulong(var, value, ctx->kvi);
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+
} else if (!strcmp(var, "reftable.indexobjects")) {
249+
opts->skip_index_objects = !git_config_bool(var, value);
250+
} else if (!strcmp(var, "reftable.geometricfactor")) {
251+
unsigned long factor = git_config_ulong(var, value, ctx->kvi);
252+
if (factor > UINT8_MAX)
253+
die("reftable geometric factor cannot exceed %u", (unsigned)UINT8_MAX);
254+
opts->auto_compaction_factor = factor;
255+
}
256+
257+
return 0;
258+
}
259+
231260
static struct ref_store *reftable_be_init(struct repository *repo,
232261
const char *gitdir,
233262
unsigned int store_flags)
@@ -243,12 +272,24 @@ static struct ref_store *reftable_be_init(struct repository *repo,
243272
base_ref_store_init(&refs->base, repo, gitdir, &refs_be_reftable);
244273
strmap_init(&refs->worktree_stacks);
245274
refs->store_flags = store_flags;
246-
refs->write_options.block_size = 4096;
275+
247276
refs->write_options.hash_id = repo->hash_algo->format_id;
248277
refs->write_options.default_permissions = calc_shared_perm(0666 & ~mask);
249278
refs->write_options.disable_auto_compact =
250279
!git_env_bool("GIT_TEST_REFTABLE_AUTOCOMPACTION", 1);
251280

281+
git_config(reftable_be_config, &refs->write_options);
282+
283+
/*
284+
* It is somewhat unfortunate that we have to mirror the default block
285+
* size of the reftable library here. But given that the write options
286+
* wouldn't be updated by the library here, and given that we require
287+
* the proper block size to trim reflog message so that they fit, we
288+
* must set up a proper value here.
289+
*/
290+
if (!refs->write_options.block_size)
291+
refs->write_options.block_size = 4096;
292+
252293
/*
253294
* Set up the main reftable stack that is hosted in GIT_COMMON_DIR.
254295
* This stack contains both the shared and the main worktree refs.
@@ -263,7 +304,7 @@ static struct ref_store *reftable_be_init(struct repository *repo,
263304
}
264305
strbuf_addstr(&path, "/reftable");
265306
refs->err = reftable_new_stack(&refs->main_stack, path.buf,
266-
refs->write_options);
307+
&refs->write_options);
267308
if (refs->err)
268309
goto done;
269310

@@ -280,7 +321,7 @@ static struct ref_store *reftable_be_init(struct repository *repo,
280321
strbuf_addf(&path, "%s/reftable", gitdir);
281322

282323
refs->err = reftable_new_stack(&refs->worktree_stack, path.buf,
283-
refs->write_options);
324+
&refs->write_options);
284325
if (refs->err)
285326
goto done;
286327
}

reftable/block.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ struct block_writer {
2929
uint32_t header_off;
3030

3131
/* How often to restart keys. */
32-
int restart_interval;
32+
uint16_t restart_interval;
3333
int hash_size;
3434

3535
/* Offset of next uint8_t to write. */

reftable/constants.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ license that can be found in the LICENSE file or at
1717

1818
#define MAX_RESTARTS ((1 << 16) - 1)
1919
#define DEFAULT_BLOCK_SIZE 4096
20+
#define DEFAULT_GEOMETRIC_FACTOR 2
2021

2122
#endif

reftable/dump.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ license that can be found in the LICENSE file or at
2727
static int compact_stack(const char *stackdir)
2828
{
2929
struct reftable_stack *stack = NULL;
30-
struct reftable_write_options cfg = { 0 };
30+
struct reftable_write_options opts = { 0 };
3131

32-
int err = reftable_new_stack(&stack, stackdir, cfg);
32+
int err = reftable_new_stack(&stack, stackdir, &opts);
3333
if (err < 0)
3434
goto done;
3535

@@ -48,6 +48,7 @@ static void print_help(void)
4848
printf("usage: dump [-cst] arg\n\n"
4949
"options: \n"
5050
" -c compact\n"
51+
" -b dump blocks\n"
5152
" -t dump table\n"
5253
" -s dump stack\n"
5354
" -6 sha256 hash format\n"
@@ -58,6 +59,7 @@ static void print_help(void)
5859
int reftable_dump_main(int argc, char *const *argv)
5960
{
6061
int err = 0;
62+
int opt_dump_blocks = 0;
6163
int opt_dump_table = 0;
6264
int opt_dump_stack = 0;
6365
int opt_compact = 0;
@@ -67,6 +69,8 @@ int reftable_dump_main(int argc, char *const *argv)
6769
for (; argc > 1; argv++, argc--)
6870
if (*argv[1] != '-')
6971
break;
72+
else if (!strcmp("-b", argv[1]))
73+
opt_dump_blocks = 1;
7074
else if (!strcmp("-t", argv[1]))
7175
opt_dump_table = 1;
7276
else if (!strcmp("-6", argv[1]))
@@ -88,7 +92,9 @@ int reftable_dump_main(int argc, char *const *argv)
8892

8993
arg = argv[1];
9094

91-
if (opt_dump_table) {
95+
if (opt_dump_blocks) {
96+
err = reftable_reader_print_blocks(arg);
97+
} else if (opt_dump_table) {
9298
err = reftable_reader_print_file(arg);
9399
} else if (opt_dump_stack) {
94100
err = reftable_stack_print_directory(arg, opt_hash_id);

reftable/reader.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,3 +856,66 @@ int reftable_reader_print_file(const char *tablename)
856856
reftable_reader_free(r);
857857
return err;
858858
}
859+
860+
int reftable_reader_print_blocks(const char *tablename)
861+
{
862+
struct {
863+
const char *name;
864+
int type;
865+
} sections[] = {
866+
{
867+
.name = "ref",
868+
.type = BLOCK_TYPE_REF,
869+
},
870+
{
871+
.name = "obj",
872+
.type = BLOCK_TYPE_OBJ,
873+
},
874+
{
875+
.name = "log",
876+
.type = BLOCK_TYPE_LOG,
877+
},
878+
};
879+
struct reftable_block_source src = { 0 };
880+
struct table_iter ti = TABLE_ITER_INIT;
881+
struct reftable_reader *r = NULL;
882+
size_t i;
883+
int err;
884+
885+
err = reftable_block_source_from_file(&src, tablename);
886+
if (err < 0)
887+
goto done;
888+
889+
err = reftable_new_reader(&r, &src, tablename);
890+
if (err < 0)
891+
goto done;
892+
893+
printf("header:\n");
894+
printf(" block_size: %d\n", r->block_size);
895+
896+
for (i = 0; i < ARRAY_SIZE(sections); i++) {
897+
err = reader_start(r, &ti, sections[i].type, 0);
898+
if (err < 0)
899+
goto done;
900+
if (err > 0)
901+
continue;
902+
903+
printf("%s:\n", sections[i].name);
904+
905+
while (1) {
906+
printf(" - length: %u\n", ti.br.block_len);
907+
printf(" restarts: %u\n", ti.br.restart_count);
908+
909+
err = table_iter_next_block(&ti);
910+
if (err < 0)
911+
goto done;
912+
if (err > 0)
913+
break;
914+
}
915+
}
916+
917+
done:
918+
reftable_reader_free(r);
919+
table_iter_close(&ti);
920+
return err;
921+
}

reftable/reftable-reader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,5 +97,7 @@ void reftable_table_from_reader(struct reftable_table *tab,
9797

9898
/* print table onto stdout for debugging. */
9999
int reftable_reader_print_file(const char *tablename);
100+
/* print blocks onto stdout for debugging. */
101+
int reftable_reader_print_blocks(const char *tablename);
100102

101103
#endif

reftable/reftable-stack.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ struct reftable_stack;
2929
* stored in 'dir'. Typically, this should be .git/reftables.
3030
*/
3131
int reftable_new_stack(struct reftable_stack **dest, const char *dir,
32-
struct reftable_write_options config);
32+
const struct reftable_write_options *opts);
3333

3434
/* returns the update_index at which a next table should be written. */
3535
uint64_t reftable_stack_next_update_index(struct reftable_stack *st);

reftable/reftable-writer.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ struct reftable_write_options {
2828
unsigned skip_index_objects : 1;
2929

3030
/* how often to write complete keys in each block. */
31-
int restart_interval;
31+
uint16_t restart_interval;
3232

3333
/* 4-byte identifier ("sha1", "s256") of the hash.
3434
* Defaults to SHA1 if unset
@@ -45,6 +45,12 @@ struct reftable_write_options {
4545

4646
/* boolean: Prevent auto-compaction of tables. */
4747
unsigned disable_auto_compact : 1;
48+
49+
/*
50+
* Geometric sequence factor used by auto-compaction to decide which
51+
* tables to compact. Defaults to 2 if unset.
52+
*/
53+
uint8_t auto_compaction_factor;
4854
};
4955

5056
/* reftable_block_stats holds statistics for a single block type */
@@ -88,7 +94,7 @@ struct reftable_stats {
8894
struct reftable_writer *
8995
reftable_new_writer(ssize_t (*writer_func)(void *, const void *, size_t),
9096
int (*flush_func)(void *),
91-
void *writer_arg, struct reftable_write_options *opts);
97+
void *writer_arg, const struct reftable_write_options *opts);
9298

9399
/* Set the range of update indices for the records we will add. When writing a
94100
table into a stack, the min should be at least

0 commit comments

Comments
 (0)