]> git.ipfire.org Git - thirdparty/git.git/commitdiff
maintenance: take a lock on the objects directory
authorDerrick Stolee <dstolee@microsoft.com>
Thu, 17 Sep 2020 18:11:48 +0000 (18:11 +0000)
committerJunio C Hamano <gitster@pobox.com>
Thu, 17 Sep 2020 18:30:05 +0000 (11:30 -0700)
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>
builtin/gc.c

index 00fff59bdb2c05a4275d1a654b16cc2c89399476..7ba9c6f7c95c5a2af1842526bf56ee58128495f6 100644 (file)
@@ -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;
 }