mirror of
https://github.com/git/git
synced 2024-11-05 01:58:18 +00:00
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:
commit
5575c713c2
38 changed files with 894 additions and 409 deletions
1
Makefile
1
Makefile
|
@ -2717,7 +2717,6 @@ REFTABLE_OBJS += reftable/error.o
|
|||
REFTABLE_OBJS += reftable/block.o
|
||||
REFTABLE_OBJS += reftable/blocksource.o
|
||||
REFTABLE_OBJS += reftable/iter.o
|
||||
REFTABLE_OBJS += reftable/publicbasics.o
|
||||
REFTABLE_OBJS += reftable/merged.o
|
||||
REFTABLE_OBJS += reftable/pq.o
|
||||
REFTABLE_OBJS += reftable/reader.o
|
||||
|
|
|
@ -1320,7 +1320,9 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
|
|||
struct reftable_log_record log = {0};
|
||||
struct reftable_iterator it = {0};
|
||||
|
||||
reftable_stack_init_log_iterator(arg->stack, &it);
|
||||
ret = reftable_stack_init_log_iterator(arg->stack, &it);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* When deleting refs we also delete all reflog entries
|
||||
|
@ -1690,7 +1692,10 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
|
|||
* copy over all log entries from the old reflog. Last but not least,
|
||||
* when renaming we also have to delete all the old reflog entries.
|
||||
*/
|
||||
reftable_stack_init_log_iterator(arg->stack, &it);
|
||||
ret = reftable_stack_init_log_iterator(arg->stack, &it);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
ret = reftable_iterator_seek_log(&it, arg->oldname);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
@ -1911,7 +1916,10 @@ static struct reftable_reflog_iterator *reflog_iterator_for_stack(struct reftabl
|
|||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
reftable_stack_init_log_iterator(stack, &iter->iter);
|
||||
ret = reftable_stack_init_log_iterator(stack, &iter->iter);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
ret = reftable_iterator_seek_log(&iter->iter, "");
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
@ -1978,7 +1986,10 @@ static int reftable_be_for_each_reflog_ent_reverse(struct ref_store *ref_store,
|
|||
if (refs->err < 0)
|
||||
return refs->err;
|
||||
|
||||
reftable_stack_init_log_iterator(stack, &it);
|
||||
ret = reftable_stack_init_log_iterator(stack, &it);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
ret = reftable_iterator_seek_log(&it, refname);
|
||||
while (!ret) {
|
||||
ret = reftable_iterator_next_log(&it, &log);
|
||||
|
@ -1994,6 +2005,7 @@ static int reftable_be_for_each_reflog_ent_reverse(struct ref_store *ref_store,
|
|||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
reftable_log_record_release(&log);
|
||||
reftable_iterator_destroy(&it);
|
||||
return ret;
|
||||
|
@ -2015,7 +2027,10 @@ static int reftable_be_for_each_reflog_ent(struct ref_store *ref_store,
|
|||
if (refs->err < 0)
|
||||
return refs->err;
|
||||
|
||||
reftable_stack_init_log_iterator(stack, &it);
|
||||
ret = reftable_stack_init_log_iterator(stack, &it);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
ret = reftable_iterator_seek_log(&it, refname);
|
||||
while (!ret) {
|
||||
struct reftable_log_record log = {0};
|
||||
|
@ -2065,7 +2080,10 @@ static int reftable_be_reflog_exists(struct ref_store *ref_store,
|
|||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
reftable_stack_init_log_iterator(stack, &it);
|
||||
ret = reftable_stack_init_log_iterator(stack, &it);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
ret = reftable_iterator_seek_log(&it, refname);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
@ -2171,7 +2189,9 @@ static int write_reflog_delete_table(struct reftable_writer *writer, void *cb_da
|
|||
|
||||
reftable_writer_set_limits(writer, ts, ts);
|
||||
|
||||
reftable_stack_init_log_iterator(arg->stack, &it);
|
||||
ret = reftable_stack_init_log_iterator(arg->stack, &it);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* In order to delete a table we need to delete all reflog entries one
|
||||
|
@ -2195,6 +2215,7 @@ static int write_reflog_delete_table(struct reftable_writer *writer, void *cb_da
|
|||
ret = reftable_writer_add_log(writer, &tombstone);
|
||||
}
|
||||
|
||||
out:
|
||||
reftable_log_record_release(&log);
|
||||
reftable_iterator_destroy(&it);
|
||||
return ret;
|
||||
|
@ -2333,7 +2354,9 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
|
|||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
reftable_stack_init_log_iterator(stack, &it);
|
||||
ret = reftable_stack_init_log_iterator(stack, &it);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
ret = reftable_iterator_seek_log(&it, refname);
|
||||
if (ret < 0)
|
||||
|
|
|
@ -6,7 +6,68 @@ license that can be found in the LICENSE file or at
|
|||
https://developers.google.com/open-source/licenses/bsd
|
||||
*/
|
||||
|
||||
#define REFTABLE_ALLOW_BANNED_ALLOCATORS
|
||||
#include "basics.h"
|
||||
#include "reftable-basics.h"
|
||||
|
||||
static void *(*reftable_malloc_ptr)(size_t sz);
|
||||
static void *(*reftable_realloc_ptr)(void *, size_t);
|
||||
static void (*reftable_free_ptr)(void *);
|
||||
|
||||
void *reftable_malloc(size_t sz)
|
||||
{
|
||||
if (reftable_malloc_ptr)
|
||||
return (*reftable_malloc_ptr)(sz);
|
||||
return malloc(sz);
|
||||
}
|
||||
|
||||
void *reftable_realloc(void *p, size_t sz)
|
||||
{
|
||||
if (reftable_realloc_ptr)
|
||||
return (*reftable_realloc_ptr)(p, sz);
|
||||
return realloc(p, sz);
|
||||
}
|
||||
|
||||
void reftable_free(void *p)
|
||||
{
|
||||
if (reftable_free_ptr)
|
||||
reftable_free_ptr(p);
|
||||
else
|
||||
free(p);
|
||||
}
|
||||
|
||||
void *reftable_calloc(size_t nelem, size_t elsize)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if (nelem && elsize > SIZE_MAX / nelem)
|
||||
return NULL;
|
||||
|
||||
p = reftable_malloc(nelem * elsize);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
memset(p, 0, nelem * elsize);
|
||||
return p;
|
||||
}
|
||||
|
||||
char *reftable_strdup(const char *str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
char *result = reftable_malloc(len + 1);
|
||||
if (!result)
|
||||
return NULL;
|
||||
memcpy(result, str, len + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
void reftable_set_alloc(void *(*malloc)(size_t),
|
||||
void *(*realloc)(void *, size_t), void (*free)(void *))
|
||||
{
|
||||
reftable_malloc_ptr = malloc;
|
||||
reftable_realloc_ptr = realloc;
|
||||
reftable_free_ptr = free;
|
||||
}
|
||||
|
||||
void put_be24(uint8_t *out, uint32_t i)
|
||||
{
|
||||
|
@ -75,14 +136,14 @@ size_t names_length(const char **names)
|
|||
return p - names;
|
||||
}
|
||||
|
||||
void parse_names(char *buf, int size, char ***namesp)
|
||||
char **parse_names(char *buf, int size)
|
||||
{
|
||||
char **names = NULL;
|
||||
size_t names_cap = 0;
|
||||
size_t names_len = 0;
|
||||
|
||||
char *p = buf;
|
||||
char *end = buf + size;
|
||||
|
||||
while (p < end) {
|
||||
char *next = strchr(p, '\n');
|
||||
if (next && next < end) {
|
||||
|
@ -91,15 +152,29 @@ void parse_names(char *buf, int size, char ***namesp)
|
|||
next = end;
|
||||
}
|
||||
if (p < next) {
|
||||
REFTABLE_ALLOC_GROW(names, names_len + 1, names_cap);
|
||||
names[names_len++] = xstrdup(p);
|
||||
char **names_grown = names;
|
||||
REFTABLE_ALLOC_GROW(names_grown, names_len + 1, names_cap);
|
||||
if (!names_grown)
|
||||
goto err;
|
||||
names = names_grown;
|
||||
|
||||
names[names_len] = reftable_strdup(p);
|
||||
if (!names[names_len++])
|
||||
goto err;
|
||||
}
|
||||
p = next + 1;
|
||||
}
|
||||
|
||||
REFTABLE_REALLOC_ARRAY(names, names_len + 1);
|
||||
names[names_len] = NULL;
|
||||
*namesp = names;
|
||||
|
||||
return names;
|
||||
|
||||
err:
|
||||
for (size_t i = 0; i < names_len; i++)
|
||||
reftable_free(names[i]);
|
||||
reftable_free(names);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int names_equal(const char **a, const char **b)
|
||||
|
@ -121,3 +196,15 @@ int common_prefix_size(struct strbuf *a, struct strbuf *b)
|
|||
|
||||
return p;
|
||||
}
|
||||
|
||||
int hash_size(uint32_t id)
|
||||
{
|
||||
switch (id) {
|
||||
case 0:
|
||||
case GIT_SHA1_FORMAT_ID:
|
||||
return GIT_SHA1_RAWSZ;
|
||||
case GIT_SHA256_FORMAT_ID:
|
||||
return GIT_SHA256_RAWSZ;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ license that can be found in the LICENSE file or at
|
|||
*/
|
||||
|
||||
#include "system.h"
|
||||
#include "reftable-basics.h"
|
||||
|
||||
/* Bigendian en/decoding of integers */
|
||||
|
||||
|
@ -37,9 +38,12 @@ size_t binsearch(size_t sz, int (*f)(size_t k, void *args), void *args);
|
|||
*/
|
||||
void free_names(char **a);
|
||||
|
||||
/* parse a newline separated list of names. `size` is the length of the buffer,
|
||||
* without terminating '\0'. Empty names are discarded. */
|
||||
void parse_names(char *buf, int size, char ***namesp);
|
||||
/*
|
||||
* Parse a newline separated list of names. `size` is the length of the buffer,
|
||||
* without terminating '\0'. Empty names are discarded. Returns a `NULL`
|
||||
* pointer when allocations fail.
|
||||
*/
|
||||
char **parse_names(char *buf, int size);
|
||||
|
||||
/* compares two NULL-terminated arrays of strings. */
|
||||
int names_equal(const char **a, const char **b);
|
||||
|
@ -53,6 +57,7 @@ void *reftable_malloc(size_t sz);
|
|||
void *reftable_realloc(void *p, size_t sz);
|
||||
void reftable_free(void *p);
|
||||
void *reftable_calloc(size_t nelem, size_t elsize);
|
||||
char *reftable_strdup(const char *str);
|
||||
|
||||
#define REFTABLE_ALLOC_ARRAY(x, alloc) (x) = reftable_malloc(st_mult(sizeof(*(x)), (alloc)))
|
||||
#define REFTABLE_CALLOC_ARRAY(x, alloc) (x) = reftable_calloc((alloc), sizeof(*(x)))
|
||||
|
@ -66,9 +71,26 @@ void *reftable_calloc(size_t nelem, size_t elsize);
|
|||
REFTABLE_REALLOC_ARRAY(x, alloc); \
|
||||
} \
|
||||
} while (0)
|
||||
#define REFTABLE_FREE_AND_NULL(p) do { reftable_free(p); (p) = NULL; } while (0)
|
||||
|
||||
#ifndef REFTABLE_ALLOW_BANNED_ALLOCATORS
|
||||
# define REFTABLE_BANNED(func) use_reftable_##func##_instead
|
||||
# undef malloc
|
||||
# define malloc(sz) REFTABLE_BANNED(malloc)
|
||||
# undef realloc
|
||||
# define realloc(ptr, sz) REFTABLE_BANNED(realloc)
|
||||
# undef free
|
||||
# define free(ptr) REFTABLE_BANNED(free)
|
||||
# undef calloc
|
||||
# define calloc(nelem, elsize) REFTABLE_BANNED(calloc)
|
||||
# undef strdup
|
||||
# define strdup(str) REFTABLE_BANNED(strdup)
|
||||
#endif
|
||||
|
||||
/* Find the longest shared prefix size of `a` and `b` */
|
||||
struct strbuf;
|
||||
int common_prefix_size(struct strbuf *a, struct strbuf *b);
|
||||
|
||||
int hash_size(uint32_t id);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -52,6 +52,8 @@ static int block_writer_register_restart(struct block_writer *w, int n,
|
|||
return -1;
|
||||
if (is_restart) {
|
||||
REFTABLE_ALLOC_GROW(w->restarts, w->restart_len + 1, w->restart_cap);
|
||||
if (!w->restarts)
|
||||
return REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
w->restarts[w->restart_len++] = w->next;
|
||||
}
|
||||
|
||||
|
@ -63,8 +65,8 @@ static int block_writer_register_restart(struct block_writer *w, int n,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
|
||||
uint32_t block_size, uint32_t header_off, int hash_size)
|
||||
int block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
|
||||
uint32_t block_size, uint32_t header_off, int hash_size)
|
||||
{
|
||||
bw->buf = buf;
|
||||
bw->hash_size = hash_size;
|
||||
|
@ -78,8 +80,12 @@ void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
|
|||
bw->last_key.len = 0;
|
||||
if (!bw->zstream) {
|
||||
REFTABLE_CALLOC_ARRAY(bw->zstream, 1);
|
||||
if (!bw->zstream)
|
||||
return REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
deflateInit(bw->zstream, 9);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t block_writer_type(struct block_writer *bw)
|
||||
|
@ -163,6 +169,10 @@ int block_writer_finish(struct block_writer *w)
|
|||
*/
|
||||
compressed_len = deflateBound(w->zstream, src_len);
|
||||
REFTABLE_ALLOC_GROW(w->compressed, compressed_len, w->compressed_cap);
|
||||
if (!w->compressed) {
|
||||
ret = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
return ret;
|
||||
}
|
||||
|
||||
w->zstream->next_out = w->compressed;
|
||||
w->zstream->avail_out = compressed_len;
|
||||
|
@ -219,12 +229,21 @@ int block_reader_init(struct block_reader *br, struct reftable_block *block,
|
|||
/* Log blocks specify the *uncompressed* size in their header. */
|
||||
REFTABLE_ALLOC_GROW(br->uncompressed_data, sz,
|
||||
br->uncompressed_cap);
|
||||
if (!br->uncompressed_data) {
|
||||
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Copy over the block header verbatim. It's not compressed. */
|
||||
memcpy(br->uncompressed_data, block->data, block_header_skip);
|
||||
|
||||
if (!br->zstream) {
|
||||
REFTABLE_CALLOC_ARRAY(br->zstream, 1);
|
||||
if (!br->zstream) {
|
||||
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = inflateInit(br->zstream);
|
||||
} else {
|
||||
err = inflateReset(br->zstream);
|
||||
|
@ -532,9 +551,9 @@ int block_iter_seek_key(struct block_iter *it, const struct block_reader *br,
|
|||
void block_writer_release(struct block_writer *bw)
|
||||
{
|
||||
deflateEnd(bw->zstream);
|
||||
FREE_AND_NULL(bw->zstream);
|
||||
FREE_AND_NULL(bw->restarts);
|
||||
FREE_AND_NULL(bw->compressed);
|
||||
REFTABLE_FREE_AND_NULL(bw->zstream);
|
||||
REFTABLE_FREE_AND_NULL(bw->restarts);
|
||||
REFTABLE_FREE_AND_NULL(bw->compressed);
|
||||
strbuf_release(&bw->last_key);
|
||||
/* the block is not owned. */
|
||||
}
|
||||
|
|
|
@ -45,8 +45,8 @@ struct block_writer {
|
|||
/*
|
||||
* initializes the blockwriter to write `typ` entries, using `buf` as temporary
|
||||
* storage. `buf` is not owned by the block_writer. */
|
||||
void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
|
||||
uint32_t block_size, uint32_t header_off, int hash_size);
|
||||
int block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
|
||||
uint32_t block_size, uint32_t header_off, int hash_size);
|
||||
|
||||
/* returns the block type (eg. 'r' for ref records. */
|
||||
uint8_t block_writer_type(struct block_writer *bw);
|
||||
|
|
|
@ -30,6 +30,8 @@ static int strbuf_read_block(void *v, struct reftable_block *dest, uint64_t off,
|
|||
struct strbuf *b = v;
|
||||
assert(off + size <= b->len);
|
||||
REFTABLE_CALLOC_ARRAY(dest->data, size);
|
||||
if (!dest->data)
|
||||
return -1;
|
||||
memcpy(dest->data, b->buf + off, size);
|
||||
dest->len = size;
|
||||
return size;
|
||||
|
@ -98,27 +100,40 @@ int reftable_block_source_from_file(struct reftable_block_source *bs,
|
|||
{
|
||||
struct file_block_source *p;
|
||||
struct stat st;
|
||||
int fd;
|
||||
int fd, err;
|
||||
|
||||
fd = open(name, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (errno == ENOENT)
|
||||
return REFTABLE_NOT_EXIST_ERROR;
|
||||
return -1;
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fstat(fd, &st) < 0) {
|
||||
close(fd);
|
||||
return REFTABLE_IO_ERROR;
|
||||
err = REFTABLE_IO_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(p, 1);
|
||||
if (!p) {
|
||||
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
p->size = st.st_size;
|
||||
p->data = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
close(fd);
|
||||
|
||||
assert(!bs->ops);
|
||||
bs->ops = &file_vtable;
|
||||
bs->arg = p;
|
||||
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
if (err < 0)
|
||||
reftable_free(p);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ const char *reftable_error_str(int err)
|
|||
return "entry too large";
|
||||
case REFTABLE_OUTDATED_ERROR:
|
||||
return "data concurrently modified";
|
||||
case REFTABLE_OUT_OF_MEMORY_ERROR:
|
||||
return "out of memory";
|
||||
case -1:
|
||||
return "general error";
|
||||
default:
|
||||
|
|
|
@ -181,14 +181,20 @@ static int indexed_table_ref_iter_next(void *p, struct reftable_record *rec)
|
|||
}
|
||||
}
|
||||
|
||||
int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
|
||||
int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest,
|
||||
struct reftable_reader *r, uint8_t *oid,
|
||||
int oid_len, uint64_t *offsets, int offset_len)
|
||||
{
|
||||
struct indexed_table_ref_iter empty = INDEXED_TABLE_REF_ITER_INIT;
|
||||
struct indexed_table_ref_iter *itr = reftable_calloc(1, sizeof(*itr));
|
||||
struct indexed_table_ref_iter *itr;
|
||||
int err = 0;
|
||||
|
||||
itr = reftable_calloc(1, sizeof(*itr));
|
||||
if (!itr) {
|
||||
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*itr = empty;
|
||||
itr->r = r;
|
||||
strbuf_add(&itr->oid, oid, oid_len);
|
||||
|
@ -197,10 +203,16 @@ int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
|
|||
itr->offset_len = offset_len;
|
||||
|
||||
err = indexed_table_ref_iter_next_block(itr);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
*dest = itr;
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
if (err < 0) {
|
||||
*dest = NULL;
|
||||
reftable_free(itr);
|
||||
} else {
|
||||
*dest = itr;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
@ -225,7 +237,7 @@ void reftable_iterator_destroy(struct reftable_iterator *it)
|
|||
return;
|
||||
it->ops->close(it->iter_arg);
|
||||
it->ops = NULL;
|
||||
FREE_AND_NULL(it->iter_arg);
|
||||
REFTABLE_FREE_AND_NULL(it->iter_arg);
|
||||
}
|
||||
|
||||
int reftable_iterator_seek_ref(struct reftable_iterator *it,
|
||||
|
|
|
@ -82,7 +82,7 @@ void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it,
|
|||
struct indexed_table_ref_iter *itr);
|
||||
|
||||
/* Takes ownership of `offsets` */
|
||||
int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
|
||||
int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest,
|
||||
struct reftable_reader *r, uint8_t *oid,
|
||||
int oid_len, uint64_t *offsets, int offset_len);
|
||||
|
||||
|
|
|
@ -30,22 +30,6 @@ struct merged_iter {
|
|||
ssize_t advance_index;
|
||||
};
|
||||
|
||||
static void merged_iter_init(struct merged_iter *mi,
|
||||
struct reftable_merged_table *mt,
|
||||
uint8_t typ)
|
||||
{
|
||||
memset(mi, 0, sizeof(*mi));
|
||||
mi->advance_index = -1;
|
||||
mi->suppress_deletions = mt->suppress_deletions;
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(mi->subiters, mt->readers_len);
|
||||
for (size_t i = 0; i < mt->readers_len; i++) {
|
||||
reftable_record_init(&mi->subiters[i].rec, typ);
|
||||
reader_init_iter(mt->readers[i], &mi->subiters[i].iter, typ);
|
||||
}
|
||||
mi->subiters_len = mt->readers_len;
|
||||
}
|
||||
|
||||
static void merged_iter_close(void *p)
|
||||
{
|
||||
struct merged_iter *mi = p;
|
||||
|
@ -70,7 +54,10 @@ static int merged_iter_advance_subiter(struct merged_iter *mi, size_t idx)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
merged_iter_pqueue_add(&mi->pq, &e);
|
||||
err = merged_iter_pqueue_add(&mi->pq, &e);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -216,6 +203,9 @@ int reftable_merged_table_new(struct reftable_merged_table **dest,
|
|||
}
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(m, 1);
|
||||
if (!m)
|
||||
return REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
|
||||
m->readers = readers;
|
||||
m->readers_len = n;
|
||||
m->min = first_min;
|
||||
|
@ -244,25 +234,63 @@ reftable_merged_table_min_update_index(struct reftable_merged_table *mt)
|
|||
return mt->min;
|
||||
}
|
||||
|
||||
void merged_table_init_iter(struct reftable_merged_table *mt,
|
||||
struct reftable_iterator *it,
|
||||
uint8_t typ)
|
||||
int merged_table_init_iter(struct reftable_merged_table *mt,
|
||||
struct reftable_iterator *it,
|
||||
uint8_t typ)
|
||||
{
|
||||
struct merged_iter *mi = reftable_malloc(sizeof(*mi));
|
||||
merged_iter_init(mi, mt, typ);
|
||||
struct merged_subiter *subiters;
|
||||
struct merged_iter *mi = NULL;
|
||||
int ret;
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(subiters, mt->readers_len);
|
||||
if (!subiters) {
|
||||
ret = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < mt->readers_len; i++) {
|
||||
reftable_record_init(&subiters[i].rec, typ);
|
||||
ret = reader_init_iter(mt->readers[i], &subiters[i].iter, typ);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(mi, 1);
|
||||
if (!mi) {
|
||||
ret = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto out;
|
||||
}
|
||||
mi->advance_index = -1;
|
||||
mi->suppress_deletions = mt->suppress_deletions;
|
||||
mi->subiters = subiters;
|
||||
mi->subiters_len = mt->readers_len;
|
||||
|
||||
iterator_from_merged_iter(it, mi);
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
if (ret < 0) {
|
||||
for (size_t i = 0; subiters && i < mt->readers_len; i++) {
|
||||
reftable_iterator_destroy(&subiters[i].iter);
|
||||
reftable_record_release(&subiters[i].rec);
|
||||
}
|
||||
reftable_free(subiters);
|
||||
reftable_free(mi);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
|
||||
struct reftable_iterator *it)
|
||||
int reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
|
||||
struct reftable_iterator *it)
|
||||
{
|
||||
merged_table_init_iter(mt, it, BLOCK_TYPE_REF);
|
||||
return merged_table_init_iter(mt, it, BLOCK_TYPE_REF);
|
||||
}
|
||||
|
||||
void reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
|
||||
struct reftable_iterator *it)
|
||||
int reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
|
||||
struct reftable_iterator *it)
|
||||
{
|
||||
merged_table_init_iter(mt, it, BLOCK_TYPE_LOG);
|
||||
return merged_table_init_iter(mt, it, BLOCK_TYPE_LOG);
|
||||
}
|
||||
|
||||
uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *mt)
|
||||
|
|
|
@ -26,8 +26,8 @@ struct reftable_merged_table {
|
|||
|
||||
struct reftable_iterator;
|
||||
|
||||
void merged_table_init_iter(struct reftable_merged_table *mt,
|
||||
struct reftable_iterator *it,
|
||||
uint8_t typ);
|
||||
int merged_table_init_iter(struct reftable_merged_table *mt,
|
||||
struct reftable_iterator *it,
|
||||
uint8_t typ);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,6 +8,7 @@ license that can be found in the LICENSE file or at
|
|||
|
||||
#include "pq.h"
|
||||
|
||||
#include "reftable-error.h"
|
||||
#include "reftable-record.h"
|
||||
#include "system.h"
|
||||
#include "basics.h"
|
||||
|
@ -44,11 +45,13 @@ struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq)
|
|||
return e;
|
||||
}
|
||||
|
||||
void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e)
|
||||
int merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
REFTABLE_ALLOC_GROW(pq->heap, pq->len + 1, pq->cap);
|
||||
if (!pq->heap)
|
||||
return REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
pq->heap[pq->len++] = *e;
|
||||
|
||||
i = pq->len - 1;
|
||||
|
@ -59,10 +62,12 @@ void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry
|
|||
SWAP(pq->heap[j], pq->heap[i]);
|
||||
i = j;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void merged_iter_pqueue_release(struct merged_iter_pqueue *pq)
|
||||
{
|
||||
FREE_AND_NULL(pq->heap);
|
||||
REFTABLE_FREE_AND_NULL(pq->heap);
|
||||
memset(pq, 0, sizeof(*pq));
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ struct merged_iter_pqueue {
|
|||
};
|
||||
|
||||
struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq);
|
||||
void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e);
|
||||
int merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e);
|
||||
void merged_iter_pqueue_release(struct merged_iter_pqueue *pq);
|
||||
int pq_less(struct pq_entry *a, struct pq_entry *b);
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -554,32 +554,37 @@ static void iterator_from_table_iter(struct reftable_iterator *it,
|
|||
it->ops = &table_iter_vtable;
|
||||
}
|
||||
|
||||
void reader_init_iter(struct reftable_reader *r,
|
||||
struct reftable_iterator *it,
|
||||
uint8_t typ)
|
||||
int reader_init_iter(struct reftable_reader *r,
|
||||
struct reftable_iterator *it,
|
||||
uint8_t typ)
|
||||
{
|
||||
struct reftable_reader_offsets *offs = reader_offsets_for(r, typ);
|
||||
|
||||
if (offs->is_present) {
|
||||
struct table_iter *ti;
|
||||
REFTABLE_ALLOC_ARRAY(ti, 1);
|
||||
if (!ti)
|
||||
return REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
|
||||
table_iter_init(ti, r);
|
||||
iterator_from_table_iter(it, ti);
|
||||
} else {
|
||||
iterator_set_empty(it);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reftable_reader_init_ref_iterator(struct reftable_reader *r,
|
||||
struct reftable_iterator *it)
|
||||
int reftable_reader_init_ref_iterator(struct reftable_reader *r,
|
||||
struct reftable_iterator *it)
|
||||
{
|
||||
reader_init_iter(r, it, BLOCK_TYPE_REF);
|
||||
return reader_init_iter(r, it, BLOCK_TYPE_REF);
|
||||
}
|
||||
|
||||
void reftable_reader_init_log_iterator(struct reftable_reader *r,
|
||||
struct reftable_iterator *it)
|
||||
int reftable_reader_init_log_iterator(struct reftable_reader *r,
|
||||
struct reftable_iterator *it)
|
||||
{
|
||||
reader_init_iter(r, it, BLOCK_TYPE_LOG);
|
||||
return reader_init_iter(r, it, BLOCK_TYPE_LOG);
|
||||
}
|
||||
|
||||
int reftable_reader_new(struct reftable_reader **out,
|
||||
|
@ -593,6 +598,10 @@ int reftable_reader_new(struct reftable_reader **out,
|
|||
int err;
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(r, 1);
|
||||
if (!r) {
|
||||
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need one extra byte to read the type of first block. We also
|
||||
|
@ -622,7 +631,11 @@ int reftable_reader_new(struct reftable_reader **out,
|
|||
|
||||
r->size = file_size - footer_size(r->version);
|
||||
r->source = *source;
|
||||
r->name = xstrdup(name);
|
||||
r->name = reftable_strdup(name);
|
||||
if (!r->name) {
|
||||
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto done;
|
||||
}
|
||||
r->hash_id = 0;
|
||||
r->refcount = 1;
|
||||
|
||||
|
@ -665,7 +678,7 @@ void reftable_reader_decref(struct reftable_reader *r)
|
|||
if (--r->refcount)
|
||||
return;
|
||||
block_source_close(&r->source);
|
||||
FREE_AND_NULL(r->name);
|
||||
REFTABLE_FREE_AND_NULL(r->name);
|
||||
reftable_free(r);
|
||||
}
|
||||
|
||||
|
@ -689,7 +702,10 @@ static int reftable_reader_refs_for_indexed(struct reftable_reader *r,
|
|||
struct indexed_table_ref_iter *itr = NULL;
|
||||
|
||||
/* Look through the reverse index. */
|
||||
reader_init_iter(r, &oit, BLOCK_TYPE_OBJ);
|
||||
err = reader_init_iter(r, &oit, BLOCK_TYPE_OBJ);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
err = iterator_seek(&oit, &want);
|
||||
if (err != 0)
|
||||
goto done;
|
||||
|
@ -707,7 +723,7 @@ static int reftable_reader_refs_for_indexed(struct reftable_reader *r,
|
|||
goto done;
|
||||
}
|
||||
|
||||
err = new_indexed_table_ref_iter(&itr, r, oid, hash_size(r->hash_id),
|
||||
err = indexed_table_ref_iter_new(&itr, r, oid, hash_size(r->hash_id),
|
||||
got.u.obj.offsets,
|
||||
got.u.obj.offset_len);
|
||||
if (err < 0)
|
||||
|
@ -732,21 +748,37 @@ static int reftable_reader_refs_for_unindexed(struct reftable_reader *r,
|
|||
int err;
|
||||
|
||||
REFTABLE_ALLOC_ARRAY(ti, 1);
|
||||
table_iter_init(ti, r);
|
||||
err = table_iter_seek_start(ti, BLOCK_TYPE_REF, 0);
|
||||
if (err < 0) {
|
||||
reftable_free(ti);
|
||||
return err;
|
||||
if (!ti) {
|
||||
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
filter = reftable_malloc(sizeof(struct filtering_ref_iterator));
|
||||
table_iter_init(ti, r);
|
||||
err = table_iter_seek_start(ti, BLOCK_TYPE_REF, 0);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
filter = reftable_malloc(sizeof(*filter));
|
||||
if (!filter) {
|
||||
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto out;
|
||||
}
|
||||
*filter = empty;
|
||||
|
||||
strbuf_add(&filter->oid, oid, oid_len);
|
||||
iterator_from_table_iter(&filter->it, ti);
|
||||
|
||||
iterator_from_filtering_ref_iterator(it, filter);
|
||||
return 0;
|
||||
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
if (err < 0) {
|
||||
if (ti)
|
||||
table_iter_close(ti);
|
||||
reftable_free(ti);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int reftable_reader_refs_for(struct reftable_reader *r,
|
||||
|
|
|
@ -56,9 +56,9 @@ struct reftable_reader {
|
|||
|
||||
const char *reader_name(struct reftable_reader *r);
|
||||
|
||||
void reader_init_iter(struct reftable_reader *r,
|
||||
struct reftable_iterator *it,
|
||||
uint8_t typ);
|
||||
int reader_init_iter(struct reftable_reader *r,
|
||||
struct reftable_iterator *it,
|
||||
uint8_t typ);
|
||||
|
||||
/* initialize a block reader to read from `r` */
|
||||
int reader_init_block_reader(struct reftable_reader *r, struct block_reader *br,
|
||||
|
|
|
@ -215,13 +215,14 @@ static void reftable_ref_record_key(const void *r, struct strbuf *dest)
|
|||
strbuf_addstr(dest, rec->refname);
|
||||
}
|
||||
|
||||
static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
|
||||
int hash_size)
|
||||
static int reftable_ref_record_copy_from(void *rec, const void *src_rec,
|
||||
int hash_size)
|
||||
{
|
||||
struct reftable_ref_record *ref = rec;
|
||||
const struct reftable_ref_record *src = src_rec;
|
||||
char *refname = NULL;
|
||||
size_t refname_cap = 0;
|
||||
int err;
|
||||
|
||||
assert(hash_size > 0);
|
||||
|
||||
|
@ -236,6 +237,11 @@ static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
|
|||
|
||||
REFTABLE_ALLOC_GROW(ref->refname, refname_len + 1,
|
||||
ref->refname_cap);
|
||||
if (!ref->refname) {
|
||||
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(ref->refname, src->refname, refname_len);
|
||||
ref->refname[refname_len] = 0;
|
||||
}
|
||||
|
@ -254,9 +260,17 @@ static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
|
|||
src->value.val2.target_value, hash_size);
|
||||
break;
|
||||
case REFTABLE_REF_SYMREF:
|
||||
ref->value.symref = xstrdup(src->value.symref);
|
||||
ref->value.symref = reftable_strdup(src->value.symref);
|
||||
if (!ref->value.symref) {
|
||||
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void reftable_ref_record_release_void(void *rec)
|
||||
|
@ -345,7 +359,7 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
|
|||
uint64_t update_index = 0;
|
||||
const char *refname = NULL;
|
||||
size_t refname_cap = 0;
|
||||
int n;
|
||||
int n, err;
|
||||
|
||||
assert(hash_size > 0);
|
||||
|
||||
|
@ -361,6 +375,10 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
|
|||
SWAP(r->refname_cap, refname_cap);
|
||||
|
||||
REFTABLE_ALLOC_GROW(r->refname, key.len + 1, r->refname_cap);
|
||||
if (!r->refname) {
|
||||
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto done;
|
||||
}
|
||||
memcpy(r->refname, key.buf, key.len);
|
||||
r->refname[key.len] = 0;
|
||||
|
||||
|
@ -369,7 +387,8 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
|
|||
switch (val_type) {
|
||||
case REFTABLE_REF_VAL1:
|
||||
if (in.len < hash_size) {
|
||||
return -1;
|
||||
err = REFTABLE_FORMAT_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
memcpy(r->value.val1, in.buf, hash_size);
|
||||
|
@ -378,7 +397,8 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
|
|||
|
||||
case REFTABLE_REF_VAL2:
|
||||
if (in.len < 2 * hash_size) {
|
||||
return -1;
|
||||
err = REFTABLE_FORMAT_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
memcpy(r->value.val2.value, in.buf, hash_size);
|
||||
|
@ -391,7 +411,8 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
|
|||
case REFTABLE_REF_SYMREF: {
|
||||
int n = decode_string(scratch, in);
|
||||
if (n < 0) {
|
||||
return -1;
|
||||
err = REFTABLE_FORMAT_ERROR;
|
||||
goto done;
|
||||
}
|
||||
string_view_consume(&in, n);
|
||||
r->value.symref = strbuf_detach(scratch, NULL);
|
||||
|
@ -405,6 +426,9 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
|
|||
}
|
||||
|
||||
return start.len - in.len;
|
||||
|
||||
done:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int reftable_ref_record_is_deletion_void(const void *p)
|
||||
|
@ -452,28 +476,33 @@ static void reftable_obj_record_key(const void *r, struct strbuf *dest)
|
|||
static void reftable_obj_record_release(void *rec)
|
||||
{
|
||||
struct reftable_obj_record *obj = rec;
|
||||
FREE_AND_NULL(obj->hash_prefix);
|
||||
FREE_AND_NULL(obj->offsets);
|
||||
REFTABLE_FREE_AND_NULL(obj->hash_prefix);
|
||||
REFTABLE_FREE_AND_NULL(obj->offsets);
|
||||
memset(obj, 0, sizeof(struct reftable_obj_record));
|
||||
}
|
||||
|
||||
static void reftable_obj_record_copy_from(void *rec, const void *src_rec,
|
||||
int hash_size UNUSED)
|
||||
static int reftable_obj_record_copy_from(void *rec, const void *src_rec,
|
||||
int hash_size UNUSED)
|
||||
{
|
||||
struct reftable_obj_record *obj = rec;
|
||||
const struct reftable_obj_record *src =
|
||||
(const struct reftable_obj_record *)src_rec;
|
||||
const struct reftable_obj_record *src = src_rec;
|
||||
|
||||
reftable_obj_record_release(obj);
|
||||
|
||||
REFTABLE_ALLOC_ARRAY(obj->hash_prefix, src->hash_prefix_len);
|
||||
if (!obj->hash_prefix)
|
||||
return REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
obj->hash_prefix_len = src->hash_prefix_len;
|
||||
if (src->hash_prefix_len)
|
||||
memcpy(obj->hash_prefix, src->hash_prefix, obj->hash_prefix_len);
|
||||
|
||||
REFTABLE_ALLOC_ARRAY(obj->offsets, src->offset_len);
|
||||
if (!obj->offsets)
|
||||
return REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
obj->offset_len = src->offset_len;
|
||||
COPY_ARRAY(obj->offsets, src->offsets, src->offset_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t reftable_obj_record_val_type(const void *rec)
|
||||
|
@ -533,6 +562,8 @@ static int reftable_obj_record_decode(void *rec, struct strbuf key,
|
|||
reftable_obj_record_release(r);
|
||||
|
||||
REFTABLE_ALLOC_ARRAY(r->hash_prefix, key.len);
|
||||
if (!r->hash_prefix)
|
||||
return REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
memcpy(r->hash_prefix, key.buf, key.len);
|
||||
r->hash_prefix_len = key.len;
|
||||
|
||||
|
@ -551,6 +582,8 @@ static int reftable_obj_record_decode(void *rec, struct strbuf key,
|
|||
return start.len - in.len;
|
||||
|
||||
REFTABLE_ALLOC_ARRAY(r->offsets, count);
|
||||
if (!r->offsets)
|
||||
return REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
r->offset_len = count;
|
||||
|
||||
n = get_var_int(&r->offsets[0], &in);
|
||||
|
@ -646,33 +679,44 @@ static void reftable_log_record_key(const void *r, struct strbuf *dest)
|
|||
strbuf_add(dest, i64, sizeof(i64));
|
||||
}
|
||||
|
||||
static void reftable_log_record_copy_from(void *rec, const void *src_rec,
|
||||
int hash_size)
|
||||
static int reftable_log_record_copy_from(void *rec, const void *src_rec,
|
||||
int hash_size)
|
||||
{
|
||||
struct reftable_log_record *dst = rec;
|
||||
const struct reftable_log_record *src =
|
||||
(const struct reftable_log_record *)src_rec;
|
||||
int ret;
|
||||
|
||||
reftable_log_record_release(dst);
|
||||
*dst = *src;
|
||||
|
||||
if (dst->refname) {
|
||||
dst->refname = xstrdup(dst->refname);
|
||||
dst->refname = reftable_strdup(dst->refname);
|
||||
if (!dst->refname) {
|
||||
ret = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
switch (dst->value_type) {
|
||||
case REFTABLE_LOG_DELETION:
|
||||
break;
|
||||
case REFTABLE_LOG_UPDATE:
|
||||
if (dst->value.update.email) {
|
||||
if (dst->value.update.email)
|
||||
dst->value.update.email =
|
||||
xstrdup(dst->value.update.email);
|
||||
}
|
||||
if (dst->value.update.name) {
|
||||
reftable_strdup(dst->value.update.email);
|
||||
if (dst->value.update.name)
|
||||
dst->value.update.name =
|
||||
xstrdup(dst->value.update.name);
|
||||
}
|
||||
if (dst->value.update.message) {
|
||||
reftable_strdup(dst->value.update.name);
|
||||
if (dst->value.update.message)
|
||||
dst->value.update.message =
|
||||
xstrdup(dst->value.update.message);
|
||||
reftable_strdup(dst->value.update.message);
|
||||
|
||||
if (!dst->value.update.email ||
|
||||
!dst->value.update.name ||
|
||||
!dst->value.update.message) {
|
||||
ret = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(dst->value.update.new_hash,
|
||||
|
@ -681,6 +725,10 @@ static void reftable_log_record_copy_from(void *rec, const void *src_rec,
|
|||
src->value.update.old_hash, hash_size);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void reftable_log_record_release_void(void *rec)
|
||||
|
@ -767,12 +815,17 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
|
|||
struct reftable_log_record *r = rec;
|
||||
uint64_t max = 0;
|
||||
uint64_t ts = 0;
|
||||
int n;
|
||||
int err, n;
|
||||
|
||||
if (key.len <= 9 || key.buf[key.len - 9] != 0)
|
||||
return REFTABLE_FORMAT_ERROR;
|
||||
|
||||
REFTABLE_ALLOC_GROW(r->refname, key.len - 8, r->refname_cap);
|
||||
if (!r->refname) {
|
||||
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
memcpy(r->refname, key.buf, key.len - 8);
|
||||
ts = get_be64(key.buf + key.len - 8);
|
||||
|
||||
|
@ -781,10 +834,10 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
|
|||
if (val_type != r->value_type) {
|
||||
switch (r->value_type) {
|
||||
case REFTABLE_LOG_UPDATE:
|
||||
FREE_AND_NULL(r->value.update.message);
|
||||
REFTABLE_FREE_AND_NULL(r->value.update.message);
|
||||
r->value.update.message_cap = 0;
|
||||
FREE_AND_NULL(r->value.update.email);
|
||||
FREE_AND_NULL(r->value.update.name);
|
||||
REFTABLE_FREE_AND_NULL(r->value.update.email);
|
||||
REFTABLE_FREE_AND_NULL(r->value.update.name);
|
||||
break;
|
||||
case REFTABLE_LOG_DELETION:
|
||||
break;
|
||||
|
@ -795,8 +848,10 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
|
|||
if (val_type == REFTABLE_LOG_DELETION)
|
||||
return 0;
|
||||
|
||||
if (in.len < 2 * hash_size)
|
||||
return REFTABLE_FORMAT_ERROR;
|
||||
if (in.len < 2 * hash_size) {
|
||||
err = REFTABLE_FORMAT_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
memcpy(r->value.update.old_hash, in.buf, hash_size);
|
||||
memcpy(r->value.update.new_hash, in.buf + hash_size, hash_size);
|
||||
|
@ -804,8 +859,10 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
|
|||
string_view_consume(&in, 2 * hash_size);
|
||||
|
||||
n = decode_string(scratch, in);
|
||||
if (n < 0)
|
||||
if (n < 0) {
|
||||
err = REFTABLE_FORMAT_ERROR;
|
||||
goto done;
|
||||
}
|
||||
string_view_consume(&in, n);
|
||||
|
||||
/*
|
||||
|
@ -816,52 +873,75 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
|
|||
*/
|
||||
if (!r->value.update.name ||
|
||||
strcmp(r->value.update.name, scratch->buf)) {
|
||||
r->value.update.name =
|
||||
reftable_realloc(r->value.update.name, scratch->len + 1);
|
||||
char *name = reftable_realloc(r->value.update.name, scratch->len + 1);
|
||||
if (!name) {
|
||||
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
r->value.update.name = name;
|
||||
memcpy(r->value.update.name, scratch->buf, scratch->len);
|
||||
r->value.update.name[scratch->len] = 0;
|
||||
}
|
||||
|
||||
n = decode_string(scratch, in);
|
||||
if (n < 0)
|
||||
if (n < 0) {
|
||||
err = REFTABLE_FORMAT_ERROR;
|
||||
goto done;
|
||||
}
|
||||
string_view_consume(&in, n);
|
||||
|
||||
/* Same as above, but for the reflog email. */
|
||||
if (!r->value.update.email ||
|
||||
strcmp(r->value.update.email, scratch->buf)) {
|
||||
r->value.update.email =
|
||||
reftable_realloc(r->value.update.email, scratch->len + 1);
|
||||
char *email = reftable_realloc(r->value.update.email, scratch->len + 1);
|
||||
if (!email) {
|
||||
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
r->value.update.email = email;
|
||||
memcpy(r->value.update.email, scratch->buf, scratch->len);
|
||||
r->value.update.email[scratch->len] = 0;
|
||||
}
|
||||
|
||||
ts = 0;
|
||||
n = get_var_int(&ts, &in);
|
||||
if (n < 0)
|
||||
if (n < 0) {
|
||||
err = REFTABLE_FORMAT_ERROR;
|
||||
goto done;
|
||||
}
|
||||
string_view_consume(&in, n);
|
||||
r->value.update.time = ts;
|
||||
if (in.len < 2)
|
||||
if (in.len < 2) {
|
||||
err = REFTABLE_FORMAT_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
r->value.update.tz_offset = get_be16(in.buf);
|
||||
string_view_consume(&in, 2);
|
||||
|
||||
n = decode_string(scratch, in);
|
||||
if (n < 0)
|
||||
if (n < 0) {
|
||||
err = REFTABLE_FORMAT_ERROR;
|
||||
goto done;
|
||||
}
|
||||
string_view_consume(&in, n);
|
||||
|
||||
REFTABLE_ALLOC_GROW(r->value.update.message, scratch->len + 1,
|
||||
r->value.update.message_cap);
|
||||
if (!r->value.update.message) {
|
||||
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
memcpy(r->value.update.message, scratch->buf, scratch->len);
|
||||
r->value.update.message[scratch->len] = 0;
|
||||
|
||||
return start.len - in.len;
|
||||
|
||||
done:
|
||||
return REFTABLE_FORMAT_ERROR;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int null_streq(const char *a, const char *b)
|
||||
|
@ -954,8 +1034,8 @@ static void reftable_index_record_key(const void *r, struct strbuf *dest)
|
|||
strbuf_addbuf(dest, &rec->last_key);
|
||||
}
|
||||
|
||||
static void reftable_index_record_copy_from(void *rec, const void *src_rec,
|
||||
int hash_size UNUSED)
|
||||
static int reftable_index_record_copy_from(void *rec, const void *src_rec,
|
||||
int hash_size UNUSED)
|
||||
{
|
||||
struct reftable_index_record *dst = rec;
|
||||
const struct reftable_index_record *src = src_rec;
|
||||
|
@ -963,6 +1043,8 @@ static void reftable_index_record_copy_from(void *rec, const void *src_rec,
|
|||
strbuf_reset(&dst->last_key);
|
||||
strbuf_addbuf(&dst->last_key, &src->last_key);
|
||||
dst->offset = src->offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void reftable_index_record_release(void *rec)
|
||||
|
@ -1054,14 +1136,14 @@ int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
|
|||
dest, hash_size);
|
||||
}
|
||||
|
||||
void reftable_record_copy_from(struct reftable_record *rec,
|
||||
int reftable_record_copy_from(struct reftable_record *rec,
|
||||
struct reftable_record *src, int hash_size)
|
||||
{
|
||||
assert(src->type == rec->type);
|
||||
|
||||
reftable_record_vtable(rec)->copy_from(reftable_record_data(rec),
|
||||
reftable_record_data(src),
|
||||
hash_size);
|
||||
return reftable_record_vtable(rec)->copy_from(reftable_record_data(rec),
|
||||
reftable_record_data(src),
|
||||
hash_size);
|
||||
}
|
||||
|
||||
uint8_t reftable_record_val_type(struct reftable_record *rec)
|
||||
|
|
|
@ -44,7 +44,7 @@ struct reftable_record_vtable {
|
|||
/* The record type of ('r' for ref). */
|
||||
uint8_t type;
|
||||
|
||||
void (*copy_from)(void *dest, const void *src, int hash_size);
|
||||
int (*copy_from)(void *dest, const void *src, int hash_size);
|
||||
|
||||
/* a value of [0..7], indicating record subvariants (eg. ref vs. symref
|
||||
* vs ref deletion) */
|
||||
|
@ -137,8 +137,8 @@ void reftable_record_init(struct reftable_record *rec, uint8_t typ);
|
|||
int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b);
|
||||
int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size);
|
||||
void reftable_record_key(struct reftable_record *rec, struct strbuf *dest);
|
||||
void reftable_record_copy_from(struct reftable_record *rec,
|
||||
struct reftable_record *src, int hash_size);
|
||||
int reftable_record_copy_from(struct reftable_record *rec,
|
||||
struct reftable_record *src, int hash_size);
|
||||
uint8_t reftable_record_val_type(struct reftable_record *rec);
|
||||
int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
|
||||
int hash_size);
|
||||
|
|
18
reftable/reftable-basics.h
Normal file
18
reftable/reftable-basics.h
Normal 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
|
|
@ -57,6 +57,9 @@ enum reftable_error {
|
|||
|
||||
/* Trying to write out-of-date data. */
|
||||
REFTABLE_OUTDATED_ERROR = -12,
|
||||
|
||||
/* An allocation has failed due to an out-of-memory situation. */
|
||||
REFTABLE_OUT_OF_MEMORY_ERROR = -13,
|
||||
};
|
||||
|
||||
/* convert the numeric error code to a string. The string should not be
|
||||
|
|
|
@ -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
|
|
@ -37,12 +37,12 @@ int reftable_merged_table_new(struct reftable_merged_table **dest,
|
|||
uint32_t hash_id);
|
||||
|
||||
/* Initialize a merged table iterator for reading refs. */
|
||||
void reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
|
||||
struct reftable_iterator *it);
|
||||
int reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
|
||||
struct reftable_iterator *it);
|
||||
|
||||
/* Initialize a merged table iterator for reading logs. */
|
||||
void reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
|
||||
struct reftable_iterator *it);
|
||||
int reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
|
||||
struct reftable_iterator *it);
|
||||
|
||||
/* returns the max update_index covered by this merged table. */
|
||||
uint64_t
|
||||
|
|
|
@ -46,12 +46,12 @@ void reftable_reader_incref(struct reftable_reader *reader);
|
|||
void reftable_reader_decref(struct reftable_reader *reader);
|
||||
|
||||
/* Initialize a reftable iterator for reading refs. */
|
||||
void reftable_reader_init_ref_iterator(struct reftable_reader *r,
|
||||
struct reftable_iterator *it);
|
||||
int reftable_reader_init_ref_iterator(struct reftable_reader *r,
|
||||
struct reftable_iterator *it);
|
||||
|
||||
/* Initialize a reftable iterator for reading logs. */
|
||||
void reftable_reader_init_log_iterator(struct reftable_reader *r,
|
||||
struct reftable_iterator *it);
|
||||
int reftable_reader_init_log_iterator(struct reftable_reader *r,
|
||||
struct reftable_iterator *it);
|
||||
|
||||
/* returns the hash ID used in this table. */
|
||||
uint32_t reftable_reader_hash_id(struct reftable_reader *r);
|
||||
|
|
|
@ -82,16 +82,16 @@ struct reftable_iterator;
|
|||
* be used to iterate through refs. The iterator is valid until the next reload
|
||||
* or write.
|
||||
*/
|
||||
void reftable_stack_init_ref_iterator(struct reftable_stack *st,
|
||||
struct reftable_iterator *it);
|
||||
int reftable_stack_init_ref_iterator(struct reftable_stack *st,
|
||||
struct reftable_iterator *it);
|
||||
|
||||
/*
|
||||
* Initialize an iterator for the merged tables contained in the stack that can
|
||||
* be used to iterate through logs. The iterator is valid until the next reload
|
||||
* or write.
|
||||
*/
|
||||
void reftable_stack_init_log_iterator(struct reftable_stack *st,
|
||||
struct reftable_iterator *it);
|
||||
int reftable_stack_init_log_iterator(struct reftable_stack *st,
|
||||
struct reftable_iterator *it);
|
||||
|
||||
/* returns the merged_table for seeking. This table is valid until the
|
||||
* next write or reload, and should not be closed or deleted.
|
||||
|
|
|
@ -101,11 +101,13 @@ struct reftable_stats {
|
|||
int object_id_len;
|
||||
};
|
||||
|
||||
/* reftable_new_writer creates a new writer */
|
||||
struct reftable_writer *
|
||||
reftable_new_writer(ssize_t (*writer_func)(void *, const void *, size_t),
|
||||
int (*flush_func)(void *),
|
||||
void *writer_arg, const struct reftable_write_options *opts);
|
||||
struct reftable_writer;
|
||||
|
||||
/* Create a new writer. */
|
||||
int reftable_writer_new(struct reftable_writer **out,
|
||||
ssize_t (*writer_func)(void *, const void *, size_t),
|
||||
int (*flush_func)(void *),
|
||||
void *writer_arg, const struct reftable_write_options *opts);
|
||||
|
||||
/* Set the range of update indices for the records we will add. When writing a
|
||||
table into a stack, the min should be at least
|
||||
|
|
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;
|
||||
|
|
|
@ -11,28 +11,44 @@ license that can be found in the LICENSE file or at
|
|||
|
||||
#include "basics.h"
|
||||
|
||||
struct tree_node *tree_search(void *key, struct tree_node **rootp,
|
||||
int (*compare)(const void *, const void *),
|
||||
int insert)
|
||||
struct tree_node *tree_search(struct tree_node *tree,
|
||||
void *key,
|
||||
int (*compare)(const void *, const void *))
|
||||
{
|
||||
int res;
|
||||
if (!tree)
|
||||
return NULL;
|
||||
res = compare(key, tree->key);
|
||||
if (res < 0)
|
||||
return tree_search(tree->left, key, compare);
|
||||
else if (res > 0)
|
||||
return tree_search(tree->right, key, compare);
|
||||
return tree;
|
||||
}
|
||||
|
||||
struct tree_node *tree_insert(struct tree_node **rootp,
|
||||
void *key,
|
||||
int (*compare)(const void *, const void *))
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!*rootp) {
|
||||
if (!insert) {
|
||||
struct tree_node *n;
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(n, 1);
|
||||
if (!n)
|
||||
return NULL;
|
||||
} else {
|
||||
struct tree_node *n;
|
||||
REFTABLE_CALLOC_ARRAY(n, 1);
|
||||
n->key = key;
|
||||
*rootp = n;
|
||||
return *rootp;
|
||||
}
|
||||
|
||||
n->key = key;
|
||||
*rootp = n;
|
||||
return *rootp;
|
||||
}
|
||||
|
||||
res = compare(key, (*rootp)->key);
|
||||
if (res < 0)
|
||||
return tree_search(key, &(*rootp)->left, compare, insert);
|
||||
return tree_insert(&(*rootp)->left, key, compare);
|
||||
else if (res > 0)
|
||||
return tree_search(key, &(*rootp)->right, compare, insert);
|
||||
return tree_insert(&(*rootp)->right, key, compare);
|
||||
return *rootp;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,12 +15,23 @@ struct tree_node {
|
|||
struct tree_node *left, *right;
|
||||
};
|
||||
|
||||
/* looks for `key` in `rootp` using `compare` as comparison function. If insert
|
||||
* is set, insert the key if it's not found. Else, return NULL.
|
||||
/*
|
||||
* Search the tree for the node matching the given key using `compare` as
|
||||
* comparison function. Returns the node whose key matches or `NULL` in case
|
||||
* the key does not exist in the tree.
|
||||
*/
|
||||
struct tree_node *tree_search(void *key, struct tree_node **rootp,
|
||||
int (*compare)(const void *, const void *),
|
||||
int insert);
|
||||
struct tree_node *tree_search(struct tree_node *tree,
|
||||
void *key,
|
||||
int (*compare)(const void *, const void *));
|
||||
|
||||
/*
|
||||
* Insert a node into the tree. Returns the newly inserted node if the key does
|
||||
* not yet exist. Otherwise it returns the preexisting node. Returns `NULL`
|
||||
* when allocating the new node fails.
|
||||
*/
|
||||
struct tree_node *tree_insert(struct tree_node **rootp,
|
||||
void *key,
|
||||
int (*compare)(const void *, const void *));
|
||||
|
||||
/* performs an infix walk of the tree. */
|
||||
void infix_walk(struct tree_node *t, void (*action)(void *arg, void *key),
|
||||
|
|
|
@ -49,8 +49,14 @@ static int padded_write(struct reftable_writer *w, uint8_t *data, size_t len,
|
|||
{
|
||||
int n = 0;
|
||||
if (w->pending_padding > 0) {
|
||||
uint8_t *zeroed = reftable_calloc(w->pending_padding, sizeof(*zeroed));
|
||||
int n = w->write(w->write_arg, zeroed, w->pending_padding);
|
||||
uint8_t *zeroed;
|
||||
int n;
|
||||
|
||||
zeroed = reftable_calloc(w->pending_padding, sizeof(*zeroed));
|
||||
if (!zeroed)
|
||||
return -1;
|
||||
|
||||
n = w->write(w->write_arg, zeroed, w->pending_padding);
|
||||
if (n < 0)
|
||||
return n;
|
||||
|
||||
|
@ -102,28 +108,37 @@ static int writer_write_header(struct reftable_writer *w, uint8_t *dest)
|
|||
return header_size(writer_version(w));
|
||||
}
|
||||
|
||||
static void writer_reinit_block_writer(struct reftable_writer *w, uint8_t typ)
|
||||
static int writer_reinit_block_writer(struct reftable_writer *w, uint8_t typ)
|
||||
{
|
||||
int block_start = 0;
|
||||
if (w->next == 0) {
|
||||
int block_start = 0, ret;
|
||||
|
||||
if (w->next == 0)
|
||||
block_start = header_size(writer_version(w));
|
||||
}
|
||||
|
||||
strbuf_reset(&w->last_key);
|
||||
block_writer_init(&w->block_writer_data, typ, w->block,
|
||||
w->opts.block_size, block_start,
|
||||
hash_size(w->opts.hash_id));
|
||||
ret = block_writer_init(&w->block_writer_data, typ, w->block,
|
||||
w->opts.block_size, block_start,
|
||||
hash_size(w->opts.hash_id));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
w->block_writer = &w->block_writer_data;
|
||||
w->block_writer->restart_interval = w->opts.restart_interval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct reftable_writer *
|
||||
reftable_new_writer(ssize_t (*writer_func)(void *, const void *, size_t),
|
||||
int (*flush_func)(void *),
|
||||
void *writer_arg, const struct reftable_write_options *_opts)
|
||||
int reftable_writer_new(struct reftable_writer **out,
|
||||
ssize_t (*writer_func)(void *, const void *, size_t),
|
||||
int (*flush_func)(void *),
|
||||
void *writer_arg, const struct reftable_write_options *_opts)
|
||||
{
|
||||
struct reftable_writer *wp = reftable_calloc(1, sizeof(*wp));
|
||||
struct reftable_write_options opts = {0};
|
||||
struct reftable_writer *wp;
|
||||
|
||||
wp = reftable_calloc(1, sizeof(*wp));
|
||||
if (!wp)
|
||||
return REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
|
||||
if (_opts)
|
||||
opts = *_opts;
|
||||
|
@ -134,13 +149,19 @@ reftable_new_writer(ssize_t (*writer_func)(void *, const void *, size_t),
|
|||
strbuf_init(&wp->block_writer_data.last_key, 0);
|
||||
strbuf_init(&wp->last_key, 0);
|
||||
REFTABLE_CALLOC_ARRAY(wp->block, opts.block_size);
|
||||
if (!wp->block) {
|
||||
reftable_free(wp);
|
||||
return REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
}
|
||||
wp->write = writer_func;
|
||||
wp->write_arg = writer_arg;
|
||||
wp->opts = opts;
|
||||
wp->flush = flush_func;
|
||||
writer_reinit_block_writer(wp, BLOCK_TYPE_REF);
|
||||
|
||||
return wp;
|
||||
*out = wp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reftable_writer_set_limits(struct reftable_writer *w, uint64_t min,
|
||||
|
@ -186,34 +207,40 @@ static int obj_index_tree_node_compare(const void *a, const void *b)
|
|||
&((const struct obj_index_tree_node *)b)->hash);
|
||||
}
|
||||
|
||||
static void writer_index_hash(struct reftable_writer *w, struct strbuf *hash)
|
||||
static int writer_index_hash(struct reftable_writer *w, struct strbuf *hash)
|
||||
{
|
||||
uint64_t off = w->next;
|
||||
|
||||
struct obj_index_tree_node want = { .hash = *hash };
|
||||
struct obj_index_tree_node *key;
|
||||
struct tree_node *node;
|
||||
|
||||
struct tree_node *node = tree_search(&want, &w->obj_index_tree,
|
||||
&obj_index_tree_node_compare, 0);
|
||||
struct obj_index_tree_node *key = NULL;
|
||||
node = tree_search(w->obj_index_tree, &want, &obj_index_tree_node_compare);
|
||||
if (!node) {
|
||||
struct obj_index_tree_node empty = OBJ_INDEX_TREE_NODE_INIT;
|
||||
key = reftable_malloc(sizeof(struct obj_index_tree_node));
|
||||
|
||||
key = reftable_malloc(sizeof(*key));
|
||||
if (!key)
|
||||
return REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
|
||||
*key = empty;
|
||||
|
||||
strbuf_reset(&key->hash);
|
||||
strbuf_addbuf(&key->hash, hash);
|
||||
tree_search((void *)key, &w->obj_index_tree,
|
||||
&obj_index_tree_node_compare, 1);
|
||||
tree_insert(&w->obj_index_tree, key,
|
||||
&obj_index_tree_node_compare);
|
||||
} else {
|
||||
key = node->key;
|
||||
}
|
||||
|
||||
if (key->offset_len > 0 && key->offsets[key->offset_len - 1] == off) {
|
||||
return;
|
||||
}
|
||||
if (key->offset_len > 0 && key->offsets[key->offset_len - 1] == off)
|
||||
return 0;
|
||||
|
||||
REFTABLE_ALLOC_GROW(key->offsets, key->offset_len + 1, key->offset_cap);
|
||||
if (!key->offsets)
|
||||
return REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
key->offsets[key->offset_len++] = off;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writer_add_record(struct reftable_writer *w,
|
||||
|
@ -230,8 +257,11 @@ static int writer_add_record(struct reftable_writer *w,
|
|||
|
||||
strbuf_reset(&w->last_key);
|
||||
strbuf_addbuf(&w->last_key, &key);
|
||||
if (!w->block_writer)
|
||||
writer_reinit_block_writer(w, reftable_record_type(rec));
|
||||
if (!w->block_writer) {
|
||||
err = writer_reinit_block_writer(w, reftable_record_type(rec));
|
||||
if (err < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (block_writer_type(w->block_writer) != reftable_record_type(rec))
|
||||
BUG("record of type %d added to writer of type %d",
|
||||
|
@ -254,7 +284,9 @@ static int writer_add_record(struct reftable_writer *w,
|
|||
err = writer_flush_block(w);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
writer_reinit_block_writer(w, reftable_record_type(rec));
|
||||
err = writer_reinit_block_writer(w, reftable_record_type(rec));
|
||||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* Try to add the record to the writer again. If this still fails then
|
||||
|
@ -284,11 +316,11 @@ int reftable_writer_add_ref(struct reftable_writer *w,
|
|||
.ref = *ref
|
||||
},
|
||||
};
|
||||
int err = 0;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
int err;
|
||||
|
||||
if (!ref->refname)
|
||||
return REFTABLE_API_ERROR;
|
||||
if (ref->update_index < w->min_update_index ||
|
||||
if (!ref->refname ||
|
||||
ref->update_index < w->min_update_index ||
|
||||
ref->update_index > w->max_update_index)
|
||||
return REFTABLE_API_ERROR;
|
||||
|
||||
|
@ -296,24 +328,32 @@ int reftable_writer_add_ref(struct reftable_writer *w,
|
|||
|
||||
err = writer_add_record(w, &rec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
goto out;
|
||||
|
||||
if (!w->opts.skip_index_objects && reftable_ref_record_val1(ref)) {
|
||||
struct strbuf h = STRBUF_INIT;
|
||||
strbuf_add(&h, (char *)reftable_ref_record_val1(ref),
|
||||
strbuf_add(&buf, (char *)reftable_ref_record_val1(ref),
|
||||
hash_size(w->opts.hash_id));
|
||||
writer_index_hash(w, &h);
|
||||
strbuf_release(&h);
|
||||
|
||||
err = writer_index_hash(w, &buf);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!w->opts.skip_index_objects && reftable_ref_record_val2(ref)) {
|
||||
struct strbuf h = STRBUF_INIT;
|
||||
strbuf_add(&h, reftable_ref_record_val2(ref),
|
||||
strbuf_reset(&buf);
|
||||
strbuf_add(&buf, reftable_ref_record_val2(ref),
|
||||
hash_size(w->opts.hash_id));
|
||||
writer_index_hash(w, &h);
|
||||
strbuf_release(&h);
|
||||
|
||||
err = writer_index_hash(w, &buf);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
strbuf_release(&buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
int reftable_writer_add_refs(struct reftable_writer *w,
|
||||
|
@ -436,7 +476,9 @@ static int writer_finish_section(struct reftable_writer *w)
|
|||
|
||||
max_level++;
|
||||
index_start = w->next;
|
||||
writer_reinit_block_writer(w, BLOCK_TYPE_INDEX);
|
||||
err = writer_reinit_block_writer(w, BLOCK_TYPE_INDEX);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
idx = w->index;
|
||||
idx_len = w->index_len;
|
||||
|
@ -530,7 +572,10 @@ static void write_object_record(void *void_arg, void *key)
|
|||
if (arg->err < 0)
|
||||
goto done;
|
||||
|
||||
writer_reinit_block_writer(arg->w, BLOCK_TYPE_OBJ);
|
||||
arg->err = writer_reinit_block_writer(arg->w, BLOCK_TYPE_OBJ);
|
||||
if (arg->err < 0)
|
||||
goto done;
|
||||
|
||||
arg->err = block_writer_add(arg->w->block_writer, &rec);
|
||||
if (arg->err == 0)
|
||||
goto done;
|
||||
|
@ -548,7 +593,7 @@ static void object_record_free(void *void_arg UNUSED, void *key)
|
|||
{
|
||||
struct obj_index_tree_node *entry = key;
|
||||
|
||||
FREE_AND_NULL(entry->offsets);
|
||||
REFTABLE_FREE_AND_NULL(entry->offsets);
|
||||
strbuf_release(&entry->hash);
|
||||
reftable_free(entry);
|
||||
}
|
||||
|
@ -559,16 +604,18 @@ static int writer_dump_object_index(struct reftable_writer *w)
|
|||
struct common_prefix_arg common = {
|
||||
.max = 1, /* obj_id_len should be >= 2. */
|
||||
};
|
||||
if (w->obj_index_tree) {
|
||||
int err;
|
||||
|
||||
if (w->obj_index_tree)
|
||||
infix_walk(w->obj_index_tree, &update_common, &common);
|
||||
}
|
||||
w->stats.object_id_len = common.max + 1;
|
||||
|
||||
writer_reinit_block_writer(w, BLOCK_TYPE_OBJ);
|
||||
err = writer_reinit_block_writer(w, BLOCK_TYPE_OBJ);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (w->obj_index_tree) {
|
||||
if (w->obj_index_tree)
|
||||
infix_walk(w->obj_index_tree, &write_object_record, &closure);
|
||||
}
|
||||
|
||||
if (closure.err < 0)
|
||||
return closure.err;
|
||||
|
@ -662,7 +709,7 @@ static void writer_clear_index(struct reftable_writer *w)
|
|||
{
|
||||
for (size_t i = 0; w->index && i < w->index_len; i++)
|
||||
strbuf_release(&w->index[i].last_key);
|
||||
FREE_AND_NULL(w->index);
|
||||
REFTABLE_FREE_AND_NULL(w->index);
|
||||
w->index_len = 0;
|
||||
w->index_cap = 0;
|
||||
}
|
||||
|
@ -726,6 +773,9 @@ static int writer_flush_nonempty_block(struct reftable_writer *w)
|
|||
* case we will end up with a multi-level index.
|
||||
*/
|
||||
REFTABLE_ALLOC_GROW(w->index, w->index_len + 1, w->index_cap);
|
||||
if (!w->index)
|
||||
return REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||
|
||||
index_record.offset = w->next;
|
||||
strbuf_reset(&index_record.last_key);
|
||||
strbuf_addbuf(&index_record.last_key, &w->block_writer->last_key);
|
||||
|
|
|
@ -28,7 +28,10 @@ static int dump_table(struct reftable_merged_table *mt)
|
|||
const struct git_hash_algo *algop;
|
||||
int err;
|
||||
|
||||
reftable_merged_table_init_ref_iterator(mt, &it);
|
||||
err = reftable_merged_table_init_ref_iterator(mt, &it);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = reftable_iterator_seek_ref(&it, "");
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -63,7 +66,10 @@ static int dump_table(struct reftable_merged_table *mt)
|
|||
reftable_iterator_destroy(&it);
|
||||
reftable_ref_record_release(&ref);
|
||||
|
||||
reftable_merged_table_init_log_iterator(mt, &it);
|
||||
err = reftable_merged_table_init_log_iterator(mt, &it);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = reftable_iterator_seek_log(&it, "");
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
|
|
@ -22,9 +22,11 @@ static int strbuf_writer_flush(void *arg UNUSED)
|
|||
struct reftable_writer *t_reftable_strbuf_writer(struct strbuf *buf,
|
||||
struct reftable_write_options *opts)
|
||||
{
|
||||
return reftable_new_writer(&strbuf_writer_write,
|
||||
&strbuf_writer_flush,
|
||||
buf, opts);
|
||||
struct reftable_writer *writer;
|
||||
int ret = reftable_writer_new(&writer, &strbuf_writer_write, &strbuf_writer_flush,
|
||||
buf, opts);
|
||||
check(!ret);
|
||||
return writer;
|
||||
}
|
||||
|
||||
void t_reftable_write_to_buf(struct strbuf *buf,
|
||||
|
|
|
@ -72,13 +72,14 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
|
|||
if_test ("parse_names works for basic input") {
|
||||
char in1[] = "line\n";
|
||||
char in2[] = "a\nb\nc";
|
||||
char **out = NULL;
|
||||
parse_names(in1, strlen(in1), &out);
|
||||
char **out = parse_names(in1, strlen(in1));
|
||||
check(out != NULL);
|
||||
check_str(out[0], "line");
|
||||
check(!out[1]);
|
||||
free_names(out);
|
||||
|
||||
parse_names(in2, strlen(in2), &out);
|
||||
out = parse_names(in2, strlen(in2));
|
||||
check(out != NULL);
|
||||
check_str(out[0], "a");
|
||||
check_str(out[1], "b");
|
||||
check_str(out[2], "c");
|
||||
|
@ -88,8 +89,8 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
|
|||
|
||||
if_test ("parse_names drops empty string") {
|
||||
char in[] = "a\n\nb\n";
|
||||
char **out = NULL;
|
||||
parse_names(in, strlen(in), &out);
|
||||
char **out = parse_names(in, strlen(in));
|
||||
check(out != NULL);
|
||||
check_str(out[0], "a");
|
||||
/* simply '\n' should be dropped as empty string */
|
||||
check_str(out[1], "b");
|
||||
|
|
|
@ -32,10 +32,12 @@ static void t_ref_block_read_write(void)
|
|||
struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(block.data, block_size);
|
||||
check(block.data != NULL);
|
||||
block.len = block_size;
|
||||
block_source_from_strbuf(&block.source ,&buf);
|
||||
block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
|
||||
header_off, hash_size(GIT_SHA1_FORMAT_ID));
|
||||
ret = block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
|
||||
header_off, hash_size(GIT_SHA1_FORMAT_ID));
|
||||
check(!ret);
|
||||
|
||||
rec.u.ref.refname = (char *) "";
|
||||
rec.u.ref.value_type = REFTABLE_REF_DELETION;
|
||||
|
@ -124,10 +126,12 @@ static void t_log_block_read_write(void)
|
|||
struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(block.data, block_size);
|
||||
check(block.data != NULL);
|
||||
block.len = block_size;
|
||||
block_source_from_strbuf(&block.source ,&buf);
|
||||
block_writer_init(&bw, BLOCK_TYPE_LOG, block.data, block_size,
|
||||
header_off, hash_size(GIT_SHA1_FORMAT_ID));
|
||||
ret = block_writer_init(&bw, BLOCK_TYPE_LOG, block.data, block_size,
|
||||
header_off, hash_size(GIT_SHA1_FORMAT_ID));
|
||||
check(!ret);
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
rec.u.log.refname = xstrfmt("branch%02"PRIuMAX , (uintmax_t)i);
|
||||
|
@ -212,10 +216,12 @@ static void t_obj_block_read_write(void)
|
|||
struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(block.data, block_size);
|
||||
check(block.data != NULL);
|
||||
block.len = block_size;
|
||||
block_source_from_strbuf(&block.source, &buf);
|
||||
block_writer_init(&bw, BLOCK_TYPE_OBJ, block.data, block_size,
|
||||
header_off, hash_size(GIT_SHA1_FORMAT_ID));
|
||||
ret = block_writer_init(&bw, BLOCK_TYPE_OBJ, block.data, block_size,
|
||||
header_off, hash_size(GIT_SHA1_FORMAT_ID));
|
||||
check(!ret);
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
uint8_t bytes[] = { i, i + 1, i + 2, i + 3, i + 5 }, *allocated;
|
||||
|
@ -294,10 +300,12 @@ static void t_index_block_read_write(void)
|
|||
struct strbuf want = STRBUF_INIT, buf = STRBUF_INIT;
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(block.data, block_size);
|
||||
check(block.data != NULL);
|
||||
block.len = block_size;
|
||||
block_source_from_strbuf(&block.source, &buf);
|
||||
block_writer_init(&bw, BLOCK_TYPE_INDEX, block.data, block_size,
|
||||
header_off, hash_size(GIT_SHA1_FORMAT_ID));
|
||||
ret = block_writer_init(&bw, BLOCK_TYPE_INDEX, block.data, block_size,
|
||||
header_off, hash_size(GIT_SHA1_FORMAT_ID));
|
||||
check(!ret);
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
strbuf_init(&recs[i].u.idx.last_key, 9);
|
||||
|
|
|
@ -29,7 +29,9 @@ merged_table_from_records(struct reftable_ref_record **refs,
|
|||
int err;
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(*readers, n);
|
||||
check(*readers != NULL);
|
||||
REFTABLE_CALLOC_ARRAY(*source, n);
|
||||
check(*source != NULL);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
t_reftable_write_to_buf(&buf[i], refs[i], sizes[i], NULL, 0, &opts);
|
||||
|
@ -82,7 +84,8 @@ static void t_merged_single_record(void)
|
|||
struct reftable_iterator it = { 0 };
|
||||
int err;
|
||||
|
||||
merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
|
||||
err = merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
|
||||
check(!err);
|
||||
err = reftable_iterator_seek_ref(&it, "a");
|
||||
check(!err);
|
||||
|
||||
|
@ -161,7 +164,8 @@ static void t_merged_refs(void)
|
|||
size_t cap = 0;
|
||||
size_t i;
|
||||
|
||||
merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
|
||||
err = merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
|
||||
check(!err);
|
||||
err = reftable_iterator_seek_ref(&it, "a");
|
||||
check(!err);
|
||||
check_int(reftable_merged_table_hash_id(mt), ==, GIT_SHA1_FORMAT_ID);
|
||||
|
@ -283,7 +287,9 @@ merged_table_from_log_records(struct reftable_log_record **logs,
|
|||
int err;
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(*readers, n);
|
||||
check(*readers != NULL);
|
||||
REFTABLE_CALLOC_ARRAY(*source, n);
|
||||
check(*source != NULL);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
t_reftable_write_to_buf(&buf[i], NULL, 0, logs[i], sizes[i], &opts);
|
||||
|
@ -367,7 +373,8 @@ static void t_merged_logs(void)
|
|||
size_t cap = 0;
|
||||
size_t i;
|
||||
|
||||
merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
|
||||
err = merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
|
||||
check(!err);
|
||||
err = reftable_iterator_seek_log(&it, "a");
|
||||
check(!err);
|
||||
check_int(reftable_merged_table_hash_id(mt), ==, GIT_SHA1_FORMAT_ID);
|
||||
|
@ -390,7 +397,8 @@ static void t_merged_logs(void)
|
|||
check(reftable_log_record_equal(want[i], &out[i],
|
||||
GIT_SHA1_RAWSZ));
|
||||
|
||||
merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
|
||||
err = merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
|
||||
check(!err);
|
||||
err = reftable_iterator_seek_log_at(&it, "a", 2);
|
||||
check(!err);
|
||||
reftable_log_record_release(&out[0]);
|
||||
|
|
|
@ -52,8 +52,11 @@ static void write_table(char ***names, struct strbuf *buf, int N,
|
|||
int i;
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(*names, N + 1);
|
||||
check(*names != NULL);
|
||||
REFTABLE_CALLOC_ARRAY(refs, N);
|
||||
check(refs != NULL);
|
||||
REFTABLE_CALLOC_ARRAY(logs, N);
|
||||
check(logs != NULL);
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
refs[i].refname = (*names)[i] = xstrfmt("refs/heads/branch%02d", i);
|
||||
|
@ -73,8 +76,8 @@ static void write_table(char ***names, struct strbuf *buf, int N,
|
|||
|
||||
t_reftable_write_to_buf(buf, refs, N, logs, N, &opts);
|
||||
|
||||
free(refs);
|
||||
free(logs);
|
||||
reftable_free(refs);
|
||||
reftable_free(logs);
|
||||
}
|
||||
|
||||
static void t_log_buffer_size(void)
|
||||
|
@ -150,23 +153,25 @@ static void t_log_overflow(void)
|
|||
|
||||
static void t_log_write_read(void)
|
||||
{
|
||||
int N = 2;
|
||||
char **names = reftable_calloc(N + 1, sizeof(*names));
|
||||
int err;
|
||||
struct reftable_write_options opts = {
|
||||
.block_size = 256,
|
||||
};
|
||||
struct reftable_ref_record ref = { 0 };
|
||||
int i = 0;
|
||||
struct reftable_log_record log = { 0 };
|
||||
int n;
|
||||
struct reftable_iterator it = { 0 };
|
||||
struct reftable_reader *reader;
|
||||
struct reftable_block_source source = { 0 };
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
|
||||
const struct reftable_stats *stats = NULL;
|
||||
int N = 2, err, i, n;
|
||||
char **names;
|
||||
|
||||
names = reftable_calloc(N + 1, sizeof(*names));
|
||||
check(names != NULL);
|
||||
|
||||
reftable_writer_set_limits(w, 0, N);
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
char name[256];
|
||||
struct reftable_ref_record ref = { 0 };
|
||||
|
@ -178,6 +183,7 @@ static void t_log_write_read(void)
|
|||
err = reftable_writer_add_ref(w, &ref);
|
||||
check(!err);
|
||||
}
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
struct reftable_log_record log = { 0 };
|
||||
|
||||
|
@ -206,7 +212,8 @@ static void t_log_write_read(void)
|
|||
err = reftable_reader_new(&reader, &source, "file.log");
|
||||
check(!err);
|
||||
|
||||
reftable_reader_init_ref_iterator(reader, &it);
|
||||
err = reftable_reader_init_ref_iterator(reader, &it);
|
||||
check(!err);
|
||||
|
||||
err = reftable_iterator_seek_ref(&it, names[N - 1]);
|
||||
check(!err);
|
||||
|
@ -221,8 +228,8 @@ static void t_log_write_read(void)
|
|||
reftable_iterator_destroy(&it);
|
||||
reftable_ref_record_release(&ref);
|
||||
|
||||
reftable_reader_init_log_iterator(reader, &it);
|
||||
|
||||
err = reftable_reader_init_log_iterator(reader, &it);
|
||||
check(!err);
|
||||
err = reftable_iterator_seek_log(&it, "");
|
||||
check(!err);
|
||||
|
||||
|
@ -296,7 +303,8 @@ static void t_log_zlib_corruption(void)
|
|||
err = reftable_reader_new(&reader, &source, "file.log");
|
||||
check(!err);
|
||||
|
||||
reftable_reader_init_log_iterator(reader, &it);
|
||||
err = reftable_reader_init_log_iterator(reader, &it);
|
||||
check(!err);
|
||||
err = reftable_iterator_seek_log(&it, "refname");
|
||||
check_int(err, ==, REFTABLE_ZLIB_ERROR);
|
||||
|
||||
|
@ -325,7 +333,8 @@ static void t_table_read_write_sequential(void)
|
|||
err = reftable_reader_new(&reader, &source, "file.ref");
|
||||
check(!err);
|
||||
|
||||
reftable_reader_init_ref_iterator(reader, &it);
|
||||
err = reftable_reader_init_ref_iterator(reader, &it);
|
||||
check(!err);
|
||||
err = reftable_iterator_seek_ref(&it, "");
|
||||
check(!err);
|
||||
|
||||
|
@ -376,7 +385,8 @@ static void t_table_read_api(void)
|
|||
err = reftable_reader_new(&reader, &source, "file.ref");
|
||||
check(!err);
|
||||
|
||||
reftable_reader_init_ref_iterator(reader, &it);
|
||||
err = reftable_reader_init_ref_iterator(reader, &it);
|
||||
check(!err);
|
||||
err = reftable_iterator_seek_ref(&it, names[0]);
|
||||
check(!err);
|
||||
|
||||
|
@ -419,7 +429,8 @@ static void t_table_read_write_seek(int index, int hash_id)
|
|||
}
|
||||
|
||||
for (i = 1; i < N; i++) {
|
||||
reftable_reader_init_ref_iterator(reader, &it);
|
||||
err = reftable_reader_init_ref_iterator(reader, &it);
|
||||
check(!err);
|
||||
err = reftable_iterator_seek_ref(&it, names[i]);
|
||||
check(!err);
|
||||
err = reftable_iterator_next_ref(&it, &ref);
|
||||
|
@ -435,7 +446,8 @@ static void t_table_read_write_seek(int index, int hash_id)
|
|||
strbuf_addstr(&pastLast, names[N - 1]);
|
||||
strbuf_addstr(&pastLast, "/");
|
||||
|
||||
reftable_reader_init_ref_iterator(reader, &it);
|
||||
err = reftable_reader_init_ref_iterator(reader, &it);
|
||||
check(!err);
|
||||
err = reftable_iterator_seek_ref(&it, pastLast.buf);
|
||||
if (err == 0) {
|
||||
struct reftable_ref_record ref = { 0 };
|
||||
|
@ -470,8 +482,7 @@ static void t_table_read_write_seek_index(void)
|
|||
|
||||
static void t_table_refs_for(int indexed)
|
||||
{
|
||||
int N = 50;
|
||||
char **want_names = reftable_calloc(N + 1, sizeof(*want_names));
|
||||
char **want_names;
|
||||
int want_names_len = 0;
|
||||
uint8_t want_hash[GIT_SHA1_RAWSZ];
|
||||
|
||||
|
@ -479,15 +490,15 @@ static void t_table_refs_for(int indexed)
|
|||
.block_size = 256,
|
||||
};
|
||||
struct reftable_ref_record ref = { 0 };
|
||||
int i = 0;
|
||||
int n;
|
||||
int err;
|
||||
struct reftable_reader *reader;
|
||||
struct reftable_block_source source = { 0 };
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
|
||||
struct reftable_iterator it = { 0 };
|
||||
int j;
|
||||
int N = 50, n, j, err, i;
|
||||
|
||||
want_names = reftable_calloc(N + 1, sizeof(*want_names));
|
||||
check(want_names != NULL);
|
||||
|
||||
t_reftable_set_hash(want_hash, 4, GIT_SHA1_FORMAT_ID);
|
||||
|
||||
|
@ -534,7 +545,8 @@ static void t_table_refs_for(int indexed)
|
|||
if (!indexed)
|
||||
reader->obj_offsets.is_present = 0;
|
||||
|
||||
reftable_reader_init_ref_iterator(reader, &it);
|
||||
err = reftable_reader_init_ref_iterator(reader, &it);
|
||||
check(!err);
|
||||
err = reftable_iterator_seek_ref(&it, "");
|
||||
check(!err);
|
||||
reftable_iterator_destroy(&it);
|
||||
|
@ -593,7 +605,8 @@ static void t_write_empty_table(void)
|
|||
err = reftable_reader_new(&rd, &source, "filename");
|
||||
check(!err);
|
||||
|
||||
reftable_reader_init_ref_iterator(rd, &it);
|
||||
err = reftable_reader_init_ref_iterator(rd, &it);
|
||||
check(!err);
|
||||
err = reftable_iterator_seek_ref(&it, "");
|
||||
check(!err);
|
||||
|
||||
|
@ -802,7 +815,8 @@ static void t_write_multiple_indices(void)
|
|||
* Seeking the log uses the log index now. In case there is any
|
||||
* confusion regarding indices we would notice here.
|
||||
*/
|
||||
reftable_reader_init_log_iterator(reader, &it);
|
||||
err = reftable_reader_init_log_iterator(reader, &it);
|
||||
check(!err);
|
||||
err = reftable_iterator_seek_log(&it, "");
|
||||
check(!err);
|
||||
|
||||
|
@ -858,7 +872,8 @@ static void t_write_multi_level_index(void)
|
|||
/*
|
||||
* Seeking the last ref should work as expected.
|
||||
*/
|
||||
reftable_reader_init_ref_iterator(reader, &it);
|
||||
err = reftable_reader_init_ref_iterator(reader, &it);
|
||||
check(!err);
|
||||
err = reftable_iterator_seek_ref(&it, "refs/heads/199");
|
||||
check(!err);
|
||||
|
||||
|
|
|
@ -661,7 +661,9 @@ static void t_reftable_stack_iterator(void)
|
|||
|
||||
reftable_iterator_destroy(&it);
|
||||
|
||||
reftable_stack_init_log_iterator(st, &it);
|
||||
err = reftable_stack_init_log_iterator(st, &it);
|
||||
check(!err);
|
||||
|
||||
reftable_iterator_seek_log(&it, logs[0].refname);
|
||||
for (i = 0; ; i++) {
|
||||
struct reftable_log_record log = { 0 };
|
||||
|
@ -1209,7 +1211,7 @@ static void unclean_stack_close(struct reftable_stack *st)
|
|||
for (size_t i = 0; i < st->readers_len; i++)
|
||||
reftable_reader_decref(st->readers[i]);
|
||||
st->readers_len = 0;
|
||||
FREE_AND_NULL(st->readers);
|
||||
REFTABLE_FREE_AND_NULL(st->readers);
|
||||
}
|
||||
|
||||
static void t_reftable_stack_compaction_concurrent_clean(void)
|
||||
|
|
|
@ -37,16 +37,17 @@ static void t_tree_search(void)
|
|||
* values[1] and values[10] (inclusive) in the tree.
|
||||
*/
|
||||
do {
|
||||
nodes[i] = tree_search(&values[i], &root, &t_compare, 1);
|
||||
nodes[i] = tree_insert(&root, &values[i], &t_compare);
|
||||
check(nodes[i] != NULL);
|
||||
i = (i * 7) % 11;
|
||||
} while (i != 1);
|
||||
|
||||
for (i = 1; i < ARRAY_SIZE(nodes); i++) {
|
||||
check_pointer_eq(&values[i], nodes[i]->key);
|
||||
check_pointer_eq(nodes[i], tree_search(&values[i], &root, &t_compare, 0));
|
||||
check_pointer_eq(nodes[i], tree_search(root, &values[i], &t_compare));
|
||||
}
|
||||
|
||||
check(!tree_search(values, &root, t_compare, 0));
|
||||
check(!tree_search(root, values, t_compare));
|
||||
tree_free(root);
|
||||
}
|
||||
|
||||
|
@ -62,7 +63,8 @@ static void t_infix_walk(void)
|
|||
size_t count = 0;
|
||||
|
||||
do {
|
||||
tree_search(&values[i], &root, t_compare, 1);
|
||||
struct tree_node *node = tree_insert(&root, &values[i], t_compare);
|
||||
check(node != NULL);
|
||||
i = (i * 7) % 11;
|
||||
count++;
|
||||
} while (i != 1);
|
||||
|
|
Loading…
Reference in a new issue