git-gc --auto: run "repack -A -d -l" as necessary.
authorJunio C Hamano <gitster@pobox.com>
Mon, 17 Sep 2007 07:55:13 +0000 (00:55 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 18 Sep 2007 06:12:16 +0000 (23:12 -0700)
This teaches "git-gc --auto" to consolidate many packs into one
without losing unreachable objects in them by using "repack -A"
when there are too many packfiles that are not marked with *.keep
in the repository. gc.autopacklimit configuration can be used
to set the maximum number of packs a repository is allowed to
have before this mechanism kicks in.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/config.txt
Documentation/git-gc.txt
builtin-gc.c
index 6b6553d9da8f92813ed4a79e310d14d0cc8b690f..b0390f82b85b17287b9e90c5ea57839517c040cf 100644 (file)
@@ -446,6 +446,12 @@ gc.auto::
        light-weight garbage collection from time to time.  Setting
        this to 0 disables it.
 
        light-weight garbage collection from time to time.  Setting
        this to 0 disables it.
 
+gc.autopacklimit::
+       When there are more than this many packs that are not
+       marked with `*.keep` file in the repository, `git gc
+       --auto` consolidates them into one larger pack.  Setting
+       this to 0 disables this.
+
 gc.packrefs::
        `git gc` does not run `git pack-refs` in a bare repository by
        default so that older dumb-transport clients can still fetch
 gc.packrefs::
        `git gc` does not run `git pack-refs` in a bare repository by
        default so that older dumb-transport clients can still fetch
index 40c1ce4a21302b315c8f88802645ce0161a0c47c..b9d5660eacee03bde2360b97b80f3378972fe678 100644 (file)
@@ -47,10 +47,15 @@ OPTIONS
        With this option, `git gc` checks if there are too many
        loose objects in the repository and runs
        gitlink:git-repack[1] with `-d -l` option to pack them.
        With this option, `git gc` checks if there are too many
        loose objects in the repository and runs
        gitlink:git-repack[1] with `-d -l` option to pack them.
-       The threshold is set with `gc.auto` configuration
+       The threshold for loose objects is set with `gc.auto` configuration
        variable, and can be disabled by setting it to 0.  Some
        Porcelain commands use this after they perform operation
        that could create many loose objects automatically.
        variable, and can be disabled by setting it to 0.  Some
        Porcelain commands use this after they perform operation
        that could create many loose objects automatically.
+       Additionally, when there are too many packs are present,
+       they are consolidated into one larger pack by running
+       the `git-repack` command with `-A` option.  The
+       threshold for number of packs is set with
+       `gc.autopacklimit` configuration variable.
 
 Configuration
 -------------
 
 Configuration
 -------------
index 34ce35befb53397cab0edd0960b6a5df872f32e9..23ad2b6a21a81f469e813173ba04d626949e972f 100644 (file)
@@ -21,6 +21,7 @@ static const char builtin_gc_usage[] = "git-gc [--prune] [--aggressive]";
 static int pack_refs = 1;
 static int aggressive_window = -1;
 static int gc_auto_threshold = 6700;
 static int pack_refs = 1;
 static int aggressive_window = -1;
 static int gc_auto_threshold = 6700;
+static int gc_auto_pack_limit = 20;
 
 #define MAX_ADD 10
 static const char *argv_pack_refs[] = {"pack-refs", "--all", "--prune", NULL};
 
 #define MAX_ADD 10
 static const char *argv_pack_refs[] = {"pack-refs", "--all", "--prune", NULL};
@@ -46,6 +47,10 @@ static int gc_config(const char *var, const char *value)
                gc_auto_threshold = git_config_int(var, value);
                return 0;
        }
                gc_auto_threshold = git_config_int(var, value);
                return 0;
        }
+       if (!strcmp(var, "gc.autopacklimit")) {
+               gc_auto_pack_limit = git_config_int(var, value);
+               return 0;
+       }
        return git_default_config(var, value);
 }
 
        return git_default_config(var, value);
 }
 
@@ -78,6 +83,9 @@ static int too_many_loose_objects(void)
        int num_loose = 0;
        int needed = 0;
 
        int num_loose = 0;
        int needed = 0;
 
+       if (gc_auto_threshold <= 0)
+               return 0;
+
        if (sizeof(path) <= snprintf(path, sizeof(path), "%s/17", objdir)) {
                warning("insanely long object directory %.*s", 50, objdir);
                return 0;
        if (sizeof(path) <= snprintf(path, sizeof(path), "%s/17", objdir)) {
                warning("insanely long object directory %.*s", 50, objdir);
                return 0;
@@ -100,21 +108,61 @@ static int too_many_loose_objects(void)
        return needed;
 }
 
        return needed;
 }
 
+static int too_many_packs(void)
+{
+       struct packed_git *p;
+       int cnt;
+
+       if (gc_auto_pack_limit <= 0)
+               return 0;
+
+       prepare_packed_git();
+       for (cnt = 0, p = packed_git; p; p = p->next) {
+               char path[PATH_MAX];
+               size_t len;
+               int keep;
+
+               if (!p->pack_local)
+                       continue;
+               len = strlen(p->pack_name);
+               if (PATH_MAX <= len + 1)
+                       continue; /* oops, give up */
+               memcpy(path, p->pack_name, len-5);
+               memcpy(path + len - 5, ".keep", 6);
+               keep = access(p->pack_name, F_OK) && (errno == ENOENT);
+               if (keep)
+                       continue;
+               /*
+                * Perhaps check the size of the pack and count only
+                * very small ones here?
+                */
+               cnt++;
+       }
+       return gc_auto_pack_limit <= cnt;
+}
+
 static int need_to_gc(void)
 {
        int ac = 0;
 
        /*
 static int need_to_gc(void)
 {
        int ac = 0;
 
        /*
-        * Setting gc.auto to 0 or negative can disable the
-        * automatic gc
+        * Setting gc.auto and gc.autopacklimit to 0 or negative can
+        * disable the automatic gc.
         */
         */
-       if (gc_auto_threshold <= 0)
-               return 0;
-
-       if (!too_many_loose_objects())
+       if (gc_auto_threshold <= 0 && gc_auto_pack_limit <= 0)
                return 0;
 
                return 0;
 
+       /*
+        * If there are too many loose objects, but not too many
+        * packs, we run "repack -d -l".  If there are too many packs,
+        * we run "repack -A -d -l".  Otherwise we tell the caller
+        * there is no need.
+        */
        argv_repack[ac++] = "repack";
        argv_repack[ac++] = "repack";
+       if (too_many_packs())
+               argv_repack[ac++] = "-A";
+       else if (!too_many_loose_objects())
+               return 0;
        argv_repack[ac++] = "-d";
        argv_repack[ac++] = "-l";
        argv_repack[ac++] = NULL;
        argv_repack[ac++] = "-d";
        argv_repack[ac++] = "-l";
        argv_repack[ac++] = NULL;