@@ -251,7 +251,24 @@ static enum schedule_priority parse_schedule(const char *value)
251251 return SCHEDULE_NONE ;
252252}
253253
254+ enum maintenance_task_label {
255+ TASK_PREFETCH ,
256+ TASK_LOOSE_OBJECTS ,
257+ TASK_INCREMENTAL_REPACK ,
258+ TASK_GC ,
259+ TASK_COMMIT_GRAPH ,
260+ TASK_PACK_REFS ,
261+ TASK_REFLOG_EXPIRE ,
262+ TASK_WORKTREE_PRUNE ,
263+ TASK_RERERE_GC ,
264+
265+ /* Leave as final value */
266+ TASK__COUNT
267+ };
268+
254269struct maintenance_run_opts {
270+ enum maintenance_task_label * tasks ;
271+ size_t tasks_nr , tasks_alloc ;
255272 int auto_flag ;
256273 int detach ;
257274 int quiet ;
@@ -261,6 +278,11 @@ struct maintenance_run_opts {
261278 .detach = -1, \
262279}
263280
281+ static void maintenance_run_opts_release (struct maintenance_run_opts * opts )
282+ {
283+ free (opts -> tasks );
284+ }
285+
264286static int pack_refs_condition (UNUSED struct gc_config * cfg )
265287{
266288 /*
@@ -1032,6 +1054,7 @@ int cmd_gc(int argc,
10321054 }
10331055
10341056out :
1057+ maintenance_run_opts_release (& opts );
10351058 gc_config_release (& cfg );
10361059 return 0 ;
10371060}
@@ -1524,30 +1547,9 @@ struct maintenance_task {
15241547 const char * name ;
15251548 maintenance_task_fn * fn ;
15261549 maintenance_auto_fn * auto_condition ;
1527- unsigned enabled :1 ;
1528-
1529- enum schedule_priority schedule ;
1530-
1531- /* -1 if not selected. */
1532- int selected_order ;
1533- };
1534-
1535- enum maintenance_task_label {
1536- TASK_PREFETCH ,
1537- TASK_LOOSE_OBJECTS ,
1538- TASK_INCREMENTAL_REPACK ,
1539- TASK_GC ,
1540- TASK_COMMIT_GRAPH ,
1541- TASK_PACK_REFS ,
1542- TASK_REFLOG_EXPIRE ,
1543- TASK_WORKTREE_PRUNE ,
1544- TASK_RERERE_GC ,
1545-
1546- /* Leave as final value */
1547- TASK__COUNT
15481550};
15491551
1550- static struct maintenance_task tasks [] = {
1552+ static const struct maintenance_task tasks [] = {
15511553 [TASK_PREFETCH ] = {
15521554 .name = "prefetch" ,
15531555 .fn = maintenance_task_prefetch ,
@@ -1566,7 +1568,6 @@ static struct maintenance_task tasks[] = {
15661568 .name = "gc" ,
15671569 .fn = maintenance_task_gc ,
15681570 .auto_condition = need_to_gc ,
1569- .enabled = 1 ,
15701571 },
15711572 [TASK_COMMIT_GRAPH ] = {
15721573 .name = "commit-graph" ,
@@ -1595,18 +1596,9 @@ static struct maintenance_task tasks[] = {
15951596 },
15961597};
15971598
1598- static int compare_tasks_by_selection (const void * a_ , const void * b_ )
1599- {
1600- const struct maintenance_task * a = a_ ;
1601- const struct maintenance_task * b = b_ ;
1602-
1603- return b -> selected_order - a -> selected_order ;
1604- }
1605-
16061599static int maintenance_run_tasks (struct maintenance_run_opts * opts ,
16071600 struct gc_config * cfg )
16081601{
1609- int i , found_selected = 0 ;
16101602 int result = 0 ;
16111603 struct lock_file lk ;
16121604 struct repository * r = the_repository ;
@@ -1635,95 +1627,120 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts,
16351627 trace2_region_leave ("maintenance" , "detach" , the_repository );
16361628 }
16371629
1638- for (i = 0 ; !found_selected && i < TASK__COUNT ; i ++ )
1639- found_selected = tasks [i ].selected_order >= 0 ;
1640-
1641- if (found_selected )
1642- QSORT (tasks , TASK__COUNT , compare_tasks_by_selection );
1643-
1644- for (i = 0 ; i < TASK__COUNT ; i ++ ) {
1645- if (found_selected && tasks [i ].selected_order < 0 )
1646- continue ;
1647-
1648- if (!found_selected && !tasks [i ].enabled )
1649- continue ;
1650-
1630+ for (size_t i = 0 ; i < opts -> tasks_nr ; i ++ ) {
16511631 if (opts -> auto_flag &&
1652- (!tasks [i ].auto_condition ||
1653- !tasks [i ].auto_condition (cfg )))
1654- continue ;
1655-
1656- if (opts -> schedule && tasks [i ].schedule < opts -> schedule )
1632+ (!tasks [opts -> tasks [i ]].auto_condition ||
1633+ !tasks [opts -> tasks [i ]].auto_condition (cfg )))
16571634 continue ;
16581635
1659- trace2_region_enter ("maintenance" , tasks [i ].name , r );
1660- if (tasks [i ].fn (opts , cfg )) {
1661- error (_ ("task '%s' failed" ), tasks [i ].name );
1636+ trace2_region_enter ("maintenance" , tasks [opts -> tasks [ i ] ].name , r );
1637+ if (tasks [opts -> tasks [ i ] ].fn (opts , cfg )) {
1638+ error (_ ("task '%s' failed" ), tasks [opts -> tasks [ i ] ].name );
16621639 result = 1 ;
16631640 }
1664- trace2_region_leave ("maintenance" , tasks [i ].name , r );
1641+ trace2_region_leave ("maintenance" , tasks [opts -> tasks [ i ] ].name , r );
16651642 }
16661643
16671644 rollback_lock_file (& lk );
16681645 return result ;
16691646}
16701647
1671- static void initialize_maintenance_strategy (void )
1648+ struct maintenance_strategy {
1649+ struct {
1650+ int enabled ;
1651+ enum schedule_priority schedule ;
1652+ } tasks [TASK__COUNT ];
1653+ };
1654+
1655+ static const struct maintenance_strategy none_strategy = { 0 };
1656+ static const struct maintenance_strategy default_strategy = {
1657+ .tasks = {
1658+ [TASK_GC ].enabled = 1 ,
1659+ },
1660+ };
1661+ static const struct maintenance_strategy incremental_strategy = {
1662+ .tasks = {
1663+ [TASK_COMMIT_GRAPH ].enabled = 1 ,
1664+ [TASK_COMMIT_GRAPH ].schedule = SCHEDULE_HOURLY ,
1665+ [TASK_PREFETCH ].enabled = 1 ,
1666+ [TASK_PREFETCH ].schedule = SCHEDULE_HOURLY ,
1667+ [TASK_INCREMENTAL_REPACK ].enabled = 1 ,
1668+ [TASK_INCREMENTAL_REPACK ].schedule = SCHEDULE_DAILY ,
1669+ [TASK_LOOSE_OBJECTS ].enabled = 1 ,
1670+ [TASK_LOOSE_OBJECTS ].schedule = SCHEDULE_DAILY ,
1671+ [TASK_PACK_REFS ].enabled = 1 ,
1672+ [TASK_PACK_REFS ].schedule = SCHEDULE_WEEKLY ,
1673+ },
1674+ };
1675+
1676+ static void initialize_task_config (struct maintenance_run_opts * opts ,
1677+ const struct string_list * selected_tasks )
16721678{
1679+ struct strbuf config_name = STRBUF_INIT ;
1680+ struct maintenance_strategy strategy ;
16731681 const char * config_str ;
16741682
1675- if (git_config_get_string_tmp ("maintenance.strategy" , & config_str ))
1676- return ;
1683+ /*
1684+ * In case the user has asked us to run tasks explicitly we only use
1685+ * those specified tasks. Specifically, we do _not_ want to consult the
1686+ * config or maintenance strategy.
1687+ */
1688+ if (selected_tasks -> nr ) {
1689+ for (size_t i = 0 ; i < selected_tasks -> nr ; i ++ ) {
1690+ enum maintenance_task_label label = (intptr_t )selected_tasks -> items [i ].util ;;
1691+ ALLOC_GROW (opts -> tasks , opts -> tasks_nr + 1 , opts -> tasks_alloc );
1692+ opts -> tasks [opts -> tasks_nr ++ ] = label ;
1693+ }
16771694
1678- if (!strcasecmp (config_str , "incremental" )) {
1679- tasks [TASK_GC ].schedule = SCHEDULE_NONE ;
1680- tasks [TASK_COMMIT_GRAPH ].enabled = 1 ;
1681- tasks [TASK_COMMIT_GRAPH ].schedule = SCHEDULE_HOURLY ;
1682- tasks [TASK_PREFETCH ].enabled = 1 ;
1683- tasks [TASK_PREFETCH ].schedule = SCHEDULE_HOURLY ;
1684- tasks [TASK_INCREMENTAL_REPACK ].enabled = 1 ;
1685- tasks [TASK_INCREMENTAL_REPACK ].schedule = SCHEDULE_DAILY ;
1686- tasks [TASK_LOOSE_OBJECTS ].enabled = 1 ;
1687- tasks [TASK_LOOSE_OBJECTS ].schedule = SCHEDULE_DAILY ;
1688- tasks [TASK_PACK_REFS ].enabled = 1 ;
1689- tasks [TASK_PACK_REFS ].schedule = SCHEDULE_WEEKLY ;
1695+ return ;
16901696 }
1691- }
16921697
1693- static void initialize_task_config (const struct string_list * selected_tasks ,
1694- int schedule )
1695- {
1696- struct strbuf config_name = STRBUF_INIT ;
1698+ /*
1699+ * Otherwise, the strategy depends on whether we run as part of a
1700+ * scheduled job or not:
1701+ *
1702+ * - Scheduled maintenance does not perform any housekeeping by
1703+ * default, but requires the user to pick a maintenance strategy.
1704+ *
1705+ * - Unscheduled maintenance uses our default strategy.
1706+ *
1707+ * Both of these are affected by the gitconfig though, which may
1708+ * override specific aspects of our strategy.
1709+ */
1710+ if (opts -> schedule ) {
1711+ strategy = none_strategy ;
16971712
1698- for (size_t i = 0 ; i < TASK__COUNT ; i ++ )
1699- tasks [i ].selected_order = -1 ;
1700- for (size_t i = 0 ; i < selected_tasks -> nr ; i ++ ) {
1701- struct maintenance_task * task = selected_tasks -> items [i ].util ;
1702- task -> selected_order = i ;
1713+ if (!git_config_get_string_tmp ("maintenance.strategy" , & config_str )) {
1714+ if (!strcasecmp (config_str , "incremental" ))
1715+ strategy = incremental_strategy ;
1716+ }
1717+ } else {
1718+ strategy = default_strategy ;
17031719 }
17041720
1705- if (schedule )
1706- initialize_maintenance_strategy ();
1707-
17081721 for (size_t i = 0 ; i < TASK__COUNT ; i ++ ) {
17091722 int config_value ;
1710- char * config_str ;
17111723
17121724 strbuf_reset (& config_name );
17131725 strbuf_addf (& config_name , "maintenance.%s.enabled" ,
17141726 tasks [i ].name );
1715-
17161727 if (!git_config_get_bool (config_name .buf , & config_value ))
1717- tasks [i ].enabled = config_value ;
1718-
1719- strbuf_reset (& config_name );
1720- strbuf_addf (& config_name , "maintenance.%s.schedule" ,
1721- tasks [i ].name );
1728+ strategy .tasks [i ].enabled = config_value ;
1729+ if (!strategy .tasks [i ].enabled )
1730+ continue ;
17221731
1723- if (!git_config_get_string (config_name .buf , & config_str )) {
1724- tasks [i ].schedule = parse_schedule (config_str );
1725- free (config_str );
1732+ if (opts -> schedule ) {
1733+ strbuf_reset (& config_name );
1734+ strbuf_addf (& config_name , "maintenance.%s.schedule" ,
1735+ tasks [i ].name );
1736+ if (!git_config_get_string_tmp (config_name .buf , & config_str ))
1737+ strategy .tasks [i ].schedule = parse_schedule (config_str );
1738+ if (strategy .tasks [i ].schedule < opts -> schedule )
1739+ continue ;
17261740 }
1741+
1742+ ALLOC_GROW (opts -> tasks , opts -> tasks_nr + 1 , opts -> tasks_alloc );
1743+ opts -> tasks [opts -> tasks_nr ++ ] = i ;
17271744 }
17281745
17291746 strbuf_release (& config_name );
@@ -1750,7 +1767,7 @@ static int task_option_parse(const struct option *opt,
17501767 return 1 ;
17511768 }
17521769
1753- string_list_append (selected_tasks , arg )-> util = & tasks [ i ] ;
1770+ string_list_append (selected_tasks , arg )-> util = ( void * )( intptr_t ) i ;
17541771
17551772 return 0 ;
17561773}
@@ -1791,7 +1808,7 @@ static int maintenance_run(int argc, const char **argv, const char *prefix,
17911808 opts .schedule , "--schedule=" );
17921809
17931810 gc_config (& cfg );
1794- initialize_task_config (& selected_tasks , opts . schedule );
1811+ initialize_task_config (& opts , & selected_tasks );
17951812
17961813 if (argc != 0 )
17971814 usage_with_options (builtin_maintenance_run_usage ,
@@ -1800,6 +1817,7 @@ static int maintenance_run(int argc, const char **argv, const char *prefix,
18001817 ret = maintenance_run_tasks (& opts , & cfg );
18011818
18021819 string_list_clear (& selected_tasks , 0 );
1820+ maintenance_run_opts_release (& opts );
18031821 gc_config_release (& cfg );
18041822 return ret ;
18051823}
0 commit comments