Skip to content

Commit 76d846d

Browse files
committed
git_config_set_multivar_in_file_gently(): add a lock timeout
In particular when multiple processes want to write to the config simultaneously, it would come in handy to not fail immediately when another process locked the config, but to gently try again. This will help with Scalar's functional test suite which wants to register multiple repositories for maintenance semi-simultaneously. As not all code paths calling this function read the config (e.g. `git config`), we have to read the config setting via `git_config_get_ulong()`. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
1 parent cd70bea commit 76d846d

2 files changed

Lines changed: 16 additions & 1 deletion

File tree

‎Documentation/config/core.adoc‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,3 +796,12 @@ core.WSLCompat::
796796
The default value is false. When set to true, Git will set the mode
797797
bits of the file in the way of wsl, so that the executable flag of
798798
files can be set or read correctly.
799+
800+
core.configWriteLockTimeoutMS::
801+
When processes try to write to the config concurrently, it is likely
802+
that one process "wins" and the other process(es) fail to lock the
803+
config file. By configuring a timeout larger than zero, Git can be
804+
told to try to lock the config again a couple times within the
805+
specified timeout. If the timeout is configure to zero (which is the
806+
default), Git will fail immediately when the config is already
807+
locked.

‎config.c‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2954,6 +2954,7 @@ int repo_config_set_multivar_in_file_gently(struct repository *r,
29542954
const char *comment,
29552955
unsigned flags)
29562956
{
2957+
static unsigned long timeout_ms = ULONG_MAX;
29572958
int fd = -1, in_fd = -1;
29582959
int ret;
29592960
struct lock_file lock = LOCK_INIT;
@@ -2982,11 +2983,16 @@ int repo_config_set_multivar_in_file_gently(struct repository *r,
29822983
if (!config_filename)
29832984
config_filename = filename_buf = repo_git_path(r, "config");
29842985

2986+
if ((long)timeout_ms < 0 &&
2987+
repo_config_get_ulong(r, "core.configWriteLockTimeoutMS", &timeout_ms))
2988+
timeout_ms = 0;
2989+
29852990
/*
29862991
* The lock serves a purpose in addition to locking: the new
29872992
* contents of .git/config will be written into it.
29882993
*/
2989-
fd = hold_lock_file_for_update(&lock, config_filename, 0);
2994+
fd = hold_lock_file_for_update_timeout(&lock, config_filename, 0,
2995+
timeout_ms);
29902996
if (fd < 0) {
29912997
error_errno(_("could not lock config file %s"), config_filename);
29922998
ret = CONFIG_NO_LOCK;

0 commit comments

Comments
 (0)