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 */
static unsigned char out[1024*1024];
z_stream z;
struct z_stream_s z;
int ret;

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 out[25 * 1024 * 1024];
int len;
z_stream z;
struct z_stream_s z;
int ret;

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-merged
UNIT_TEST_PROGRAMS += t-reftable-pq
UNIT_TEST_PROGRAMS += t-reftable-reader
UNIT_TEST_PROGRAMS += t-reftable-readwrite
UNIT_TEST_PROGRAMS += t-reftable-record
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_OBJS += $(UNIT_TEST_DIR)/test-lib.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/merged.o
REFTABLE_OBJS += reftable/pq.o
REFTABLE_OBJS += reftable/reader.o
REFTABLE_OBJS += reftable/record.o
REFTABLE_OBJS += reftable/stack.o
REFTABLE_OBJS += reftable/system.o
REFTABLE_OBJS += reftable/table.o
REFTABLE_OBJS += reftable/tree.o
REFTABLE_OBJS += reftable/writer.o


View File

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

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

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


View File

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

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

View File

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

View File

@ -1,10 +1,10 @@
/*
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
*/
* 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
*/

#define REFTABLE_ALLOW_BANNED_ALLOCATORS
#include "basics.h"

View File

@ -1,10 +1,10 @@
/*
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
*/
* 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 BASICS_H
#define BASICS_H
@ -18,13 +18,6 @@ https://developers.google.com/open-source/licenses/bsd

#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
* using REFTABLE_BUF_INIT for stack-allocated variables.

View File

@ -1,15 +1,16 @@
/*
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
*/
* 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
*/

#include "block.h"

#include "blocksource.h"
#include "constants.h"
#include "iter.h"
#include "record.h"
#include "reftable-error.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
* 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;
uLongf src_len = w->next - block_header_skip, compressed_len;
int ret;
@ -210,61 +211,86 @@ int block_writer_finish(struct block_writer *w)
return w->next;
}

