summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar Derrick Stolee <dstolee@microsoft.com>2020-09-17 18:11:48 +0000
committerLibravatar Junio C Hamano <gitster@pobox.com>2020-09-17 11:30:05 -0700
commitd7514f6ed57d20bcc9dcfb43016b95dba82ba790 (patch)
treee5fb5acb0e4b14f471c5f541edce34671127a140
parentmaintenance: add --task option (diff)
downloadtgif-d7514f6ed57d20bcc9dcfb43016b95dba82ba790.tar.xz
maintenance: take a lock on the objects directory
Performing maintenance on a Git repository involves writing data to the .git directory, which is not safe to do with multiple writers attempting the same operation. Ensure that only one 'git maintenance' process is running at a time by holding a file-based lock. Simply the presence of the .git/maintenance.lock file will prevent future maintenance. This lock is never committed, since it does not represent meaningful data. Instead, it is only a placeholder. If the lock file already exists, then no maintenance tasks are attempted. This will become very important later when we implement the 'prefetch' task, as this is our stop-gap from creating a recursive process loop between 'git fetch' and 'git maintenance run --auto'. Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--builtin/gc.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/builtin/gc.c b/builtin/gc.c
index 00fff59bdb..7ba9c6f7c9 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -798,6 +798,25 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
{
int i, found_selected = 0;
int result = 0;
+ struct lock_file lk;
+ struct repository *r = the_repository;
+ char *lock_path = xstrfmt("%s/maintenance", r->objects->odb->path);
+
+ if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) {
+ /*
+ * Another maintenance command is running.
+ *
+ * If --auto was provided, then it is likely due to a
+ * recursive process stack. Do not report an error in
+ * that case.
+ */
+ if (!opts->auto_flag && !opts->quiet)
+ warning(_("lock file '%s' exists, skipping maintenance"),
+ lock_path);
+ free(lock_path);
+ return 0;
+ }
+ free(lock_path);
for (i = 0; !found_selected && i < TASK__COUNT; i++)
found_selected = tasks[i].selected_order >= 0;
@@ -818,6 +837,7 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
}
}
+ rollback_lock_file(&lk);
return result;
}