diff options
| -rw-r--r-- | reftable/block.c | 56 | ||||
| -rw-r--r-- | reftable/block.h | 2 | ||||
| -rw-r--r-- | reftable/reftable-block.h | 5 | ||||
| -rw-r--r-- | t/unit-tests/t-reftable-block.c | 78 |
4 files changed, 140 insertions, 1 deletions
diff --git a/reftable/block.c b/reftable/block.c index 20712be7ee..08e22170d5 100644 --- a/reftable/block.c +++ b/reftable/block.c @@ -10,6 +10,7 @@ #include "blocksource.h" #include "constants.h" +#include "iter.h" #include "record.h" #include "reftable-error.h" #include "system.h" @@ -581,6 +582,61 @@ done: return err; } +static int block_iter_seek_void(void *it, struct reftable_record *want) +{ + struct reftable_buf buf = REFTABLE_BUF_INIT; + struct block_iter *bi = it; + int err; + + if (bi->block->block_type != want->type) + return REFTABLE_API_ERROR; + + err = reftable_record_key(want, &buf); + if (err < 0) + goto out; + + err = block_iter_seek_key(it, &buf); + if (err < 0) + goto out; + + err = 0; + +out: + reftable_buf_release(&buf); + return err; +} + +static int block_iter_next_void(void *it, struct reftable_record *rec) +{ + return block_iter_next(it, rec); +} + +static void block_iter_close_void(void *it) +{ + block_iter_close(it); +} + +static struct reftable_iterator_vtable block_iter_vtable = { + .seek = &block_iter_seek_void, + .next = &block_iter_next_void, + .close = &block_iter_close_void, +}; + +int reftable_block_init_iterator(const struct reftable_block *b, + struct reftable_iterator *it) +{ + struct block_iter *bi; + + REFTABLE_CALLOC_ARRAY(bi, 1); + block_iter_init(bi, b); + + assert(!it->ops); + it->iter_arg = bi; + it->ops = &block_iter_vtable; + + return 0; +} + void block_writer_release(struct block_writer *bw) { deflateEnd(bw->zstream); diff --git a/reftable/block.h b/reftable/block.h index 1bfd44f56a..3d06939392 100644 --- a/reftable/block.h +++ b/reftable/block.h @@ -63,7 +63,7 @@ int block_writer_finish(struct block_writer *w); /* clears out internally allocated block_writer members. */ void block_writer_release(struct block_writer *bw); -/* Iterate over entries in a block */ +/* Iterator for records contained in a single block. */ struct block_iter { /* offset within the block of the next entry to read. */ uint32_t next_off; diff --git a/reftable/reftable-block.h b/reftable/reftable-block.h index 13bd68be8c..04c3b518c8 100644 --- a/reftable/reftable-block.h +++ b/reftable/reftable-block.h @@ -13,6 +13,7 @@ #include "reftable-basics.h" #include "reftable-blocksource.h" +#include "reftable-iterator.h" struct z_stream_s; @@ -60,6 +61,10 @@ int reftable_block_init(struct reftable_block *b, /* Release resources allocated by the block. */ void reftable_block_release(struct reftable_block *b); +/* Initialize a generic record iterator from the given block. */ +int reftable_block_init_iterator(const struct reftable_block *b, + struct reftable_iterator *it); + /* Returns the block type (eg. 'r' for refs). */ uint8_t reftable_block_type(const struct reftable_block *b); diff --git a/t/unit-tests/t-reftable-block.c b/t/unit-tests/t-reftable-block.c index 9f91d697f6..5577a5769e 100644 --- a/t/unit-tests/t-reftable-block.c +++ b/t/unit-tests/t-reftable-block.c @@ -372,12 +372,90 @@ static void t_index_block_read_write(void) reftable_record_release(&recs[i]); } +static void t_block_iterator(void) +{ + struct reftable_block_source source = { 0 }; + struct block_writer writer = { + .last_key = REFTABLE_BUF_INIT, + }; + struct reftable_record expected_refs[20]; + struct reftable_ref_record ref = { 0 }; + struct reftable_iterator it = { 0 }; + struct reftable_block block = { 0 }; + struct reftable_buf data; + int err; + + data.len = 1024; + REFTABLE_CALLOC_ARRAY(data.buf, data.len); + check(data.buf != NULL); + + err = block_writer_init(&writer, BLOCK_TYPE_REF, (uint8_t *) data.buf, data.len, + 0, hash_size(REFTABLE_HASH_SHA1)); + check(!err); + + for (size_t i = 0; i < ARRAY_SIZE(expected_refs); i++) { + expected_refs[i] = (struct reftable_record) { + .type = BLOCK_TYPE_REF, + .u.ref = { + .value_type = REFTABLE_REF_VAL1, + .refname = xstrfmt("refs/heads/branch-%02"PRIuMAX, (uintmax_t)i), + }, + }; + memset(expected_refs[i].u.ref.value.val1, i, REFTABLE_HASH_SIZE_SHA1); + + err = block_writer_add(&writer, &expected_refs[i]); + check_int(err, ==, 0); + } + + err = block_writer_finish(&writer); + check_int(err, >, 0); + + block_source_from_buf(&source, &data); + reftable_block_init(&block, &source, 0, 0, data.len, REFTABLE_HASH_SIZE_SHA1); + + err = reftable_block_init_iterator(&block, &it); + check_int(err, ==, 0); + + for (size_t i = 0; ; i++) { + err = reftable_iterator_next_ref(&it, &ref); + if (err > 0) { + check_int(i, ==, ARRAY_SIZE(expected_refs)); + break; + } + check_int(err, ==, 0); + + check(reftable_ref_record_equal(&ref, &expected_refs[i].u.ref, + REFTABLE_HASH_SIZE_SHA1)); + } + + err = reftable_iterator_seek_ref(&it, "refs/heads/does-not-exist"); + check_int(err, ==, 0); + err = reftable_iterator_next_ref(&it, &ref); + check_int(err, ==, 1); + + err = reftable_iterator_seek_ref(&it, "refs/heads/branch-13"); + check_int(err, ==, 0); + err = reftable_iterator_next_ref(&it, &ref); + check_int(err, ==, 0); + check(reftable_ref_record_equal(&ref, &expected_refs[13].u.ref, + REFTABLE_HASH_SIZE_SHA1)); + + for (size_t i = 0; i < ARRAY_SIZE(expected_refs); i++) + reftable_free(expected_refs[i].u.ref.refname); + reftable_ref_record_release(&ref); + reftable_iterator_destroy(&it); + reftable_block_release(&block); + block_writer_release(&writer); + reftable_buf_release(&data); +} + int cmd_main(int argc UNUSED, const char *argv[] UNUSED) { TEST(t_index_block_read_write(), "read-write operations on index blocks work"); TEST(t_log_block_read_write(), "read-write operations on log blocks work"); TEST(t_obj_block_read_write(), "read-write operations on obj blocks work"); TEST(t_ref_block_read_write(), "read-write operations on ref blocks work"); + TEST(t_block_iterator(), "block iterator works"); return test_done(); } |
