Skip to content

Commit b08ff1f

Browse files
derrickstoleegitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 1942d48 commit b08ff1f

File tree

4 files changed

+118
-4
lines changed

4 files changed

+118
-4
lines changed

Documentation/config/maintenance.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ maintenance.<task>.enabled::
1010
`--task` option exists. By default, only `maintenance.gc.enabled`
1111
is true.
1212

13+
maintenance.<task>.schedule::
14+
This config option controls whether or not the given `<task>` runs
15+
during a `git maintenance run --schedule=<frequency>` command. The
16+
value must be one of "hourly", "daily", or "weekly".
17+
1318
maintenance.commit-graph.auto::
1419
This integer config option controls how often the `commit-graph` task
1520
should be run as part of `git maintenance run --auto`. If zero, then

Documentation/git-maintenance.txt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,18 @@ OPTIONS
110110
only if certain thresholds are met. For example, the `gc` task
111111
runs when the number of loose objects exceeds the number stored
112112
in the `gc.auto` config setting, or when the number of pack-files
113-
exceeds the `gc.autoPackLimit` config setting.
113+
exceeds the `gc.autoPackLimit` config setting. Not compatible with
114+
the `--schedule` option.
115+
116+
--schedule::
117+
When combined with the `run` subcommand, run maintenance tasks
118+
only if certain time conditions are met, as specified by the
119+
`maintenance.<task>.schedule` config value for each `<task>`.
120+
This config value specifies a number of seconds since the last
121+
time that task ran, according to the `maintenance.<task>.lastRun`
122+
config value. The tasks that are tested are those provided by
123+
the `--task=<task>` option(s) or those with
124+
`maintenance.<task>.enabled` set to true.
114125

115126
--quiet::
116127
Do not report progress or other information over `stderr`.

builtin/gc.c

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -703,14 +703,51 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
703703
return 0;
704704
}
705705

706-
static const char * const builtin_maintenance_run_usage[] = {
707-
N_("git maintenance run [--auto] [--[no-]quiet] [--task=<task>]"),
706+
static const char *const builtin_maintenance_run_usage[] = {
707+
N_("git maintenance run [--auto] [--[no-]quiet] [--task=<task>] [--schedule]"),
708708
NULL
709709
};
710710

711+
enum schedule_priority {
712+
SCHEDULE_NONE = 0,
713+
SCHEDULE_WEEKLY = 1,
714+
SCHEDULE_DAILY = 2,
715+
SCHEDULE_HOURLY = 3,
716+
};
717+
718+
static enum schedule_priority parse_schedule(const char *value)
719+
{
720+
if (!value)
721+
return SCHEDULE_NONE;
722+
if (!strcasecmp(value, "hourly"))
723+
return SCHEDULE_HOURLY;
724+
if (!strcasecmp(value, "daily"))
725+
return SCHEDULE_DAILY;
726+
if (!strcasecmp(value, "weekly"))
727+
return SCHEDULE_WEEKLY;
728+
return SCHEDULE_NONE;
729+
}
730+
731+
static int maintenance_opt_schedule(const struct option *opt, const char *arg,
732+
int unset)
733+
{
734+
enum schedule_priority *priority = opt->value;
735+
736+
if (unset)
737+
die(_("--no-schedule is not allowed"));
738+
739+
*priority = parse_schedule(arg);
740+
741+
if (!*priority)
742+
die(_("unrecognized --schedule argument '%s'"), arg);
743+
744+
return 0;
745+
}
746+
711747
struct maintenance_run_opts {
712748
int auto_flag;
713749
int quiet;
750+
enum schedule_priority schedule;
714751
};
715752

716753
/* Remember to update object flag allocation in object.h */
@@ -1158,6 +1195,8 @@ struct maintenance_task {
11581195
maintenance_auto_fn *auto_condition;
11591196
unsigned enabled:1;
11601197

1198+
enum schedule_priority schedule;
1199+
11611200
/* -1 if not selected. */
11621201
int selected_order;
11631202
};
@@ -1253,6 +1292,9 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
12531292
!tasks[i].auto_condition()))
12541293
continue;
12551294

