diff --git a/builtin/gc.c b/builtin/gc.c index 5d445edaa0..17490106fc 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -593,7 +593,39 @@ static int keep_one_pack(struct string_list_item *item, void *data) return 0; } -static void add_repack_all_option(struct gc_config *cfg, +enum odb_optimize_flags { + /* Enable verbose logging and progress reporting. */ + ODB_OPTIMIZE_VERBOSE = (1 << 0), + + /* Perform auto-maintenance, only optimizing objects as required. */ + ODB_OPTIMIZE_AUTO = (1 << 1), + + /* Recompute existing deltas. */ + ODB_OPTIMIZE_NO_REUSE_DELTAS = (1 << 2), +}; + +struct odb_optimize_options { + enum odb_optimize_flags flags; + const char *prune_expire; + const char *expire_to; + int depth; + int window; + + /* Backend-specific options. */ + int keep_largest_pack; + int cruft_packs; + unsigned long max_cruft_size; +}; + +#define OPTIMIZE_FIELDS_FROM_GC_CONFIG(cfg, aggressive) \ + .prune_expire = (cfg)->prune_expire, \ + .expire_to = (cfg)->repack_expire_to, \ + .cruft_packs = (cfg)->cruft_packs, \ + .max_cruft_size = (cfg)->max_cruft_size, \ + .window = (aggressive) ? (cfg)->aggressive_window : 0, \ + .depth = (aggressive) ? (cfg)->aggressive_depth : 0 + +static void add_repack_all_option(const struct odb_optimize_options *opts, struct string_list *keep_pack, struct strvec *args) { @@ -603,22 +635,22 @@ static void add_repack_all_option(struct gc_config *cfg, repo_config_get_string(the_repository, "gc.repackfilter", &repack_filter); repo_config_get_string(the_repository, "gc.repackfilterto", &repack_filter_to); - if (cfg->prune_expire && !strcmp(cfg->prune_expire, "now") - && !(cfg->cruft_packs && cfg->repack_expire_to)) + if (opts->prune_expire && !strcmp(opts->prune_expire, "now") && + !(opts->cruft_packs && opts->expire_to)) strvec_push(args, "-a"); - else if (cfg->cruft_packs) { + else if (opts->cruft_packs) { strvec_push(args, "--cruft"); - if (cfg->prune_expire) - strvec_pushf(args, "--cruft-expiration=%s", cfg->prune_expire); - if (cfg->max_cruft_size) + if (opts->prune_expire) + strvec_pushf(args, "--cruft-expiration=%s", opts->prune_expire); + if (opts->max_cruft_size) strvec_pushf(args, "--max-cruft-size=%lu", - cfg->max_cruft_size); - if (cfg->repack_expire_to) - strvec_pushf(args, "--expire-to=%s", cfg->repack_expire_to); + opts->max_cruft_size); + if (opts->expire_to) + strvec_pushf(args, "--expire-to=%s", opts->expire_to); } else { strvec_push(args, "-A"); - if (cfg->prune_expire) - strvec_pushf(args, "--unpack-unreachable=%s", cfg->prune_expire); + if (opts->prune_expire) + strvec_pushf(args, "--unpack-unreachable=%s", opts->prune_expire); } if (keep_pack) @@ -786,10 +818,8 @@ static int gc_foreground_tasks(struct maintenance_run_opts *opts, return 0; } -static int maintenance_task_odb(struct maintenance_run_opts *opts, - struct gc_config *cfg, - int keep_largest_pack, - int aggressive) +static int odb_optimize(struct object_database *odb, + const struct odb_optimize_options *opts) { struct child_process repack_cmd = CHILD_PROCESS_INIT; unsigned long big_pack_threshold = 0; @@ -801,21 +831,20 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts, repo_config_get_int(the_repository, "gc.autopacklimit", &gc_auto_pack_limit); repo_config_get_ulong(the_repository, "gc.bigpackthreshold", &big_pack_threshold); - if (the_repository->repository_format_precious_objects) + if (odb->repo->repository_format_precious_objects) return 0; repack_cmd.git_cmd = 1; repack_cmd.odb_to_close = the_repository->objects; strvec_pushl(&repack_cmd.args, "repack", "-d", "-l", NULL); - if (aggressive) { + if (opts->flags & ODB_OPTIMIZE_NO_REUSE_DELTAS) strvec_push(&repack_cmd.args, "-f"); - if (cfg->aggressive_depth > 0) - strvec_pushf(&repack_cmd.args, "--depth=%d", cfg->aggressive_depth); - if (cfg->aggressive_window > 0) - strvec_pushf(&repack_cmd.args, "--window=%d", cfg->aggressive_window); - } - if (opts->quiet) + if (opts->depth > 0) + strvec_pushf(&repack_cmd.args, "--depth=%d", opts->depth); + if (opts->window > 0) + strvec_pushf(&repack_cmd.args, "--window=%d", opts->window); + if (!(opts->flags & ODB_OPTIMIZE_VERBOSE)) strvec_push(&repack_cmd.args, "-q"); /* @@ -829,47 +858,49 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts, * * - Otherwise we perform an incremental repack. */ - if (!opts->auto_flag) { + if (!(opts->flags & ODB_OPTIMIZE_AUTO)) { struct string_list keep_pack = STRING_LIST_INIT_NODUP; - if (keep_largest_pack != -1) { - if (keep_largest_pack) + if (opts->keep_largest_pack != -1) { + if (opts->keep_largest_pack) find_base_packs(&keep_pack, 0); } else if (big_pack_threshold) { find_base_packs(&keep_pack, big_pack_threshold); } - add_repack_all_option(cfg, &keep_pack, &repack_cmd.args); - string_list_clear(&keep_pack, 0); - } else if (too_many_packs(gc_auto_pack_limit)) { - struct string_list keep_pack = STRING_LIST_INIT_NODUP; - - if (big_pack_threshold) { - find_base_packs(&keep_pack, big_pack_threshold); - if (keep_pack.nr >= gc_auto_pack_limit) { - string_list_clear(&keep_pack, 0); - find_base_packs(&keep_pack, 0); - } - } else { - struct packed_git *p = find_base_packs(&keep_pack, 0); - uint64_t mem_have, mem_want; - - mem_have = total_ram(); - mem_want = estimate_repack_memory(p); - - /* - * Only allow 1/2 of memory for pack-objects, leave - * the rest for the OS and other processes in the - * system. - */ - if (!mem_have || mem_want < mem_have / 2) - string_list_clear(&keep_pack, 0); - } - - add_repack_all_option(cfg, &keep_pack, &repack_cmd.args); + add_repack_all_option(opts, &keep_pack, &repack_cmd.args); string_list_clear(&keep_pack, 0); } else { - add_repack_incremental_option(&repack_cmd.args); + if (too_many_packs(gc_auto_pack_limit)) { + struct string_list keep_pack = STRING_LIST_INIT_NODUP; + + if (big_pack_threshold) { + find_base_packs(&keep_pack, big_pack_threshold); + if (keep_pack.nr >= gc_auto_pack_limit) { + string_list_clear(&keep_pack, 0); + find_base_packs(&keep_pack, 0); + } + } else { + struct packed_git *p = find_base_packs(&keep_pack, 0); + uint64_t mem_have, mem_want; + + mem_have = total_ram(); + mem_want = estimate_repack_memory(p); + + /* + * Only allow 1/2 of memory for pack-objects, leave + * the rest for the OS and other processes in the + * system. + */ + if (!mem_have || mem_want < mem_have / 2) + string_list_clear(&keep_pack, 0); + } + + add_repack_all_option(opts, &keep_pack, &repack_cmd.args); + string_list_clear(&keep_pack, 0); + } else { + add_repack_incremental_option(&repack_cmd.args); + } } if (run_command(&repack_cmd)) { @@ -877,13 +908,13 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts, goto out; } - if (cfg->prune_expire) { + if (opts->prune_expire) { struct child_process prune_cmd = CHILD_PROCESS_INIT; strvec_pushl(&prune_cmd.args, "prune", "--expire", NULL); /* run `git prune` even if using cruft packs */ - strvec_push(&prune_cmd.args, cfg->prune_expire); - if (opts->quiet) + strvec_push(&prune_cmd.args, opts->prune_expire); + if (!(opts->flags & ODB_OPTIMIZE_VERBOSE)) strvec_push(&prune_cmd.args, "--no-progress"); if (repo_has_promisor_remote(the_repository)) strvec_push(&prune_cmd.args, @@ -896,7 +927,7 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts, } } - if (opts->auto_flag && too_many_loose_objects(gc_auto_threshold)) + if (opts->flags & ODB_OPTIMIZE_AUTO && too_many_loose_objects(gc_auto_threshold)) warning(_("There are too many unreachable loose objects; " "run 'git prune' to remove them.")); @@ -906,6 +937,26 @@ out: return ret; } +static int maintenance_task_odb(struct maintenance_run_opts *opts, + struct gc_config *cfg, + int keep_largest_pack, + int aggressive) +{ + struct odb_optimize_options odb_opts = { + .keep_largest_pack = keep_largest_pack, + OPTIMIZE_FIELDS_FROM_GC_CONFIG(cfg, aggressive), + }; + + if (opts->auto_flag) + odb_opts.flags |= ODB_OPTIMIZE_AUTO; + if (!opts->quiet) + odb_opts.flags |= ODB_OPTIMIZE_VERBOSE; + if (aggressive) + odb_opts.flags |= ODB_OPTIMIZE_NO_REUSE_DELTAS; + + return odb_optimize(the_repository->objects, &odb_opts); +} + int cmd_gc(int argc, const char **argv, const char *prefix, @@ -1596,11 +1647,19 @@ static int maintenance_task_geometric_repack(struct maintenance_run_opts *opts, child.odb_to_close = the_repository->objects; strvec_pushl(&child.args, "repack", "-d", "-l", NULL); - if (geometry.split < geometry.pack_nr) + if (geometry.split < geometry.pack_nr) { strvec_pushf(&child.args, "--geometric=%d", geometry.split_factor); - else - add_repack_all_option(cfg, NULL, &child.args); + } else { + struct odb_optimize_options odb_opts = { + OPTIMIZE_FIELDS_FROM_GC_CONFIG(cfg, 0), + }; + + if (!opts->quiet) + odb_opts.flags |= ODB_OPTIMIZE_VERBOSE; + + add_repack_all_option(&odb_opts, NULL, &child.args); + } if (opts->quiet) strvec_push(&child.args, "--quiet"); if (the_repository->settings.core_multi_pack_index)