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.
 
+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
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.
-       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.
+       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
 -------------
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 gc_auto_pack_limit = 20;
 
 #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;
        }
+       if (!strcmp(var, "gc.autopacklimit")) {
+               gc_auto_pack_limit = git_config_int(var, value);
+               return 0;
+       }
        return git_default_config(var, value);
 }
 
@@ -78,6 +83,9 @@ static int too_many_loose_objects(void)
        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;
@@ -100,21 +108,61 @@ static int too_many_loose_objects(void)
        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;
 
        /*
-        * 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;
 
+       /*
+        * 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";
+       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;