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
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/block.o
REFTABLE_OBJS += reftable/blocksource.o REFTABLE_OBJS += reftable/blocksource.o
REFTABLE_OBJS += reftable/iter.o REFTABLE_OBJS += reftable/iter.o
REFTABLE_OBJS += reftable/publicbasics.o
REFTABLE_OBJS += reftable/merged.o REFTABLE_OBJS += reftable/merged.o
REFTABLE_OBJS += reftable/pq.o REFTABLE_OBJS += reftable/pq.o
REFTABLE_OBJS += reftable/reader.o REFTABLE_OBJS += reftable/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_log_record log = {0};
struct reftable_iterator it = {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 * 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, * 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. * 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); ret = reftable_iterator_seek_log(&it, arg->oldname);
if (ret < 0) if (ret < 0)
goto done; goto done;
@@ -1911,7 +1916,10 @@ static struct reftable_reflog_iterator *reflog_iterator_for_stack(struct reftabl
if (ret < 0) if (ret < 0)
goto done; 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, ""); ret = reftable_iterator_seek_log(&iter->iter, "");
if (ret < 0) if (ret < 0)
goto done; goto done;
@@ -1978,7 +1986,10 @@ static int reftable_be_for_each_reflog_ent_reverse(struct ref_store *ref_store,
if (refs->err < 0) if (refs->err < 0)
return refs->err; 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); ret = reftable_iterator_seek_log(&it, refname);
while (!ret) { while (!ret) {
ret = reftable_iterator_next_log(&it, &log); 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; break;
} }
done:
reftable_log_record_release(&log); reftable_log_record_release(&log);
reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);
return ret; return ret;
@@ -2015,7 +2027,10 @@ static int reftable_be_for_each_reflog_ent(struct ref_store *ref_store,
if (refs->err < 0) if (refs->err < 0)
return refs->err; 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); ret = reftable_iterator_seek_log(&it, refname);
while (!ret) { while (!ret) {
struct reftable_log_record log = {0}; struct reftable_log_record log = {0};
@@ -2065,7 +2080,10 @@ static int reftable_be_reflog_exists(struct ref_store *ref_store,
if (ret < 0) if (ret < 0)
goto done; 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); ret = reftable_iterator_seek_log(&it, refname);
if (ret < 0) if (ret < 0)
goto done; 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_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 * 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); ret = reftable_writer_add_log(writer, &tombstone);
} }
out:
reftable_log_record_release(&log); reftable_log_record_release(&log);
reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);
return ret; return ret;
@@ -2333,7 +2354,9 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
if (ret < 0) if (ret < 0)
goto done; 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); ret = reftable_iterator_seek_log(&it, refname);
if (ret < 0) 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 https://developers.google.com/open-source/licenses/bsd
*/ */
#define REFTABLE_ALLOW_BANNED_ALLOCATORS
#include "basics.h" #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) void put_be24(uint8_t *out, uint32_t i)
{ {
@@ -75,14 +136,14 @@ size_t names_length(const char **names)
return p - names; return p - names;
} }
void parse_names(char *buf, int size, char ***namesp) char **parse_names(char *buf, int size)
{ {
char **names = NULL; char **names = NULL;
size_t names_cap = 0; size_t names_cap = 0;
size_t names_len = 0; size_t names_len = 0;
char *p = buf; char *p = buf;
char *end = buf + size; char *end = buf + size;
while (p < end) { while (p < end) {
char *next = strchr(p, '\n'); char *next = strchr(p, '\n');
if (next && next < end) { if (next && next < end) {
@@ -91,15 +152,29 @@ void parse_names(char *buf, int size, char ***namesp)
next = end; next = end;
} }
if (p < next) { if (p < next) {
REFTABLE_ALLOC_GROW(names, names_len + 1, names_cap); char **names_grown = names;
names[names_len++] = xstrdup(p); 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; p = next + 1;
} }
REFTABLE_REALLOC_ARRAY(names, names_len + 1); REFTABLE_REALLOC_ARRAY(names, names_len + 1);
names[names_len] = NULL; 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) 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; 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 @@ https://developers.google.com/open-source/licenses/bsd
*/ */
#include "system.h" #include "system.h"
#include "reftable-basics.h"
/* Bigendian en/decoding of integers */ /* 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); 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. */ * Parse a newline separated list of names. `size` is the length of the buffer,
void parse_names(char *buf, int size, char ***namesp); * 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. */ /* compares two NULL-terminated arrays of strings. */
int names_equal(const char **a, const char **b); 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_realloc(void *p, size_t sz);
void reftable_free(void *p); void reftable_free(void *p);
void *reftable_calloc(size_t nelem, size_t elsize); 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_ALLOC_ARRAY(x, alloc) (x) = reftable_malloc(st_mult(sizeof(*(x)), (alloc)))
#define REFTABLE_CALLOC_ARRAY(x, alloc) (x) = reftable_calloc((alloc), sizeof(*(x))) #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); \ REFTABLE_REALLOC_ARRAY(x, alloc); \
} \ } \
} while (0) } 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` */ /* Find the longest shared prefix size of `a` and `b` */
struct strbuf; struct strbuf;
int common_prefix_size(struct strbuf *a, struct strbuf *b); int common_prefix_size(struct strbuf *a, struct strbuf *b);
int hash_size(uint32_t id);
#endif #endif

View File

@@ -52,6 +52,8 @@ static int block_writer_register_restart(struct block_writer *w, int n,
return -1; return -1;
if (is_restart) { if (is_restart) {
REFTABLE_ALLOC_GROW(w->restarts, w->restart_len + 1, w->restart_cap); 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; 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; return 0;
} }
void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf, 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) uint32_t block_size, uint32_t header_off, int hash_size)
{ {
bw->buf = buf; bw->buf = buf;
bw->hash_size = hash_size; 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; bw->last_key.len = 0;
if (!bw->zstream) { if (!bw->zstream) {
REFTABLE_CALLOC_ARRAY(bw->zstream, 1); REFTABLE_CALLOC_ARRAY(bw->zstream, 1);
if (!bw->zstream)
return REFTABLE_OUT_OF_MEMORY_ERROR;
deflateInit(bw->zstream, 9); deflateInit(bw->zstream, 9);
} }
return 0;
} }
uint8_t block_writer_type(struct block_writer *bw) 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); compressed_len = deflateBound(w->zstream, src_len);
REFTABLE_ALLOC_GROW(w->compressed, compressed_len, w->compressed_cap); 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->next_out = w->compressed;
w->zstream->avail_out = compressed_len; 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. */ /* Log blocks specify the *uncompressed* size in their header. */
REFTABLE_ALLOC_GROW(br->uncompressed_data, sz, REFTABLE_ALLOC_GROW(br->uncompressed_data, sz,
br->uncompressed_cap); 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. */ /* Copy over the block header verbatim. It's not compressed. */
memcpy(br->uncompressed_data, block->data, block_header_skip); memcpy(br->uncompressed_data, block->data, block_header_skip);
if (!br->zstream) { if (!br->zstream) {
REFTABLE_CALLOC_ARRAY(br->zstream, 1); REFTABLE_CALLOC_ARRAY(br->zstream, 1);
if (!br->zstream) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto done;
}
err = inflateInit(br->zstream); err = inflateInit(br->zstream);
} else { } else {
err = inflateReset(br->zstream); err = inflateReset(br->zstream);
@@ -532,9 +551,9 @@ done:
void block_writer_release(struct block_writer *bw) void block_writer_release(struct block_writer *bw)
{ {
deflateEnd(bw->zstream); deflateEnd(bw->zstream);
FREE_AND_NULL(bw->zstream); REFTABLE_FREE_AND_NULL(bw->zstream);
FREE_AND_NULL(bw->restarts); REFTABLE_FREE_AND_NULL(bw->restarts);
FREE_AND_NULL(bw->compressed); REFTABLE_FREE_AND_NULL(bw->compressed);
strbuf_release(&bw->last_key); strbuf_release(&bw->last_key);
/* the block is not owned. */ /* 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 * initializes the blockwriter to write `typ` entries, using `buf` as temporary
* storage. `buf` is not owned by the block_writer. */ * storage. `buf` is not owned by the block_writer. */
void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf, 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); uint32_t block_size, uint32_t header_off, int hash_size);
/* returns the block type (eg. 'r' for ref records. */ /* returns the block type (eg. 'r' for ref records. */
uint8_t block_writer_type(struct block_writer *bw); 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; struct strbuf *b = v;
assert(off + size <= b->len); assert(off + size <= b->len);
REFTABLE_CALLOC_ARRAY(dest->data, size); REFTABLE_CALLOC_ARRAY(dest->data, size);
if (!dest->data)
return -1;
memcpy(dest->data, b->buf + off, size); memcpy(dest->data, b->buf + off, size);
dest->len = size; dest->len = size;
return size; return size;
@@ -98,27 +100,40 @@ int reftable_block_source_from_file(struct reftable_block_source *bs,
{ {
struct file_block_source *p; struct file_block_source *p;
struct stat st; struct stat st;
int fd; int fd, err;
fd = open(name, O_RDONLY); fd = open(name, O_RDONLY);
if (fd < 0) { if (fd < 0) {
if (errno == ENOENT) if (errno == ENOENT)
return REFTABLE_NOT_EXIST_ERROR; return REFTABLE_NOT_EXIST_ERROR;
return -1; err = -1;
goto out;
} }
if (fstat(fd, &st) < 0) { if (fstat(fd, &st) < 0) {
close(fd); err = REFTABLE_IO_ERROR;
return REFTABLE_IO_ERROR; goto out;
} }
REFTABLE_CALLOC_ARRAY(p, 1); REFTABLE_CALLOC_ARRAY(p, 1);
if (!p) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out;
}
p->size = st.st_size; p->size = st.st_size;
p->data = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); p->data = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
assert(!bs->ops); assert(!bs->ops);
bs->ops = &file_vtable; bs->ops = &file_vtable;
bs->arg = p; bs->arg = p;
err = 0;
out:
if (fd >= 0)
close(fd);
if (err < 0)
reftable_free(p);
return 0; return 0;
} }

View File

@@ -35,6 +35,8 @@ const char *reftable_error_str(int err)
return "entry too large"; return "entry too large";
case REFTABLE_OUTDATED_ERROR: case REFTABLE_OUTDATED_ERROR:
return "data concurrently modified"; return "data concurrently modified";
case REFTABLE_OUT_OF_MEMORY_ERROR:
return "out of memory";
case -1: case -1:
return "general error"; return "general error";
default: 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, struct reftable_reader *r, uint8_t *oid,
int oid_len, uint64_t *offsets, int offset_len) int oid_len, uint64_t *offsets, int offset_len)
{ {
struct indexed_table_ref_iter empty = INDEXED_TABLE_REF_ITER_INIT; struct indexed_table_ref_iter empty = INDEXED_TABLE_REF_ITER_INIT;
struct indexed_table_ref_iter *itr = reftable_calloc(1, sizeof(*itr)); struct indexed_table_ref_iter *itr;
int err = 0; int err = 0;
itr = reftable_calloc(1, sizeof(*itr));
if (!itr) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out;
}
*itr = empty; *itr = empty;
itr->r = r; itr->r = r;
strbuf_add(&itr->oid, oid, oid_len); 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; itr->offset_len = offset_len;
err = indexed_table_ref_iter_next_block(itr); err = indexed_table_ref_iter_next_block(itr);
if (err < 0)
goto out;
*dest = itr;
err = 0;
out:
if (err < 0) { if (err < 0) {
*dest = NULL;
reftable_free(itr); reftable_free(itr);
} else {
*dest = itr;
} }
return err; return err;
} }
@@ -225,7 +237,7 @@ void reftable_iterator_destroy(struct reftable_iterator *it)
return; return;
it->ops->close(it->iter_arg); it->ops->close(it->iter_arg);
it->ops = NULL; 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, 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); struct indexed_table_ref_iter *itr);
/* Takes ownership of `offsets` */ /* 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, struct reftable_reader *r, uint8_t *oid,
int oid_len, uint64_t *offsets, int offset_len); int oid_len, uint64_t *offsets, int offset_len);

View File

@@ -30,22 +30,6 @@ struct merged_iter {
ssize_t advance_index; 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) static void merged_iter_close(void *p)
{ {
struct merged_iter *mi = 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) if (err)
return err; return err;
merged_iter_pqueue_add(&mi->pq, &e); err = merged_iter_pqueue_add(&mi->pq, &e);
if (err)
return err;
return 0; return 0;
} }
@@ -216,6 +203,9 @@ int reftable_merged_table_new(struct reftable_merged_table **dest,
} }
REFTABLE_CALLOC_ARRAY(m, 1); REFTABLE_CALLOC_ARRAY(m, 1);
if (!m)
return REFTABLE_OUT_OF_MEMORY_ERROR;
m->readers = readers; m->readers = readers;
m->readers_len = n; m->readers_len = n;
m->min = first_min; m->min = first_min;
@@ -244,25 +234,63 @@ reftable_merged_table_min_update_index(struct reftable_merged_table *mt)
return mt->min; return mt->min;
} }
void merged_table_init_iter(struct reftable_merged_table *mt, int merged_table_init_iter(struct reftable_merged_table *mt,
struct reftable_iterator *it, struct reftable_iterator *it,
uint8_t typ) uint8_t typ)
{ {
struct merged_iter *mi = reftable_malloc(sizeof(*mi)); struct merged_subiter *subiters;
merged_iter_init(mi, mt, typ); 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); 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, int reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
struct reftable_iterator *it) 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, int reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
struct reftable_iterator *it) 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) 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; struct reftable_iterator;
void merged_table_init_iter(struct reftable_merged_table *mt, int merged_table_init_iter(struct reftable_merged_table *mt,
struct reftable_iterator *it, struct reftable_iterator *it,
uint8_t typ); uint8_t typ);
#endif #endif

View File

@@ -8,6 +8,7 @@ https://developers.google.com/open-source/licenses/bsd
#include "pq.h" #include "pq.h"
#include "reftable-error.h"
#include "reftable-record.h" #include "reftable-record.h"
#include "system.h" #include "system.h"
#include "basics.h" #include "basics.h"
@@ -44,11 +45,13 @@ struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq)
return e; 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; size_t i = 0;
REFTABLE_ALLOC_GROW(pq->heap, pq->len + 1, pq->cap); REFTABLE_ALLOC_GROW(pq->heap, pq->len + 1, pq->cap);
if (!pq->heap)
return REFTABLE_OUT_OF_MEMORY_ERROR;
pq->heap[pq->len++] = *e; pq->heap[pq->len++] = *e;
i = pq->len - 1; 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]); SWAP(pq->heap[j], pq->heap[i]);
i = j; i = j;
} }
return 0;
} }
void merged_iter_pqueue_release(struct merged_iter_pqueue *pq) 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)); 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); 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); void merged_iter_pqueue_release(struct merged_iter_pqueue *pq);
int pq_less(struct pq_entry *a, struct pq_entry *b); 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; it->ops = &table_iter_vtable;
} }
void reader_init_iter(struct reftable_reader *r, int reader_init_iter(struct reftable_reader *r,
struct reftable_iterator *it, struct reftable_iterator *it,
uint8_t typ) uint8_t typ)
{ {
struct reftable_reader_offsets *offs = reader_offsets_for(r, typ); struct reftable_reader_offsets *offs = reader_offsets_for(r, typ);
if (offs->is_present) { if (offs->is_present) {
struct table_iter *ti; struct table_iter *ti;
REFTABLE_ALLOC_ARRAY(ti, 1); REFTABLE_ALLOC_ARRAY(ti, 1);
if (!ti)
return REFTABLE_OUT_OF_MEMORY_ERROR;
table_iter_init(ti, r); table_iter_init(ti, r);
iterator_from_table_iter(it, ti); iterator_from_table_iter(it, ti);
} else { } else {
iterator_set_empty(it); iterator_set_empty(it);
} }
return 0;
} }
void reftable_reader_init_ref_iterator(struct reftable_reader *r, int reftable_reader_init_ref_iterator(struct reftable_reader *r,
struct reftable_iterator *it) 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, int reftable_reader_init_log_iterator(struct reftable_reader *r,
struct reftable_iterator *it) 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, int reftable_reader_new(struct reftable_reader **out,
@@ -593,6 +598,10 @@ int reftable_reader_new(struct reftable_reader **out,
int err; int err;
REFTABLE_CALLOC_ARRAY(r, 1); 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 * 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->size = file_size - footer_size(r->version);
r->source = *source; 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->hash_id = 0;
r->refcount = 1; r->refcount = 1;
@@ -665,7 +678,7 @@ void reftable_reader_decref(struct reftable_reader *r)
if (--r->refcount) if (--r->refcount)
return; return;
block_source_close(&r->source); block_source_close(&r->source);
FREE_AND_NULL(r->name); REFTABLE_FREE_AND_NULL(r->name);
reftable_free(r); 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; struct indexed_table_ref_iter *itr = NULL;
/* Look through the reverse index. */ /* 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); err = iterator_seek(&oit, &want);
if (err != 0) if (err != 0)
goto done; goto done;
@@ -707,7 +723,7 @@ static int reftable_reader_refs_for_indexed(struct reftable_reader *r,
goto done; 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.offsets,
got.u.obj.offset_len); got.u.obj.offset_len);
if (err < 0) if (err < 0)
@@ -732,21 +748,37 @@ static int reftable_reader_refs_for_unindexed(struct reftable_reader *r,
int err; int err;
REFTABLE_ALLOC_ARRAY(ti, 1); REFTABLE_ALLOC_ARRAY(ti, 1);
table_iter_init(ti, r); if (!ti) {
err = table_iter_seek_start(ti, BLOCK_TYPE_REF, 0); err = REFTABLE_OUT_OF_MEMORY_ERROR;
if (err < 0) { goto out;
reftable_free(ti);
return err;
} }
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; *filter = empty;
strbuf_add(&filter->oid, oid, oid_len); strbuf_add(&filter->oid, oid, oid_len);
iterator_from_table_iter(&filter->it, ti); iterator_from_table_iter(&filter->it, ti);
iterator_from_filtering_ref_iterator(it, filter); 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, 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); const char *reader_name(struct reftable_reader *r);
void reader_init_iter(struct reftable_reader *r, int reader_init_iter(struct reftable_reader *r,
struct reftable_iterator *it, struct reftable_iterator *it,
uint8_t typ); uint8_t typ);
/* initialize a block reader to read from `r` */ /* initialize a block reader to read from `r` */
int reader_init_block_reader(struct reftable_reader *r, struct block_reader *br, 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); strbuf_addstr(dest, rec->refname);
} }
static void reftable_ref_record_copy_from(void *rec, const void *src_rec, static int reftable_ref_record_copy_from(void *rec, const void *src_rec,
int hash_size) int hash_size)
{ {
struct reftable_ref_record *ref = rec; struct reftable_ref_record *ref = rec;
const struct reftable_ref_record *src = src_rec; const struct reftable_ref_record *src = src_rec;
char *refname = NULL; char *refname = NULL;
size_t refname_cap = 0; size_t refname_cap = 0;
int err;
assert(hash_size > 0); 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, REFTABLE_ALLOC_GROW(ref->refname, refname_len + 1,
ref->refname_cap); ref->refname_cap);
if (!ref->refname) {
err = REFTABLE_OUT_OF_MEMORY_ERROR;
goto out;
}
memcpy(ref->refname, src->refname, refname_len); memcpy(ref->refname, src->refname, refname_len);
ref->refname[refname_len] = 0; 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); src->value.val2.target_value, hash_size);
break; break;
case REFTABLE_REF_SYMREF: 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; break;
} }
err = 0;
out:
return err;
} }
static void reftable_ref_record_release_void(void *rec) 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; uint64_t update_index = 0;
const char *refname = NULL; const char *refname = NULL;
size_t refname_cap = 0; size_t refname_cap = 0;
int n; int n, err;
assert(hash_size > 0); 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); SWAP(r->refname_cap, refname_cap);
REFTABLE_ALLOC_GROW(r->refname, key.len + 1, r->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); memcpy(r->refname, key.buf, key.len);
r->refname[key.len] = 0; r->refname[key.len] = 0;
@@ -369,7 +387,8 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
switch (val_type) { switch (val_type) {
case REFTABLE_REF_VAL1: case REFTABLE_REF_VAL1:
if (in.len < hash_size) { if (in.len < hash_size) {
return -1; err = REFTABLE_FORMAT_ERROR;
goto done;
} }
memcpy(r->value.val1, in.buf, hash_size); 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: case REFTABLE_REF_VAL2:
if (in.len < 2 * hash_size) { if (in.len < 2 * hash_size) {
return -1; err = REFTABLE_FORMAT_ERROR;
goto done;
} }
memcpy(r->value.val2.value, in.buf, hash_size); 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: { case REFTABLE_REF_SYMREF: {
int n = decode_string(scratch, in); int n = decode_string(scratch, in);
if (n < 0) { if (n < 0) {
return -1; err = REFTABLE_FORMAT_ERROR;
goto done;
} }
string_view_consume(&in, n); string_view_consume(&in, n);
r->value.symref = strbuf_detach(scratch, NULL); 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; return start.len - in.len;
done:
return err;
} }
static int reftable_ref_record_is_deletion_void(const void *p) 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) static void reftable_obj_record_release(void *rec)
{ {
struct reftable_obj_record *obj = rec; struct reftable_obj_record *obj = rec;
FREE_AND_NULL(obj->hash_prefix); REFTABLE_FREE_AND_NULL(obj->hash_prefix);
FREE_AND_NULL(obj->offsets); REFTABLE_FREE_AND_NULL(obj->offsets);
memset(obj, 0, sizeof(struct reftable_obj_record)); memset(obj, 0, sizeof(struct reftable_obj_record));
} }
static void reftable_obj_record_copy_from(void *rec, const void *src_rec, static int reftable_obj_record_copy_from(void *rec, const void *src_rec,
int hash_size UNUSED) int hash_size UNUSED)
{ {
struct reftable_obj_record *obj = rec; struct reftable_obj_record *obj = rec;
const struct reftable_obj_record *src = const struct reftable_obj_record *src = src_rec;
(const struct reftable_obj_record *)src_rec;
reftable_obj_record_release(obj); reftable_obj_record_release(obj);
REFTABLE_ALLOC_ARRAY(obj->hash_prefix, src->hash_prefix_len); 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; obj->hash_prefix_len = src->hash_prefix_len;
if (src->hash_prefix_len) if (src->hash_prefix_len)
memcpy(obj->hash_prefix, src->hash_prefix, obj->hash_prefix_len); memcpy(obj->hash_prefix, src->hash_prefix, obj->hash_prefix_len);
REFTABLE_ALLOC_ARRAY(obj->offsets, src->offset_len); REFTABLE_ALLOC_ARRAY(obj->offsets, src->offset_len);
if (!obj->offsets)
return REFTABLE_OUT_OF_MEMORY_ERROR;
obj->offset_len = src->offset_len; obj->offset_len = src->offset_len;
COPY_ARRAY(obj->offsets, src->offsets, 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) 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_obj_record_release(r);
REFTABLE_ALLOC_ARRAY(r->hash_prefix, key.len); 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); memcpy(r->hash_prefix, key.buf, key.len);
r->hash_prefix_len = 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; return start.len - in.len;
REFTABLE_ALLOC_ARRAY(r->offsets, count); REFTABLE_ALLOC_ARRAY(r->offsets, count);
if (!r->offsets)
return REFTABLE_OUT_OF_MEMORY_ERROR;
r->offset_len = count; r->offset_len = count;
n = get_var_int(&r->offsets[0], &in); 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)); strbuf_add(dest, i64, sizeof(i64));
} }
static void reftable_log_record_copy_from(void *rec, const void *src_rec, static int reftable_log_record_copy_from(void *rec, const void *src_rec,
int hash_size) int hash_size)
{ {
struct reftable_log_record *dst = rec; struct reftable_log_record *dst = rec;
const struct reftable_log_record *src = const struct reftable_log_record *src =
(const struct reftable_log_record *)src_rec; (const struct reftable_log_record *)src_rec;
int ret;
reftable_log_record_release(dst); reftable_log_record_release(dst);
*dst = *src; *dst = *src;
if (dst->refname) { 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) { switch (dst->value_type) {
case REFTABLE_LOG_DELETION: case REFTABLE_LOG_DELETION:
break; break;
case REFTABLE_LOG_UPDATE: case REFTABLE_LOG_UPDATE:
if (dst->value.update.email) { if (dst->value.update.email)
dst->value.update.email = dst->value.update.email =
xstrdup(dst->value.update.email); reftable_strdup(dst->value.update.email);
} if (dst->value.update.name)
if (dst->value.update.name) {
dst->value.update.name = dst->value.update.name =
xstrdup(dst->value.update.name); reftable_strdup(dst->value.update.name);
} if (dst->value.update.message)
if (dst->value.update.message) {
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, 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); src->value.update.old_hash, hash_size);
break; break;
} }
ret = 0;
out:
return ret;
} }
static void reftable_log_record_release_void(void *rec) 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; struct reftable_log_record *r = rec;
uint64_t max = 0; uint64_t max = 0;
uint64_t ts = 0; uint64_t ts = 0;
int n; int err, n;
if (key.len <= 9 || key.buf[key.len - 9] != 0) if (key.len <= 9 || key.buf[key.len - 9] != 0)
return REFTABLE_FORMAT_ERROR; return REFTABLE_FORMAT_ERROR;
REFTABLE_ALLOC_GROW(r->refname, key.len - 8, r->refname_cap); 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); memcpy(r->refname, key.buf, key.len - 8);
ts = get_be64(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) { if (val_type != r->value_type) {
switch (r->value_type) { switch (r->value_type) {
case REFTABLE_LOG_UPDATE: 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; r->value.update.message_cap = 0;
FREE_AND_NULL(r->value.update.email); REFTABLE_FREE_AND_NULL(r->value.update.email);
FREE_AND_NULL(r->value.update.name); REFTABLE_FREE_AND_NULL(r->value.update.name);
break; break;
case REFTABLE_LOG_DELETION: case REFTABLE_LOG_DELETION:
break; break;
@@ -795,8 +848,10 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
if (val_type == REFTABLE_LOG_DELETION) if (val_type == REFTABLE_LOG_DELETION)
return 0; return 0;
if (in.len < 2 * hash_size) if (in.len < 2 * hash_size) {
return REFTABLE_FORMAT_ERROR; err = REFTABLE_FORMAT_ERROR;
goto done;
}
memcpy(r->value.update.old_hash, in.buf, hash_size); memcpy(r->value.update.old_hash, in.buf, hash_size);
memcpy(r->value.update.new_hash, in.buf + hash_size, 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); string_view_consume(&in, 2 * hash_size);
n = decode_string(scratch, in); n = decode_string(scratch, in);
if (n < 0) if (n < 0) {
err = REFTABLE_FORMAT_ERROR;
goto done; goto done;
}
string_view_consume(&in, n); 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 || if (!r->value.update.name ||
strcmp(r->value.update.name, scratch->buf)) { strcmp(r->value.update.name, scratch->buf)) {
r->value.update.name = char *name = reftable_realloc(r->value.update.name, scratch->len + 1);
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); memcpy(r->value.update.name, scratch->buf, scratch->len);
r->value.update.name[scratch->len] = 0; r->value.update.name[scratch->len] = 0;
} }
n = decode_string(scratch, in); n = decode_string(scratch, in);
if (n < 0) if (n < 0) {
err = REFTABLE_FORMAT_ERROR;
goto done; goto done;
}
string_view_consume(&in, n); string_view_consume(&in, n);
/* Same as above, but for the reflog email. */ /* Same as above, but for the reflog email. */
if (!r->value.update.email || if (!r->value.update.email ||
strcmp(r->value.update.email, scratch->buf)) { strcmp(r->value.update.email, scratch->buf)) {
r->value.update.email = char *email = reftable_realloc(r->value.update.email, scratch->len + 1);
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); memcpy(r->value.update.email, scratch->buf, scratch->len);
r->value.update.email[scratch->len] = 0; r->value.update.email[scratch->len] = 0;
} }
ts = 0; ts = 0;
n = get_var_int(&ts, &in); n = get_var_int(&ts, &in);
if (n < 0) if (n < 0) {
err = REFTABLE_FORMAT_ERROR;
goto done; goto done;
}
string_view_consume(&in, n); string_view_consume(&in, n);
r->value.update.time = ts; r->value.update.time = ts;
if (in.len < 2) if (in.len < 2) {
err = REFTABLE_FORMAT_ERROR;
goto done; goto done;
}
r->value.update.tz_offset = get_be16(in.buf); r->value.update.tz_offset = get_be16(in.buf);
string_view_consume(&in, 2); string_view_consume(&in, 2);
n = decode_string(scratch, in); n = decode_string(scratch, in);
if (n < 0) if (n < 0) {
err = REFTABLE_FORMAT_ERROR;
goto done; goto done;
}
string_view_consume(&in, n); string_view_consume(&in, n);
REFTABLE_ALLOC_GROW(r->value.update.message, scratch->len + 1, REFTABLE_ALLOC_GROW(r->value.update.message, scratch->len + 1,
r->value.update.message_cap); 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); memcpy(r->value.update.message, scratch->buf, scratch->len);
r->value.update.message[scratch->len] = 0; r->value.update.message[scratch->len] = 0;
return start.len - in.len; return start.len - in.len;
done: done:
return REFTABLE_FORMAT_ERROR; return err;
} }
static int null_streq(const char *a, const char *b) 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); strbuf_addbuf(dest, &rec->last_key);
} }
static void reftable_index_record_copy_from(void *rec, const void *src_rec, static int reftable_index_record_copy_from(void *rec, const void *src_rec,
int hash_size UNUSED) int hash_size UNUSED)
{ {
struct reftable_index_record *dst = rec; struct reftable_index_record *dst = rec;
const struct reftable_index_record *src = src_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_reset(&dst->last_key);
strbuf_addbuf(&dst->last_key, &src->last_key); strbuf_addbuf(&dst->last_key, &src->last_key);
dst->offset = src->offset; dst->offset = src->offset;
return 0;
} }
static void reftable_index_record_release(void *rec) 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); 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) struct reftable_record *src, int hash_size)
{ {
assert(src->type == rec->type); assert(src->type == rec->type);
reftable_record_vtable(rec)->copy_from(reftable_record_data(rec), return reftable_record_vtable(rec)->copy_from(reftable_record_data(rec),
reftable_record_data(src), reftable_record_data(src),
hash_size); hash_size);
} }
uint8_t reftable_record_val_type(struct reftable_record *rec) 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). */ /* The record type of ('r' for ref). */
uint8_t type; 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 /* a value of [0..7], indicating record subvariants (eg. ref vs. symref
* vs ref deletion) */ * 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_cmp(struct reftable_record *a, struct reftable_record *b);
int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size); 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_key(struct reftable_record *rec, struct strbuf *dest);
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); struct reftable_record *src, int hash_size);
uint8_t reftable_record_val_type(struct reftable_record *rec); uint8_t reftable_record_val_type(struct reftable_record *rec);
int reftable_record_encode(struct reftable_record *rec, struct string_view dest, int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
int hash_size); 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. */ /* Trying to write out-of-date data. */
REFTABLE_OUTDATED_ERROR = -12, 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 /* 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); uint32_t hash_id);
/* Initialize a merged table iterator for reading refs. */ /* Initialize a merged table iterator for reading refs. */
void reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt, int reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
struct reftable_iterator *it); struct reftable_iterator *it);
/* Initialize a merged table iterator for reading logs. */ /* Initialize a merged table iterator for reading logs. */
void reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt, int reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
struct reftable_iterator *it); struct reftable_iterator *it);
/* returns the max update_index covered by this merged table. */ /* returns the max update_index covered by this merged table. */
uint64_t uint64_t

View File

@@ -46,12 +46,12 @@ void reftable_reader_incref(struct reftable_reader *reader);
void reftable_reader_decref(struct reftable_reader *reader); void reftable_reader_decref(struct reftable_reader *reader);
/* Initialize a reftable iterator for reading refs. */ /* Initialize a reftable iterator for reading refs. */
void reftable_reader_init_ref_iterator(struct reftable_reader *r, int reftable_reader_init_ref_iterator(struct reftable_reader *r,
struct reftable_iterator *it); struct reftable_iterator *it);
/* Initialize a reftable iterator for reading logs. */ /* Initialize a reftable iterator for reading logs. */
void reftable_reader_init_log_iterator(struct reftable_reader *r, int reftable_reader_init_log_iterator(struct reftable_reader *r,
struct reftable_iterator *it); struct reftable_iterator *it);
/* returns the hash ID used in this table. */ /* returns the hash ID used in this table. */
uint32_t reftable_reader_hash_id(struct reftable_reader *r); 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 * be used to iterate through refs. The iterator is valid until the next reload
* or write. * or write.
*/ */
void reftable_stack_init_ref_iterator(struct reftable_stack *st, int reftable_stack_init_ref_iterator(struct reftable_stack *st,
struct reftable_iterator *it); struct reftable_iterator *it);
/* /*
* Initialize an iterator for the merged tables contained in the stack that can * 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 * be used to iterate through logs. The iterator is valid until the next reload
* or write. * or write.
*/ */
void reftable_stack_init_log_iterator(struct reftable_stack *st, int reftable_stack_init_log_iterator(struct reftable_stack *st,
struct reftable_iterator *it); struct reftable_iterator *it);
/* returns the merged_table for seeking. This table is valid until the /* returns the merged_table for seeking. This table is valid until the
* next write or reload, and should not be closed or deleted. * next write or reload, and should not be closed or deleted.

View File

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

View File

@@ -11,28 +11,44 @@ https://developers.google.com/open-source/licenses/bsd
#include "basics.h" #include "basics.h"
struct tree_node *tree_search(void *key, struct tree_node **rootp, struct tree_node *tree_search(struct tree_node *tree,
int (*compare)(const void *, const void *), void *key,
int insert) int (*compare)(const void *, const void *))
{ {
int res; 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 (!*rootp) {
if (!insert) { struct tree_node *n;
REFTABLE_CALLOC_ARRAY(n, 1);
if (!n)
return NULL; return NULL;
} else {
struct tree_node *n; n->key = key;
REFTABLE_CALLOC_ARRAY(n, 1); *rootp = n;
n->key = key; return *rootp;
*rootp = n;
return *rootp;
}
} }
res = compare(key, (*rootp)->key); res = compare(key, (*rootp)->key);
if (res < 0) if (res < 0)
return tree_search(key, &(*rootp)->left, compare, insert); return tree_insert(&(*rootp)->left, key, compare);
else if (res > 0) else if (res > 0)
return tree_search(key, &(*rootp)->right, compare, insert); return tree_insert(&(*rootp)->right, key, compare);
return *rootp; return *rootp;
} }

View File

@@ -15,12 +15,23 @@ struct tree_node {
struct tree_node *left, *right; 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, struct tree_node *tree_search(struct tree_node *tree,
int (*compare)(const void *, const void *), void *key,
int insert); 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. */ /* performs an infix walk of the tree. */
void infix_walk(struct tree_node *t, void (*action)(void *arg, void *key), 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; int n = 0;
if (w->pending_padding > 0) { if (w->pending_padding > 0) {
uint8_t *zeroed = reftable_calloc(w->pending_padding, sizeof(*zeroed)); uint8_t *zeroed;
int n = w->write(w->write_arg, zeroed, w->pending_padding); 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) if (n < 0)
return n; return n;
@@ -102,28 +108,37 @@ static int writer_write_header(struct reftable_writer *w, uint8_t *dest)
return header_size(writer_version(w)); 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; int block_start = 0, ret;
if (w->next == 0) {
if (w->next == 0)
block_start = header_size(writer_version(w)); block_start = header_size(writer_version(w));
}
strbuf_reset(&w->last_key); strbuf_reset(&w->last_key);
block_writer_init(&w->block_writer_data, typ, w->block, ret = block_writer_init(&w->block_writer_data, typ, w->block,
w->opts.block_size, block_start, w->opts.block_size, block_start,
hash_size(w->opts.hash_id)); hash_size(w->opts.hash_id));
if (ret < 0)
return ret;
w->block_writer = &w->block_writer_data; w->block_writer = &w->block_writer_data;
w->block_writer->restart_interval = w->opts.restart_interval; w->block_writer->restart_interval = w->opts.restart_interval;
return 0;
} }
struct reftable_writer * int reftable_writer_new(struct reftable_writer **out,
reftable_new_writer(ssize_t (*writer_func)(void *, const void *, size_t), ssize_t (*writer_func)(void *, const void *, size_t),
int (*flush_func)(void *), int (*flush_func)(void *),
void *writer_arg, const struct reftable_write_options *_opts) 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_write_options opts = {0};
struct reftable_writer *wp;
wp = reftable_calloc(1, sizeof(*wp));
if (!wp)
return REFTABLE_OUT_OF_MEMORY_ERROR;
if (_opts) if (_opts)
opts = *_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->block_writer_data.last_key, 0);
strbuf_init(&wp->last_key, 0); strbuf_init(&wp->last_key, 0);
REFTABLE_CALLOC_ARRAY(wp->block, opts.block_size); 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 = writer_func;
wp->write_arg = writer_arg; wp->write_arg = writer_arg;
wp->opts = opts; wp->opts = opts;
wp->flush = flush_func; wp->flush = flush_func;
writer_reinit_block_writer(wp, BLOCK_TYPE_REF); writer_reinit_block_writer(wp, BLOCK_TYPE_REF);
return wp; *out = wp;
return 0;
} }
void reftable_writer_set_limits(struct reftable_writer *w, uint64_t min, 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); &((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; uint64_t off = w->next;
struct obj_index_tree_node want = { .hash = *hash }; 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, node = tree_search(w->obj_index_tree, &want, &obj_index_tree_node_compare);
&obj_index_tree_node_compare, 0);
struct obj_index_tree_node *key = NULL;
if (!node) { if (!node) {
struct obj_index_tree_node empty = OBJ_INDEX_TREE_NODE_INIT; 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; *key = empty;
strbuf_reset(&key->hash); strbuf_reset(&key->hash);
strbuf_addbuf(&key->hash, hash); strbuf_addbuf(&key->hash, hash);
tree_search((void *)key, &w->obj_index_tree, tree_insert(&w->obj_index_tree, key,
&obj_index_tree_node_compare, 1); &obj_index_tree_node_compare);
} else { } else {
key = node->key; key = node->key;
} }
if (key->offset_len > 0 && key->offsets[key->offset_len - 1] == off) { if (key->offset_len > 0 && key->offsets[key->offset_len - 1] == off)
return; return 0;
}
REFTABLE_ALLOC_GROW(key->offsets, key->offset_len + 1, key->offset_cap); 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; key->offsets[key->offset_len++] = off;
return 0;
} }
static int writer_add_record(struct reftable_writer *w, 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_reset(&w->last_key);
strbuf_addbuf(&w->last_key, &key); strbuf_addbuf(&w->last_key, &key);
if (!w->block_writer) if (!w->block_writer) {
writer_reinit_block_writer(w, reftable_record_type(rec)); 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)) if (block_writer_type(w->block_writer) != reftable_record_type(rec))
BUG("record of type %d added to writer of type %d", 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); err = writer_flush_block(w);
if (err < 0) if (err < 0)
goto done; 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 * 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 .ref = *ref
}, },
}; };
int err = 0; struct strbuf buf = STRBUF_INIT;
int err;
if (!ref->refname) if (!ref->refname ||
return REFTABLE_API_ERROR; ref->update_index < w->min_update_index ||
if (ref->update_index < w->min_update_index ||
ref->update_index > w->max_update_index) ref->update_index > w->max_update_index)
return REFTABLE_API_ERROR; return REFTABLE_API_ERROR;
@@ -296,24 +328,32 @@ int reftable_writer_add_ref(struct reftable_writer *w,
err = writer_add_record(w, &rec); err = writer_add_record(w, &rec);
if (err < 0) if (err < 0)
return err; goto out;
if (!w->opts.skip_index_objects && reftable_ref_record_val1(ref)) { if (!w->opts.skip_index_objects && reftable_ref_record_val1(ref)) {
struct strbuf h = STRBUF_INIT; strbuf_add(&buf, (char *)reftable_ref_record_val1(ref),
strbuf_add(&h, (char *)reftable_ref_record_val1(ref),
hash_size(w->opts.hash_id)); 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)) { if (!w->opts.skip_index_objects && reftable_ref_record_val2(ref)) {
struct strbuf h = STRBUF_INIT; strbuf_reset(&buf);
strbuf_add(&h, reftable_ref_record_val2(ref), strbuf_add(&buf, reftable_ref_record_val2(ref),
hash_size(w->opts.hash_id)); 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, int reftable_writer_add_refs(struct reftable_writer *w,
@@ -436,7 +476,9 @@ static int writer_finish_section(struct reftable_writer *w)
max_level++; max_level++;
index_start = w->next; 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 = w->index;
idx_len = w->index_len; idx_len = w->index_len;
@@ -530,7 +572,10 @@ static void write_object_record(void *void_arg, void *key)
if (arg->err < 0) if (arg->err < 0)
goto done; 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); arg->err = block_writer_add(arg->w->block_writer, &rec);
if (arg->err == 0) if (arg->err == 0)
goto done; goto done;
@@ -548,7 +593,7 @@ static void object_record_free(void *void_arg UNUSED, void *key)
{ {
struct obj_index_tree_node *entry = key; struct obj_index_tree_node *entry = key;
FREE_AND_NULL(entry->offsets); REFTABLE_FREE_AND_NULL(entry->offsets);
strbuf_release(&entry->hash); strbuf_release(&entry->hash);
reftable_free(entry); reftable_free(entry);
} }
@@ -559,16 +604,18 @@ static int writer_dump_object_index(struct reftable_writer *w)
struct common_prefix_arg common = { struct common_prefix_arg common = {
.max = 1, /* obj_id_len should be >= 2. */ .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); infix_walk(w->obj_index_tree, &update_common, &common);
}
w->stats.object_id_len = common.max + 1; w->stats.object_id_len = common.max + 1;
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); infix_walk(w->obj_index_tree, &write_object_record, &closure);
}
if (closure.err < 0) if (closure.err < 0)
return closure.err; 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++) for (size_t i = 0; w->index && i < w->index_len; i++)
strbuf_release(&w->index[i].last_key); strbuf_release(&w->index[i].last_key);
FREE_AND_NULL(w->index); REFTABLE_FREE_AND_NULL(w->index);
w->index_len = 0; w->index_len = 0;
w->index_cap = 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. * case we will end up with a multi-level index.
*/ */
REFTABLE_ALLOC_GROW(w->index, w->index_len + 1, w->index_cap); 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; index_record.offset = w->next;
strbuf_reset(&index_record.last_key); strbuf_reset(&index_record.last_key);
strbuf_addbuf(&index_record.last_key, &w->block_writer->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; const struct git_hash_algo *algop;
int err; 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, ""); err = reftable_iterator_seek_ref(&it, "");
if (err < 0) if (err < 0)
return err; return err;
@@ -63,7 +66,10 @@ static int dump_table(struct reftable_merged_table *mt)
reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);
reftable_ref_record_release(&ref); 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, ""); err = reftable_iterator_seek_log(&it, "");
if (err < 0) if (err < 0)
return err; 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_writer *t_reftable_strbuf_writer(struct strbuf *buf,
struct reftable_write_options *opts) struct reftable_write_options *opts)
{ {
return reftable_new_writer(&strbuf_writer_write, struct reftable_writer *writer;
&strbuf_writer_flush, int ret = reftable_writer_new(&writer, &strbuf_writer_write, &strbuf_writer_flush,
buf, opts); buf, opts);
check(!ret);
return writer;
} }
void t_reftable_write_to_buf(struct strbuf *buf, 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") { if_test ("parse_names works for basic input") {
char in1[] = "line\n"; char in1[] = "line\n";
char in2[] = "a\nb\nc"; char in2[] = "a\nb\nc";
char **out = NULL; char **out = parse_names(in1, strlen(in1));
parse_names(in1, strlen(in1), &out); check(out != NULL);
check_str(out[0], "line"); check_str(out[0], "line");
check(!out[1]); check(!out[1]);
free_names(out); 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[0], "a");
check_str(out[1], "b"); check_str(out[1], "b");
check_str(out[2], "c"); 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") { if_test ("parse_names drops empty string") {
char in[] = "a\n\nb\n"; char in[] = "a\n\nb\n";
char **out = NULL; char **out = parse_names(in, strlen(in));
parse_names(in, strlen(in), &out); check(out != NULL);
check_str(out[0], "a"); check_str(out[0], "a");
/* simply '\n' should be dropped as empty string */ /* simply '\n' should be dropped as empty string */
check_str(out[1], "b"); 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; struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
REFTABLE_CALLOC_ARRAY(block.data, block_size); REFTABLE_CALLOC_ARRAY(block.data, block_size);
check(block.data != NULL);
block.len = block_size; block.len = block_size;
block_source_from_strbuf(&block.source ,&buf); block_source_from_strbuf(&block.source ,&buf);
block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size, ret = block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
header_off, hash_size(GIT_SHA1_FORMAT_ID)); header_off, hash_size(GIT_SHA1_FORMAT_ID));
check(!ret);
rec.u.ref.refname = (char *) ""; rec.u.ref.refname = (char *) "";
rec.u.ref.value_type = REFTABLE_REF_DELETION; 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; struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
REFTABLE_CALLOC_ARRAY(block.data, block_size); REFTABLE_CALLOC_ARRAY(block.data, block_size);
check(block.data != NULL);
block.len = block_size; block.len = block_size;
block_source_from_strbuf(&block.source ,&buf); block_source_from_strbuf(&block.source ,&buf);
block_writer_init(&bw, BLOCK_TYPE_LOG, block.data, block_size, ret = block_writer_init(&bw, BLOCK_TYPE_LOG, block.data, block_size,
header_off, hash_size(GIT_SHA1_FORMAT_ID)); header_off, hash_size(GIT_SHA1_FORMAT_ID));
check(!ret);
for (i = 0; i < N; i++) { for (i = 0; i < N; i++) {
rec.u.log.refname = xstrfmt("branch%02"PRIuMAX , (uintmax_t)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; struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
REFTABLE_CALLOC_ARRAY(block.data, block_size); REFTABLE_CALLOC_ARRAY(block.data, block_size);
check(block.data != NULL);
block.len = block_size; block.len = block_size;
block_source_from_strbuf(&block.source, &buf); block_source_from_strbuf(&block.source, &buf);
block_writer_init(&bw, BLOCK_TYPE_OBJ, block.data, block_size, ret = block_writer_init(&bw, BLOCK_TYPE_OBJ, block.data, block_size,
header_off, hash_size(GIT_SHA1_FORMAT_ID)); header_off, hash_size(GIT_SHA1_FORMAT_ID));
check(!ret);
for (i = 0; i < N; i++) { for (i = 0; i < N; i++) {
uint8_t bytes[] = { i, i + 1, i + 2, i + 3, i + 5 }, *allocated; 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; struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
REFTABLE_CALLOC_ARRAY(block.data, block_size); REFTABLE_CALLOC_ARRAY(block.data, block_size);
check(block.data != NULL);
block.len = block_size; block.len = block_size;
block_source_from_strbuf(&block.source, &buf); block_source_from_strbuf(&block.source, &buf);
block_writer_init(&bw, BLOCK_TYPE_INDEX, block.data, block_size, ret = block_writer_init(&bw, BLOCK_TYPE_INDEX, block.data, block_size,
header_off, hash_size(GIT_SHA1_FORMAT_ID)); header_off, hash_size(GIT_SHA1_FORMAT_ID));
check(!ret);
for (i = 0; i < N; i++) { for (i = 0; i < N; i++) {
strbuf_init(&recs[i].u.idx.last_key, 9); 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; int err;
REFTABLE_CALLOC_ARRAY(*readers, n); REFTABLE_CALLOC_ARRAY(*readers, n);
check(*readers != NULL);
REFTABLE_CALLOC_ARRAY(*source, n); REFTABLE_CALLOC_ARRAY(*source, n);
check(*source != NULL);
for (size_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
t_reftable_write_to_buf(&buf[i], refs[i], sizes[i], NULL, 0, &opts); t_reftable_write_to_buf(&buf[i], refs[i], sizes[i], NULL, 0, &opts);
@@ -82,7 +84,8 @@ static void t_merged_single_record(void)
struct reftable_iterator it = { 0 }; struct reftable_iterator it = { 0 };
int err; 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"); err = reftable_iterator_seek_ref(&it, "a");
check(!err); check(!err);
@@ -161,7 +164,8 @@ static void t_merged_refs(void)
size_t cap = 0; size_t cap = 0;
size_t i; 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"); err = reftable_iterator_seek_ref(&it, "a");
check(!err); check(!err);
check_int(reftable_merged_table_hash_id(mt), ==, GIT_SHA1_FORMAT_ID); 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; int err;
REFTABLE_CALLOC_ARRAY(*readers, n); REFTABLE_CALLOC_ARRAY(*readers, n);
check(*readers != NULL);
REFTABLE_CALLOC_ARRAY(*source, n); REFTABLE_CALLOC_ARRAY(*source, n);
check(*source != NULL);
for (size_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
t_reftable_write_to_buf(&buf[i], NULL, 0, logs[i], sizes[i], &opts); t_reftable_write_to_buf(&buf[i], NULL, 0, logs[i], sizes[i], &opts);
@@ -367,7 +373,8 @@ static void t_merged_logs(void)
size_t cap = 0; size_t cap = 0;
size_t i; 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"); err = reftable_iterator_seek_log(&it, "a");
check(!err); check(!err);
check_int(reftable_merged_table_hash_id(mt), ==, GIT_SHA1_FORMAT_ID); 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], check(reftable_log_record_equal(want[i], &out[i],
GIT_SHA1_RAWSZ)); 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); err = reftable_iterator_seek_log_at(&it, "a", 2);
check(!err); check(!err);
reftable_log_record_release(&out[0]); 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; int i;
REFTABLE_CALLOC_ARRAY(*names, N + 1); REFTABLE_CALLOC_ARRAY(*names, N + 1);
check(*names != NULL);
REFTABLE_CALLOC_ARRAY(refs, N); REFTABLE_CALLOC_ARRAY(refs, N);
check(refs != NULL);
REFTABLE_CALLOC_ARRAY(logs, N); REFTABLE_CALLOC_ARRAY(logs, N);
check(logs != NULL);
for (i = 0; i < N; i++) { for (i = 0; i < N; i++) {
refs[i].refname = (*names)[i] = xstrfmt("refs/heads/branch%02d", 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); t_reftable_write_to_buf(buf, refs, N, logs, N, &opts);
free(refs); reftable_free(refs);
free(logs); reftable_free(logs);
} }
static void t_log_buffer_size(void) static void t_log_buffer_size(void)
@@ -150,23 +153,25 @@ static void t_log_overflow(void)
static void t_log_write_read(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 = { struct reftable_write_options opts = {
.block_size = 256, .block_size = 256,
}; };
struct reftable_ref_record ref = { 0 }; struct reftable_ref_record ref = { 0 };
int i = 0;
struct reftable_log_record log = { 0 }; struct reftable_log_record log = { 0 };
int n;
struct reftable_iterator it = { 0 }; struct reftable_iterator it = { 0 };
struct reftable_reader *reader; struct reftable_reader *reader;
struct reftable_block_source source = { 0 }; struct reftable_block_source source = { 0 };
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
const struct reftable_stats *stats = NULL; 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); reftable_writer_set_limits(w, 0, N);
for (i = 0; i < N; i++) { for (i = 0; i < N; i++) {
char name[256]; char name[256];
struct reftable_ref_record ref = { 0 }; struct reftable_ref_record ref = { 0 };
@@ -178,6 +183,7 @@ static void t_log_write_read(void)
err = reftable_writer_add_ref(w, &ref); err = reftable_writer_add_ref(w, &ref);
check(!err); check(!err);
} }
for (i = 0; i < N; i++) { for (i = 0; i < N; i++) {
struct reftable_log_record log = { 0 }; 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"); err = reftable_reader_new(&reader, &source, "file.log");
check(!err); 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]); err = reftable_iterator_seek_ref(&it, names[N - 1]);
check(!err); check(!err);
@@ -221,8 +228,8 @@ static void t_log_write_read(void)
reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);
reftable_ref_record_release(&ref); reftable_ref_record_release(&ref);
reftable_reader_init_log_iterator(reader, &it); err = reftable_reader_init_log_iterator(reader, &it);
check(!err);
err = reftable_iterator_seek_log(&it, ""); err = reftable_iterator_seek_log(&it, "");
check(!err); check(!err);
@@ -296,7 +303,8 @@ static void t_log_zlib_corruption(void)
err = reftable_reader_new(&reader, &source, "file.log"); err = reftable_reader_new(&reader, &source, "file.log");
check(!err); 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"); err = reftable_iterator_seek_log(&it, "refname");
check_int(err, ==, REFTABLE_ZLIB_ERROR); 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"); err = reftable_reader_new(&reader, &source, "file.ref");
check(!err); 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, ""); err = reftable_iterator_seek_ref(&it, "");
check(!err); check(!err);
@@ -376,7 +385,8 @@ static void t_table_read_api(void)
err = reftable_reader_new(&reader, &source, "file.ref"); err = reftable_reader_new(&reader, &source, "file.ref");
check(!err); 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]); err = reftable_iterator_seek_ref(&it, names[0]);
check(!err); check(!err);
@@ -419,7 +429,8 @@ static void t_table_read_write_seek(int index, int hash_id)
} }
for (i = 1; i < N; i++) { 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]); err = reftable_iterator_seek_ref(&it, names[i]);
check(!err); check(!err);
err = reftable_iterator_next_ref(&it, &ref); 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, names[N - 1]);
strbuf_addstr(&pastLast, "/"); 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); err = reftable_iterator_seek_ref(&it, pastLast.buf);
if (err == 0) { if (err == 0) {
struct reftable_ref_record ref = { 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) static void t_table_refs_for(int indexed)
{ {
int N = 50; char **want_names;
char **want_names = reftable_calloc(N + 1, sizeof(*want_names));
int want_names_len = 0; int want_names_len = 0;
uint8_t want_hash[GIT_SHA1_RAWSZ]; uint8_t want_hash[GIT_SHA1_RAWSZ];
@@ -479,15 +490,15 @@ static void t_table_refs_for(int indexed)
.block_size = 256, .block_size = 256,
}; };
struct reftable_ref_record ref = { 0 }; struct reftable_ref_record ref = { 0 };
int i = 0;
int n;
int err;
struct reftable_reader *reader; struct reftable_reader *reader;
struct reftable_block_source source = { 0 }; struct reftable_block_source source = { 0 };
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
struct reftable_iterator it = { 0 }; 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); 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) if (!indexed)
reader->obj_offsets.is_present = 0; 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, ""); err = reftable_iterator_seek_ref(&it, "");
check(!err); check(!err);
reftable_iterator_destroy(&it); reftable_iterator_destroy(&it);
@@ -593,7 +605,8 @@ static void t_write_empty_table(void)
err = reftable_reader_new(&rd, &source, "filename"); err = reftable_reader_new(&rd, &source, "filename");
check(!err); 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, ""); err = reftable_iterator_seek_ref(&it, "");
check(!err); 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 * Seeking the log uses the log index now. In case there is any
* confusion regarding indices we would notice here. * confusion regarding indices we would notice here.
*/ */
reftable_reader_init_log_iterator(reader, &it); err = reftable_reader_init_log_iterator(reader, &it);
check(!err);
err = reftable_iterator_seek_log(&it, ""); err = reftable_iterator_seek_log(&it, "");
check(!err); check(!err);
@@ -858,7 +872,8 @@ static void t_write_multi_level_index(void)
/* /*
* Seeking the last ref should work as expected. * 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"); err = reftable_iterator_seek_ref(&it, "refs/heads/199");
check(!err); check(!err);

View File

@@ -661,7 +661,9 @@ static void t_reftable_stack_iterator(void)
reftable_iterator_destroy(&it); 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); reftable_iterator_seek_log(&it, logs[0].refname);
for (i = 0; ; i++) { for (i = 0; ; i++) {
struct reftable_log_record log = { 0 }; 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++) for (size_t i = 0; i < st->readers_len; i++)
reftable_reader_decref(st->readers[i]); reftable_reader_decref(st->readers[i]);
st->readers_len = 0; st->readers_len = 0;
FREE_AND_NULL(st->readers); REFTABLE_FREE_AND_NULL(st->readers);
} }
static void t_reftable_stack_compaction_concurrent_clean(void) 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. * values[1] and values[10] (inclusive) in the tree.
*/ */
do { 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; i = (i * 7) % 11;
} while (i != 1); } while (i != 1);
for (i = 1; i < ARRAY_SIZE(nodes); i++) { for (i = 1; i < ARRAY_SIZE(nodes); i++) {
check_pointer_eq(&values[i], nodes[i]->key); 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); tree_free(root);
} }
@@ -62,7 +63,8 @@ static void t_infix_walk(void)
size_t count = 0; size_t count = 0;
do { 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; i = (i * 7) % 11;
count++; count++;
} while (i != 1); } while (i != 1);