Skip to content

Commit 0a148a8

Browse files
pks-tgitster
authored andcommitted
reftable/reader: make table iterator reseekable
In 67ce50b (Merge branch 'ps/reftable-reusable-iterator', 2024-05-30) we have refactored the interface of reftable iterators such that they can be reused in theory. This patch series only landed the required changes on the interface level, but didn't yet implement the actual logic to make iterators reusable. As it turns out almost all of the infrastructure already does support re-seeking. The only exception is the table iterator, which does not reset its `is_finished` bit. Do so and add a couple of tests that verify that we can re-seek iterators. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent a4f50bb commit 0a148a8

File tree

4 files changed

+174
-0
lines changed

4 files changed

+174
-0
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,6 +1346,7 @@ UNIT_TEST_PROGRAMS += t-reftable-basics
13461346
UNIT_TEST_PROGRAMS += t-reftable-block
13471347
UNIT_TEST_PROGRAMS += t-reftable-merged
13481348
UNIT_TEST_PROGRAMS += t-reftable-pq
1349+
UNIT_TEST_PROGRAMS += t-reftable-reader
13491350
UNIT_TEST_PROGRAMS += t-reftable-readwrite
13501351
UNIT_TEST_PROGRAMS += t-reftable-record
13511352
UNIT_TEST_PROGRAMS += t-reftable-stack

reftable/reader.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ static int table_iter_seek_to(struct table_iter *ti, uint64_t off, uint8_t typ)
328328
ti->typ = block_reader_type(&ti->br);
329329
ti->block_off = off;
330330
block_iter_seek_start(&ti->bi, &ti->br);
331+
ti->is_finished = 0;
331332
return 0;
332333
}
333334

t/unit-tests/t-reftable-merged.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,81 @@ static void t_merged_refs(void)
194194
reftable_free(bs);
195195
}
196196

