Skip to content

Commit b8ca235

Browse files
pks-tgitster
authored andcommitted
reftable/merged: stop using generic tables in the merged table
The merged table provides access to a reftable stack by merging the contents of those tables into a virtual table. These subtables are being tracked via `struct reftable_table`, which is a generic interface for accessing either a single reftable or a merged reftable. So in theory, it would be possible for the merged table to merge together other merged tables. This is somewhat nonsensical though: we only ever set up a merged table over normal reftables, and there is no reason to do otherwise. This generic interface thus makes the code way harder to follow and reason about than really necessary. The abstraction layer may also have an impact on performance, even though the extra set of vtable function calls probably doesn't really matter. Refactor the merged tables to use a `struct reftable_reader` for each of the subtables instead, which gives us direct access to the underlying tables. Adjust names accordingly. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 6631ed3 commit b8ca235

File tree

8 files changed

+60
-75
lines changed

8 files changed

+60
-75
lines changed

reftable/merged.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ license that can be found in the LICENSE file or at
1111
#include "constants.h"
1212
#include "iter.h"
1313
#include "pq.h"
14+
#include "reader.h"
1415
#include "record.h"
1516
#include "generic.h"
1617
#include "reftable-merged.h"
@@ -25,7 +26,7 @@ struct merged_subiter {
2526
struct merged_iter {
2627
struct merged_subiter *subiters;
2728
struct merged_iter_pqueue pq;
28-
size_t stack_len;
29+
size_t subiters_len;
2930
int suppress_deletions;
3031
ssize_t advance_index;
3132
};
@@ -38,20 +39,20 @@ static void merged_iter_init(struct merged_iter *mi,
3839
mi->advance_index = -1;
3940
mi->suppress_deletions = mt->suppress_deletions;
4041

41-
REFTABLE_CALLOC_ARRAY(mi->subiters, mt->stack_len);
42-
for (size_t i = 0; i < mt->stack_len; i++) {
42+
REFTABLE_CALLOC_ARRAY(mi->subiters, mt->readers_len);
43+
for (size_t i = 0; i < mt->readers_len; i++) {
4344
reftable_record_init(&mi->subiters[i].rec, typ);
44-
table_init_iter(&mt->stack[i], &mi->subiters[i].iter, typ);
45+
reader_init_iter(mt->readers[i], &mi->subiters[i].iter, typ);
4546
}
46-
mi->stack_len = mt->stack_len;
47+
mi->subiters_len = mt->readers_len;
4748
}
4849

4950
static void merged_iter_close(void *p)
5051
{
5152
struct merged_iter *mi = p;
5253

5354
merged_iter_pqueue_release(&mi->pq);
54-
for (size_t i = 0; i < mi->stack_len; i++) {
55+
for (size_t i = 0; i < mi->subiters_len; i++) {
5556
reftable_iterator_destroy(&mi->subiters[i].iter);
5657
reftable_record_release(&mi->subiters[i].rec);
5758
}
@@ -80,7 +81,7 @@ static int merged_iter_seek(struct merged_iter *mi, struct reftable_record *want
8081

8182
mi->advance_index = -1;
8283

83-
for (size_t i = 0; i < mi->stack_len; i++) {
84+
for (size_t i = 0; i < mi->subiters_len; i++) {
8485
err = iterator_seek(&mi->subiters[i].iter, want);
8586
if (err < 0)
8687
return err;
@@ -193,18 +194,18 @@ static void iterator_from_merged_iter(struct reftable_iterator *it,
193194
}
194195

195196
int reftable_merged_table_new(struct reftable_merged_table **dest,
196-
struct reftable_table *stack, size_t n,
197+
struct reftable_reader **readers, size_t n,
197198
uint32_t hash_id)
198199
{
199200
struct reftable_merged_table *m = NULL;
200201
uint64_t last_max = 0;
201202
uint64_t first_min = 0;
202203

203204
for (size_t i = 0; i < n; i++) {
204-
uint64_t min = reftable_table_min_update_index(&stack[i]);
205-
uint64_t max = reftable_table_max_update_index(&stack[i]);
205+
uint64_t min = reftable_reader_min_update_index(readers[i]);
206+
uint64_t max = reftable_reader_max_update_index(readers[i]);
206207

207-
if (reftable_table_hash_id(&stack[i]) != hash_id) {
208+
if (reftable_reader_hash_id(readers[i]) != hash_id) {
208209
return REFTABLE_FORMAT_ERROR;
209210
}
210211
if (i == 0 || min < first_min) {
@@ -216,8 +217,8 @@ int reftable_merged_table_new(struct reftable_merged_table **dest,
216217
}
217218

218219
REFTABLE_CALLOC_ARRAY(m, 1);
219-
m->stack = stack;
220-
m->stack_len = n;
220+
m->readers = readers;
221+
m->readers_len = n;
221222
m->min = first_min;
222223
m->max = last_max;
223224
m->hash_id = hash_id;
@@ -229,7 +230,6 @@ void reftable_merged_table_free(struct reftable_merged_table *mt)
229230
{
230231
if (!mt)
231232
return;
232-
FREE_AND_NULL(mt->stack);
233233
reftable_free(mt);
234234
}
235235

reftable/merged.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ license that can be found in the LICENSE file or at
1212
#include "system.h"
1313

1414
struct reftable_merged_table {
15-
struct reftable_table *stack;
16-
size_t stack_len;
15+
struct reftable_reader **readers;
16+
size_t readers_len;
1717
uint32_t hash_id;
1818

1919
/* If unset, produce deletions. This is useful for compaction. For the

reftable/reader.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -605,9 +605,9 @@ static void iterator_from_table_iter(struct reftable_iterator *it,
605605
it->ops = &table_iter_vtable;
606606
}
607607

608-
static void reader_init_iter(struct reftable_reader *r,
609-
struct reftable_iterator *it,
610-
uint8_t typ)
608+
void reader_init_iter(struct reftable_reader *r,
609+
struct reftable_iterator *it,
610+
uint8_t typ)
611611
{
612612
struct reftable_reader_offsets *offs = reader_offsets_for(r, typ);
613613

reftable/reader.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ int init_reader(struct reftable_reader *r, struct reftable_block_source *source,
5757
void reader_close(struct reftable_reader *r);
5858
const char *reader_name(struct reftable_reader *r);
5959

60+
void reader_init_iter(struct reftable_reader *r,
61+
struct reftable_iterator *it,
62+
uint8_t typ);
63+
6064
/* initialize a block reader to read from `r` */
6165
int reader_init_block_reader(struct reftable_reader *r, struct block_reader *br,
6266
uint64_t next_off, uint8_t want_typ);

reftable/reftable-merged.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@ struct reftable_merged_table;
2828

2929
/* A generic reftable; see below. */
3030
struct reftable_table;
31+
struct reftable_reader;
3132

3233
/*
33-
* reftable_merged_table_new creates a new merged table. It takes ownership of
34-
* the stack array.
34+
* reftable_merged_table_new creates a new merged table. The readers must be
35+
* kept alive as long as the merged table is still in use.
3536
*/
3637
int reftable_merged_table_new(struct reftable_merged_table **dest,
37-
struct reftable_table *stack, size_t n,
38+
struct reftable_reader **readers, size_t n,
3839
uint32_t hash_id);
3940

4041
/* Initialize a merged table iterator for reading refs. */

reftable/stack.c

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -225,13 +225,11 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
225225
const char **names,
226226
int reuse_open)
227227
{
228-
size_t cur_len = !st->merged ? 0 : st->merged->stack_len;
228+
size_t cur_len = !st->merged ? 0 : st->merged->readers_len;
229229
struct reftable_reader **cur = stack_copy_readers(st, cur_len);
230230
size_t names_len = names_length(names);
231231
struct reftable_reader **new_readers =
232232
reftable_calloc(names_len, sizeof(*new_readers));
233-
struct reftable_table *new_tables =
234-
reftable_calloc(names_len, sizeof(*new_tables));
235233
size_t new_readers_len = 0;
236234
struct reftable_merged_table *new_merged = NULL;
237235
struct strbuf table_path = STRBUF_INIT;
@@ -267,17 +265,15 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
267265
}
268266

269267
new_readers[new_readers_len] = rd;
270-
reftable_table_from_reader(&new_tables[new_readers_len], rd);
271268
new_readers_len++;
272269
}
273270

274271
/* success! */
275-
err = reftable_merged_table_new(&new_merged, new_tables,
272+
err = reftable_merged_table_new(&new_merged, new_readers,
276273
new_readers_len, st->opts.hash_id);
277274
if (err < 0)
278275
goto done;
279276

280-
new_tables = NULL;
281277
st->readers_len = new_readers_len;
282278
if (st->merged)
283279
reftable_merged_table_free(st->merged);
@@ -309,7 +305,6 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
309305
reftable_reader_free(new_readers[i]);
310306
}
311307
reftable_free(new_readers);
312-
reftable_free(new_tables);
313308
reftable_free(cur);
314309
strbuf_release(&table_path);
315310
return err;
@@ -520,7 +515,7 @@ static int stack_uptodate(struct reftable_stack *st)
520515
}
521516
}
522517

523-
if (names[st->merged->stack_len]) {
518+
if (names[st->merged->readers_len]) {
524519
err = 1;
525520
goto done;
526521
}
@@ -659,7 +654,7 @@ int reftable_addition_commit(struct reftable_addition *add)
659654
if (add->new_tables_len == 0)
660655
goto done;
661656

662-
for (i = 0; i < add->stack->merged->stack_len; i++) {
657+
for (i = 0; i < add->stack->merged->readers_len; i++) {
663658
strbuf_addstr(&table_list, add->stack->readers[i]->name);
664659
strbuf_addstr(&table_list, "\n");
665660
}
@@ -839,7 +834,7 @@ int reftable_addition_add(struct reftable_addition *add,
839834

840835
uint64_t reftable_stack_next_update_index(struct reftable_stack *st)
841836
{
842-
int sz = st->merged->stack_len;
837+
int sz = st->merged->readers_len;
843838
if (sz > 0)
844839
return reftable_reader_max_update_index(st->readers[sz - 1]) +
845840
1;
@@ -906,30 +901,23 @@ static int stack_write_compact(struct reftable_stack *st,
906901
size_t first, size_t last,
907902
struct reftable_log_expiry_config *config)
908903
{
909-
size_t subtabs_len = last - first + 1;
910-
struct reftable_table *subtabs = reftable_calloc(
911-
last - first + 1, sizeof(*subtabs));
912904
struct reftable_merged_table *mt = NULL;
913905
struct reftable_iterator it = { NULL };
914906
struct reftable_ref_record ref = { NULL };
915907
struct reftable_log_record log = { NULL };
908+
size_t subtabs_len = last - first + 1;
916909
uint64_t entries = 0;
917910
int err = 0;
918911

919-
for (size_t i = first, j = 0; i <= last; i++) {
920-
struct reftable_reader *t = st->readers[i];
921-
reftable_table_from_reader(&subtabs[j++], t);
922-
st->stats.bytes += t->size;
923-
}
912+
for (size_t i = first; i <= last; i++)
913+
st->stats.bytes += st->readers[i]->size;
924914
reftable_writer_set_limits(wr, st->readers[first]->min_update_index,
925915
st->readers[last]->max_update_index);
926916

927-
err = reftable_merged_table_new(&mt, subtabs, subtabs_len,
917+
err = reftable_merged_table_new(&mt, st->readers + first, subtabs_len,
928918
st->opts.hash_id);
929-
if (err < 0) {
930-
reftable_free(subtabs);
919+
if (err < 0)
931920
goto done;
932-
}
933921

934922
merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
935923
err = reftable_iterator_seek_ref(&it, "");
@@ -1207,7 +1195,7 @@ static int stack_compact_range(struct reftable_stack *st,
12071195
* have compacted them.
12081196
*/
12091197
for (size_t j = 1; j < last - first + 1; j++) {
1210-
const char *old = first + j < st->merged->stack_len ?
1198+
const char *old = first + j < st->merged->readers_len ?
12111199
st->readers[first + j]->name : NULL;
12121200
const char *new = names[i + j];
12131201

@@ -1248,10 +1236,10 @@ static int stack_compact_range(struct reftable_stack *st,
12481236
* `fd_read_lines()` uses a `NULL` sentinel to indicate that
12491237
* the array is at its end. As we use `free_names()` to free
12501238
* the array, we need to include this sentinel value here and
1251-
* thus have to allocate `stack_len + 1` many entries.
1239+
* thus have to allocate `readers_len + 1` many entries.
12521240
*/
1253-
REFTABLE_CALLOC_ARRAY(names, st->merged->stack_len + 1);
1254-
for (size_t i = 0; i < st->merged->stack_len; i++)
1241+
REFTABLE_CALLOC_ARRAY(names, st->merged->readers_len + 1);
1242+
for (size_t i = 0; i < st->merged->readers_len; i++)
12551243
names[i] = xstrdup(st->readers[i]->name);
12561244
first_to_replace = first;
12571245
last_to_replace = last;
@@ -1358,7 +1346,7 @@ static int stack_compact_range_stats(struct reftable_stack *st,
13581346
int reftable_stack_compact_all(struct reftable_stack *st,
13591347
struct reftable_log_expiry_config *config)
13601348
{
1361-
size_t last = st->merged->stack_len ? st->merged->stack_len - 1 : 0;
1349+
size_t last = st->merged->readers_len ? st->merged->readers_len - 1 : 0;
13621350
return stack_compact_range_stats(st, 0, last, config, 0);
13631351
}
13641352

@@ -1449,9 +1437,9 @@ static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack *st)
14491437
int overhead = header_size(version) - 1;
14501438
uint64_t *sizes;
14511439

1452-
REFTABLE_CALLOC_ARRAY(sizes, st->merged->stack_len);
1440+
REFTABLE_CALLOC_ARRAY(sizes, st->merged->readers_len);
14531441

1454-
for (size_t i = 0; i < st->merged->stack_len; i++)
1442+
for (size_t i = 0; i < st->merged->readers_len; i++)
14551443
sizes[i] = st->readers[i]->size - overhead;
14561444

14571445
return sizes;
@@ -1461,7 +1449,7 @@ int reftable_stack_auto_compact(struct reftable_stack *st)
14611449
{
14621450
uint64_t *sizes = stack_table_sizes_for_compaction(st);
14631451
struct segment seg =
1464-
suggest_compaction_segment(sizes, st->merged->stack_len,
1452+
suggest_compaction_segment(sizes, st->merged->readers_len,
14651453
st->opts.auto_compaction_factor);
14661454
reftable_free(sizes);
14671455
if (segment_size(&seg) > 0)

reftable/stack_test.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -347,9 +347,9 @@ static void test_reftable_stack_transaction_api_performs_auto_compaction(void)
347347
* all tables in the stack.
348348
*/
349349
if (i != n)
350-
EXPECT(st->merged->stack_len == i + 1);
350+
EXPECT(st->merged->readers_len == i + 1);
351351
else
352-
EXPECT(st->merged->stack_len == 1);
352+
EXPECT(st->merged->readers_len == 1);
353353
}
354354

355355
reftable_stack_destroy(st);
@@ -375,7 +375,7 @@ static void test_reftable_stack_auto_compaction_fails_gracefully(void)
375375

376376
err = reftable_stack_add(st, write_test_ref, &ref);
377377
EXPECT_ERR(err);
378-
EXPECT(st->merged->stack_len == 1);
378+
EXPECT(st->merged->readers_len == 1);
379379
EXPECT(st->stats.attempts == 0);
380380
EXPECT(st->stats.failures == 0);
381381

@@ -390,7 +390,7 @@ static void test_reftable_stack_auto_compaction_fails_gracefully(void)
390390
ref.update_index = 2;
391391
err = reftable_stack_add(st, write_test_ref, &ref);
392392
EXPECT_ERR(err);
393-
EXPECT(st->merged->stack_len == 2);
393+
EXPECT(st->merged->readers_len == 2);
394394
EXPECT(st->stats.attempts == 1);
395395
EXPECT(st->stats.failures == 1);
396396

@@ -881,7 +881,7 @@ static void test_reftable_stack_auto_compaction(void)
881881

882882
err = reftable_stack_auto_compact(st);
883883
EXPECT_ERR(err);
884-
EXPECT(i < 3 || st->merged->stack_len < 2 * fastlog2(i));
884+
EXPECT(i < 3 || st->merged->readers_len < 2 * fastlog2(i));
885885
}
886886

887887
EXPECT(reftable_stack_compaction_stats(st)->entries_written <
@@ -905,7 +905,7 @@ static void test_reftable_stack_auto_compaction_with_locked_tables(void)
905905
EXPECT_ERR(err);
906906

907907
write_n_ref_tables(st, 5);
908-
EXPECT(st->merged->stack_len == 5);
908+
EXPECT(st->merged->readers_len == 5);
909909

910910
/*
911911
* Given that all tables we have written should be roughly the same
@@ -925,7 +925,7 @@ static void test_reftable_stack_auto_compaction_with_locked_tables(void)
925925
err = reftable_stack_auto_compact(st);
926926
EXPECT_ERR(err);
927927
EXPECT(st->stats.failures == 0);
928-
EXPECT(st->merged->stack_len == 4);
928+
EXPECT(st->merged->readers_len == 4);
929929

930930
reftable_stack_destroy(st);
931931
strbuf_release(&buf);
@@ -970,9 +970,9 @@ static void test_reftable_stack_add_performs_auto_compaction(void)
970970
* all tables in the stack.
971971
*/
972972
if (i != n)
973-
EXPECT(st->merged->stack_len == i + 1);
973+
EXPECT(st->merged->readers_len == i + 1);
974974
else
975-
EXPECT(st->merged->stack_len == 1);
975+
EXPECT(st->merged->readers_len == 1);
976976
}
977977

978978
reftable_stack_destroy(st);
@@ -994,7 +994,7 @@ static void test_reftable_stack_compaction_with_locked_tables(void)
994994
EXPECT_ERR(err);
995995

996996
write_n_ref_tables(st, 3);
997-
EXPECT(st->merged->stack_len == 3);
997+
EXPECT(st->merged->readers_len == 3);
998998

999999
/* Lock one of the tables that we're about to compact. */
10001000
strbuf_reset(&buf);
@@ -1008,7 +1008,7 @@ static void test_reftable_stack_compaction_with_locked_tables(void)
10081008
err = reftable_stack_compact_all(st, NULL);
10091009
EXPECT(err == REFTABLE_LOCK_ERROR);
10101010
EXPECT(st->stats.failures == 1);
1011-
EXPECT(st->merged->stack_len == 3);
1011+
EXPECT(st->merged->readers_len == 3);
10121012

10131013
reftable_stack_destroy(st);
10141014
strbuf_release(&buf);

0 commit comments

Comments
 (0)