Merge branch 'ps/reftable-alloc-failures'

The reftable library is now prepared to expect that the memory
allocation function given to it may fail to allocate and to deal
with such an error.

* ps/reftable-alloc-failures: (26 commits)
  reftable/basics: fix segfault when growing `names` array fails
  reftable/basics: ban standard allocator functions
  reftable: introduce `REFTABLE_FREE_AND_NULL()`
  reftable: fix calls to free(3P)
  reftable: handle trivial allocation failures
  reftable/tree: handle allocation failures
  reftable/pq: handle allocation failures when adding entries
  reftable/block: handle allocation failures
  reftable/blocksource: handle allocation failures
  reftable/iter: handle allocation failures when creating indexed table iter
  reftable/stack: handle allocation failures in auto compaction
  reftable/stack: handle allocation failures in `stack_compact_range()`
  reftable/stack: handle allocation failures in `reftable_new_stack()`
  reftable/stack: handle allocation failures on reload
  reftable/reader: handle allocation failures in `reader_init_iter()`
  reftable/reader: handle allocation failures for unindexed reader
  reftable/merged: handle allocation failures in `merged_table_init_iter()`
  reftable/writer: handle allocation failures in `reftable_new_writer()`
  reftable/writer: handle allocation failures in `writer_index_hash()`
  reftable/record: handle allocation failures when decoding records
  ...
This commit is contained in:
Junio C Hamano 2024-10-10 14:22:24 -07:00
commit 5575c713c2
38 changed files with 894 additions and 409 deletions

View file

@ -2717,7 +2717,6 @@ REFTABLE_OBJS += reftable/error.o
REFTABLE_OBJS += reftable/block.o
REFTABLE_OBJS += reftable/blocksource.o
REFTABLE_OBJS += reftable/iter.o
REFTABLE_OBJS += reftable/publicbasics.o
REFTABLE_OBJS += reftable/merged.o
REFTABLE_OBJS += reftable/pq.o
REFTABLE_OBJS += reftable/reader.o

View file