int block_reader_init(struct block_reader *br, struct reftable_block *block,
uint32_t header_off, uint32_t table_block_size,
uint32_t hash_size)
static int read_block(struct reftable_block_source *source,
struct reftable_block_data *dest, uint64_t off,
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;
uint8_t typ = block->data[header_off];
uint32_t sz = reftable_get_be24(block->data + header_off + 1);
int err = 0;
uint16_t restart_count = 0;
uint32_t restart_start = 0;
uint8_t *restart_bytes = NULL;
uint16_t restart_count;
uint32_t restart_off;
uint32_t block_size;
uint8_t block_type;
int err;

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)) {
err = REFTABLE_FORMAT_ERROR;
block_type = block->block_data.data[header_size];
if (!reftable_is_block_type(block_type)) {
err = REFTABLE_FORMAT_ERROR;
goto done;
}

if (typ == BLOCK_TYPE_LOG) {
uint32_t block_header_skip = 4 + header_off;
uLong dst_len = sz - block_header_skip;
uLong src_len = block->len - block_header_skip;
block_size = reftable_get_be24(block->block_data.data + header_size + 1);
if (block_size > guess_block_size) {
err = read_block(source, &block->block_data, offset, block_size);
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. */
REFTABLE_ALLOC_GROW_OR_NULL(br->uncompressed_data, sz,
br->uncompressed_cap);
if (!br->uncompressed_data) {
REFTABLE_ALLOC_GROW_OR_NULL(block->uncompressed_data, block_size,
block->uncompressed_cap);
if (!block->uncompressed_data) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}

/* 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) {
REFTABLE_CALLOC_ARRAY(br->zstream, 1);
if (!br->zstream) {
if (!block->zstream) {
REFTABLE_CALLOC_ARRAY(block->zstream, 1);
if (!block->zstream) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}

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

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

/*
* 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
* 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) {
err = REFTABLE_ZLIB_ERROR;
goto done;
}
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;
goto done;
}

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

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

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

br->hash_size = hash_size;
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;
err = 0;

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

void block_reader_release(struct block_reader *br)
void reftable_block_release(struct reftable_block *block)
{
inflateEnd(br->zstream);
reftable_free(br->zstream);
reftable_free(br->uncompressed_data);
reftable_block_done(&br->block);
inflateEnd(block->zstream);
reftable_free(block->zstream);
reftable_free(block->uncompressed_data);
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 = {
.buf = br->block.data + off,
.len = br->block_len - off,
.buf = block->block_data.data + off,
.len = block->restart_off - off,
};
uint8_t extra = 0;

@ -353,33 +378,36 @@ int block_reader_first_key(const struct block_reader *br, struct reftable_buf *k
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);
it->next_off = br->header_off + 4;
it->next_off = it->block->header_off + 4;
}

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

static int restart_needle_less(size_t idx, void *_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 = {
.buf = args->reader->block.data + off,
.len = args->reader->block_len - off,
.buf = args->block->block_data.data + off,
.len = args->block->restart_off - off,
};
uint64_t prefix_len, suffix_len;
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)
{
struct string_view in = {
.buf = (unsigned char *) it->block + it->next_off,
.len = it->block_len - it->next_off,
.buf = (unsigned char *) it->block->block_data.data + it->next_off,
.len = it->block->restart_off - it->next_off,
};
struct string_view start = in;
uint8_t extra = 0;
int n = 0;

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

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;

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);
if (n < 0)
return -1;
@ -444,8 +472,6 @@ void block_iter_reset(struct block_iter *it)
reftable_buf_reset(&it->last_key);
it->next_off = 0;
it->block = NULL;
it->block_len = 0;
it->hash_size = 0;
}

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);
}

int block_iter_seek_key(struct block_iter *it, const struct block_reader *br,
struct reftable_buf *want)
int block_iter_seek_key(struct block_iter *it, struct reftable_buf *want)
{
struct restart_needle_less_args args = {
.needle = *want,
.reader = br,
.block = it->block,
};
struct reftable_record rec;
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
* 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) {
err = REFTABLE_FORMAT_ERROR;
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.
*/
if (i > 0)
it->next_off = block_reader_restart_offset(br, i - 1);
it->next_off = block_restart_offset(it->block, i - 1);
else
it->next_off = br->header_off + 4;
it->block = br->block.data;
it->block_len = br->block_len;
it->hash_size = br->hash_size;
it->next_off = it->block->header_off + 4;

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

/*
* 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
* 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
* far and then back up.
*/
@ -561,6 +583,61 @@ done:
return err;
}

static int block_iter_seek_void(void *it, struct reftable_record *want)
{
struct reftable_buf buf = REFTABLE_BUF_INIT;
struct block_iter *bi = it;
int err;

if (bi->block->block_type != want->type)
return REFTABLE_API_ERROR;

err = reftable_record_key(want, &buf);
if (err < 0)
goto out;

err = block_iter_seek_key(it, &buf);
if (err < 0)
goto out;

err = 0;

out:
reftable_buf_release(&buf);
return err;
}

static int block_iter_next_void(void *it, struct reftable_record *rec)
{
return block_iter_next(it, rec);
}

static void block_iter_close_void(void *it)
{
block_iter_close(it);
}

static struct reftable_iterator_vtable block_iter_vtable = {
.seek = &block_iter_seek_void,
.next = &block_iter_next_void,
.close = &block_iter_close_void,
};

int reftable_block_init_iterator(const struct reftable_block *b,
struct reftable_iterator *it)
{
struct block_iter *bi;

REFTABLE_CALLOC_ARRAY(bi, 1);
block_iter_init(bi, b);

assert(!it->ops);
it->iter_arg = bi;
it->ops = &block_iter_vtable;

return 0;
}

void block_writer_release(struct block_writer *bw)
{
deflateEnd(bw->zstream);
@ -571,14 +648,3 @@ void block_writer_release(struct block_writer *bw)
reftable_buf_release(&bw->last_key);
/* 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,16 +1,17 @@
/*
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
*/
* 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 BLOCK_H
#define BLOCK_H

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

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

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

struct z_stream;

/* 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 */
/* Iterator for records contained in a single block. */
struct block_iter {
/* offset within the block of the next entry to read. */
uint32_t next_off;
const unsigned char *block;
size_t block_len;
uint32_t hash_size;
const struct reftable_block *block;

/* key for last entry we read. */
struct reftable_buf last_key;
@ -120,12 +79,23 @@ struct block_iter {
.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 */
int block_iter_seek_key(struct block_iter *it, const struct block_reader *br,
struct reftable_buf *want);
/* Position the initialized iterator at the first record of its block. */
void block_iter_seek_start(struct block_iter *it);

/*
* 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. */
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_t footer_size(int version);

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

#endif

View File

@ -1,10 +1,10 @@
/*
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
*/
* 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
*/

#include "system.h"

@ -13,7 +13,42 @@ https://developers.google.com/open-source/licenses/bsd
#include "reftable-blocksource.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)
memset(dest->data, 0xff, dest->len);
@ -24,8 +59,8 @@ static void reftable_buf_close(void *b REFTABLE_UNUSED)
{
}

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

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

@ -67,7 +102,7 @@ static uint64_t file_size(void *b)
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,8 +113,8 @@ static void file_close(void *v)
reftable_free(b);
}

static ssize_t file_read_block(void *v, struct reftable_block *dest, uint64_t off,
uint32_t size)
static ssize_t file_read_data(void *v, struct reftable_block_data *dest, uint64_t off,
uint32_t size)
{
struct file_block_source *b = v;
assert(off + size <= b->size);
@ -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 = {
.size = &file_size,
.read_block = &file_read_block,
.return_block = &file_return_block,
.read_data = &file_read_data,
.release_data = &file_release_data,
.close = &file_close,
};


View File

@ -1,10 +1,10 @@
/*
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
*/
* 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 BLOCKSOURCE_H
#define BLOCKSOURCE_H
@ -12,9 +12,34 @@ https://developers.google.com/open-source/licenses/bsd
#include "system.h"

struct reftable_block_source;
struct reftable_block_data;
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,
struct reftable_buf *buf);


View File

@ -1,19 +1,15 @@
/*
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
*/
* 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 CONSTANTS_H
#define CONSTANTS_H

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

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

View File

@ -1,10 +1,10 @@
/*
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
*/
* 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
*/

#include "system.h"
#include "reftable-error.h"

View File

@ -1,19 +1,20 @@
/*
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
*/
* 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
*/

#include "iter.h"

#include "system.h"

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

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;
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_buf_release(&it->oid);
}
@ -127,11 +128,10 @@ static int indexed_table_ref_iter_next_block(struct indexed_table_ref_iter *it)
return 1;
}

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

off = it->offsets[it->offset_idx++];
err = reader_init_block_reader(it->r, &it->block_reader, off,
BLOCK_TYPE_REF);
err = table_init_block(it->table, &it->block, off, REFTABLE_BLOCK_TYPE_REF);
if (err < 0) {
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. */
return REFTABLE_FORMAT_ERROR;
}
block_iter_seek_start(&it->cur, &it->block_reader);
block_iter_init(&it->cur, &it->block);
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,
struct reftable_reader *r, uint8_t *oid,
struct reftable_table *t, uint8_t *oid,
int oid_len, uint64_t *offsets, int offset_len)
{
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->r = r;
itr->table = t;

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

View File

@ -1,10 +1,10 @@
/*
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
*/
* 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 ITER_H
#define ITER_H
@ -59,7 +59,7 @@ void iterator_from_filtering_ref_iterator(struct reftable_iterator *,
* but using the object index.
*/
struct indexed_table_ref_iter {
struct reftable_reader *r;
struct reftable_table *table;
struct reftable_buf oid;

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

/* Takes ownership of `offsets` */
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);

#endif

View File

@ -1,21 +1,21 @@
/*
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
*/
* 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
*/

#include "merged.h"

#include "constants.h"
#include "iter.h"
#include "pq.h"
#include "reader.h"
#include "record.h"
#include "reftable-merged.h"
#include "reftable-error.h"
#include "system.h"
#include "table.h"

struct merged_subiter {
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,
struct reftable_reader **readers, size_t n,
struct reftable_table **tables, size_t n,
enum reftable_hash hash_id)
{
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;

for (size_t i = 0; i < n; i++) {
uint64_t min = reftable_reader_min_update_index(readers[i]);
uint64_t max = reftable_reader_max_update_index(readers[i]);
uint64_t min = reftable_table_min_update_index(tables[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;
}
if (i == 0 || min < first_min) {
@ -218,8 +218,8 @@ int reftable_merged_table_new(struct reftable_merged_table **dest,
if (!m)
return REFTABLE_OUT_OF_MEMORY_ERROR;

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

if (mt->readers_len) {
REFTABLE_CALLOC_ARRAY(subiters, mt->readers_len);
if (mt->tables_len) {
REFTABLE_CALLOC_ARRAY(subiters, mt->tables_len);
if (!subiters) {
ret = REFTABLE_OUT_OF_MEMORY_ERROR;
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);
if (ret < 0)
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)
goto out;
}
@ -280,14 +280,14 @@ int merged_table_init_iter(struct reftable_merged_table *mt,
mi->advance_index = -1;
mi->suppress_deletions = mt->suppress_deletions;
mi->subiters = subiters;
mi->subiters_len = mt->readers_len;
mi->subiters_len = mt->tables_len;

iterator_from_merged_iter(it, mi);
ret = 0;

out:
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_record_release(&subiters[i].rec);
}
@ -301,13 +301,13 @@ out:
int reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
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,
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)

View File

@ -1,10 +1,10 @@
/*
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
*/
* 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 MERGED_H
#define MERGED_H
@ -13,8 +13,8 @@ https://developers.google.com/open-source/licenses/bsd
#include "reftable-basics.h"

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

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

View File

@ -1,10 +1,10 @@
/*
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
*/
* 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
*/

#include "pq.h"


View File

@ -1,10 +1,10 @@
/*
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
*/
* 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 PQ_H
#define 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,10 +1,10 @@
/*
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
*/
* 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
*/

/* 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)
{
switch (typ) {
case BLOCK_TYPE_REF:
case BLOCK_TYPE_LOG:
case BLOCK_TYPE_OBJ:
case BLOCK_TYPE_INDEX:
case REFTABLE_BLOCK_TYPE_REF:
case REFTABLE_BLOCK_TYPE_LOG:
case REFTABLE_BLOCK_TYPE_OBJ:
case REFTABLE_BLOCK_TYPE_INDEX:
return 1;
}
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 = {
.key = &reftable_ref_record_key,
.type = BLOCK_TYPE_REF,
.type = REFTABLE_BLOCK_TYPE_REF,
.copy_from = &reftable_ref_record_copy_from,
.val_type = &reftable_ref_record_val_type,
.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 = {
.key = &reftable_obj_record_key,
.type = BLOCK_TYPE_OBJ,
.type = REFTABLE_BLOCK_TYPE_OBJ,
.copy_from = &reftable_obj_record_copy_from,
.val_type = &reftable_obj_record_val_type,
.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 = {
.key = &reftable_log_record_key,
.type = BLOCK_TYPE_LOG,
.type = REFTABLE_BLOCK_TYPE_LOG,
.copy_from = &reftable_log_record_copy_from,
.val_type = &reftable_log_record_val_type,
.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 = {
.key = &reftable_index_record_key,
.type = BLOCK_TYPE_INDEX,
.type = REFTABLE_BLOCK_TYPE_INDEX,
.copy_from = &reftable_index_record_copy_from,
.val_type = &reftable_index_record_val_type,
.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)
{
switch (rec->type) {
case BLOCK_TYPE_REF:
case REFTABLE_BLOCK_TYPE_REF:
return &rec->u.ref;
case BLOCK_TYPE_LOG:
case REFTABLE_BLOCK_TYPE_LOG:
return &rec->u.log;
case BLOCK_TYPE_INDEX:
case REFTABLE_BLOCK_TYPE_INDEX:
return &rec->u.idx;
case BLOCK_TYPE_OBJ:
case REFTABLE_BLOCK_TYPE_OBJ:
return &rec->u.obj;
}
abort();
@ -1291,13 +1291,13 @@ static struct reftable_record_vtable *
reftable_record_vtable(struct reftable_record *rec)
{
switch (rec->type) {
case BLOCK_TYPE_REF:
case REFTABLE_BLOCK_TYPE_REF:
return &reftable_ref_record_vtable;
case BLOCK_TYPE_LOG:
case REFTABLE_BLOCK_TYPE_LOG:
return &reftable_log_record_vtable;
case BLOCK_TYPE_INDEX:
case REFTABLE_BLOCK_TYPE_INDEX:
return &reftable_index_record_vtable;
case BLOCK_TYPE_OBJ:
case REFTABLE_BLOCK_TYPE_OBJ:
return &reftable_obj_record_vtable;
}
abort();
@ -1309,11 +1309,11 @@ int reftable_record_init(struct reftable_record *rec, uint8_t typ)
rec->type = typ;

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

View File

@ -1,10 +1,10 @@
/*
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
*/
* 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 RECORD_H
#define RECORD_H

View File

@ -4,13 +4,21 @@
* 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_BASICS_H
#define REFTABLE_BASICS_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
* 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,17 +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
*/
* 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_BLOCKSOURCE_H
#define REFTABLE_BLOCKSOURCE_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_vtable *ops;
@ -20,7 +21,7 @@ struct reftable_block_source {

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

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

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

/* mark the block as read; may return the data back to malloc */
void (*return_block)(void *source, struct reftable_block *blockp);
/* Mark the block as read; may release the data. */
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);
};


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,10 +1,10 @@
/*
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
*/
* 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_ERROR_H
#define REFTABLE_ERROR_H

View File

@ -1,10 +1,10 @@
/*
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
*/
* 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_ITERATOR_H
#define REFTABLE_ITERATOR_H

View File

@ -1,10 +1,10 @@
/*
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
*/
* 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_MERGED_H
#define 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. */
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.
*/
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);

/* 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,10 +1,10 @@
/*
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
*/
* 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_RECORD_H
#define REFTABLE_RECORD_H

View File

@ -1,10 +1,10 @@
/*
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
*/
* 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_STACK_H
#define 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,10 +1,10 @@
/*
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
*/
* 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_WRITER_H
#define REFTABLE_WRITER_H

View File

@ -1,20 +1,20 @@
/*
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
*/
* 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
*/

#include "stack.h"

#include "system.h"
#include "constants.h"
#include "merged.h"
#include "reader.h"
#include "reftable-error.h"
#include "reftable-record.h"
#include "reftable-merged.h"
#include "table.h"
#include "writer.h"

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)
{
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,
struct reftable_iterator *it)
{
return merged_table_init_iter(reftable_stack_merged_table(st),
it, BLOCK_TYPE_LOG);
it, REFTABLE_BLOCK_TYPE_LOG);
}

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

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

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

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

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

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

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

static struct reftable_reader **stack_copy_readers(struct reftable_stack *st,
size_t cur_len)
static struct reftable_table **stack_copy_tables(struct reftable_stack *st,
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)
return NULL;
for (size_t i = 0; i < cur_len; i++)
cur[i] = st->readers[i];
cur[i] = st->tables[i];
return cur;
}

@ -299,19 +299,19 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
const char **names,
int reuse_open)
{
size_t cur_len = !st->merged ? 0 : st->merged->readers_len;
struct reftable_reader **cur = NULL;
struct reftable_reader **reused = NULL;
struct reftable_reader **new_readers = NULL;
size_t cur_len = !st->merged ? 0 : st->merged->tables_len;
struct reftable_table **cur = NULL;
struct reftable_table **reused = NULL;
struct reftable_table **new_tables = NULL;
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_buf table_path = REFTABLE_BUF_INIT;
int err = 0;
size_t i;

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

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

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

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

/*
* When reloading the stack fails, we end up
* releasing all new readers. This also
* includes the reused readers, even though
* releasing all new tables. This also
* includes the reused tables, even though
* they are still in used by the old stack. We
* thus need to keep them alive here, which we
* 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;
goto done;
}
reused[reused_len++] = rd;
reftable_reader_incref(rd);
reused[reused_len++] = table;
reftable_table_incref(table);
break;
}
}

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

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

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

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

/* success! */
err = reftable_merged_table_new(&new_merged, new_readers,
new_readers_len, st->opts.hash_id);
err = reftable_merged_table_new(&new_merged, new_tables,
new_tables_len, st->opts.hash_id);
if (err < 0)
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
* 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.
*/
for (i = 0; i < cur_len; 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);
if (err < 0)
goto done;

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

if (st->readers)
reftable_free(st->readers);
st->readers = new_readers;
st->readers_len = new_readers_len;
new_readers = NULL;
new_readers_len = 0;
if (st->tables)
reftable_free(st->tables);
st->tables = new_tables;
st->tables_len = new_tables_len;
new_tables = NULL;
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
* decrement their refcount via `new_readers`.
* decrement their refcount via `new_tables`.
*/
for (i = 0; i < reused_len; i++)
reftable_reader_decref(reused[i]);
reftable_table_decref(reused[i]);

done:
for (i = 0; i < new_readers_len; i++)
reftable_reader_decref(new_readers[i]);
reftable_free(new_readers);
for (i = 0; i < new_tables_len; i++)
reftable_table_decref(new_tables[i]);
reftable_free(new_tables);
reftable_free(reused);
reftable_free(cur);
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
* case, we have to refresh when the loaded stack has
* any readers.
* any tables.
*/
if (errno == ENOENT)
return !!st->readers_len;
return !!st->tables_len;
return REFTABLE_IO_ERROR;
}

@ -637,19 +637,19 @@ static int stack_uptodate(struct reftable_stack *st)
if (err < 0)
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]) {
err = 1;
goto done;
}

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

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

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

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)
return reftable_reader_max_update_index(st->readers[sz - 1]) +
return reftable_table_max_update_index(st->tables[sz - 1]) +
1;
return 1;
}
@ -1021,8 +1021,8 @@ static int stack_compact_locked(struct reftable_stack *st,
struct reftable_tmpfile tab_file = REFTABLE_TMPFILE_INIT;
int err = 0;

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

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

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

@ -1126,7 +1126,7 @@ static int stack_write_compact(struct reftable_stack *st,
}
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)
goto done;

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

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)
goto done;

