Merge branch 'kn/reftable-optimize-reloading' into jch
The reftable code has been optimized to avoid an unnecessary stat/reload of the stack when an addition already holds the list_file lock, reducing the number of newfstatat syscalls from linear to constant when writing refs. * kn/reftable-optimize-reloading: reftable/stack: avoid reloading the stack when already locked reftable/stack: move list lock to `struct reftable_stack` reftable/stack: rename reftable_stack_new_addition() reftable/stack: remove `REFTABLE_STACK_NEW_ADDITION_RELOAD`jch
commit
411e51a37d
|
|
@ -1001,9 +1001,8 @@ static int prepare_transaction_update(struct write_transaction_table_arg **out,
|
||||||
if (!arg) {
|
if (!arg) {
|
||||||
struct reftable_addition *addition;
|
struct reftable_addition *addition;
|
||||||
|
|
||||||
ret = reftable_stack_new_addition(&addition, be->stack,
|
ret = reftable_stack_addition_new(&addition, be->stack,
|
||||||
&reftable_be_write_options(refs)->opts,
|
&reftable_be_write_options(refs)->opts);
|
||||||
REFTABLE_STACK_NEW_ADDITION_RELOAD);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (ret == REFTABLE_LOCK_ERROR)
|
if (ret == REFTABLE_LOCK_ERROR)
|
||||||
strbuf_addstr(err, "cannot lock references");
|
strbuf_addstr(err, "cannot lock references");
|
||||||
|
|
@ -2009,8 +2008,7 @@ static int reftable_be_rename_ref(struct ref_store *ref_store,
|
||||||
if (ret)
|
if (ret)
|
||||||
goto done;
|
goto done;
|
||||||
ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg,
|
ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg,
|
||||||
&reftable_be_write_options(refs)->opts,
|
&reftable_be_write_options(refs)->opts);
|
||||||
REFTABLE_STACK_NEW_ADDITION_RELOAD);
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
assert(ret != REFTABLE_API_ERROR);
|
assert(ret != REFTABLE_API_ERROR);
|
||||||
|
|
@ -2040,8 +2038,7 @@ static int reftable_be_copy_ref(struct ref_store *ref_store,
|
||||||
if (ret)
|
if (ret)
|
||||||
goto done;
|
goto done;
|
||||||
ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg,
|
ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg,
|
||||||
&reftable_be_write_options(refs)->opts,
|
&reftable_be_write_options(refs)->opts);
|
||||||
REFTABLE_STACK_NEW_ADDITION_RELOAD);
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
assert(ret != REFTABLE_API_ERROR);
|
assert(ret != REFTABLE_API_ERROR);
|
||||||
|
|
@ -2423,8 +2420,7 @@ static int reftable_be_create_reflog(struct ref_store *ref_store,
|
||||||
arg.stack = be->stack;
|
arg.stack = be->stack;
|
||||||
|
|
||||||
ret = reftable_stack_add(be->stack, &write_reflog_existence_table, &arg,
|
ret = reftable_stack_add(be->stack, &write_reflog_existence_table, &arg,
|
||||||
&reftable_be_write_options(refs)->opts,
|
&reftable_be_write_options(refs)->opts);
|
||||||
REFTABLE_STACK_NEW_ADDITION_RELOAD);
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -2498,8 +2494,7 @@ static int reftable_be_delete_reflog(struct ref_store *ref_store,
|
||||||
arg.stack = be->stack;
|
arg.stack = be->stack;
|
||||||
|
|
||||||
ret = reftable_stack_add(be->stack, &write_reflog_delete_table, &arg,
|
ret = reftable_stack_add(be->stack, &write_reflog_delete_table, &arg,
|
||||||
&reftable_be_write_options(refs)->opts,
|
&reftable_be_write_options(refs)->opts);
|
||||||
REFTABLE_STACK_NEW_ADDITION_RELOAD);
|
|
||||||
|
|
||||||
assert(ret != REFTABLE_API_ERROR);
|
assert(ret != REFTABLE_API_ERROR);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -2620,9 +2615,8 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
ret = reftable_stack_new_addition(&add, be->stack,
|
ret = reftable_stack_addition_new(&add, be->stack,
|
||||||
&reftable_be_write_options(refs)->opts,
|
&reftable_be_write_options(refs)->opts);
|
||||||
REFTABLE_STACK_NEW_ADDITION_RELOAD);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,22 +58,13 @@ uint64_t reftable_stack_next_update_index(struct reftable_stack *st);
|
||||||
/* holds a transaction to add tables at the top of a stack. */
|
/* holds a transaction to add tables at the top of a stack. */
|
||||||
struct reftable_addition;
|
struct reftable_addition;
|
||||||
|
|
||||||
enum {
|
|
||||||
/*
|
|
||||||
* Reload the stack when the stack is out-of-date after locking it.
|
|
||||||
*/
|
|
||||||
REFTABLE_STACK_NEW_ADDITION_RELOAD = (1 << 0),
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns a new transaction to add reftables to the given stack. As a side
|
* returns a new transaction to add reftables to the given stack. As a side
|
||||||
* effect, the ref database is locked. Accepts REFTABLE_STACK_NEW_ADDITION_*
|
* effect, the ref database is locked.
|
||||||
* flags.
|
|
||||||
*/
|
*/
|
||||||
int reftable_stack_new_addition(struct reftable_addition **dest,
|
int reftable_stack_addition_new(struct reftable_addition **dest,
|
||||||
struct reftable_stack *st,
|
struct reftable_stack *st,
|
||||||
const struct reftable_write_options *opts,
|
const struct reftable_write_options *opts);
|
||||||
unsigned int flags);
|
|
||||||
|
|
||||||
/* Adds a reftable to transaction. */
|
/* Adds a reftable to transaction. */
|
||||||
int reftable_addition_add(struct reftable_addition *add,
|
int reftable_addition_add(struct reftable_addition *add,
|
||||||
|
|
@ -93,14 +84,12 @@ void reftable_addition_destroy(struct reftable_addition *add);
|
||||||
/*
|
/*
|
||||||
* Add a new table to the stack. The write_table function must call
|
* Add a new table to the stack. The write_table function must call
|
||||||
* reftable_writer_set_limits, add refs and return an error value.
|
* reftable_writer_set_limits, add refs and return an error value.
|
||||||
* The flags are passed through to `reftable_stack_new_addition()`.
|
|
||||||
*/
|
*/
|
||||||
int reftable_stack_add(struct reftable_stack *st,
|
int reftable_stack_add(struct reftable_stack *st,
|
||||||
int (*write_table)(struct reftable_writer *wr,
|
int (*write_table)(struct reftable_writer *wr,
|
||||||
void *write_arg),
|
void *write_arg),
|
||||||
void *write_arg,
|
void *write_arg,
|
||||||
const struct reftable_write_options *opts,
|
const struct reftable_write_options *opts);
|
||||||
unsigned flags);
|
|
||||||
|
|
||||||
struct reftable_iterator;
|
struct reftable_iterator;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -536,6 +536,8 @@ int reftable_new_stack(struct reftable_stack **dest, const char *dir,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p->list_lock = REFTABLE_FLOCK_INIT;
|
||||||
|
|
||||||
err = reftable_stack_reload_maybe_reuse(p, 1);
|
err = reftable_stack_reload_maybe_reuse(p, 1);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -551,14 +553,21 @@ out:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether the given stack is up-to-date with what we have in memory.
|
* Check whether the given stack is up-to-date with what we have in memory.
|
||||||
|
* If skip_if_locked is set skip stack reloading if the stack is currently
|
||||||
|
* locked. Stack reloading must _not_ be skipped right after obtaining the
|
||||||
|
* lock, to check for concurrent updates which may have happened.
|
||||||
|
*
|
||||||
* Returns 0 if so, 1 if the stack is out-of-date or a negative error code
|
* Returns 0 if so, 1 if the stack is out-of-date or a negative error code
|
||||||
* otherwise.
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
static int stack_uptodate(struct reftable_stack *st)
|
static int stack_uptodate(struct reftable_stack *st, int skip_if_locked)
|
||||||
{
|
{
|
||||||
char **names = NULL;
|
char **names = NULL;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (skip_if_locked && st->list_lock.fd != -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When we have cached stat information available then we use it to
|
* When we have cached stat information available then we use it to
|
||||||
* verify whether the file has been rewritten.
|
* verify whether the file has been rewritten.
|
||||||
|
|
@ -621,17 +630,23 @@ done:
|
||||||
|
|
||||||
int reftable_stack_reload(struct reftable_stack *st)
|
int reftable_stack_reload(struct reftable_stack *st)
|
||||||
{
|
{
|
||||||
int err = stack_uptodate(st);
|
int err = stack_uptodate(st, 1);
|
||||||
if (err > 0)
|
if (err > 0)
|
||||||
return reftable_stack_reload_maybe_reuse(st, 1);
|
return reftable_stack_reload_maybe_reuse(st, 1);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct reftable_addition {
|
struct reftable_addition {
|
||||||
struct reftable_flock tables_list_lock;
|
|
||||||
struct reftable_stack *stack;
|
struct reftable_stack *stack;
|
||||||
struct reftable_write_options opts;
|
struct reftable_write_options opts;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* While the list lock is acquired on the stack, we need to distinguish
|
||||||
|
* which 'reftable_addition' is responsible for the lock. This avoids
|
||||||
|
* clearing the lock of another 'reftable_addition'.
|
||||||
|
*/
|
||||||
|
unsigned int locked : 1;
|
||||||
|
|
||||||
char **new_tables;
|
char **new_tables;
|
||||||
size_t new_tables_len, new_tables_cap;
|
size_t new_tables_len, new_tables_cap;
|
||||||
uint64_t next_update_index;
|
uint64_t next_update_index;
|
||||||
|
|
@ -653,14 +668,15 @@ static void reftable_addition_close(struct reftable_addition *add)
|
||||||
add->new_tables_len = 0;
|
add->new_tables_len = 0;
|
||||||
add->new_tables_cap = 0;
|
add->new_tables_cap = 0;
|
||||||
|
|
||||||
flock_release(&add->tables_list_lock);
|
if (add->locked)
|
||||||
|
flock_release(&add->stack->list_lock);
|
||||||
|
add->locked = 0;
|
||||||
reftable_buf_release(&nm);
|
reftable_buf_release(&nm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int reftable_stack_init_addition(struct reftable_addition *add,
|
static int reftable_stack_init_addition(struct reftable_addition *add,
|
||||||
struct reftable_stack *st,
|
struct reftable_stack *st,
|
||||||
const struct reftable_write_options *opts,
|
const struct reftable_write_options *opts)
|
||||||
unsigned int flags)
|
|
||||||
{
|
{
|
||||||
struct reftable_buf lock_file_name = REFTABLE_BUF_INIT;
|
struct reftable_buf lock_file_name = REFTABLE_BUF_INIT;
|
||||||
int err;
|
int err;
|
||||||
|
|
@ -670,31 +686,28 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
|
||||||
if (opts)
|
if (opts)
|
||||||
add->opts = *opts;
|
add->opts = *opts;
|
||||||
|
|
||||||
err = flock_acquire(&add->tables_list_lock, st->list_file,
|
err = flock_acquire(&add->stack->list_lock, st->list_file,
|
||||||
add->opts.lock_timeout_ms);
|
add->opts.lock_timeout_ms);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
add->locked = 1;
|
||||||
|
|
||||||
if (add->opts.default_permissions) {
|
if (add->opts.default_permissions) {
|
||||||
if (chmod(add->tables_list_lock.path,
|
if (chmod(add->stack->list_lock.path,
|
||||||
add->opts.default_permissions) < 0) {
|
add->opts.default_permissions) < 0) {
|
||||||
err = REFTABLE_IO_ERROR;
|
err = REFTABLE_IO_ERROR;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = stack_uptodate(st);
|
err = stack_uptodate(st, 0);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (err > 0 && flags & REFTABLE_STACK_NEW_ADDITION_RELOAD) {
|
if (err > 0) {
|
||||||
err = reftable_stack_reload_maybe_reuse(add->stack, 1);
|
err = reftable_stack_reload_maybe_reuse(add->stack, 1);
|
||||||
if (err)
|
if (err)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (err > 0) {
|
|
||||||
err = REFTABLE_OUTDATED_ERROR;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
add->next_update_index = reftable_stack_next_update_index(st);
|
add->next_update_index = reftable_stack_next_update_index(st);
|
||||||
done:
|
done:
|
||||||
|
|
@ -708,13 +721,12 @@ static int stack_try_add(struct reftable_stack *st,
|
||||||
int (*write_table)(struct reftable_writer *wr,
|
int (*write_table)(struct reftable_writer *wr,
|
||||||
void *arg),
|
void *arg),
|
||||||
void *arg,
|
void *arg,
|
||||||
const struct reftable_write_options *opts,
|
const struct reftable_write_options *opts)
|
||||||
unsigned flags)
|
|
||||||
{
|
{
|
||||||
struct reftable_addition add;
|
struct reftable_addition add;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = reftable_stack_init_addition(&add, st, opts, flags);
|
err = reftable_stack_init_addition(&add, st, opts);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
|
@ -731,17 +743,10 @@ done:
|
||||||
int reftable_stack_add(struct reftable_stack *st,
|
int reftable_stack_add(struct reftable_stack *st,
|
||||||
int (*write)(struct reftable_writer *wr, void *arg),
|
int (*write)(struct reftable_writer *wr, void *arg),
|
||||||
void *arg,
|
void *arg,
|
||||||
const struct reftable_write_options *opts,
|
const struct reftable_write_options *opts)
|
||||||
unsigned flags)
|
|
||||||
{
|
{
|
||||||
int err = stack_try_add(st, write, arg, opts, flags);
|
int err = stack_try_add(st, write, arg, opts);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
if (err == REFTABLE_OUTDATED_ERROR) {
|
|
||||||
/* Ignore error return, we want to propagate
|
|
||||||
REFTABLE_OUTDATED_ERROR.
|
|
||||||
*/
|
|
||||||
reftable_stack_reload(st);
|
|
||||||
}
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -787,7 +792,7 @@ int reftable_addition_commit(struct reftable_addition *add)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = reftable_write_data(add->tables_list_lock.fd,
|
err = reftable_write_data(add->stack->list_lock.fd,
|
||||||
table_list.buf, table_list.len);
|
table_list.buf, table_list.len);
|
||||||
reftable_buf_release(&table_list);
|
reftable_buf_release(&table_list);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
|
@ -795,17 +800,18 @@ int reftable_addition_commit(struct reftable_addition *add)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = fsync(add->tables_list_lock.fd);
|
err = fsync(add->stack->list_lock.fd);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
err = REFTABLE_IO_ERROR;
|
err = REFTABLE_IO_ERROR;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = flock_commit(&add->tables_list_lock);
|
err = flock_commit(&add->stack->list_lock);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
err = REFTABLE_IO_ERROR;
|
err = REFTABLE_IO_ERROR;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
add->locked = 0;
|
||||||
|
|
||||||
/* success, no more state to clean up. */
|
/* success, no more state to clean up. */
|
||||||
for (i = 0; i < add->new_tables_len; i++)
|
for (i = 0; i < add->new_tables_len; i++)
|
||||||
|
|
@ -841,10 +847,9 @@ done:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int reftable_stack_new_addition(struct reftable_addition **dest,
|
int reftable_stack_addition_new(struct reftable_addition **dest,
|
||||||
struct reftable_stack *st,
|
struct reftable_stack *st,
|
||||||
const struct reftable_write_options *opts,
|
const struct reftable_write_options *opts)
|
||||||
unsigned int flags)
|
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
|
@ -852,7 +857,7 @@ int reftable_stack_new_addition(struct reftable_addition **dest,
|
||||||
if (!*dest)
|
if (!*dest)
|
||||||
return REFTABLE_OUT_OF_MEMORY_ERROR;
|
return REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||||
|
|
||||||
err = reftable_stack_init_addition(*dest, st, opts, flags);
|
err = reftable_stack_init_addition(*dest, st, opts);
|
||||||
if (err) {
|
if (err) {
|
||||||
reftable_free(*dest);
|
reftable_free(*dest);
|
||||||
*dest = NULL;
|
*dest = NULL;
|
||||||
|
|
@ -1202,7 +1207,7 @@ static int stack_compact_range(struct reftable_stack *st,
|
||||||
* we could check that relevant tables still exist. But for now it's
|
* we could check that relevant tables still exist. But for now it's
|
||||||
* good enough to just abort.
|
* good enough to just abort.
|
||||||
*/
|
*/
|
||||||
err = stack_uptodate(st);
|
err = stack_uptodate(st, 0);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (err > 0) {
|
if (err > 0) {
|
||||||
|
|
@ -1321,7 +1326,7 @@ static int stack_compact_range(struct reftable_stack *st,
|
||||||
* tables with our compacted version. If they don't, then we need to
|
* tables with our compacted version. If they don't, then we need to
|
||||||
* abort.
|
* abort.
|
||||||
*/
|
*/
|
||||||
err = stack_uptodate(st);
|
err = stack_uptodate(st, 0);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (err > 0) {
|
if (err > 0) {
|
||||||
|
|
@ -1840,12 +1845,7 @@ static int reftable_stack_clean_locked(struct reftable_stack *st)
|
||||||
int reftable_stack_clean(struct reftable_stack *st)
|
int reftable_stack_clean(struct reftable_stack *st)
|
||||||
{
|
{
|
||||||
struct reftable_addition *add = NULL;
|
struct reftable_addition *add = NULL;
|
||||||
int err = reftable_stack_new_addition(&add, st, NULL, 0);
|
int err = reftable_stack_addition_new(&add, st, NULL);
|
||||||
if (err < 0) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = reftable_stack_reload(st);
|
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@
|
||||||
#define STACK_H
|
#define STACK_H
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "reftable-writer.h"
|
|
||||||
#include "reftable-stack.h"
|
#include "reftable-stack.h"
|
||||||
|
|
||||||
struct reftable_stack {
|
struct reftable_stack {
|
||||||
|
|
@ -18,6 +17,12 @@ struct reftable_stack {
|
||||||
char *list_file;
|
char *list_file;
|
||||||
int list_fd;
|
int list_fd;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set while an addition holds the stack locked. Used by
|
||||||
|
* stack_uptodate() to skip reload checks while locked.
|
||||||
|
*/
|
||||||
|
struct reftable_flock list_lock;
|
||||||
|
|
||||||
char *reftable_dir;
|
char *reftable_dir;
|
||||||
|
|
||||||
struct reftable_stack_options opts;
|
struct reftable_stack_options opts;
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ static void write_n_ref_tables(struct reftable_stack *st,
|
||||||
cl_reftable_set_hash(ref.value.val1, i, REFTABLE_HASH_SHA1);
|
cl_reftable_set_hash(ref.value.val1, i, REFTABLE_HASH_SHA1);
|
||||||
|
|
||||||
cl_assert_equal_i(reftable_stack_add(st,
|
cl_assert_equal_i(reftable_stack_add(st,
|
||||||
&write_test_ref, &ref, &opts, 0), 0);
|
&write_test_ref, &ref, &opts), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,7 +168,7 @@ void test_reftable_stack__add_one(void)
|
||||||
err = reftable_new_stack(&st, dir, NULL);
|
err = reftable_new_stack(&st, dir, NULL);
|
||||||
cl_assert(!err);
|
cl_assert(!err);
|
||||||
|
|
||||||
err = reftable_stack_add(st, write_test_ref, &ref, &opts, 0);
|
err = reftable_stack_add(st, write_test_ref, &ref, &opts);
|
||||||
cl_assert(!err);
|
cl_assert(!err);
|
||||||
|
|
||||||
err = reftable_stack_read_ref(st, ref.refname, &dest);
|
err = reftable_stack_read_ref(st, ref.refname, &dest);
|
||||||
|
|
@ -231,12 +231,9 @@ void test_reftable_stack__uptodate(void)
|
||||||
cl_assert_equal_i(reftable_new_stack(&st1, dir, NULL), 0);
|
cl_assert_equal_i(reftable_new_stack(&st1, dir, NULL), 0);
|
||||||
cl_assert_equal_i(reftable_new_stack(&st2, dir, NULL), 0);
|
cl_assert_equal_i(reftable_new_stack(&st2, dir, NULL), 0);
|
||||||
cl_assert_equal_i(reftable_stack_add(st1, write_test_ref,
|
cl_assert_equal_i(reftable_stack_add(st1, write_test_ref,
|
||||||
&ref1, NULL, 0), 0);
|
&ref1, NULL), 0);
|
||||||
cl_assert_equal_i(reftable_stack_add(st2, write_test_ref,
|
cl_assert_equal_i(reftable_stack_add(st2, write_test_ref,
|
||||||
&ref2, NULL, 0), REFTABLE_OUTDATED_ERROR);
|
&ref2, NULL), 0);
|
||||||
cl_assert_equal_i(reftable_stack_reload(st2), 0);
|
|
||||||
cl_assert_equal_i(reftable_stack_add(st2, write_test_ref,
|
|
||||||
&ref2, NULL, 0), 0);
|
|
||||||
reftable_stack_destroy(st1);
|
reftable_stack_destroy(st1);
|
||||||
reftable_stack_destroy(st2);
|
reftable_stack_destroy(st2);
|
||||||
clear_dir(dir);
|
clear_dir(dir);
|
||||||
|
|
@ -260,7 +257,7 @@ void test_reftable_stack__transaction_api(void)
|
||||||
|
|
||||||
reftable_addition_destroy(add);
|
reftable_addition_destroy(add);
|
||||||
|
|
||||||
cl_assert_equal_i(reftable_stack_new_addition(&add, st, NULL, 0), 0);
|
cl_assert_equal_i(reftable_stack_addition_new(&add, st, NULL), 0);
|
||||||
cl_assert_equal_i(reftable_addition_add(add, write_test_ref,
|
cl_assert_equal_i(reftable_addition_add(add, write_test_ref,
|
||||||
&ref), 0);
|
&ref), 0);
|
||||||
cl_assert_equal_i(reftable_addition_commit(add), 0);
|
cl_assert_equal_i(reftable_addition_commit(add), 0);
|
||||||
|
|
@ -301,21 +298,17 @@ void test_reftable_stack__transaction_with_reload(void)
|
||||||
|
|
||||||
cl_assert_equal_i(reftable_new_stack(&st1, dir, NULL), 0);
|
cl_assert_equal_i(reftable_new_stack(&st1, dir, NULL), 0);
|
||||||
cl_assert_equal_i(reftable_new_stack(&st2, dir, NULL), 0);
|
cl_assert_equal_i(reftable_new_stack(&st2, dir, NULL), 0);
|
||||||
cl_assert_equal_i(reftable_stack_new_addition(&add, st1, NULL, 0), 0);
|
cl_assert_equal_i(reftable_stack_addition_new(&add, st1, NULL), 0);
|
||||||
cl_assert_equal_i(reftable_addition_add(add, write_test_ref,
|
cl_assert_equal_i(reftable_addition_add(add, write_test_ref,
|
||||||
&refs[0]), 0);
|
&refs[0]), 0);
|
||||||
cl_assert_equal_i(reftable_addition_commit(add), 0);
|
cl_assert_equal_i(reftable_addition_commit(add), 0);
|
||||||
reftable_addition_destroy(add);
|
reftable_addition_destroy(add);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The second stack is now outdated, which we should notice. We do not
|
* The second stack is now outdated, but it should automatically reload it
|
||||||
* create the addition and lock the stack by default, but allow the
|
* with the newer updates.
|
||||||
* reload to happen when REFTABLE_STACK_NEW_ADDITION_RELOAD is set.
|
|
||||||
*/
|
*/
|
||||||
cl_assert_equal_i(reftable_stack_new_addition(&add, st2, NULL, 0),
|
cl_assert_equal_i(reftable_stack_addition_new(&add, st2, NULL), 0);
|
||||||
REFTABLE_OUTDATED_ERROR);
|
|
||||||
cl_assert_equal_i(reftable_stack_new_addition(&add, st2, NULL,
|
|
||||||
REFTABLE_STACK_NEW_ADDITION_RELOAD), 0);
|
|
||||||
cl_assert_equal_i(reftable_addition_add(add, write_test_ref,
|
cl_assert_equal_i(reftable_addition_add(add, write_test_ref,
|
||||||
&refs[1]), 0);
|
&refs[1]), 0);
|
||||||
cl_assert_equal_i(reftable_addition_commit(add), 0);
|
cl_assert_equal_i(reftable_addition_commit(add), 0);
|
||||||
|
|
@ -362,8 +355,8 @@ void test_reftable_stack__transaction_api_performs_auto_compaction(void)
|
||||||
* we can ensure that we indeed honor this setting and have
|
* we can ensure that we indeed honor this setting and have
|
||||||
* better control over when exactly auto compaction runs.
|
* better control over when exactly auto compaction runs.
|
||||||
*/
|
*/
|
||||||
cl_assert_equal_i(reftable_stack_new_addition(&add,
|
cl_assert_equal_i(reftable_stack_addition_new(&add,
|
||||||
st, &write_opts, 0), 0);
|
st, &write_opts), 0);
|
||||||
cl_assert_equal_i(reftable_addition_add(add,
|
cl_assert_equal_i(reftable_addition_add(add,
|
||||||
write_test_ref, &ref), 0);
|
write_test_ref, &ref), 0);
|
||||||
cl_assert_equal_i(reftable_addition_commit(add), 0);
|
cl_assert_equal_i(reftable_addition_commit(add), 0);
|
||||||
|
|
@ -400,7 +393,7 @@ void test_reftable_stack__auto_compaction_fails_gracefully(void)
|
||||||
|
|
||||||
cl_assert_equal_i(reftable_new_stack(&st, dir, NULL), 0);
|
cl_assert_equal_i(reftable_new_stack(&st, dir, NULL), 0);
|
||||||
cl_assert_equal_i(reftable_stack_add(st, write_test_ref,
|
cl_assert_equal_i(reftable_stack_add(st, write_test_ref,
|
||||||
&ref, NULL, 0), 0);
|
&ref, NULL), 0);
|
||||||
cl_assert_equal_i(st->merged->tables_len, 1);
|
cl_assert_equal_i(st->merged->tables_len, 1);
|
||||||
cl_assert_equal_i(st->stats.attempts, 0);
|
cl_assert_equal_i(st->stats.attempts, 0);
|
||||||
cl_assert_equal_i(st->stats.failures, 0);
|
cl_assert_equal_i(st->stats.failures, 0);
|
||||||
|
|
@ -418,7 +411,7 @@ void test_reftable_stack__auto_compaction_fails_gracefully(void)
|
||||||
write_file_buf(table_path.buf, "", 0);
|
write_file_buf(table_path.buf, "", 0);
|
||||||
|
|
||||||
ref.update_index = 2;
|
ref.update_index = 2;
|
||||||
err = reftable_stack_add(st, write_test_ref, &ref, NULL, 0);
|
err = reftable_stack_add(st, write_test_ref, &ref, NULL);
|
||||||
cl_assert(!err);
|
cl_assert(!err);
|
||||||
cl_assert_equal_i(st->merged->tables_len, 2);
|
cl_assert_equal_i(st->merged->tables_len, 2);
|
||||||
cl_assert_equal_i(st->stats.attempts, 1);
|
cl_assert_equal_i(st->stats.attempts, 1);
|
||||||
|
|
@ -453,9 +446,9 @@ void test_reftable_stack__update_index_check(void)
|
||||||
|
|
||||||
cl_assert_equal_i(reftable_new_stack(&st, dir, NULL), 0);
|
cl_assert_equal_i(reftable_new_stack(&st, dir, NULL), 0);
|
||||||
cl_assert_equal_i(reftable_stack_add(st, write_test_ref,
|
cl_assert_equal_i(reftable_stack_add(st, write_test_ref,
|
||||||
&ref1, NULL, 0), 0);
|
&ref1, NULL), 0);
|
||||||
cl_assert_equal_i(reftable_stack_add(st, write_test_ref,
|
cl_assert_equal_i(reftable_stack_add(st, write_test_ref,
|
||||||
&ref2, NULL, 0), REFTABLE_API_ERROR);
|
&ref2, NULL), REFTABLE_API_ERROR);
|
||||||
reftable_stack_destroy(st);
|
reftable_stack_destroy(st);
|
||||||
clear_dir(dir);
|
clear_dir(dir);
|
||||||
}
|
}
|
||||||
|
|
@ -469,7 +462,7 @@ void test_reftable_stack__lock_failure(void)
|
||||||
cl_assert_equal_i(reftable_new_stack(&st, dir, NULL), 0);
|
cl_assert_equal_i(reftable_new_stack(&st, dir, NULL), 0);
|
||||||
for (i = -1; i != REFTABLE_EMPTY_TABLE_ERROR; i--)
|
for (i = -1; i != REFTABLE_EMPTY_TABLE_ERROR; i--)
|
||||||
cl_assert_equal_i(reftable_stack_add(st, write_error,
|
cl_assert_equal_i(reftable_stack_add(st, write_error,
|
||||||
&i, NULL, 0), i);
|
&i, NULL), i);
|
||||||
|
|
||||||
reftable_stack_destroy(st);
|
reftable_stack_destroy(st);
|
||||||
clear_dir(dir);
|
clear_dir(dir);
|
||||||
|
|
@ -513,7 +506,7 @@ void test_reftable_stack__add(void)
|
||||||
|
|
||||||
for (i = 0; i < N; i++)
|
for (i = 0; i < N; i++)
|
||||||
cl_assert_equal_i(reftable_stack_add(st, write_test_ref,
|
cl_assert_equal_i(reftable_stack_add(st, write_test_ref,
|
||||||
&refs[i], &opts, 0), 0);
|
&refs[i], &opts), 0);
|
||||||
|
|
||||||
for (i = 0; i < N; i++) {
|
for (i = 0; i < N; i++) {
|
||||||
struct write_log_arg arg = {
|
struct write_log_arg arg = {
|
||||||
|
|
@ -521,7 +514,7 @@ void test_reftable_stack__add(void)
|
||||||
.update_index = reftable_stack_next_update_index(st),
|
.update_index = reftable_stack_next_update_index(st),
|
||||||
};
|
};
|
||||||
cl_assert_equal_i(reftable_stack_add(st, write_test_log,
|
cl_assert_equal_i(reftable_stack_add(st, write_test_log,
|
||||||
&arg, &opts, 0), 0);
|
&arg, &opts), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
cl_assert_equal_i(reftable_stack_compact_all(st, &opts, NULL), 0);
|
cl_assert_equal_i(reftable_stack_compact_all(st, &opts, NULL), 0);
|
||||||
|
|
@ -604,7 +597,7 @@ void test_reftable_stack__iterator(void)
|
||||||
|
|
||||||
for (i = 0; i < N; i++)
|
for (i = 0; i < N; i++)
|
||||||
cl_assert_equal_i(reftable_stack_add(st, write_test_ref,
|
cl_assert_equal_i(reftable_stack_add(st, write_test_ref,
|
||||||
&refs[i], NULL, 0), 0);
|
&refs[i], NULL), 0);
|
||||||
|
|
||||||
for (i = 0; i < N; i++) {
|
for (i = 0; i < N; i++) {
|
||||||
struct write_log_arg arg = {
|
struct write_log_arg arg = {
|
||||||
|
|
@ -613,7 +606,7 @@ void test_reftable_stack__iterator(void)
|
||||||
};
|
};
|
||||||
|
|
||||||
cl_assert_equal_i(reftable_stack_add(st, write_test_log,
|
cl_assert_equal_i(reftable_stack_add(st, write_test_log,
|
||||||
&arg, NULL, 0), 0);
|
&arg, NULL), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
reftable_stack_init_ref_iterator(st, &it);
|
reftable_stack_init_ref_iterator(st, &it);
|
||||||
|
|
@ -685,11 +678,11 @@ void test_reftable_stack__log_normalize(void)
|
||||||
|
|
||||||
input.value.update.message = (char *) "one\ntwo";
|
input.value.update.message = (char *) "one\ntwo";
|
||||||
cl_assert_equal_i(reftable_stack_add(st, write_test_log,
|
cl_assert_equal_i(reftable_stack_add(st, write_test_log,
|
||||||
&arg, NULL, 0), REFTABLE_API_ERROR);
|
&arg, NULL), REFTABLE_API_ERROR);
|
||||||
|
|
||||||
input.value.update.message = (char *) "one";
|
input.value.update.message = (char *) "one";
|
||||||
cl_assert_equal_i(reftable_stack_add(st, write_test_log,
|
cl_assert_equal_i(reftable_stack_add(st, write_test_log,
|
||||||
&arg, NULL, 0), 0);
|
&arg, NULL), 0);
|
||||||
cl_assert_equal_i(reftable_stack_read_log(st, input.refname,
|
cl_assert_equal_i(reftable_stack_read_log(st, input.refname,
|
||||||
&dest), 0);
|
&dest), 0);
|
||||||
cl_assert_equal_s(dest.value.update.message, "one\n");
|
cl_assert_equal_s(dest.value.update.message, "one\n");
|
||||||
|
|
@ -697,7 +690,7 @@ void test_reftable_stack__log_normalize(void)
|
||||||
input.value.update.message = (char *) "two\n";
|
input.value.update.message = (char *) "two\n";
|
||||||
arg.update_index = 2;
|
arg.update_index = 2;
|
||||||
cl_assert_equal_i(reftable_stack_add(st, write_test_log,
|
cl_assert_equal_i(reftable_stack_add(st, write_test_log,
|
||||||
&arg, NULL, 0), 0);
|
&arg, NULL), 0);
|
||||||
cl_assert_equal_i(reftable_stack_read_log(st, input.refname,
|
cl_assert_equal_i(reftable_stack_read_log(st, input.refname,
|
||||||
&dest), 0);
|
&dest), 0);
|
||||||
cl_assert_equal_s(dest.value.update.message, "two\n");
|
cl_assert_equal_s(dest.value.update.message, "two\n");
|
||||||
|
|
@ -747,7 +740,7 @@ void test_reftable_stack__tombstone(void)
|
||||||
}
|
}
|
||||||
for (i = 0; i < N; i++)
|
for (i = 0; i < N; i++)
|
||||||
cl_assert_equal_i(reftable_stack_add(st, write_test_ref,
|
cl_assert_equal_i(reftable_stack_add(st, write_test_ref,
|
||||||
&refs[i], NULL, 0), 0);
|
&refs[i], NULL), 0);
|
||||||
|
|
||||||
for (i = 0; i < N; i++) {
|
for (i = 0; i < N; i++) {
|
||||||
struct write_log_arg arg = {
|
struct write_log_arg arg = {
|
||||||
|
|
@ -755,7 +748,7 @@ void test_reftable_stack__tombstone(void)
|
||||||
.update_index = reftable_stack_next_update_index(st),
|
.update_index = reftable_stack_next_update_index(st),
|
||||||
};
|
};
|
||||||
cl_assert_equal_i(reftable_stack_add(st, write_test_log,
|
cl_assert_equal_i(reftable_stack_add(st, write_test_log,
|
||||||
&arg, NULL, 0), 0);
|
&arg, NULL), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
cl_assert_equal_i(reftable_stack_read_ref(st, "branch",
|
cl_assert_equal_i(reftable_stack_read_ref(st, "branch",
|
||||||
|
|
@ -801,7 +794,7 @@ void test_reftable_stack__hash_id(void)
|
||||||
|
|
||||||
cl_assert_equal_i(reftable_new_stack(&st, dir, NULL), 0);
|
cl_assert_equal_i(reftable_new_stack(&st, dir, NULL), 0);
|
||||||
cl_assert_equal_i(reftable_stack_add(st, write_test_ref,
|
cl_assert_equal_i(reftable_stack_add(st, write_test_ref,
|
||||||
&ref, NULL, 0), 0);
|
&ref, NULL), 0);
|
||||||
|
|
||||||
/* can't read it with the wrong hash ID. */
|
/* can't read it with the wrong hash ID. */
|
||||||
cl_assert_equal_i(reftable_new_stack(&st32, dir,
|
cl_assert_equal_i(reftable_new_stack(&st32, dir,
|
||||||
|
|
@ -869,7 +862,7 @@ void test_reftable_stack__reflog_expire(void)
|
||||||
.update_index = reftable_stack_next_update_index(st),
|
.update_index = reftable_stack_next_update_index(st),
|
||||||
};
|
};
|
||||||
cl_assert_equal_i(reftable_stack_add(st, write_test_log,
|
cl_assert_equal_i(reftable_stack_add(st, write_test_log,
|
||||||
&arg, NULL, 0), 0);
|
&arg, NULL), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
cl_assert_equal_i(reftable_stack_compact_all(st, NULL, NULL), 0);
|
cl_assert_equal_i(reftable_stack_compact_all(st, NULL, NULL), 0);
|
||||||
|
|
@ -908,7 +901,7 @@ void test_reftable_stack__empty_add(void)
|
||||||
|
|
||||||
cl_assert_equal_i(reftable_new_stack(&st, dir, NULL), 0);
|
cl_assert_equal_i(reftable_new_stack(&st, dir, NULL), 0);
|
||||||
cl_assert_equal_i(reftable_stack_add(st, write_nothing,
|
cl_assert_equal_i(reftable_stack_add(st, write_nothing,
|
||||||
NULL, NULL, 0), 0);
|
NULL, NULL), 0);
|
||||||
cl_assert_equal_i(reftable_new_stack(&st2, dir, NULL), 0);
|
cl_assert_equal_i(reftable_new_stack(&st2, dir, NULL), 0);
|
||||||
clear_dir(dir);
|
clear_dir(dir);
|
||||||
reftable_stack_destroy(st);
|
reftable_stack_destroy(st);
|
||||||
|
|
@ -947,7 +940,7 @@ void test_reftable_stack__auto_compaction(void)
|
||||||
};
|
};
|
||||||
snprintf(name, sizeof(name), "branch%04"PRIuMAX, (uintmax_t)i);
|
snprintf(name, sizeof(name), "branch%04"PRIuMAX, (uintmax_t)i);
|
||||||
|
|
||||||
err = reftable_stack_add(st, write_test_ref, &ref, &opts, 0);
|
err = reftable_stack_add(st, write_test_ref, &ref, &opts);
|
||||||
cl_assert(!err);
|
cl_assert(!err);
|
||||||
|
|
||||||
err = reftable_stack_auto_compact(st, &opts);
|
err = reftable_stack_auto_compact(st, &opts);
|
||||||
|
|
@ -983,7 +976,7 @@ void test_reftable_stack__auto_compaction_factor(void)
|
||||||
};
|
};
|
||||||
xsnprintf(name, sizeof(name), "branch%04"PRIuMAX, (uintmax_t)i);
|
xsnprintf(name, sizeof(name), "branch%04"PRIuMAX, (uintmax_t)i);
|
||||||
|
|
||||||
err = reftable_stack_add(st, &write_test_ref, &ref, &opts, 0);
|
err = reftable_stack_add(st, &write_test_ref, &ref, &opts);
|
||||||
cl_assert(!err);
|
cl_assert(!err);
|
||||||
|
|
||||||
cl_assert(i < 5 || st->merged->tables_len < 5 * fastlogN(i, 5));
|
cl_assert(i < 5 || st->merged->tables_len < 5 * fastlogN(i, 5));
|
||||||
|
|
@ -1064,7 +1057,7 @@ void test_reftable_stack__add_performs_auto_compaction(void)
|
||||||
ref.refname = buf;
|
ref.refname = buf;
|
||||||
|
|
||||||
cl_assert_equal_i(reftable_stack_add(st, write_test_ref,
|
cl_assert_equal_i(reftable_stack_add(st, write_test_ref,
|
||||||
&ref, &write_opts, 0), 0);
|
&ref, &write_opts), 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The stack length should grow continuously for all runs where
|
* The stack length should grow continuously for all runs where
|
||||||
|
|
@ -1303,7 +1296,7 @@ void test_reftable_stack__invalid_limit_updates(void)
|
||||||
|
|
||||||
reftable_addition_destroy(add);
|
reftable_addition_destroy(add);
|
||||||
|
|
||||||
cl_assert_equal_i(reftable_stack_new_addition(&add, st, &opts, 0), 0);
|
cl_assert_equal_i(reftable_stack_addition_new(&add, st, &opts), 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* write_limits_after_ref also updates the update indexes after adding
|
* write_limits_after_ref also updates the update indexes after adding
|
||||||
|
|
@ -1317,3 +1310,31 @@ void test_reftable_stack__invalid_limit_updates(void)
|
||||||
reftable_stack_destroy(st);
|
reftable_stack_destroy(st);
|
||||||
clear_dir(dir);
|
clear_dir(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_reftable_stack__two_additions(void)
|
||||||
|
{
|
||||||
|
struct reftable_stack *st = NULL;
|
||||||
|
char *dir = get_tmp_dir(__LINE__);
|
||||||
|
struct reftable_addition *add1 = NULL;
|
||||||
|
struct reftable_addition *add2 = NULL;
|
||||||
|
|
||||||
|
struct reftable_ref_record ref = {
|
||||||
|
.refname = (char *) "HEAD",
|
||||||
|
.update_index = 1,
|
||||||
|
.value_type = REFTABLE_REF_SYMREF,
|
||||||
|
.value.symref = (char *) "master",
|
||||||
|
};
|
||||||
|
|
||||||
|
cl_assert_equal_i(reftable_new_stack(&st, dir, NULL), 0);
|
||||||
|
|
||||||
|
cl_assert_equal_i(reftable_stack_addition_new(&add1, st, NULL), 0);
|
||||||
|
cl_assert_equal_i(reftable_stack_addition_new(&add2, st, NULL), REFTABLE_LOCK_ERROR);
|
||||||
|
|
||||||
|
cl_assert_equal_i(reftable_addition_add(add1, write_test_ref, &ref), 0);
|
||||||
|
|
||||||
|
cl_assert_equal_i(reftable_addition_commit(add1), 0);
|
||||||
|
|
||||||
|
reftable_addition_destroy(add1);
|
||||||
|
reftable_stack_destroy(st);
|
||||||
|
clear_dir(dir);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue