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