@ -1320,7 +1320,9 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
struct reftable_log_record log = {0};
struct reftable_iterator it = {0};
reftable_stack_init_log_iterator(arg->stack, &it);
ret = reftable_stack_init_log_iterator(arg->stack, &it);
if (ret < 0)
goto done;
/*
* When deleting refs we also delete all reflog entries
@ -1690,7 +1692,10 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
* copy over all log entries from the old reflog. Last but not least,
* when renaming we also have to delete all the old reflog entries.
*/
reftable_stack_init_log_iterator(arg->stack, &it);
ret = reftable_stack_init_log_iterator(arg->stack, &it);
if (ret < 0)
goto done;
ret = reftable_iterator_seek_log(&it, arg->oldname);
if (ret < 0)
goto done;
@ -1911,7 +1916,10 @@ static struct reftable_reflog_iterator *reflog_iterator_for_stack(struct reftabl
if (ret < 0)
goto done;
reftable_stack_init_log_iterator(stack, &iter->iter);
ret = reftable_stack_init_log_iterator(stack, &iter->iter);
if (ret < 0)
goto done;
ret = reftable_iterator_seek_log(&iter->iter, "");
if (ret < 0)
goto done;
@ -1978,7 +1986,10 @@ static int reftable_be_for_each_reflog_ent_reverse(struct ref_store *ref_store,
if (refs->err < 0)
return refs->err;
reftable_stack_init_log_iterator(stack, &it);
ret = reftable_stack_init_log_iterator(stack, &it);
if (ret < 0)
goto done;
ret = reftable_iterator_seek_log(&it, refname);
while (!ret) {
ret = reftable_iterator_next_log(&it, &log);
@ -1994,6 +2005,7 @@ static int reftable_be_for_each_reflog_ent_reverse(struct ref_store *ref_store,
break;
}
done:
reftable_log_record_release(&log);
reftable_iterator_destroy(&it);
return ret;
@ -2015,7 +2027,10 @@ static int reftable_be_for_each_reflog_ent(struct ref_store *ref_store,
if (refs->err < 0)
return refs->err;
reftable_stack_init_log_iterator(stack, &it);
ret = reftable_stack_init_log_iterator(stack, &it);
if (ret < 0)
goto done;
ret = reftable_iterator_seek_log(&it, refname);
while (!ret) {
struct reftable_log_record log = {0};
@ -2065,7 +2080,10 @@ static int reftable_be_reflog_exists(struct ref_store *ref_store,
if (ret < 0)
goto done;
reftable_stack_init_log_iterator(stack, &it);
ret = reftable_stack_init_log_iterator(stack, &it);
if (ret < 0)
goto done;
ret = reftable_iterator_seek_log(&it, refname);
if (ret < 0)
goto done;
@ -2171,7 +2189,9 @@ static int write_reflog_delete_table(struct reftable_writer *writer, void *cb_da
reftable_writer_set_limits(writer, ts, ts);
reftable_stack_init_log_iterator(arg->stack, &it);
ret = reftable_stack_init_log_iterator(arg->stack, &it);
if (ret < 0)
goto out;
/*
* In order to delete a table we need to delete all reflog entries one
@ -2195,6 +2215,7 @@ static int write_reflog_delete_table(struct reftable_writer *writer, void *cb_da
ret = reftable_writer_add_log(writer, &tombstone);
}
out:
reftable_log_record_release(&log);
reftable_iterator_destroy(&it);
return ret;
@ -2333,7 +2354,9 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
if (ret < 0)
goto done;
reftable_stack_init_log_iterator(stack, &it);
ret = reftable_stack_init_log_iterator(stack, &it);
if (ret < 0)
goto done;
ret = reftable_iterator_seek_log(&it, refname);
if (ret < 0)

View file

@ -6,7 +6,68 @@ 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"
#include "reftable-basics.h"
static void *(*reftable_malloc_ptr)(size_t sz);
static void *(*reftable_realloc_ptr)(void *, size_t);
static void (*reftable_free_ptr)(void *);
void *reftable_malloc(size_t sz)
{
if (reftable_malloc_ptr)
return (*reftable_malloc_ptr)(sz);
return malloc(sz);
}
void *reftable_realloc(void *p, size_t sz)
{
if (reftable_realloc_ptr)
return (*reftable_realloc_ptr)(p, sz);
return realloc(p, sz);
}
void reftable_free(void *p)
{
if (reftable_free_ptr)
reftable_free_ptr(p);
else
free(p);
}
void *reftable_calloc(size_t nelem, size_t elsize)
{
void *p;
if (nelem && elsize > SIZE_MAX / nelem)
return NULL;
p = reftable_malloc(nelem * elsize);
if (!p)
return NULL;
memset(p, 0, nelem * elsize);
return p;
}
char *reftable_strdup(const char *str)
{
size_t len = strlen(str);
char *result = reftable_malloc(len + 1);
if (!result)
return NULL;
memcpy(result, str, len + 1);
return result;
}
void reftable_set_alloc(void *(*malloc)(size_t),
void *(*realloc)(void *, size_t), void (*free)(void *))
{
reftable_malloc_ptr = malloc;
reftable_realloc_ptr = realloc;
reftable_free_ptr = free;
}
void put_be24(uint8_t *out, uint32_t i)
{
@ -75,14 +136,14 @@ size_t names_length(const char **names)
return p - names;
}
void parse_names(char *buf, int size, char ***namesp)
char **parse_names(char *buf, int size)
{
char **names = NULL;
size_t names_cap = 0;
size_t names_len = 0;
char *p = buf;
char *end = buf + size;
while (p < end) {
char *next = strchr(p, '\n');
if (next && next < end) {
@ -91,15 +152,29 @@ void parse_names(char *buf, int size, char ***namesp)
next = end;
}
if (p < next) {
REFTABLE_ALLOC_GROW(names, names_len + 1, names_cap);
names[names_len++] = xstrdup(p);
char **names_grown = names;
REFTABLE_ALLOC_GROW(names_grown, names_len + 1, names_cap);
if (!names_grown)
goto err;
names = names_grown;
names[names_len] = reftable_strdup(p);
if (!names[names_len++])
goto err;
}
p = next + 1;
}
REFTABLE_REALLOC_ARRAY(names, names_len + 1);
names[names_len] = NULL;
*namesp = names;
return names;
err:
for (size_t i = 0; i < names_len; i++)
reftable_free(names[i]);
reftable_free(names);
return NULL;
}
int names_equal(const char **a, const char **b)
@ -121,3 +196,15 @@ int common_prefix_size(struct strbuf *a, struct strbuf *b)
return p;
}
int hash_size(uint32_t id)
{
switch (id) {
case 0:
case GIT_SHA1_FORMAT_ID:
return GIT_SHA1_RAWSZ;
case GIT_SHA256_FORMAT_ID:
return GIT_SHA256_RAWSZ;
}
abort();
}

View file

@ -14,6 +14,7 @@ license that can be found in the LICENSE file or at
*/
#include "system.h"
#include "reftable-basics.h"
/* Bigendian en/decoding of integers */
@ -37,9 +38,12 @@ size_t binsearch(size_t sz, int (*f)(size_t k, void *args), void *args);
*/
void free_names(char **a);
/* parse a newline separated list of names. `size` is the length of the buffer,
* without terminating '\0'. Empty names are discarded. */
void parse_names(char *buf, int size, char ***namesp);
/*
* Parse a newline separated list of names. `size` is the length of the buffer,
* without terminating '\0'. Empty names are discarded. Returns a `NULL`
* pointer when allocations fail.
*/
char **parse_names(char *buf, int size);
/* compares two NULL-terminated arrays of strings. */
int names_equal(const char **a, const char **b);
@ -53,6 +57,7 @@ void *reftable_malloc(size_t sz);
void *reftable_realloc(void *p, size_t sz);
void reftable_free(void *p);
void *reftable_calloc(size_t nelem, size_t elsize);
char *reftable_strdup(const char *str);
#define REFTABLE_ALLOC_ARRAY(x, alloc) (x) = reftable_malloc(st_mult(sizeof(*(x)), (alloc)))
#define REFTABLE_CALLOC_ARRAY(x, alloc) (x) = reftable_calloc((alloc), sizeof(*(x)))
@ -66,9 +71,26 @@ void *reftable_calloc(size_t nelem, size_t elsize);
REFTABLE_REALLOC_ARRAY(x, alloc); \
} \
} while (0)
#define REFTABLE_FREE_AND_NULL(p) do { reftable_free(p); (p) = NULL; } while (0)
#ifndef REFTABLE_ALLOW_BANNED_ALLOCATORS
# define REFTABLE_BANNED(func) use_reftable_##func##_instead
# undef malloc
# define malloc(sz) REFTABLE_BANNED(malloc)
# undef realloc
# define realloc(ptr, sz) REFTABLE_BANNED(realloc)
# undef free
# define free(ptr) REFTABLE_BANNED(free)
# undef calloc
# define calloc(nelem, elsize) REFTABLE_BANNED(calloc)
# undef strdup
# define strdup(str) REFTABLE_BANNED(strdup)
#endif
/* Find the longest shared prefix size of `a` and `b` */
struct strbuf;
int common_prefix_size(struct strbuf *a, struct strbuf *b);
int hash_size(uint32_t id);
#endif

View file

@ -52,6 +52,8 @@ static int block_writer_register_restart(struct block_writer *w, int n,
return -1;
if (is_restart) {
REFTABLE_ALLOC_GROW(w->restarts, w->restart_len + 1, w->restart_cap);
if (!w->restarts)
return REFTABLE_OUT_OF_MEMORY_ERROR;
w->restarts[w->restart_len++] = w->next;
}
@ -63,8 +65,8 @@ static int block_writer_register_restart(struct block_writer *w, int n,
return 0;
}
void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
uint32_t block_size, uint32_t header_off, int hash_size)
int block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
uint32_t block_size, uint32_t header_off, int hash_size)
{
bw->buf = buf;
bw->hash_size = hash_size;
@ -78,8 +80,12 @@ void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
bw->last_key.len = 0;
if (!bw->zstream) {
REFTABLE_CALLOC_ARRAY(bw->zstream, 1);
if (!bw->zstream)
return REFTABLE_OUT_OF_MEMORY_ERROR;
deflateInit(bw->zstream, 9);
}
return 0;
}
uint8_t block_writer_type(struct block_writer *bw)
@ -163,6 +169,10 @@ int block_writer_finish(struct block_writer *w)
*/
compressed_len = deflateBound(w->zstream, src_len);
REFTABLE_ALLOC_GROW(w->compressed, compressed_len, w->compressed_cap);
if (!w->compressed) {
ret = REFTABLE_OUT_OF_MEMORY_ERROR;
return ret;
}
w->zstream->next_out = w->compressed;
w->zstream->avail_out = compressed_len;
@ -219,12 +229,21 @@ int block_reader_init(struct block_reader *br, struct reftable_block *block,
/* Log blocks specify the *uncompressed* size in their header. */
REFTABLE_ALLOC_GROW(br->uncompressed_data, sz,
br->uncompressed_cap);
if (!br->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);
if (!br->zstream) {
REFTABLE_CALLOC_ARRAY(br->zstream, 1);
if (!br->zstream) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
err = inflateInit(br->zstream);
} else {
err = inflateReset(br->zstream);
@ -532,9 +551,9 @@ int block_iter_seek_key(struct block_iter *it, const struct block_reader *br,
void block_writer_release(struct block_writer *bw)
{
deflateEnd(bw->zstream);
FREE_AND_NULL(bw->zstream);
FREE_AND_NULL(bw->restarts);
FREE_AND_NULL(bw->compressed);
REFTABLE_FREE_AND_NULL(bw->zstream);
REFTABLE_FREE_AND_NULL(bw->restarts);
REFTABLE_FREE_AND_NULL(bw->compressed);
strbuf_release(&bw->last_key);
/* the block is not owned. */
}

View file

@ -45,8 +45,8 @@ struct block_writer {
/*
* initializes the blockwriter to write `typ` entries, using `buf` as temporary
* storage. `buf` is not owned by the block_writer. */
void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
uint32_t block_size, uint32_t header_off, int hash_size);
int block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
uint32_t block_size, uint32_t header_off, int hash_size);
/* returns the block type (eg. 'r' for ref records. */
uint8_t block_writer_type(struct block_writer *bw);

View file

@ -30,6 +30,8 @@ static int strbuf_read_block(void *v, struct reftable_block *dest, uint64_t off,
struct strbuf *b = v;
assert(off + size <= b->len);
REFTABLE_CALLOC_ARRAY(dest->data, size);
if (!dest->data)
return -1;
memcpy(dest->data, b->buf + off, size);
dest->len = size;
return size;
@ -98,27 +100,40 @@ int reftable_block_source_from_file(struct reftable_block_source *bs,
{
struct file_block_source *p;
struct stat st;
int fd;
int fd, err;
fd = open(name, O_RDONLY);
if (fd < 0) {
if (errno == ENOENT)
return REFTABLE_NOT_EXIST_ERROR;
return -1;
err = -1;
goto out;
}
if (fstat(fd, &st) < 0) {
close(fd);
return REFTABLE_IO_ERROR;
err = REFTABLE_IO_ERROR;
goto out;
}
REFTABLE_CALLOC_ARRAY(p, 1);
if (!p) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out;
}
p->size = st.st_size;
p->data = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
assert(!bs->ops);
bs->ops = &file_vtable;
bs->arg = p;
err = 0;
out:
if (fd >= 0)
close(fd);
if (err < 0)
reftable_free(p);
return 0;
}

View file

@ -35,6 +35,8 @@ const char *reftable_error_str(int err)
return "entry too large";
case REFTABLE_OUTDATED_ERROR:
return "data concurrently modified";
case REFTABLE_OUT_OF_MEMORY_ERROR:
return "out of memory";
case -1:
return "general error";
default:

View file

@ -181,14 +181,20 @@ static int indexed_table_ref_iter_next(void *p, struct reftable_record *rec)
}
}
int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest,
struct reftable_reader *r, uint8_t *oid,
int oid_len, uint64_t *offsets, int offset_len)
{
struct indexed_table_ref_iter empty = INDEXED_TABLE_REF_ITER_INIT;
struct indexed_table_ref_iter *itr = reftable_calloc(1, sizeof(*itr));
struct indexed_table_ref_iter *itr;
int err = 0;
itr = reftable_calloc(1, sizeof(*itr));
if (!itr) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out;
}
*itr = empty;
itr->r = r;
strbuf_add(&itr->oid, oid, oid_len);
@ -197,10 +203,16 @@ int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
itr->offset_len = offset_len;
err = indexed_table_ref_iter_next_block(itr);
if (err < 0)
goto out;
*dest = itr;
err = 0;
out:
if (err < 0) {
*dest = NULL;
reftable_free(itr);
} else {
*dest = itr;
}
return err;
}
@ -225,7 +237,7 @@ void reftable_iterator_destroy(struct reftable_iterator *it)
return;
it->ops->close(it->iter_arg);
it->ops = NULL;
FREE_AND_NULL(it->iter_arg);
REFTABLE_FREE_AND_NULL(it->iter_arg);
}
int reftable_iterator_seek_ref(struct reftable_iterator *it,

View file

@ -82,7 +82,7 @@ void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it,
struct indexed_table_ref_iter *itr);
/* Takes ownership of `offsets` */
int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest,
struct reftable_reader *r, uint8_t *oid,
int oid_len, uint64_t *offsets, int offset_len);

View file

@ -30,22 +30,6 @@ struct merged_iter {
ssize_t advance_index;
};
static void merged_iter_init(struct merged_iter *mi,
struct reftable_merged_table *mt,
uint8_t typ)
{
memset(mi, 0, sizeof(*mi));
mi->advance_index = -1;
mi->suppress_deletions = mt->suppress_deletions;
REFTABLE_CALLOC_ARRAY(mi->subiters, mt->readers_len);
for (size_t i = 0; i < mt->readers_len; i++) {
reftable_record_init(&mi->subiters[i].rec, typ);
reader_init_iter(mt->readers[i], &mi->subiters[i].iter, typ);
}
mi->subiters_len = mt->readers_len;
}
static void merged_iter_close(void *p)
{
struct merged_iter *mi = p;
@ -70,7 +54,10 @@ static int merged_iter_advance_subiter(struct merged_iter *mi, size_t idx)
if (err)
return err;
merged_iter_pqueue_add(&mi->pq, &e);
err = merged_iter_pqueue_add(&mi->pq, &e);
if (err)
return err;
return 0;
}
@ -216,6 +203,9 @@ int reftable_merged_table_new(struct reftable_merged_table **dest,
}
REFTABLE_CALLOC_ARRAY(m, 1);
if (!m)
return REFTABLE_OUT_OF_MEMORY_ERROR;
m->readers = readers;
m->readers_len = n;
m->min = first_min;
@ -244,25 +234,63 @@ reftable_merged_table_min_update_index(struct reftable_merged_table *mt)
return mt->min;
}
void merged_table_init_iter(struct reftable_merged_table *mt,
struct reftable_iterator *it,
uint8_t typ)
int merged_table_init_iter(struct reftable_merged_table *mt,
struct reftable_iterator *it,
uint8_t typ)
{
struct merged_iter *mi = reftable_malloc(sizeof(*mi));
merged_iter_init(mi, mt, typ);
struct merged_subiter *subiters;
struct merged_iter *mi = NULL;
int ret;
REFTABLE_CALLOC_ARRAY(subiters, mt->readers_len);
if (!subiters) {
ret = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out;
}
for (size_t i = 0; i < mt->readers_len; i++) {
reftable_record_init(&subiters[i].rec, typ);
ret = reader_init_iter(mt->readers[i], &subiters[i].iter, typ);
if (ret < 0)
goto out;
}
REFTABLE_CALLOC_ARRAY(mi, 1);
if (!mi) {
ret = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out;
}
mi->advance_index = -1;
mi->suppress_deletions = mt->suppress_deletions;
mi->subiters = subiters;
mi->subiters_len = mt->readers_len;
iterator_from_merged_iter(it, mi);
ret = 0;
out:
if (ret < 0) {
for (size_t i = 0; subiters && i < mt->readers_len; i++) {
reftable_iterator_destroy(&subiters[i].iter);
reftable_record_release(&subiters[i].rec);
}
reftable_free(subiters);
reftable_free(mi);
}
return ret;
}
void reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
struct reftable_iterator *it)
int reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
struct reftable_iterator *it)
{
merged_table_init_iter(mt, it, BLOCK_TYPE_REF);
return merged_table_init_iter(mt, it, BLOCK_TYPE_REF);
}
void reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
struct reftable_iterator *it)
int reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
struct reftable_iterator *it)
{
merged_table_init_iter(mt, it, BLOCK_TYPE_LOG);
return merged_table_init_iter(mt, it, BLOCK_TYPE_LOG);
}
uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *mt)

View file