@ -1376,7 +1376,7 @@ static int stack_compact_range(struct reftable_stack *st,
* compacted in the updated "tables.list" file.
*/
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;

/*
@ -1386,8 +1386,8 @@ static int stack_compact_range(struct reftable_stack *st,
* have compacted them.
*/
for (size_t j = 1; j < last - first + 1; j++) {
const char *old = first + j < st->merged->readers_len ?
st->readers[first + j]->name : NULL;
const char *old = first + j < st->merged->tables_len ?
st->tables[first + j]->name : NULL;
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
* the array is at its end. As we use `free_names()` to free
* 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) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}

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

@ -1559,7 +1559,7 @@ done:
int reftable_stack_compact_all(struct reftable_stack *st,
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);
}

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

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

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

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

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

sizes = stack_table_sizes_for_compaction(st);
if (!sizes)
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);
reftable_free(sizes);

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

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)
goto done;

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

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

if (update_idx <= max) {
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))
continue;

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


View File

@ -1,10 +1,10 @@
/*
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
*/
* 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 STACK_H
#define STACK_H
@ -22,8 +22,8 @@ struct reftable_stack {

struct reftable_write_options opts;

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

View File

@ -1,10 +1,10 @@
/*
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
*/
* 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 SYSTEM_H
#define 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
* license that can be found in the LICENSE file or at
* https://developers.google.com/open-source/licenses/bsd
*/

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

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

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

uint64_t block_source_size(struct reftable_block_source *source)
{
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)
static struct reftable_table_offsets *
table_offsets_for(struct reftable_table *t, uint8_t typ)
{
switch (typ) {
case BLOCK_TYPE_REF:
return &r->ref_offsets;
case BLOCK_TYPE_LOG:
return &r->log_offsets;
case BLOCK_TYPE_OBJ:
return &r->obj_offsets;
case REFTABLE_BLOCK_TYPE_REF:
return &t->ref_offsets;
case REFTABLE_BLOCK_TYPE_LOG:
return &t->log_offsets;
case REFTABLE_BLOCK_TYPE_OBJ:
return &t->obj_offsets;
}
abort();
}

static int reader_get_block(struct reftable_reader *r,
struct reftable_block *dest, uint64_t off,
uint32_t sz)
enum reftable_hash reftable_table_hash_id(struct reftable_table *t)
{
ssize_t bytes_read;
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;
return t->hash_id;
}

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)
{
return r->name;
}

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

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

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

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

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

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

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