197+
static void t_merged_seek_multiple_times(void)
198+
{
199+
struct reftable_ref_record r1[] = {
200+
{
201+
.refname = (char *) "a",
202+
.update_index = 1,
203+
.value_type = REFTABLE_REF_VAL1,
204+
.value.val1 = { 1 },
205+
},
206+
{
207+
.refname = (char *) "c",
208+
.update_index = 1,
209+
.value_type = REFTABLE_REF_VAL1,
210+
.value.val1 = { 2 },
211+
}
212+
};
213+
struct reftable_ref_record r2[] = {
214+
{
215+
.refname = (char *) "b",
216+
.update_index = 2,
217+
.value_type = REFTABLE_REF_VAL1,
218+
.value.val1 = { 3 },
219+
},
220+
{
221+
.refname = (char *) "d",
222+
.update_index = 2,
223+
.value_type = REFTABLE_REF_VAL1,
224+
.value.val1 = { 4 },
225+
},
226+
};
227+
struct reftable_ref_record *refs[] = {
228+
r1, r2,
229+
};
230+
size_t sizes[] = {
231+
ARRAY_SIZE(r1), ARRAY_SIZE(r2),
232+
};
233+
struct strbuf bufs[] = {
234+
STRBUF_INIT, STRBUF_INIT,
235+
};
236+
struct reftable_block_source *sources = NULL;
237+
struct reftable_reader **readers = NULL;
238+
struct reftable_ref_record rec = { 0 };
239+
struct reftable_iterator it = { 0 };
240+
struct reftable_merged_table *mt;
241+
242+
mt = merged_table_from_records(refs, &sources, &readers, sizes, bufs, 2);
243+
merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
244+
245+
for (size_t i = 0; i < 5; i++) {
246+
int err = reftable_iterator_seek_ref(&it, "c");
247+
check(!err);
248+
249+
err = reftable_iterator_next_ref(&it, &rec);
250+
check(!err);
251+
err = reftable_ref_record_equal(&rec, &r1[1], GIT_SHA1_RAWSZ);
252+
check(err == 1);
253+
254+
err = reftable_iterator_next_ref(&it, &rec);
255+
check(!err);
256+
err = reftable_ref_record_equal(&rec, &r2[1], GIT_SHA1_RAWSZ);
257+
check(err == 1);
258+
259+
err = reftable_iterator_next_ref(&it, &rec);
260+
check(err > 0);
261+
}
262+
263+
for (size_t i = 0; i < ARRAY_SIZE(bufs); i++)
264+
strbuf_release(&bufs[i]);
265+
readers_destroy(readers, ARRAY_SIZE(refs));
266+
reftable_ref_record_release(&rec);
267+
reftable_iterator_destroy(&it);
268+
reftable_merged_table_free(mt);
269+
reftable_free(sources);
270+
}
271+
197272
static struct reftable_merged_table *
198273
merged_table_from_log_records(struct reftable_log_record **logs,
199274
struct reftable_block_source **source,
@@ -383,6 +458,7 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
383458
TEST(t_default_write_opts(), "merged table with default write opts");
384459
TEST(t_merged_logs(), "merged table with multiple log updates for same ref");
385460
TEST(t_merged_refs(), "merged table with multiple updates to same ref");
461+
TEST(t_merged_seek_multiple_times(), "merged table can seek multiple times");
386462
TEST(t_merged_single_record(), "ref ocurring in only one record can be fetched");
387463

388464
return test_done();

t/unit-tests/t-reftable-reader.c

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#include "test-lib.h"
2+
#include "lib-reftable.h"
3+
#include "reftable/blocksource.h"
4+
#include "reftable/reader.h"
5+
6+
static int t_reader_seek_once(void)
7+
{
8+
struct reftable_ref_record records[] = {
9+
{
10+
.refname = (char *) "refs/heads/main",
11+
.value_type = REFTABLE_REF_VAL1,
12+
.value.val1 = { 42 },
13+
},
14+
};
15+
struct reftable_block_source source = { 0 };
16+
struct reftable_ref_record ref = { 0 };
17+
struct reftable_iterator it = { 0 };
18+
struct reftable_reader *reader;
19+
struct strbuf buf = STRBUF_INIT;
20+
int ret;
21+
22+
t_reftable_write_to_buf(&buf, records, ARRAY_SIZE(records), NULL, 0, NULL);
23+
block_source_from_strbuf(&source, &buf);
24+
25+
ret = reftable_reader_new(&reader, &source, "name");
26+
check(!ret);
27+
28+
reftable_reader_init_ref_iterator(reader, &it);
29+
ret = reftable_iterator_seek_ref(&it, "");
30+
check(!ret);
31+
ret = reftable_iterator_next_ref(&it, &ref);
32+
check(!ret);
33+
34+
ret = reftable_ref_record_equal(&ref, &records[0], GIT_SHA1_RAWSZ);
35+
check_int(ret, ==, 1);
36+
37+
ret = reftable_iterator_next_ref(&it, &ref);
38+
check_int(ret, ==, 1);
39+
40+
reftable_ref_record_release(&ref);
41+
reftable_iterator_destroy(&it);
42+
reftable_reader_decref(reader);
43+
strbuf_release(&buf);
44+
return 0;
45+
}
46+
47+
static int t_reader_reseek(void)
48+
{
49+
struct reftable_ref_record records[] = {
50+
{
51+
.refname = (char *) "refs/heads/main",
52+
.value_type = REFTABLE_REF_VAL1,
53+
.value.val1 = { 42 },
54+
},
55+
};
56+
struct reftable_block_source source = { 0 };
57+
struct reftable_ref_record ref = { 0 };
58+
struct reftable_iterator it = { 0 };
59+
struct reftable_reader *reader;
60+
struct strbuf buf = STRBUF_INIT;
61+
int ret;
62+
63+
t_reftable_write_to_buf(&buf, records, ARRAY_SIZE(records), NULL, 0, NULL);
64+
block_source_from_strbuf(&source, &buf);
65+
66+
ret = reftable_reader_new(&reader, &source, "name");
67+
check(!ret);
68+
69+
reftable_reader_init_ref_iterator(reader, &it);
70+
71+
for (size_t i = 0; i < 5; i++) {
72+
ret = reftable_iterator_seek_ref(&it, "");
73+
check(!ret);
74+
ret = reftable_iterator_next_ref(&it, &ref);
75+
check(!ret);
76+
77+
ret = reftable_ref_record_equal(&ref, &records[0], GIT_SHA1_RAWSZ);
78+
check_int(ret, ==, 1);
79+
80+
ret = reftable_iterator_next_ref(&it, &ref);
81+
check_int(ret, ==, 1);
82+
}
83+
84+
reftable_ref_record_release(&ref);
85+
reftable_iterator_destroy(&it);
86+
reftable_reader_decref(reader);
87+
strbuf_release(&buf);
88+
return 0;
89+
}
90+
91+
int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
92+
{
93+
TEST(t_reader_seek_once(), "reader can seek once");
94+
TEST(t_reader_reseek(), "reader can reseek multiple times");
95+
return test_done();
96+
}

0 commit comments

Comments
 (0)