@ -26,8 +26,8 @@ struct reftable_merged_table {
struct reftable_iterator;
void merged_table_init_iter(struct reftable_merged_table *mt,
struct reftable_iterator *it,
uint8_t typ);
int merged_table_init_iter(struct reftable_merged_table *mt,
struct reftable_iterator *it,
uint8_t typ);
#endif

View file

@ -8,6 +8,7 @@ license that can be found in the LICENSE file or at
#include "pq.h"
#include "reftable-error.h"
#include "reftable-record.h"
#include "system.h"
#include "basics.h"
@ -44,11 +45,13 @@ struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq)
return e;
}
void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e)
int merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e)
{
size_t i = 0;
REFTABLE_ALLOC_GROW(pq->heap, pq->len + 1, pq->cap);
if (!pq->heap)
return REFTABLE_OUT_OF_MEMORY_ERROR;
pq->heap[pq->len++] = *e;
i = pq->len - 1;
@ -59,10 +62,12 @@ void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry
SWAP(pq->heap[j], pq->heap[i]);
i = j;
}
return 0;
}
void merged_iter_pqueue_release(struct merged_iter_pqueue *pq)
{
FREE_AND_NULL(pq->heap);
REFTABLE_FREE_AND_NULL(pq->heap);
memset(pq, 0, sizeof(*pq));
}

View file

@ -23,7 +23,7 @@ struct merged_iter_pqueue {
};
struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq);
void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e);
int merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e);
void merged_iter_pqueue_release(struct merged_iter_pqueue *pq);
int pq_less(struct pq_entry *a, struct pq_entry *b);

View file

@ -1,66 +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
*/
#include "system.h"
#include "reftable-malloc.h"
#include "basics.h"
static void *(*reftable_malloc_ptr)(size_t sz);
static void *(*reftable_realloc_ptr)(void *, size_t);
static void (*reftable_free_ptr)(void *);
void *reftable_malloc(size_t sz)
{
if (reftable_malloc_ptr)
return (*reftable_malloc_ptr)(sz);
return malloc(sz);
}
void *reftable_realloc(void *p, size_t sz)
{
if (reftable_realloc_ptr)
return (*reftable_realloc_ptr)(p, sz);
return realloc(p, sz);
}
void reftable_free(void *p)
{
if (reftable_free_ptr)
reftable_free_ptr(p);
else
free(p);
}
void *reftable_calloc(size_t nelem, size_t elsize)
{
size_t sz = st_mult(nelem, elsize);
void *p = reftable_malloc(sz);
memset(p, 0, sz);
return p;
}
void reftable_set_alloc(void *(*malloc)(size_t),
void *(*realloc)(void *, size_t), void (*free)(void *))
{
reftable_malloc_ptr = malloc;
reftable_realloc_ptr = realloc;
reftable_free_ptr = free;
}
int hash_size(uint32_t id)
{
switch (id) {
case 0:
case GIT_SHA1_FORMAT_ID:
return GIT_SHA1_RAWSZ;
case GIT_SHA256_FORMAT_ID:
return GIT_SHA256_RAWSZ;
}
abort();
}

View file