r->object_id_len = r->obj_offsets.offset & ((1 << 5) - 1);
r->obj_offsets.offset >>= 5;
t->object_id_len = t->obj_offsets.offset & ((1 << 5) - 1);
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;
r->log_offsets.offset = reftable_get_be64(f);
t->log_offsets.offset = reftable_get_be64(f);
f += 8;
r->log_offsets.index_offset = reftable_get_be64(f);
t->log_offsets.index_offset = reftable_get_be64(f);
f += 8;

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

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

struct table_iter {
struct reftable_reader *r;
struct reftable_table *table;
uint8_t typ;
uint64_t block_off;
struct block_reader br;
struct reftable_block block;
struct block_iter bi;
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;
memset(ti, 0, sizeof(*ti));
reftable_reader_incref(r);
ti->r = r;
reftable_table_incref(t);
ti->table = t;
ti->bi = bi;
return 0;
}
@ -190,8 +150,8 @@ static int table_iter_next_in_block(struct table_iter *ti,
struct reftable_record *rec)
{
int res = block_iter_next(&ti->bi, rec);
if (res == 0 && reftable_record_type(rec) == BLOCK_TYPE_REF) {
rec->u.ref.update_index += ti->r->min_update_index;
if (res == 0 && reftable_record_type(rec) == REFTABLE_BLOCK_TYPE_REF) {
rec->u.ref.update_index += ti->table->min_update_index;
}

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)
{
block_reader_release(&ti->br);
reftable_block_release(&ti->block);
block_iter_reset(&ti->bi);
}

static int32_t extract_block_size(uint8_t *data, uint8_t *typ, uint64_t off,
int version)
int table_init_block(struct reftable_table *t, struct reftable_block *block,
uint64_t next_off, uint8_t want_typ)
{
int32_t result = 0;
uint32_t header_off = next_off ? 0 : header_size(t->version);
int err;

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)
{
int32_t guess_block_size = r->block_size ? r->block_size :
DEFAULT_BLOCK_SIZE;
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;

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)
goto done;

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

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

@ -268,15 +192,15 @@ static void table_iter_close(struct table_iter *ti)
{
table_iter_block_done(ti);
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)
{
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;

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)
ti->is_finished = 1;
if (err)
@ -284,7 +208,7 @@ static int table_iter_next_block(struct table_iter *ti)

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

return 0;
}
@ -326,27 +250,27 @@ static int table_iter_seek_to(struct table_iter *ti, uint64_t off, uint8_t typ)
{
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)
return err;

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

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;
if (index) {
off = offs->index_offset;
if (off == 0) {
return 1;
}
typ = BLOCK_TYPE_INDEX;
typ = REFTABLE_BLOCK_TYPE_INDEX;
}

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
* we would not do a linear search there anymore.
*/
memset(&next.br.block, 0, sizeof(next.br.block));
next.br.zstream = NULL;
next.br.uncompressed_data = NULL;
next.br.uncompressed_cap = 0;
memset(&next.block.block_data, 0, sizeof(next.block.block_data));
next.block.zstream = NULL;
next.block.uncompressed_data = NULL;
next.block.uncompressed_cap = 0;

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

