Merge branch 'kn/reftable-optimize-reloading' into next
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`next
commit
d714ed570a
|
|
@ -1001,9 +1001,8 @@ static int prepare_transaction_update(struct write_transaction_table_arg **out,
|
|||
if (!arg) {
|
||||
struct reftable_addition *addition;
|
||||
|
||||
ret = reftable_stack_new_addition(&addition, be->stack,
|
||||
&reftable_be_write_options(refs)->opts,
|
||||
REFTABLE_STACK_NEW_ADDITION_RELOAD);
|
||||
ret = reftable_stack_addition_new(&addition, be->stack,
|
||||
&reftable_be_write_options(refs)->opts);
|
||||
if (ret) {
|
||||
if (ret == REFTABLE_LOCK_ERROR)
|
||||
strbuf_addstr(err, "cannot lock references");
|
||||
|
|
@ -2009,8 +2008,7 @@ static int reftable_be_rename_ref(struct ref_store *ref_store,
|
|||
if (ret)
|
||||
goto done;
|
||||
ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg,
|
||||
&reftable_be_write_options(refs)->opts,
|
||||
REFTABLE_STACK_NEW_ADDITION_RELOAD);
|
||||
&reftable_be_write_options(refs)->opts);
|
||||
|
||||
done:
|
||||
assert(ret != REFTABLE_API_ERROR);
|
||||
|
|
@ -2040,8 +2038,7 @@ static int reftable_be_copy_ref(struct ref_store *ref_store,
|
|||
if (ret)
|
||||
goto done;
|
||||
ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg,
|
||||
&reftable_be_write_options(refs)->opts,
|
||||
REFTABLE_STACK_NEW_ADDITION_RELOAD);
|
||||
&reftable_be_write_options(refs)->opts);
|
||||
|
||||
done:
|
||||
assert(ret != REFTABLE_API_ERROR);
|
||||
|
|
@ -2423,8 +2420,7 @@ static int reftable_be_create_reflog(struct ref_store *ref_store,
|
|||
arg.stack = be->stack;
|
||||
|
||||
ret = reftable_stack_add(be->stack, &write_reflog_existence_table, &arg,
|
||||
&reftable_be_write_options(refs)->opts,
|
||||
REFTABLE_STACK_NEW_ADDITION_RELOAD);
|
||||
&reftable_be_write_options(refs)->opts);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
|
|
@ -2498,8 +2494,7 @@ static int reftable_be_delete_reflog(struct ref_store *ref_store,
|
|||
arg.stack = be->stack;
|
||||
|
||||
ret = reftable_stack_add(be->stack, &write_reflog_delete_table, &arg,
|
||||
&reftable_be_write_options(refs)->opts,
|
||||
REFTABLE_STACK_NEW_ADDITION_RELOAD);
|
||||
&reftable_be_write_options(refs)->opts);
|
||||
|
||||
assert(ret != REFTABLE_API_ERROR);
|
||||
return ret;
|
||||
|
|
@ -2620,9 +2615,8 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
|
|||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
ret = reftable_stack_new_addition(&add, be->stack,
|
||||
&reftable_be_write_options(refs)->opts,
|
||||
REFTABLE_STACK_NEW_ADDITION_RELOAD);
|
||||
ret = reftable_stack_addition_new(&add, be->stack,
|
||||
&reftable_be_write_options(refs)->opts);
|
||||
if (ret < 0)
|
||||
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. */
|
||||
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
|
||||
* effect, the ref database is locked. Accepts REFTABLE_STACK_NEW_ADDITION_*
|
||||
* flags.
|
||||
* effect, the ref database is locked.
|
||||
*/
|
||||
int reftable_stack_new_addition(struct reftable_addition **dest,
|
||||
int reftable_stack_addition_new(struct reftable_addition **dest,
|
||||
struct reftable_stack *st,
|
||||
const struct reftable_write_options *opts,
|
||||
unsigned int flags);
|
||||
const struct reftable_write_options *opts);
|
||||
|
||||
/* Adds a reftable to transaction. */
|
||||
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
|
||||
* 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 (*write_table)(struct reftable_writer *wr,
|
||||
void *write_arg),
|
||||
void *write_arg,
|
||||
const struct reftable_write_options *opts,
|
||||
unsigned flags);
|
||||
const struct reftable_write_options *opts);
|
||||
|
||||
struct reftable_iterator;
|
||||
|
||||
|
|
|
|||
|
|
@ -536,6 +536,8 @@ int reftable_new_stack(struct reftable_stack **dest, const char *dir,
|
|||
goto out;
|
||||
}
|
||||
|
||||
p->list_lock = REFTABLE_FLOCK_INIT;
|
||||
|
||||
err = reftable_stack_reload_maybe_reuse(p, 1);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
|
@ -551,14 +553,21 @@ out:
|
|||
|
||||
/*
|
||||
* 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
|
||||
* otherwise.
|
||||
*/
|
||||
static int stack_uptodate(struct reftable_stack *st)
|
||||
static int stack_uptodate(struct reftable_stack *st, int skip_if_locked)
|
||||
{
|
||||
char **names = NULL;
|
||||
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
|
||||
* verify whether the file has been rewritten.
|
||||
|
|
@ -621,17 +630,23 @@ done:
|
|||
|
||||
int reftable_stack_reload(struct reftable_stack *st)
|
||||
{
|
||||
int err = stack_uptodate(st);
|
||||
int err = stack_uptodate(st, 1);
|
||||
if (err > 0)
|
||||
return reftable_stack_reload_maybe_reuse(st, 1);
|
||||
return err;
|
||||
}
|
||||
|
||||
struct reftable_addition {
|
||||
struct reftable_flock tables_list_lock;
|
||||
struct reftable_stack *stack;
|
||||
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;
|
||||
size_t new_tables_len, new_tables_cap;
|
||||
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_cap = 0;
|
||||
|
||||
flock_release(&add->tables_list_lock);
|
||||
if (add->locked)
|
||||
flock_release(&add->stack->list_lock);
|
||||
add->locked = 0;
|
||||
reftable_buf_release(&nm);
|
||||
}
|
||||
|
||||
static int reftable_stack_init_addition(struct reftable_addition *add,
|
||||
struct reftable_stack *st,
|
||||
const struct reftable_write_options *opts,
|
||||
unsigned int flags)
|
||||
const struct reftable_write_options *opts)
|
||||
{
|
||||
struct reftable_buf lock_file_name = REFTABLE_BUF_INIT;
|
||||
int err;
|
||||
|
|
@ -670,31 +686,28 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
|
|||
if (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);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
add->locked = 1;
|
||||
|
||||
if (add->opts.default_permissions) {
|
||||
if (chmod(add->tables_list_lock.path,
|
||||
if (chmod(add->stack->list_lock.path,
|
||||
add->opts.default_permissions) < 0) {
|
||||
err = REFTABLE_IO_ERROR;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
err = stack_uptodate(st);
|
||||
err = stack_uptodate(st, 0);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
if (err > 0 && flags & REFTABLE_STACK_NEW_ADDITION_RELOAD) {
|
||||
if (err > 0) {
|
||||
err = reftable_stack_reload_maybe_reuse(add->stack, 1);
|
||||
if (err)
|
||||
goto done;
|
||||
}
|
||||
if (err > 0) {
|
||||
err = REFTABLE_OUTDATED_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
add->next_update_index = reftable_stack_next_update_index(st);
|
||||
done:
|
||||
|
|
@ -708,13 +721,12 @@ static int stack_try_add(struct reftable_stack *st,
|
|||
int (*write_table)(struct reftable_writer *wr,
|
||||
void *arg),
|
||||
void *arg,
|
||||
const struct reftable_write_options *opts,
|
||||
unsigned flags)
|
||||
const struct reftable_write_options *opts)
|
||||
{
|
||||
struct reftable_addition add;
|
||||
int err;
|
||||
|
||||
err = reftable_stack_init_addition(&add, st, opts, flags);
|
||||
err = reftable_stack_init_addition(&add, st, opts);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
|
|
@ -731,17 +743,10 @@ done:
|
|||
int reftable_stack_add(struct reftable_stack *st,
|
||||
int (*write)(struct reftable_writer *wr, void *arg),
|
||||
void *arg,
|
||||
const struct reftable_write_options *opts,
|
||||
unsigned flags)
|
||||
const struct reftable_write_options *opts)
|
||||
{
|
||||
int err = stack_try_add(st, write, arg, opts, flags);
|
||||
int err = stack_try_add(st, write, arg, opts);
|
||||
if (err < 0) {
|
||||
if (err == REFTABLE_OUTDATED_ERROR) {
|
||||
/* Ignore error return, we want to propagate
|
||||
REFTABLE_OUTDATED_ERROR.
|
||||
*/
|
||||
reftable_stack_reload(st);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -787,7 +792,7 @@ int reftable_addition_commit(struct reftable_addition *add)
|
|||
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);
|
||||
reftable_buf_release(&table_list);
|
||||
if (err < 0) {
|
||||
|
|
@ -795,17 +800,18 @@ int reftable_addition_commit(struct reftable_addition *add)
|
|||
goto done;
|
||||
}
|
||||
|
||||
err = fsync(add->tables_list_lock.fd);
|
||||
err = fsync(add->stack->list_lock.fd);
|
||||
if (err < 0) {
|
||||
err = REFTABLE_IO_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = flock_commit(&add->tables_list_lock);
|
||||
err = flock_commit(&add->stack->list_lock);
|
||||
if (err < 0) {
|
||||
err = REFTABLE_IO_ERROR;
|
||||
goto done;
|
||||
}
|
||||
add->locked = 0;
|
||||
|
||||
/* success, no more state to clean up. */
|
||||
for (i = 0; i < add->new_tables_len; i++)
|
||||
|
|
@ -841,10 +847,9 @@ done:
|
|||
return err;
|
||||
}
|
||||
|
||||
int reftable_stack_new_addition(struct reftable_addition **dest,
|
||||
int reftable_stack_addition_new(struct reftable_addition **dest,
|
||||
struct reftable_stack *st,
|
||||
const struct reftable_write_options *opts,
|
||||
unsigned int flags)
|
||||
const struct reftable_write_options *opts)
|
||||
{
|
||||
int err;
|
||||
|
||||
|
|
@ -852,7 +857,7 @@ int reftable_stack_new_addition(struct reftable_addition **dest,
|
|||
if (!*dest)
|
||||
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) {
|
||||
reftable_free(*dest);
|
||||
*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
|
||||
* good enough to just abort.
|
||||
*/
|
||||
err = stack_uptodate(st);
|
||||
err = stack_uptodate(st, 0);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
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
|
||||
* abort.
|
||||
*/
|
||||
err = stack_uptodate(st);
|
||||
err = stack_uptodate(st, 0);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
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)
|
||||
{
|
||||
struct reftable_addition *add = NULL;
|
||||
int err = reftable_stack_new_addition(&add, st, NULL, 0);
|
||||
if (err < 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = reftable_stack_reload(st);
|
||||
int err = reftable_stack_addition_new(&add, st, NULL);
|
||||
if (err < 0) {
|
||||
goto done;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
#define STACK_H
|
||||
|
||||
#include "system.h"
|
||||
#include "reftable-writer.h"
|
||||
#include "reftable-stack.h"
|
||||
|
||||
struct reftable_stack {
|
||||
|
|
@ -18,6 +17,12 @@ struct reftable_stack {
|
|||
char *list_file;
|
||||
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;
|
||||
|
||||
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_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);
|
||||
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);
|
||||
|
||||
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(&st2, dir, NULL), 0);
|
||||
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,
|
||||
&ref2, NULL, 0), REFTABLE_OUTDATED_ERROR);
|
||||
cl_assert_equal_i(reftable_stack_reload(st2), 0);
|
||||
cl_assert_equal_i(reftable_stack_add(st2, write_test_ref,
|
||||
&ref2, NULL, 0), 0);
|
||||
&ref2, NULL), 0);
|
||||
reftable_stack_destroy(st1);
|
||||
reftable_stack_destroy(st2);
|
||||
clear_dir(dir);
|
||||
|
|
@ -260,7 +257,7 @@ void test_reftable_stack__transaction_api(void)
|
|||
|
||||
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,
|
||||
&ref), 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(&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,
|
||||
&refs[0]), 0);
|
||||
cl_assert_equal_i(reftable_addition_commit(add), 0);
|
||||
reftable_addition_destroy(add);
|
||||
|
||||
/*
|
||||
* The second stack is now outdated, which we should notice. We do not
|
||||
* create the addition and lock the stack by default, but allow the
|
||||
* reload to happen when REFTABLE_STACK_NEW_ADDITION_RELOAD is set.
|
||||
* The second stack is now outdated, but it should automatically reload it
|
||||
* with the newer updates.
|
||||
*/
|
||||
cl_assert_equal_i(reftable_stack_new_addition(&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_stack_addition_new(&add, st2, NULL), 0);
|
||||
cl_assert_equal_i(reftable_addition_add(add, write_test_ref,
|
||||
&refs[1]), 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
|
||||
* better control over when exactly auto compaction runs.
|
||||
*/
|
||||
cl_assert_equal_i(reftable_stack_new_addition(&add,
|
||||
st, &write_opts, 0), 0);
|
||||
cl_assert_equal_i(reftable_stack_addition_new(&add,
|
||||
st, &write_opts), 0);
|
||||
cl_assert_equal_i(reftable_addition_add(add,
|
||||
write_test_ref, &ref), 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_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->stats.attempts, 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);
|
||||
|
||||
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_equal_i(st->merged->tables_len, 2);
|
||||
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_stack_add(st, write_test_ref,
|
||||
&ref1, NULL, 0), 0);
|
||||
&ref1, NULL), 0);
|
||||
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);
|
||||
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);
|
||||
for (i = -1; i != REFTABLE_EMPTY_TABLE_ERROR; i--)
|
||||
cl_assert_equal_i(reftable_stack_add(st, write_error,
|
||||
&i, NULL, 0), i);
|
||||
&i, NULL), i);
|
||||
|
||||
reftable_stack_destroy(st);
|
||||
clear_dir(dir);
|
||||
|
|
@ -513,7 +506,7 @@ void test_reftable_stack__add(void)
|
|||
|
||||
for (i = 0; i < N; i++)
|
||||
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++) {
|
||||
struct write_log_arg arg = {
|
||||
|
|
@ -521,7 +514,7 @@ void test_reftable_stack__add(void)
|
|||
.update_index = reftable_stack_next_update_index(st),
|
||||
};
|
||||
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);
|
||||
|
|
@ -604,7 +597,7 @@ void test_reftable_stack__iterator(void)
|
|||
|
||||
for (i = 0; i < N; i++)
|
||||
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++) {
|
||||
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,
|
||||
&arg, NULL, 0), 0);
|
||||
&arg, NULL), 0);
|
||||
}
|
||||
|
||||
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";
|
||||
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";
|
||||
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,
|
||||
&dest), 0);
|
||||
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";
|
||||
arg.update_index = 2;
|
||||
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,
|
||||
&dest), 0);
|
||||
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++)
|
||||
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++) {
|
||||
struct write_log_arg arg = {
|
||||
|
|
@ -755,7 +748,7 @@ void test_reftable_stack__tombstone(void)
|
|||
.update_index = reftable_stack_next_update_index(st),
|
||||
};
|
||||
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",
|
||||
|
|
@ -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_stack_add(st, write_test_ref,
|
||||
&ref, NULL, 0), 0);
|
||||
&ref, NULL), 0);
|
||||
|
||||
/* can't read it with the wrong hash ID. */
|
||||
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),
|
||||
};
|
||||
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);
|
||||
|
|
@ -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_stack_add(st, write_nothing,
|
||||
NULL, NULL, 0), 0);
|
||||
NULL, NULL), 0);
|
||||
cl_assert_equal_i(reftable_new_stack(&st2, dir, NULL), 0);
|
||||
clear_dir(dir);
|
||||
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);
|
||||
|
||||
err = reftable_stack_add(st, write_test_ref, &ref, &opts, 0);
|
||||
err = reftable_stack_add(st, write_test_ref, &ref, &opts);
|
||||
cl_assert(!err);
|
||||
|
||||
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);
|
||||
|
||||
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(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;
|
||||
|
||||
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
|
||||
|
|
@ -1303,7 +1296,7 @@ void test_reftable_stack__invalid_limit_updates(void)
|
|||
|
||||
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
|
||||
|
|
@ -1317,3 +1310,31 @@ void test_reftable_stack__invalid_limit_updates(void)
|
|||
reftable_stack_destroy(st);
|
||||
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