@ -554,32 +554,37 @@ static void iterator_from_table_iter(struct reftable_iterator *it,
it->ops = &table_iter_vtable;
}
void reader_init_iter(struct reftable_reader *r,
struct reftable_iterator *it,
uint8_t typ)
int reader_init_iter(struct reftable_reader *r,
struct reftable_iterator *it,
uint8_t typ)
{
struct reftable_reader_offsets *offs = reader_offsets_for(r, typ);
if (offs->is_present) {
struct table_iter *ti;
REFTABLE_ALLOC_ARRAY(ti, 1);
if (!ti)
return REFTABLE_OUT_OF_MEMORY_ERROR;
table_iter_init(ti, r);
iterator_from_table_iter(it, ti);
} else {
iterator_set_empty(it);
}
return 0;
}
void reftable_reader_init_ref_iterator(struct reftable_reader *r,
struct reftable_iterator *it)
int reftable_reader_init_ref_iterator(struct reftable_reader *r,
struct reftable_iterator *it)
{
reader_init_iter(r, it, BLOCK_TYPE_REF);
return reader_init_iter(r, it, BLOCK_TYPE_REF);
}
void reftable_reader_init_log_iterator(struct reftable_reader *r,
struct reftable_iterator *it)
int reftable_reader_init_log_iterator(struct reftable_reader *r,
struct reftable_iterator *it)
{
reader_init_iter(r, it, BLOCK_TYPE_LOG);
return reader_init_iter(r, it, BLOCK_TYPE_LOG);
}
int reftable_reader_new(struct reftable_reader **out,
@ -593,6 +598,10 @@ int reftable_reader_new(struct reftable_reader **out,
int err;
REFTABLE_CALLOC_ARRAY(r, 1);
if (!r) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
/*
* We need one extra byte to read the type of first block. We also
@ -622,7 +631,11 @@ int reftable_reader_new(struct reftable_reader **out,
r->size = file_size - footer_size(r->version);
r->source = *source;
r->name = xstrdup(name);
r->name = reftable_strdup(name);
if (!r->name) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
r->hash_id = 0;
r->refcount = 1;
@ -665,7 +678,7 @@ void reftable_reader_decref(struct reftable_reader *r)
if (--r->refcount)
return;
block_source_close(&r->source);
FREE_AND_NULL(r->name);
REFTABLE_FREE_AND_NULL(r->name);
reftable_free(r);
}
@ -689,7 +702,10 @@ static int reftable_reader_refs_for_indexed(struct reftable_reader *r,
struct indexed_table_ref_iter *itr = NULL;
/* Look through the reverse index. */
reader_init_iter(r, &oit, BLOCK_TYPE_OBJ);
err = reader_init_iter(r, &oit, BLOCK_TYPE_OBJ);
if (err < 0)
goto done;
err = iterator_seek(&oit, &want);
if (err != 0)
goto done;
@ -707,7 +723,7 @@ static int reftable_reader_refs_for_indexed(struct reftable_reader *r,
goto done;
}
err = new_indexed_table_ref_iter(&itr, r, oid, hash_size(r->hash_id),
err = indexed_table_ref_iter_new(&itr, r, oid, hash_size(r->hash_id),
got.u.obj.offsets,
got.u.obj.offset_len);
if (err < 0)
@ -732,21 +748,37 @@ static int reftable_reader_refs_for_unindexed(struct reftable_reader *r,
int err;
REFTABLE_ALLOC_ARRAY(ti, 1);
table_iter_init(ti, r);
err = table_iter_seek_start(ti, BLOCK_TYPE_REF, 0);
if (err < 0) {
reftable_free(ti);
return err;
if (!ti) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out;
}
filter = reftable_malloc(sizeof(struct filtering_ref_iterator));
table_iter_init(ti, r);
err = table_iter_seek_start(ti, BLOCK_TYPE_REF, 0);
if (err < 0)
goto out;
filter = reftable_malloc(sizeof(*filter));
if (!filter) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out;
}
*filter = empty;
strbuf_add(&filter->oid, oid, oid_len);
iterator_from_table_iter(&filter->it, ti);
iterator_from_filtering_ref_iterator(it, filter);
return 0;
err = 0;
out:
if (err < 0) {
if (ti)
table_iter_close(ti);
reftable_free(ti);
}
return err;
}
int reftable_reader_refs_for(struct reftable_reader *r,

View file

@ -56,9 +56,9 @@ struct reftable_reader {
const char *reader_name(struct reftable_reader *r);
void reader_init_iter(struct reftable_reader *r,
struct reftable_iterator *it,
uint8_t typ);
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,

View file

@ -215,13 +215,14 @@ static void reftable_ref_record_key(const void *r, struct strbuf *dest)
strbuf_addstr(dest, rec->refname);
}
static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
int hash_size)
static int reftable_ref_record_copy_from(void *rec, const void *src_rec,
int hash_size)
{
struct reftable_ref_record *ref = rec;
const struct reftable_ref_record *src = src_rec;
char *refname = NULL;
size_t refname_cap = 0;
int err;
assert(hash_size > 0);
@ -236,6 +237,11 @@ static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
REFTABLE_ALLOC_GROW(ref->refname, refname_len + 1,
ref->refname_cap);
if (!ref->refname) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out;
}
memcpy(ref->refname, src->refname, refname_len);
ref->refname[refname_len] = 0;
}
@ -254,9 +260,17 @@ static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
src->value.val2.target_value, hash_size);
break;
case REFTABLE_REF_SYMREF:
ref->value.symref = xstrdup(src->value.symref);
ref->value.symref = reftable_strdup(src->value.symref);
if (!ref->value.symref) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out;
}
break;
}
err = 0;
out:
return err;
}
static void reftable_ref_record_release_void(void *rec)
@ -345,7 +359,7 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
uint64_t update_index = 0;
const char *refname = NULL;
size_t refname_cap = 0;
int n;
int n, err;
assert(hash_size > 0);
@ -361,6 +375,10 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
SWAP(r->refname_cap, refname_cap);
REFTABLE_ALLOC_GROW(r->refname, key.len + 1, r->refname_cap);
if (!r->refname) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
memcpy(r->refname, key.buf, key.len);
r->refname[key.len] = 0;
@ -369,7 +387,8 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
switch (val_type) {
case REFTABLE_REF_VAL1:
if (in.len < hash_size) {
return -1;
err = REFTABLE_FORMAT_ERROR;
goto done;
}
memcpy(r->value.val1, in.buf, hash_size);
@ -378,7 +397,8 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
case REFTABLE_REF_VAL2:
if (in.len < 2 * hash_size) {
return -1;
err = REFTABLE_FORMAT_ERROR;
goto done;
}
memcpy(r->value.val2.value, in.buf, hash_size);
@ -391,7 +411,8 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
case REFTABLE_REF_SYMREF: {
int n = decode_string(scratch, in);
if (n < 0) {
return -1;
err = REFTABLE_FORMAT_ERROR;
goto done;
}
string_view_consume(&in, n);
r->value.symref = strbuf_detach(scratch, NULL);
@ -405,6 +426,9 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
}
return start.len - in.len;
done:
return err;
}
static int reftable_ref_record_is_deletion_void(const void *p)
@ -452,28 +476,33 @@ static void reftable_obj_record_key(const void *r, struct strbuf *dest)
static void reftable_obj_record_release(void *rec)
{
struct reftable_obj_record *obj = rec;
FREE_AND_NULL(obj->hash_prefix);
FREE_AND_NULL(obj->offsets);
REFTABLE_FREE_AND_NULL(obj->hash_prefix);
REFTABLE_FREE_AND_NULL(obj->offsets);
memset(obj, 0, sizeof(struct reftable_obj_record));
}
static void reftable_obj_record_copy_from(void *rec, const void *src_rec,
int hash_size UNUSED)
static int reftable_obj_record_copy_from(void *rec, const void *src_rec,
int hash_size UNUSED)
{
struct reftable_obj_record *obj = rec;
const struct reftable_obj_record *src =
(const struct reftable_obj_record *)src_rec;
const struct reftable_obj_record *src = src_rec;
reftable_obj_record_release(obj);
REFTABLE_ALLOC_ARRAY(obj->hash_prefix, src->hash_prefix_len);
if (!obj->hash_prefix)
return REFTABLE_OUT_OF_MEMORY_ERROR;
obj->hash_prefix_len = src->hash_prefix_len;
if (src->hash_prefix_len)
memcpy(obj->hash_prefix, src->hash_prefix, obj->hash_prefix_len);
REFTABLE_ALLOC_ARRAY(obj->offsets, src->offset_len);
if (!obj->offsets)
return REFTABLE_OUT_OF_MEMORY_ERROR;
obj->offset_len = src->offset_len;
COPY_ARRAY(obj->offsets, src->offsets, src->offset_len);
return 0;
}
static uint8_t reftable_obj_record_val_type(const void *rec)
@ -533,6 +562,8 @@ static int reftable_obj_record_decode(void *rec, struct strbuf key,
reftable_obj_record_release(r);
REFTABLE_ALLOC_ARRAY(r->hash_prefix, key.len);
if (!r->hash_prefix)
return REFTABLE_OUT_OF_MEMORY_ERROR;
memcpy(r->hash_prefix, key.buf, key.len);
r->hash_prefix_len = key.len;
@ -551,6 +582,8 @@ static int reftable_obj_record_decode(void *rec, struct strbuf key,
return start.len - in.len;
REFTABLE_ALLOC_ARRAY(r->offsets, count);
if (!r->offsets)
return REFTABLE_OUT_OF_MEMORY_ERROR;
r->offset_len = count;
n = get_var_int(&r->offsets[0], &in);
@ -646,33 +679,44 @@ static void reftable_log_record_key(const void *r, struct strbuf *dest)
strbuf_add(dest, i64, sizeof(i64));
}
static void reftable_log_record_copy_from(void *rec, const void *src_rec,
int hash_size)
static int reftable_log_record_copy_from(void *rec, const void *src_rec,
int hash_size)
{
struct reftable_log_record *dst = rec;
const struct reftable_log_record *src =
(const struct reftable_log_record *)src_rec;
int ret;
reftable_log_record_release(dst);
*dst = *src;
if (dst->refname) {
dst->refname = xstrdup(dst->refname);
dst->refname = reftable_strdup(dst->refname);
if (!dst->refname) {
ret = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out;
}
}
switch (dst->value_type) {
case REFTABLE_LOG_DELETION:
break;
case REFTABLE_LOG_UPDATE:
if (dst->value.update.email) {
if (dst->value.update.email)
dst->value.update.email =
xstrdup(dst->value.update.email);
}
if (dst->value.update.name) {
reftable_strdup(dst->value.update.email);
if (dst->value.update.name)
dst->value.update.name =
xstrdup(dst->value.update.name);
}
if (dst->value.update.message) {
reftable_strdup(dst->value.update.name);
if (dst->value.update.message)
dst->value.update.message =
xstrdup(dst->value.update.message);
reftable_strdup(dst->value.update.message);
if (!dst->value.update.email ||
!dst->value.update.name ||
!dst->value.update.message) {
ret = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out;
}
memcpy(dst->value.update.new_hash,
@ -681,6 +725,10 @@ static void reftable_log_record_copy_from(void *rec, const void *src_rec,
src->value.update.old_hash, hash_size);
break;
}
ret = 0;
out:
return ret;
}
static void reftable_log_record_release_void(void *rec)
@ -767,12 +815,17 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
struct reftable_log_record *r = rec;
uint64_t max = 0;
uint64_t ts = 0;
int n;
int err, n;
if (key.len <= 9 || key.buf[key.len - 9] != 0)
return REFTABLE_FORMAT_ERROR;
REFTABLE_ALLOC_GROW(r->refname, key.len - 8, r->refname_cap);
if (!r->refname) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
memcpy(r->refname, key.buf, key.len - 8);
ts = get_be64(key.buf + key.len - 8);
@ -781,10 +834,10 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
if (val_type != r->value_type) {
switch (r->value_type) {
case REFTABLE_LOG_UPDATE:
FREE_AND_NULL(r->value.update.message);
REFTABLE_FREE_AND_NULL(r->value.update.message);
r->value.update.message_cap = 0;
FREE_AND_NULL(r->value.update.email);
FREE_AND_NULL(r->value.update.name);
REFTABLE_FREE_AND_NULL(r->value.update.email);
REFTABLE_FREE_AND_NULL(r->value.update.name);
break;
case REFTABLE_LOG_DELETION:
break;
@ -795,8 +848,10 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
if (val_type == REFTABLE_LOG_DELETION)
return 0;
if (in.len < 2 * hash_size)
return REFTABLE_FORMAT_ERROR;
if (in.len < 2 * hash_size) {
err = REFTABLE_FORMAT_ERROR;
goto done;
}
memcpy(r->value.update.old_hash, in.buf, hash_size);
memcpy(r->value.update.new_hash, in.buf + hash_size, hash_size);
@ -804,8 +859,10 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
string_view_consume(&in, 2 * hash_size);
n = decode_string(scratch, in);
if (n < 0)
if (n < 0) {
err = REFTABLE_FORMAT_ERROR;
goto done;
}
string_view_consume(&in, n);
/*
@ -816,52 +873,75 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
*/
if (!r->value.update.name ||
strcmp(r->value.update.name, scratch->buf)) {
r->value.update.name =
reftable_realloc(r->value.update.name, scratch->len + 1);
char *name = reftable_realloc(r->value.update.name, scratch->len + 1);
if (!name) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
r->value.update.name = name;
memcpy(r->value.update.name, scratch->buf, scratch->len);
r->value.update.name[scratch->len] = 0;
}
n = decode_string(scratch, in);
if (n < 0)
if (n < 0) {
err = REFTABLE_FORMAT_ERROR;
goto done;
}
string_view_consume(&in, n);
/* Same as above, but for the reflog email. */
if (!r->value.update.email ||
strcmp(r->value.update.email, scratch->buf)) {
r->value.update.email =
reftable_realloc(r->value.update.email, scratch->len + 1);
char *email = reftable_realloc(r->value.update.email, scratch->len + 1);
if (!email) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
r->value.update.email = email;
memcpy(r->value.update.email, scratch->buf, scratch->len);
r->value.update.email[scratch->len] = 0;
}
ts = 0;
n = get_var_int(&ts, &in);
if (n < 0)
if (n < 0) {
err = REFTABLE_FORMAT_ERROR;
goto done;
}
string_view_consume(&in, n);
r->value.update.time = ts;
if (in.len < 2)
if (in.len < 2) {
err = REFTABLE_FORMAT_ERROR;
goto done;
}
r->value.update.tz_offset = get_be16(in.buf);
string_view_consume(&in, 2);
n = decode_string(scratch, in);
if (n < 0)
if (n < 0) {
err = REFTABLE_FORMAT_ERROR;
goto done;
}
string_view_consume(&in, n);
REFTABLE_ALLOC_GROW(r->value.update.message, scratch->len + 1,
r->value.update.message_cap);
if (!r->value.update.message) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
memcpy(r->value.update.message, scratch->buf, scratch->len);
r->value.update.message[scratch->len] = 0;
return start.len - in.len;
done:
return REFTABLE_FORMAT_ERROR;
return err;
}
static int null_streq(const char *a, const char *b)
@ -954,8 +1034,8 @@ static void reftable_index_record_key(const void *r, struct strbuf *dest)
strbuf_addbuf(dest, &rec->last_key);
}
static void reftable_index_record_copy_from(void *rec, const void *src_rec,
int hash_size UNUSED)
static int reftable_index_record_copy_from(void *rec, const void *src_rec,
int hash_size UNUSED)
{
struct reftable_index_record *dst = rec;
const struct reftable_index_record *src = src_rec;
@ -963,6 +1043,8 @@ static void reftable_index_record_copy_from(void *rec, const void *src_rec,
strbuf_reset(&dst->last_key);
strbuf_addbuf(&dst->last_key, &src->last_key);
dst->offset = src->offset;
return 0;
}
static void reftable_index_record_release(void *rec)
@ -1054,14 +1136,14 @@ int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
dest, hash_size);
}
void reftable_record_copy_from(struct reftable_record *rec,
int reftable_record_copy_from(struct reftable_record *rec,
struct reftable_record *src, int hash_size)
{
assert(src->type == rec->type);
reftable_record_vtable(rec)->copy_from(reftable_record_data(rec),
reftable_record_data(src),
hash_size);
return reftable_record_vtable(rec)->copy_from(reftable_record_data(rec),
reftable_record_data(src),
hash_size);
}
uint8_t reftable_record_val_type(struct reftable_record *rec)

View file

@ -44,7 +44,7 @@ struct reftable_record_vtable {
/* The record type of ('r' for ref). */
uint8_t type;
void (*copy_from)(void *dest, const void *src, int hash_size);
int (*copy_from)(void *dest, const void *src, int hash_size);
/* a value of [0..7], indicating record subvariants (eg. ref vs. symref
* vs ref deletion) */
@ -137,8 +137,8 @@ void reftable_record_init(struct reftable_record *rec, uint8_t typ);
int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b);
int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size);
void reftable_record_key(struct reftable_record *rec, struct strbuf *dest);
void reftable_record_copy_from(struct reftable_record *rec,
struct reftable_record *src, int hash_size);
int reftable_record_copy_from(struct reftable_record *rec,
struct reftable_record *src, int hash_size);
uint8_t reftable_record_val_type(struct reftable_record *rec);
int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
int hash_size);

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_BASICS_H
#define REFTABLE_BASICS_H
#include <stddef.h>
/* Overrides the functions to use for memory management. */
void reftable_set_alloc(void *(*malloc)(size_t),
void *(*realloc)(void *, size_t), void (*free)(void *));
#endif

View file

@ -57,6 +57,9 @@ enum reftable_error {
/* Trying to write out-of-date data. */
REFTABLE_OUTDATED_ERROR = -12,
/* An allocation has failed due to an out-of-memory situation. */
REFTABLE_OUT_OF_MEMORY_ERROR = -13,
};
/* convert the numeric error code to a string. The string should not be

View file

@ -1,18 +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_H
#define REFTABLE_H
#include <stddef.h>
/* Overrides the functions to use for memory management. */
void reftable_set_alloc(void *(*malloc)(size_t),
void *(*realloc)(void *, size_t), void (*free)(void *));
#endif

View file

@ -37,12 +37,12 @@ int reftable_merged_table_new(struct reftable_merged_table **dest,
uint32_t hash_id);
/* Initialize a merged table iterator for reading refs. */
void reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
struct reftable_iterator *it);
int reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
struct reftable_iterator *it);
/* Initialize a merged table iterator for reading logs. */
void reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
struct reftable_iterator *it);
int reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
struct reftable_iterator *it);
/* returns the max update_index covered by this merged table. */
uint64_t