err = block_reader_first_key(&next.br, &got_key);
err = reftable_block_first_key(&next.block, &got_key);
if (err < 0)
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
* 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)
goto done;
err = 0;
@ -441,10 +366,10 @@ static int table_iter_seek_indexed(struct table_iter *ti,
struct reftable_record *rec)
{
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 = {
.type = BLOCK_TYPE_INDEX,
.type = REFTABLE_BLOCK_TYPE_INDEX,
.u.idx = { .last_key = REFTABLE_BUF_INIT },
};
int err;
@ -493,7 +418,9 @@ static int table_iter_seek_indexed(struct table_iter *ti,
if (err != 0)
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)
goto done;

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

if (ti->typ != BLOCK_TYPE_INDEX) {
if (ti->typ != REFTABLE_BLOCK_TYPE_INDEX) {
err = REFTABLE_FORMAT_ERROR;
goto done;
}
@ -518,7 +445,7 @@ static int table_iter_seek(struct table_iter *ti,
struct reftable_record *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;

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;
}

int reader_init_iter(struct reftable_reader *r,
struct reftable_iterator *it,
uint8_t typ)
int table_init_iter(struct reftable_table *t,
struct reftable_iterator *it,
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) {
struct table_iter *ti;
@ -578,7 +505,7 @@ int reader_init_iter(struct reftable_reader *r,
if (!ti)
return REFTABLE_OUT_OF_MEMORY_ERROR;

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

int reftable_reader_init_ref_iterator(struct reftable_reader *r,
struct reftable_iterator *it)
int reftable_table_init_ref_iterator(struct reftable_table *t,
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,
struct reftable_iterator *it)
int reftable_table_init_log_iterator(struct reftable_table *t,
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,
struct reftable_block_source *source, char const *name)
int reftable_table_new(struct reftable_table **out,
struct reftable_block_source *source, char const *name)
{
struct reftable_block footer = { 0 };
struct reftable_block header = { 0 };
struct reftable_reader *r;
struct reftable_block_data footer = { 0 };
struct reftable_block_data header = { 0 };
struct reftable_table *t;
uint64_t file_size = block_source_size(source);
uint32_t read_size;
ssize_t bytes_read;
int err;

REFTABLE_CALLOC_ARRAY(r, 1);
if (!r) {
REFTABLE_CALLOC_ARRAY(t, 1);
if (!t) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
@ -626,7 +553,7 @@ int reftable_reader_new(struct reftable_reader **out,
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) {
err = REFTABLE_IO_ERROR;
goto done;
@ -636,84 +563,84 @@ int reftable_reader_new(struct reftable_reader **out,
err = REFTABLE_FORMAT_ERROR;
goto done;
}
r->version = header.data[4];
if (r->version != 1 && r->version != 2) {
t->version = header.data[4];
if (t->version != 1 && t->version != 2) {
err = REFTABLE_FORMAT_ERROR;
goto done;
}

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

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

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

*out = r;
*out = t;

done:
reftable_block_done(&footer);
reftable_block_done(&header);
block_source_release_data(&footer);
block_source_release_data(&header);
if (err) {
if (r)
reftable_free(r->name);
reftable_free(r);
if (t)
reftable_free(t->name);
reftable_free(t);
block_source_close(source);
}
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;
if (--r->refcount)
if (--t->refcount)
return;
block_source_close(&r->source);
REFTABLE_FREE_AND_NULL(r->name);
reftable_free(r);
block_source_close(&t->source);
REFTABLE_FREE_AND_NULL(t->name);
reftable_free(t);
}

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

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

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

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 */
iterator_set_empty(it);
err = 0;
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.offset_len);
if (err < 0)
@ -748,14 +675,14 @@ done:
return err;
}

static int reftable_reader_refs_for_unindexed(struct reftable_reader *r,
struct reftable_iterator *it,
uint8_t *oid)
static int reftable_table_refs_for_unindexed(struct reftable_table *t,
struct reftable_iterator *it,
uint8_t *oid)
{
struct table_iter *ti;
struct filtering_ref_iterator *filter = NULL;
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;

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

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

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

int reftable_reader_refs_for(struct reftable_reader *r,
struct reftable_iterator *it, uint8_t *oid)
int reftable_table_refs_for(struct reftable_table *t,
struct reftable_iterator *it, uint8_t *oid)
{
if (r->obj_offsets.is_present)
return reftable_reader_refs_for_indexed(r, it, oid);
return reftable_reader_refs_for_unindexed(r, it, oid);
if (t->obj_offsets.is_present)
return reftable_table_refs_for_indexed(t, 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 {
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;
struct table_iter *ti;
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)
goto done;
goto out;

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

out:
if (err < 0)
goto done;

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);
reftable_free(ti);
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,10 +1,10 @@
/*
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
*/
* 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
*/

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

View File

@ -1,10 +1,10 @@
/*
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
*/
* 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 TREE_H
#define TREE_H

View File

@ -1,10 +1,10 @@
/*
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
*/
* 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
*/

#include "writer.h"

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

*out = wp;

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

max_level++;
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)
return err;

@ -544,7 +544,7 @@ static int writer_finish_section(struct reftable_writer *w)
w->index_cap = 0;
for (i = 0; i < idx_len; i++) {
struct reftable_record rec = {
.type = BLOCK_TYPE_INDEX,
.type = REFTABLE_BLOCK_TYPE_INDEX,
.u = {
.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 obj_index_tree_node *entry = key;
struct reftable_record
rec = { .type = BLOCK_TYPE_OBJ,
rec = { .type = REFTABLE_BLOCK_TYPE_OBJ,
.u.obj = {
.hash_prefix = (uint8_t *)entry->hash.buf,
.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)
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)
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);
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)
return err;

@ -708,7 +708,7 @@ static int writer_finish_public_section(struct reftable_writer *w)
err = writer_finish_section(w);
if (err < 0)
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) {
err = writer_dump_object_index(w);
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
* 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;

bstats = writer_reftable_block_stats(w, typ);

View File

@ -1,10 +1,10 @@
/*
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
*/
* 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 WRITER_H
#define WRITER_H

View File

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

static void print_help(void)
@ -20,6 +21,72 @@ static void print_help(void)
"\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)
{
struct reftable_iterator it = { NULL };
@ -126,19 +193,19 @@ static int dump_reftable(const char *tablename)
{
struct reftable_block_source src = { 0 };
struct reftable_merged_table *mt = NULL;
struct reftable_reader *r = NULL;
struct reftable_table *table = NULL;
int err;

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

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

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

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

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

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

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

View File

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

foreach unit_test_program : unit_test_programs

View File

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

View File

@ -19,24 +19,25 @@ static void t_ref_block_read_write(void)
struct reftable_record recs[30];
const size_t N = ARRAY_SIZE(recs);
const size_t block_size = 1024;
struct reftable_block block = { 0 };
struct reftable_block_source source = { 0 };
struct block_writer bw = {
.last_key = REFTABLE_BUF_INIT,
};
struct reftable_record rec = {
.type = BLOCK_TYPE_REF,
.type = REFTABLE_BLOCK_TYPE_REF,
};
size_t i = 0;
int ret;
struct block_reader br = { 0 };
struct reftable_block block = { 0 };
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);
check(block.data != NULL);
block.len = block_size;
block_source_from_buf(&block.source ,&buf);
ret = block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
REFTABLE_CALLOC_ARRAY(block_data.buf, block_size);
check(block_data.buf != NULL);
block_data.len = 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));
check(!ret);

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

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++) {
ret = block_iter_next(&it, &rec);
@ -77,10 +79,9 @@ static void t_ref_block_read_write(void)
}

for (i = 0; i < N; i++) {
block_iter_reset(&it);
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);

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

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

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));
}

block_reader_release(&br);
reftable_block_release(&block);
block_iter_close(&it);
reftable_record_release(&rec);
reftable_block_done(&br.block);
reftable_buf_release(&want);
reftable_buf_release(&buf);
reftable_buf_release(&block_data);
for (i = 0; i < N; i++)
reftable_record_release(&recs[i]);
}
@ -113,24 +113,25 @@ static void t_log_block_read_write(void)
struct reftable_record recs[30];
const size_t N = ARRAY_SIZE(recs);
const size_t block_size = 2048;
struct reftable_block block = { 0 };
struct reftable_block_source source = { 0 };
struct block_writer bw = {
.last_key = REFTABLE_BUF_INIT,
};
struct reftable_record rec = {
.type = BLOCK_TYPE_LOG,
.type = REFTABLE_BLOCK_TYPE_LOG,
};
size_t i = 0;
int ret;
struct block_reader br = { 0 };
struct reftable_block block = { 0 };
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);
check(block.data != NULL);
block.len = block_size;
block_source_from_buf(&block.source ,&buf);
ret = block_writer_init(&bw, BLOCK_TYPE_LOG, block.data, block_size,
REFTABLE_CALLOC_ARRAY(block_data.buf, block_size);
check(block_data.buf != NULL);
block_data.len = 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));
check(!ret);

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

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++) {
ret = block_iter_next(&it, &rec);
@ -166,11 +168,10 @@ static void t_log_block_read_write(void)
}

