Skip to content

Commit 536e6b7

Browse files
pks-tgitster
authored andcommitted
builtin/maintenance: let tasks do maintenance before and after detach
Both git-gc(1) and git-maintenance(1) have logic to daemonize so that the maintenance tasks are performed in the background. git-gc(1) has some special logic though to not perform _all_ housekeeping tasks in the background: both references and reflogs are still handled synchronously in the foreground. This split exists because otherwise it may easily happen that git-gc(1) keeps the "packed-refs" file locked for an extended amount of time, where the next Git command that wants to modify any reference could now fail. This was especially important in the past, where git-gc(1) was still executed directly as part of our automatic maintenance: git-gc(1) was invoked via `git gc --auto --detach`, so we knew to handle most of the maintenance tasks in the background while doing those parts that may cause locking issues in the foreground. We have since moved to git-maintenance(1), which is a more flexible replacement for git-gc(1). By default this command runs git-gc(1), only, but it can be configured to run different tasks, as well. This command does not know about the split between maintenance tasks that should run before and after detach though, and this has led to several bug reports about spurious locking errors for the "packed-refs" file. Prepare for a fix by introducing this split for maintenance tasks. Note that this commit does not yet change any of the tasks, so there should not (yet) be a change in behaviour. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 2c85270 commit 536e6b7

File tree

1 file changed

+33
-15
lines changed

1 file changed

+33
-15
lines changed

builtin/gc.c

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,74 +1545,86 @@ typedef int (*maintenance_auto_fn)(struct gc_config *cfg);
15451545

15461546
struct maintenance_task {
15471547
const char *name;
1548-
maintenance_task_fn fn;
1548+
maintenance_task_fn before_detach;
1549+
maintenance_task_fn after_detach;
15491550
maintenance_auto_fn auto_condition;
15501551
};
15511552

15521553
static const struct maintenance_task tasks[] = {
15531554
[TASK_PREFETCH] = {
15541555
.name = "prefetch",
1555-
.fn = maintenance_task_prefetch,
1556+
.after_detach = maintenance_task_prefetch,
15561557
},
15571558
[TASK_LOOSE_OBJECTS] = {
15581559
.name = "loose-objects",
1559-
.fn = maintenance_task_loose_objects,
1560+
.after_detach = maintenance_task_loose_objects,
15601561
.auto_condition = loose_object_auto_condition,
15611562
},
15621563
[TASK_INCREMENTAL_REPACK] = {
15631564
.name = "incremental-repack",
1564-
.fn = maintenance_task_incremental_repack,
1565+
.after_detach = maintenance_task_incremental_repack,
15651566
.auto_condition = incremental_repack_auto_condition,
15661567
},
15671568
[TASK_GC] = {
15681569
.name = "gc",
1569-
.fn = maintenance_task_gc,
1570+
.after_detach = maintenance_task_gc,
15701571
.auto_condition = need_to_gc,
15711572
},
15721573
[TASK_COMMIT_GRAPH] = {
15731574
.name = "commit-graph",
1574-
.fn = maintenance_task_commit_graph,
1575+
.after_detach = maintenance_task_commit_graph,
15751576
.auto_condition = should_write_commit_graph,
15761577
},
15771578
[TASK_PACK_REFS] = {
15781579
.name = "pack-refs",
1579-
.fn = maintenance_task_pack_refs,
1580+
.after_detach = maintenance_task_pack_refs,
15801581
.auto_condition = pack_refs_condition,
15811582
},
15821583
[TASK_REFLOG_EXPIRE] = {
15831584
.name = "reflog-expire",
1584-
.fn = maintenance_task_reflog_expire,
1585+
.after_detach = maintenance_task_reflog_expire,
15851586
.auto_condition = reflog_expire_condition,
15861587
},
15871588
[TASK_WORKTREE_PRUNE] = {
15881589
.name = "worktree-prune",
1589-
.fn = maintenance_task_worktree_prune,
1590+
.after_detach = maintenance_task_worktree_prune,
15901591
.auto_condition = worktree_prune_condition,
15911592
},
15921593
[TASK_RERERE_GC] = {
15931594
.name = "rerere-gc",
1594-
.fn = maintenance_task_rerere_gc,
1595+
.after_detach = maintenance_task_rerere_gc,
15951596
.auto_condition = rerere_gc_condition,
15961597
},
15971598
};
15981599

1600+
enum task_phase {
1601+
TASK_PHASE_BEFORE_DETACH,
1602+
TASK_PHASE_AFTER_DETACH,
1603+
};
1604+
15991605
static int maybe_run_task(const struct maintenance_task *task,
16001606
struct repository *repo,
16011607
struct maintenance_run_opts *opts,
1602-
struct gc_config *cfg)
1608+
struct gc_config *cfg,
1609+
enum task_phase phase)
16031610
{
1611+
int before = (phase == TASK_PHASE_BEFORE_DETACH);
1612+
maintenance_task_fn fn = before ? task->before_detach : task->after_detach;
1613+
const char *region = before ? "maintenance before" : "maintenance";
16041614
int ret = 0;
16051615

1616+
if (!fn)
1617+
return 0;
16061618
if (opts->auto_flag &&
16071619
(!task->auto_condition || !task->auto_condition(cfg)))
16081620
return 0;
16091621

1610-
trace2_region_enter("maintenance", task->name, repo);
1611-
if (task->fn(opts, cfg)) {
1622+
trace2_region_enter(region, task->name, repo);
1623+
if (fn(opts, cfg)) {
16121624
error(_("task '%s' failed"), task->name);
16131625
ret = 1;
16141626
}
1615-
trace2_region_leave("maintenance", task->name, repo);
1627+
trace2_region_leave(region, task->name, repo);
16161628

16171629
return ret;
16181630
}
@@ -1641,6 +1653,11 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts,
16411653
}
16421654
free(lock_path);
16431655

1656+
for (size_t i = 0; i < opts->tasks_nr; i++)
1657+
if (maybe_run_task(&tasks[opts->tasks[i]], r, opts, cfg,
1658+
TASK_PHASE_BEFORE_DETACH))
1659+
result = 1;
1660+
16441661
/* Failure to daemonize is ok, we'll continue in foreground. */
16451662
if (opts->detach > 0) {
16461663
trace2_region_enter("maintenance", "detach", the_repository);
@@ -1649,7 +1666,8 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts,
16491666
}
16501667

16511668
for (size_t i = 0; i < opts->tasks_nr; i++)
1652-
if (maybe_run_task(&tasks[opts->tasks[i]], r, opts, cfg))
1669+
if (maybe_run_task(&tasks[opts->tasks[i]], r, opts, cfg,
1670+
TASK_PHASE_AFTER_DETACH))
16531671
result = 1;
16541672

16551673
rollback_lock_file(&lk);

0 commit comments

Comments
 (0)