Maintenance currently triggers when certain data-size thresholds are
met, such as number of pack-files or loose objects. Users may want to
run certain maintenance tasks based on frequency instead. For example,
a user may want to perform a 'prefetch' task every hour, or 'gc' task
every day. To help these users, update the 'git maintenance run' command
to include a '--schedule=<frequency>' option. The allowed frequencies
are 'hourly', 'daily', and 'weekly'. These values are also allowed in a
new config value 'maintenance.<task>.schedule'.
The 'git maintenance run --schedule=<frequency>' checks the '*.schedule'
config value for each enabled task to see if the configured frequency is
at least as frequent as the frequency from the '--schedule' argument. We
use the following order, for full clarity:
'hourly' > 'daily' > 'weekly'
Use new 'enum schedule_priority' to track these values numerically.
The following cron table would run the scheduled tasks with the correct
frequencies:
0 1-23 * * * git -C <repo> maintenance run --schedule=hourly
0 0 * * 1-6 git -C <repo> maintenance run --schedule=daily
0 0 * * 0 git -C <repo> maintenance run --schedule=weekly
This cron schedule will run --schedule=hourly every hour except at
midnight. This avoids a concurrent run with the --schedule=daily that
runs at midnight every day except the first day of the week. This avoids
a concurrent run with the --schedule=weekly that runs at midnight on
the first day of the week. Since --schedule=daily also runs the
'hourly' tasks and --schedule=weekly runs the 'hourly' and 'daily'
tasks, we will still see all tasks run with the proper frequencies.
Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Derrick Stolee committedSep 11, 2020 at 17:49 UTCb08ff1fee000230ad22fee823aabff2613bd4e62
4 files changed+118-4
Documentation/config/maintenance.txt
+5
index 06db758172..70585564fa 100644--- a/Documentation/config/maintenance.txt+++ b/Documentation/config/maintenance.txt@@ -10,6 +10,11 @@ maintenance.<task>.enabled:: `--task` option exists. By default, only `maintenance.gc.enabled` is true.+maintenance.<task>.schedule::+ This config option controls whether or not the given `<task>` runs+ during a `git maintenance run --schedule=<frequency>` command. The+ value must be one of "hourly", "daily", or "weekly".+ maintenance.commit-graph.auto:: This integer config option controls how often the `commit-graph` task should be run as part of `git maintenance run --auto`. If zero, then
Documentation/git-maintenance.txt
+12-1
index 3f5d8946b4..ed94f66e36 100644--- a/Documentation/git-maintenance.txt+++ b/Documentation/git-maintenance.txt@@ -110,7 +110,18 @@ OPTIONS only if certain thresholds are met. For example, the `gc` task runs when the number of loose objects exceeds the number stored in the `gc.auto` config setting, or when the number of pack-files- exceeds the `gc.autoPackLimit` config setting.+ exceeds the `gc.autoPackLimit` config setting. Not compatible with+ the `--schedule` option.++--schedule::+ When combined with the `run` subcommand, run maintenance tasks+ only if certain time conditions are met, as specified by the+ `maintenance.<task>.schedule` config value for each `<task>`.+ This config value specifies a number of seconds since the last+ time that task ran, according to the `maintenance.<task>.lastRun`+ config value. The tasks that are tested are those provided by+ the `--task=<task>` option(s) or those with+ `maintenance.<task>.enabled` set to true. --quiet:: Do not report progress or other information over `stderr`.
builtin/gc.c
+61-3
index 2b99596ec8..03b24ea0db 100644--- a/builtin/gc.c+++ b/builtin/gc.c@@ -703,14 +703,51 @@ int cmd_gc(int argc, const char **argv, const char *prefix) return 0; }-static const char * const builtin_maintenance_run_usage[] = {- N_("git maintenance run [--auto] [--[no-]quiet] [--task=<task>]"),+static const char *const builtin_maintenance_run_usage[] = {+ N_("git maintenance run [--auto] [--[no-]quiet] [--task=<task>] [--schedule]"), NULL };+enum schedule_priority {+ SCHEDULE_NONE = 0,+ SCHEDULE_WEEKLY = 1,+ SCHEDULE_DAILY = 2,+ SCHEDULE_HOURLY = 3,+};++static enum schedule_priority parse_schedule(const char *value)+{+ if (!value)+ return SCHEDULE_NONE;+ if (!strcasecmp(value, "hourly"))+ return SCHEDULE_HOURLY;+ if (!strcasecmp(value, "daily"))+ return SCHEDULE_DAILY;+ if (!strcasecmp(value, "weekly"))+ return SCHEDULE_WEEKLY;+ return SCHEDULE_NONE;+}++static int maintenance_opt_schedule(const struct option *opt, const char *arg,+ int unset)+{+ enum schedule_priority *priority = opt->value;++ if (unset)+ die(_("--no-schedule is not allowed"));++ *priority = parse_schedule(arg);++ if (!*priority)+ die(_("unrecognized --schedule argument '%s'"), arg);++ return 0;+}+ struct maintenance_run_opts { int auto_flag; int quiet;+ enum schedule_priority schedule; }; /* Remember to update object flag allocation in object.h */@@ -1158,6 +1195,8 @@ struct maintenance_task { maintenance_auto_fn *auto_condition; unsigned enabled:1;+ enum schedule_priority schedule;+ /* -1 if not selected. */ int selected_order; };@@ -1253,6 +1292,9 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts) !tasks[i].auto_condition())) continue;+ if (opts->schedule && tasks[i].schedule < opts->schedule)+ continue;+ trace2_region_enter("maintenance", tasks[i].name, r); if (tasks[i].fn(opts)) { error(_("task '%s' failed"), tasks[i].name);@@ -1273,13 +1315,23 @@ static void initialize_task_config(void) for (i = 0; i < TASK__COUNT; i++) { int config_value;+ char *config_str;- strbuf_setlen(&config_name, 0);+ strbuf_reset(&config_name); strbuf_addf(&config_name, "maintenance.%s.enabled", tasks[i].name); if (!git_config_get_bool(config_name.buf, &config_value)) tasks[i].enabled = config_value;++ strbuf_reset(&config_name);+ strbuf_addf(&config_name, "maintenance.%s.schedule",+ tasks[i].name);++ if (!git_config_get_string(config_name.buf, &config_str)) {+ tasks[i].schedule = parse_schedule(config_str);+ free(config_str);+ } } strbuf_release(&config_name);@@ -1323,6 +1375,9 @@ static int maintenance_run(int argc, const char **argv, const char *prefix) struct option builtin_maintenance_run_options[] = { OPT_BOOL(0, "auto", &opts.auto_flag, N_("run tasks based on the state of the repository")),+ OPT_CALLBACK(0, "schedule", &opts.schedule, N_("frequency"),+ N_("run tasks based on frequency"),+ maintenance_opt_schedule), OPT_BOOL(0, "quiet", &opts.quiet, N_("do not report progress or other information over stderr")), OPT_CALLBACK_F(0, "task", NULL, N_("task"),@@ -1343,6 +1398,9 @@ static int maintenance_run(int argc, const char **argv, const char *prefix) builtin_maintenance_run_usage, PARSE_OPT_STOP_AT_NON_OPTION);+ if (opts.auto_flag && opts.schedule)+ die(_("use at most one of --auto and --schedule=<frequency>"));+ if (argc != 0) usage_with_options(builtin_maintenance_run_usage, builtin_maintenance_run_options);