for (i = 0; i < N; i++) {
block_iter_reset(&it);
reftable_buf_reset(&want);
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);

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

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

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));
}

block_reader_release(&br);
reftable_block_release(&block);
block_iter_close(&it);
reftable_record_release(&rec);
reftable_block_done(&br.block);
reftable_buf_release(&want);
reftable_buf_release(&buf);
reftable_buf_release(&block_data);
for (i = 0; i < N; i++)
reftable_record_release(&recs[i]);
}
@ -203,24 +203,25 @@ static void t_obj_block_read_write(void)
struct reftable_record recs[30];
const size_t N = ARRAY_SIZE(recs);
const size_t block_size = 1024;
struct reftable_block block = { 0 };
struct reftable_block_source source = { 0 };
struct block_writer bw = {
.last_key = REFTABLE_BUF_INIT,
};
struct reftable_record rec = {
.type = BLOCK_TYPE_OBJ,
.type = REFTABLE_BLOCK_TYPE_OBJ,
};
size_t i = 0;
int ret;
struct block_reader br = { 0 };
struct reftable_block block = { 0 };
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);
check(block.data != NULL);
block.len = block_size;
block_source_from_buf(&block.source, &buf);
ret = block_writer_init(&bw, BLOCK_TYPE_OBJ, block.data, block_size,
REFTABLE_CALLOC_ARRAY(block_data.buf, block_size);
check(block_data.buf != NULL);
block_data.len = 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));
check(!ret);

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

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++) {
ret = block_iter_next(&it, &rec);
@ -258,10 +260,9 @@ static void t_obj_block_read_write(void)
}

for (i = 0; i < N; i++) {
block_iter_reset(&it);
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);

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));
}

block_reader_release(&br);
reftable_block_release(&block);
block_iter_close(&it);
reftable_record_release(&rec);
reftable_block_done(&br.block);
reftable_buf_release(&want);
reftable_buf_release(&buf);
reftable_buf_release(&block_data);
for (i = 0; i < N; i++)
reftable_record_release(&recs[i]);
}
@ -286,25 +286,26 @@ static void t_index_block_read_write(void)
struct reftable_record recs[30];
const size_t N = ARRAY_SIZE(recs);
const size_t block_size = 1024;
struct reftable_block block = { 0 };
struct reftable_block_source source = { 0 };
struct block_writer bw = {
.last_key = REFTABLE_BUF_INIT,
};
struct reftable_record rec = {
.type = BLOCK_TYPE_INDEX,
.type = REFTABLE_BLOCK_TYPE_INDEX,
.u.idx.last_key = REFTABLE_BUF_INIT,
};
size_t i = 0;
int ret;
struct block_reader br = { 0 };
struct reftable_block block = { 0 };
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);
check(block.data != NULL);
block.len = block_size;
block_source_from_buf(&block.source, &buf);
ret = block_writer_init(&bw, BLOCK_TYPE_INDEX, block.data, block_size,
REFTABLE_CALLOC_ARRAY(block_data.buf, block_size);
check(block_data.buf != NULL);
block_data.len = 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));
check(!ret);

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

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));
recs[i].u.idx.offset = i;

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

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++) {
ret = block_iter_next(&it, &rec);
@ -342,10 +344,9 @@ static void t_index_block_read_write(void)
}

for (i = 0; i < N; i++) {
block_iter_reset(&it);
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);

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

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

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));
}

block_reader_release(&br);
reftable_block_release(&block);
block_iter_close(&it);
reftable_record_release(&rec);
reftable_block_done(&br.block);
reftable_buf_release(&want);
reftable_buf_release(&buf);
reftable_buf_release(&block_data);
for (i = 0; i < N; 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)
{
TEST(t_index_block_read_write(), "read-write operations on index blocks work");
TEST(t_log_block_read_write(), "read-write operations on log blocks work");
TEST(t_obj_block_read_write(), "read-write operations on obj blocks work");
TEST(t_ref_block_read_write(), "read-write operations on ref blocks work");
TEST(t_block_iterator(), "block iterator works");

return test_done();
}

View File

@ -11,7 +11,7 @@ https://developers.google.com/open-source/licenses/bsd
#include "reftable/blocksource.h"
#include "reftable/constants.h"
#include "reftable/merged.h"
#include "reftable/reader.h"
#include "reftable/table.h"
#include "reftable/reftable-error.h"
#include "reftable/reftable-merged.h"
#include "reftable/reftable-writer.h"
@ -19,7 +19,7 @@ https://developers.google.com/open-source/licenses/bsd
static struct reftable_merged_table *
merged_table_from_records(struct reftable_ref_record **refs,
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_merged_table *mt = NULL;
@ -28,8 +28,8 @@ merged_table_from_records(struct reftable_ref_record **refs,
};
int err;

REFTABLE_CALLOC_ARRAY(*readers, n);
check(*readers != NULL);
REFTABLE_CALLOC_ARRAY(*tables, n);
check(*tables != NULL);
REFTABLE_CALLOC_ARRAY(*source, n);
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);
block_source_from_buf(&(*source)[i], &buf[i]);

err = reftable_reader_new(&(*readers)[i], &(*source)[i],
"name");
err = reftable_table_new(&(*tables)[i], &(*source)[i],
"name");
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);
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++)
reftable_reader_decref(readers[i]);
reftable_free(readers);
reftable_table_decref(tables[i]);
reftable_free(tables);
}

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) };
struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT };
struct reftable_block_source *bs = NULL;
struct reftable_reader **readers = NULL;
struct reftable_table **tables = NULL;
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_iterator it = { 0 };
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);
err = reftable_iterator_seek_ref(&it, "a");
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));
reftable_ref_record_release(&ref);
reftable_iterator_destroy(&it);
readers_destroy(readers, 3);
tables_destroy(tables, 3);
reftable_merged_table_free(mt);
for (size_t i = 0; i < ARRAY_SIZE(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) };
struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT };
struct reftable_block_source *bs = NULL;
struct reftable_reader **readers = NULL;
struct reftable_table **tables = NULL;
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 };
int err;
struct reftable_ref_record *out = NULL;
@ -164,7 +164,7 @@ static void t_merged_refs(void)
size_t cap = 0;
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);
err = reftable_iterator_seek_ref(&it, "a");
check(!err);
@ -193,7 +193,7 @@ static void t_merged_refs(void)

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

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

for (size_t i = 0; i < 5; i++) {
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++)
reftable_buf_release(&bufs[i]);
readers_destroy(readers, ARRAY_SIZE(refs));
tables_destroy(tables, ARRAY_SIZE(refs));
reftable_ref_record_release(&rec);
reftable_iterator_destroy(&it);
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,
};
struct reftable_block_source *sources = NULL;
struct reftable_reader **readers = NULL;
struct reftable_table **tables = NULL;
struct reftable_ref_record rec = { 0 };
struct reftable_iterator it = { 0 };
struct reftable_merged_table *mt;
int err;

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

