maintenance: create maintenance.strategy config

To provide an on-ramp for users to use background maintenance without several 'git config' commands, create a 'maintenance.strategy' config option. Currently, the only important value is 'incremental' which assigns the following schedule: * gc: never * prefetch: hourly * commit-graph: hourly * loose-objects: daily * incremental-repack: daily These tasks are chosen to minimize disruptions to foreground Git commands and use few compute resources. The 'maintenance.strategy' is intended as a baseline that can be customzied further by manually assigning 'maintenance.<task>.enabled' and 'maintenance.<task>.schedule' config options, which will override any recommendation from 'maintenance.strategy'. This operates similarly to config options like 'feature.experimental' which operate as "meta" config options that change default config values. This presents a way forward for updating the 'incremental' strategy in the future or adding new strategies. For example, a potential strategy could be to include a 'full' strategy that runs the 'gc' task weekly and no other tasks by default. Helped-by: Martin Ågren <martin.agren@gmail.com> Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Oct 15, 2020 at 17:22 UTC a4cb1a2339c1aa4ba71ebc6d2b07d537e1071124
3 files changed +90 -2
Documentation/config/maintenance.txt
+15
@@ -3,6 +3,21 @@ maintenance.auto::
3 `git maintenance run --auto` after doing their normal work. Defaults
4 to true.
5
6 +maintenance.strategy::
7 + This string config option provides a way to specify one of a few
8 + recommended schedules for background maintenance. This only affects
9 + which tasks are run during `git maintenance run --schedule=X`
10 + commands, provided no `--task=<task>` arguments are provided.
11 + Further, if a `maintenance.<task>.schedule` config value is set,
12 + then that value is used instead of the one provided by
13 + `maintenance.strategy`. The possible strategy strings are:
14 ++
15 +* `none`: This default setting implies no task are run at any schedule.
16 +* `incremental`: This setting optimizes for performing small maintenance
17 + activities that do not delete any data. This does not schedule the `gc`
18 + task, but runs the `prefetch` and `commit-graph` tasks hourly and the
19 + `loose-objects` and `incremental-repack` tasks daily.
20 +
21 maintenance.<task>.enabled::
22 This boolean config option controls whether the maintenance task
23 with name `<task>` is run when no `--task` option is specified to
builtin/gc.c
+26 -2
@@ -1308,12 +1308,35 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
1308 return result;
1309 }
1310
1311 -static void initialize_task_config(void)
1311 +static void initialize_maintenance_strategy(void)
1312 +{
1313 + char *config_str;
1314 +
1315 + if (git_config_get_string("maintenance.strategy", &config_str))
1316 + return;
1317 +
1318 + if (!strcasecmp(config_str, "incremental")) {
1319 + tasks[TASK_GC].schedule = SCHEDULE_NONE;
1320 + tasks[TASK_COMMIT_GRAPH].enabled = 1;
1321 + tasks[TASK_COMMIT_GRAPH].schedule = SCHEDULE_HOURLY;
1322 + tasks[TASK_PREFETCH].enabled = 1;
1323 + tasks[TASK_PREFETCH].schedule = SCHEDULE_HOURLY;
1324 + tasks[TASK_INCREMENTAL_REPACK].enabled = 1;
1325 + tasks[TASK_INCREMENTAL_REPACK].schedule = SCHEDULE_DAILY;
1326 + tasks[TASK_LOOSE_OBJECTS].enabled = 1;
1327 + tasks[TASK_LOOSE_OBJECTS].schedule = SCHEDULE_DAILY;
1328 + }
1329 +}
1330 +
1331 +static void initialize_task_config(int schedule)
1332 {
1333 int i;
1334 struct strbuf config_name = STRBUF_INIT;
1335 gc_config();
1336
1337 + if (schedule)
1338 + initialize_maintenance_strategy();
1339 +
1340 for (i = 0; i < TASK__COUNT; i++) {
1341 int config_value;
1342 char *config_str;
@@ -1389,7 +1412,6 @@ static int maintenance_run(int argc, const char **argv, const char *prefix)
1412 memset(&opts, 0, sizeof(opts));
1413
1414 opts.quiet = !isatty(2);
1392 - initialize_task_config();
1415
1416 for (i = 0; i < TASK__COUNT; i++)
1417 tasks[i].selected_order = -1;
@@ -1402,6 +1424,8 @@ static int maintenance_run(int argc, const char **argv, const char *prefix)
1424 if (opts.auto_flag && opts.schedule)
1425 die(_("use at most one of --auto and --schedule=<frequency>"));
1426
1427 + initialize_task_config(opts.schedule);
1428 +
1429 if (argc != 0)
1430 usage_with_options(builtin_maintenance_run_usage,
1431 builtin_maintenance_run_options);
t/t7900-maintenance.sh
+49
@@ -300,6 +300,55 @@ test_expect_success '--schedule inheritance weekly -> daily -> hourly' '
300 test_subcommand git multi-pack-index write --no-progress <weekly.txt
301 '
302
303 +test_expect_success 'maintenance.strategy inheritance' '
304 + for task in commit-graph loose-objects incremental-repack
305 + do
306 + git config --unset maintenance.$task.schedule || return 1
307 + done &&
308 +
309 + test_when_finished git config --unset maintenance.strategy &&
310 + git config maintenance.strategy incremental &&
311 +
312 + GIT_TRACE2_EVENT="$(pwd)/incremental-hourly.txt" \
313 + git maintenance run --schedule=hourly --quiet &&
314 + GIT_TRACE2_EVENT="$(pwd)/incremental-daily.txt" \
315 + git maintenance run --schedule=daily --quiet &&
316 +
317 + test_subcommand git commit-graph write --split --reachable \
318 + --no-progress <incremental-hourly.txt &&
319 + test_subcommand ! git prune-packed --quiet <incremental-hourly.txt &&
320 + test_subcommand ! git multi-pack-index write --no-progress \
321 + <incremental-hourly.txt &&
322 +
323 + test_subcommand git commit-graph write --split --reachable \
324 + --no-progress <incremental-daily.txt &&
325 + test_subcommand git prune-packed --quiet <incremental-daily.txt &&
326 + test_subcommand git multi-pack-index write --no-progress \
327 + <incremental-daily.txt &&
328 +
329 + # Modify defaults
330 + git config maintenance.commit-graph.schedule daily &&
331 + git config maintenance.loose-objects.schedule hourly &&
332 + git config maintenance.incremental-repack.enabled false &&
333 +
334 + GIT_TRACE2_EVENT="$(pwd)/modified-hourly.txt" \
335 + git maintenance run --schedule=hourly --quiet &&
336 + GIT_TRACE2_EVENT="$(pwd)/modified-daily.txt" \
337 + git maintenance run --schedule=daily --quiet &&
338 +
339 + test_subcommand ! git commit-graph write --split --reachable \
340 + --no-progress <modified-hourly.txt &&
341 + test_subcommand git prune-packed --quiet <modified-hourly.txt &&
342 + test_subcommand ! git multi-pack-index write --no-progress \
343 + <modified-hourly.txt &&
344 +
345 + test_subcommand git commit-graph write --split --reachable \
346 + --no-progress <modified-daily.txt &&
347 + test_subcommand git prune-packed --quiet <modified-daily.txt &&
348 + test_subcommand ! git multi-pack-index write --no-progress \
349 + <modified-daily.txt
350 +'
351 +
352 test_expect_success 'register and unregister' '
353 test_when_finished git config --global --unset-all maintenance.repo &&
354 git config --global --add maintenance.repo /existing1 &&