summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2018-04-15 15:36:14 (GMT)
committerJunio C Hamano <gitster@pobox.com>2018-04-16 04:52:29 (GMT)
commitae4e89e549b76b561a1c384dd7314c9b671c22bc (patch)
tree60df0a8ae7e4eaa21e2f9c815bc7fd96cb1d6efa /builtin
parented7e5fc3a2562e3d4fb4fe25e8dca0e9daa0ed13 (diff)
downloadgit-ae4e89e549b76b561a1c384dd7314c9b671c22bc.zip
git-ae4e89e549b76b561a1c384dd7314c9b671c22bc.tar.gz
git-ae4e89e549b76b561a1c384dd7314c9b671c22bc.tar.bz2
gc: add --keep-largest-pack option
This adds a new repack mode that combines everything into a secondary pack, leaving the largest pack alone. This could help reduce memory pressure. On linux-2.6.git, valgrind massif reports 1.6GB heap in "pack all" case, and 535MB in "pack all except the base pack" case. We save roughly 1GB memory by excluding the base pack. This should also lower I/O because we don't have to rewrite a giant pack every time (e.g. for linux-2.6.git that's a 1.4GB pack file).. PS. The use of string_list here seems overkill, but we'll need it in the next patch... Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'builtin')
-rw-r--r--builtin/gc.c45
1 files changed, 41 insertions, 4 deletions
diff --git a/builtin/gc.c b/builtin/gc.c
index 3e67124..f251662 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -166,6 +166,22 @@ static int too_many_loose_objects(void)
return needed;
}
+static void find_base_packs(struct string_list *packs)
+{
+ struct packed_git *p, *base = NULL;
+
+ for (p = get_packed_git(the_repository); p; p = p->next) {
+ if (!p->pack_local)
+ continue;
+ if (!base || base->pack_size < p->pack_size) {
+ base = p;
+ }
+ }
+
+ if (base)
+ string_list_append(packs, base->pack_name);
+}
+
static int too_many_packs(void)
{
struct packed_git *p;
@@ -188,7 +204,13 @@ static int too_many_packs(void)
return gc_auto_pack_limit < cnt;
}
-static void add_repack_all_option(void)
+static int keep_one_pack(struct string_list_item *item, void *data)
+{
+ argv_array_pushf(&repack, "--keep-pack=%s", basename(item->string));
+ return 0;
+}
+
+static void add_repack_all_option(struct string_list *keep_pack)
{
if (prune_expire && !strcmp(prune_expire, "now"))
argv_array_push(&repack, "-a");
@@ -197,6 +219,9 @@ static void add_repack_all_option(void)
if (prune_expire)
argv_array_pushf(&repack, "--unpack-unreachable=%s", prune_expire);
}
+
+ if (keep_pack)
+ for_each_string_list(keep_pack, keep_one_pack, NULL);
}
static void add_repack_incremental_option(void)
@@ -220,7 +245,7 @@ static int need_to_gc(void)
* there is no need.
*/
if (too_many_packs())
- add_repack_all_option();
+ add_repack_all_option(NULL);
else if (too_many_loose_objects())
add_repack_incremental_option();
else
@@ -354,6 +379,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
const char *name;
pid_t pid;
int daemonized = 0;
+ int keep_base_pack = -1;
struct option builtin_gc_options[] = {
OPT__QUIET(&quiet, N_("suppress progress reporting")),
@@ -366,6 +392,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
OPT_BOOL_F(0, "force", &force,
N_("force running gc even if there may be another gc running"),
PARSE_OPT_NOCOMPLETE),
+ OPT_BOOL(0, "keep-largest-pack", &keep_base_pack,
+ N_("repack all other packs except the largest pack")),
OPT_END()
};
@@ -431,8 +459,17 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
*/
daemonized = !daemonize();
}
- } else
- add_repack_all_option();
+ } else {
+ struct string_list keep_pack = STRING_LIST_INIT_NODUP;
+
+ if (keep_base_pack != -1) {
+ if (keep_base_pack)
+ find_base_packs(&keep_pack);
+ }
+
+ add_repack_all_option(&keep_pack);
+ string_list_clear(&keep_pack, 0);
+ }
name = lock_repo_for_gc(force, &pid);
if (name) {