maintenance: add --schedule option and config
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>
This commit is contained in:
parent
1942d48380
commit
b08ff1fee0
@ -10,6 +10,11 @@ maintenance.<task>.enabled::
|
|||||||
`--task` option exists. By default, only `maintenance.gc.enabled`
|
`--task` option exists. By default, only `maintenance.gc.enabled`
|
||||||
is true.
|
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::
|
maintenance.commit-graph.auto::
|
||||||
This integer config option controls how often the `commit-graph` task
|
This integer config option controls how often the `commit-graph` task
|
||||||
should be run as part of `git maintenance run --auto`. If zero, then
|
should be run as part of `git maintenance run --auto`. If zero, then
|
||||||
|
@ -110,7 +110,18 @@ OPTIONS
|
|||||||
only if certain thresholds are met. For example, the `gc` task
|
only if certain thresholds are met. For example, the `gc` task
|
||||||
runs when the number of loose objects exceeds the number stored
|
runs when the number of loose objects exceeds the number stored
|
||||||
in the `gc.auto` config setting, or when the number of pack-files
|
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::
|
--quiet::
|
||||||
Do not report progress or other information over `stderr`.
|
Do not report progress or other information over `stderr`.
|
||||||
|
64
builtin/gc.c
64
builtin/gc.c
@ -703,14 +703,51 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char * const builtin_maintenance_run_usage[] = {
|
static const char *const builtin_maintenance_run_usage[] = {
|
||||||
N_("git maintenance run [--auto] [--[no-]quiet] [--task=<task>]"),
|
N_("git maintenance run [--auto] [--[no-]quiet] [--task=<task>] [--schedule]"),
|
||||||
NULL
|
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 {
|
struct maintenance_run_opts {
|
||||||
int auto_flag;
|
int auto_flag;
|
||||||
int quiet;
|
int quiet;
|
||||||
|
enum schedule_priority schedule;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Remember to update object flag allocation in object.h */
|
/* Remember to update object flag allocation in object.h */
|
||||||
@ -1158,6 +1195,8 @@ struct maintenance_task {
|
|||||||
maintenance_auto_fn *auto_condition;
|
maintenance_auto_fn *auto_condition;
|
||||||
unsigned enabled:1;
|
unsigned enabled:1;
|
||||||
|
|
||||||
|
enum schedule_priority schedule;
|
||||||
|
|
||||||
/* -1 if not selected. */
|
/* -1 if not selected. */
|
||||||
int selected_order;
|
int selected_order;
|
||||||
};
|
};
|
||||||
@ -1253,6 +1292,9 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
|
|||||||
!tasks[i].auto_condition()))
|
!tasks[i].auto_condition()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (opts->schedule && tasks[i].schedule < opts->schedule)
|
||||||
|
continue;
|
||||||
|
|
||||||
trace2_region_enter("maintenance", tasks[i].name, r);
|
trace2_region_enter("maintenance", tasks[i].name, r);
|
||||||
if (tasks[i].fn(opts)) {
|
if (tasks[i].fn(opts)) {
|
||||||
error(_("task '%s' failed"), tasks[i].name);
|
error(_("task '%s' failed"), tasks[i].name);
|
||||||
@ -1273,13 +1315,23 @@ static void initialize_task_config(void)
|
|||||||
|
|
||||||
for (i = 0; i < TASK__COUNT; i++) {
|
for (i = 0; i < TASK__COUNT; i++) {
|
||||||
int config_value;
|
int config_value;
|
||||||
|
char *config_str;
|
||||||
|
|
||||||
strbuf_setlen(&config_name, 0);
|
strbuf_reset(&config_name);
|
||||||
strbuf_addf(&config_name, "maintenance.%s.enabled",
|
strbuf_addf(&config_name, "maintenance.%s.enabled",
|
||||||
tasks[i].name);
|
tasks[i].name);
|
||||||
|
|
||||||
if (!git_config_get_bool(config_name.buf, &config_value))
|
if (!git_config_get_bool(config_name.buf, &config_value))
|
||||||
tasks[i].enabled = 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);
|
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[] = {
|
struct option builtin_maintenance_run_options[] = {
|
||||||
OPT_BOOL(0, "auto", &opts.auto_flag,
|
OPT_BOOL(0, "auto", &opts.auto_flag,
|
||||||
N_("run tasks based on the state of the repository")),
|
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,
|
OPT_BOOL(0, "quiet", &opts.quiet,
|
||||||
N_("do not report progress or other information over stderr")),
|
N_("do not report progress or other information over stderr")),
|
||||||
OPT_CALLBACK_F(0, "task", NULL, N_("task"),
|
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,
|
builtin_maintenance_run_usage,
|
||||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
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)
|
if (argc != 0)
|
||||||
usage_with_options(builtin_maintenance_run_usage,
|
usage_with_options(builtin_maintenance_run_usage,
|
||||||
builtin_maintenance_run_options);
|
builtin_maintenance_run_options);
|
||||||
|
@ -260,4 +260,44 @@ test_expect_success 'maintenance.incremental-repack.auto' '
|
|||||||
test_subcommand git multi-pack-index write --no-progress <trace-B
|
test_subcommand git multi-pack-index write --no-progress <trace-B
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success '--auto and --schedule incompatible' '
|
||||||
|
test_must_fail git maintenance run --auto --schedule=daily 2>err &&
|
||||||
|
test_i18ngrep "at most one" err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'invalid --schedule value' '
|
||||||
|
test_must_fail git maintenance run --schedule=annually 2>err &&
|
||||||
|
test_i18ngrep "unrecognized --schedule" err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '--schedule inheritance weekly -> daily -> hourly' '
|
||||||
|
git config maintenance.loose-objects.enabled true &&
|
||||||
|
git config maintenance.loose-objects.schedule hourly &&
|
||||||
|
git config maintenance.commit-graph.enabled true &&
|
||||||
|
git config maintenance.commit-graph.schedule daily &&
|
||||||
|
git config maintenance.incremental-repack.enabled true &&
|
||||||
|
git config maintenance.incremental-repack.schedule weekly &&
|
||||||
|
|
||||||
|
GIT_TRACE2_EVENT="$(pwd)/hourly.txt" \
|
||||||
|
git maintenance run --schedule=hourly 2>/dev/null &&
|
||||||
|
test_subcommand git prune-packed --quiet <hourly.txt &&
|
||||||
|
test_subcommand ! git commit-graph write --split --reachable \
|
||||||
|
--no-progress <hourly.txt &&
|
||||||
|
test_subcommand ! git multi-pack-index write --no-progress <hourly.txt &&
|
||||||
|
|
||||||
|
GIT_TRACE2_EVENT="$(pwd)/daily.txt" \
|
||||||
|
git maintenance run --schedule=daily 2>/dev/null &&
|
||||||
|
test_subcommand git prune-packed --quiet <daily.txt &&
|
||||||
|
test_subcommand git commit-graph write --split --reachable \
|
||||||
|
--no-progress <daily.txt &&
|
||||||
|
test_subcommand ! git multi-pack-index write --no-progress <daily.txt &&
|
||||||
|
|
||||||
|
GIT_TRACE2_EVENT="$(pwd)/weekly.txt" \
|
||||||
|
git maintenance run --schedule=weekly 2>/dev/null &&
|
||||||
|
test_subcommand git prune-packed --quiet <weekly.txt &&
|
||||||
|
test_subcommand git commit-graph write --split --reachable \
|
||||||
|
--no-progress <weekly.txt &&
|
||||||
|
test_subcommand git multi-pack-index write --no-progress <weekly.txt
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
Loading…
x
Reference in New Issue
Block a user