Skip to content

Commit

Permalink
Merge pull request #468: maintenance: delete stale lock files, fix lo…
Browse files Browse the repository at this point in the history
…ose-objects task

The maintenance.lock file exists to prevent concurrent maintenance
processes from writing to a repository at the same time. However, it has
the downside of causing maintenance to start failing without recovery if
there is any reason why the maintenance command failed without cleaning
up the lock-file.

This change makes it such that maintenance will delete a lock file that
was modified over 6 hours ago. This will auto-heal repositories that are
stuck with failed maintenance (and maybe it will fail again, but we will
get a message other than the lock file exists).

The intention here is to get users out of a bad state without weakening the maintenance lock _too_ much. I'm open to other thoughts, including expanding the timeframe from 6 to 24 hours.

---

The `fixup!` commit fixes the use of the `gvfs.sharedcache` config value around the loose-objects task. Specifically, the loose-objects step might fail because it is calling `git pack-objects {garbage}/pack/loose` which fails.
  • Loading branch information
derrickstolee authored and dscho committed Jun 17, 2022
2 parents 3447791 + b958fd0 commit 1df65de
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 0 deletions.
21 changes: 21 additions & 0 deletions builtin/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1284,6 +1284,8 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
char *lock_path = xstrfmt("%s/maintenance", r->objects->odb->path);

if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) {
struct stat st;
struct strbuf lock_dot_lock = STRBUF_INIT;
/*
* Another maintenance command is running.
*
Expand All @@ -1294,6 +1296,25 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
if (!opts->auto_flag && !opts->quiet)
warning(_("lock file '%s' exists, skipping maintenance"),
lock_path);

/*
* Check timestamp on .lock file to see if we should
* delete it to recover from a fail state.
*/
strbuf_addstr(&lock_dot_lock, lock_path);
strbuf_addstr(&lock_dot_lock, ".lock");
if (lstat(lock_dot_lock.buf, &st))
warning_errno(_("unable to stat '%s'"), lock_dot_lock.buf);
else {
if (st.st_mtime < time(NULL) - (6 * 60 * 60)) {
if (unlink(lock_dot_lock.buf))
warning_errno(_("unable to delete stale lock file"));
else
warning(_("deleted stale lock file"));
}
}

strbuf_release(&lock_dot_lock);
free(lock_path);
return 0;
}
Expand Down
17 changes: 17 additions & 0 deletions t/t7900-maintenance.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,23 @@ test_expect_success 'run [--auto|--quiet]' '
test_subcommand git gc --no-quiet <run-no-quiet.txt
'

test_expect_success 'lock file behavior' '
test_when_finished git config --unset maintenance.commit-graph.schedule &&
git config maintenance.commit-graph.schedule hourly &&
touch .git/objects/maintenance.lock &&
git maintenance run --schedule=hourly --no-quiet 2>err &&
grep "lock file .* exists, skipping maintenance" err &&
test-tool chmtime =-22000 .git/objects/maintenance.lock &&
git maintenance run --schedule=hourly --no-quiet 2>err &&
grep "deleted stale lock file" err &&
test_path_is_missing .git/objects/maintenance.lock &&
git maintenance run --schedule=hourly 2>err &&
test_must_be_empty err
'

test_expect_success 'maintenance.auto config option' '
GIT_TRACE2_EVENT="$(pwd)/default" git commit --quiet --allow-empty -m 1 &&
test_subcommand git maintenance run --auto --quiet <default &&
Expand Down

0 comments on commit 1df65de

Please sign in to comment.