Merge branch 'ps/reftable-api-revamp'

Overhaul of the reftable API.

* ps/reftable-api-revamp:
  reftable/table: move printing logic into test helper
  reftable/constants: make block types part of the public interface
  reftable/table: introduce iterator for table blocks
  reftable/table: add `reftable_table` to the public interface
  reftable/block: expose a generic iterator over reftable records
  reftable/block: make block iterators reseekable
  reftable/block: store block pointer in the block iterator
  reftable/block: create public interface for reading blocks
  git-zlib: use `struct z_stream_s` instead of typedef
  reftable/block: rename `block_reader` to `reftable_block`
  reftable/block: rename `block` to `block_data`
  reftable/table: move reading block into block reader
  reftable/block: simplify how we track restart points
  reftable/blocksource: consolidate code into a single file
  reftable/reader: rename data structure to "table"
  reftable: fix formatting of the license header
main
Junio C Hamano 2025-04-29 14:21:29 -07:00
commit a819a3da85
54 changed files with 1640 additions and 1279 deletions

View File

@ -125,7 +125,7 @@ static int try_zlib(unsigned char *buf, int len)
{ {
/* make this absurdly large so we don't have to loop */ /* make this absurdly large so we don't have to loop */
static unsigned char out[1024*1024]; static unsigned char out[1024*1024];
z_stream z; struct z_stream_s z;
int ret; int ret;


memset(&z, 0, sizeof(z)); memset(&z, 0, sizeof(z));
@ -278,7 +278,7 @@ int main(int argc, char **argv)
static unsigned char buf[25 * 1024 * 1024]; static unsigned char buf[25 * 1024 * 1024];
static unsigned char out[25 * 1024 * 1024]; static unsigned char out[25 * 1024 * 1024];
int len; int len;
z_stream z; struct z_stream_s z;
int ret; int ret;


len = read(0, buf, sizeof(buf)); len = read(0, buf, sizeof(buf));

View File

@ -1377,10 +1377,10 @@ UNIT_TEST_PROGRAMS += t-reftable-basics
UNIT_TEST_PROGRAMS += t-reftable-block UNIT_TEST_PROGRAMS += t-reftable-block
UNIT_TEST_PROGRAMS += t-reftable-merged UNIT_TEST_PROGRAMS += t-reftable-merged
UNIT_TEST_PROGRAMS += t-reftable-pq UNIT_TEST_PROGRAMS += t-reftable-pq
UNIT_TEST_PROGRAMS += t-reftable-reader
UNIT_TEST_PROGRAMS += t-reftable-readwrite UNIT_TEST_PROGRAMS += t-reftable-readwrite
UNIT_TEST_PROGRAMS += t-reftable-record UNIT_TEST_PROGRAMS += t-reftable-record
UNIT_TEST_PROGRAMS += t-reftable-stack UNIT_TEST_PROGRAMS += t-reftable-stack
UNIT_TEST_PROGRAMS += t-reftable-table
UNIT_TEST_PROGS = $(patsubst %,$(UNIT_TEST_BIN)/%$X,$(UNIT_TEST_PROGRAMS)) UNIT_TEST_PROGS = $(patsubst %,$(UNIT_TEST_BIN)/%$X,$(UNIT_TEST_PROGRAMS))
UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o
UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/lib-reftable.o UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/lib-reftable.o
@ -2737,10 +2737,10 @@ REFTABLE_OBJS += reftable/blocksource.o
REFTABLE_OBJS += reftable/iter.o REFTABLE_OBJS += reftable/iter.o
REFTABLE_OBJS += reftable/merged.o REFTABLE_OBJS += reftable/merged.o
REFTABLE_OBJS += reftable/pq.o REFTABLE_OBJS += reftable/pq.o
REFTABLE_OBJS += reftable/reader.o
REFTABLE_OBJS += reftable/record.o REFTABLE_OBJS += reftable/record.o
REFTABLE_OBJS += reftable/stack.o REFTABLE_OBJS += reftable/stack.o
REFTABLE_OBJS += reftable/system.o REFTABLE_OBJS += reftable/system.o
REFTABLE_OBJS += reftable/table.o
REFTABLE_OBJS += reftable/tree.o REFTABLE_OBJS += reftable/tree.o
REFTABLE_OBJS += reftable/writer.o REFTABLE_OBJS += reftable/writer.o



View File

@ -4,7 +4,7 @@
#ifdef HAVE_ZLIB_NG #ifdef HAVE_ZLIB_NG
# include <zlib-ng.h> # include <zlib-ng.h>


# define z_stream zng_stream # define z_stream_s zng_stream_s
# define gz_header_s zng_gz_header_s # define gz_header_s zng_gz_header_s


# define crc32(crc, buf, len) zng_crc32(crc, buf, len) # define crc32(crc, buf, len) zng_crc32(crc, buf, len)

View File

@ -4,7 +4,7 @@
#include "compat/zlib-compat.h" #include "compat/zlib-compat.h"


typedef struct git_zstream { typedef struct git_zstream {
z_stream z; struct z_stream_s z;
unsigned long avail_in; unsigned long avail_in;
unsigned long avail_out; unsigned long avail_out;
unsigned long total_in; unsigned long total_in;

View File

@ -446,10 +446,10 @@ libgit_sources = [
'reftable/iter.c', 'reftable/iter.c',
'reftable/merged.c', 'reftable/merged.c',
'reftable/pq.c', 'reftable/pq.c',
'reftable/reader.c',
'reftable/record.c', 'reftable/record.c',
'reftable/stack.c', 'reftable/stack.c',
'reftable/system.c', 'reftable/system.c',
'reftable/table.c',
'reftable/tree.c', 'reftable/tree.c',
'reftable/writer.c', 'reftable/writer.c',
'remote.c', 'remote.c',

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#define REFTABLE_ALLOW_BANNED_ALLOCATORS #define REFTABLE_ALLOW_BANNED_ALLOCATORS

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef BASICS_H #ifndef BASICS_H
@ -18,13 +18,6 @@ https://developers.google.com/open-source/licenses/bsd


#define REFTABLE_UNUSED __attribute__((__unused__)) #define REFTABLE_UNUSED __attribute__((__unused__))


struct reftable_buf {
size_t alloc;
size_t len;
char *buf;
};
#define REFTABLE_BUF_INIT { 0 }

/* /*
* Initialize the buffer such that it is ready for use. This is equivalent to * Initialize the buffer such that it is ready for use. This is equivalent to
* using REFTABLE_BUF_INIT for stack-allocated variables. * using REFTABLE_BUF_INIT for stack-allocated variables.

View File

@ -1,15 +1,16 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#include "block.h" #include "block.h"


#include "blocksource.h" #include "blocksource.h"
#include "constants.h" #include "constants.h"
#include "iter.h"
#include "record.h" #include "record.h"
#include "reftable-error.h" #include "reftable-error.h"
#include "system.h" #include "system.h"
@ -160,7 +161,7 @@ int block_writer_finish(struct block_writer *w)
* Log records are stored zlib-compressed. Note that the compression * Log records are stored zlib-compressed. Note that the compression
* also spans over the restart points we have just written. * also spans over the restart points we have just written.
*/ */
if (block_writer_type(w) == BLOCK_TYPE_LOG) { if (block_writer_type(w) == REFTABLE_BLOCK_TYPE_LOG) {
int block_header_skip = 4 + w->header_off; int block_header_skip = 4 + w->header_off;
uLongf src_len = w->next - block_header_skip, compressed_len; uLongf src_len = w->next - block_header_skip, compressed_len;
int ret; int ret;
@ -210,61 +211,86 @@ int block_writer_finish(struct block_writer *w)
return w->next; return w->next;
} }


int block_reader_init(struct block_reader *br, struct reftable_block *block, static int read_block(struct reftable_block_source *source,
uint32_t header_off, uint32_t table_block_size, struct reftable_block_data *dest, uint64_t off,
uint32_t hash_size) uint32_t sz)
{ {
size_t size = block_source_size(source);
block_source_release_data(dest);
if (off >= size)
return 0;
if (off + sz > size)
sz = size - off;
return block_source_read_data(source, dest, off, sz);
}

int reftable_block_init(struct reftable_block *block,
struct reftable_block_source *source,
uint32_t offset, uint32_t header_size,
uint32_t table_block_size, uint32_t hash_size)
{
uint32_t guess_block_size = table_block_size ?
table_block_size : DEFAULT_BLOCK_SIZE;
uint32_t full_block_size = table_block_size; uint32_t full_block_size = table_block_size;
uint8_t typ = block->data[header_off]; uint16_t restart_count;
uint32_t sz = reftable_get_be24(block->data + header_off + 1); uint32_t restart_off;
int err = 0; uint32_t block_size;
uint16_t restart_count = 0; uint8_t block_type;
uint32_t restart_start = 0; int err;
uint8_t *restart_bytes = NULL;


reftable_block_done(&br->block); err = read_block(source, &block->block_data, offset, guess_block_size);
if (err < 0)
goto done;


if (!reftable_is_block_type(typ)) { block_type = block->block_data.data[header_size];
if (!reftable_is_block_type(block_type)) {
err = REFTABLE_FORMAT_ERROR; err = REFTABLE_FORMAT_ERROR;
goto done; goto done;
} }


if (typ == BLOCK_TYPE_LOG) { block_size = reftable_get_be24(block->block_data.data + header_size + 1);
uint32_t block_header_skip = 4 + header_off; if (block_size > guess_block_size) {
uLong dst_len = sz - block_header_skip; err = read_block(source, &block->block_data, offset, block_size);
uLong src_len = block->len - block_header_skip; if (err < 0)
goto done;
}

if (block_type == REFTABLE_BLOCK_TYPE_LOG) {
uint32_t block_header_skip = 4 + header_size;
uLong dst_len = block_size - block_header_skip;
uLong src_len = block->block_data.len - block_header_skip;


/* Log blocks specify the *uncompressed* size in their header. */ /* Log blocks specify the *uncompressed* size in their header. */
REFTABLE_ALLOC_GROW_OR_NULL(br->uncompressed_data, sz, REFTABLE_ALLOC_GROW_OR_NULL(block->uncompressed_data, block_size,
br->uncompressed_cap); block->uncompressed_cap);
if (!br->uncompressed_data) { if (!block->uncompressed_data) {
err = REFTABLE_OUT_OF_MEMORY_ERROR; err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done; goto done;
} }


/* Copy over the block header verbatim. It's not compressed. */ /* Copy over the block header verbatim. It's not compressed. */
memcpy(br->uncompressed_data, block->data, block_header_skip); memcpy(block->uncompressed_data, block->block_data.data, block_header_skip);


if (!br->zstream) { if (!block->zstream) {
REFTABLE_CALLOC_ARRAY(br->zstream, 1); REFTABLE_CALLOC_ARRAY(block->zstream, 1);
if (!br->zstream) { if (!block->zstream) {
err = REFTABLE_OUT_OF_MEMORY_ERROR; err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done; goto done;
} }


err = inflateInit(br->zstream); err = inflateInit(block->zstream);
} else { } else {
err = inflateReset(br->zstream); err = inflateReset(block->zstream);
} }
if (err != Z_OK) { if (err != Z_OK) {
err = REFTABLE_ZLIB_ERROR; err = REFTABLE_ZLIB_ERROR;
goto done; goto done;
} }


br->zstream->next_in = block->data + block_header_skip; block->zstream->next_in = block->block_data.data + block_header_skip;
br->zstream->avail_in = src_len; block->zstream->avail_in = src_len;
br->zstream->next_out = br->uncompressed_data + block_header_skip; block->zstream->next_out = block->uncompressed_data + block_header_skip;
br->zstream->avail_out = dst_len; block->zstream->avail_out = dst_len;


/* /*
* We know both input as well as output size, and we know that * We know both input as well as output size, and we know that
@ -273,72 +299,71 @@ int block_reader_init(struct block_reader *br, struct reftable_block *block,
* here to instruct zlib to inflate the data in one go, which * here to instruct zlib to inflate the data in one go, which
* is more efficient than using `Z_NO_FLUSH`. * is more efficient than using `Z_NO_FLUSH`.
*/ */
err = inflate(br->zstream, Z_FINISH); err = inflate(block->zstream, Z_FINISH);
if (err != Z_STREAM_END) { if (err != Z_STREAM_END) {
err = REFTABLE_ZLIB_ERROR; err = REFTABLE_ZLIB_ERROR;
goto done; goto done;
} }
err = 0; err = 0;


if (br->zstream->total_out + block_header_skip != sz) { if (block->zstream->total_out + block_header_skip != block_size) {
err = REFTABLE_FORMAT_ERROR; err = REFTABLE_FORMAT_ERROR;
goto done; goto done;
} }


/* We're done with the input data. */ /* We're done with the input data. */
reftable_block_done(block); block_source_release_data(&block->block_data);
block->data = br->uncompressed_data; block->block_data.data = block->uncompressed_data;
block->len = sz; block->block_data.len = block_size;
full_block_size = src_len + block_header_skip - br->zstream->avail_in; full_block_size = src_len + block_header_skip - block->zstream->avail_in;
} else if (full_block_size == 0) { } else if (full_block_size == 0) {
full_block_size = sz; full_block_size = block_size;
} else if (sz < full_block_size && sz < block->len && } else if (block_size < full_block_size && block_size < block->block_data.len &&
block->data[sz] != 0) { block->block_data.data[block_size] != 0) {
/* If the block is smaller than the full block size, it is /* If the block is smaller than the full block size, it is
padded (data followed by '\0') or the next block is padded (data followed by '\0') or the next block is
unaligned. */ unaligned. */
full_block_size = sz; full_block_size = block_size;
} }


restart_count = reftable_get_be16(block->data + sz - 2); restart_count = reftable_get_be16(block->block_data.data + block_size - 2);
restart_start = sz - 2 - 3 * restart_count; restart_off = block_size - 2 - 3 * restart_count;
restart_bytes = block->data + restart_start;


/* transfer ownership. */ block->block_type = block_type;
br->block = *block; block->hash_size = hash_size;
block->data = NULL; block->restart_off = restart_off;
block->len = 0; block->full_block_size = full_block_size;
block->header_off = header_size;
block->restart_count = restart_count;


br->hash_size = hash_size; err = 0;
br->block_len = restart_start;
br->full_block_size = full_block_size;
br->header_off = header_off;
br->restart_count = restart_count;
br->restart_bytes = restart_bytes;


done: done:
if (err < 0)
reftable_block_release(block);
return err; return err;
} }


void block_reader_release(struct block_reader *br) void reftable_block_release(struct reftable_block *block)
{ {
inflateEnd(br->zstream); inflateEnd(block->zstream);
reftable_free(br->zstream); reftable_free(block->zstream);
reftable_free(br->uncompressed_data); reftable_free(block->uncompressed_data);
reftable_block_done(&br->block); block_source_release_data(&block->block_data);
memset(block, 0, sizeof(*block));
} }


uint8_t block_reader_type(const struct block_reader *r) uint8_t reftable_block_type(const struct reftable_block *b)
{ {
return r->block.data[r->header_off]; return b->block_data.data[b->header_off];
} }


int block_reader_first_key(const struct block_reader *br, struct reftable_buf *key) int reftable_block_first_key(const struct reftable_block *block, struct reftable_buf *key)
{ {
int off = br->header_off + 4, n; int off = block->header_off + 4, n;
struct string_view in = { struct string_view in = {
.buf = br->block.data + off, .buf = block->block_data.data + off,
.len = br->block_len - off, .len = block->restart_off - off,
}; };
uint8_t extra = 0; uint8_t extra = 0;


@ -353,33 +378,36 @@ int block_reader_first_key(const struct block_reader *br, struct reftable_buf *k
return 0; return 0;
} }


static uint32_t block_reader_restart_offset(const struct block_reader *br, size_t idx) static uint32_t block_restart_offset(const struct reftable_block *b, size_t idx)
{ {
return reftable_get_be24(br->restart_bytes + 3 * idx); return reftable_get_be24(b->block_data.data + b->restart_off + 3 * idx);
} }


void block_iter_seek_start(struct block_iter *it, const struct block_reader *br) void block_iter_init(struct block_iter *it, const struct reftable_block *block)
{
it->block = block;
block_iter_seek_start(it);
}

void block_iter_seek_start(struct block_iter *it)
{ {
it->block = br->block.data;
it->block_len = br->block_len;
it->hash_size = br->hash_size;
reftable_buf_reset(&it->last_key); reftable_buf_reset(&it->last_key);
it->next_off = br->header_off + 4; it->next_off = it->block->header_off + 4;
} }


struct restart_needle_less_args { struct restart_needle_less_args {
int error; int error;
struct reftable_buf needle; struct reftable_buf needle;
const struct block_reader *reader; const struct reftable_block *block;
}; };


static int restart_needle_less(size_t idx, void *_args) static int restart_needle_less(size_t idx, void *_args)
{ {
struct restart_needle_less_args *args = _args; struct restart_needle_less_args *args = _args;
uint32_t off = block_reader_restart_offset(args->reader, idx); uint32_t off = block_restart_offset(args->block, idx);
struct string_view in = { struct string_view in = {
.buf = args->reader->block.data + off, .buf = args->block->block_data.data + off,
.len = args->reader->block_len - off, .len = args->block->restart_off - off,
}; };
uint64_t prefix_len, suffix_len; uint64_t prefix_len, suffix_len;
uint8_t extra; uint8_t extra;
@ -412,14 +440,14 @@ static int restart_needle_less(size_t idx, void *_args)
int block_iter_next(struct block_iter *it, struct reftable_record *rec) int block_iter_next(struct block_iter *it, struct reftable_record *rec)
{ {
struct string_view in = { struct string_view in = {
.buf = (unsigned char *) it->block + it->next_off, .buf = (unsigned char *) it->block->block_data.data + it->next_off,
.len = it->block_len - it->next_off, .len = it->block->restart_off - it->next_off,
}; };
struct string_view start = in; struct string_view start = in;
uint8_t extra = 0; uint8_t extra = 0;
int n = 0; int n = 0;


if (it->next_off >= it->block_len) if (it->next_off >= it->block->restart_off)
return 1; return 1;


n = reftable_decode_key(&it->last_key, &extra, in); n = reftable_decode_key(&it->last_key, &extra, in);
@ -429,7 +457,7 @@ int block_iter_next(struct block_iter *it, struct reftable_record *rec)
return REFTABLE_FORMAT_ERROR; return REFTABLE_FORMAT_ERROR;


string_view_consume(&in, n); string_view_consume(&in, n);
n = reftable_record_decode(rec, it->last_key, extra, in, it->hash_size, n = reftable_record_decode(rec, it->last_key, extra, in, it->block->hash_size,
&it->scratch); &it->scratch);
if (n < 0) if (n < 0)
return -1; return -1;
@ -444,8 +472,6 @@ void block_iter_reset(struct block_iter *it)
reftable_buf_reset(&it->last_key); reftable_buf_reset(&it->last_key);
it->next_off = 0; it->next_off = 0;
it->block = NULL; it->block = NULL;
it->block_len = 0;
it->hash_size = 0;
} }


void block_iter_close(struct block_iter *it) void block_iter_close(struct block_iter *it)
@ -454,12 +480,11 @@ void block_iter_close(struct block_iter *it)
reftable_buf_release(&it->scratch); reftable_buf_release(&it->scratch);
} }


int block_iter_seek_key(struct block_iter *it, const struct block_reader *br, int block_iter_seek_key(struct block_iter *it, struct reftable_buf *want)
struct reftable_buf *want)
{ {
struct restart_needle_less_args args = { struct restart_needle_less_args args = {
.needle = *want, .needle = *want,
.reader = br, .block = it->block,
}; };
struct reftable_record rec; struct reftable_record rec;
int err = 0; int err = 0;
@ -477,7 +502,7 @@ int block_iter_seek_key(struct block_iter *it, const struct block_reader *br,
* restart point. While that works alright, we would end up scanning * restart point. While that works alright, we would end up scanning
* too many record. * too many record.
*/ */
i = binsearch(br->restart_count, &restart_needle_less, &args); i = binsearch(it->block->restart_count, &restart_needle_less, &args);
if (args.error) { if (args.error) {
err = REFTABLE_FORMAT_ERROR; err = REFTABLE_FORMAT_ERROR;
goto done; goto done;
@ -502,21 +527,18 @@ int block_iter_seek_key(struct block_iter *it, const struct block_reader *br,
* starting from the preceding restart point. * starting from the preceding restart point.
*/ */
if (i > 0) if (i > 0)
it->next_off = block_reader_restart_offset(br, i - 1); it->next_off = block_restart_offset(it->block, i - 1);
else else
it->next_off = br->header_off + 4; it->next_off = it->block->header_off + 4;
it->block = br->block.data;
it->block_len = br->block_len;
it->hash_size = br->hash_size;


err = reftable_record_init(&rec, block_reader_type(br)); err = reftable_record_init(&rec, reftable_block_type(it->block));
if (err < 0) if (err < 0)
goto done; goto done;


/* /*
* We're looking for the last entry less than the wanted key so that * We're looking for the last entry less than the wanted key so that
* the next call to `block_reader_next()` would yield the wanted * the next call to `block_reader_next()` would yield the wanted
* record. We thus don't want to position our reader at the sought * record. We thus don't want to position our iterator at the sought
* after record, but one before. To do so, we have to go one entry too * after record, but one before. To do so, we have to go one entry too
* far and then back up. * far and then back up.
*/ */
@ -561,6 +583,61 @@ done:
return err; 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) void block_writer_release(struct block_writer *bw)
{ {
deflateEnd(bw->zstream); deflateEnd(bw->zstream);
@ -571,14 +648,3 @@ void block_writer_release(struct block_writer *bw)
reftable_buf_release(&bw->last_key); reftable_buf_release(&bw->last_key);
/* the block is not owned. */ /* the block is not owned. */
} }

void reftable_block_done(struct reftable_block *blockp)
{
struct reftable_block_source source = blockp->source;
if (blockp && source.ops)
source.ops->return_block(source.arg, blockp);
blockp->data = NULL;
blockp->len = 0;
blockp->source.ops = NULL;
blockp->source.arg = NULL;
}

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef BLOCK_H #ifndef BLOCK_H
@ -11,6 +11,7 @@ https://developers.google.com/open-source/licenses/bsd


#include "basics.h" #include "basics.h"
#include "record.h" #include "record.h"
#include "reftable-block.h"
#include "reftable-blocksource.h" #include "reftable-blocksource.h"


/* /*
@ -18,7 +19,7 @@ https://developers.google.com/open-source/licenses/bsd
* allocation overhead. * allocation overhead.
*/ */
struct block_writer { struct block_writer {
z_stream *zstream; struct z_stream_s *zstream;
unsigned char *compressed; unsigned char *compressed;
size_t compressed_cap; size_t compressed_cap;


@ -62,53 +63,11 @@ int block_writer_finish(struct block_writer *w);
/* clears out internally allocated block_writer members. */ /* clears out internally allocated block_writer members. */
void block_writer_release(struct block_writer *bw); void block_writer_release(struct block_writer *bw);


struct z_stream; /* Iterator for records contained in a single block. */

/* Read a block. */
struct block_reader {
/* offset of the block header; nonzero for the first block in a
* reftable. */
uint32_t header_off;

/* the memory block */
struct reftable_block block;
uint32_t hash_size;

/* Uncompressed data for log entries. */
z_stream *zstream;
unsigned char *uncompressed_data;
size_t uncompressed_cap;

/* size of the data, excluding restart data. */
uint32_t block_len;
uint8_t *restart_bytes;
uint16_t restart_count;

/* size of the data in the file. For log blocks, this is the compressed
* size. */
uint32_t full_block_size;
};

/* initializes a block reader. */
int block_reader_init(struct block_reader *br, struct reftable_block *bl,
uint32_t header_off, uint32_t table_block_size,
uint32_t hash_size);

void block_reader_release(struct block_reader *br);

/* Returns the block type (eg. 'r' for refs) */
uint8_t block_reader_type(const struct block_reader *r);

/* Decodes the first key in the block */
int block_reader_first_key(const struct block_reader *br, struct reftable_buf *key);

/* Iterate over entries in a block */
struct block_iter { struct block_iter {
/* offset within the block of the next entry to read. */ /* offset within the block of the next entry to read. */
uint32_t next_off; uint32_t next_off;
const unsigned char *block; const struct reftable_block *block;
size_t block_len;
uint32_t hash_size;


/* key for last entry we read. */ /* key for last entry we read. */
struct reftable_buf last_key; struct reftable_buf last_key;
@ -120,12 +79,23 @@ struct block_iter {
.scratch = REFTABLE_BUF_INIT, \ .scratch = REFTABLE_BUF_INIT, \
} }


/* Position `it` at start of the block */ /*
void block_iter_seek_start(struct block_iter *it, const struct block_reader *br); * Initialize the block iterator with the given block. The iterator will be
* positioned at the first record contained in the block. The block must remain
* valid until the end of the iterator's lifetime. It is valid to re-initialize
* iterators multiple times.
*/
void block_iter_init(struct block_iter *it, const struct reftable_block *block);


/* Position `it` to the `want` key in the block */ /* Position the initialized iterator at the first record of its block. */
int block_iter_seek_key(struct block_iter *it, const struct block_reader *br, void block_iter_seek_start(struct block_iter *it);
struct reftable_buf *want);
/*
* Position the initialized iterator at the desired record key. It is not an
* error in case the record cannot be found. If so, a subsequent call to
* `block_iter_next()` will indicate that the iterator is exhausted.
*/
int block_iter_seek_key(struct block_iter *it, struct reftable_buf *want);


/* return < 0 for error, 0 for OK, > 0 for EOF. */ /* return < 0 for error, 0 for OK, > 0 for EOF. */
int block_iter_next(struct block_iter *it, struct reftable_record *rec); int block_iter_next(struct block_iter *it, struct reftable_record *rec);
@ -142,7 +112,4 @@ size_t header_size(int version);
/* size of file footer, depending on format version */ /* size of file footer, depending on format version */
size_t footer_size(int version); size_t footer_size(int version);


/* returns a block to its source. */
void reftable_block_done(struct reftable_block *ret);

#endif #endif

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#include "system.h" #include "system.h"
@ -13,7 +13,42 @@ https://developers.google.com/open-source/licenses/bsd
#include "reftable-blocksource.h" #include "reftable-blocksource.h"
#include "reftable-error.h" #include "reftable-error.h"


static void reftable_buf_return_block(void *b REFTABLE_UNUSED, struct reftable_block *dest) void block_source_release_data(struct reftable_block_data *data)
{
struct reftable_block_source source = data->source;
if (data && source.ops)
source.ops->release_data(source.arg, data);
data->data = NULL;
data->len = 0;
data->source.ops = NULL;
data->source.arg = NULL;
}

void block_source_close(struct reftable_block_source *source)
{
if (!source->ops) {
return;
}

source->ops->close(source->arg);
source->ops = NULL;
}

ssize_t block_source_read_data(struct reftable_block_source *source,
struct reftable_block_data *dest, uint64_t off,
uint32_t size)
{
ssize_t result = source->ops->read_data(source->arg, dest, off, size);
dest->source = *source;
return result;
}

uint64_t block_source_size(struct reftable_block_source *source)
{
return source->ops->size(source->arg);
}

static void reftable_buf_release_data(void *b REFTABLE_UNUSED, struct reftable_block_data *dest)
{ {
if (dest->len) if (dest->len)
memset(dest->data, 0xff, dest->len); memset(dest->data, 0xff, dest->len);
@ -24,7 +59,7 @@ static void reftable_buf_close(void *b REFTABLE_UNUSED)
{ {
} }


static ssize_t reftable_buf_read_block(void *v, struct reftable_block *dest, static ssize_t reftable_buf_read_data(void *v, struct reftable_block_data *dest,
uint64_t off, uint32_t size) uint64_t off, uint32_t size)
{ {
struct reftable_buf *b = v; struct reftable_buf *b = v;
@ -44,8 +79,8 @@ static uint64_t reftable_buf_size(void *b)


static struct reftable_block_source_vtable reftable_buf_vtable = { static struct reftable_block_source_vtable reftable_buf_vtable = {
.size = &reftable_buf_size, .size = &reftable_buf_size,
.read_block = &reftable_buf_read_block, .read_data = &reftable_buf_read_data,
.return_block = &reftable_buf_return_block, .release_data = &reftable_buf_release_data,
.close = &reftable_buf_close, .close = &reftable_buf_close,
}; };


@ -67,7 +102,7 @@ static uint64_t file_size(void *b)
return ((struct file_block_source *)b)->size; return ((struct file_block_source *)b)->size;
} }


static void file_return_block(void *b REFTABLE_UNUSED, struct reftable_block *dest REFTABLE_UNUSED) static void file_release_data(void *b REFTABLE_UNUSED, struct reftable_block_data *dest REFTABLE_UNUSED)
{ {
} }


@ -78,7 +113,7 @@ static void file_close(void *v)
reftable_free(b); reftable_free(b);
} }


static ssize_t file_read_block(void *v, struct reftable_block *dest, uint64_t off, static ssize_t file_read_data(void *v, struct reftable_block_data *dest, uint64_t off,
uint32_t size) uint32_t size)
{ {
struct file_block_source *b = v; struct file_block_source *b = v;
@ -90,8 +125,8 @@ static ssize_t file_read_block(void *v, struct reftable_block *dest, uint64_t of


static struct reftable_block_source_vtable file_vtable = { static struct reftable_block_source_vtable file_vtable = {
.size = &file_size, .size = &file_size,
.read_block = &file_read_block, .read_data = &file_read_data,
.return_block = &file_return_block, .release_data = &file_release_data,
.close = &file_close, .close = &file_close,
}; };



View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef BLOCKSOURCE_H #ifndef BLOCKSOURCE_H
@ -12,9 +12,34 @@ https://developers.google.com/open-source/licenses/bsd
#include "system.h" #include "system.h"


struct reftable_block_source; struct reftable_block_source;
struct reftable_block_data;
struct reftable_buf; struct reftable_buf;


/* Create an in-memory block source for reading reftables */ /*
* Close the block source and the underlying resource. This is a no-op in case
* the block source is zero-initialized.
*/
void block_source_close(struct reftable_block_source *source);

/*
* Read a block of length `size` from the source at the given `off`.
*/
ssize_t block_source_read_data(struct reftable_block_source *source,
struct reftable_block_data *dest, uint64_t off,
uint32_t size);

/*
* Return the total length of the underlying resource.
*/
uint64_t block_source_size(struct reftable_block_source *source);

/*
* Return a block to its original source, releasing any resources associated
* with it.
*/
void block_source_release_data(struct reftable_block_data *data);

/* Create an in-memory block source for reading reftables. */
void block_source_from_buf(struct reftable_block_source *bs, void block_source_from_buf(struct reftable_block_source *bs,
struct reftable_buf *buf); struct reftable_buf *buf);



View File

@ -1,19 +1,15 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef CONSTANTS_H #ifndef CONSTANTS_H
#define CONSTANTS_H #define CONSTANTS_H


#define BLOCK_TYPE_LOG 'g' #include "reftable-constants.h"
#define BLOCK_TYPE_INDEX 'i'
#define BLOCK_TYPE_REF 'r'
#define BLOCK_TYPE_OBJ 'o'
#define BLOCK_TYPE_ANY 0


#define MAX_RESTARTS ((1 << 16) - 1) #define MAX_RESTARTS ((1 << 16) - 1)
#define DEFAULT_BLOCK_SIZE 4096 #define DEFAULT_BLOCK_SIZE 4096

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#include "system.h" #include "system.h"

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#include "iter.h" #include "iter.h"
@ -11,9 +11,10 @@ https://developers.google.com/open-source/licenses/bsd
#include "system.h" #include "system.h"


#include "block.h" #include "block.h"
#include "blocksource.h"
#include "constants.h" #include "constants.h"
#include "reader.h"
#include "reftable-error.h" #include "reftable-error.h"
#include "table.h"


int iterator_seek(struct reftable_iterator *it, struct reftable_record *want) int iterator_seek(struct reftable_iterator *it, struct reftable_record *want)
{ {
@ -113,7 +114,7 @@ static void indexed_table_ref_iter_close(void *p)
{ {
struct indexed_table_ref_iter *it = p; struct indexed_table_ref_iter *it = p;
block_iter_close(&it->cur); block_iter_close(&it->cur);
reftable_block_done(&it->block_reader.block); block_source_release_data(&it->block.block_data);
reftable_free(it->offsets); reftable_free(it->offsets);
reftable_buf_release(&it->oid); reftable_buf_release(&it->oid);
} }
@ -127,11 +128,10 @@ static int indexed_table_ref_iter_next_block(struct indexed_table_ref_iter *it)
return 1; return 1;
} }


reftable_block_done(&it->block_reader.block); block_source_release_data(&it->block.block_data);


off = it->offsets[it->offset_idx++]; off = it->offsets[it->offset_idx++];
err = reader_init_block_reader(it->r, &it->block_reader, off, err = table_init_block(it->table, &it->block, off, REFTABLE_BLOCK_TYPE_REF);
BLOCK_TYPE_REF);
if (err < 0) { if (err < 0) {
return err; return err;
} }
@ -139,7 +139,7 @@ static int indexed_table_ref_iter_next_block(struct indexed_table_ref_iter *it)
/* indexed block does not exist. */ /* indexed block does not exist. */
return REFTABLE_FORMAT_ERROR; return REFTABLE_FORMAT_ERROR;
} }
block_iter_seek_start(&it->cur, &it->block_reader); block_iter_init(&it->cur, &it->block);
return 0; return 0;
} }


@ -181,7 +181,7 @@ static int indexed_table_ref_iter_next(void *p, struct reftable_record *rec)
} }


int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest, int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest,
struct reftable_reader *r, uint8_t *oid, struct reftable_table *t, uint8_t *oid,
int oid_len, uint64_t *offsets, int offset_len) int oid_len, uint64_t *offsets, int offset_len)
{ {
struct indexed_table_ref_iter empty = INDEXED_TABLE_REF_ITER_INIT; struct indexed_table_ref_iter empty = INDEXED_TABLE_REF_ITER_INIT;
@ -195,7 +195,7 @@ int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest,
} }


*itr = empty; *itr = empty;
itr->r = r; itr->table = t;


err = reftable_buf_add(&itr->oid, oid, oid_len); err = reftable_buf_add(&itr->oid, oid, oid_len);
if (err < 0) if (err < 0)
@ -246,7 +246,7 @@ int reftable_iterator_seek_ref(struct reftable_iterator *it,
const char *name) const char *name)
{ {
struct reftable_record want = { struct reftable_record want = {
.type = BLOCK_TYPE_REF, .type = REFTABLE_BLOCK_TYPE_REF,
.u.ref = { .u.ref = {
.refname = (char *)name, .refname = (char *)name,
}, },
@ -258,7 +258,7 @@ int reftable_iterator_next_ref(struct reftable_iterator *it,
struct reftable_ref_record *ref) struct reftable_ref_record *ref)
{ {
struct reftable_record rec = { struct reftable_record rec = {
.type = BLOCK_TYPE_REF, .type = REFTABLE_BLOCK_TYPE_REF,
.u = { .u = {
.ref = *ref .ref = *ref
}, },
@ -272,7 +272,7 @@ int reftable_iterator_seek_log_at(struct reftable_iterator *it,
const char *name, uint64_t update_index) const char *name, uint64_t update_index)
{ {
struct reftable_record want = { struct reftable_record want = {
.type = BLOCK_TYPE_LOG, .type = REFTABLE_BLOCK_TYPE_LOG,
.u.log = { .u.log = {
.refname = (char *)name, .refname = (char *)name,
.update_index = update_index, .update_index = update_index,
@ -291,7 +291,7 @@ int reftable_iterator_next_log(struct reftable_iterator *it,
struct reftable_log_record *log) struct reftable_log_record *log)
{ {
struct reftable_record rec = { struct reftable_record rec = {
.type = BLOCK_TYPE_LOG, .type = REFTABLE_BLOCK_TYPE_LOG,
.u = { .u = {
.log = *log, .log = *log,
}, },

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef ITER_H #ifndef ITER_H
@ -59,7 +59,7 @@ void iterator_from_filtering_ref_iterator(struct reftable_iterator *,
* but using the object index. * but using the object index.
*/ */
struct indexed_table_ref_iter { struct indexed_table_ref_iter {
struct reftable_reader *r; struct reftable_table *table;
struct reftable_buf oid; struct reftable_buf oid;


/* mutable */ /* mutable */
@ -68,7 +68,7 @@ struct indexed_table_ref_iter {
/* Points to the next offset to read. */ /* Points to the next offset to read. */
int offset_idx; int offset_idx;
int offset_len; int offset_len;
struct block_reader block_reader; struct reftable_block block;
struct block_iter cur; struct block_iter cur;
int is_finished; int is_finished;
}; };
@ -83,7 +83,7 @@ void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it,


/* Takes ownership of `offsets` */ /* Takes ownership of `offsets` */
int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest, int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest,
struct reftable_reader *r, uint8_t *oid, struct reftable_table *t, uint8_t *oid,
int oid_len, uint64_t *offsets, int offset_len); int oid_len, uint64_t *offsets, int offset_len);


#endif #endif

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#include "merged.h" #include "merged.h"
@ -11,11 +11,11 @@ https://developers.google.com/open-source/licenses/bsd
#include "constants.h" #include "constants.h"
#include "iter.h" #include "iter.h"
#include "pq.h" #include "pq.h"
#include "reader.h"
#include "record.h" #include "record.h"
#include "reftable-merged.h" #include "reftable-merged.h"
#include "reftable-error.h" #include "reftable-error.h"
#include "system.h" #include "system.h"
#include "table.h"


struct merged_subiter { struct merged_subiter {
struct reftable_iterator iter; struct reftable_iterator iter;
@ -192,7 +192,7 @@ static void iterator_from_merged_iter(struct reftable_iterator *it,
} }


int reftable_merged_table_new(struct reftable_merged_table **dest, int reftable_merged_table_new(struct reftable_merged_table **dest,
struct reftable_reader **readers, size_t n, struct reftable_table **tables, size_t n,
enum reftable_hash hash_id) enum reftable_hash hash_id)
{ {
struct reftable_merged_table *m = NULL; struct reftable_merged_table *m = NULL;
@ -200,10 +200,10 @@ int reftable_merged_table_new(struct reftable_merged_table **dest,
uint64_t first_min = 0; uint64_t first_min = 0;


for (size_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
uint64_t min = reftable_reader_min_update_index(readers[i]); uint64_t min = reftable_table_min_update_index(tables[i]);
uint64_t max = reftable_reader_max_update_index(readers[i]); uint64_t max = reftable_table_max_update_index(tables[i]);


if (reftable_reader_hash_id(readers[i]) != hash_id) { if (reftable_table_hash_id(tables[i]) != hash_id) {
return REFTABLE_FORMAT_ERROR; return REFTABLE_FORMAT_ERROR;
} }
if (i == 0 || min < first_min) { if (i == 0 || min < first_min) {
@ -218,8 +218,8 @@ int reftable_merged_table_new(struct reftable_merged_table **dest,
if (!m) if (!m)
return REFTABLE_OUT_OF_MEMORY_ERROR; return REFTABLE_OUT_OF_MEMORY_ERROR;


m->readers = readers; m->tables = tables;
m->readers_len = n; m->tables_len = n;
m->min = first_min; m->min = first_min;
m->max = last_max; m->max = last_max;
m->hash_id = hash_id; m->hash_id = hash_id;
@ -254,20 +254,20 @@ int merged_table_init_iter(struct reftable_merged_table *mt,
struct merged_iter *mi = NULL; struct merged_iter *mi = NULL;
int ret; int ret;


if (mt->readers_len) { if (mt->tables_len) {
REFTABLE_CALLOC_ARRAY(subiters, mt->readers_len); REFTABLE_CALLOC_ARRAY(subiters, mt->tables_len);
if (!subiters) { if (!subiters) {
ret = REFTABLE_OUT_OF_MEMORY_ERROR; ret = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out; goto out;
} }
} }


for (size_t i = 0; i < mt->readers_len; i++) { for (size_t i = 0; i < mt->tables_len; i++) {
ret = reftable_record_init(&subiters[i].rec, typ); ret = reftable_record_init(&subiters[i].rec, typ);
if (ret < 0) if (ret < 0)
goto out; goto out;


ret = reader_init_iter(mt->readers[i], &subiters[i].iter, typ); ret = table_init_iter(mt->tables[i], &subiters[i].iter, typ);
if (ret < 0) if (ret < 0)
goto out; goto out;
} }
@ -280,14 +280,14 @@ int merged_table_init_iter(struct reftable_merged_table *mt,
mi->advance_index = -1; mi->advance_index = -1;
mi->suppress_deletions = mt->suppress_deletions; mi->suppress_deletions = mt->suppress_deletions;
mi->subiters = subiters; mi->subiters = subiters;
mi->subiters_len = mt->readers_len; mi->subiters_len = mt->tables_len;


iterator_from_merged_iter(it, mi); iterator_from_merged_iter(it, mi);
ret = 0; ret = 0;


out: out:
if (ret < 0) { if (ret < 0) {
for (size_t i = 0; subiters && i < mt->readers_len; i++) { for (size_t i = 0; subiters && i < mt->tables_len; i++) {
reftable_iterator_destroy(&subiters[i].iter); reftable_iterator_destroy(&subiters[i].iter);
reftable_record_release(&subiters[i].rec); reftable_record_release(&subiters[i].rec);
} }
@ -301,13 +301,13 @@ out:
int reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt, int reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
struct reftable_iterator *it) struct reftable_iterator *it)
{ {
return merged_table_init_iter(mt, it, BLOCK_TYPE_REF); return merged_table_init_iter(mt, it, REFTABLE_BLOCK_TYPE_REF);
} }


int reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt, int reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
struct reftable_iterator *it) struct reftable_iterator *it)
{ {
return merged_table_init_iter(mt, it, BLOCK_TYPE_LOG); return merged_table_init_iter(mt, it, REFTABLE_BLOCK_TYPE_LOG);
} }


enum reftable_hash reftable_merged_table_hash_id(struct reftable_merged_table *mt) enum reftable_hash reftable_merged_table_hash_id(struct reftable_merged_table *mt)

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef MERGED_H #ifndef MERGED_H
@ -13,8 +13,8 @@ https://developers.google.com/open-source/licenses/bsd
#include "reftable-basics.h" #include "reftable-basics.h"


struct reftable_merged_table { struct reftable_merged_table {
struct reftable_reader **readers; struct reftable_table **tables;
size_t readers_len; size_t tables_len;
enum reftable_hash hash_id; enum reftable_hash hash_id;


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

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#include "pq.h" #include "pq.h"

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef PQ_H #ifndef PQ_H

View File

@ -1,67 +0,0 @@
/*
Copyright 2020 Google LLC

Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd
*/

#ifndef READER_H
#define READER_H

#include "block.h"
#include "record.h"
#include "reftable-iterator.h"
#include "reftable-reader.h"

uint64_t block_source_size(struct reftable_block_source *source);

ssize_t block_source_read_block(struct reftable_block_source *source,
struct reftable_block *dest, uint64_t off,
uint32_t size);
void block_source_close(struct reftable_block_source *source);

/* metadata for a block type */
struct reftable_reader_offsets {
int is_present;
uint64_t offset;
uint64_t index_offset;
};

/* The state for reading a reftable file. */
struct reftable_reader {
/* for convenience, associate a name with the instance. */
char *name;
struct reftable_block_source source;

/* Size of the file, excluding the footer. */
uint64_t size;

/* The hash function used for ref records. */
enum reftable_hash hash_id;

uint32_t block_size;
uint64_t min_update_index;
uint64_t max_update_index;
/* Length of the OID keys in the 'o' section */
int object_id_len;
int version;

struct reftable_reader_offsets ref_offsets;
struct reftable_reader_offsets obj_offsets;
struct reftable_reader_offsets log_offsets;

uint64_t refcount;
};

const char *reader_name(struct reftable_reader *r);

int reader_init_iter(struct reftable_reader *r,
struct reftable_iterator *it,
uint8_t typ);

/* initialize a block reader to read from `r` */
int reader_init_block_reader(struct reftable_reader *r, struct block_reader *br,
uint64_t next_off, uint8_t want_typ);

#endif

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


/* record.c - methods for different types of records. */ /* record.c - methods for different types of records. */
@ -69,10 +69,10 @@ int put_var_int(struct string_view *dest, uint64_t value)
int reftable_is_block_type(uint8_t typ) int reftable_is_block_type(uint8_t typ)
{ {
switch (typ) { switch (typ) {
case BLOCK_TYPE_REF: case REFTABLE_BLOCK_TYPE_REF:
case BLOCK_TYPE_LOG: case REFTABLE_BLOCK_TYPE_LOG:
case BLOCK_TYPE_OBJ: case REFTABLE_BLOCK_TYPE_OBJ:
case BLOCK_TYPE_INDEX: case REFTABLE_BLOCK_TYPE_INDEX:
return 1; return 1;
} }
return 0; return 0;
@ -459,7 +459,7 @@ static int reftable_ref_record_cmp_void(const void *_a, const void *_b)


static struct reftable_record_vtable reftable_ref_record_vtable = { static struct reftable_record_vtable reftable_ref_record_vtable = {
.key = &reftable_ref_record_key, .key = &reftable_ref_record_key,
.type = BLOCK_TYPE_REF, .type = REFTABLE_BLOCK_TYPE_REF,
.copy_from = &reftable_ref_record_copy_from, .copy_from = &reftable_ref_record_copy_from,
.val_type = &reftable_ref_record_val_type, .val_type = &reftable_ref_record_val_type,
.encode = &reftable_ref_record_encode, .encode = &reftable_ref_record_encode,
@ -659,7 +659,7 @@ static int reftable_obj_record_cmp_void(const void *_a, const void *_b)


static struct reftable_record_vtable reftable_obj_record_vtable = { static struct reftable_record_vtable reftable_obj_record_vtable = {
.key = &reftable_obj_record_key, .key = &reftable_obj_record_key,
.type = BLOCK_TYPE_OBJ, .type = REFTABLE_BLOCK_TYPE_OBJ,
.copy_from = &reftable_obj_record_copy_from, .copy_from = &reftable_obj_record_copy_from,
.val_type = &reftable_obj_record_val_type, .val_type = &reftable_obj_record_val_type,
.encode = &reftable_obj_record_encode, .encode = &reftable_obj_record_encode,
@ -1030,7 +1030,7 @@ static int reftable_log_record_is_deletion_void(const void *p)


static struct reftable_record_vtable reftable_log_record_vtable = { static struct reftable_record_vtable reftable_log_record_vtable = {
.key = &reftable_log_record_key, .key = &reftable_log_record_key,
.type = BLOCK_TYPE_LOG, .type = REFTABLE_BLOCK_TYPE_LOG,
.copy_from = &reftable_log_record_copy_from, .copy_from = &reftable_log_record_copy_from,
.val_type = &reftable_log_record_val_type, .val_type = &reftable_log_record_val_type,
.encode = &reftable_log_record_encode, .encode = &reftable_log_record_encode,
@ -1132,7 +1132,7 @@ static int reftable_index_record_cmp(const void *_a, const void *_b)


static struct reftable_record_vtable reftable_index_record_vtable = { static struct reftable_record_vtable reftable_index_record_vtable = {
.key = &reftable_index_record_key, .key = &reftable_index_record_key,
.type = BLOCK_TYPE_INDEX, .type = REFTABLE_BLOCK_TYPE_INDEX,
.copy_from = &reftable_index_record_copy_from, .copy_from = &reftable_index_record_copy_from,
.val_type = &reftable_index_record_val_type, .val_type = &reftable_index_record_val_type,
.encode = &reftable_index_record_encode, .encode = &reftable_index_record_encode,
@ -1275,13 +1275,13 @@ int reftable_log_record_is_deletion(const struct reftable_log_record *log)
static void *reftable_record_data(struct reftable_record *rec) static void *reftable_record_data(struct reftable_record *rec)
{ {
switch (rec->type) { switch (rec->type) {
case BLOCK_TYPE_REF: case REFTABLE_BLOCK_TYPE_REF:
return &rec->u.ref; return &rec->u.ref;
case BLOCK_TYPE_LOG: case REFTABLE_BLOCK_TYPE_LOG:
return &rec->u.log; return &rec->u.log;
case BLOCK_TYPE_INDEX: case REFTABLE_BLOCK_TYPE_INDEX:
return &rec->u.idx; return &rec->u.idx;
case BLOCK_TYPE_OBJ: case REFTABLE_BLOCK_TYPE_OBJ:
return &rec->u.obj; return &rec->u.obj;
} }
abort(); abort();
@ -1291,13 +1291,13 @@ static struct reftable_record_vtable *
reftable_record_vtable(struct reftable_record *rec) reftable_record_vtable(struct reftable_record *rec)
{ {
switch (rec->type) { switch (rec->type) {
case BLOCK_TYPE_REF: case REFTABLE_BLOCK_TYPE_REF:
return &reftable_ref_record_vtable; return &reftable_ref_record_vtable;
case BLOCK_TYPE_LOG: case REFTABLE_BLOCK_TYPE_LOG:
return &reftable_log_record_vtable; return &reftable_log_record_vtable;
case BLOCK_TYPE_INDEX: case REFTABLE_BLOCK_TYPE_INDEX:
return &reftable_index_record_vtable; return &reftable_index_record_vtable;
case BLOCK_TYPE_OBJ: case REFTABLE_BLOCK_TYPE_OBJ:
return &reftable_obj_record_vtable; return &reftable_obj_record_vtable;
} }
abort(); abort();
@ -1309,11 +1309,11 @@ int reftable_record_init(struct reftable_record *rec, uint8_t typ)
rec->type = typ; rec->type = typ;


switch (typ) { switch (typ) {
case BLOCK_TYPE_REF: case REFTABLE_BLOCK_TYPE_REF:
case BLOCK_TYPE_LOG: case REFTABLE_BLOCK_TYPE_LOG:
case BLOCK_TYPE_OBJ: case REFTABLE_BLOCK_TYPE_OBJ:
return 0; return 0;
case BLOCK_TYPE_INDEX: case REFTABLE_BLOCK_TYPE_INDEX:
reftable_buf_init(&rec->u.idx.last_key); reftable_buf_init(&rec->u.idx.last_key);
return 0; return 0;
default: default:

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef RECORD_H #ifndef RECORD_H

View File

@ -11,6 +11,14 @@


#include <stddef.h> #include <stddef.h>


/* A buffer that contains arbitrary byte slices. */
struct reftable_buf {
size_t alloc;
size_t len;
char *buf;
};
#define REFTABLE_BUF_INIT { 0 }

/* /*
* Hash functions understood by the reftable library. Note that the values are * Hash functions understood by the reftable library. Note that the values are
* arbitrary and somewhat random such that we can easily detect cases where the * arbitrary and somewhat random such that we can easily detect cases where the

74
reftable/reftable-block.h Normal file
View File

@ -0,0 +1,74 @@
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file or at
* https://developers.google.com/open-source/licenses/bsd
*/

#ifndef REFTABLE_BLOCK_H
#define REFTABLE_BLOCK_H

#include <stdint.h>

#include "reftable-basics.h"
#include "reftable-blocksource.h"
#include "reftable-iterator.h"

struct z_stream_s;

/*
* A block part of a reftable. Contains records as well as some metadata
* describing them.
*/
struct reftable_block {
/*
* Offset of the block header; nonzero for the first block in a
* reftable.
*/
uint32_t header_off;

/* The memory block. */
struct reftable_block_data block_data;
uint32_t hash_size;

/* Uncompressed data for log entries. */
struct z_stream_s *zstream;
unsigned char *uncompressed_data;
size_t uncompressed_cap;

/*
* Restart point data. Restart points are located after the block's
* record data.
*/
uint16_t restart_count;
uint32_t restart_off;

/*
* Size of the data in the file. For log blocks, this is the compressed
* size.
*/
uint32_t full_block_size;
uint8_t block_type;
};

/* Initialize a reftable block from the given block source. */
int reftable_block_init(struct reftable_block *b,
struct reftable_block_source *source,
uint32_t offset, uint32_t header_size,
uint32_t table_block_size, uint32_t hash_size);

/* 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);

/* Decodes the first key in the block. */
int reftable_block_first_key(const struct reftable_block *b, struct reftable_buf *key);

#endif /* REFTABLE_BLOCK_H */

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef REFTABLE_BLOCKSOURCE_H #ifndef REFTABLE_BLOCKSOURCE_H
@ -11,7 +11,8 @@ https://developers.google.com/open-source/licenses/bsd


#include <stdint.h> #include <stdint.h>


/* block_source is a generic wrapper for a seekable readable file. /*
* Generic wrapper for a seekable readable file.
*/ */
struct reftable_block_source { struct reftable_block_source {
struct reftable_block_source_vtable *ops; struct reftable_block_source_vtable *ops;
@ -20,7 +21,7 @@ struct reftable_block_source {


/* a contiguous segment of bytes. It keeps track of its generating block_source /* a contiguous segment of bytes. It keeps track of its generating block_source
* so it can return itself into the pool. */ * so it can return itself into the pool. */
struct reftable_block { struct reftable_block_data {
uint8_t *data; uint8_t *data;
size_t len; size_t len;
struct reftable_block_source source; struct reftable_block_source source;
@ -28,20 +29,20 @@ struct reftable_block {


/* block_source_vtable are the operations that make up block_source */ /* block_source_vtable are the operations that make up block_source */
struct reftable_block_source_vtable { struct reftable_block_source_vtable {
/* returns the size of a block source */ /* Returns the size of a block source. */
uint64_t (*size)(void *source); uint64_t (*size)(void *source);


/* /*
* Reads a segment from the block source. It is an error to read beyond * Reads a segment from the block source. It is an error to read beyond
* the end of the block. * the end of the block.
*/ */
ssize_t (*read_block)(void *source, struct reftable_block *dest, ssize_t (*read_data)(void *source, struct reftable_block_data *dest,
uint64_t off, uint32_t size); uint64_t off, uint32_t size);


/* mark the block as read; may return the data back to malloc */ /* Mark the block as read; may release the data. */
void (*return_block)(void *source, struct reftable_block *blockp); void (*release_data)(void *source, struct reftable_block_data *data);


/* release all resources associated with the block source */ /* Release all resources associated with the block source. */
void (*close)(void *source); void (*close)(void *source);
}; };



View File

@ -0,0 +1,18 @@
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file or at
* https://developers.google.com/open-source/licenses/bsd
*/

#ifndef REFTABLE_CONSTANTS_H
#define REFTABLE_CONSTANTS_H

#define REFTABLE_BLOCK_TYPE_LOG 'g'
#define REFTABLE_BLOCK_TYPE_INDEX 'i'
#define REFTABLE_BLOCK_TYPE_REF 'r'
#define REFTABLE_BLOCK_TYPE_OBJ 'o'
#define REFTABLE_BLOCK_TYPE_ANY 0

#endif /* REFTABLE_CONSTANTS_H */

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef REFTABLE_ERROR_H #ifndef REFTABLE_ERROR_H

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef REFTABLE_ITERATOR_H #ifndef REFTABLE_ITERATOR_H

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef REFTABLE_MERGED_H #ifndef REFTABLE_MERGED_H
@ -26,14 +26,14 @@ https://developers.google.com/open-source/licenses/bsd
/* A merged table is implements seeking/iterating over a stack of tables. */ /* A merged table is implements seeking/iterating over a stack of tables. */
struct reftable_merged_table; struct reftable_merged_table;


struct reftable_reader; struct reftable_table;


/* /*
* reftable_merged_table_new creates a new merged table. The readers must be * reftable_merged_table_new creates a new merged table. The tables must be
* kept alive as long as the merged table is still in use. * kept alive as long as the merged table is still in use.
*/ */
int reftable_merged_table_new(struct reftable_merged_table **dest, int reftable_merged_table_new(struct reftable_merged_table **dest,
struct reftable_reader **readers, size_t n, struct reftable_table **tables, size_t n,
enum reftable_hash hash_id); enum reftable_hash hash_id);


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

View File

@ -1,72 +0,0 @@
/*
Copyright 2020 Google LLC

Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd
*/

#ifndef REFTABLE_READER_H
#define REFTABLE_READER_H

#include "reftable-iterator.h"
#include "reftable-blocksource.h"

/*
* Reading single tables
*
* The follow routines are for reading single files. For an
* application-level interface, skip ahead to struct
* reftable_merged_table and struct reftable_stack.
*/

/* The reader struct is a handle to an open reftable file. */
struct reftable_reader;

/* reftable_reader_new opens a reftable for reading. If successful,
* returns 0 code and sets pp. The name is used for creating a
* stack. Typically, it is the basename of the file. The block source
* `src` is owned by the reader, and is closed on calling
* reftable_reader_destroy(). On error, the block source `src` is
* closed as well.
*/
int reftable_reader_new(struct reftable_reader **pp,
struct reftable_block_source *src, const char *name);

/*
* Manage the reference count of the reftable reader. A newly initialized
* reader starts with a refcount of 1 and will be deleted once the refcount has
* reached 0.
*
* This is required because readers may have longer lifetimes than the stack
* they belong to. The stack may for example be reloaded while the old tables
* are still being accessed by an iterator.
*/
void reftable_reader_incref(struct reftable_reader *reader);
void reftable_reader_decref(struct reftable_reader *reader);

/* Initialize a reftable iterator for reading refs. */
int reftable_reader_init_ref_iterator(struct reftable_reader *r,
struct reftable_iterator *it);

/* Initialize a reftable iterator for reading logs. */
int reftable_reader_init_log_iterator(struct reftable_reader *r,
struct reftable_iterator *it);

/* returns the hash ID used in this table. */
enum reftable_hash reftable_reader_hash_id(struct reftable_reader *r);

/* return an iterator for the refs pointing to `oid`. */
int reftable_reader_refs_for(struct reftable_reader *r,
struct reftable_iterator *it, uint8_t *oid);

/* return the max_update_index for a table */
uint64_t reftable_reader_max_update_index(struct reftable_reader *r);

/* return the min_update_index for a table */
uint64_t reftable_reader_min_update_index(struct reftable_reader *r);

/* print blocks onto stdout for debugging. */
int reftable_reader_print_blocks(const char *tablename);

#endif

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef REFTABLE_RECORD_H #ifndef REFTABLE_RECORD_H

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef REFTABLE_STACK_H #ifndef REFTABLE_STACK_H

115
reftable/reftable-table.h Normal file
View File

@ -0,0 +1,115 @@
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file or at
* https://developers.google.com/open-source/licenses/bsd
*/

#ifndef REFTABLE_TABLE_H
#define REFTABLE_TABLE_H

#include "reftable-iterator.h"
#include "reftable-block.h"
#include "reftable-blocksource.h"

/*
* Reading single tables
*
* The follow routines are for reading single files. For an
* application-level interface, skip ahead to struct
* reftable_merged_table and struct reftable_stack.
*/

/* Metadata for a block type. */
struct reftable_table_offsets {
int is_present;
uint64_t offset;
uint64_t index_offset;
};

/* The table struct is a handle to an open reftable file. */
struct reftable_table {
/* for convenience, associate a name with the instance. */
char *name;
struct reftable_block_source source;

/* Size of the file, excluding the footer. */
uint64_t size;

/* The hash function used for ref records. */
enum reftable_hash hash_id;

uint32_t block_size;
uint64_t min_update_index;
uint64_t max_update_index;
/* Length of the OID keys in the 'o' section */
int object_id_len;
int version;

struct reftable_table_offsets ref_offsets;
struct reftable_table_offsets obj_offsets;
struct reftable_table_offsets log_offsets;

uint64_t refcount;
};

/* reftable_table_new opens a reftable for reading. If successful,
* returns 0 code and sets pp. The name is used for creating a
* stack. Typically, it is the basename of the file. The block source
* `src` is owned by the table, and is closed on calling
* reftable_table_destroy(). On error, the block source `src` is
* closed as well.
*/
int reftable_table_new(struct reftable_table **out,
struct reftable_block_source *src, const char *name);

/*
* Manage the reference count of the reftable table. A newly initialized
* table starts with a refcount of 1 and will be deleted once the refcount has
* reached 0.
*
* This is required because tables may have longer lifetimes than the stack
* they belong to. The stack may for example be reloaded while the old tables
* are still being accessed by an iterator.
*/
void reftable_table_incref(struct reftable_table *table);
void reftable_table_decref(struct reftable_table *table);

/* Initialize a reftable iterator for reading refs. */
int reftable_table_init_ref_iterator(struct reftable_table *t,
struct reftable_iterator *it);

/* Initialize a reftable iterator for reading logs. */
int reftable_table_init_log_iterator(struct reftable_table *t,
struct reftable_iterator *it);

/* returns the hash ID used in this table. */
enum reftable_hash reftable_table_hash_id(struct reftable_table *t);

/* return an iterator for the refs pointing to `oid`. */
int reftable_table_refs_for(struct reftable_table *t,
struct reftable_iterator *it, uint8_t *oid);

/* return the max_update_index for a table */
uint64_t reftable_table_max_update_index(struct reftable_table *t);

/* return the min_update_index for a table */
uint64_t reftable_table_min_update_index(struct reftable_table *t);

/*
* An iterator that iterates through the blocks contained in a given table.
*/
struct reftable_table_iterator {
void *iter_arg;
};

int reftable_table_iterator_init(struct reftable_table_iterator *it,
struct reftable_table *t);

void reftable_table_iterator_release(struct reftable_table_iterator *it);

int reftable_table_iterator_next(struct reftable_table_iterator *it,
const struct reftable_block **out);

#endif

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef REFTABLE_WRITER_H #ifndef REFTABLE_WRITER_H

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#include "stack.h" #include "stack.h"
@ -11,10 +11,10 @@ https://developers.google.com/open-source/licenses/bsd
#include "system.h" #include "system.h"
#include "constants.h" #include "constants.h"
#include "merged.h" #include "merged.h"
#include "reader.h"
#include "reftable-error.h" #include "reftable-error.h"
#include "reftable-record.h" #include "reftable-record.h"
#include "reftable-merged.h" #include "reftable-merged.h"
#include "table.h"
#include "writer.h" #include "writer.h"


static int stack_try_add(struct reftable_stack *st, static int stack_try_add(struct reftable_stack *st,
@ -203,14 +203,14 @@ int reftable_stack_init_ref_iterator(struct reftable_stack *st,
struct reftable_iterator *it) struct reftable_iterator *it)
{ {
return merged_table_init_iter(reftable_stack_merged_table(st), return merged_table_init_iter(reftable_stack_merged_table(st),
it, BLOCK_TYPE_REF); it, REFTABLE_BLOCK_TYPE_REF);
} }


int reftable_stack_init_log_iterator(struct reftable_stack *st, int reftable_stack_init_log_iterator(struct reftable_stack *st,
struct reftable_iterator *it) struct reftable_iterator *it)
{ {
return merged_table_init_iter(reftable_stack_merged_table(st), return merged_table_init_iter(reftable_stack_merged_table(st),
it, BLOCK_TYPE_LOG); it, REFTABLE_BLOCK_TYPE_LOG);
} }


struct reftable_merged_table * struct reftable_merged_table *
@ -248,11 +248,11 @@ void reftable_stack_destroy(struct reftable_stack *st)
REFTABLE_FREE_AND_NULL(names); REFTABLE_FREE_AND_NULL(names);
} }


if (st->readers) { if (st->tables) {
struct reftable_buf filename = REFTABLE_BUF_INIT; struct reftable_buf filename = REFTABLE_BUF_INIT;


for (size_t i = 0; i < st->readers_len; i++) { for (size_t i = 0; i < st->tables_len; i++) {
const char *name = reader_name(st->readers[i]); const char *name = reftable_table_name(st->tables[i]);
int try_unlinking = 1; int try_unlinking = 1;


reftable_buf_reset(&filename); reftable_buf_reset(&filename);
@ -260,7 +260,7 @@ void reftable_stack_destroy(struct reftable_stack *st)
if (stack_filename(&filename, st, name) < 0) if (stack_filename(&filename, st, name) < 0)
try_unlinking = 0; try_unlinking = 0;
} }
reftable_reader_decref(st->readers[i]); reftable_table_decref(st->tables[i]);


if (try_unlinking && filename.len) { if (try_unlinking && filename.len) {
/* On Windows, can only unlink after closing. */ /* On Windows, can only unlink after closing. */
@ -269,8 +269,8 @@ void reftable_stack_destroy(struct reftable_stack *st)
} }


reftable_buf_release(&filename); reftable_buf_release(&filename);
st->readers_len = 0; st->tables_len = 0;
REFTABLE_FREE_AND_NULL(st->readers); REFTABLE_FREE_AND_NULL(st->tables);
} }


if (st->list_fd >= 0) { if (st->list_fd >= 0) {
@ -284,14 +284,14 @@ void reftable_stack_destroy(struct reftable_stack *st)
free_names(names); free_names(names);
} }


static struct reftable_reader **stack_copy_readers(struct reftable_stack *st, static struct reftable_table **stack_copy_tables(struct reftable_stack *st,
size_t cur_len) size_t cur_len)
{ {
struct reftable_reader **cur = reftable_calloc(cur_len, sizeof(*cur)); struct reftable_table **cur = reftable_calloc(cur_len, sizeof(*cur));
if (!cur) if (!cur)
return NULL; return NULL;
for (size_t i = 0; i < cur_len; i++) for (size_t i = 0; i < cur_len; i++)
cur[i] = st->readers[i]; cur[i] = st->tables[i];
return cur; return cur;
} }


@ -299,19 +299,19 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
const char **names, const char **names,
int reuse_open) int reuse_open)
{ {
size_t cur_len = !st->merged ? 0 : st->merged->readers_len; size_t cur_len = !st->merged ? 0 : st->merged->tables_len;
struct reftable_reader **cur = NULL; struct reftable_table **cur = NULL;
struct reftable_reader **reused = NULL; struct reftable_table **reused = NULL;
struct reftable_reader **new_readers = NULL; struct reftable_table **new_tables = NULL;
size_t reused_len = 0, reused_alloc = 0, names_len; size_t reused_len = 0, reused_alloc = 0, names_len;
size_t new_readers_len = 0; size_t new_tables_len = 0;
struct reftable_merged_table *new_merged = NULL; struct reftable_merged_table *new_merged = NULL;
struct reftable_buf table_path = REFTABLE_BUF_INIT; struct reftable_buf table_path = REFTABLE_BUF_INIT;
int err = 0; int err = 0;
size_t i; size_t i;


if (cur_len) { if (cur_len) {
cur = stack_copy_readers(st, cur_len); cur = stack_copy_tables(st, cur_len);
if (!cur) { if (!cur) {
err = REFTABLE_OUT_OF_MEMORY_ERROR; err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done; goto done;
@ -321,28 +321,28 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
names_len = names_length(names); names_len = names_length(names);


if (names_len) { if (names_len) {
new_readers = reftable_calloc(names_len, sizeof(*new_readers)); new_tables = reftable_calloc(names_len, sizeof(*new_tables));
if (!new_readers) { if (!new_tables) {
err = REFTABLE_OUT_OF_MEMORY_ERROR; err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done; goto done;
} }
} }


while (*names) { while (*names) {
struct reftable_reader *rd = NULL; struct reftable_table *table = NULL;
const char *name = *names++; const char *name = *names++;


/* this is linear; we assume compaction keeps the number of /* this is linear; we assume compaction keeps the number of
tables under control so this is not quadratic. */ tables under control so this is not quadratic. */
for (i = 0; reuse_open && i < cur_len; i++) { for (i = 0; reuse_open && i < cur_len; i++) {
if (cur[i] && 0 == strcmp(cur[i]->name, name)) { if (cur[i] && 0 == strcmp(cur[i]->name, name)) {
rd = cur[i]; table = cur[i];
cur[i] = NULL; cur[i] = NULL;


/* /*
* When reloading the stack fails, we end up * When reloading the stack fails, we end up
* releasing all new readers. This also * releasing all new tables. This also
* includes the reused readers, even though * includes the reused tables, even though
* they are still in used by the old stack. We * they are still in used by the old stack. We
* thus need to keep them alive here, which we * thus need to keep them alive here, which we
* do by bumping their refcount. * do by bumping their refcount.
@ -354,13 +354,13 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
err = REFTABLE_OUT_OF_MEMORY_ERROR; err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done; goto done;
} }
reused[reused_len++] = rd; reused[reused_len++] = table;
reftable_reader_incref(rd); reftable_table_incref(table);
break; break;
} }
} }


if (!rd) { if (!table) {
struct reftable_block_source src = { NULL }; struct reftable_block_source src = { NULL };


err = stack_filename(&table_path, st, name); err = stack_filename(&table_path, st, name);
@ -372,36 +372,36 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
if (err < 0) if (err < 0)
goto done; goto done;


err = reftable_reader_new(&rd, &src, name); err = reftable_table_new(&table, &src, name);
if (err < 0) if (err < 0)
goto done; goto done;
} }


new_readers[new_readers_len] = rd; new_tables[new_tables_len] = table;
new_readers_len++; new_tables_len++;
} }


/* success! */ /* success! */
err = reftable_merged_table_new(&new_merged, new_readers, err = reftable_merged_table_new(&new_merged, new_tables,
new_readers_len, st->opts.hash_id); new_tables_len, st->opts.hash_id);
if (err < 0) if (err < 0)
goto done; goto done;


/* /*
* Close the old, non-reused readers and proactively try to unlink * Close the old, non-reused tables and proactively try to unlink
* them. This is done for systems like Windows, where the underlying * them. This is done for systems like Windows, where the underlying
* file of such an open reader wouldn't have been possible to be * file of such an open table wouldn't have been possible to be
* unlinked by the compacting process. * unlinked by the compacting process.
*/ */
for (i = 0; i < cur_len; i++) { for (i = 0; i < cur_len; i++) {
if (cur[i]) { if (cur[i]) {
const char *name = reader_name(cur[i]); const char *name = reftable_table_name(cur[i]);


err = stack_filename(&table_path, st, name); err = stack_filename(&table_path, st, name);
if (err < 0) if (err < 0)
goto done; goto done;


reftable_reader_decref(cur[i]); reftable_table_decref(cur[i]);
unlink(table_path.buf); unlink(table_path.buf);
} }
} }
@ -412,25 +412,25 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
new_merged->suppress_deletions = 1; new_merged->suppress_deletions = 1;
st->merged = new_merged; st->merged = new_merged;


if (st->readers) if (st->tables)
reftable_free(st->readers); reftable_free(st->tables);
st->readers = new_readers; st->tables = new_tables;
st->readers_len = new_readers_len; st->tables_len = new_tables_len;
new_readers = NULL; new_tables = NULL;
new_readers_len = 0; new_tables_len = 0;


/* /*
* Decrement the refcount of reused readers again. This only needs to * Decrement the refcount of reused tables again. This only needs to
* happen on the successful case, because on the unsuccessful one we * happen on the successful case, because on the unsuccessful one we
* decrement their refcount via `new_readers`. * decrement their refcount via `new_tables`.
*/ */
for (i = 0; i < reused_len; i++) for (i = 0; i < reused_len; i++)
reftable_reader_decref(reused[i]); reftable_table_decref(reused[i]);


done: done:
for (i = 0; i < new_readers_len; i++) for (i = 0; i < new_tables_len; i++)
reftable_reader_decref(new_readers[i]); reftable_table_decref(new_tables[i]);
reftable_free(new_readers); reftable_free(new_tables);
reftable_free(reused); reftable_free(reused);
reftable_free(cur); reftable_free(cur);
reftable_buf_release(&table_path); reftable_buf_release(&table_path);
@ -615,10 +615,10 @@ static int stack_uptodate(struct reftable_stack *st)
/* /*
* It's fine for "tables.list" to not exist. In that * It's fine for "tables.list" to not exist. In that
* case, we have to refresh when the loaded stack has * case, we have to refresh when the loaded stack has
* any readers. * any tables.
*/ */
if (errno == ENOENT) if (errno == ENOENT)
return !!st->readers_len; return !!st->tables_len;
return REFTABLE_IO_ERROR; return REFTABLE_IO_ERROR;
} }


@ -637,19 +637,19 @@ static int stack_uptodate(struct reftable_stack *st)
if (err < 0) if (err < 0)
return err; return err;


for (size_t i = 0; i < st->readers_len; i++) { for (size_t i = 0; i < st->tables_len; i++) {
if (!names[i]) { if (!names[i]) {
err = 1; err = 1;
goto done; goto done;
} }


if (strcmp(st->readers[i]->name, names[i])) { if (strcmp(st->tables[i]->name, names[i])) {
err = 1; err = 1;
goto done; goto done;
} }
} }


if (names[st->merged->readers_len]) { if (names[st->merged->tables_len]) {
err = 1; err = 1;
goto done; goto done;
} }
@ -792,8 +792,8 @@ int reftable_addition_commit(struct reftable_addition *add)
if (add->new_tables_len == 0) if (add->new_tables_len == 0)
goto done; goto done;


for (i = 0; i < add->stack->merged->readers_len; i++) { for (i = 0; i < add->stack->merged->tables_len; i++) {
if ((err = reftable_buf_addstr(&table_list, add->stack->readers[i]->name)) < 0 || if ((err = reftable_buf_addstr(&table_list, add->stack->tables[i]->name)) < 0 ||
(err = reftable_buf_addstr(&table_list, "\n")) < 0) (err = reftable_buf_addstr(&table_list, "\n")) < 0)
goto done; goto done;
} }
@ -1000,9 +1000,9 @@ done:


uint64_t reftable_stack_next_update_index(struct reftable_stack *st) uint64_t reftable_stack_next_update_index(struct reftable_stack *st)
{ {
int sz = st->merged->readers_len; int sz = st->merged->tables_len;
if (sz > 0) if (sz > 0)
return reftable_reader_max_update_index(st->readers[sz - 1]) + return reftable_table_max_update_index(st->tables[sz - 1]) +
1; 1;
return 1; return 1;
} }
@ -1021,8 +1021,8 @@ static int stack_compact_locked(struct reftable_stack *st,
struct reftable_tmpfile tab_file = REFTABLE_TMPFILE_INIT; struct reftable_tmpfile tab_file = REFTABLE_TMPFILE_INIT;
int err = 0; int err = 0;


err = format_name(&next_name, reftable_reader_min_update_index(st->readers[first]), err = format_name(&next_name, reftable_table_min_update_index(st->tables[first]),
reftable_reader_max_update_index(st->readers[last])); reftable_table_max_update_index(st->tables[last]));
if (err < 0) if (err < 0)
goto done; goto done;


@ -1087,18 +1087,18 @@ static int stack_write_compact(struct reftable_stack *st,
int err = 0; int err = 0;


for (size_t i = first; i <= last; i++) for (size_t i = first; i <= last; i++)
st->stats.bytes += st->readers[i]->size; st->stats.bytes += st->tables[i]->size;
err = reftable_writer_set_limits(wr, st->readers[first]->min_update_index, err = reftable_writer_set_limits(wr, st->tables[first]->min_update_index,
st->readers[last]->max_update_index); st->tables[last]->max_update_index);
if (err < 0) if (err < 0)
goto done; goto done;


err = reftable_merged_table_new(&mt, st->readers + first, subtabs_len, err = reftable_merged_table_new(&mt, st->tables + first, subtabs_len,
st->opts.hash_id); st->opts.hash_id);
if (err < 0) if (err < 0)
goto done; goto done;


err = merged_table_init_iter(mt, &it, BLOCK_TYPE_REF); err = merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_REF);
if (err < 0) if (err < 0)
goto done; goto done;


@ -1126,7 +1126,7 @@ static int stack_write_compact(struct reftable_stack *st,
} }
reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);


err = merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG); err = merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_LOG);
if (err < 0) if (err < 0)
goto done; goto done;


@ -1250,7 +1250,7 @@ static int stack_compact_range(struct reftable_stack *st,
table_locks[i] = REFTABLE_FLOCK_INIT; table_locks[i] = REFTABLE_FLOCK_INIT;


for (i = last + 1; i > first; i--) { for (i = last + 1; i > first; i--) {
err = stack_filename(&table_name, st, reader_name(st->readers[i - 1])); err = stack_filename(&table_name, st, reftable_table_name(st->tables[i - 1]));
if (err < 0) if (err < 0)
goto done; goto done;


@ -1376,7 +1376,7 @@ static int stack_compact_range(struct reftable_stack *st,
* compacted in the updated "tables.list" file. * compacted in the updated "tables.list" file.
*/ */
for (size_t i = 0; names[i]; i++) { for (size_t i = 0; names[i]; i++) {
if (strcmp(names[i], st->readers[first]->name)) if (strcmp(names[i], st->tables[first]->name))
continue; continue;


/* /*
@ -1386,8 +1386,8 @@ static int stack_compact_range(struct reftable_stack *st,
* have compacted them. * have compacted them.
*/ */
for (size_t j = 1; j < last - first + 1; j++) { for (size_t j = 1; j < last - first + 1; j++) {
const char *old = first + j < st->merged->readers_len ? const char *old = first + j < st->merged->tables_len ?
st->readers[first + j]->name : NULL; st->tables[first + j]->name : NULL;
const char *new = names[i + j]; const char *new = names[i + j];


/* /*
@ -1427,16 +1427,16 @@ static int stack_compact_range(struct reftable_stack *st,
* `fd_read_lines()` uses a `NULL` sentinel to indicate that * `fd_read_lines()` uses a `NULL` sentinel to indicate that
* the array is at its end. As we use `free_names()` to free * the array is at its end. As we use `free_names()` to free
* the array, we need to include this sentinel value here and * the array, we need to include this sentinel value here and
* thus have to allocate `readers_len + 1` many entries. * thus have to allocate `tables_len + 1` many entries.
*/ */
REFTABLE_CALLOC_ARRAY(names, st->merged->readers_len + 1); REFTABLE_CALLOC_ARRAY(names, st->merged->tables_len + 1);
if (!names) { if (!names) {
err = REFTABLE_OUT_OF_MEMORY_ERROR; err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done; goto done;
} }


for (size_t i = 0; i < st->merged->readers_len; i++) { for (size_t i = 0; i < st->merged->tables_len; i++) {
names[i] = reftable_strdup(st->readers[i]->name); names[i] = reftable_strdup(st->tables[i]->name);
if (!names[i]) { if (!names[i]) {
err = REFTABLE_OUT_OF_MEMORY_ERROR; err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done; goto done;
@ -1451,8 +1451,8 @@ static int stack_compact_range(struct reftable_stack *st,
* it into place now. * it into place now.
*/ */
if (!is_empty_table) { if (!is_empty_table) {
err = format_name(&new_table_name, st->readers[first]->min_update_index, err = format_name(&new_table_name, st->tables[first]->min_update_index,
st->readers[last]->max_update_index); st->tables[last]->max_update_index);
if (err < 0) if (err < 0)
goto done; goto done;


@ -1559,7 +1559,7 @@ done:
int reftable_stack_compact_all(struct reftable_stack *st, int reftable_stack_compact_all(struct reftable_stack *st,
struct reftable_log_expiry_config *config) struct reftable_log_expiry_config *config)
{ {
size_t last = st->merged->readers_len ? st->merged->readers_len - 1 : 0; size_t last = st->merged->tables_len ? st->merged->tables_len - 1 : 0;
return stack_compact_range(st, 0, last, config, 0); return stack_compact_range(st, 0, last, config, 0);
} }


@ -1650,12 +1650,12 @@ static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack *st)
int overhead = header_size(version) - 1; int overhead = header_size(version) - 1;
uint64_t *sizes; uint64_t *sizes;


REFTABLE_CALLOC_ARRAY(sizes, st->merged->readers_len); REFTABLE_CALLOC_ARRAY(sizes, st->merged->tables_len);
if (!sizes) if (!sizes)
return NULL; return NULL;


for (size_t i = 0; i < st->merged->readers_len; i++) for (size_t i = 0; i < st->merged->tables_len; i++)
sizes[i] = st->readers[i]->size - overhead; sizes[i] = st->tables[i]->size - overhead;


return sizes; return sizes;
} }
@ -1665,14 +1665,14 @@ int reftable_stack_auto_compact(struct reftable_stack *st)
struct segment seg; struct segment seg;
uint64_t *sizes; uint64_t *sizes;


if (st->merged->readers_len < 2) if (st->merged->tables_len < 2)
return 0; return 0;


sizes = stack_table_sizes_for_compaction(st); sizes = stack_table_sizes_for_compaction(st);
if (!sizes) if (!sizes)
return REFTABLE_OUT_OF_MEMORY_ERROR; return REFTABLE_OUT_OF_MEMORY_ERROR;


seg = suggest_compaction_segment(sizes, st->merged->readers_len, seg = suggest_compaction_segment(sizes, st->merged->tables_len,
st->opts.auto_compaction_factor); st->opts.auto_compaction_factor);
reftable_free(sizes); reftable_free(sizes);


@ -1763,7 +1763,7 @@ static void remove_maybe_stale_table(struct reftable_stack *st, uint64_t max,
int err = 0; int err = 0;
uint64_t update_idx = 0; uint64_t update_idx = 0;
struct reftable_block_source src = { NULL }; struct reftable_block_source src = { NULL };
struct reftable_reader *rd = NULL; struct reftable_table *table = NULL;
struct reftable_buf table_path = REFTABLE_BUF_INIT; struct reftable_buf table_path = REFTABLE_BUF_INIT;


err = stack_filename(&table_path, st, name); err = stack_filename(&table_path, st, name);
@ -1774,12 +1774,12 @@ static void remove_maybe_stale_table(struct reftable_stack *st, uint64_t max,
if (err < 0) if (err < 0)
goto done; goto done;


err = reftable_reader_new(&rd, &src, name); err = reftable_table_new(&table, &src, name);
if (err < 0) if (err < 0)
goto done; goto done;


update_idx = reftable_reader_max_update_index(rd); update_idx = reftable_table_max_update_index(table);
reftable_reader_decref(rd); reftable_table_decref(table);


if (update_idx <= max) { if (update_idx <= max) {
unlink(table_path.buf); unlink(table_path.buf);
@ -1803,8 +1803,8 @@ static int reftable_stack_clean_locked(struct reftable_stack *st)
if (!is_table_name(d->d_name)) if (!is_table_name(d->d_name))
continue; continue;


for (size_t i = 0; !found && i < st->readers_len; i++) for (size_t i = 0; !found && i < st->tables_len; i++)
found = !strcmp(reader_name(st->readers[i]), d->d_name); found = !strcmp(reftable_table_name(st->tables[i]), d->d_name);
if (found) if (found)
continue; continue;



View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef STACK_H #ifndef STACK_H
@ -22,8 +22,8 @@ struct reftable_stack {


struct reftable_write_options opts; struct reftable_write_options opts;


struct reftable_reader **readers; struct reftable_table **tables;
size_t readers_len; size_t tables_len;
struct reftable_merged_table *merged; struct reftable_merged_table *merged;
struct reftable_compaction_stats stats; struct reftable_compaction_stats stats;
}; };

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef SYSTEM_H #ifndef SYSTEM_H

View File

@ -1,86 +1,46 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#include "reader.h" #include "table.h"


#include "system.h" #include "system.h"
#include "block.h" #include "block.h"
#include "blocksource.h"
#include "constants.h" #include "constants.h"
#include "iter.h" #include "iter.h"
#include "record.h" #include "record.h"
#include "reftable-error.h" #include "reftable-error.h"


uint64_t block_source_size(struct reftable_block_source *source) static struct reftable_table_offsets *
{ table_offsets_for(struct reftable_table *t, uint8_t typ)
return source->ops->size(source->arg);
}

ssize_t block_source_read_block(struct reftable_block_source *source,
struct reftable_block *dest, uint64_t off,
uint32_t size)
{
ssize_t result = source->ops->read_block(source->arg, dest, off, size);
dest->source = *source;
return result;
}

void block_source_close(struct reftable_block_source *source)
{
if (!source->ops) {
return;
}

source->ops->close(source->arg);
source->ops = NULL;
}

static struct reftable_reader_offsets *
reader_offsets_for(struct reftable_reader *r, uint8_t typ)
{ {
switch (typ) { switch (typ) {
case BLOCK_TYPE_REF: case REFTABLE_BLOCK_TYPE_REF:
return &r->ref_offsets; return &t->ref_offsets;
case BLOCK_TYPE_LOG: case REFTABLE_BLOCK_TYPE_LOG:
return &r->log_offsets; return &t->log_offsets;
case BLOCK_TYPE_OBJ: case REFTABLE_BLOCK_TYPE_OBJ:
return &r->obj_offsets; return &t->obj_offsets;
} }
abort(); abort();
} }


static int reader_get_block(struct reftable_reader *r, enum reftable_hash reftable_table_hash_id(struct reftable_table *t)
struct reftable_block *dest, uint64_t off,
uint32_t sz)
{ {
ssize_t bytes_read; return t->hash_id;
if (off >= r->size)
return 0;
if (off + sz > r->size)
sz = r->size - off;

bytes_read = block_source_read_block(&r->source, dest, off, sz);
if (bytes_read < 0)
return (int)bytes_read;

return 0;
} }


enum reftable_hash reftable_reader_hash_id(struct reftable_reader *r) const char *reftable_table_name(struct reftable_table *t)
{ {
return r->hash_id; return t->name;
} }


const char *reader_name(struct reftable_reader *r) static int parse_footer(struct reftable_table *t, uint8_t *footer,
{
return r->name;
}

static int parse_footer(struct reftable_reader *r, uint8_t *footer,
uint8_t *header) uint8_t *header)
{ {
uint8_t *f = footer; uint8_t *f = footer;
@ -95,29 +55,29 @@ static int parse_footer(struct reftable_reader *r, uint8_t *footer,
} }
f += 4; f += 4;


if (memcmp(footer, header, header_size(r->version))) { if (memcmp(footer, header, header_size(t->version))) {
err = REFTABLE_FORMAT_ERROR; err = REFTABLE_FORMAT_ERROR;
goto done; goto done;
} }


f++; f++;
r->block_size = reftable_get_be24(f); t->block_size = reftable_get_be24(f);


f += 3; f += 3;
r->min_update_index = reftable_get_be64(f); t->min_update_index = reftable_get_be64(f);
f += 8; f += 8;
r->max_update_index = reftable_get_be64(f); t->max_update_index = reftable_get_be64(f);
f += 8; f += 8;


if (r->version == 1) { if (t->version == 1) {
r->hash_id = REFTABLE_HASH_SHA1; t->hash_id = REFTABLE_HASH_SHA1;
} else { } else {
switch (reftable_get_be32(f)) { switch (reftable_get_be32(f)) {
case REFTABLE_FORMAT_ID_SHA1: case REFTABLE_FORMAT_ID_SHA1:
r->hash_id = REFTABLE_HASH_SHA1; t->hash_id = REFTABLE_HASH_SHA1;
break; break;
case REFTABLE_FORMAT_ID_SHA256: case REFTABLE_FORMAT_ID_SHA256:
r->hash_id = REFTABLE_HASH_SHA256; t->hash_id = REFTABLE_HASH_SHA256;
break; break;
default: default:
err = REFTABLE_FORMAT_ERROR; err = REFTABLE_FORMAT_ERROR;
@ -127,20 +87,20 @@ static int parse_footer(struct reftable_reader *r, uint8_t *footer,
f += 4; f += 4;
} }


r->ref_offsets.index_offset = reftable_get_be64(f); t->ref_offsets.index_offset = reftable_get_be64(f);
f += 8; f += 8;


r->obj_offsets.offset = reftable_get_be64(f); t->obj_offsets.offset = reftable_get_be64(f);
f += 8; f += 8;


r->object_id_len = r->obj_offsets.offset & ((1 << 5) - 1); t->object_id_len = t->obj_offsets.offset & ((1 << 5) - 1);
r->obj_offsets.offset >>= 5; t->obj_offsets.offset >>= 5;


r->obj_offsets.index_offset = reftable_get_be64(f); t->obj_offsets.index_offset = reftable_get_be64(f);
f += 8; f += 8;
r->log_offsets.offset = reftable_get_be64(f); t->log_offsets.offset = reftable_get_be64(f);
f += 8; f += 8;
r->log_offsets.index_offset = reftable_get_be64(f); t->log_offsets.index_offset = reftable_get_be64(f);
f += 8; f += 8;


computed_crc = crc32(0, footer, f - footer); computed_crc = crc32(0, footer, f - footer);
@ -151,13 +111,13 @@ static int parse_footer(struct reftable_reader *r, uint8_t *footer,
goto done; goto done;
} }


first_block_typ = header[header_size(r->version)]; first_block_typ = header[header_size(t->version)];
r->ref_offsets.is_present = (first_block_typ == BLOCK_TYPE_REF); t->ref_offsets.is_present = (first_block_typ == REFTABLE_BLOCK_TYPE_REF);
r->ref_offsets.offset = 0; t->ref_offsets.offset = 0;
r->log_offsets.is_present = (first_block_typ == BLOCK_TYPE_LOG || t->log_offsets.is_present = (first_block_typ == REFTABLE_BLOCK_TYPE_LOG ||
r->log_offsets.offset > 0); t->log_offsets.offset > 0);
r->obj_offsets.is_present = r->obj_offsets.offset > 0; t->obj_offsets.is_present = t->obj_offsets.offset > 0;
if (r->obj_offsets.is_present && !r->object_id_len) { if (t->obj_offsets.is_present && !t->object_id_len) {
err = REFTABLE_FORMAT_ERROR; err = REFTABLE_FORMAT_ERROR;
goto done; goto done;
} }
@ -168,20 +128,20 @@ done:
} }


struct table_iter { struct table_iter {
struct reftable_reader *r; struct reftable_table *table;
uint8_t typ; uint8_t typ;
uint64_t block_off; uint64_t block_off;
struct block_reader br; struct reftable_block block;
struct block_iter bi; struct block_iter bi;
int is_finished; int is_finished;
}; };


static int table_iter_init(struct table_iter *ti, struct reftable_reader *r) static int table_iter_init(struct table_iter *ti, struct reftable_table *t)
{ {
struct block_iter bi = BLOCK_ITER_INIT; struct block_iter bi = BLOCK_ITER_INIT;
memset(ti, 0, sizeof(*ti)); memset(ti, 0, sizeof(*ti));
reftable_reader_incref(r); reftable_table_incref(t);
ti->r = r; ti->table = t;
ti->bi = bi; ti->bi = bi;
return 0; return 0;
} }
@ -190,8 +150,8 @@ static int table_iter_next_in_block(struct table_iter *ti,
struct reftable_record *rec) struct reftable_record *rec)
{ {
int res = block_iter_next(&ti->bi, rec); int res = block_iter_next(&ti->bi, rec);
if (res == 0 && reftable_record_type(rec) == BLOCK_TYPE_REF) { if (res == 0 && reftable_record_type(rec) == REFTABLE_BLOCK_TYPE_REF) {
rec->u.ref.update_index += ti->r->min_update_index; rec->u.ref.update_index += ti->table->min_update_index;
} }


return res; return res;
@ -199,68 +159,32 @@ static int table_iter_next_in_block(struct table_iter *ti,


static void table_iter_block_done(struct table_iter *ti) static void table_iter_block_done(struct table_iter *ti)
{ {
block_reader_release(&ti->br); reftable_block_release(&ti->block);
block_iter_reset(&ti->bi); block_iter_reset(&ti->bi);
} }


static int32_t extract_block_size(uint8_t *data, uint8_t *typ, uint64_t off, int table_init_block(struct reftable_table *t, struct reftable_block *block,
int version)
{
int32_t result = 0;

if (off == 0) {
data += header_size(version);
}

*typ = data[0];
if (reftable_is_block_type(*typ)) {
result = reftable_get_be24(data + 1);
}
return result;
}

int reader_init_block_reader(struct reftable_reader *r, struct block_reader *br,
uint64_t next_off, uint8_t want_typ) uint64_t next_off, uint8_t want_typ)
{ {
int32_t guess_block_size = r->block_size ? r->block_size : uint32_t header_off = next_off ? 0 : header_size(t->version);
DEFAULT_BLOCK_SIZE; int err;
struct reftable_block block = { NULL };
uint8_t block_typ = 0;
int err = 0;
uint32_t header_off = next_off ? 0 : header_size(r->version);
int32_t block_size = 0;


if (next_off >= r->size) if (next_off >= t->size)
return 1; return 1;


err = reader_get_block(r, &block, next_off, guess_block_size); err = reftable_block_init(block, &t->source, next_off, header_off,
t->block_size, hash_size(t->hash_id));
if (err < 0) if (err < 0)
goto done; goto done;


block_size = extract_block_size(block.data, &block_typ, next_off, if (want_typ != REFTABLE_BLOCK_TYPE_ANY && block->block_type != want_typ) {
r->version);
if (block_size < 0) {
err = block_size;
goto done;
}
if (want_typ != BLOCK_TYPE_ANY && block_typ != want_typ) {
err = 1; err = 1;
goto done; goto done;
} }


if (block_size > guess_block_size) {
reftable_block_done(&block);
err = reader_get_block(r, &block, next_off, block_size);
if (err < 0) {
goto done;
}
}

err = block_reader_init(br, &block, header_off, r->block_size,
hash_size(r->hash_id));
done: done:
reftable_block_done(&block); if (err)

reftable_block_release(block);
return err; return err;
} }


@ -268,15 +192,15 @@ static void table_iter_close(struct table_iter *ti)
{ {
table_iter_block_done(ti); table_iter_block_done(ti);
block_iter_close(&ti->bi); block_iter_close(&ti->bi);
reftable_reader_decref(ti->r); reftable_table_decref(ti->table);
} }


static int table_iter_next_block(struct table_iter *ti) static int table_iter_next_block(struct table_iter *ti)
{ {
uint64_t next_block_off = ti->block_off + ti->br.full_block_size; uint64_t next_block_off = ti->block_off + ti->block.full_block_size;
int err; int err;


err = reader_init_block_reader(ti->r, &ti->br, next_block_off, ti->typ); err = table_init_block(ti->table, &ti->block, next_block_off, ti->typ);
if (err > 0) if (err > 0)
ti->is_finished = 1; ti->is_finished = 1;
if (err) if (err)
@ -284,7 +208,7 @@ static int table_iter_next_block(struct table_iter *ti)


ti->block_off = next_block_off; ti->block_off = next_block_off;
ti->is_finished = 0; ti->is_finished = 0;
block_iter_seek_start(&ti->bi, &ti->br); block_iter_init(&ti->bi, &ti->block);


return 0; return 0;
} }
@ -326,27 +250,27 @@ static int table_iter_seek_to(struct table_iter *ti, uint64_t off, uint8_t typ)
{ {
int err; int err;


err = reader_init_block_reader(ti->r, &ti->br, off, typ); err = table_init_block(ti->table, &ti->block, off, typ);
if (err != 0) if (err != 0)
return err; return err;


ti->typ = block_reader_type(&ti->br); ti->typ = reftable_block_type(&ti->block);
ti->block_off = off; ti->block_off = off;
block_iter_seek_start(&ti->bi, &ti->br); block_iter_init(&ti->bi, &ti->block);
ti->is_finished = 0; ti->is_finished = 0;
return 0; return 0;
} }


static int table_iter_seek_start(struct table_iter *ti, uint8_t typ, int index) static int table_iter_seek_start(struct table_iter *ti, uint8_t typ, int index)
{ {
struct reftable_reader_offsets *offs = reader_offsets_for(ti->r, typ); struct reftable_table_offsets *offs = table_offsets_for(ti->table, typ);
uint64_t off = offs->offset; uint64_t off = offs->offset;
if (index) { if (index) {
off = offs->index_offset; off = offs->index_offset;
if (off == 0) { if (off == 0) {
return 1; return 1;
} }
typ = BLOCK_TYPE_INDEX; typ = REFTABLE_BLOCK_TYPE_INDEX;
} }


return table_iter_seek_to(ti, off, typ); return table_iter_seek_to(ti, off, typ);
@ -396,10 +320,10 @@ static int table_iter_seek_linear(struct table_iter *ti,
* as we have more than three blocks we would have an index, so * as we have more than three blocks we would have an index, so
* we would not do a linear search there anymore. * we would not do a linear search there anymore.
*/ */
memset(&next.br.block, 0, sizeof(next.br.block)); memset(&next.block.block_data, 0, sizeof(next.block.block_data));
next.br.zstream = NULL; next.block.zstream = NULL;
next.br.uncompressed_data = NULL; next.block.uncompressed_data = NULL;
next.br.uncompressed_cap = 0; next.block.uncompressed_cap = 0;


err = table_iter_next_block(&next); err = table_iter_next_block(&next);
if (err < 0) if (err < 0)
@ -407,7 +331,7 @@ static int table_iter_seek_linear(struct table_iter *ti,
if (err > 0) if (err > 0)
break; break;


err = block_reader_first_key(&next.br, &got_key); err = reftable_block_first_key(&next.block, &got_key);
if (err < 0) if (err < 0)
goto done; goto done;


@ -425,7 +349,8 @@ static int table_iter_seek_linear(struct table_iter *ti,
* the wanted key inside of it. If the block does not contain our key * the wanted key inside of it. If the block does not contain our key
* we know that the corresponding record does not exist. * we know that the corresponding record does not exist.
*/ */
err = block_iter_seek_key(&ti->bi, &ti->br, &want_key); block_iter_init(&ti->bi, &ti->block);
err = block_iter_seek_key(&ti->bi, &want_key);
if (err < 0) if (err < 0)
goto done; goto done;
err = 0; err = 0;
@ -441,10 +366,10 @@ static int table_iter_seek_indexed(struct table_iter *ti,
struct reftable_record *rec) struct reftable_record *rec)
{ {
struct reftable_record want_index = { struct reftable_record want_index = {
.type = BLOCK_TYPE_INDEX, .u.idx = { .last_key = REFTABLE_BUF_INIT } .type = REFTABLE_BLOCK_TYPE_INDEX, .u.idx = { .last_key = REFTABLE_BUF_INIT }
}; };
struct reftable_record index_result = { struct reftable_record index_result = {
.type = BLOCK_TYPE_INDEX, .type = REFTABLE_BLOCK_TYPE_INDEX,
.u.idx = { .last_key = REFTABLE_BUF_INIT }, .u.idx = { .last_key = REFTABLE_BUF_INIT },
}; };
int err; int err;
@ -493,7 +418,9 @@ static int table_iter_seek_indexed(struct table_iter *ti,
if (err != 0) if (err != 0)
goto done; goto done;


err = block_iter_seek_key(&ti->bi, &ti->br, &want_index.u.idx.last_key); block_iter_init(&ti->bi, &ti->block);

err = block_iter_seek_key(&ti->bi, &want_index.u.idx.last_key);
if (err < 0) if (err < 0)
goto done; goto done;


@ -502,7 +429,7 @@ static int table_iter_seek_indexed(struct table_iter *ti,
break; break;
} }


if (ti->typ != BLOCK_TYPE_INDEX) { if (ti->typ != REFTABLE_BLOCK_TYPE_INDEX) {
err = REFTABLE_FORMAT_ERROR; err = REFTABLE_FORMAT_ERROR;
goto done; goto done;
} }
@ -518,7 +445,7 @@ static int table_iter_seek(struct table_iter *ti,
struct reftable_record *want) struct reftable_record *want)
{ {
uint8_t typ = reftable_record_type(want); uint8_t typ = reftable_record_type(want);
struct reftable_reader_offsets *offs = reader_offsets_for(ti->r, typ); struct reftable_table_offsets *offs = table_offsets_for(ti->table, typ);
int err; int err;


err = table_iter_seek_start(ti, reftable_record_type(want), err = table_iter_seek_start(ti, reftable_record_type(want),
@ -566,11 +493,11 @@ static void iterator_from_table_iter(struct reftable_iterator *it,
it->ops = &table_iter_vtable; it->ops = &table_iter_vtable;
} }


int reader_init_iter(struct reftable_reader *r, int table_init_iter(struct reftable_table *t,
struct reftable_iterator *it, struct reftable_iterator *it,
uint8_t typ) uint8_t typ)
{ {
struct reftable_reader_offsets *offs = reader_offsets_for(r, typ); struct reftable_table_offsets *offs = table_offsets_for(t, typ);


if (offs->is_present) { if (offs->is_present) {
struct table_iter *ti; struct table_iter *ti;
@ -578,7 +505,7 @@ int reader_init_iter(struct reftable_reader *r,
if (!ti) if (!ti)
return REFTABLE_OUT_OF_MEMORY_ERROR; return REFTABLE_OUT_OF_MEMORY_ERROR;


table_iter_init(ti, r); table_iter_init(ti, t);
iterator_from_table_iter(it, ti); iterator_from_table_iter(it, ti);
} else { } else {
iterator_set_empty(it); iterator_set_empty(it);
@ -587,31 +514,31 @@ int reader_init_iter(struct reftable_reader *r,
return 0; return 0;
} }


int reftable_reader_init_ref_iterator(struct reftable_reader *r, int reftable_table_init_ref_iterator(struct reftable_table *t,
struct reftable_iterator *it) struct reftable_iterator *it)
{ {
return reader_init_iter(r, it, BLOCK_TYPE_REF); return table_init_iter(t, it, REFTABLE_BLOCK_TYPE_REF);
} }


int reftable_reader_init_log_iterator(struct reftable_reader *r, int reftable_table_init_log_iterator(struct reftable_table *t,
struct reftable_iterator *it) struct reftable_iterator *it)
{ {
return reader_init_iter(r, it, BLOCK_TYPE_LOG); return table_init_iter(t, it, REFTABLE_BLOCK_TYPE_LOG);
} }


int reftable_reader_new(struct reftable_reader **out, int reftable_table_new(struct reftable_table **out,
struct reftable_block_source *source, char const *name) struct reftable_block_source *source, char const *name)
{ {
struct reftable_block footer = { 0 }; struct reftable_block_data footer = { 0 };
struct reftable_block header = { 0 }; struct reftable_block_data header = { 0 };
struct reftable_reader *r; struct reftable_table *t;
uint64_t file_size = block_source_size(source); uint64_t file_size = block_source_size(source);
uint32_t read_size; uint32_t read_size;
ssize_t bytes_read; ssize_t bytes_read;
int err; int err;


REFTABLE_CALLOC_ARRAY(r, 1); REFTABLE_CALLOC_ARRAY(t, 1);
if (!r) { if (!t) {
err = REFTABLE_OUT_OF_MEMORY_ERROR; err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done; goto done;
} }
@ -626,7 +553,7 @@ int reftable_reader_new(struct reftable_reader **out,
goto done; goto done;
} }


bytes_read = block_source_read_block(source, &header, 0, read_size); bytes_read = block_source_read_data(source, &header, 0, read_size);
if (bytes_read < 0 || (size_t)bytes_read != read_size) { if (bytes_read < 0 || (size_t)bytes_read != read_size) {
err = REFTABLE_IO_ERROR; err = REFTABLE_IO_ERROR;
goto done; goto done;
@ -636,84 +563,84 @@ int reftable_reader_new(struct reftable_reader **out,
err = REFTABLE_FORMAT_ERROR; err = REFTABLE_FORMAT_ERROR;
goto done; goto done;
} }
r->version = header.data[4]; t->version = header.data[4];
if (r->version != 1 && r->version != 2) { if (t->version != 1 && t->version != 2) {
err = REFTABLE_FORMAT_ERROR; err = REFTABLE_FORMAT_ERROR;
goto done; goto done;
} }


r->size = file_size - footer_size(r->version); t->size = file_size - footer_size(t->version);
r->source = *source; t->source = *source;
r->name = reftable_strdup(name); t->name = reftable_strdup(name);
if (!r->name) { if (!t->name) {
err = REFTABLE_OUT_OF_MEMORY_ERROR; err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done; goto done;
} }
r->hash_id = 0; t->hash_id = 0;
r->refcount = 1; t->refcount = 1;


bytes_read = block_source_read_block(source, &footer, r->size, bytes_read = block_source_read_data(source, &footer, t->size,
footer_size(r->version)); footer_size(t->version));
if (bytes_read < 0 || (size_t)bytes_read != footer_size(r->version)) { if (bytes_read < 0 || (size_t)bytes_read != footer_size(t->version)) {
err = REFTABLE_IO_ERROR; err = REFTABLE_IO_ERROR;
goto done; goto done;
} }


err = parse_footer(r, footer.data, header.data); err = parse_footer(t, footer.data, header.data);
if (err) if (err)
goto done; goto done;


*out = r; *out = t;


done: done:
reftable_block_done(&footer); block_source_release_data(&footer);
reftable_block_done(&header); block_source_release_data(&header);
if (err) { if (err) {
if (r) if (t)
reftable_free(r->name); reftable_free(t->name);
reftable_free(r); reftable_free(t);
block_source_close(source); block_source_close(source);
} }
return err; return err;
} }


void reftable_reader_incref(struct reftable_reader *r) void reftable_table_incref(struct reftable_table *t)
{ {
r->refcount++; t->refcount++;
} }


void reftable_reader_decref(struct reftable_reader *r) void reftable_table_decref(struct reftable_table *t)
{ {
if (!r) if (!t)
return; return;
if (--r->refcount) if (--t->refcount)
return; return;
block_source_close(&r->source); block_source_close(&t->source);
REFTABLE_FREE_AND_NULL(r->name); REFTABLE_FREE_AND_NULL(t->name);
reftable_free(r); reftable_free(t);
} }


static int reftable_reader_refs_for_indexed(struct reftable_reader *r, static int reftable_table_refs_for_indexed(struct reftable_table *t,
struct reftable_iterator *it, struct reftable_iterator *it,
uint8_t *oid) uint8_t *oid)
{ {
struct reftable_record want = { struct reftable_record want = {
.type = BLOCK_TYPE_OBJ, .type = REFTABLE_BLOCK_TYPE_OBJ,
.u.obj = { .u.obj = {
.hash_prefix = oid, .hash_prefix = oid,
.hash_prefix_len = r->object_id_len, .hash_prefix_len = t->object_id_len,
}, },
}; };
struct reftable_iterator oit = { NULL }; struct reftable_iterator oit = { NULL };
struct reftable_record got = { struct reftable_record got = {
.type = BLOCK_TYPE_OBJ, .type = REFTABLE_BLOCK_TYPE_OBJ,
.u.obj = { 0 }, .u.obj = { 0 },
}; };
int err = 0; int err = 0;
struct indexed_table_ref_iter *itr = NULL; struct indexed_table_ref_iter *itr = NULL;


/* Look through the reverse index. */ /* Look through the reverse index. */
err = reader_init_iter(r, &oit, BLOCK_TYPE_OBJ); err = table_init_iter(t, &oit, REFTABLE_BLOCK_TYPE_OBJ);
if (err < 0) if (err < 0)
goto done; goto done;


@ -727,14 +654,14 @@ static int reftable_reader_refs_for_indexed(struct reftable_reader *r,
goto done; goto done;


if (err > 0 || memcmp(want.u.obj.hash_prefix, got.u.obj.hash_prefix, if (err > 0 || memcmp(want.u.obj.hash_prefix, got.u.obj.hash_prefix,
r->object_id_len)) { t->object_id_len)) {
/* didn't find it; return empty iterator */ /* didn't find it; return empty iterator */
iterator_set_empty(it); iterator_set_empty(it);
err = 0; err = 0;
goto done; goto done;
} }


err = indexed_table_ref_iter_new(&itr, r, oid, hash_size(r->hash_id), err = indexed_table_ref_iter_new(&itr, t, oid, hash_size(t->hash_id),
got.u.obj.offsets, got.u.obj.offsets,
got.u.obj.offset_len); got.u.obj.offset_len);
if (err < 0) if (err < 0)
@ -748,14 +675,14 @@ done:
return err; return err;
} }


static int reftable_reader_refs_for_unindexed(struct reftable_reader *r, static int reftable_table_refs_for_unindexed(struct reftable_table *t,
struct reftable_iterator *it, struct reftable_iterator *it,
uint8_t *oid) uint8_t *oid)
{ {
struct table_iter *ti; struct table_iter *ti;
struct filtering_ref_iterator *filter = NULL; struct filtering_ref_iterator *filter = NULL;
struct filtering_ref_iterator empty = FILTERING_REF_ITERATOR_INIT; struct filtering_ref_iterator empty = FILTERING_REF_ITERATOR_INIT;
uint32_t oid_len = hash_size(r->hash_id); uint32_t oid_len = hash_size(t->hash_id);
int err; int err;


REFTABLE_ALLOC_ARRAY(ti, 1); REFTABLE_ALLOC_ARRAY(ti, 1);
@ -764,8 +691,8 @@ static int reftable_reader_refs_for_unindexed(struct reftable_reader *r,
goto out; goto out;
} }


table_iter_init(ti, r); table_iter_init(ti, t);
err = table_iter_seek_start(ti, BLOCK_TYPE_REF, 0); err = table_iter_seek_start(ti, REFTABLE_BLOCK_TYPE_REF, 0);
if (err < 0) if (err < 0)
goto out; goto out;


@ -795,85 +722,67 @@ out:
return err; return err;
} }


int reftable_reader_refs_for(struct reftable_reader *r, int reftable_table_refs_for(struct reftable_table *t,
struct reftable_iterator *it, uint8_t *oid) struct reftable_iterator *it, uint8_t *oid)
{ {
if (r->obj_offsets.is_present) if (t->obj_offsets.is_present)
return reftable_reader_refs_for_indexed(r, it, oid); return reftable_table_refs_for_indexed(t, it, oid);
return reftable_reader_refs_for_unindexed(r, it, oid); return reftable_table_refs_for_unindexed(t, it, oid);
} }


uint64_t reftable_reader_max_update_index(struct reftable_reader *r) uint64_t reftable_table_max_update_index(struct reftable_table *t)
{ {
return r->max_update_index; return t->max_update_index;
} }


uint64_t reftable_reader_min_update_index(struct reftable_reader *r) uint64_t reftable_table_min_update_index(struct reftable_table *t)
{ {
return r->min_update_index; return t->min_update_index;
} }


int reftable_reader_print_blocks(const char *tablename) int reftable_table_iterator_init(struct reftable_table_iterator *it,
struct reftable_table *t)
{ {
struct { struct table_iter *ti;
const char *name;
int type;
} sections[] = {
{
.name = "ref",
.type = BLOCK_TYPE_REF,
},
{
.name = "obj",
.type = BLOCK_TYPE_OBJ,
},
{
.name = "log",
.type = BLOCK_TYPE_LOG,
},
};
struct reftable_block_source src = { 0 };
struct reftable_reader *r = NULL;
struct table_iter ti = { 0 };
size_t i;
int err; int err;


err = reftable_block_source_from_file(&src, tablename); REFTABLE_ALLOC_ARRAY(ti, 1);
if (!ti)
return REFTABLE_OUT_OF_MEMORY_ERROR;

err = table_iter_init(ti, t);
if (err < 0) if (err < 0)
goto done; goto out;


err = reftable_reader_new(&r, &src, tablename); it->iter_arg = ti;
err = 0;

out:
if (err < 0) if (err < 0)
goto done; reftable_free(ti);

table_iter_init(&ti, r);

printf("header:\n");
printf(" block_size: %d\n", r->block_size);

for (i = 0; i < sizeof(sections) / sizeof(*sections); i++) {
err = table_iter_seek_start(&ti, sections[i].type, 0);
if (err < 0)
goto done;
if (err > 0)
continue;

printf("%s:\n", sections[i].name);

while (1) {
printf(" - length: %u\n", ti.br.block_len);
printf(" restarts: %u\n", ti.br.restart_count);

err = table_iter_next_block(&ti);
if (err < 0)
goto done;
if (err > 0)
break;
}
}

done:
reftable_reader_decref(r);
table_iter_close(&ti);
return err; return err;
} }

void reftable_table_iterator_release(struct reftable_table_iterator *it)
{
if (!it->iter_arg)
return;
table_iter_close(it->iter_arg);
reftable_free(it->iter_arg);
it->iter_arg = NULL;
}

int reftable_table_iterator_next(struct reftable_table_iterator *it,
const struct reftable_block **out)
{
struct table_iter *ti = it->iter_arg;
int err;

err = table_iter_next_block(ti);
if (err)
return err;

*out = &ti->block;

return 0;
}

29
reftable/table.h Normal file
View File

@ -0,0 +1,29 @@
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file or at
* https://developers.google.com/open-source/licenses/bsd
*/

#ifndef TABLE_H
#define TABLE_H

#include "block.h"
#include "record.h"
#include "reftable-iterator.h"
#include "reftable-table.h"

const char *reftable_table_name(struct reftable_table *t);

int table_init_iter(struct reftable_table *t,
struct reftable_iterator *it,
uint8_t typ);

/*
* Initialize a block by reading from the given table and offset.
*/
int table_init_block(struct reftable_table *t, struct reftable_block *block,
uint64_t next_off, uint8_t want_typ);

#endif

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#include "system.h" #include "system.h"

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef TREE_H #ifndef TREE_H

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#include "writer.h" #include "writer.h"
@ -172,7 +172,7 @@ int reftable_writer_new(struct reftable_writer **out,
wp->write_arg = writer_arg; wp->write_arg = writer_arg;
wp->opts = opts; wp->opts = opts;
wp->flush = flush_func; wp->flush = flush_func;
writer_reinit_block_writer(wp, BLOCK_TYPE_REF); writer_reinit_block_writer(wp, REFTABLE_BLOCK_TYPE_REF);


*out = wp; *out = wp;


@ -342,7 +342,7 @@ int reftable_writer_add_ref(struct reftable_writer *w,
struct reftable_ref_record *ref) struct reftable_ref_record *ref)
{ {
struct reftable_record rec = { struct reftable_record rec = {
.type = BLOCK_TYPE_REF, .type = REFTABLE_BLOCK_TYPE_REF,
.u = { .u = {
.ref = *ref .ref = *ref
}, },
@ -406,13 +406,13 @@ static int reftable_writer_add_log_verbatim(struct reftable_writer *w,
struct reftable_log_record *log) struct reftable_log_record *log)
{ {
struct reftable_record rec = { struct reftable_record rec = {
.type = BLOCK_TYPE_LOG, .type = REFTABLE_BLOCK_TYPE_LOG,
.u = { .u = {
.log = *log, .log = *log,
}, },
}; };
if (w->block_writer && if (w->block_writer &&
block_writer_type(w->block_writer) == BLOCK_TYPE_REF) { block_writer_type(w->block_writer) == REFTABLE_BLOCK_TYPE_REF) {
int err = writer_finish_public_section(w); int err = writer_finish_public_section(w);
if (err < 0) if (err < 0)
return err; return err;
@ -532,7 +532,7 @@ static int writer_finish_section(struct reftable_writer *w)


max_level++; max_level++;
index_start = w->next; index_start = w->next;
err = writer_reinit_block_writer(w, BLOCK_TYPE_INDEX); err = writer_reinit_block_writer(w, REFTABLE_BLOCK_TYPE_INDEX);
if (err < 0) if (err < 0)
return err; return err;


@ -544,7 +544,7 @@ static int writer_finish_section(struct reftable_writer *w)
w->index_cap = 0; w->index_cap = 0;
for (i = 0; i < idx_len; i++) { for (i = 0; i < idx_len; i++) {
struct reftable_record rec = { struct reftable_record rec = {
.type = BLOCK_TYPE_INDEX, .type = REFTABLE_BLOCK_TYPE_INDEX,
.u = { .u = {
.idx = idx[i], .idx = idx[i],
}, },
@ -609,7 +609,7 @@ static void write_object_record(void *void_arg, void *key)
struct write_record_arg *arg = void_arg; struct write_record_arg *arg = void_arg;
struct obj_index_tree_node *entry = key; struct obj_index_tree_node *entry = key;
struct reftable_record struct reftable_record
rec = { .type = BLOCK_TYPE_OBJ, rec = { .type = REFTABLE_BLOCK_TYPE_OBJ,
.u.obj = { .u.obj = {
.hash_prefix = (uint8_t *)entry->hash.buf, .hash_prefix = (uint8_t *)entry->hash.buf,
.hash_prefix_len = arg->w->stats.object_id_len, .hash_prefix_len = arg->w->stats.object_id_len,
@ -639,7 +639,7 @@ static void write_object_record(void *void_arg, void *key)
if (arg->err < 0) if (arg->err < 0)
goto done; goto done;


arg->err = writer_reinit_block_writer(arg->w, BLOCK_TYPE_OBJ); arg->err = writer_reinit_block_writer(arg->w, REFTABLE_BLOCK_TYPE_OBJ);
if (arg->err < 0) if (arg->err < 0)
goto done; goto done;


@ -684,7 +684,7 @@ static int writer_dump_object_index(struct reftable_writer *w)
infix_walk(w->obj_index_tree, &update_common, &common); infix_walk(w->obj_index_tree, &update_common, &common);
w->stats.object_id_len = common.max + 1; w->stats.object_id_len = common.max + 1;


err = writer_reinit_block_writer(w, BLOCK_TYPE_OBJ); err = writer_reinit_block_writer(w, REFTABLE_BLOCK_TYPE_OBJ);
if (err < 0) if (err < 0)
return err; return err;


@ -708,7 +708,7 @@ static int writer_finish_public_section(struct reftable_writer *w)
err = writer_finish_section(w); err = writer_finish_section(w);
if (err < 0) if (err < 0)
return err; return err;
if (typ == BLOCK_TYPE_REF && !w->opts.skip_index_objects && if (typ == REFTABLE_BLOCK_TYPE_REF && !w->opts.skip_index_objects &&
w->stats.ref_stats.index_blocks > 0) { w->stats.ref_stats.index_blocks > 0) {
err = writer_dump_object_index(w); err = writer_dump_object_index(w);
if (err < 0) if (err < 0)
@ -813,7 +813,7 @@ static int writer_flush_nonempty_block(struct reftable_writer *w)
* By default, all records except for log records are padded to the * By default, all records except for log records are padded to the
* block size. * block size.
*/ */
if (!w->opts.unpadded && typ != BLOCK_TYPE_LOG) if (!w->opts.unpadded && typ != REFTABLE_BLOCK_TYPE_LOG)
padding = w->opts.block_size - raw_bytes; padding = w->opts.block_size - raw_bytes;


bstats = writer_reftable_block_stats(w, typ); bstats = writer_reftable_block_stats(w, typ);

View File

@ -1,9 +1,9 @@
/* /*
Copyright 2020 Google LLC * Copyright 2020 Google LLC

*
Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd * https://developers.google.com/open-source/licenses/bsd
*/ */


#ifndef WRITER_H #ifndef WRITER_H

View File

@ -2,10 +2,11 @@
#include "hash.h" #include "hash.h"
#include "hex.h" #include "hex.h"
#include "reftable/system.h" #include "reftable/system.h"
#include "reftable/reftable-constants.h"
#include "reftable/reftable-error.h" #include "reftable/reftable-error.h"
#include "reftable/reftable-merged.h" #include "reftable/reftable-merged.h"
#include "reftable/reftable-reader.h"
#include "reftable/reftable-stack.h" #include "reftable/reftable-stack.h"
#include "reftable/reftable-table.h"
#include "test-tool.h" #include "test-tool.h"


static void print_help(void) static void print_help(void)
@ -20,6 +21,72 @@ static void print_help(void)
"\n"); "\n");
} }


static int dump_blocks(const char *tablename)
{
struct reftable_table_iterator ti = { 0 };
struct reftable_block_source src = { 0 };
struct reftable_table *table = NULL;
uint8_t section_type = 0;
int err;

err = reftable_block_source_from_file(&src, tablename);
if (err < 0)
goto done;

err = reftable_table_new(&table, &src, tablename);
if (err < 0)
goto done;

err = reftable_table_iterator_init(&ti, table);
if (err < 0)
goto done;

printf("header:\n");
printf(" block_size: %d\n", table->block_size);

while (1) {
const struct reftable_block *block;

err = reftable_table_iterator_next(&ti, &block);
if (err < 0)
goto done;
if (err > 0)
break;

if (block->block_type != section_type) {
const char *section;
switch (block->block_type) {
case REFTABLE_BLOCK_TYPE_LOG:
section = "log";
break;
case REFTABLE_BLOCK_TYPE_REF:
section = "ref";
break;
case REFTABLE_BLOCK_TYPE_OBJ:
section = "obj";
break;
case REFTABLE_BLOCK_TYPE_INDEX:
section = "idx";
break;
default:
err = -1;
goto done;
}

section_type = block->block_type;
printf("%s:\n", section);
}

printf(" - length: %u\n", block->restart_off);
printf(" restarts: %u\n", block->restart_count);
}

done:
reftable_table_iterator_release(&ti);
reftable_table_decref(table);
return err;
}

static int dump_table(struct reftable_merged_table *mt) static int dump_table(struct reftable_merged_table *mt)
{ {
struct reftable_iterator it = { NULL }; struct reftable_iterator it = { NULL };
@ -126,19 +193,19 @@ static int dump_reftable(const char *tablename)
{ {
struct reftable_block_source src = { 0 }; struct reftable_block_source src = { 0 };
struct reftable_merged_table *mt = NULL; struct reftable_merged_table *mt = NULL;
struct reftable_reader *r = NULL; struct reftable_table *table = NULL;
int err; int err;


err = reftable_block_source_from_file(&src, tablename); err = reftable_block_source_from_file(&src, tablename);
if (err < 0) if (err < 0)
goto done; goto done;


err = reftable_reader_new(&r, &src, tablename); err = reftable_table_new(&table, &src, tablename);
if (err < 0) if (err < 0)
goto done; goto done;


err = reftable_merged_table_new(&mt, &r, 1, err = reftable_merged_table_new(&mt, &table, 1,
reftable_reader_hash_id(r)); reftable_table_hash_id(table));
if (err < 0) if (err < 0)
goto done; goto done;


@ -146,7 +213,7 @@ static int dump_reftable(const char *tablename)


done: done:
reftable_merged_table_free(mt); reftable_merged_table_free(mt);
reftable_reader_decref(r); reftable_table_decref(table);
return err; return err;
} }


@ -184,7 +251,7 @@ int cmd__dump_reftable(int argc, const char **argv)
arg = argv[1]; arg = argv[1];


if (opt_dump_blocks) { if (opt_dump_blocks) {
err = reftable_reader_print_blocks(arg); err = dump_blocks(arg);
} else if (opt_dump_table) { } else if (opt_dump_table) {
err = dump_reftable(arg); err = dump_reftable(arg);
} else if (opt_dump_stack) { } else if (opt_dump_stack) {

View File

@ -58,10 +58,10 @@ unit_test_programs = [
'unit-tests/t-reftable-block.c', 'unit-tests/t-reftable-block.c',
'unit-tests/t-reftable-merged.c', 'unit-tests/t-reftable-merged.c',
'unit-tests/t-reftable-pq.c', 'unit-tests/t-reftable-pq.c',
'unit-tests/t-reftable-reader.c',
'unit-tests/t-reftable-readwrite.c', 'unit-tests/t-reftable-readwrite.c',
'unit-tests/t-reftable-record.c', 'unit-tests/t-reftable-record.c',
'unit-tests/t-reftable-stack.c', 'unit-tests/t-reftable-stack.c',
'unit-tests/t-reftable-table.c',
] ]


foreach unit_test_program : unit_test_programs foreach unit_test_program : unit_test_programs

View File

@ -93,6 +93,9 @@ test_expect_success 'many refs results in multiple blocks' '
restarts: 3 restarts: 3
- length: 3289 - length: 3289
restarts: 3 restarts: 3
idx:
- length: 103
restarts: 1
EOF EOF
test-tool dump-reftable -b .git/reftable/*.ref >actual && test-tool dump-reftable -b .git/reftable/*.ref >actual &&
test_cmp expect actual test_cmp expect actual
@ -241,6 +244,9 @@ test_expect_success 'object index gets written by default with ref index' '
restarts: 1 restarts: 1
- length: 80 - length: 80
restarts: 1 restarts: 1
idx:
- length: 55
restarts: 2
obj: obj:
- length: 11 - length: 11
restarts: 1 restarts: 1
@ -277,6 +283,9 @@ test_expect_success 'object index can be disabled' '
restarts: 1 restarts: 1
- length: 80 - length: 80
restarts: 1 restarts: 1
idx:
- length: 55
restarts: 2
EOF EOF
test-tool dump-reftable -b .git/reftable/*.ref >actual && test-tool dump-reftable -b .git/reftable/*.ref >actual &&
test_cmp expect actual test_cmp expect actual

View File

@ -19,24 +19,25 @@ static void t_ref_block_read_write(void)
struct reftable_record recs[30]; struct reftable_record recs[30];
const size_t N = ARRAY_SIZE(recs); const size_t N = ARRAY_SIZE(recs);
const size_t block_size = 1024; const size_t block_size = 1024;
struct reftable_block block = { 0 }; struct reftable_block_source source = { 0 };
struct block_writer bw = { struct block_writer bw = {
.last_key = REFTABLE_BUF_INIT, .last_key = REFTABLE_BUF_INIT,
}; };
struct reftable_record rec = { struct reftable_record rec = {
.type = BLOCK_TYPE_REF, .type = REFTABLE_BLOCK_TYPE_REF,
}; };
size_t i = 0; size_t i = 0;
int ret; int ret;
struct block_reader br = { 0 }; struct reftable_block block = { 0 };
struct block_iter it = BLOCK_ITER_INIT; struct block_iter it = BLOCK_ITER_INIT;
struct reftable_buf want = REFTABLE_BUF_INIT, buf = REFTABLE_BUF_INIT; struct reftable_buf want = REFTABLE_BUF_INIT;
struct reftable_buf block_data = REFTABLE_BUF_INIT;


REFTABLE_CALLOC_ARRAY(block.data, block_size); REFTABLE_CALLOC_ARRAY(block_data.buf, block_size);
check(block.data != NULL); check(block_data.buf != NULL);
block.len = block_size; block_data.len = block_size;
block_source_from_buf(&block.source ,&buf);
ret = block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size, ret = block_writer_init(&bw, REFTABLE_BLOCK_TYPE_REF, (uint8_t *) block_data.buf, block_size,
header_off, hash_size(REFTABLE_HASH_SHA1)); header_off, hash_size(REFTABLE_HASH_SHA1));
check(!ret); check(!ret);


@ -62,9 +63,10 @@ static void t_ref_block_read_write(void)


block_writer_release(&bw); block_writer_release(&bw);


block_reader_init(&br, &block, header_off, block_size, REFTABLE_HASH_SIZE_SHA1); block_source_from_buf(&source ,&block_data);
reftable_block_init(&block, &source, 0, header_off, block_size, REFTABLE_HASH_SIZE_SHA1);


block_iter_seek_start(&it, &br); block_iter_init(&it, &block);


for (i = 0; ; i++) { for (i = 0; ; i++) {
ret = block_iter_next(&it, &rec); ret = block_iter_next(&it, &rec);
@ -77,10 +79,9 @@ static void t_ref_block_read_write(void)
} }


for (i = 0; i < N; i++) { for (i = 0; i < N; i++) {
block_iter_reset(&it);
reftable_record_key(&recs[i], &want); reftable_record_key(&recs[i], &want);


ret = block_iter_seek_key(&it, &br, &want); ret = block_iter_seek_key(&it, &want);
check_int(ret, ==, 0); check_int(ret, ==, 0);


ret = block_iter_next(&it, &rec); ret = block_iter_next(&it, &rec);
@ -89,7 +90,7 @@ static void t_ref_block_read_write(void)
check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1));


want.len--; want.len--;
ret = block_iter_seek_key(&it, &br, &want); ret = block_iter_seek_key(&it, &want);
check_int(ret, ==, 0); check_int(ret, ==, 0);


ret = block_iter_next(&it, &rec); ret = block_iter_next(&it, &rec);
@ -97,12 +98,11 @@ static void t_ref_block_read_write(void)
check(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1)); check(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1));
} }


block_reader_release(&br); reftable_block_release(&block);
block_iter_close(&it); block_iter_close(&it);
reftable_record_release(&rec); reftable_record_release(&rec);
reftable_block_done(&br.block);
reftable_buf_release(&want); reftable_buf_release(&want);
reftable_buf_release(&buf); reftable_buf_release(&block_data);
for (i = 0; i < N; i++) for (i = 0; i < N; i++)
reftable_record_release(&recs[i]); reftable_record_release(&recs[i]);
} }
@ -113,24 +113,25 @@ static void t_log_block_read_write(void)
struct reftable_record recs[30]; struct reftable_record recs[30];
const size_t N = ARRAY_SIZE(recs); const size_t N = ARRAY_SIZE(recs);
const size_t block_size = 2048; const size_t block_size = 2048;
struct reftable_block block = { 0 }; struct reftable_block_source source = { 0 };
struct block_writer bw = { struct block_writer bw = {
.last_key = REFTABLE_BUF_INIT, .last_key = REFTABLE_BUF_INIT,
}; };
struct reftable_record rec = { struct reftable_record rec = {
.type = BLOCK_TYPE_LOG, .type = REFTABLE_BLOCK_TYPE_LOG,
}; };
size_t i = 0; size_t i = 0;
int ret; int ret;
struct block_reader br = { 0 }; struct reftable_block block = { 0 };
struct block_iter it = BLOCK_ITER_INIT; struct block_iter it = BLOCK_ITER_INIT;
struct reftable_buf want = REFTABLE_BUF_INIT, buf = REFTABLE_BUF_INIT; struct reftable_buf want = REFTABLE_BUF_INIT;
struct reftable_buf block_data = REFTABLE_BUF_INIT;


REFTABLE_CALLOC_ARRAY(block.data, block_size); REFTABLE_CALLOC_ARRAY(block_data.buf, block_size);
check(block.data != NULL); check(block_data.buf != NULL);
block.len = block_size; block_data.len = block_size;
block_source_from_buf(&block.source ,&buf);
ret = block_writer_init(&bw, BLOCK_TYPE_LOG, block.data, block_size, ret = block_writer_init(&bw, REFTABLE_BLOCK_TYPE_LOG, (uint8_t *) block_data.buf, block_size,
header_off, hash_size(REFTABLE_HASH_SHA1)); header_off, hash_size(REFTABLE_HASH_SHA1));
check(!ret); check(!ret);


@ -151,9 +152,10 @@ static void t_log_block_read_write(void)


block_writer_release(&bw); block_writer_release(&bw);


block_reader_init(&br, &block, header_off, block_size, REFTABLE_HASH_SIZE_SHA1); block_source_from_buf(&source, &block_data);
reftable_block_init(&block, &source, 0, header_off, block_size, REFTABLE_HASH_SIZE_SHA1);


block_iter_seek_start(&it, &br); block_iter_init(&it, &block);


for (i = 0; ; i++) { for (i = 0; ; i++) {
ret = block_iter_next(&it, &rec); ret = block_iter_next(&it, &rec);
@ -166,11 +168,10 @@ static void t_log_block_read_write(void)
} }


for (i = 0; i < N; i++) { for (i = 0; i < N; i++) {
block_iter_reset(&it);
reftable_buf_reset(&want); reftable_buf_reset(&want);
check(!reftable_buf_addstr(&want, recs[i].u.log.refname)); check(!reftable_buf_addstr(&want, recs[i].u.log.refname));


ret = block_iter_seek_key(&it, &br, &want); ret = block_iter_seek_key(&it, &want);
check_int(ret, ==, 0); check_int(ret, ==, 0);


ret = block_iter_next(&it, &rec); ret = block_iter_next(&it, &rec);
@ -179,7 +180,7 @@ static void t_log_block_read_write(void)
check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1));


want.len--; want.len--;
ret = block_iter_seek_key(&it, &br, &want); ret = block_iter_seek_key(&it, &want);
check_int(ret, ==, 0); check_int(ret, ==, 0);


ret = block_iter_next(&it, &rec); ret = block_iter_next(&it, &rec);
@ -187,12 +188,11 @@ static void t_log_block_read_write(void)
check(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1)); check(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1));
} }


block_reader_release(&br); reftable_block_release(&block);
block_iter_close(&it); block_iter_close(&it);
reftable_record_release(&rec); reftable_record_release(&rec);
reftable_block_done(&br.block);
reftable_buf_release(&want); reftable_buf_release(&want);
reftable_buf_release(&buf); reftable_buf_release(&block_data);
for (i = 0; i < N; i++) for (i = 0; i < N; i++)
reftable_record_release(&recs[i]); reftable_record_release(&recs[i]);
} }
@ -203,24 +203,25 @@ static void t_obj_block_read_write(void)
struct reftable_record recs[30]; struct reftable_record recs[30];
const size_t N = ARRAY_SIZE(recs); const size_t N = ARRAY_SIZE(recs);
const size_t block_size = 1024; const size_t block_size = 1024;
struct reftable_block block = { 0 }; struct reftable_block_source source = { 0 };
struct block_writer bw = { struct block_writer bw = {
.last_key = REFTABLE_BUF_INIT, .last_key = REFTABLE_BUF_INIT,
}; };
struct reftable_record rec = { struct reftable_record rec = {
.type = BLOCK_TYPE_OBJ, .type = REFTABLE_BLOCK_TYPE_OBJ,
}; };
size_t i = 0; size_t i = 0;
int ret; int ret;
struct block_reader br = { 0 }; struct reftable_block block = { 0 };
struct block_iter it = BLOCK_ITER_INIT; struct block_iter it = BLOCK_ITER_INIT;
struct reftable_buf want = REFTABLE_BUF_INIT, buf = REFTABLE_BUF_INIT; struct reftable_buf want = REFTABLE_BUF_INIT;
struct reftable_buf block_data = REFTABLE_BUF_INIT;


REFTABLE_CALLOC_ARRAY(block.data, block_size); REFTABLE_CALLOC_ARRAY(block_data.buf, block_size);
check(block.data != NULL); check(block_data.buf != NULL);
block.len = block_size; block_data.len = block_size;
block_source_from_buf(&block.source, &buf);
ret = block_writer_init(&bw, BLOCK_TYPE_OBJ, block.data, block_size, ret = block_writer_init(&bw, REFTABLE_BLOCK_TYPE_OBJ, (uint8_t *) block_data.buf, block_size,
header_off, hash_size(REFTABLE_HASH_SHA1)); header_off, hash_size(REFTABLE_HASH_SHA1));
check(!ret); check(!ret);


@ -243,9 +244,10 @@ static void t_obj_block_read_write(void)


block_writer_release(&bw); block_writer_release(&bw);


block_reader_init(&br, &block, header_off, block_size, REFTABLE_HASH_SIZE_SHA1); block_source_from_buf(&source, &block_data);
reftable_block_init(&block, &source, 0, header_off, block_size, REFTABLE_HASH_SIZE_SHA1);


block_iter_seek_start(&it, &br); block_iter_init(&it, &block);


for (i = 0; ; i++) { for (i = 0; ; i++) {
ret = block_iter_next(&it, &rec); ret = block_iter_next(&it, &rec);
@ -258,10 +260,9 @@ static void t_obj_block_read_write(void)
} }


for (i = 0; i < N; i++) { for (i = 0; i < N; i++) {
block_iter_reset(&it);
reftable_record_key(&recs[i], &want); reftable_record_key(&recs[i], &want);


ret = block_iter_seek_key(&it, &br, &want); ret = block_iter_seek_key(&it, &want);
check_int(ret, ==, 0); check_int(ret, ==, 0);


ret = block_iter_next(&it, &rec); ret = block_iter_next(&it, &rec);
@ -270,12 +271,11 @@ static void t_obj_block_read_write(void)
check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1));
} }


block_reader_release(&br); reftable_block_release(&block);
block_iter_close(&it); block_iter_close(&it);
reftable_record_release(&rec); reftable_record_release(&rec);
reftable_block_done(&br.block);
reftable_buf_release(&want); reftable_buf_release(&want);
reftable_buf_release(&buf); reftable_buf_release(&block_data);
for (i = 0; i < N; i++) for (i = 0; i < N; i++)
reftable_record_release(&recs[i]); reftable_record_release(&recs[i]);
} }
@ -286,25 +286,26 @@ static void t_index_block_read_write(void)
struct reftable_record recs[30]; struct reftable_record recs[30];
const size_t N = ARRAY_SIZE(recs); const size_t N = ARRAY_SIZE(recs);
const size_t block_size = 1024; const size_t block_size = 1024;
struct reftable_block block = { 0 }; struct reftable_block_source source = { 0 };
struct block_writer bw = { struct block_writer bw = {
.last_key = REFTABLE_BUF_INIT, .last_key = REFTABLE_BUF_INIT,
}; };
struct reftable_record rec = { struct reftable_record rec = {
.type = BLOCK_TYPE_INDEX, .type = REFTABLE_BLOCK_TYPE_INDEX,
.u.idx.last_key = REFTABLE_BUF_INIT, .u.idx.last_key = REFTABLE_BUF_INIT,
}; };
size_t i = 0; size_t i = 0;
int ret; int ret;
struct block_reader br = { 0 }; struct reftable_block block = { 0 };
struct block_iter it = BLOCK_ITER_INIT; struct block_iter it = BLOCK_ITER_INIT;
struct reftable_buf want = REFTABLE_BUF_INIT, buf = REFTABLE_BUF_INIT; struct reftable_buf want = REFTABLE_BUF_INIT;
struct reftable_buf block_data = REFTABLE_BUF_INIT;


REFTABLE_CALLOC_ARRAY(block.data, block_size); REFTABLE_CALLOC_ARRAY(block_data.buf, block_size);
check(block.data != NULL); check(block_data.buf != NULL);
block.len = block_size; block_data.len = block_size;
block_source_from_buf(&block.source, &buf);
ret = block_writer_init(&bw, BLOCK_TYPE_INDEX, block.data, block_size, ret = block_writer_init(&bw, REFTABLE_BLOCK_TYPE_INDEX, (uint8_t *) block_data.buf, block_size,
header_off, hash_size(REFTABLE_HASH_SHA1)); header_off, hash_size(REFTABLE_HASH_SHA1));
check(!ret); check(!ret);


@ -314,7 +315,7 @@ static void t_index_block_read_write(void)
snprintf(buf, sizeof(buf), "branch%02"PRIuMAX, (uintmax_t)i); snprintf(buf, sizeof(buf), "branch%02"PRIuMAX, (uintmax_t)i);


reftable_buf_init(&recs[i].u.idx.last_key); reftable_buf_init(&recs[i].u.idx.last_key);
recs[i].type = BLOCK_TYPE_INDEX; recs[i].type = REFTABLE_BLOCK_TYPE_INDEX;
check(!reftable_buf_addstr(&recs[i].u.idx.last_key, buf)); check(!reftable_buf_addstr(&recs[i].u.idx.last_key, buf));
recs[i].u.idx.offset = i; recs[i].u.idx.offset = i;


@ -327,9 +328,10 @@ static void t_index_block_read_write(void)


block_writer_release(&bw); block_writer_release(&bw);


block_reader_init(&br, &block, header_off, block_size, REFTABLE_HASH_SIZE_SHA1); block_source_from_buf(&source, &block_data);
reftable_block_init(&block, &source, 0, header_off, block_size, REFTABLE_HASH_SIZE_SHA1);


block_iter_seek_start(&it, &br); block_iter_init(&it, &block);


for (i = 0; ; i++) { for (i = 0; ; i++) {
ret = block_iter_next(&it, &rec); ret = block_iter_next(&it, &rec);
@ -342,10 +344,9 @@ static void t_index_block_read_write(void)
} }


for (i = 0; i < N; i++) { for (i = 0; i < N; i++) {
block_iter_reset(&it);
reftable_record_key(&recs[i], &want); reftable_record_key(&recs[i], &want);


ret = block_iter_seek_key(&it, &br, &want); ret = block_iter_seek_key(&it, &want);
check_int(ret, ==, 0); check_int(ret, ==, 0);


ret = block_iter_next(&it, &rec); ret = block_iter_next(&it, &rec);
@ -354,7 +355,7 @@ static void t_index_block_read_write(void)
check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1));


want.len--; want.len--;
ret = block_iter_seek_key(&it, &br, &want); ret = block_iter_seek_key(&it, &want);
check_int(ret, ==, 0); check_int(ret, ==, 0);


ret = block_iter_next(&it, &rec); ret = block_iter_next(&it, &rec);
@ -362,22 +363,99 @@ static void t_index_block_read_write(void)
check(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1)); check(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1));
} }


block_reader_release(&br); reftable_block_release(&block);
block_iter_close(&it); block_iter_close(&it);
reftable_record_release(&rec); reftable_record_release(&rec);
reftable_block_done(&br.block);
reftable_buf_release(&want); reftable_buf_release(&want);
reftable_buf_release(&buf); reftable_buf_release(&block_data);
for (i = 0; i < N; i++) for (i = 0; i < N; i++)
reftable_record_release(&recs[i]); 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, REFTABLE_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 = REFTABLE_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) 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_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_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_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_ref_block_read_write(), "read-write operations on ref blocks work");
TEST(t_block_iterator(), "block iterator works");


return test_done(); return test_done();
} }

View File

@ -11,7 +11,7 @@ https://developers.google.com/open-source/licenses/bsd
#include "reftable/blocksource.h" #include "reftable/blocksource.h"
#include "reftable/constants.h" #include "reftable/constants.h"
#include "reftable/merged.h" #include "reftable/merged.h"
#include "reftable/reader.h" #include "reftable/table.h"
#include "reftable/reftable-error.h" #include "reftable/reftable-error.h"
#include "reftable/reftable-merged.h" #include "reftable/reftable-merged.h"
#include "reftable/reftable-writer.h" #include "reftable/reftable-writer.h"
@ -19,7 +19,7 @@ https://developers.google.com/open-source/licenses/bsd
static struct reftable_merged_table * static struct reftable_merged_table *
merged_table_from_records(struct reftable_ref_record **refs, merged_table_from_records(struct reftable_ref_record **refs,
struct reftable_block_source **source, struct reftable_block_source **source,
struct reftable_reader ***readers, const size_t *sizes, struct reftable_table ***tables, const size_t *sizes,
struct reftable_buf *buf, const size_t n) struct reftable_buf *buf, const size_t n)
{ {
struct reftable_merged_table *mt = NULL; struct reftable_merged_table *mt = NULL;
@ -28,8 +28,8 @@ merged_table_from_records(struct reftable_ref_record **refs,
}; };
int err; int err;


REFTABLE_CALLOC_ARRAY(*readers, n); REFTABLE_CALLOC_ARRAY(*tables, n);
check(*readers != NULL); check(*tables != NULL);
REFTABLE_CALLOC_ARRAY(*source, n); REFTABLE_CALLOC_ARRAY(*source, n);
check(*source != NULL); check(*source != NULL);


@ -37,21 +37,21 @@ merged_table_from_records(struct reftable_ref_record **refs,
t_reftable_write_to_buf(&buf[i], refs[i], sizes[i], NULL, 0, &opts); t_reftable_write_to_buf(&buf[i], refs[i], sizes[i], NULL, 0, &opts);
block_source_from_buf(&(*source)[i], &buf[i]); block_source_from_buf(&(*source)[i], &buf[i]);


err = reftable_reader_new(&(*readers)[i], &(*source)[i], err = reftable_table_new(&(*tables)[i], &(*source)[i],
"name"); "name");
check(!err); check(!err);
} }


err = reftable_merged_table_new(&mt, *readers, n, REFTABLE_HASH_SHA1); err = reftable_merged_table_new(&mt, *tables, n, REFTABLE_HASH_SHA1);
check(!err); check(!err);
return mt; return mt;
} }


static void readers_destroy(struct reftable_reader **readers, const size_t n) static void tables_destroy(struct reftable_table **tables, const size_t n)
{ {
for (size_t i = 0; i < n; i++) for (size_t i = 0; i < n; i++)
reftable_reader_decref(readers[i]); reftable_table_decref(tables[i]);
reftable_free(readers); reftable_free(tables);
} }


static void t_merged_single_record(void) static void t_merged_single_record(void)
@ -77,14 +77,14 @@ static void t_merged_single_record(void)
size_t sizes[] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) }; size_t sizes[] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) };
struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT }; struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT };
struct reftable_block_source *bs = NULL; struct reftable_block_source *bs = NULL;
struct reftable_reader **readers = NULL; struct reftable_table **tables = NULL;
struct reftable_merged_table *mt = struct reftable_merged_table *mt =
merged_table_from_records(refs, &bs, &readers, sizes, bufs, 3); merged_table_from_records(refs, &bs, &tables, sizes, bufs, 3);
struct reftable_ref_record ref = { 0 }; struct reftable_ref_record ref = { 0 };
struct reftable_iterator it = { 0 }; struct reftable_iterator it = { 0 };
int err; int err;


err = merged_table_init_iter(mt, &it, BLOCK_TYPE_REF); err = merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_REF);
check(!err); check(!err);
err = reftable_iterator_seek_ref(&it, "a"); err = reftable_iterator_seek_ref(&it, "a");
check(!err); check(!err);
@ -94,7 +94,7 @@ static void t_merged_single_record(void)
check(reftable_ref_record_equal(&r2[0], &ref, REFTABLE_HASH_SIZE_SHA1)); check(reftable_ref_record_equal(&r2[0], &ref, REFTABLE_HASH_SIZE_SHA1));
reftable_ref_record_release(&ref); reftable_ref_record_release(&ref);
reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);
readers_destroy(readers, 3); tables_destroy(tables, 3);
reftable_merged_table_free(mt); reftable_merged_table_free(mt);
for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) for (size_t i = 0; i < ARRAY_SIZE(bufs); i++)
reftable_buf_release(&bufs[i]); reftable_buf_release(&bufs[i]);
@ -154,9 +154,9 @@ static void t_merged_refs(void)
size_t sizes[3] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) }; size_t sizes[3] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) };
struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT }; struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT };
struct reftable_block_source *bs = NULL; struct reftable_block_source *bs = NULL;
struct reftable_reader **readers = NULL; struct reftable_table **tables = NULL;
struct reftable_merged_table *mt = struct reftable_merged_table *mt =
merged_table_from_records(refs, &bs, &readers, sizes, bufs, 3); merged_table_from_records(refs, &bs, &tables, sizes, bufs, 3);
struct reftable_iterator it = { 0 }; struct reftable_iterator it = { 0 };
int err; int err;
struct reftable_ref_record *out = NULL; struct reftable_ref_record *out = NULL;
@ -164,7 +164,7 @@ static void t_merged_refs(void)
size_t cap = 0; size_t cap = 0;
size_t i; size_t i;


err = merged_table_init_iter(mt, &it, BLOCK_TYPE_REF); err = merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_REF);
check(!err); check(!err);
err = reftable_iterator_seek_ref(&it, "a"); err = reftable_iterator_seek_ref(&it, "a");
check(!err); check(!err);
@ -193,7 +193,7 @@ static void t_merged_refs(void)


for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
reftable_buf_release(&bufs[i]); reftable_buf_release(&bufs[i]);
readers_destroy(readers, 3); tables_destroy(tables, 3);
reftable_merged_table_free(mt); reftable_merged_table_free(mt);
reftable_free(bs); reftable_free(bs);
} }
@ -238,13 +238,13 @@ static void t_merged_seek_multiple_times(void)
REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT,
}; };
struct reftable_block_source *sources = NULL; struct reftable_block_source *sources = NULL;
struct reftable_reader **readers = NULL; struct reftable_table **tables = NULL;
struct reftable_ref_record rec = { 0 }; struct reftable_ref_record rec = { 0 };
struct reftable_iterator it = { 0 }; struct reftable_iterator it = { 0 };
struct reftable_merged_table *mt; struct reftable_merged_table *mt;


mt = merged_table_from_records(refs, &sources, &readers, sizes, bufs, 2); mt = merged_table_from_records(refs, &sources, &tables, sizes, bufs, 2);
merged_table_init_iter(mt, &it, BLOCK_TYPE_REF); merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_REF);


for (size_t i = 0; i < 5; i++) { for (size_t i = 0; i < 5; i++) {
int err = reftable_iterator_seek_ref(&it, "c"); int err = reftable_iterator_seek_ref(&it, "c");
@ -266,7 +266,7 @@ static void t_merged_seek_multiple_times(void)


for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) for (size_t i = 0; i < ARRAY_SIZE(bufs); i++)
reftable_buf_release(&bufs[i]); reftable_buf_release(&bufs[i]);
readers_destroy(readers, ARRAY_SIZE(refs)); tables_destroy(tables, ARRAY_SIZE(refs));
reftable_ref_record_release(&rec); reftable_ref_record_release(&rec);
reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);
reftable_merged_table_free(mt); reftable_merged_table_free(mt);
@ -313,14 +313,14 @@ static void t_merged_seek_multiple_times_without_draining(void)
REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT,
}; };
struct reftable_block_source *sources = NULL; struct reftable_block_source *sources = NULL;
struct reftable_reader **readers = NULL; struct reftable_table **tables = NULL;
struct reftable_ref_record rec = { 0 }; struct reftable_ref_record rec = { 0 };
struct reftable_iterator it = { 0 }; struct reftable_iterator it = { 0 };
struct reftable_merged_table *mt; struct reftable_merged_table *mt;
int err; int err;


mt = merged_table_from_records(refs, &sources, &readers, sizes, bufs, 2); mt = merged_table_from_records(refs, &sources, &tables, sizes, bufs, 2);
merged_table_init_iter(mt, &it, BLOCK_TYPE_REF); merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_REF);


err = reftable_iterator_seek_ref(&it, "b"); err = reftable_iterator_seek_ref(&it, "b");
check(!err); check(!err);
@ -338,7 +338,7 @@ static void t_merged_seek_multiple_times_without_draining(void)


for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) for (size_t i = 0; i < ARRAY_SIZE(bufs); i++)
reftable_buf_release(&bufs[i]); reftable_buf_release(&bufs[i]);
readers_destroy(readers, ARRAY_SIZE(refs)); tables_destroy(tables, ARRAY_SIZE(refs));
reftable_ref_record_release(&rec); reftable_ref_record_release(&rec);
reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);
reftable_merged_table_free(mt); reftable_merged_table_free(mt);
@ -348,7 +348,7 @@ static void t_merged_seek_multiple_times_without_draining(void)
static struct reftable_merged_table * static struct reftable_merged_table *
merged_table_from_log_records(struct reftable_log_record **logs, merged_table_from_log_records(struct reftable_log_record **logs,
struct reftable_block_source **source, struct reftable_block_source **source,
struct reftable_reader ***readers, const size_t *sizes, struct reftable_table ***tables, const size_t *sizes,
struct reftable_buf *buf, const size_t n) struct reftable_buf *buf, const size_t n)
{ {
struct reftable_merged_table *mt = NULL; struct reftable_merged_table *mt = NULL;
@ -358,8 +358,8 @@ merged_table_from_log_records(struct reftable_log_record **logs,
}; };
int err; int err;


REFTABLE_CALLOC_ARRAY(*readers, n); REFTABLE_CALLOC_ARRAY(*tables, n);
check(*readers != NULL); check(*tables != NULL);
REFTABLE_CALLOC_ARRAY(*source, n); REFTABLE_CALLOC_ARRAY(*source, n);
check(*source != NULL); check(*source != NULL);


@ -367,12 +367,12 @@ merged_table_from_log_records(struct reftable_log_record **logs,
t_reftable_write_to_buf(&buf[i], NULL, 0, logs[i], sizes[i], &opts); t_reftable_write_to_buf(&buf[i], NULL, 0, logs[i], sizes[i], &opts);
block_source_from_buf(&(*source)[i], &buf[i]); block_source_from_buf(&(*source)[i], &buf[i]);


err = reftable_reader_new(&(*readers)[i], &(*source)[i], err = reftable_table_new(&(*tables)[i], &(*source)[i],
"name"); "name");
check(!err); check(!err);
} }


err = reftable_merged_table_new(&mt, *readers, n, REFTABLE_HASH_SHA1); err = reftable_merged_table_new(&mt, *tables, n, REFTABLE_HASH_SHA1);
check(!err); check(!err);
return mt; return mt;
} }
@ -435,9 +435,9 @@ static void t_merged_logs(void)
size_t sizes[3] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) }; size_t sizes[3] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) };
struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT }; struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT };
struct reftable_block_source *bs = NULL; struct reftable_block_source *bs = NULL;
struct reftable_reader **readers = NULL; struct reftable_table **tables = NULL;
struct reftable_merged_table *mt = merged_table_from_log_records( struct reftable_merged_table *mt = merged_table_from_log_records(
logs, &bs, &readers, sizes, bufs, 3); logs, &bs, &tables, sizes, bufs, 3);
struct reftable_iterator it = { 0 }; struct reftable_iterator it = { 0 };
int err; int err;
struct reftable_log_record *out = NULL; struct reftable_log_record *out = NULL;
@ -445,7 +445,7 @@ static void t_merged_logs(void)
size_t cap = 0; size_t cap = 0;
size_t i; size_t i;


err = merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG); err = merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_LOG);
check(!err); check(!err);
err = reftable_iterator_seek_log(&it, "a"); err = reftable_iterator_seek_log(&it, "a");
check(!err); check(!err);
@ -469,7 +469,7 @@ static void t_merged_logs(void)
check(reftable_log_record_equal(want[i], &out[i], check(reftable_log_record_equal(want[i], &out[i],
REFTABLE_HASH_SIZE_SHA1)); REFTABLE_HASH_SIZE_SHA1));


err = merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG); err = merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_LOG);
check(!err); check(!err);
err = reftable_iterator_seek_log_at(&it, "a", 2); err = reftable_iterator_seek_log_at(&it, "a", 2);
check(!err); check(!err);
@ -485,7 +485,7 @@ static void t_merged_logs(void)


for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
reftable_buf_release(&bufs[i]); reftable_buf_release(&bufs[i]);
readers_destroy(readers, 3); tables_destroy(tables, 3);
reftable_merged_table_free(mt); reftable_merged_table_free(mt);
reftable_free(bs); reftable_free(bs);
} }
@ -502,7 +502,7 @@ static void t_default_write_opts(void)
int err; int err;
struct reftable_block_source source = { 0 }; struct reftable_block_source source = { 0 };
uint32_t hash_id; uint32_t hash_id;
struct reftable_reader *rd = NULL; struct reftable_table *table = NULL;
struct reftable_merged_table *merged = NULL; struct reftable_merged_table *merged = NULL;


reftable_writer_set_limits(w, 1, 1); reftable_writer_set_limits(w, 1, 1);
@ -516,18 +516,18 @@ static void t_default_write_opts(void)


block_source_from_buf(&source, &buf); block_source_from_buf(&source, &buf);


err = reftable_reader_new(&rd, &source, "filename"); err = reftable_table_new(&table, &source, "filename");
check(!err); check(!err);


hash_id = reftable_reader_hash_id(rd); hash_id = reftable_table_hash_id(table);
check_int(hash_id, ==, REFTABLE_HASH_SHA1); check_int(hash_id, ==, REFTABLE_HASH_SHA1);


err = reftable_merged_table_new(&merged, &rd, 1, REFTABLE_HASH_SHA256); err = reftable_merged_table_new(&merged, &table, 1, REFTABLE_HASH_SHA256);
check_int(err, ==, REFTABLE_FORMAT_ERROR); check_int(err, ==, REFTABLE_FORMAT_ERROR);
err = reftable_merged_table_new(&merged, &rd, 1, REFTABLE_HASH_SHA1); err = reftable_merged_table_new(&merged, &table, 1, REFTABLE_HASH_SHA1);
check(!err); check(!err);


reftable_reader_decref(rd); reftable_table_decref(table);
reftable_merged_table_free(merged); reftable_merged_table_free(merged);
reftable_buf_release(&buf); reftable_buf_release(&buf);
} }

View File

@ -34,7 +34,7 @@ static void t_pq_record(void)
char *last = NULL; char *last = NULL;


for (i = 0; i < N; i++) { for (i = 0; i < N; i++) {
check(!reftable_record_init(&recs[i], BLOCK_TYPE_REF)); check(!reftable_record_init(&recs[i], REFTABLE_BLOCK_TYPE_REF));
recs[i].u.ref.refname = xstrfmt("%02"PRIuMAX, (uintmax_t)i); recs[i].u.ref.refname = xstrfmt("%02"PRIuMAX, (uintmax_t)i);
} }


@ -57,7 +57,7 @@ static void t_pq_record(void)
merged_iter_pqueue_check(&pq); merged_iter_pqueue_check(&pq);


check(pq_entry_equal(&top, &e)); check(pq_entry_equal(&top, &e));
check(reftable_record_type(e.rec) == BLOCK_TYPE_REF); check(reftable_record_type(e.rec) == REFTABLE_BLOCK_TYPE_REF);
if (last) if (last)
check_int(strcmp(last, e.rec->u.ref.refname), <, 0); check_int(strcmp(last, e.rec->u.ref.refname), <, 0);
last = e.rec->u.ref.refname; last = e.rec->u.ref.refname;
@ -76,7 +76,7 @@ static void t_pq_index(void)
size_t N = ARRAY_SIZE(recs), i; size_t N = ARRAY_SIZE(recs), i;


for (i = 0; i < N; i++) { for (i = 0; i < N; i++) {
check(!reftable_record_init(&recs[i], BLOCK_TYPE_REF)); check(!reftable_record_init(&recs[i], REFTABLE_BLOCK_TYPE_REF));
recs[i].u.ref.refname = (char *) "refs/heads/master"; recs[i].u.ref.refname = (char *) "refs/heads/master";
} }


@ -100,7 +100,7 @@ static void t_pq_index(void)
merged_iter_pqueue_check(&pq); merged_iter_pqueue_check(&pq);


check(pq_entry_equal(&top, &e)); check(pq_entry_equal(&top, &e));
check(reftable_record_type(e.rec) == BLOCK_TYPE_REF); check(reftable_record_type(e.rec) == REFTABLE_BLOCK_TYPE_REF);
check_int(e.index, ==, i); check_int(e.index, ==, i);
if (last) if (last)
check_str(last, e.rec->u.ref.refname); check_str(last, e.rec->u.ref.refname);
@ -117,7 +117,7 @@ static void t_merged_iter_pqueue_top(void)
size_t N = ARRAY_SIZE(recs), i; size_t N = ARRAY_SIZE(recs), i;


for (i = 0; i < N; i++) { for (i = 0; i < N; i++) {
check(!reftable_record_init(&recs[i], BLOCK_TYPE_REF)); check(!reftable_record_init(&recs[i], REFTABLE_BLOCK_TYPE_REF));
recs[i].u.ref.refname = (char *) "refs/heads/master"; recs[i].u.ref.refname = (char *) "refs/heads/master";
} }



View File

@ -1,96 +0,0 @@
#include "test-lib.h"
#include "lib-reftable.h"
#include "reftable/blocksource.h"
#include "reftable/reader.h"

static int t_reader_seek_once(void)
{
struct reftable_ref_record records[] = {
{
.refname = (char *) "refs/heads/main",
.value_type = REFTABLE_REF_VAL1,
.value.val1 = { 42 },
},
};
struct reftable_block_source source = { 0 };
struct reftable_ref_record ref = { 0 };
struct reftable_iterator it = { 0 };
struct reftable_reader *reader;
struct reftable_buf buf = REFTABLE_BUF_INIT;
int ret;

t_reftable_write_to_buf(&buf, records, ARRAY_SIZE(records), NULL, 0, NULL);
block_source_from_buf(&source, &buf);

ret = reftable_reader_new(&reader, &source, "name");
check(!ret);

reftable_reader_init_ref_iterator(reader, &it);
ret = reftable_iterator_seek_ref(&it, "");
check(!ret);
ret = reftable_iterator_next_ref(&it, &ref);
check(!ret);

ret = reftable_ref_record_equal(&ref, &records[0], REFTABLE_HASH_SIZE_SHA1);
check_int(ret, ==, 1);

ret = reftable_iterator_next_ref(&it, &ref);
check_int(ret, ==, 1);

reftable_ref_record_release(&ref);
reftable_iterator_destroy(&it);
reftable_reader_decref(reader);
reftable_buf_release(&buf);
return 0;
}

static int t_reader_reseek(void)
{
struct reftable_ref_record records[] = {
{
.refname = (char *) "refs/heads/main",
.value_type = REFTABLE_REF_VAL1,
.value.val1 = { 42 },
},
};
struct reftable_block_source source = { 0 };
struct reftable_ref_record ref = { 0 };
struct reftable_iterator it = { 0 };
struct reftable_reader *reader;
struct reftable_buf buf = REFTABLE_BUF_INIT;
int ret;

t_reftable_write_to_buf(&buf, records, ARRAY_SIZE(records), NULL, 0, NULL);
block_source_from_buf(&source, &buf);

ret = reftable_reader_new(&reader, &source, "name");
check(!ret);

reftable_reader_init_ref_iterator(reader, &it);

for (size_t i = 0; i < 5; i++) {
ret = reftable_iterator_seek_ref(&it, "");
check(!ret);
ret = reftable_iterator_next_ref(&it, &ref);
check(!ret);

ret = reftable_ref_record_equal(&ref, &records[0], REFTABLE_HASH_SIZE_SHA1);
check_int(ret, ==, 1);

ret = reftable_iterator_next_ref(&it, &ref);
check_int(ret, ==, 1);
}

reftable_ref_record_release(&ref);
reftable_iterator_destroy(&it);
reftable_reader_decref(reader);
reftable_buf_release(&buf);
return 0;
}

int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
{
TEST(t_reader_seek_once(), "reader can seek once");
TEST(t_reader_reseek(), "reader can reseek multiple times");
return test_done();
}

View File

@ -12,9 +12,9 @@ https://developers.google.com/open-source/licenses/bsd
#include "lib-reftable.h" #include "lib-reftable.h"
#include "reftable/basics.h" #include "reftable/basics.h"
#include "reftable/blocksource.h" #include "reftable/blocksource.h"
#include "reftable/reader.h"
#include "reftable/reftable-error.h" #include "reftable/reftable-error.h"
#include "reftable/reftable-writer.h" #include "reftable/reftable-writer.h"
#include "reftable/table.h"
#include "strbuf.h" #include "strbuf.h"


static const int update_index = 5; static const int update_index = 5;
@ -23,22 +23,22 @@ static void t_buffer(void)
{ {
struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_buf buf = REFTABLE_BUF_INIT;
struct reftable_block_source source = { 0 }; struct reftable_block_source source = { 0 };
struct reftable_block out = { 0 }; struct reftable_block_data out = { 0 };
int n; int n;
uint8_t in[] = "hello"; uint8_t in[] = "hello";
check(!reftable_buf_add(&buf, in, sizeof(in))); check(!reftable_buf_add(&buf, in, sizeof(in)));
block_source_from_buf(&source, &buf); block_source_from_buf(&source, &buf);
check_int(block_source_size(&source), ==, 6); check_int(block_source_size(&source), ==, 6);
n = block_source_read_block(&source, &out, 0, sizeof(in)); n = block_source_read_data(&source, &out, 0, sizeof(in));
check_int(n, ==, sizeof(in)); check_int(n, ==, sizeof(in));
check(!memcmp(in, out.data, n)); check(!memcmp(in, out.data, n));
reftable_block_done(&out); block_source_release_data(&out);


n = block_source_read_block(&source, &out, 1, 2); n = block_source_read_data(&source, &out, 1, 2);
check_int(n, ==, 2); check_int(n, ==, 2);
check(!memcmp(out.data, "el", 2)); check(!memcmp(out.data, "el", 2));


reftable_block_done(&out); block_source_release_data(&out);
block_source_close(&source); block_source_close(&source);
reftable_buf_release(&buf); reftable_buf_release(&buf);
} }
@ -204,7 +204,7 @@ static void t_log_write_read(void)
struct reftable_ref_record ref = { 0 }; struct reftable_ref_record ref = { 0 };
struct reftable_log_record log = { 0 }; struct reftable_log_record log = { 0 };
struct reftable_iterator it = { 0 }; struct reftable_iterator it = { 0 };
struct reftable_reader *reader; struct reftable_table *table;
struct reftable_block_source source = { 0 }; struct reftable_block_source source = { 0 };
struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_buf buf = REFTABLE_BUF_INIT;
struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
@ -254,10 +254,10 @@ static void t_log_write_read(void)


block_source_from_buf(&source, &buf); block_source_from_buf(&source, &buf);


err = reftable_reader_new(&reader, &source, "file.log"); err = reftable_table_new(&table, &source, "file.log");
check(!err); check(!err);


err = reftable_reader_init_ref_iterator(reader, &it); err = reftable_table_init_ref_iterator(table, &it);
check(!err); check(!err);


err = reftable_iterator_seek_ref(&it, names[N - 1]); err = reftable_iterator_seek_ref(&it, names[N - 1]);
@ -273,7 +273,7 @@ static void t_log_write_read(void)
reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);
reftable_ref_record_release(&ref); reftable_ref_record_release(&ref);


err = reftable_reader_init_log_iterator(reader, &it); err = reftable_table_init_log_iterator(table, &it);
check(!err); check(!err);
err = reftable_iterator_seek_log(&it, ""); err = reftable_iterator_seek_log(&it, "");
check(!err); check(!err);
@ -294,7 +294,7 @@ static void t_log_write_read(void)
/* cleanup. */ /* cleanup. */
reftable_buf_release(&buf); reftable_buf_release(&buf);
free_names(names); free_names(names);
reftable_reader_decref(reader); reftable_table_decref(table);
} }


static void t_log_zlib_corruption(void) static void t_log_zlib_corruption(void)
@ -303,7 +303,7 @@ static void t_log_zlib_corruption(void)
.block_size = 256, .block_size = 256,
}; };
struct reftable_iterator it = { 0 }; struct reftable_iterator it = { 0 };
struct reftable_reader *reader; struct reftable_table *table;
struct reftable_block_source source = { 0 }; struct reftable_block_source source = { 0 };
struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_buf buf = REFTABLE_BUF_INIT;
struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
@ -345,10 +345,10 @@ static void t_log_zlib_corruption(void)


block_source_from_buf(&source, &buf); block_source_from_buf(&source, &buf);


err = reftable_reader_new(&reader, &source, "file.log"); err = reftable_table_new(&table, &source, "file.log");
check(!err); check(!err);


err = reftable_reader_init_log_iterator(reader, &it); err = reftable_table_init_log_iterator(table, &it);
check(!err); check(!err);
err = reftable_iterator_seek_log(&it, "refname"); err = reftable_iterator_seek_log(&it, "refname");
check_int(err, ==, REFTABLE_ZLIB_ERROR); check_int(err, ==, REFTABLE_ZLIB_ERROR);
@ -356,7 +356,7 @@ static void t_log_zlib_corruption(void)
reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);


/* cleanup. */ /* cleanup. */
reftable_reader_decref(reader); reftable_table_decref(table);
reftable_buf_release(&buf); reftable_buf_release(&buf);
} }


@ -367,7 +367,7 @@ static void t_table_read_write_sequential(void)
int N = 50; int N = 50;
struct reftable_iterator it = { 0 }; struct reftable_iterator it = { 0 };
struct reftable_block_source source = { 0 }; struct reftable_block_source source = { 0 };
struct reftable_reader *reader; struct reftable_table *table;
int err = 0; int err = 0;
int j = 0; int j = 0;


@ -375,10 +375,10 @@ static void t_table_read_write_sequential(void)


block_source_from_buf(&source, &buf); block_source_from_buf(&source, &buf);


err = reftable_reader_new(&reader, &source, "file.ref"); err = reftable_table_new(&table, &source, "file.ref");
check(!err); check(!err);


err = reftable_reader_init_ref_iterator(reader, &it); err = reftable_table_init_ref_iterator(table, &it);
check(!err); check(!err);
err = reftable_iterator_seek_ref(&it, ""); err = reftable_iterator_seek_ref(&it, "");
check(!err); check(!err);
@ -396,7 +396,7 @@ static void t_table_read_write_sequential(void)
check_int(j, ==, N); check_int(j, ==, N);


reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);
reftable_reader_decref(reader); reftable_table_decref(table);
reftable_buf_release(&buf); reftable_buf_release(&buf);
free_names(names); free_names(names);
} }
@ -417,7 +417,7 @@ static void t_table_read_api(void)
char **names; char **names;
struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_buf buf = REFTABLE_BUF_INIT;
int N = 50; int N = 50;
struct reftable_reader *reader; struct reftable_table *table;
struct reftable_block_source source = { 0 }; struct reftable_block_source source = { 0 };
int err; int err;
struct reftable_log_record log = { 0 }; struct reftable_log_record log = { 0 };
@ -427,10 +427,10 @@ static void t_table_read_api(void)


block_source_from_buf(&source, &buf); block_source_from_buf(&source, &buf);


err = reftable_reader_new(&reader, &source, "file.ref"); err = reftable_table_new(&table, &source, "file.ref");
check(!err); check(!err);


err = reftable_reader_init_ref_iterator(reader, &it); err = reftable_table_init_ref_iterator(table, &it);
check(!err); check(!err);
err = reftable_iterator_seek_ref(&it, names[0]); err = reftable_iterator_seek_ref(&it, names[0]);
check(!err); check(!err);
@ -441,7 +441,7 @@ static void t_table_read_api(void)
reftable_buf_release(&buf); reftable_buf_release(&buf);
free_names(names); free_names(names);
reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);
reftable_reader_decref(reader); reftable_table_decref(table);
reftable_buf_release(&buf); reftable_buf_release(&buf);
} }


@ -450,7 +450,7 @@ static void t_table_read_write_seek(int index, enum reftable_hash hash_id)
char **names; char **names;
struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_buf buf = REFTABLE_BUF_INIT;
int N = 50; int N = 50;
struct reftable_reader *reader; struct reftable_table *table;
struct reftable_block_source source = { 0 }; struct reftable_block_source source = { 0 };
int err; int err;
int i = 0; int i = 0;
@ -463,18 +463,18 @@ static void t_table_read_write_seek(int index, enum reftable_hash hash_id)


block_source_from_buf(&source, &buf); block_source_from_buf(&source, &buf);


err = reftable_reader_new(&reader, &source, "file.ref"); err = reftable_table_new(&table, &source, "file.ref");
check(!err); check(!err);
check_int(hash_id, ==, reftable_reader_hash_id(reader)); check_int(hash_id, ==, reftable_table_hash_id(table));


if (!index) { if (!index) {
reader->ref_offsets.index_offset = 0; table->ref_offsets.index_offset = 0;
} else { } else {
check_int(reader->ref_offsets.index_offset, >, 0); check_int(table->ref_offsets.index_offset, >, 0);
} }


for (i = 1; i < N; i++) { for (i = 1; i < N; i++) {
err = reftable_reader_init_ref_iterator(reader, &it); err = reftable_table_init_ref_iterator(table, &it);
check(!err); check(!err);
err = reftable_iterator_seek_ref(&it, names[i]); err = reftable_iterator_seek_ref(&it, names[i]);
check(!err); check(!err);
@ -491,7 +491,7 @@ static void t_table_read_write_seek(int index, enum reftable_hash hash_id)
check(!reftable_buf_addstr(&pastLast, names[N - 1])); check(!reftable_buf_addstr(&pastLast, names[N - 1]));
check(!reftable_buf_addstr(&pastLast, "/")); check(!reftable_buf_addstr(&pastLast, "/"));


err = reftable_reader_init_ref_iterator(reader, &it); err = reftable_table_init_ref_iterator(table, &it);
check(!err); check(!err);
err = reftable_iterator_seek_ref(&it, pastLast.buf); err = reftable_iterator_seek_ref(&it, pastLast.buf);
if (err == 0) { if (err == 0) {
@ -507,7 +507,7 @@ static void t_table_read_write_seek(int index, enum reftable_hash hash_id)


reftable_buf_release(&buf); reftable_buf_release(&buf);
free_names(names); free_names(names);
reftable_reader_decref(reader); reftable_table_decref(table);
} }


static void t_table_read_write_seek_linear(void) static void t_table_read_write_seek_linear(void)
@ -535,7 +535,7 @@ static void t_table_refs_for(int indexed)
.block_size = 256, .block_size = 256,
}; };
struct reftable_ref_record ref = { 0 }; struct reftable_ref_record ref = { 0 };
struct reftable_reader *reader; struct reftable_table *table;
struct reftable_block_source source = { 0 }; struct reftable_block_source source = { 0 };
struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_buf buf = REFTABLE_BUF_INIT;
struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
@ -585,18 +585,18 @@ static void t_table_refs_for(int indexed)


block_source_from_buf(&source, &buf); block_source_from_buf(&source, &buf);


err = reftable_reader_new(&reader, &source, "file.ref"); err = reftable_table_new(&table, &source, "file.ref");
check(!err); check(!err);
if (!indexed) if (!indexed)
reader->obj_offsets.is_present = 0; table->obj_offsets.is_present = 0;


err = reftable_reader_init_ref_iterator(reader, &it); err = reftable_table_init_ref_iterator(table, &it);
check(!err); check(!err);
err = reftable_iterator_seek_ref(&it, ""); err = reftable_iterator_seek_ref(&it, "");
check(!err); check(!err);
reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);


err = reftable_reader_refs_for(reader, &it, want_hash); err = reftable_table_refs_for(table, &it, want_hash);
check(!err); check(!err);


for (j = 0; ; j++) { for (j = 0; ; j++) {
@ -613,7 +613,7 @@ static void t_table_refs_for(int indexed)
reftable_buf_release(&buf); reftable_buf_release(&buf);
free_names(want_names); free_names(want_names);
reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);
reftable_reader_decref(reader); reftable_table_decref(table);
} }


static void t_table_refs_for_no_index(void) static void t_table_refs_for_no_index(void)
@ -632,7 +632,7 @@ static void t_write_empty_table(void)
struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_buf buf = REFTABLE_BUF_INIT;
struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
struct reftable_block_source source = { 0 }; struct reftable_block_source source = { 0 };
struct reftable_reader *rd = NULL; struct reftable_table *table = NULL;
struct reftable_ref_record rec = { 0 }; struct reftable_ref_record rec = { 0 };
struct reftable_iterator it = { 0 }; struct reftable_iterator it = { 0 };
int err; int err;
@ -647,10 +647,10 @@ static void t_write_empty_table(void)


block_source_from_buf(&source, &buf); block_source_from_buf(&source, &buf);


err = reftable_reader_new(&rd, &source, "filename"); err = reftable_table_new(&table, &source, "filename");
check(!err); check(!err);


err = reftable_reader_init_ref_iterator(rd, &it); err = reftable_table_init_ref_iterator(table, &it);
check(!err); check(!err);
err = reftable_iterator_seek_ref(&it, ""); err = reftable_iterator_seek_ref(&it, "");
check(!err); check(!err);
@ -659,7 +659,7 @@ static void t_write_empty_table(void)
check_int(err, >, 0); check_int(err, >, 0);


reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);
reftable_reader_decref(rd); reftable_table_decref(table);
reftable_buf_release(&buf); reftable_buf_release(&buf);
} }


@ -803,7 +803,7 @@ static void t_write_multiple_indices(void)
struct reftable_iterator it = { 0 }; struct reftable_iterator it = { 0 };
const struct reftable_stats *stats; const struct reftable_stats *stats;
struct reftable_writer *writer; struct reftable_writer *writer;
struct reftable_reader *reader; struct reftable_table *table;
char buf[128]; char buf[128];
int err, i; int err, i;


@ -852,21 +852,21 @@ static void t_write_multiple_indices(void)
check_int(stats->log_stats.index_offset, >, 0); check_int(stats->log_stats.index_offset, >, 0);


block_source_from_buf(&source, &writer_buf); block_source_from_buf(&source, &writer_buf);
err = reftable_reader_new(&reader, &source, "filename"); err = reftable_table_new(&table, &source, "filename");
check(!err); check(!err);


/* /*
* Seeking the log uses the log index now. In case there is any * Seeking the log uses the log index now. In case there is any
* confusion regarding indices we would notice here. * confusion regarding indices we would notice here.
*/ */
err = reftable_reader_init_log_iterator(reader, &it); err = reftable_table_init_log_iterator(table, &it);
check(!err); check(!err);
err = reftable_iterator_seek_log(&it, ""); err = reftable_iterator_seek_log(&it, "");
check(!err); check(!err);


reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);
reftable_writer_free(writer); reftable_writer_free(writer);
reftable_reader_decref(reader); reftable_table_decref(table);
reftable_buf_release(&writer_buf); reftable_buf_release(&writer_buf);
} }


@ -880,7 +880,7 @@ static void t_write_multi_level_index(void)
struct reftable_iterator it = { 0 }; struct reftable_iterator it = { 0 };
const struct reftable_stats *stats; const struct reftable_stats *stats;
struct reftable_writer *writer; struct reftable_writer *writer;
struct reftable_reader *reader; struct reftable_table *table;
int err; int err;


writer = t_reftable_strbuf_writer(&writer_buf, &opts); writer = t_reftable_strbuf_writer(&writer_buf, &opts);
@ -909,20 +909,20 @@ static void t_write_multi_level_index(void)
check_int(stats->ref_stats.max_index_level, ==, 2); check_int(stats->ref_stats.max_index_level, ==, 2);


block_source_from_buf(&source, &writer_buf); block_source_from_buf(&source, &writer_buf);
err = reftable_reader_new(&reader, &source, "filename"); err = reftable_table_new(&table, &source, "filename");
check(!err); check(!err);


/* /*
* Seeking the last ref should work as expected. * Seeking the last ref should work as expected.
*/ */
err = reftable_reader_init_ref_iterator(reader, &it); err = reftable_table_init_ref_iterator(table, &it);
check(!err); check(!err);
err = reftable_iterator_seek_ref(&it, "refs/heads/199"); err = reftable_iterator_seek_ref(&it, "refs/heads/199");
check(!err); check(!err);


reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);
reftable_writer_free(writer); reftable_writer_free(writer);
reftable_reader_decref(reader); reftable_table_decref(table);
reftable_buf_release(&writer_buf); reftable_buf_release(&writer_buf);
reftable_buf_release(&buf); reftable_buf_release(&buf);
} }
@ -931,11 +931,11 @@ static void t_corrupt_table_empty(void)
{ {
struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_buf buf = REFTABLE_BUF_INIT;
struct reftable_block_source source = { 0 }; struct reftable_block_source source = { 0 };
struct reftable_reader *reader; struct reftable_table *table;
int err; int err;


block_source_from_buf(&source, &buf); block_source_from_buf(&source, &buf);
err = reftable_reader_new(&reader, &source, "file.log"); err = reftable_table_new(&table, &source, "file.log");
check_int(err, ==, REFTABLE_FORMAT_ERROR); check_int(err, ==, REFTABLE_FORMAT_ERROR);
} }


@ -944,12 +944,12 @@ static void t_corrupt_table(void)
uint8_t zeros[1024] = { 0 }; uint8_t zeros[1024] = { 0 };
struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_buf buf = REFTABLE_BUF_INIT;
struct reftable_block_source source = { 0 }; struct reftable_block_source source = { 0 };
struct reftable_reader *reader; struct reftable_table *table;
int err; int err;
check(!reftable_buf_add(&buf, zeros, sizeof(zeros))); check(!reftable_buf_add(&buf, zeros, sizeof(zeros)));


block_source_from_buf(&source, &buf); block_source_from_buf(&source, &buf);
err = reftable_reader_new(&reader, &source, "file.log"); err = reftable_table_new(&table, &source, "file.log");
check_int(err, ==, REFTABLE_FORMAT_ERROR); check_int(err, ==, REFTABLE_FORMAT_ERROR);


reftable_buf_release(&buf); reftable_buf_release(&buf);

View File

@ -84,17 +84,17 @@ static void t_reftable_ref_record_comparison(void)
{ {
struct reftable_record in[3] = { struct reftable_record in[3] = {
{ {
.type = BLOCK_TYPE_REF, .type = REFTABLE_BLOCK_TYPE_REF,
.u.ref.refname = (char *) "refs/heads/master", .u.ref.refname = (char *) "refs/heads/master",
.u.ref.value_type = REFTABLE_REF_VAL1, .u.ref.value_type = REFTABLE_REF_VAL1,
}, },
{ {
.type = BLOCK_TYPE_REF, .type = REFTABLE_BLOCK_TYPE_REF,
.u.ref.refname = (char *) "refs/heads/master", .u.ref.refname = (char *) "refs/heads/master",
.u.ref.value_type = REFTABLE_REF_DELETION, .u.ref.value_type = REFTABLE_REF_DELETION,
}, },
{ {
.type = BLOCK_TYPE_REF, .type = REFTABLE_BLOCK_TYPE_REF,
.u.ref.refname = (char *) "HEAD", .u.ref.refname = (char *) "HEAD",
.u.ref.value_type = REFTABLE_REF_SYMREF, .u.ref.value_type = REFTABLE_REF_SYMREF,
.u.ref.value.symref = (char *) "refs/heads/master", .u.ref.value.symref = (char *) "refs/heads/master",
@ -141,10 +141,10 @@ static void t_reftable_ref_record_roundtrip(void)


for (int i = REFTABLE_REF_DELETION; i < REFTABLE_NR_REF_VALUETYPES; i++) { for (int i = REFTABLE_REF_DELETION; i < REFTABLE_NR_REF_VALUETYPES; i++) {
struct reftable_record in = { struct reftable_record in = {
.type = BLOCK_TYPE_REF, .type = REFTABLE_BLOCK_TYPE_REF,
.u.ref.value_type = i, .u.ref.value_type = i,
}; };
struct reftable_record out = { .type = BLOCK_TYPE_REF }; struct reftable_record out = { .type = REFTABLE_BLOCK_TYPE_REF };
struct reftable_buf key = REFTABLE_BUF_INIT; struct reftable_buf key = REFTABLE_BUF_INIT;
uint8_t buffer[1024] = { 0 }; uint8_t buffer[1024] = { 0 };
struct string_view dest = { struct string_view dest = {
@ -198,17 +198,17 @@ static void t_reftable_log_record_comparison(void)
{ {
struct reftable_record in[3] = { struct reftable_record in[3] = {
{ {
.type = BLOCK_TYPE_LOG, .type = REFTABLE_BLOCK_TYPE_LOG,
.u.log.refname = (char *) "refs/heads/master", .u.log.refname = (char *) "refs/heads/master",
.u.log.update_index = 42, .u.log.update_index = 42,
}, },
{ {
.type = BLOCK_TYPE_LOG, .type = REFTABLE_BLOCK_TYPE_LOG,
.u.log.refname = (char *) "refs/heads/master", .u.log.refname = (char *) "refs/heads/master",
.u.log.update_index = 22, .u.log.update_index = 22,
}, },
{ {
.type = BLOCK_TYPE_LOG, .type = REFTABLE_BLOCK_TYPE_LOG,
.u.log.refname = (char *) "refs/heads/main", .u.log.refname = (char *) "refs/heads/main",
.u.log.update_index = 22, .u.log.update_index = 22,
}, },
@ -297,7 +297,7 @@ static void t_reftable_log_record_roundtrip(void)
check(!reftable_log_record_is_deletion(&in[2])); check(!reftable_log_record_is_deletion(&in[2]));


for (size_t i = 0; i < ARRAY_SIZE(in); i++) { for (size_t i = 0; i < ARRAY_SIZE(in); i++) {
struct reftable_record rec = { .type = BLOCK_TYPE_LOG }; struct reftable_record rec = { .type = REFTABLE_BLOCK_TYPE_LOG };
struct reftable_buf key = REFTABLE_BUF_INIT; struct reftable_buf key = REFTABLE_BUF_INIT;
uint8_t buffer[1024] = { 0 }; uint8_t buffer[1024] = { 0 };
struct string_view dest = { struct string_view dest = {
@ -306,7 +306,7 @@ static void t_reftable_log_record_roundtrip(void)
}; };
/* populate out, to check for leaks. */ /* populate out, to check for leaks. */
struct reftable_record out = { struct reftable_record out = {
.type = BLOCK_TYPE_LOG, .type = REFTABLE_BLOCK_TYPE_LOG,
.u.log = { .u.log = {
.refname = xstrdup("old name"), .refname = xstrdup("old name"),
.value_type = REFTABLE_LOG_UPDATE, .value_type = REFTABLE_LOG_UPDATE,
@ -384,21 +384,21 @@ static void t_reftable_obj_record_comparison(void)
uint64_t offsets[] = { 0, 16, 32, 48, 64, 80, 96, 112}; uint64_t offsets[] = { 0, 16, 32, 48, 64, 80, 96, 112};
struct reftable_record in[3] = { struct reftable_record in[3] = {
{ {
.type = BLOCK_TYPE_OBJ, .type = REFTABLE_BLOCK_TYPE_OBJ,
.u.obj.hash_prefix = id_bytes, .u.obj.hash_prefix = id_bytes,
.u.obj.hash_prefix_len = 7, .u.obj.hash_prefix_len = 7,
.u.obj.offsets = offsets, .u.obj.offsets = offsets,
.u.obj.offset_len = 8, .u.obj.offset_len = 8,
}, },
{ {
.type = BLOCK_TYPE_OBJ, .type = REFTABLE_BLOCK_TYPE_OBJ,
.u.obj.hash_prefix = id_bytes, .u.obj.hash_prefix = id_bytes,
.u.obj.hash_prefix_len = 7, .u.obj.hash_prefix_len = 7,
.u.obj.offsets = offsets, .u.obj.offsets = offsets,
.u.obj.offset_len = 5, .u.obj.offset_len = 5,
}, },
{ {
.type = BLOCK_TYPE_OBJ, .type = REFTABLE_BLOCK_TYPE_OBJ,
.u.obj.hash_prefix = id_bytes, .u.obj.hash_prefix = id_bytes,
.u.obj.hash_prefix_len = 5, .u.obj.hash_prefix_len = 5,
}, },
@ -450,13 +450,13 @@ static void t_reftable_obj_record_roundtrip(void)
.len = sizeof(buffer), .len = sizeof(buffer),
}; };
struct reftable_record in = { struct reftable_record in = {
.type = BLOCK_TYPE_OBJ, .type = REFTABLE_BLOCK_TYPE_OBJ,
.u = { .u = {
.obj = recs[i], .obj = recs[i],
}, },
}; };
struct reftable_buf key = REFTABLE_BUF_INIT; struct reftable_buf key = REFTABLE_BUF_INIT;
struct reftable_record out = { .type = BLOCK_TYPE_OBJ }; struct reftable_record out = { .type = REFTABLE_BLOCK_TYPE_OBJ };
int n, m; int n, m;
uint8_t extra; uint8_t extra;


@ -482,17 +482,17 @@ static void t_reftable_index_record_comparison(void)
{ {
struct reftable_record in[3] = { struct reftable_record in[3] = {
{ {
.type = BLOCK_TYPE_INDEX, .type = REFTABLE_BLOCK_TYPE_INDEX,
.u.idx.offset = 22, .u.idx.offset = 22,
.u.idx.last_key = REFTABLE_BUF_INIT, .u.idx.last_key = REFTABLE_BUF_INIT,
}, },
{ {
.type = BLOCK_TYPE_INDEX, .type = REFTABLE_BLOCK_TYPE_INDEX,
.u.idx.offset = 32, .u.idx.offset = 32,
.u.idx.last_key = REFTABLE_BUF_INIT, .u.idx.last_key = REFTABLE_BUF_INIT,
}, },
{ {
.type = BLOCK_TYPE_INDEX, .type = REFTABLE_BLOCK_TYPE_INDEX,
.u.idx.offset = 32, .u.idx.offset = 32,
.u.idx.last_key = REFTABLE_BUF_INIT, .u.idx.last_key = REFTABLE_BUF_INIT,
}, },
@ -523,7 +523,7 @@ static void t_reftable_index_record_comparison(void)
static void t_reftable_index_record_roundtrip(void) static void t_reftable_index_record_roundtrip(void)
{ {
struct reftable_record in = { struct reftable_record in = {
.type = BLOCK_TYPE_INDEX, .type = REFTABLE_BLOCK_TYPE_INDEX,
.u.idx = { .u.idx = {
.offset = 42, .offset = 42,
.last_key = REFTABLE_BUF_INIT, .last_key = REFTABLE_BUF_INIT,
@ -537,7 +537,7 @@ static void t_reftable_index_record_roundtrip(void)
struct reftable_buf scratch = REFTABLE_BUF_INIT; struct reftable_buf scratch = REFTABLE_BUF_INIT;
struct reftable_buf key = REFTABLE_BUF_INIT; struct reftable_buf key = REFTABLE_BUF_INIT;
struct reftable_record out = { struct reftable_record out = {
.type = BLOCK_TYPE_INDEX, .type = REFTABLE_BLOCK_TYPE_INDEX,
.u.idx = { .last_key = REFTABLE_BUF_INIT }, .u.idx = { .last_key = REFTABLE_BUF_INIT },
}; };
int n, m; int n, m;

View File

@ -12,9 +12,9 @@ https://developers.google.com/open-source/licenses/bsd
#include "lib-reftable.h" #include "lib-reftable.h"
#include "dir.h" #include "dir.h"
#include "reftable/merged.h" #include "reftable/merged.h"
#include "reftable/reader.h"
#include "reftable/reftable-error.h" #include "reftable/reftable-error.h"
#include "reftable/stack.h" #include "reftable/stack.h"
#include "reftable/table.h"
#include "strbuf.h" #include "strbuf.h"
#include "tempfile.h" #include "tempfile.h"
#include <dirent.h> #include <dirent.h>
@ -176,7 +176,7 @@ static void t_reftable_stack_add_one(void)
err = reftable_stack_read_ref(st, ref.refname, &dest); err = reftable_stack_read_ref(st, ref.refname, &dest);
check(!err); check(!err);
check(reftable_ref_record_equal(&ref, &dest, REFTABLE_HASH_SIZE_SHA1)); check(reftable_ref_record_equal(&ref, &dest, REFTABLE_HASH_SIZE_SHA1));
check_int(st->readers_len, >, 0); check_int(st->tables_len, >, 0);


#ifndef GIT_WINDOWS_NATIVE #ifndef GIT_WINDOWS_NATIVE
check(!reftable_buf_addstr(&scratch, dir)); check(!reftable_buf_addstr(&scratch, dir));
@ -189,7 +189,7 @@ static void t_reftable_stack_add_one(void)
check(!reftable_buf_addstr(&scratch, dir)); check(!reftable_buf_addstr(&scratch, dir));
check(!reftable_buf_addstr(&scratch, "/")); check(!reftable_buf_addstr(&scratch, "/"));
/* do not try at home; not an external API for reftable. */ /* do not try at home; not an external API for reftable. */
check(!reftable_buf_addstr(&scratch, st->readers[0]->name)); check(!reftable_buf_addstr(&scratch, st->tables[0]->name));
err = stat(scratch.buf, &stat_result); err = stat(scratch.buf, &stat_result);
check(!err); check(!err);
check_int((stat_result.st_mode & 0777), ==, opts.default_permissions); check_int((stat_result.st_mode & 0777), ==, opts.default_permissions);
@ -402,9 +402,9 @@ static void t_reftable_stack_transaction_api_performs_auto_compaction(void)
* all tables in the stack. * all tables in the stack.
*/ */
if (i != n) if (i != n)
check_int(st->merged->readers_len, ==, i + 1); check_int(st->merged->tables_len, ==, i + 1);
else else
check_int(st->merged->readers_len, ==, 1); check_int(st->merged->tables_len, ==, 1);
} }


reftable_stack_destroy(st); reftable_stack_destroy(st);
@ -430,7 +430,7 @@ static void t_reftable_stack_auto_compaction_fails_gracefully(void)


err = reftable_stack_add(st, write_test_ref, &ref); err = reftable_stack_add(st, write_test_ref, &ref);
check(!err); check(!err);
check_int(st->merged->readers_len, ==, 1); check_int(st->merged->tables_len, ==, 1);
check_int(st->stats.attempts, ==, 0); check_int(st->stats.attempts, ==, 0);
check_int(st->stats.failures, ==, 0); check_int(st->stats.failures, ==, 0);


@ -441,14 +441,14 @@ static void t_reftable_stack_auto_compaction_fails_gracefully(void)
*/ */
check(!reftable_buf_addstr(&table_path, dir)); check(!reftable_buf_addstr(&table_path, dir));
check(!reftable_buf_addstr(&table_path, "/")); check(!reftable_buf_addstr(&table_path, "/"));
check(!reftable_buf_addstr(&table_path, st->readers[0]->name)); check(!reftable_buf_addstr(&table_path, st->tables[0]->name));
check(!reftable_buf_addstr(&table_path, ".lock")); check(!reftable_buf_addstr(&table_path, ".lock"));
write_file_buf(table_path.buf, "", 0); write_file_buf(table_path.buf, "", 0);


ref.update_index = 2; ref.update_index = 2;
err = reftable_stack_add(st, write_test_ref, &ref); err = reftable_stack_add(st, write_test_ref, &ref);
check(!err); check(!err);
check_int(st->merged->readers_len, ==, 2); check_int(st->merged->tables_len, ==, 2);
check_int(st->stats.attempts, ==, 1); check_int(st->stats.attempts, ==, 1);
check_int(st->stats.failures, ==, 1); check_int(st->stats.failures, ==, 1);


@ -592,7 +592,7 @@ static void t_reftable_stack_add(void)
check(!reftable_buf_addstr(&path, dir)); check(!reftable_buf_addstr(&path, dir));
check(!reftable_buf_addstr(&path, "/")); check(!reftable_buf_addstr(&path, "/"));
/* do not try at home; not an external API for reftable. */ /* do not try at home; not an external API for reftable. */
check(!reftable_buf_addstr(&path, st->readers[0]->name)); check(!reftable_buf_addstr(&path, st->tables[0]->name));
err = stat(path.buf, &stat_result); err = stat(path.buf, &stat_result);
check(!err); check(!err);
check_int((stat_result.st_mode & 0777), ==, opts.default_permissions); check_int((stat_result.st_mode & 0777), ==, opts.default_permissions);
@ -1026,7 +1026,7 @@ static void t_reftable_stack_auto_compaction(void)


err = reftable_stack_auto_compact(st); err = reftable_stack_auto_compact(st);
check(!err); check(!err);
check(i < 2 || st->merged->readers_len < 2 * fastlogN(i, 2)); check(i < 2 || st->merged->tables_len < 2 * fastlogN(i, 2));
} }


check_int(reftable_stack_compaction_stats(st)->entries_written, <, check_int(reftable_stack_compaction_stats(st)->entries_written, <,
@ -1061,7 +1061,7 @@ static void t_reftable_stack_auto_compaction_factor(void)
err = reftable_stack_add(st, &write_test_ref, &ref); err = reftable_stack_add(st, &write_test_ref, &ref);
check(!err); check(!err);


check(i < 5 || st->merged->readers_len < 5 * fastlogN(i, 5)); check(i < 5 || st->merged->tables_len < 5 * fastlogN(i, 5));
} }


reftable_stack_destroy(st); reftable_stack_destroy(st);
@ -1082,7 +1082,7 @@ static void t_reftable_stack_auto_compaction_with_locked_tables(void)
check(!err); check(!err);


write_n_ref_tables(st, 5); write_n_ref_tables(st, 5);
check_int(st->merged->readers_len, ==, 5); check_int(st->merged->tables_len, ==, 5);


/* /*
* Given that all tables we have written should be roughly the same * Given that all tables we have written should be roughly the same
@ -1091,7 +1091,7 @@ static void t_reftable_stack_auto_compaction_with_locked_tables(void)
*/ */
check(!reftable_buf_addstr(&buf, dir)); check(!reftable_buf_addstr(&buf, dir));
check(!reftable_buf_addstr(&buf, "/")); check(!reftable_buf_addstr(&buf, "/"));
check(!reftable_buf_addstr(&buf, st->readers[2]->name)); check(!reftable_buf_addstr(&buf, st->tables[2]->name));
check(!reftable_buf_addstr(&buf, ".lock")); check(!reftable_buf_addstr(&buf, ".lock"));
write_file_buf(buf.buf, "", 0); write_file_buf(buf.buf, "", 0);


@ -1104,7 +1104,7 @@ static void t_reftable_stack_auto_compaction_with_locked_tables(void)
err = reftable_stack_auto_compact(st); err = reftable_stack_auto_compact(st);
check(!err); check(!err);
check_int(st->stats.failures, ==, 0); check_int(st->stats.failures, ==, 0);
check_int(st->merged->readers_len, ==, 4); check_int(st->merged->tables_len, ==, 4);


reftable_stack_destroy(st); reftable_stack_destroy(st);
reftable_buf_release(&buf); reftable_buf_release(&buf);
@ -1149,9 +1149,9 @@ static void t_reftable_stack_add_performs_auto_compaction(void)
* all tables in the stack. * all tables in the stack.
*/ */
if (i != n) if (i != n)
check_int(st->merged->readers_len, ==, i + 1); check_int(st->merged->tables_len, ==, i + 1);
else else
check_int(st->merged->readers_len, ==, 1); check_int(st->merged->tables_len, ==, 1);
} }


reftable_stack_destroy(st); reftable_stack_destroy(st);
@ -1172,12 +1172,12 @@ static void t_reftable_stack_compaction_with_locked_tables(void)
check(!err); check(!err);


write_n_ref_tables(st, 3); write_n_ref_tables(st, 3);
check_int(st->merged->readers_len, ==, 3); check_int(st->merged->tables_len, ==, 3);


/* Lock one of the tables that we're about to compact. */ /* Lock one of the tables that we're about to compact. */
check(!reftable_buf_addstr(&buf, dir)); check(!reftable_buf_addstr(&buf, dir));
check(!reftable_buf_addstr(&buf, "/")); check(!reftable_buf_addstr(&buf, "/"));
check(!reftable_buf_addstr(&buf, st->readers[1]->name)); check(!reftable_buf_addstr(&buf, st->tables[1]->name));
check(!reftable_buf_addstr(&buf, ".lock")); check(!reftable_buf_addstr(&buf, ".lock"));
write_file_buf(buf.buf, "", 0); write_file_buf(buf.buf, "", 0);


@ -1188,7 +1188,7 @@ static void t_reftable_stack_compaction_with_locked_tables(void)
err = reftable_stack_compact_all(st, NULL); err = reftable_stack_compact_all(st, NULL);
check_int(err, ==, REFTABLE_LOCK_ERROR); check_int(err, ==, REFTABLE_LOCK_ERROR);
check_int(st->stats.failures, ==, 1); check_int(st->stats.failures, ==, 1);
check_int(st->merged->readers_len, ==, 3); check_int(st->merged->tables_len, ==, 3);


reftable_stack_destroy(st); reftable_stack_destroy(st);
reftable_buf_release(&buf); reftable_buf_release(&buf);
@ -1222,10 +1222,10 @@ static void t_reftable_stack_compaction_concurrent(void)
static void unclean_stack_close(struct reftable_stack *st) static void unclean_stack_close(struct reftable_stack *st)
{ {
/* break abstraction boundary to simulate unclean shutdown. */ /* break abstraction boundary to simulate unclean shutdown. */
for (size_t i = 0; i < st->readers_len; i++) for (size_t i = 0; i < st->tables_len; i++)
reftable_reader_decref(st->readers[i]); reftable_table_decref(st->tables[i]);
st->readers_len = 0; st->tables_len = 0;
REFTABLE_FREE_AND_NULL(st->readers); REFTABLE_FREE_AND_NULL(st->tables);
} }


static void t_reftable_stack_compaction_concurrent_clean(void) static void t_reftable_stack_compaction_concurrent_clean(void)
@ -1275,7 +1275,7 @@ static void t_reftable_stack_read_across_reload(void)
err = reftable_new_stack(&st1, dir, &opts); err = reftable_new_stack(&st1, dir, &opts);
check(!err); check(!err);
write_n_ref_tables(st1, 2); write_n_ref_tables(st1, 2);
check_int(st1->merged->readers_len, ==, 2); check_int(st1->merged->tables_len, ==, 2);
reftable_stack_init_ref_iterator(st1, &it); reftable_stack_init_ref_iterator(st1, &it);
err = reftable_iterator_seek_ref(&it, ""); err = reftable_iterator_seek_ref(&it, "");
check(!err); check(!err);
@ -1283,10 +1283,10 @@ static void t_reftable_stack_read_across_reload(void)
/* Set up a second stack for the same directory and compact it. */ /* Set up a second stack for the same directory and compact it. */
err = reftable_new_stack(&st2, dir, &opts); err = reftable_new_stack(&st2, dir, &opts);
check(!err); check(!err);
check_int(st2->merged->readers_len, ==, 2); check_int(st2->merged->tables_len, ==, 2);
err = reftable_stack_compact_all(st2, NULL); err = reftable_stack_compact_all(st2, NULL);
check(!err); check(!err);
check_int(st2->merged->readers_len, ==, 1); check_int(st2->merged->tables_len, ==, 1);


/* /*
* Verify that we can continue to use the old iterator even after we * Verify that we can continue to use the old iterator even after we
@ -1294,7 +1294,7 @@ static void t_reftable_stack_read_across_reload(void)
*/ */
err = reftable_stack_reload(st1); err = reftable_stack_reload(st1);
check(!err); check(!err);
check_int(st1->merged->readers_len, ==, 1); check_int(st1->merged->tables_len, ==, 1);
err = reftable_iterator_next_ref(&it, &rec); err = reftable_iterator_next_ref(&it, &rec);
check(!err); check(!err);
check_str(rec.refname, "refs/heads/branch-0000"); check_str(rec.refname, "refs/heads/branch-0000");
@ -1325,19 +1325,19 @@ static void t_reftable_stack_reload_with_missing_table(void)
err = reftable_new_stack(&st, dir, &opts); err = reftable_new_stack(&st, dir, &opts);
check(!err); check(!err);
write_n_ref_tables(st, 2); write_n_ref_tables(st, 2);
check_int(st->merged->readers_len, ==, 2); check_int(st->merged->tables_len, ==, 2);
reftable_stack_init_ref_iterator(st, &it); reftable_stack_init_ref_iterator(st, &it);
err = reftable_iterator_seek_ref(&it, ""); err = reftable_iterator_seek_ref(&it, "");
check(!err); check(!err);


/* /*
* Update the tables.list file with some garbage data, while reusing * Update the tables.list file with some garbage data, while reusing
* our old readers. This should trigger a partial reload of the stack, * our old tables. This should trigger a partial reload of the stack,
* where we try to reuse our old readers. * where we try to reuse our old tables.
*/ */
check(!reftable_buf_addstr(&content, st->readers[0]->name)); check(!reftable_buf_addstr(&content, st->tables[0]->name));
check(!reftable_buf_addstr(&content, "\n")); check(!reftable_buf_addstr(&content, "\n"));
check(!reftable_buf_addstr(&content, st->readers[1]->name)); check(!reftable_buf_addstr(&content, st->tables[1]->name));
check(!reftable_buf_addstr(&content, "\n")); check(!reftable_buf_addstr(&content, "\n"));
check(!reftable_buf_addstr(&content, "garbage\n")); check(!reftable_buf_addstr(&content, "garbage\n"));
check(!reftable_buf_addstr(&table_path, st->list_file)); check(!reftable_buf_addstr(&table_path, st->list_file));
@ -1348,7 +1348,7 @@ static void t_reftable_stack_reload_with_missing_table(void)


err = reftable_stack_reload(st); err = reftable_stack_reload(st);
check_int(err, ==, -4); check_int(err, ==, -4);
check_int(st->merged->readers_len, ==, 2); check_int(st->merged->tables_len, ==, 2);


/* /*
* Even though the reload has failed, we should be able to continue * Even though the reload has failed, we should be able to continue

View File

@ -0,0 +1,206 @@
#include "test-lib.h"
#include "lib-reftable.h"
#include "reftable/blocksource.h"
#include "reftable/constants.h"
#include "reftable/iter.h"
#include "reftable/table.h"
#include "strbuf.h"

static int t_table_seek_once(void)
{
struct reftable_ref_record records[] = {
{
.refname = (char *) "refs/heads/main",
.value_type = REFTABLE_REF_VAL1,
.value.val1 = { 42 },
},
};
struct reftable_block_source source = { 0 };
struct reftable_ref_record ref = { 0 };
struct reftable_iterator it = { 0 };
struct reftable_table *table;
struct reftable_buf buf = REFTABLE_BUF_INIT;
int ret;

t_reftable_write_to_buf(&buf, records, ARRAY_SIZE(records), NULL, 0, NULL);
block_source_from_buf(&source, &buf);

ret = reftable_table_new(&table, &source, "name");
check(!ret);

reftable_table_init_ref_iterator(table, &it);
ret = reftable_iterator_seek_ref(&it, "");
check(!ret);
ret = reftable_iterator_next_ref(&it, &ref);
check(!ret);

ret = reftable_ref_record_equal(&ref, &records[0], REFTABLE_HASH_SIZE_SHA1);
check_int(ret, ==, 1);

ret = reftable_iterator_next_ref(&it, &ref);
check_int(ret, ==, 1);

reftable_ref_record_release(&ref);
reftable_iterator_destroy(&it);
reftable_table_decref(table);
reftable_buf_release(&buf);
return 0;
}

static int t_table_reseek(void)
{
struct reftable_ref_record records[] = {
{
.refname = (char *) "refs/heads/main",
.value_type = REFTABLE_REF_VAL1,
.value.val1 = { 42 },
},
};
struct reftable_block_source source = { 0 };
struct reftable_ref_record ref = { 0 };
struct reftable_iterator it = { 0 };
struct reftable_table *table;
struct reftable_buf buf = REFTABLE_BUF_INIT;
int ret;

t_reftable_write_to_buf(&buf, records, ARRAY_SIZE(records), NULL, 0, NULL);
block_source_from_buf(&source, &buf);

ret = reftable_table_new(&table, &source, "name");
check(!ret);

reftable_table_init_ref_iterator(table, &it);

for (size_t i = 0; i < 5; i++) {
ret = reftable_iterator_seek_ref(&it, "");
check(!ret);
ret = reftable_iterator_next_ref(&it, &ref);
check(!ret);

ret = reftable_ref_record_equal(&ref, &records[0], REFTABLE_HASH_SIZE_SHA1);
check_int(ret, ==, 1);

ret = reftable_iterator_next_ref(&it, &ref);
check_int(ret, ==, 1);
}

reftable_ref_record_release(&ref);
reftable_iterator_destroy(&it);
reftable_table_decref(table);
reftable_buf_release(&buf);
return 0;
}

static int t_table_block_iterator(void)
{
struct reftable_block_source source = { 0 };
struct reftable_table_iterator it = { 0 };
struct reftable_ref_record *records;
const struct reftable_block *block;
struct reftable_table *table;
struct reftable_buf buf = REFTABLE_BUF_INIT;
struct {
uint8_t block_type;
uint16_t header_off;
uint16_t restart_count;
uint16_t record_count;
} expected_blocks[] = {
{
.block_type = REFTABLE_BLOCK_TYPE_REF,
.header_off = 24,
.restart_count = 10,
.record_count = 158,
},
{
.block_type = REFTABLE_BLOCK_TYPE_REF,
.restart_count = 10,
.record_count = 159,
},
{
.block_type = REFTABLE_BLOCK_TYPE_REF,
.restart_count = 10,
.record_count = 159,
},
{
.block_type = REFTABLE_BLOCK_TYPE_REF,
.restart_count = 2,
.record_count = 24,
},
{
.block_type = REFTABLE_BLOCK_TYPE_INDEX,
.restart_count = 1,
.record_count = 4,
},
{
.block_type = REFTABLE_BLOCK_TYPE_OBJ,
.restart_count = 1,
.record_count = 1,
},
};
const size_t nrecords = 500;
int ret;

REFTABLE_CALLOC_ARRAY(records, nrecords);
for (size_t i = 0; i < nrecords; i++) {
records[i].value_type = REFTABLE_REF_VAL1;
records[i].refname = xstrfmt("refs/heads/branch-%03"PRIuMAX,
(uintmax_t) i);
}

t_reftable_write_to_buf(&buf, records, nrecords, NULL, 0, NULL);
block_source_from_buf(&source, &buf);

ret = reftable_table_new(&table, &source, "name");
check(!ret);

ret = reftable_table_iterator_init(&it, table);
check(!ret);

for (size_t i = 0; i < ARRAY_SIZE(expected_blocks); i++) {
struct reftable_iterator record_it = { 0 };
struct reftable_record record = {
.type = expected_blocks[i].block_type,
};

ret = reftable_table_iterator_next(&it, &block);
check(!ret);

check_int(block->block_type, ==, expected_blocks[i].block_type);
check_int(block->header_off, ==, expected_blocks[i].header_off);
check_int(block->restart_count, ==, expected_blocks[i].restart_count);

ret = reftable_block_init_iterator(block, &record_it);
check(!ret);

for (size_t j = 0; ; j++) {
ret = iterator_next(&record_it, &record);
if (ret > 0) {
check_int(j, ==, expected_blocks[i].record_count);
break;
}
check(!ret);
}

reftable_iterator_destroy(&record_it);
reftable_record_release(&record);
}

ret = reftable_table_iterator_next(&it, &block);
check_int(ret, ==, 1);

for (size_t i = 0; i < nrecords; i++)
reftable_free(records[i].refname);
reftable_table_iterator_release(&it);
reftable_table_decref(table);
reftable_buf_release(&buf);
reftable_free(records);
return 0;
}

int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
{
TEST(t_table_seek_once(), "table can seek once");
TEST(t_table_reseek(), "table can reseek multiple times");
TEST(t_table_block_iterator(), "table can iterate through blocks");
return test_done();
}