err = reftable_iterator_seek_ref(&it, "b");
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++)
reftable_buf_release(&bufs[i]);
readers_destroy(readers, ARRAY_SIZE(refs));
tables_destroy(tables, ARRAY_SIZE(refs));
reftable_ref_record_release(&rec);
reftable_iterator_destroy(&it);
reftable_merged_table_free(mt);
@ -348,7 +348,7 @@ static void t_merged_seek_multiple_times_without_draining(void)
static struct reftable_merged_table *
merged_table_from_log_records(struct reftable_log_record **logs,
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_merged_table *mt = NULL;
@ -358,8 +358,8 @@ merged_table_from_log_records(struct reftable_log_record **logs,
};
int err;

REFTABLE_CALLOC_ARRAY(*readers, n);
check(*readers != NULL);
REFTABLE_CALLOC_ARRAY(*tables, n);
check(*tables != NULL);
REFTABLE_CALLOC_ARRAY(*source, n);
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);
block_source_from_buf(&(*source)[i], &buf[i]);

err = reftable_reader_new(&(*readers)[i], &(*source)[i],
"name");
err = reftable_table_new(&(*tables)[i], &(*source)[i],
"name");
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);
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) };
struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT };
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(
logs, &bs, &readers, sizes, bufs, 3);
logs, &bs, &tables, sizes, bufs, 3);
struct reftable_iterator it = { 0 };
int err;
struct reftable_log_record *out = NULL;
@ -445,7 +445,7 @@ static void t_merged_logs(void)
size_t cap = 0;
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);
err = reftable_iterator_seek_log(&it, "a");
check(!err);
@ -469,7 +469,7 @@ static void t_merged_logs(void)
check(reftable_log_record_equal(want[i], &out[i],
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);
err = reftable_iterator_seek_log_at(&it, "a", 2);
check(!err);
@ -485,7 +485,7 @@ static void t_merged_logs(void)

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

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

block_source_from_buf(&source, &buf);

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

hash_id = reftable_reader_hash_id(rd);
hash_id = reftable_table_hash_id(table);
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);
err = reftable_merged_table_new(&merged, &rd, 1, REFTABLE_HASH_SHA1);
err = reftable_merged_table_new(&merged, &table, 1, REFTABLE_HASH_SHA1);
check(!err);

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

View File

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

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);
}

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

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)
check_int(strcmp(last, e.rec->u.ref.refname), <, 0);
last = e.rec->u.ref.refname;
@ -76,7 +76,7 @@ static void t_pq_index(void)
size_t N = ARRAY_SIZE(recs), 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";
}

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

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);
if (last)
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;

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";
}


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 "reftable/basics.h"
#include "reftable/blocksource.h"
#include "reftable/reader.h"
#include "reftable/reftable-error.h"
#include "reftable/reftable-writer.h"
#include "reftable/table.h"
#include "strbuf.h"

static const int update_index = 5;
@ -23,22 +23,22 @@ static void t_buffer(void)
{
struct reftable_buf buf = REFTABLE_BUF_INIT;
struct reftable_block_source source = { 0 };
struct reftable_block out = { 0 };
struct reftable_block_data out = { 0 };
int n;
uint8_t in[] = "hello";
check(!reftable_buf_add(&buf, in, sizeof(in)));
block_source_from_buf(&source, &buf);
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(!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(!memcmp(out.data, "el", 2));

reftable_block_done(&out);
block_source_release_data(&out);
block_source_close(&source);
reftable_buf_release(&buf);
}
@ -204,7 +204,7 @@ static void t_log_write_read(void)
struct reftable_ref_record ref = { 0 };
struct reftable_log_record log = { 0 };
struct reftable_iterator it = { 0 };
struct reftable_reader *reader;
struct reftable_table *table;
struct reftable_block_source source = { 0 };
struct reftable_buf buf = REFTABLE_BUF_INIT;
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);

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

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

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_ref_record_release(&ref);

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

static void t_log_zlib_corruption(void)
@ -303,7 +303,7 @@ static void t_log_zlib_corruption(void)
.block_size = 256,
};
struct reftable_iterator it = { 0 };
struct reftable_reader *reader;
struct reftable_table *table;
struct reftable_block_source source = { 0 };
struct reftable_buf buf = REFTABLE_BUF_INIT;
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);

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

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

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

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

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

block_source_from_buf(&source, &buf);

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

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

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

block_source_from_buf(&source, &buf);

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

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

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

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

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

for (i = 1; i < N; i++) {
err = reftable_reader_init_ref_iterator(reader, &it);
err = reftable_table_init_ref_iterator(table, &it);
check(!err);
err = reftable_iterator_seek_ref(&it, names[i]);
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, "/"));

err = reftable_reader_init_ref_iterator(reader, &it);
err = reftable_table_init_ref_iterator(table, &it);
check(!err);
err = reftable_iterator_seek_ref(&it, pastLast.buf);
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);
free_names(names);
reftable_reader_decref(reader);
reftable_table_decref(table);
}

static void t_table_read_write_seek_linear(void)
@ -535,7 +535,7 @@ static void t_table_refs_for(int indexed)
.block_size = 256,
};
struct reftable_ref_record ref = { 0 };
struct reftable_reader *reader;
struct reftable_table *table;
struct reftable_block_source source = { 0 };
struct reftable_buf buf = REFTABLE_BUF_INIT;
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);

err = reftable_reader_new(&reader, &source, "file.ref");
err = reftable_table_new(&table, &source, "file.ref");
check(!err);
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);
err = reftable_iterator_seek_ref(&it, "");
check(!err);
reftable_iterator_destroy(&it);

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

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

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_writer *w = t_reftable_strbuf_writer(&buf, &opts);
struct reftable_block_source source = { 0 };
struct reftable_reader *rd = NULL;
struct reftable_table *table = NULL;
struct reftable_ref_record rec = { 0 };
struct reftable_iterator it = { 0 };
int err;
@ -647,10 +647,10 @@ static void t_write_empty_table(void)

block_source_from_buf(&source, &buf);

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

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

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

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

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

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

