By default, the geometric sequence uses a factor of 2, meaning that for any
table, the next-biggest table must at least be twice as big. A maximum factor
of 256 is supported.
+
+reftable.lockTimeout::
+ Whenever the reftable backend appends a new table to the stack, it has
+ to lock the central "tables.list" file before updating it. This config
+ controls how long the process will wait to acquire the lock in case
+ another process has already acquired it. Value 0 means not to retry at
+ all; -1 means to try indefinitely. Default is 100 (i.e., retry for
+ 100ms).
if (factor > UINT8_MAX)
die("reftable geometric factor cannot exceed %u", (unsigned)UINT8_MAX);
opts->auto_compaction_factor = factor;
+ } else if (!strcmp(var, "reftable.locktimeout")) {
+ int64_t lock_timeout = git_config_int64(var, value, ctx->kvi);
+ if (lock_timeout > LONG_MAX)
+ die("reftable lock timeout cannot exceed %"PRIdMAX, (intmax_t)LONG_MAX);
+ if (lock_timeout < 0 && lock_timeout != -1)
+ die("reftable lock timeout does not support negative values other than -1");
+ opts->lock_timeout_ms = lock_timeout;
}
return 0;
refs->write_options.default_permissions = calc_shared_perm(0666 & ~mask);
refs->write_options.disable_auto_compact =
!git_env_bool("GIT_TEST_REFTABLE_AUTOCOMPACTION", 1);
+ refs->write_options.lock_timeout_ms = 100;
git_config(reftable_be_config, &refs->write_options);
* tables to compact. Defaults to 2 if unset.
*/
uint8_t auto_compaction_factor;
+
+ /*
+ * The number of milliseconds to wait when trying to lock "tables.list".
+ * Note that this does not apply to locking individual tables, as these
+ * should only ever be locked when already holding the "tables.list"
+ * lock.
+ *
+ * Passing 0 will fail immediately when the file is locked, passing a
+ * negative value will cause us to block indefinitely.
+ */
+ long lock_timeout_ms;
};
/* reftable_block_stats holds statistics for a single block type */
add->stack = st;
- err = hold_lock_file_for_update(&add->tables_list_lock, st->list_file,
- LOCK_NO_DEREF);
+ err = hold_lock_file_for_update_timeout(&add->tables_list_lock,
+ st->list_file,
+ LOCK_NO_DEREF,
+ st->opts.lock_timeout_ms);
if (err < 0) {
if (errno == EEXIST) {
err = REFTABLE_LOCK_ERROR;
* Hold the lock so that we can read "tables.list" and lock all tables
* which are part of the user-specified range.
*/
- err = hold_lock_file_for_update(&tables_list_lock, st->list_file,
- LOCK_NO_DEREF);
+ err = hold_lock_file_for_update_timeout(&tables_list_lock,
+ st->list_file,
+ LOCK_NO_DEREF,
+ st->opts.lock_timeout_ms);
if (err < 0) {
if (errno == EEXIST)
err = REFTABLE_LOCK_ERROR;
* "tables.list". We'll then replace the compacted range of tables with
* the new table.
*/
- err = hold_lock_file_for_update(&tables_list_lock, st->list_file,
- LOCK_NO_DEREF);
+ err = hold_lock_file_for_update_timeout(&tables_list_lock,
+ st->list_file,
+ LOCK_NO_DEREF,
+ st->opts.lock_timeout_ms);
if (err < 0) {
if (errno == EEXIST)
err = REFTABLE_LOCK_ERROR;
)
'
+test_expect_success 'ref transaction: timeout acquiring tables.list lock' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ >.git/reftable/tables.list.lock &&
+ test_must_fail git update-ref refs/heads/branch HEAD 2>err &&
+ test_grep "cannot lock references" err
+ )
+'
+
+test_expect_success 'ref transaction: retry acquiring tables.list lock' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ LOCK=.git/reftable/tables.list.lock &&
+ >$LOCK &&
+ {
+ ( sleep 1 && rm -f $LOCK ) &
+ } &&
+ git -c reftable.lockTimeout=5000 update-ref refs/heads/branch HEAD
+ )
+'
+
test_expect_success 'pack-refs: compacts tables' '
test_when_finished "rm -rf repo" &&
git init repo &&