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