/*
* Seeking the log uses the log index now. In case there is any
* 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);
err = reftable_iterator_seek_log(&it, "");
check(!err);

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

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

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

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

/*
* 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);
err = reftable_iterator_seek_ref(&it, "refs/heads/199");
check(!err);

reftable_iterator_destroy(&it);
reftable_writer_free(writer);
reftable_reader_decref(reader);
reftable_table_decref(table);
reftable_buf_release(&writer_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_block_source source = { 0 };
struct reftable_reader *reader;
struct reftable_table *table;
int err;

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);
}

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

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

reftable_buf_release(&buf);

View File

@ -84,17 +84,17 @@ static void t_reftable_ref_record_comparison(void)
{
struct reftable_record in[3] = {
{
.type = BLOCK_TYPE_REF,
.type = REFTABLE_BLOCK_TYPE_REF,
.u.ref.refname = (char *) "refs/heads/master",
.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.value_type = REFTABLE_REF_DELETION,
},
{
.type = BLOCK_TYPE_REF,
.type = REFTABLE_BLOCK_TYPE_REF,
.u.ref.refname = (char *) "HEAD",
.u.ref.value_type = REFTABLE_REF_SYMREF,
.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++) {
struct reftable_record in = {
.type = BLOCK_TYPE_REF,
.type = REFTABLE_BLOCK_TYPE_REF,
.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;
uint8_t buffer[1024] = { 0 };
struct string_view dest = {
@ -198,17 +198,17 @@ static void t_reftable_log_record_comparison(void)
{
struct reftable_record in[3] = {
{
.type = BLOCK_TYPE_LOG,
.type = REFTABLE_BLOCK_TYPE_LOG,
.u.log.refname = (char *) "refs/heads/master",
.u.log.update_index = 42,
},
{
.type = BLOCK_TYPE_LOG,
.type = REFTABLE_BLOCK_TYPE_LOG,
.u.log.refname = (char *) "refs/heads/master",
.u.log.update_index = 22,
},
{
.type = BLOCK_TYPE_LOG,
.type = REFTABLE_BLOCK_TYPE_LOG,
.u.log.refname = (char *) "refs/heads/main",
.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]));

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;
uint8_t buffer[1024] = { 0 };
struct string_view dest = {
@ -306,7 +306,7 @@ static void t_reftable_log_record_roundtrip(void)
};
/* populate out, to check for leaks. */
struct reftable_record out = {
.type = BLOCK_TYPE_LOG,
.type = REFTABLE_BLOCK_TYPE_LOG,
.u.log = {
.refname = xstrdup("old name"),
.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};
struct reftable_record in[3] = {
{
.type = BLOCK_TYPE_OBJ,
.type = REFTABLE_BLOCK_TYPE_OBJ,
.u.obj.hash_prefix = id_bytes,
.u.obj.hash_prefix_len = 7,
.u.obj.offsets = offsets,
.u.obj.offset_len = 8,
},
{
.type = BLOCK_TYPE_OBJ,
.type = REFTABLE_BLOCK_TYPE_OBJ,
.u.obj.hash_prefix = id_bytes,
.u.obj.hash_prefix_len = 7,
.u.obj.offsets = offsets,
.u.obj.offset_len = 5,
},
{
.type = BLOCK_TYPE_OBJ,
.type = REFTABLE_BLOCK_TYPE_OBJ,
.u.obj.hash_prefix = id_bytes,
.u.obj.hash_prefix_len = 5,
},
@ -450,13 +450,13 @@ static void t_reftable_obj_record_roundtrip(void)
.len = sizeof(buffer),
};
struct reftable_record in = {
.type = BLOCK_TYPE_OBJ,
.type = REFTABLE_BLOCK_TYPE_OBJ,
.u = {
.obj = recs[i],
},
};
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;
uint8_t extra;

@ -482,17 +482,17 @@ static void t_reftable_index_record_comparison(void)
{
struct reftable_record in[3] = {
{
.type = BLOCK_TYPE_INDEX,
.type = REFTABLE_BLOCK_TYPE_INDEX,
.u.idx.offset = 22,
.u.idx.last_key = REFTABLE_BUF_INIT,
},
{
.type = BLOCK_TYPE_INDEX,
.type = REFTABLE_BLOCK_TYPE_INDEX,
.u.idx.offset = 32,
.u.idx.last_key = REFTABLE_BUF_INIT,
},
{
.type = BLOCK_TYPE_INDEX,
.type = REFTABLE_BLOCK_TYPE_INDEX,
.u.idx.offset = 32,
.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)
{
struct reftable_record in = {
.type = BLOCK_TYPE_INDEX,
.type = REFTABLE_BLOCK_TYPE_INDEX,
.u.idx = {
.offset = 42,
.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 key = REFTABLE_BUF_INIT;
struct reftable_record out = {
.type = BLOCK_TYPE_INDEX,
.type = REFTABLE_BLOCK_TYPE_INDEX,
.u.idx = { .last_key = REFTABLE_BUF_INIT },
};
int n, m;

View File

@ -12,9 +12,9 @@ https://developers.google.com/open-source/licenses/bsd
#include "lib-reftable.h"
#include "dir.h"
#include "reftable/merged.h"
#include "reftable/reader.h"
#include "reftable/reftable-error.h"
#include "reftable/stack.h"
#include "reftable/table.h"
#include "strbuf.h"
#include "tempfile.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);
check(!err);
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
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, "/"));
/* 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);
check(!err);
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.
*/
if (i != n)
check_int(st->merged->readers_len, ==, i + 1);
check_int(st->merged->tables_len, ==, i + 1);
else
check_int(st->merged->readers_len, ==, 1);
check_int(st->merged->tables_len, ==, 1);
}

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);
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.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, "/"));
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"));
write_file_buf(table_path.buf, "", 0);

ref.update_index = 2;
err = reftable_stack_add(st, write_test_ref, &ref);
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.failures, ==, 1);

@ -592,7 +592,7 @@ static void t_reftable_stack_add(void)
check(!reftable_buf_addstr(&path, dir));
check(!reftable_buf_addstr(&path, "/"));
/* 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);
check(!err);
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);
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, <,
@ -1061,7 +1061,7 @@ static void t_reftable_stack_auto_compaction_factor(void)
err = reftable_stack_add(st, &write_test_ref, &ref);
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);
@ -1082,7 +1082,7 @@ static void t_reftable_stack_auto_compaction_with_locked_tables(void)
check(!err);

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
@ -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, "/"));
check(!reftable_buf_addstr(&buf, st->readers[2]->name));
check(!reftable_buf_addstr(&buf, st->tables[2]->name));
check(!reftable_buf_addstr(&buf, ".lock"));
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);
check(!err);
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_buf_release(&buf);
@ -1149,9 +1149,9 @@ static void t_reftable_stack_add_performs_auto_compaction(void)
* all tables in the stack.
*/
if (i != n)
check_int(st->merged->readers_len, ==, i + 1);
check_int(st->merged->tables_len, ==, i + 1);
else
check_int(st->merged->readers_len, ==, 1);
check_int(st->merged->tables_len, ==, 1);
}

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

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. */
check(!reftable_buf_addstr(&buf, dir));
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"));
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);
check_int(err, ==, REFTABLE_LOCK_ERROR);
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_buf_release(&buf);
@ -1222,10 +1222,10 @@ static void t_reftable_stack_compaction_concurrent(void)
static void unclean_stack_close(struct reftable_stack *st)
{
/* break abstraction boundary to simulate unclean shutdown. */
for (size_t i = 0; i < st->readers_len; i++)
reftable_reader_decref(st->readers[i]);
st->readers_len = 0;
REFTABLE_FREE_AND_NULL(st->readers);
for (size_t i = 0; i < st->tables_len; i++)
reftable_table_decref(st->tables[i]);
st->tables_len = 0;
REFTABLE_FREE_AND_NULL(st->tables);
}

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);
check(!err);
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);
err = reftable_iterator_seek_ref(&it, "");
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. */
err = reftable_new_stack(&st2, dir, &opts);
check(!err);
check_int(st2->merged->readers_len, ==, 2);
check_int(st2->merged->tables_len, ==, 2);
err = reftable_stack_compact_all(st2, NULL);
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
@ -1294,7 +1294,7 @@ static void t_reftable_stack_read_across_reload(void)
*/
err = reftable_stack_reload(st1);
check(!err);
check_int(st1->merged->readers_len, ==, 1);
check_int(st1->merged->tables_len, ==, 1);
err = reftable_iterator_next_ref(&it, &rec);
check(!err);
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);
check(!err);
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);
err = reftable_iterator_seek_ref(&it, "");
check(!err);

/*
* Update the tables.list file with some garbage data, while reusing
* our old readers. This should trigger a partial reload of the stack,
* where we try to reuse our old readers.
* our old tables. This should trigger a partial reload of the stack,
* 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, st->readers[1]->name));
check(!reftable_buf_addstr(&content, st->tables[1]->name));
check(!reftable_buf_addstr(&content, "\n"));
check(!reftable_buf_addstr(&content, "garbage\n"));
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);
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

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();
}