aboutsummaryrefslogtreecommitdiffstats
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/gc.c7
-rw-r--r--builtin/repack.c134
2 files changed, 130 insertions, 11 deletions
diff --git a/builtin/gc.c b/builtin/gc.c
index 00192ae5d3..c97c9fb046 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -52,6 +52,7 @@ static const char * const builtin_gc_usage[] = {
static int pack_refs = 1;
static int prune_reflogs = 1;
static int cruft_packs = 1;
+static unsigned long max_cruft_size;
static int aggressive_depth = 50;
static int aggressive_window = 250;
static int gc_auto_threshold = 6700;
@@ -163,6 +164,7 @@ static void gc_config(void)
git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
git_config_get_bool("gc.autodetach", &detach_auto);
git_config_get_bool("gc.cruftpacks", &cruft_packs);
+ git_config_get_ulong("gc.maxcruftsize", &max_cruft_size);
git_config_get_expiry("gc.pruneexpire", &prune_expire);
git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
git_config_get_expiry("gc.logexpiry", &gc_log_expire);
@@ -347,6 +349,9 @@ static void add_repack_all_option(struct string_list *keep_pack)
strvec_push(&repack, "--cruft");
if (prune_expire)
strvec_pushf(&repack, "--cruft-expiration=%s", prune_expire);
+ if (max_cruft_size)
+ strvec_pushf(&repack, "--max-cruft-size=%lu",
+ max_cruft_size);
} else {
strvec_push(&repack, "-A");
if (prune_expire)
@@ -575,6 +580,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
N_("prune unreferenced objects"),
PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
OPT_BOOL(0, "cruft", &cruft_packs, N_("pack unreferenced objects separately")),
+ OPT_MAGNITUDE(0, "max-cruft-size", &max_cruft_size,
+ N_("with --cruft, limit the size of new cruft packs")),
OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
OPT_BOOL_F(0, "auto", &auto_gc, N_("enable auto-gc mode"),
PARSE_OPT_NOCOMPLETE),
diff --git a/builtin/repack.c b/builtin/repack.c
index 8a5bbb9cba..04770b15fe 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -27,6 +27,7 @@
#define PACK_CRUFT 4
#define DELETE_PACK 1
+#define RETAIN_PACK 2
static int pack_everything;
static int delta_base_offset = 1;
@@ -116,11 +117,26 @@ static void pack_mark_for_deletion(struct string_list_item *item)
item->util = (void*)((uintptr_t)item->util | DELETE_PACK);
}
+static void pack_unmark_for_deletion(struct string_list_item *item)
+{
+ item->util = (void*)((uintptr_t)item->util & ~DELETE_PACK);
+}
+
static int pack_is_marked_for_deletion(struct string_list_item *item)
{
return (uintptr_t)item->util & DELETE_PACK;
}
+static void pack_mark_retained(struct string_list_item *item)
+{
+ item->util = (void*)((uintptr_t)item->util | RETAIN_PACK);
+}
+
+static int pack_is_retained(struct string_list_item *item)
+{
+ return (uintptr_t)item->util & RETAIN_PACK;
+}
+
static void mark_packs_for_deletion_1(struct string_list *names,
struct string_list *list)
{
@@ -133,17 +149,39 @@ static void mark_packs_for_deletion_1(struct string_list *names,
if (len < hexsz)
continue;
sha1 = item->string + len - hexsz;
- /*
- * Mark this pack for deletion, which ensures that this
- * pack won't be included in a MIDX (if `--write-midx`
- * was given) and that we will actually delete this pack
- * (if `-d` was given).
- */
- if (!string_list_has_string(names, sha1))
+
+ if (pack_is_retained(item)) {
+ pack_unmark_for_deletion(item);
+ } else if (!string_list_has_string(names, sha1)) {
+ /*
+ * Mark this pack for deletion, which ensures
+ * that this pack won't be included in a MIDX
+ * (if `--write-midx` was given) and that we
+ * will actually delete this pack (if `-d` was
+ * given).
+ */
pack_mark_for_deletion(item);
+ }
}
}
+static void retain_cruft_pack(struct existing_packs *existing,
+ struct packed_git *cruft)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct string_list_item *item;
+
+ strbuf_addstr(&buf, pack_basename(cruft));
+ strbuf_strip_suffix(&buf, ".pack");
+
+ item = string_list_lookup(&existing->cruft_packs, buf.buf);
+ if (!item)
+ BUG("could not find cruft pack '%s'", pack_basename(cruft));
+
+ pack_mark_retained(item);
+ strbuf_release(&buf);
+}
+
static void mark_packs_for_deletion(struct existing_packs *existing,
struct string_list *names)
@@ -225,6 +263,8 @@ static void collect_pack_filenames(struct existing_packs *existing,
}
string_list_sort(&existing->kept_packs);
+ string_list_sort(&existing->non_kept_packs);
+ string_list_sort(&existing->cruft_packs);
strbuf_release(&buf);
}
@@ -806,6 +846,72 @@ static void remove_redundant_bitmaps(struct string_list *include,
strbuf_release(&path);
}
+static int existing_cruft_pack_cmp(const void *va, const void *vb)
+{
+ struct packed_git *a = *(struct packed_git **)va;
+ struct packed_git *b = *(struct packed_git **)vb;
+
+ if (a->pack_size < b->pack_size)
+ return -1;
+ if (a->pack_size > b->pack_size)
+ return 1;
+ return 0;
+}
+
+static void collapse_small_cruft_packs(FILE *in, size_t max_size,
+ struct existing_packs *existing)
+{
+ struct packed_git **existing_cruft, *p;
+ struct strbuf buf = STRBUF_INIT;
+ size_t total_size = 0;
+ size_t existing_cruft_nr = 0;
+ size_t i;
+
+ ALLOC_ARRAY(existing_cruft, existing->cruft_packs.nr);
+
+ for (p = get_all_packs(the_repository); p; p = p->next) {
+ if (!(p->is_cruft && p->pack_local))
+ continue;
+
+ strbuf_reset(&buf);
+ strbuf_addstr(&buf, pack_basename(p));
+ strbuf_strip_suffix(&buf, ".pack");
+
+ if (!string_list_has_string(&existing->cruft_packs, buf.buf))
+ continue;
+
+ if (existing_cruft_nr >= existing->cruft_packs.nr)
+ BUG("too many cruft packs (found %"PRIuMAX", but knew "
+ "of %"PRIuMAX")",
+ (uintmax_t)existing_cruft_nr + 1,
+ (uintmax_t)existing->cruft_packs.nr);
+ existing_cruft[existing_cruft_nr++] = p;
+ }
+
+ QSORT(existing_cruft, existing_cruft_nr, existing_cruft_pack_cmp);
+
+ for (i = 0; i < existing_cruft_nr; i++) {
+ size_t proposed;
+
+ p = existing_cruft[i];
+ proposed = st_add(total_size, p->pack_size);
+
+ if (proposed <= max_size) {
+ total_size = proposed;
+ fprintf(in, "-%s\n", pack_basename(p));
+ } else {
+ retain_cruft_pack(existing, p);
+ fprintf(in, "%s\n", pack_basename(p));
+ }
+ }
+
+ for (i = 0; i < existing->non_kept_packs.nr; i++)
+ fprintf(in, "-%s.pack\n",
+ existing->non_kept_packs.items[i].string);
+
+ strbuf_release(&buf);
+}
+
static int write_cruft_pack(const struct pack_objects_args *args,
const char *destination,
const char *pack_prefix,
@@ -853,10 +959,14 @@ static int write_cruft_pack(const struct pack_objects_args *args,
in = xfdopen(cmd.in, "w");
for_each_string_list_item(item, names)
fprintf(in, "%s-%s.pack\n", pack_prefix, item->string);
- for_each_string_list_item(item, &existing->non_kept_packs)
- fprintf(in, "-%s.pack\n", item->string);
- for_each_string_list_item(item, &existing->cruft_packs)
- fprintf(in, "-%s.pack\n", item->string);
+ if (args->max_pack_size && !cruft_expiration) {
+ collapse_small_cruft_packs(in, args->max_pack_size, existing);
+ } else {
+ for_each_string_list_item(item, &existing->non_kept_packs)
+ fprintf(in, "-%s.pack\n", item->string);
+ for_each_string_list_item(item, &existing->cruft_packs)
+ fprintf(in, "-%s.pack\n", item->string);
+ }
for_each_string_list_item(item, &existing->kept_packs)
fprintf(in, "%s.pack\n", item->string);
fclose(in);
@@ -919,6 +1029,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
PACK_CRUFT),
OPT_STRING(0, "cruft-expiration", &cruft_expiration, N_("approxidate"),
N_("with --cruft, expire objects older than this")),
+ OPT_MAGNITUDE(0, "max-cruft-size", &cruft_po_args.max_pack_size,
+ N_("with --cruft, limit the size of new cruft packs")),
OPT_BOOL('d', NULL, &delete_redundant,
N_("remove redundant packs, and run git-prune-packed")),
OPT_BOOL('f', NULL, &po_args.no_reuse_delta,