1295+
if (opts->schedule && tasks[i].schedule < opts->schedule)
1296+
continue;
1297+
12561298
trace2_region_enter("maintenance", tasks[i].name, r);
12571299
if (tasks[i].fn(opts)) {
12581300
error(_("task '%s' failed"), tasks[i].name);
@@ -1273,13 +1315,23 @@ static void initialize_task_config(void)
12731315

12741316
for (i = 0; i < TASK__COUNT; i++) {
12751317
int config_value;
1318+
char *config_str;
12761319

1277-
strbuf_setlen(&config_name, 0);
1320+
strbuf_reset(&config_name);
12781321
strbuf_addf(&config_name, "maintenance.%s.enabled",
12791322
tasks[i].name);
12801323

12811324
if (!git_config_get_bool(config_name.buf, &config_value))
12821325
tasks[i].enabled = config_value;
1326+
1327+
strbuf_reset(&config_name);
1328+
strbuf_addf(&config_name, "maintenance.%s.schedule",
1329+
tasks[i].name);
1330+
1331+
if (!git_config_get_string(config_name.buf, &config_str)) {
1332+
tasks[i].schedule = parse_schedule(config_str);
1333+
free(config_str);
1334+
}
12831335
}
12841336

12851337
strbuf_release(&config_name);
@@ -1323,6 +1375,9 @@ static int maintenance_run(int argc, const char **argv, const char *prefix)
13231375
struct option builtin_maintenance_run_options[] = {
13241376
OPT_BOOL(0, "auto", &opts.auto_flag,
13251377
N_("run tasks based on the state of the repository")),
1378+
OPT_CALLBACK(0, "schedule", &opts.schedule, N_("frequency"),
1379+
N_("run tasks based on frequency"),
1380+
maintenance_opt_schedule),
13261381
OPT_BOOL(0, "quiet", &opts.quiet,
13271382
N_("do not report progress or other information over stderr")),
13281383
OPT_CALLBACK_F(0, "task", NULL, N_("task"),
@@ -1343,6 +1398,9 @@ static int maintenance_run(int argc, const char **argv, const char *prefix)
13431398
builtin_maintenance_run_usage,
13441399
PARSE_OPT_STOP_AT_NON_OPTION);
13451400

1401+
if (opts.auto_flag && opts.schedule)
1402+
die(_("use at most one of --auto and --schedule=<frequency>"));
1403+
13461404
if (argc != 0)
13471405
usage_with_options(builtin_maintenance_run_usage,
13481406
builtin_maintenance_run_options);

t/t7900-maintenance.sh

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,4 +260,44 @@ test_expect_success 'maintenance.incremental-repack.auto' '
260260
test_subcommand git multi-pack-index write --no-progress <trace-B
261261
'
262262

263+
test_expect_success '--auto and --schedule incompatible' '
264+
test_must_fail git maintenance run --auto --schedule=daily 2>err &&
265+
test_i18ngrep "at most one" err
266+
'
267+
268+
test_expect_success 'invalid --schedule value' '
269+
test_must_fail git maintenance run --schedule=annually 2>err &&
270+
test_i18ngrep "unrecognized --schedule" err
271+
'
272+
273+
test_expect_success '--schedule inheritance weekly -> daily -> hourly' '
274+
git config maintenance.loose-objects.enabled true &&
275+
git config maintenance.loose-objects.schedule hourly &&
276+
git config maintenance.commit-graph.enabled true &&
277+
git config maintenance.commit-graph.schedule daily &&
278+
git config maintenance.incremental-repack.enabled true &&
279+
git config maintenance.incremental-repack.schedule weekly &&
280+
281+
GIT_TRACE2_EVENT="$(pwd)/hourly.txt" \
282+
git maintenance run --schedule=hourly 2>/dev/null &&
283+
test_subcommand git prune-packed --quiet <hourly.txt &&
284+
test_subcommand ! git commit-graph write --split --reachable \
285+
--no-progress <hourly.txt &&
286+
test_subcommand ! git multi-pack-index write --no-progress <hourly.txt &&
287+
288+
GIT_TRACE2_EVENT="$(pwd)/daily.txt" \
289+
git maintenance run --schedule=daily 2>/dev/null &&
290+
test_subcommand git prune-packed --quiet <daily.txt &&
291+
test_subcommand git commit-graph write --split --reachable \
292+
--no-progress <daily.txt &&
293+
test_subcommand ! git multi-pack-index write --no-progress <daily.txt &&
294+
295+
GIT_TRACE2_EVENT="$(pwd)/weekly.txt" \
296+
git maintenance run --schedule=weekly 2>/dev/null &&
297+
test_subcommand git prune-packed --quiet <weekly.txt &&
298+
test_subcommand git commit-graph write --split --reachable \
299+
--no-progress <weekly.txt &&
300+
test_subcommand git multi-pack-index write --no-progress <weekly.txt
301+
'
302+
263303
test_done

0 commit comments

Comments
 (0)