View file

@ -46,12 +46,12 @@ void reftable_reader_incref(struct reftable_reader *reader);
void reftable_reader_decref(struct reftable_reader *reader);
/* Initialize a reftable iterator for reading refs. */
void reftable_reader_init_ref_iterator(struct reftable_reader *r,
struct reftable_iterator *it);
int reftable_reader_init_ref_iterator(struct reftable_reader *r,
struct reftable_iterator *it);
/* Initialize a reftable iterator for reading logs. */
void reftable_reader_init_log_iterator(struct reftable_reader *r,
struct reftable_iterator *it);
int reftable_reader_init_log_iterator(struct reftable_reader *r,
struct reftable_iterator *it);
/* returns the hash ID used in this table. */
uint32_t reftable_reader_hash_id(struct reftable_reader *r);

View file

@ -82,16 +82,16 @@ struct reftable_iterator;
* be used to iterate through refs. The iterator is valid until the next reload
* or write.
*/
void reftable_stack_init_ref_iterator(struct reftable_stack *st,
struct reftable_iterator *it);
int reftable_stack_init_ref_iterator(struct reftable_stack *st,
struct reftable_iterator *it);
/*
* Initialize an iterator for the merged tables contained in the stack that can
* be used to iterate through logs. The iterator is valid until the next reload
* or write.
*/
void reftable_stack_init_log_iterator(struct reftable_stack *st,
struct reftable_iterator *it);
int reftable_stack_init_log_iterator(struct reftable_stack *st,
struct reftable_iterator *it);
/* returns the merged_table for seeking. This table is valid until the
* next write or reload, and should not be closed or deleted.

View file

@ -101,11 +101,13 @@ struct reftable_stats {
int object_id_len;
};
/* reftable_new_writer creates a new writer */
struct reftable_writer *
reftable_new_writer(ssize_t (*writer_func)(void *, const void *, size_t),
int (*flush_func)(void *),
void *writer_arg, const struct reftable_write_options *opts);
struct reftable_writer;
/* Create a new writer. */
int reftable_writer_new(struct reftable_writer **out,
ssize_t (*writer_func)(void *, const void *, size_t),
int (*flush_func)(void *),
void *writer_arg, const struct reftable_write_options *opts);
/* Set the range of update indices for the records we will add. When writing a
table into a stack, the min should be at least

View file

@ -56,10 +56,16 @@ static int reftable_fd_flush(void *arg)
int reftable_new_stack(struct reftable_stack **dest, const char *dir,
const struct reftable_write_options *_opts)
{
struct reftable_stack *p = reftable_calloc(1, sizeof(*p));
struct strbuf list_file_name = STRBUF_INIT;
struct reftable_write_options opts = {0};
int err = 0;
struct reftable_write_options opts = { 0 };
struct reftable_stack *p;
int err;
p = reftable_calloc(1, sizeof(*p));
if (!p) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out;
}
if (_opts)
opts = *_opts;
@ -74,15 +80,23 @@ int reftable_new_stack(struct reftable_stack **dest, const char *dir,
p->list_file = strbuf_detach(&list_file_name, NULL);
p->list_fd = -1;
p->reftable_dir = xstrdup(dir);
p->opts = opts;
p->reftable_dir = reftable_strdup(dir);
if (!p->reftable_dir) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out;
}
err = reftable_stack_reload_maybe_reuse(p, 1);
if (err < 0) {
if (err < 0)
goto out;
*dest = p;
err = 0;
out:
if (err < 0)
reftable_stack_destroy(p);
} else {
*dest = p;
}
return err;
}
@ -102,13 +116,22 @@ static int fd_read_lines(int fd, char ***namesp)
}
REFTABLE_ALLOC_ARRAY(buf, size + 1);
if (!buf) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
if (read_in_full(fd, buf, size) != size) {
err = REFTABLE_IO_ERROR;
goto done;
}
buf[size] = 0;
parse_names(buf, size, namesp);
*namesp = parse_names(buf, size);
if (!*namesp) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
done:
reftable_free(buf);
@ -122,6 +145,8 @@ int read_lines(const char *filename, char ***namesp)
if (fd < 0) {
if (errno == ENOENT) {
REFTABLE_CALLOC_ARRAY(*namesp, 1);
if (!*namesp)
return REFTABLE_OUT_OF_MEMORY_ERROR;
return 0;
}
@ -132,18 +157,18 @@ int read_lines(const char *filename, char ***namesp)
return err;
}
void reftable_stack_init_ref_iterator(struct reftable_stack *st,
int reftable_stack_init_ref_iterator(struct reftable_stack *st,
struct reftable_iterator *it)
{
merged_table_init_iter(reftable_stack_merged_table(st),
it, BLOCK_TYPE_REF);
return merged_table_init_iter(reftable_stack_merged_table(st),
it, BLOCK_TYPE_REF);
}
void reftable_stack_init_log_iterator(struct reftable_stack *st,
struct reftable_iterator *it)
int reftable_stack_init_log_iterator(struct reftable_stack *st,
struct reftable_iterator *it)
{
merged_table_init_iter(reftable_stack_merged_table(st),
it, BLOCK_TYPE_LOG);
return merged_table_init_iter(reftable_stack_merged_table(st),
it, BLOCK_TYPE_LOG);
}
struct reftable_merged_table *
@ -167,6 +192,10 @@ void reftable_stack_destroy(struct reftable_stack *st)
{
char **names = NULL;
int err = 0;
if (!st)
return;
if (st->merged) {
reftable_merged_table_free(st->merged);
st->merged = NULL;
@ -174,7 +203,7 @@ void reftable_stack_destroy(struct reftable_stack *st)
err = read_lines(st->list_file, &names);
if (err < 0) {
FREE_AND_NULL(names);
REFTABLE_FREE_AND_NULL(names);
}
if (st->readers) {
@ -195,7 +224,7 @@ void reftable_stack_destroy(struct reftable_stack *st)
}
strbuf_release(&filename);
st->readers_len = 0;
FREE_AND_NULL(st->readers);
REFTABLE_FREE_AND_NULL(st->readers);
}
if (st->list_fd >= 0) {
@ -203,20 +232,20 @@ void reftable_stack_destroy(struct reftable_stack *st)
st->list_fd = -1;
}
FREE_AND_NULL(st->list_file);
FREE_AND_NULL(st->reftable_dir);
REFTABLE_FREE_AND_NULL(st->list_file);
REFTABLE_FREE_AND_NULL(st->reftable_dir);
reftable_free(st);
free_names(names);
}
static struct reftable_reader **stack_copy_readers(struct reftable_stack *st,
int cur_len)
size_t cur_len)
{
struct reftable_reader **cur = reftable_calloc(cur_len, sizeof(*cur));
int i = 0;
for (i = 0; i < cur_len; i++) {
if (!cur)
return NULL;
for (size_t i = 0; i < cur_len; i++)
cur[i] = st->readers[i];
}
return cur;
}
@ -225,18 +254,30 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
int reuse_open)
{
size_t cur_len = !st->merged ? 0 : st->merged->readers_len;
struct reftable_reader **cur = stack_copy_readers(st, cur_len);
struct reftable_reader **cur;
struct reftable_reader **reused = NULL;
size_t reused_len = 0, reused_alloc = 0;
size_t names_len = names_length(names);
struct reftable_reader **new_readers =
reftable_calloc(names_len, sizeof(*new_readers));
struct reftable_reader **new_readers;
size_t reused_len = 0, reused_alloc = 0, names_len;
size_t new_readers_len = 0;
struct reftable_merged_table *new_merged = NULL;
struct strbuf table_path = STRBUF_INIT;
int err = 0;
size_t i;
cur = stack_copy_readers(st, cur_len);
if (!cur) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
names_len = names_length(names);
new_readers = reftable_calloc(names_len, sizeof(*new_readers));
if (!new_readers) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
while (*names) {
struct reftable_reader *rd = NULL;
const char *name = *names++;
@ -257,6 +298,10 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
* do by bumping their refcount.
*/
REFTABLE_ALLOC_GROW(reused, reused_len + 1, reused_alloc);
if (!reused) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
reused[reused_len++] = rd;
reftable_reader_incref(rd);
break;
@ -382,6 +427,10 @@ static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st,
}
REFTABLE_CALLOC_ARRAY(names, 1);
if (!names) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out;
}
} else {
err = fd_read_lines(fd, &names);
if (err < 0)
@ -749,7 +798,11 @@ int reftable_stack_new_addition(struct reftable_addition **dest,
{
int err = 0;
struct reftable_addition empty = REFTABLE_ADDITION_INIT;
REFTABLE_CALLOC_ARRAY(*dest, 1);
if (!*dest)
return REFTABLE_OUT_OF_MEMORY_ERROR;
**dest = empty;
err = reftable_stack_init_addition(*dest, st, flags);
if (err) {
@ -812,8 +865,11 @@ int reftable_addition_add(struct reftable_addition *add,
}
tab_fd = get_tempfile_fd(tab_file);
wr = reftable_new_writer(reftable_fd_write, reftable_fd_flush, &tab_fd,
&add->stack->opts);
err = reftable_writer_new(&wr, reftable_fd_write, reftable_fd_flush,
&tab_fd, &add->stack->opts);
if (err < 0)
goto done;
err = write_table(wr, arg);
if (err < 0)
goto done;
@ -853,7 +909,12 @@ int reftable_addition_add(struct reftable_addition *add,
REFTABLE_ALLOC_GROW(add->new_tables, add->new_tables_len + 1,
add->new_tables_cap);
if (!add->new_tables) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
add->new_tables[add->new_tables_len++] = strbuf_detach(&next_name, NULL);
done:
delete_tempfile(&tab_file);
strbuf_release(&temp_tab_file_name);
@ -902,8 +963,11 @@ static int stack_compact_locked(struct reftable_stack *st,
goto done;
}
wr = reftable_new_writer(reftable_fd_write, reftable_fd_flush,
&tab_fd, &st->opts);
err = reftable_writer_new(&wr, reftable_fd_write, reftable_fd_flush,
&tab_fd, &st->opts);
if (err < 0)
goto done;
err = stack_write_compact(st, wr, first, last, config);
if (err < 0)
goto done;
@ -950,7 +1014,10 @@ static int stack_write_compact(struct reftable_stack *st,
if (err < 0)
goto done;
merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
err = merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
if (err < 0)
goto done;
err = reftable_iterator_seek_ref(&it, "");
if (err < 0)
goto done;
@ -975,7 +1042,10 @@ static int stack_write_compact(struct reftable_stack *st,
}
reftable_iterator_destroy(&it);
merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
err = merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
if (err < 0)
goto done;
err = reftable_iterator_seek_log(&it, "");
if (err < 0)
goto done;
@ -1091,6 +1161,11 @@ static int stack_compact_range(struct reftable_stack *st,
* from the point of view of the newer process.
*/
REFTABLE_CALLOC_ARRAY(table_locks, last - first + 1);
if (!table_locks) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
for (i = last + 1; i > first; i--) {
stack_filename(&table_name, st, reader_name(st->readers[i - 1]));
@ -1274,8 +1349,18 @@ static int stack_compact_range(struct reftable_stack *st,
* thus have to allocate `readers_len + 1` many entries.
*/
REFTABLE_CALLOC_ARRAY(names, st->merged->readers_len + 1);
for (size_t i = 0; i < st->merged->readers_len; i++)
names[i] = xstrdup(st->readers[i]->name);
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);
if (!names[i]) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
}
first_to_replace = first;
last_to_replace = last;
}
@ -1348,7 +1433,7 @@ static int stack_compact_range(struct reftable_stack *st,
struct lock_file *table_lock = &table_locks[i];
char *table_path = get_locked_file_path(table_lock);
unlink(table_path);
free(table_path);
reftable_free(table_path);
}
done:
@ -1465,6 +1550,8 @@ static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack *st)
uint64_t *sizes;
REFTABLE_CALLOC_ARRAY(sizes, st->merged->readers_len);
if (!sizes)
return NULL;
for (size_t i = 0; i < st->merged->readers_len; i++)
sizes[i] = st->readers[i]->size - overhead;
@ -1474,11 +1561,17 @@ static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack *st)
int reftable_stack_auto_compact(struct reftable_stack *st)
{
uint64_t *sizes = stack_table_sizes_for_compaction(st);
struct segment seg =
suggest_compaction_segment(sizes, st->merged->readers_len,
st->opts.auto_compaction_factor);
struct segment seg;
uint64_t *sizes;
sizes = stack_table_sizes_for_compaction(st);
if (!sizes)
return REFTABLE_OUT_OF_MEMORY_ERROR;
seg = suggest_compaction_segment(sizes, st->merged->readers_len,
st->opts.auto_compaction_factor);
reftable_free(sizes);
if (segment_size(&seg) > 0)
return stack_compact_range(st, seg.start, seg.end - 1,
NULL, STACK_COMPACT_RANGE_BEST_EFFORT);
@ -1498,7 +1591,10 @@ int reftable_stack_read_ref(struct reftable_stack *st, const char *refname,
struct reftable_iterator it = { 0 };
int ret;
reftable_merged_table_init_ref_iterator(st->merged, &it);
ret = reftable_merged_table_init_ref_iterator(st->merged, &it);
if (ret)
goto out;
ret = reftable_iterator_seek_ref(&it, refname);
if (ret)
goto out;
@ -1525,7 +1621,10 @@ int reftable_stack_read_log(struct reftable_stack *st, const char *refname,
struct reftable_iterator it = {0};
int err;
reftable_stack_init_log_iterator(st, &it);
err = reftable_stack_init_log_iterator(st, &it);
if (err)
goto done;
err = reftable_iterator_seek_log(&it, refname);
if (err)
goto done;

View file

@ -11,28 +11,44 @@ license that can be found in the LICENSE file or at
#include "basics.h"
struct tree_node *tree_search(void *key, struct tree_node **rootp,
int (*compare)(const void *, const void *),
int insert)
struct tree_node *tree_search(struct tree_node *tree,
void *key,
int (*compare)(const void *, const void *))
{
int res;
if (!tree)
return NULL;
res = compare(key, tree->key);
if (res < 0)
return tree_search(tree->left, key, compare);
else if (res > 0)
return tree_search(tree->right, key, compare);
return tree;
}
struct tree_node *tree_insert(struct tree_node **rootp,
void *key,
int (*compare)(const void *, const void *))
{
int res;
if (!*rootp) {
if (!insert) {
struct tree_node *n;
REFTABLE_CALLOC_ARRAY(n, 1);
if (!n)
return NULL;
} else {
struct tree_node *n;
REFTABLE_CALLOC_ARRAY(n, 1);
n->key = key;
*rootp = n;
return *rootp;
}
n->key = key;
*rootp = n;
return *rootp;
}
res = compare(key, (*rootp)->key);
if (res < 0)
return tree_search(key, &(*rootp)->left, compare, insert);
return tree_insert(&(*rootp)->left, key, compare);
else if (res > 0)
return tree_search(key, &(*rootp)->right, compare, insert);
return tree_insert(&(*rootp)->right, key, compare);
return *rootp;
}

View file

@ -15,12 +15,23 @@ struct tree_node {
struct tree_node *left, *right;
};
/* looks for `key` in `rootp` using `compare` as comparison function. If insert
* is set, insert the key if it's not found. Else, return NULL.
/*
* Search the tree for the node matching the given key using `compare` as
* comparison function. Returns the node whose key matches or `NULL` in case
* the key does not exist in the tree.
*/
struct tree_node *tree_search(void *key, struct tree_node **rootp,
int (*compare)(const void *, const void *),
int insert);
struct tree_node *tree_search(struct tree_node *tree,
void *key,
int (*compare)(const void *, const void *));
/*
* Insert a node into the tree. Returns the newly inserted node if the key does
* not yet exist. Otherwise it returns the preexisting node. Returns `NULL`
* when allocating the new node fails.
*/
struct tree_node *tree_insert(struct tree_node **rootp,
void *key,
int (*compare)(const void *, const void *));
/* performs an infix walk of the tree. */
void infix_walk(struct tree_node *t, void (*action)(void *arg, void *key),

View file

@ -49,8 +49,14 @@ static int padded_write(struct reftable_writer *w, uint8_t *data, size_t len,
{
int n = 0;
if (w->pending_padding > 0) {
uint8_t *zeroed = reftable_calloc(w->pending_padding, sizeof(*zeroed));
int n = w->write(w->write_arg, zeroed, w->pending_padding);
uint8_t *zeroed;
int n;
zeroed = reftable_calloc(w->pending_padding, sizeof(*zeroed));
if (!zeroed)
return -1;
n = w->write(w->write_arg, zeroed, w->pending_padding);
if (n < 0)
return n;
@ -102,28 +108,37 @@ static int writer_write_header(struct reftable_writer *w, uint8_t *dest)
return header_size(writer_version(w));
}
static void writer_reinit_block_writer(struct reftable_writer *w, uint8_t typ)
static int writer_reinit_block_writer(struct reftable_writer *w, uint8_t typ)
{
int block_start = 0;
if (w->next == 0) {
int block_start = 0, ret;
if (w->next == 0)
block_start = header_size(writer_version(w));
}
strbuf_reset(&w->last_key);
block_writer_init(&w->block_writer_data, typ, w->block,
w->opts.block_size, block_start,
hash_size(w->opts.hash_id));
ret = block_writer_init(&w->block_writer_data, typ, w->block,
w->opts.block_size, block_start,
hash_size(w->opts.hash_id));
if (ret < 0)
return ret;
w->block_writer = &w->block_writer_data;
w->block_writer->restart_interval = w->opts.restart_interval;
return 0;
}
struct reftable_writer *
reftable_new_writer(ssize_t (*writer_func)(void *, const void *, size_t),
int (*flush_func)(void *),
void *writer_arg, const struct reftable_write_options *_opts)
int reftable_writer_new(struct reftable_writer **out,
ssize_t (*writer_func)(void *, const void *, size_t),
int (*flush_func)(void *),
void *writer_arg, const struct reftable_write_options *_opts)
{
struct reftable_writer *wp = reftable_calloc(1, sizeof(*wp));
struct reftable_write_options opts = {0};
struct reftable_writer *wp;
wp = reftable_calloc(1, sizeof(*wp));
if (!wp)
return REFTABLE_OUT_OF_MEMORY_ERROR;
if (_opts)
opts = *_opts;
@ -134,13 +149,19 @@ reftable_new_writer(ssize_t (*writer_func)(void *, const void *, size_t),
strbuf_init(&wp->block_writer_data.last_key, 0);
strbuf_init(&wp->last_key, 0);
REFTABLE_CALLOC_ARRAY(wp->block, opts.block_size);
if (!wp->block) {
reftable_free(wp);
return REFTABLE_OUT_OF_MEMORY_ERROR;
}
wp->write = writer_func;
wp->write_arg = writer_arg;
wp->opts = opts;
wp->flush = flush_func;
writer_reinit_block_writer(wp, BLOCK_TYPE_REF);
return wp;
*out = wp;
return 0;
}
void reftable_writer_set_limits(struct reftable_writer *w, uint64_t min,
@ -186,34 +207,40 @@ static int obj_index_tree_node_compare(const void *a, const void *b)
&((const struct obj_index_tree_node *)b)->hash);
}
static void writer_index_hash(struct reftable_writer *w, struct strbuf *hash)
static int writer_index_hash(struct reftable_writer *w, struct strbuf *hash)
{
uint64_t off = w->next;
struct obj_index_tree_node want = { .hash = *hash };
struct obj_index_tree_node *key;
struct tree_node *node;
struct tree_node *node = tree_search(&want, &w->obj_index_tree,
&obj_index_tree_node_compare, 0);
struct obj_index_tree_node *key = NULL;
node = tree_search(w->obj_index_tree, &want, &obj_index_tree_node_compare);
if (!node) {
struct obj_index_tree_node empty = OBJ_INDEX_TREE_NODE_INIT;
key = reftable_malloc(sizeof(struct obj_index_tree_node));
key = reftable_malloc(sizeof(*key));
if (!key)
return REFTABLE_OUT_OF_MEMORY_ERROR;
*key = empty;
strbuf_reset(&key->hash);
strbuf_addbuf(&key->hash, hash);
tree_search((void *)key, &w->obj_index_tree,
&obj_index_tree_node_compare, 1);
tree_insert(&w->obj_index_tree, key,
&obj_index_tree_node_compare);
} else {
key = node->key;
}
if (key->offset_len > 0 && key->offsets[key->offset_len - 1] == off) {
return;
}
if (key->offset_len > 0 && key->offsets[key->offset_len - 1] == off)
return 0;
REFTABLE_ALLOC_GROW(key->offsets, key->offset_len + 1, key->offset_cap);
if (!key->offsets)
return REFTABLE_OUT_OF_MEMORY_ERROR;
key->offsets[key->offset_len++] = off;
return 0;
}
static int writer_add_record(struct reftable_writer *w,
@ -230,8 +257,11 @@ static int writer_add_record(struct reftable_writer *w,
strbuf_reset(&w->last_key);
strbuf_addbuf(&w->last_key, &key);
if (!w->block_writer)
writer_reinit_block_writer(w, reftable_record_type(rec));
if (!w->block_writer) {
err = writer_reinit_block_writer(w, reftable_record_type(rec));
if (err < 0)
goto done;
}
if (block_writer_type(w->block_writer) != reftable_record_type(rec))
BUG("record of type %d added to writer of type %d",
@ -254,7 +284,9 @@ static int writer_add_record(struct reftable_writer *w,
err = writer_flush_block(w);
if (err < 0)
goto done;
writer_reinit_block_writer(w, reftable_record_type(rec));
err = writer_reinit_block_writer(w, reftable_record_type(rec));
if (err < 0)
goto done;
/*
* Try to add the record to the writer again. If this still fails then
@ -284,11 +316,11 @@ int reftable_writer_add_ref(struct reftable_writer *w,
.ref = *ref
},
};
int err = 0;
struct strbuf buf = STRBUF_INIT;
int err;
if (!ref->refname)
return REFTABLE_API_ERROR;
if (ref->update_index < w->min_update_index ||
if (!ref->refname ||
ref->update_index < w->min_update_index ||
ref->update_index > w->max_update_index)
return REFTABLE_API_ERROR;
@ -296,24 +328,32 @@ int reftable_writer_add_ref(struct reftable_writer *w,
err = writer_add_record(w, &rec);
if (err < 0)
return err;
goto out;
if (!w->opts.skip_index_objects && reftable_ref_record_val1(ref)) {
struct strbuf h = STRBUF_INIT;
strbuf_add(&h, (char *)reftable_ref_record_val1(ref),
strbuf_add(&buf, (char *)reftable_ref_record_val1(ref),
hash_size(w->opts.hash_id));
writer_index_hash(w, &h);
strbuf_release(&h);
err = writer_index_hash(w, &buf);
if (err < 0)
goto out;
}
if (!w->opts.skip_index_objects && reftable_ref_record_val2(ref)) {
struct strbuf h = STRBUF_INIT;
strbuf_add(&h, reftable_ref_record_val2(ref),
strbuf_reset(&buf);
strbuf_add(&buf, reftable_ref_record_val2(ref),
hash_size(w->opts.hash_id));
writer_index_hash(w, &h);
strbuf_release(&h);
err = writer_index_hash(w, &buf);
if (err < 0)
goto out;
}
return 0;
err = 0;
out:
strbuf_release(&buf);
return err;
}
int reftable_writer_add_refs(struct reftable_writer *w,
@ -436,7 +476,9 @@ static int writer_finish_section(struct reftable_writer *w)
max_level++;
index_start = w->next;
writer_reinit_block_writer(w, BLOCK_TYPE_INDEX);
err = writer_reinit_block_writer(w, BLOCK_TYPE_INDEX);
if (err < 0)
return err;
idx = w->index;
idx_len = w->index_len;
@ -530,7 +572,10 @@ static void write_object_record(void *void_arg, void *key)
if (arg->err < 0)
goto done;
writer_reinit_block_writer(arg->w, BLOCK_TYPE_OBJ);
arg->err = writer_reinit_block_writer(arg->w, BLOCK_TYPE_OBJ);
if (arg->err < 0)
goto done;
arg->err = block_writer_add(arg->w->block_writer, &rec);
if (arg->err == 0)
goto done;
@ -548,7 +593,7 @@ static void object_record_free(void *void_arg UNUSED, void *key)
{
struct obj_index_tree_node *entry = key;
FREE_AND_NULL(entry->offsets);
REFTABLE_FREE_AND_NULL(entry->offsets);
strbuf_release(&entry->hash);
reftable_free(entry);
}
@ -559,16 +604,18 @@ static int writer_dump_object_index(struct reftable_writer *w)
struct common_prefix_arg common = {
.max = 1, /* obj_id_len should be >= 2. */
};
if (w->obj_index_tree) {
int err;
if (w->obj_index_tree)
infix_walk(w->obj_index_tree, &update_common, &common);
}
w->stats.object_id_len = common.max + 1;
writer_reinit_block_writer(w, BLOCK_TYPE_OBJ);
err = writer_reinit_block_writer(w, BLOCK_TYPE_OBJ);
if (err < 0)
return err;
if (w->obj_index_tree) {
if (w->obj_index_tree)
infix_walk(w->obj_index_tree, &write_object_record, &closure);
}
if (closure.err < 0)
return closure.err;
@ -662,7 +709,7 @@ static void writer_clear_index(struct reftable_writer *w)
{
for (size_t i = 0; w->index && i < w->index_len; i++)
strbuf_release(&w->index[i].last_key);
FREE_AND_NULL(w->index);
REFTABLE_FREE_AND_NULL(w->index);
w->index_len = 0;
w->index_cap = 0;
}
@ -726,6 +773,9 @@ static int writer_flush_nonempty_block(struct reftable_writer *w)
* case we will end up with a multi-level index.
*/
REFTABLE_ALLOC_GROW(w->index, w->index_len + 1, w->index_cap);
if (!w->index)
return REFTABLE_OUT_OF_MEMORY_ERROR;
index_record.offset = w->next;
strbuf_reset(&index_record.last_key);
strbuf_addbuf(&index_record.last_key, &w->block_writer->last_key);

View file

@ -28,7 +28,10 @@ static int dump_table(struct reftable_merged_table *mt)
const struct git_hash_algo *algop;
int err;
reftable_merged_table_init_ref_iterator(mt, &it);
err = reftable_merged_table_init_ref_iterator(mt, &it);
if (err < 0)
return err;
err = reftable_iterator_seek_ref(&it, "");
if (err < 0)
return err;
@ -63,7 +66,10 @@ static int dump_table(struct reftable_merged_table *mt)
reftable_iterator_destroy(&it);
reftable_ref_record_release(&ref);
reftable_merged_table_init_log_iterator(mt, &it);
err = reftable_merged_table_init_log_iterator(mt, &it);
if (err < 0)
return err;
err = reftable_iterator_seek_log(&it, "");
if (err < 0)
return err;

View file

@ -22,9 +22,11 @@ static int strbuf_writer_flush(void *arg UNUSED)
struct reftable_writer *t_reftable_strbuf_writer(struct strbuf *buf,
struct reftable_write_options *opts)
{
return reftable_new_writer(&strbuf_writer_write,
&strbuf_writer_flush,
buf, opts);
struct reftable_writer *writer;
int ret = reftable_writer_new(&writer, &strbuf_writer_write, &strbuf_writer_flush,
buf, opts);
check(!ret);
return writer;
}
void t_reftable_write_to_buf(struct strbuf *buf,

View file

@ -72,13 +72,14 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
if_test ("parse_names works for basic input") {
char in1[] = "line\n";
char in2[] = "a\nb\nc";
char **out = NULL;
parse_names(in1, strlen(in1), &out);
char **out = parse_names(in1, strlen(in1));
check(out != NULL);
check_str(out[0], "line");
check(!out[1]);
free_names(out);
parse_names(in2, strlen(in2), &out);
out = parse_names(in2, strlen(in2));
check(out != NULL);
check_str(out[0], "a");
check_str(out[1], "b");
check_str(out[2], "c");
@ -88,8 +89,8 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
if_test ("parse_names drops empty string") {
char in[] = "a\n\nb\n";
char **out = NULL;
parse_names(in, strlen(in), &out);
char **out = parse_names(in, strlen(in));
check(out != NULL);
check_str(out[0], "a");
/* simply '\n' should be dropped as empty string */
check_str(out[1], "b");

View file

@ -32,10 +32,12 @@ static void t_ref_block_read_write(void)
struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
REFTABLE_CALLOC_ARRAY(block.data, block_size);
check(block.data != NULL);
block.len = block_size;
block_source_from_strbuf(&block.source ,&buf);
block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
header_off, hash_size(GIT_SHA1_FORMAT_ID));
ret = block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
header_off, hash_size(GIT_SHA1_FORMAT_ID));
check(!ret);
rec.u.ref.refname = (char *) "";
rec.u.ref.value_type = REFTABLE_REF_DELETION;
@ -124,10 +126,12 @@ static void t_log_block_read_write(void)
struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
REFTABLE_CALLOC_ARRAY(block.data, block_size);
check(block.data != NULL);
block.len = block_size;
block_source_from_strbuf(&block.source ,&buf);
block_writer_init(&bw, BLOCK_TYPE_LOG, block.data, block_size,
header_off, hash_size(GIT_SHA1_FORMAT_ID));
ret = block_writer_init(&bw, BLOCK_TYPE_LOG, block.data, block_size,
header_off, hash_size(GIT_SHA1_FORMAT_ID));
check(!ret);
for (i = 0; i < N; i++) {
rec.u.log.refname = xstrfmt("branch%02"PRIuMAX , (uintmax_t)i);
@ -212,10 +216,12 @@ static void t_obj_block_read_write(void)
struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
REFTABLE_CALLOC_ARRAY(block.data, block_size);
check(block.data != NULL);
block.len = block_size;
block_source_from_strbuf(&block.source, &buf);
block_writer_init(&bw, BLOCK_TYPE_OBJ, block.data, block_size,
header_off, hash_size(GIT_SHA1_FORMAT_ID));
ret = block_writer_init(&bw, BLOCK_TYPE_OBJ, block.data, block_size,
header_off, hash_size(GIT_SHA1_FORMAT_ID));
check(!ret);
for (i = 0; i < N; i++) {
uint8_t bytes[] = { i, i + 1, i + 2, i + 3, i + 5 }, *allocated;
@ -294,10 +300,12 @@ static void t_index_block_read_write(void)
struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
REFTABLE_CALLOC_ARRAY(block.data, block_size);
check(block.data != NULL);
block.len = block_size;
block_source_from_strbuf(&block.source, &buf);
block_writer_init(&bw, BLOCK_TYPE_INDEX, block.data, block_size,
header_off, hash_size(GIT_SHA1_FORMAT_ID));
ret = block_writer_init(&bw, BLOCK_TYPE_INDEX, block.data, block_size,
header_off, hash_size(GIT_SHA1_FORMAT_ID));
check(!ret);
for (i = 0; i < N; i++) {
strbuf_init(&recs[i].u.idx.last_key, 9);

View file

@ -29,7 +29,9 @@ merged_table_from_records(struct reftable_ref_record **refs,
int err;
REFTABLE_CALLOC_ARRAY(*readers, n);
check(*readers != NULL);
REFTABLE_CALLOC_ARRAY(*source, n);
check(*source != NULL);
for (size_t i = 0; i < n; i++) {
t_reftable_write_to_buf(&buf[i], refs[i], sizes[i], NULL, 0, &opts);
@ -82,7 +84,8 @@ static void t_merged_single_record(void)
struct reftable_iterator it = { 0 };
int err;
merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
err = merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
check(!err);
err = reftable_iterator_seek_ref(&it, "a");
check(!err);
@ -161,7 +164,8 @@ static void t_merged_refs(void)
size_t cap = 0;
size_t i;
merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
err = merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
check(!err);
err = reftable_iterator_seek_ref(&it, "a");
check(!err);
check_int(reftable_merged_table_hash_id(mt), ==, GIT_SHA1_FORMAT_ID);
@ -283,7 +287,9 @@ merged_table_from_log_records(struct reftable_log_record **logs,
int err;
REFTABLE_CALLOC_ARRAY(*readers, n);
check(*readers != NULL);
REFTABLE_CALLOC_ARRAY(*source, n);
check(*source != NULL);
for (size_t i = 0; i < n; i++) {
t_reftable_write_to_buf(&buf[i], NULL, 0, logs[i], sizes[i], &opts);
@ -367,7 +373,8 @@ static void t_merged_logs(void)
size_t cap = 0;
size_t i;
merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
err = merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
check(!err);
err = reftable_iterator_seek_log(&it, "a");
check(!err);
check_int(reftable_merged_table_hash_id(mt), ==, GIT_SHA1_FORMAT_ID);
@ -390,7 +397,8 @@ static void t_merged_logs(void)
check(reftable_log_record_equal(want[i], &out[i],
GIT_SHA1_RAWSZ));
merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
err = merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
check(!err);
err = reftable_iterator_seek_log_at(&it, "a", 2);
check(!err);
reftable_log_record_release(&out[0]);

View file

@ -52,8 +52,11 @@ static void write_table(char ***names, struct strbuf *buf, int N,
int i;
REFTABLE_CALLOC_ARRAY(*names, N + 1);
check(*names != NULL);
REFTABLE_CALLOC_ARRAY(refs, N);
check(refs != NULL);
REFTABLE_CALLOC_ARRAY(logs, N);
check(logs != NULL);
for (i = 0; i < N; i++) {
refs[i].refname = (*names)[i] = xstrfmt("refs/heads/branch%02d", i);
@ -73,8 +76,8 @@ static void write_table(char ***names, struct strbuf *buf, int N,
t_reftable_write_to_buf(buf, refs, N, logs, N, &opts);
free(refs);
free(logs);
reftable_free(refs);
reftable_free(logs);
}
static void t_log_buffer_size(void)
@ -150,23 +153,25 @@ static void t_log_overflow(void)
static void t_log_write_read(void)
{
int N = 2;
char **names = reftable_calloc(N + 1, sizeof(*names));
int err;
struct reftable_write_options opts = {
.block_size = 256,
};
struct reftable_ref_record ref = { 0 };
int i = 0;
struct reftable_log_record log = { 0 };
int n;
struct reftable_iterator it = { 0 };
struct reftable_reader *reader;
struct reftable_block_source source = { 0 };
struct strbuf buf = STRBUF_INIT;
struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
const struct reftable_stats *stats = NULL;
int N = 2, err, i, n;
char **names;
names = reftable_calloc(N + 1, sizeof(*names));
check(names != NULL);
reftable_writer_set_limits(w, 0, N);
for (i = 0; i < N; i++) {
char name[256];
struct reftable_ref_record ref = { 0 };
@ -178,6 +183,7 @@ static void t_log_write_read(void)
err = reftable_writer_add_ref(w, &ref);
check(!err);
}
for (i = 0; i < N; i++) {
struct reftable_log_record log = { 0 };
@ -206,7 +212,8 @@ static void t_log_write_read(void)
err = reftable_reader_new(&reader, &source, "file.log");
check(!err);
reftable_reader_init_ref_iterator(reader, &it);
err = reftable_reader_init_ref_iterator(reader, &it);
check(!err);
err = reftable_iterator_seek_ref(&it, names[N - 1]);
check(!err);
@ -221,8 +228,8 @@ static void t_log_write_read(void)
reftable_iterator_destroy(&it);
reftable_ref_record_release(&ref);
reftable_reader_init_log_iterator(reader, &it);
err = reftable_reader_init_log_iterator(reader, &it);
check(!err);
err = reftable_iterator_seek_log(&it, "");
check(!err);
@ -296,7 +303,8 @@ static void t_log_zlib_corruption(void)
err = reftable_reader_new(&reader, &source, "file.log");
check(!err);
reftable_reader_init_log_iterator(reader, &it);
err = reftable_reader_init_log_iterator(reader, &it);
check(!err);
err = reftable_iterator_seek_log(&it, "refname");
check_int(err, ==, REFTABLE_ZLIB_ERROR);
@ -325,7 +333,8 @@ static void t_table_read_write_sequential(void)
err = reftable_reader_new(&reader, &source, "file.ref");
check(!err);
reftable_reader_init_ref_iterator(reader, &it);
err = reftable_reader_init_ref_iterator(reader, &it);
check(!err);
err = reftable_iterator_seek_ref(&it, "");
check(!err);
@ -376,7 +385,8 @@ static void t_table_read_api(void)
err = reftable_reader_new(&reader, &source, "file.ref");
check(!err);
reftable_reader_init_ref_iterator(reader, &it);
err = reftable_reader_init_ref_iterator(reader, &it);
check(!err);
err = reftable_iterator_seek_ref(&it, names[0]);
check(!err);
@ -419,7 +429,8 @@ static void t_table_read_write_seek(int index, int hash_id)
}
for (i = 1; i < N; i++) {
reftable_reader_init_ref_iterator(reader, &it);
err = reftable_reader_init_ref_iterator(reader, &it);
check(!err);
err = reftable_iterator_seek_ref(&it, names[i]);
check(!err);
err = reftable_iterator_next_ref(&it, &ref);
@ -435,7 +446,8 @@ static void t_table_read_write_seek(int index, int hash_id)
strbuf_addstr(&pastLast, names[N - 1]);
strbuf_addstr(&pastLast, "/");
reftable_reader_init_ref_iterator(reader, &it);
err = reftable_reader_init_ref_iterator(reader, &it);
check(!err);
err = reftable_iterator_seek_ref(&it, pastLast.buf);
if (err == 0) {
struct reftable_ref_record ref = { 0 };
@ -470,8 +482,7 @@ static void t_table_read_write_seek_index(void)
static void t_table_refs_for(int indexed)
{
int N = 50;
char **want_names = reftable_calloc(N + 1, sizeof(*want_names));
char **want_names;
int want_names_len = 0;
uint8_t want_hash[GIT_SHA1_RAWSZ];
@ -479,15 +490,15 @@ static void t_table_refs_for(int indexed)
.block_size = 256,
};
struct reftable_ref_record ref = { 0 };
int i = 0;
int n;
int err;
struct reftable_reader *reader;
struct reftable_block_source source = { 0 };
struct strbuf buf = STRBUF_INIT;
struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
struct reftable_iterator it = { 0 };
int j;
int N = 50, n, j, err, i;
want_names = reftable_calloc(N + 1, sizeof(*want_names));
check(want_names != NULL);
t_reftable_set_hash(want_hash, 4, GIT_SHA1_FORMAT_ID);
@ -534,7 +545,8 @@ static void t_table_refs_for(int indexed)
if (!indexed)
reader->obj_offsets.is_present = 0;
reftable_reader_init_ref_iterator(reader, &it);
err = reftable_reader_init_ref_iterator(reader, &it);
check(!err);
err = reftable_iterator_seek_ref(&it, "");
check(!err);
reftable_iterator_destroy(&it);
@ -593,7 +605,8 @@ static void t_write_empty_table(void)
err = reftable_reader_new(&rd, &source, "filename");
check(!err);
reftable_reader_init_ref_iterator(rd, &it);
err = reftable_reader_init_ref_iterator(rd, &it);
check(!err);
err = reftable_iterator_seek_ref(&it, "");
check(!err);
@ -802,7 +815,8 @@ static void t_write_multiple_indices(void)
* Seeking the log uses the log index now. In case there is any
* confusion regarding indices we would notice here.
*/
reftable_reader_init_log_iterator(reader, &it);
err = reftable_reader_init_log_iterator(reader, &it);
check(!err);
err = reftable_iterator_seek_log(&it, "");
check(!err);
@ -858,7 +872,8 @@ static void t_write_multi_level_index(void)
/*
* Seeking the last ref should work as expected.
*/
reftable_reader_init_ref_iterator(reader, &it);
err = reftable_reader_init_ref_iterator(reader, &it);
check(!err);
err = reftable_iterator_seek_ref(&it, "refs/heads/199");
check(!err);

View file

@ -661,7 +661,9 @@ static void t_reftable_stack_iterator(void)
reftable_iterator_destroy(&it);
reftable_stack_init_log_iterator(st, &it);
err = reftable_stack_init_log_iterator(st, &it);
check(!err);
reftable_iterator_seek_log(&it, logs[0].refname);
for (i = 0; ; i++) {
struct reftable_log_record log = { 0 };
@ -1209,7 +1211,7 @@ static void unclean_stack_close(struct reftable_stack *st)
for (size_t i = 0; i < st->readers_len; i++)
reftable_reader_decref(st->readers[i]);
st->readers_len = 0;
FREE_AND_NULL(st->readers);
REFTABLE_FREE_AND_NULL(st->readers);
}
static void t_reftable_stack_compaction_concurrent_clean(void)

View file

@ -37,16 +37,17 @@ static void t_tree_search(void)
* values[1] and values[10] (inclusive) in the tree.
*/
do {
nodes[i] = tree_search(&values[i], &root, &t_compare, 1);
nodes[i] = tree_insert(&root, &values[i], &t_compare);
check(nodes[i] != NULL);
i = (i * 7) % 11;
} while (i != 1);
for (i = 1; i < ARRAY_SIZE(nodes); i++) {
check_pointer_eq(&values[i], nodes[i]->key);
check_pointer_eq(nodes[i], tree_search(&values[i], &root, &t_compare, 0));
check_pointer_eq(nodes[i], tree_search(root, &values[i], &t_compare));
}
check(!tree_search(values, &root, t_compare, 0));
check(!tree_search(root, values, t_compare));
tree_free(root);
}
@ -62,7 +63,8 @@ static void t_infix_walk(void)
size_t count = 0;
do {
tree_search(&values[i], &root, t_compare, 1);
struct tree_node *node = tree_insert(&root, &values[i], t_compare);
check(node != NULL);
i = (i * 7) % 11;
count++;
} while (i != 1);