Skip to content

Commit 50d8459

Browse files
pks-tgitster
authored andcommitted
reftable/block: expose a generic iterator over reftable records
Expose a generic iterator over reftable records and expose it via the public interface. Together with an upcoming iterator for reftable blocks contained in a table this will allow users to trivially iterate through blocks and their respective records individually. This functionality will be used to implement consistency checks for the reftable backend, which requires more fine-grained control over how we read data. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 6da48a5 commit 50d8459

File tree

4 files changed

+140
-1
lines changed

4 files changed

+140
-1
lines changed

reftable/block.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "blocksource.h"
1212
#include "constants.h"
13+
#include "iter.h"
1314
#include "record.h"
1415
#include "reftable-error.h"
1516
#include "system.h"
@@ -581,6 +582,61 @@ int block_iter_seek_key(struct block_iter *it, struct reftable_buf *want)
581582
return err;
582583
}
583584

585+
static int block_iter_seek_void(void *it, struct reftable_record *want)
586+
{
587+
struct reftable_buf buf = REFTABLE_BUF_INIT;
588+
struct block_iter *bi = it;
589+
int err;
590+
591+
if (bi->block->block_type != want->type)
592+
return REFTABLE_API_ERROR;
593+
594+
err = reftable_record_key(want, &buf);
595+
if (err < 0)
596+
goto out;
597+
598+
err = block_iter_seek_key(it, &buf);
599+
if (err < 0)
600+
goto out;
601+
602+
err = 0;
603+
604+
out:
605+
reftable_buf_release(&buf);
606+
return err;
607+
}
608+
609+
static int block_iter_next_void(void *it, struct reftable_record *rec)
610+
{
611+
return block_iter_next(it, rec);
612+
}
613+
614+
static void block_iter_close_void(void *it)
615+
{
616+
block_iter_close(it);
617+
}
618+
619+
static struct reftable_iterator_vtable block_iter_vtable = {
620+
.seek = &block_iter_seek_void,
621+
.next = &block_iter_next_void,
622+
.close = &block_iter_close_void,
623+
};
624+
625+
int reftable_block_init_iterator(const struct reftable_block *b,
626+
struct reftable_iterator *it)
627+
{
628+
struct block_iter *bi;
629+
630+
REFTABLE_CALLOC_ARRAY(bi, 1);
631+
block_iter_init(bi, b);
632+
633+
assert(!it->ops);
634+
it->iter_arg = bi;
635+
it->ops = &block_iter_vtable;
636+
637+
return 0;
638+
}
639+
584640
void block_writer_release(struct block_writer *bw)
585641
{
586642
deflateEnd(bw->zstream);

reftable/block.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ int block_writer_finish(struct block_writer *w);
6363
/* clears out internally allocated block_writer members. */
6464
void block_writer_release(struct block_writer *bw);
6565

66-
/* Iterate over entries in a block */
66+
/* Iterator for records contained in a single block. */
6767
struct block_iter {
6868
/* offset within the block of the next entry to read. */
6969
uint32_t next_off;

reftable/reftable-block.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include "reftable-basics.h"
1515
#include "reftable-blocksource.h"
16+
#include "reftable-iterator.h"
1617

1718
struct z_stream_s;
1819

@@ -60,6 +61,10 @@ int reftable_block_init(struct reftable_block *b,
6061
/* Release resources allocated by the block. */
6162
void reftable_block_release(struct reftable_block *b);
6263

64+
/* Initialize a generic record iterator from the given block. */
65+
int reftable_block_init_iterator(const struct reftable_block *b,
66+
struct reftable_iterator *it);
67+
6368
/* Returns the block type (eg. 'r' for refs). */
6469
uint8_t reftable_block_type(const struct reftable_block *b);
6570

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

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,12 +372,90 @@ static void t_index_block_read_write(void)
372372
reftable_record_release(&recs[i]);
373373
}
374374

375+
static void t_block_iterator(void)
376+
{
377+
struct reftable_block_source source = { 0 };
378+
struct block_writer writer = {
379+
.last_key = REFTABLE_BUF_INIT,
380+
};
381+
struct reftable_record expected_refs[20];
382+
struct reftable_ref_record ref = { 0 };
383+
struct reftable_iterator it = { 0 };
384+
struct reftable_block block = { 0 };
385+
struct reftable_buf data;
386+
int err;
387+
388+
data.len = 1024;
389+
REFTABLE_CALLOC_ARRAY(data.buf, data.len);
390+
check(data.buf != NULL);
391+
392+
err = block_writer_init(&writer, BLOCK_TYPE_REF, (uint8_t *) data.buf, data.len,
393+
0, hash_size(REFTABLE_HASH_SHA1));
394+
check(!err);
395+
396+
for (size_t i = 0; i < ARRAY_SIZE(expected_refs); i++) {
397+
expected_refs[i] = (struct reftable_record) {
398+
.type = BLOCK_TYPE_REF,
399+
.u.ref = {
400+
.value_type = REFTABLE_REF_VAL1,
401+
.refname = xstrfmt("refs/heads/branch-%02"PRIuMAX, (uintmax_t)i),
402+
},
403+
};
404+
memset(expected_refs[i].u.ref.value.val1, i, REFTABLE_HASH_SIZE_SHA1);
405+
406+
err = block_writer_add(&writer, &expected_refs[i]);
407+
check_int(err, ==, 0);
408+
}
409+
410+
err = block_writer_finish(&writer);
411+
check_int(err, >, 0);
412+
413+
block_source_from_buf(&source, &data);
414+
reftable_block_init(&block, &source, 0, 0, data.len, REFTABLE_HASH_SIZE_SHA1);
415+
416+
err = reftable_block_init_iterator(&block, &it);
417+
check_int(err, ==, 0);
418+
419+
for (size_t i = 0; ; i++) {
420+
err = reftable_iterator_next_ref(&it, &ref);
421+
if (err > 0) {
422+
check_int(i, ==, ARRAY_SIZE(expected_refs));
423+
break;
424+
}
425+
check_int(err, ==, 0);
426+
427+
check(reftable_ref_record_equal(&ref, &expected_refs[i].u.ref,
428+
REFTABLE_HASH_SIZE_SHA1));
429+
}
430+
431+
err = reftable_iterator_seek_ref(&it, "refs/heads/does-not-exist");
432+
check_int(err, ==, 0);
433+
err = reftable_iterator_next_ref(&it, &ref);
434+
check_int(err, ==, 1);
435+
436+
err = reftable_iterator_seek_ref(&it, "refs/heads/branch-13");
437+
check_int(err, ==, 0);
438+
err = reftable_iterator_next_ref(&it, &ref);
439+
check_int(err, ==, 0);
440+
check(reftable_ref_record_equal(&ref, &expected_refs[13].u.ref,
441+
REFTABLE_HASH_SIZE_SHA1));
442+
443+
for (size_t i = 0; i < ARRAY_SIZE(expected_refs); i++)
444+
reftable_free(expected_refs[i].u.ref.refname);
445+
reftable_ref_record_release(&ref);
446+
reftable_iterator_destroy(&it);
447+
reftable_block_release(&block);
448+
block_writer_release(&writer);
449+
reftable_buf_release(&data);
450+
}
451+
375452
int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
376453
{
377454
TEST(t_index_block_read_write(), "read-write operations on index blocks work");
378455
TEST(t_log_block_read_write(), "read-write operations on log blocks work");
379456
TEST(t_obj_block_read_write(), "read-write operations on obj blocks work");
380457
TEST(t_ref_block_read_write(), "read-write operations on ref blocks work");
458+
TEST(t_block_iterator(), "block iterator works");
381459

382460
return test_done();
383461
}

0 commit comments

Comments
 (0)