git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCHv2 0/5] Speed up repacking when lots of pack-kept objects
@ 2019-03-16 20:05 Nathaniel Filardo
  2019-03-16 20:05 ` [PATCHv2 1/5] count-objects: report statistics about kept packs Nathaniel Filardo
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Nathaniel Filardo @ 2019-03-16 20:05 UTC (permalink / raw)
  To: git; +Cc: Derrick Stolee, Nathaniel Filardo

This patch series improves handling of very large repositories, as generated
by, for example, bup (https://github.com/bup/bup).  Prolonged operation
thereof creates quite a lot of small pack files; repacking improves
filesystem performance of the objects/pack directory, but is quite
expensive, in terms of time and memory.  We have adopted a strategy that
marks "large" (tens of GB) of pack files as "kept" and defers repacking
until there are enough un-kept packs or enough bytes of un-kept objects.
(The first patch in the series will make our accounting easier, replacing
some terrible shell scripting with grep.)

While this strategy has generally improved our lives relative to either
extreme (not repacking, or repacking after every bup save operation), it
still leaves a good bit to be desired.  Because our packs are marked as
kept, repacking will leave the objects therein alone, but it still must
instantiate in memory and walk the entire object graph.  However, because
our kept packs are transitively closed, such that an object in one
necessarily references only objects in other kept packs, we should like to
avoid reasoning about them more or less altogether.

This series attempts to do just that.  The middle patches are just some
groundwork for the last patch, which carries the punch line.  This last
patch adds an option to builtin/repack to enumerate commits (and their
trees) within kept packs as UNINTERESTING to its spawned
builtin/pack-objects command.  Together with inducing the use of sparse
reachability, this speeds enumerating candidate objects for repacking and
thereby substantially reduces the runtime of our repack operations, while
producing identical results.  Some test results are reported in the commit
log for the central change.

Take two incorporates feedback from Derrick Stolee.

Nathaniel Filardo (5):
  count-objects: report statistics about kept packs
  revision walk: optionally use sparse reachability
  repack: add --sparse and pass to pack-objects
  repack: optionally assume transitive kept packs
  builtin/gc: add --assume-pack-keep-transitive

 Documentation/git-count-objects.txt |  8 ++++
 Documentation/git-gc.txt            |  5 +++
 Documentation/git-repack.txt        | 25 ++++++++++++
 bisect.c                            |  2 +-
 builtin/count-objects.c             | 17 +++++++-
 builtin/gc.c                        |  5 +++
 builtin/pack-objects.c              |  3 +-
 builtin/repack.c                    | 60 ++++++++++++++++++++++++++++-
 builtin/rev-list.c                  |  2 +-
 http-push.c                         |  2 +-
 list-objects.c                      |  5 +--
 list-objects.h                      |  3 +-
 revision.c                          |  3 +-
 revision.h                          |  1 +
 t/t5322-pack-objects-sparse.sh      |  6 +++
 15 files changed, 134 insertions(+), 13 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCHv2 1/5] count-objects: report statistics about kept packs
  2019-03-16 20:05 [PATCHv2 0/5] Speed up repacking when lots of pack-kept objects Nathaniel Filardo
@ 2019-03-16 20:05 ` Nathaniel Filardo
  2019-03-16 20:05 ` [PATCHv2 2/5] revision walk: optionally use sparse reachability Nathaniel Filardo
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Nathaniel Filardo @ 2019-03-16 20:05 UTC (permalink / raw)
  To: git; +Cc: Derrick Stolee, Nathaniel Filardo

Specifically: number of kept packs, size of kept packs (and indexes),
and number of objects in kept packs.

Add documentation of resulting fields.  While here, correct the omission
from ae72f68541 ("count-objects -v: show number of packs as well.",
2006-12-27) of the "packs" field.

Signed-off-by: Nathaniel Filardo <nwf20@cl.cam.ac.uk>
---
 Documentation/git-count-objects.txt |  8 ++++++++
 builtin/count-objects.c             | 17 +++++++++++++++--
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-count-objects.txt b/Documentation/git-count-objects.txt
index cb9b4d2e46..8d88f87856 100644
--- a/Documentation/git-count-objects.txt
+++ b/Documentation/git-count-objects.txt
@@ -26,10 +26,18 @@ count: the number of loose objects
 +
 size: disk space consumed by loose objects, in KiB (unless -H is specified)
 +
+packs: the number of pack files
++
+packs-keep: the number of pack files marked kept
++
 in-pack: the number of in-pack objects
 +
+in-pack-keep: the number of objects in packs marked kept
++
 size-pack: disk space consumed by the packs, in KiB (unless -H is specified)
 +
+size-pack-keep: disk space consumed by kept packs, in KiB (unless -H is specified)
++
 prune-packable: the number of loose objects that are also present in
 the packs. These objects could be pruned using `git prune-packed`.
 +
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index 3fae474f6f..0309c7907f 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -117,17 +117,24 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
 
 	if (verbose) {
 		struct packed_git *p;
-		unsigned long num_pack = 0;
-		off_t size_pack = 0;
+		unsigned long num_pack = 0, num_pack_keep = 0;
+		unsigned long packed_keep = 0;
+		off_t size_pack = 0, size_pack_keep = 0;
 		struct strbuf loose_buf = STRBUF_INIT;
 		struct strbuf pack_buf = STRBUF_INIT;
 		struct strbuf garbage_buf = STRBUF_INIT;
+		struct strbuf pack_keep_buf = STRBUF_INIT;
 
 		for (p = get_all_packs(the_repository); p; p = p->next) {
 			if (!p->pack_local)
 				continue;
 			if (open_pack_index(p))
 				continue;
+			if (p->pack_keep || p->pack_keep_in_core) {
+				packed_keep += p->num_objects;
+				size_pack_keep += p->pack_size + p->index_size;
+				num_pack_keep++;
+			}
 			packed += p->num_objects;
 			size_pack += p->pack_size + p->index_size;
 			num_pack++;
@@ -136,12 +143,15 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
 		if (human_readable) {
 			strbuf_humanise_bytes(&loose_buf, loose_size);
 			strbuf_humanise_bytes(&pack_buf, size_pack);
+			strbuf_humanise_bytes(&pack_keep_buf, size_pack_keep);
 			strbuf_humanise_bytes(&garbage_buf, size_garbage);
 		} else {
 			strbuf_addf(&loose_buf, "%lu",
 				    (unsigned long)(loose_size / 1024));
 			strbuf_addf(&pack_buf, "%lu",
 				    (unsigned long)(size_pack / 1024));
+			strbuf_addf(&pack_keep_buf, "%lu",
+				    (unsigned long)(size_pack_keep / 1024));
 			strbuf_addf(&garbage_buf, "%lu",
 				    (unsigned long)(size_garbage / 1024));
 		}
@@ -149,8 +159,11 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
 		printf("count: %lu\n", loose);
 		printf("size: %s\n", loose_buf.buf);
 		printf("in-pack: %lu\n", packed);
+		printf("in-pack-keep: %lu\n", packed_keep);
 		printf("packs: %lu\n", num_pack);
+		printf("packs-keep: %lu\n", num_pack_keep);
 		printf("size-pack: %s\n", pack_buf.buf);
+		printf("size-pack-keep: %s\n", pack_keep_buf.buf);
 		printf("prune-packable: %lu\n", packed_loose);
 		printf("garbage: %lu\n", garbage);
 		printf("size-garbage: %s\n", garbage_buf.buf);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCHv2 2/5] revision walk: optionally use sparse reachability
  2019-03-16 20:05 [PATCHv2 0/5] Speed up repacking when lots of pack-kept objects Nathaniel Filardo
  2019-03-16 20:05 ` [PATCHv2 1/5] count-objects: report statistics about kept packs Nathaniel Filardo
@ 2019-03-16 20:05 ` Nathaniel Filardo
  2019-03-16 20:05 ` [PATCHv2 3/5] repack: add --sparse and pass to pack-objects Nathaniel Filardo
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Nathaniel Filardo @ 2019-03-16 20:05 UTC (permalink / raw)
  To: git; +Cc: Derrick Stolee, Nathaniel Filardo

Add another bit flag to the struct rev_info.

The only caller that uses this after this patch is builtin/pack-objects.
Without this, sparsity seems to do little good therein, as
prepare_revision_walk will densely propagate UNINTERESTING flags from
trees to tree contents, before mark_edges_uninteresting has a chance to
be faster by being sparse.

While here, drop the "sparse" parameter to mark_edges_uninteresting,
introduced in 4f6d26b167 ("list-objects: consume sparse tree walk",
2019-01-16) which can now use the flag in struct rev_info.  No
functional change intended.

Signed-off-by: Nathaniel Filardo <nwf20@cl.cam.ac.uk>
---
 bisect.c               | 2 +-
 builtin/pack-objects.c | 3 ++-
 builtin/rev-list.c     | 2 +-
 http-push.c            | 2 +-
 list-objects.c         | 5 ++---
 list-objects.h         | 3 +--
 revision.c             | 3 ++-
 revision.h             | 1 +
 8 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/bisect.c b/bisect.c
index 3af955c4bc..6bf521138a 100644
--- a/bisect.c
+++ b/bisect.c
@@ -658,7 +658,7 @@ static void bisect_common(struct rev_info *revs)
 	if (prepare_revision_walk(revs))
 		die("revision walk setup failed");
 	if (revs->tree_objects)
-		mark_edges_uninteresting(revs, NULL, 0);
+		mark_edges_uninteresting(revs, NULL);
 }
 
 static void exit_if_skipped_commits(struct commit_list *tried,
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index a154fc29f6..fb9937edf9 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -3134,9 +3134,10 @@ static void get_object_list(int ac, const char **av)
 	if (use_delta_islands)
 		load_delta_islands(the_repository);
 
+	revs.sparse_tree_walk = !!sparse;
 	if (prepare_revision_walk(&revs))
 		die(_("revision walk setup failed"));
-	mark_edges_uninteresting(&revs, show_edge, sparse);
+	mark_edges_uninteresting(&revs, show_edge);
 
 	if (!fn_show_object)
 		fn_show_object = show_object;
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 5b5b6dbb1c..14ef659c12 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -546,7 +546,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
 	if (prepare_revision_walk(&revs))
 		die("revision walk setup failed");
 	if (revs.tree_objects)
-		mark_edges_uninteresting(&revs, show_edge, 0);
+		mark_edges_uninteresting(&revs, show_edge);
 
 	if (bisect_list) {
 		int reaches, all;
diff --git a/http-push.c b/http-push.c
index b22c7caea0..39b6f5bafb 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1933,7 +1933,7 @@ int cmd_main(int argc, const char **argv)
 		pushing = 0;
 		if (prepare_revision_walk(&revs))
 			die("revision walk setup failed");
-		mark_edges_uninteresting(&revs, NULL, 0);
+		mark_edges_uninteresting(&revs, NULL);
 		objects_to_send = get_delta(&revs, ref_lock);
 		finish_all_active_slots();
 
diff --git a/list-objects.c b/list-objects.c
index dc77361e11..7ea108fba8 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -254,13 +254,12 @@ static void add_edge_parents(struct commit *commit,
 }
 
 void mark_edges_uninteresting(struct rev_info *revs,
-			      show_edge_fn show_edge,
-			      int sparse)
+			      show_edge_fn show_edge)
 {
 	struct commit_list *list;
 	int i;
 
-	if (sparse) {
+	if (revs->sparse_tree_walk) {
 		struct oidset set;
 		oidset_init(&set, 16);
 
diff --git a/list-objects.h b/list-objects.h
index a952680e46..9388d96785 100644
--- a/list-objects.h
+++ b/list-objects.h
@@ -11,8 +11,7 @@ void traverse_commit_list(struct rev_info *, show_commit_fn, show_object_fn, voi
 
 typedef void (*show_edge_fn)(struct commit *);
 void mark_edges_uninteresting(struct rev_info *revs,
-			      show_edge_fn show_edge,
-			      int sparse);
+			      show_edge_fn show_edge);
 
 struct oidset;
 struct list_objects_filter_options;
diff --git a/revision.c b/revision.c
index eb8e51bc63..1f43f6f2da 100644
--- a/revision.c
+++ b/revision.c
@@ -456,7 +456,8 @@ static struct commit *handle_commit(struct rev_info *revs,
 		if (!revs->tree_objects)
 			return NULL;
 		if (flags & UNINTERESTING) {
-			mark_tree_contents_uninteresting(revs->repo, tree);
+			if (!revs->sparse_tree_walk)
+				mark_tree_contents_uninteresting(revs->repo, tree);
 			return NULL;
 		}
 		add_pending_object_with_path(revs, object, name, mode, path);
diff --git a/revision.h b/revision.h
index 4134dc6029..a7154566b3 100644
--- a/revision.h
+++ b/revision.h
@@ -145,6 +145,7 @@ struct rev_info {
 			first_parent_only:1,
 			line_level_traverse:1,
 			tree_blobs_in_commit_order:1,
+			sparse_tree_walk:1,
 
 			/*
 			 * Blobs are shown without regard for their existence.
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCHv2 3/5] repack: add --sparse and pass to pack-objects
  2019-03-16 20:05 [PATCHv2 0/5] Speed up repacking when lots of pack-kept objects Nathaniel Filardo
  2019-03-16 20:05 ` [PATCHv2 1/5] count-objects: report statistics about kept packs Nathaniel Filardo
  2019-03-16 20:05 ` [PATCHv2 2/5] revision walk: optionally use sparse reachability Nathaniel Filardo
@ 2019-03-16 20:05 ` Nathaniel Filardo
  2019-03-16 20:05 ` [PATCHv2 4/5] repack: optionally assume transitive kept packs Nathaniel Filardo
  2019-03-16 20:05 ` [PATCHv2 5/5] builtin/gc: add --assume-pack-keep-transitive Nathaniel Filardo
  4 siblings, 0 replies; 6+ messages in thread
From: Nathaniel Filardo @ 2019-03-16 20:05 UTC (permalink / raw)
  To: git; +Cc: Derrick Stolee, Nathaniel Filardo

The sparse connectivity algorithm saves a whole lot of time when there
are UNINTERESTING trees around.
---
 Documentation/git-repack.txt   | 4 ++++
 builtin/repack.c               | 5 +++++
 t/t5322-pack-objects-sparse.sh | 6 ++++++
 3 files changed, 15 insertions(+)

diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt
index aa0cc8bd44..836d81457a 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -165,6 +165,10 @@ depth is 4095.
 	Pass the `--delta-islands` option to `git-pack-objects`, see
 	linkgit:git-pack-objects[1].
 
+--sparse::
+	Pass the `--sparse` option to `git-pack-objects`; see
+	linkgit:git-pack-objects[1].
+
 Configuration
 -------------
 
diff --git a/builtin/repack.c b/builtin/repack.c
index 67f8978043..8e7641482b 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -288,6 +288,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 	int no_update_server_info = 0;
 	int midx_cleared = 0;
 	struct pack_objects_args po_args = {NULL};
+	int sparse = 0;
 
 	struct option builtin_repack_options[] = {
 		OPT_BIT('a', NULL, &pack_everything,
@@ -326,6 +327,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 				N_("maximum size of each packfile")),
 		OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects,
 				N_("repack objects in packs marked with .keep")),
+		OPT_BOOL(0, "sparse", &sparse,
+			 N_("use the sparse reachability algorithm")),
 		OPT_STRING_LIST(0, "keep-pack", &keep_pack_list, N_("name"),
 				N_("do not repack this pack")),
 		OPT_END()
@@ -366,6 +369,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 	argv_array_push(&cmd.args, "--all");
 	argv_array_push(&cmd.args, "--reflog");
 	argv_array_push(&cmd.args, "--indexed-objects");
+	if (sparse)
+		argv_array_push(&cmd.args, "--sparse");
 	if (repository_format_partial_clone)
 		argv_array_push(&cmd.args, "--exclude-promisor-objects");
 	if (write_bitmaps)
diff --git a/t/t5322-pack-objects-sparse.sh b/t/t5322-pack-objects-sparse.sh
index 7124b5581a..66e133dcfe 100755
--- a/t/t5322-pack-objects-sparse.sh
+++ b/t/t5322-pack-objects-sparse.sh
@@ -133,4 +133,10 @@ test_expect_success 'pack.useSparse overridden' '
 	test_cmp required_objects.txt sparse_objects.txt
 '
 
+# repack --sparse invokes pack-objects --sparse
+test_expect_success 'repack --sparse and fsck' '
+	git repack -a --sparse &&
+	git fsck
+'
+
 test_done
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCHv2 4/5] repack: optionally assume transitive kept packs
  2019-03-16 20:05 [PATCHv2 0/5] Speed up repacking when lots of pack-kept objects Nathaniel Filardo
                   ` (2 preceding siblings ...)
  2019-03-16 20:05 ` [PATCHv2 3/5] repack: add --sparse and pass to pack-objects Nathaniel Filardo
@ 2019-03-16 20:05 ` Nathaniel Filardo
  2019-03-16 20:05 ` [PATCHv2 5/5] builtin/gc: add --assume-pack-keep-transitive Nathaniel Filardo
  4 siblings, 0 replies; 6+ messages in thread
From: Nathaniel Filardo @ 2019-03-16 20:05 UTC (permalink / raw)
  To: git; +Cc: Derrick Stolee, Nathaniel Filardo

If the user is careful to mark .pack files as kept only when they refer
to (other) kept packs, then we can rely on this when walking the object
graph in subsequent repack operations and reduce the time and memory
spent building the object graph.

Towards that end, then, teach git repack to enumerate the COMMITs and
TREEs in kept packs and mark them as UNINTERESTING for pack-object's
operation.  Because this creates UNINTERESTING marks, we make repack's
--assume-pack-keep-transitive imply --sparse for pack-object to avoid
hauling the entire object graph into memory.

In testing with a 203GB repository with 80M objects, this amounts to
several gigabytes of memory and over ten minutes saved.  This machine
has 32G of RAM and the repository is on a fast SSD to speed testing.

All told, this test repository takes about 33 minutes elapsed (28
minutes in user code) and 3 GB of RAM to repack 12M objects occupying
33GB scattered across 477 pack files not marked as kept (the remainder
of the objects are spread across three kept pack files).  The time and
RAM usage with --assume-pack-keep-transitive should be dominated by
factors proportional to the size and number of un-kept objects.

Without these optimizations, it takes about 45 minutes (34 minutes in
user code) and 7 GB of RAM to compute the same pack file.  The extra
time and total memory use are expected to be proportional to the kept
packs' size, not the working set of the repack.  The time discrepancy
can be expected to be more dramatic when the repository is on spinning
rust rather than SSD.

Signed-off-by: Nathaniel Filardo <nwf20@cl.cam.ac.uk>
---
 Documentation/git-repack.txt | 21 +++++++++++++
 builtin/repack.c             | 57 ++++++++++++++++++++++++++++++++++--
 2 files changed, 76 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt
index 836d81457a..014812c4bb 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -169,6 +169,27 @@ depth is 4095.
 	Pass the `--sparse` option to `git-pack-objects`; see
 	linkgit:git-pack-objects[1].
 
+--assume-pack-keep-transitive::
+	This flag accelerates the search for objects to pack by assuming
+	that commit objects found in kept packfiles make reference only
+	to that or other kept packfiles.  This is very useful if, for
+	example, this repository periodically repacks all reachable objects
+	and marks the resulting pack file as kept.
+
+	Because this option may prevent git from descending into kept packs,
+	no objects inside kept packs will be available for delta processing.
+	One should therefore restrict the use of this option to situations
+	where delta processing is disabled or when relatively large amounts
+	of data are considered and the relative gain of a wider set of
+	possible delta base objects is reduced.
+
+	The simplest way to ensure transitivity of kept packs is to run `git
+	repack` with `-a` (or `-A`) and `-d` and mark all resulting packs as
+	kept, never removing the kept marker.  In practice, one may wish to
+	wait to mark packs as kept until they are sufficiently large
+	(reducing the number of pack files necessary for a given set of
+	objects) but not so large as to be unwieldy.
+
 Configuration
 -------------
 
diff --git a/builtin/repack.c b/builtin/repack.c
index 8e7641482b..2b94548850 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -11,6 +11,8 @@
 #include "midx.h"
 #include "packfile.h"
 #include "object-store.h"
+#include "revision.h"
+#include "list-objects.h"
 
 static int delta_base_offset = 1;
 static int pack_kept_objects = -1;
@@ -256,6 +258,30 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
 		die(_("could not finish pack-objects to repack promisor objects"));
 }
 
+static void apkt_show_commit(struct commit *commit, void *data)
+{
+	struct tree *tree;
+	struct pack_entry e;
+
+	if (!find_pack_entry(the_repository, &commit->object.oid, &e))
+		return;
+
+	if (!(e.p->pack_keep || e.p->pack_keep_in_core))
+		return;
+
+	tree = get_commit_tree(commit);
+	if (tree)
+		tree->object.flags |= UNINTERESTING;
+
+	write_oid(&commit->object.oid, e.p, 0, data);
+	write_oid(&tree->object.oid, NULL, 0, data);
+}
+
+static void apkt_show_object(struct object *obj, const char *name, void *data)
+{
+	return;
+}
+
 #define ALL_INTO_ONE 1
 #define LOOSEN_UNREACHABLE 2
 
@@ -287,6 +313,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 	struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
 	int no_update_server_info = 0;
 	int midx_cleared = 0;
+	int assume_pack_keep_transitive = 0;
 	struct pack_objects_args po_args = {NULL};
 	int sparse = 0;
 
@@ -329,6 +356,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 				N_("repack objects in packs marked with .keep")),
 		OPT_BOOL(0, "sparse", &sparse,
 			 N_("use the sparse reachability algorithm")),
+		OPT_BOOL(0, "assume-pack-keep-transitive", &assume_pack_keep_transitive,
+				N_("assume kept packs reference only kept packs")),
 		OPT_STRING_LIST(0, "keep-pack", &keep_pack_list, N_("name"),
 				N_("do not repack this pack")),
 		OPT_END()
@@ -346,6 +375,11 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 	    (unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE)))
 		die(_("--keep-unreachable and -A are incompatible"));
 
+	if (assume_pack_keep_transitive) {
+		/* imply --honor-pack-keep */
+		pack_kept_objects = 0;
+	}
+
 	if (pack_kept_objects < 0)
 		pack_kept_objects = write_bitmaps;
 
@@ -369,7 +403,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 	argv_array_push(&cmd.args, "--all");
 	argv_array_push(&cmd.args, "--reflog");
 	argv_array_push(&cmd.args, "--indexed-objects");
-	if (sparse)
+	if (sparse || assume_pack_keep_transitive)
 		argv_array_push(&cmd.args, "--sparse");
 	if (repository_format_partial_clone)
 		argv_array_push(&cmd.args, "--exclude-promisor-objects");
@@ -404,12 +438,31 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 		argv_array_push(&cmd.args, "--incremental");
 	}
 
-	cmd.no_stdin = 1;
+	cmd.in = -1;
+	cmd.no_stdin = !assume_pack_keep_transitive;
 
 	ret = start_command(&cmd);
 	if (ret)
 		return ret;
 
+	if (assume_pack_keep_transitive) {
+		struct rev_info revs;
+		const char *revargv[] = { "skip", "--all", "--reflog", "--indexed-objects", NULL };
+
+		repo_init_revisions(the_repository, &revs, NULL);
+		revs.sparse_tree_walk = !!(sparse || assume_pack_keep_transitive);
+		setup_revisions(sizeof(revargv)/sizeof(revargv[0]) - 1 , revargv, &revs, NULL);
+		if (prepare_revision_walk(&revs))
+			die("revision walk setup failed");
+
+		xwrite(cmd.in, "--not\n", 6);
+		traverse_commit_list(&revs, apkt_show_commit, apkt_show_object,
+				     &cmd);
+		xwrite(cmd.in, "--not\n", 6);
+
+		close(cmd.in);
+	}
+
 	out = xfdopen(cmd.out, "r");
 	while (strbuf_getline_lf(&line, out) != EOF) {
 		if (line.len != the_hash_algo->hexsz)
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCHv2 5/5] builtin/gc: add --assume-pack-keep-transitive
  2019-03-16 20:05 [PATCHv2 0/5] Speed up repacking when lots of pack-kept objects Nathaniel Filardo
                   ` (3 preceding siblings ...)
  2019-03-16 20:05 ` [PATCHv2 4/5] repack: optionally assume transitive kept packs Nathaniel Filardo
@ 2019-03-16 20:05 ` Nathaniel Filardo
  4 siblings, 0 replies; 6+ messages in thread
From: Nathaniel Filardo @ 2019-03-16 20:05 UTC (permalink / raw)
  To: git; +Cc: Derrick Stolee, Nathaniel Filardo

Just pass it on down to builtin/repack.

Signed-off-by: Nathaniel Filardo <nwf20@cl.cam.ac.uk>
---
 Documentation/git-gc.txt | 5 +++++
 builtin/gc.c             | 5 +++++
 2 files changed, 10 insertions(+)

diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
index a7c1b0f60e..7115564f7d 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -96,6 +96,11 @@ be performed as well.
 	`.keep` files are consolidated into a single pack. When this
 	option is used, `gc.bigPackThreshold` is ignored.
 
+--assume-pack-keep-transitive::
+	Pass the `--assume-pack-keep-transitive` option to `git-repack`;
+	see linkgit:git-repack[1].
+
+
 CONFIGURATION
 -------------
 
diff --git a/builtin/gc.c b/builtin/gc.c
index 020f725acc..b0c160abec 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -504,6 +504,7 @@ static void gc_before_repack(void)
 int cmd_gc(int argc, const char **argv, const char *prefix)
 {
 	int aggressive = 0;
+	int assume_pack_keep_transitive = 0;
 	int auto_gc = 0;
 	int quiet = 0;
 	int force = 0;
@@ -526,6 +527,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
 			   PARSE_OPT_NOCOMPLETE),
 		OPT_BOOL(0, "keep-largest-pack", &keep_base_pack,
 			 N_("repack all other packs except the largest pack")),
+		OPT_BOOL(0, "assume-pack-keep-transitive", &assume_pack_keep_transitive,
+			 N_("assume kept packs reference only kept packs")),
 		OPT_END()
 	};
 
@@ -564,6 +567,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
 	}
 	if (quiet)
 		argv_array_push(&repack, "-q");
+	if (assume_pack_keep_transitive)
+		argv_array_push(&repack, "--assume-pack-keep-transitive");
 
 	if (auto_gc) {
 		/*
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2019-03-16 20:05 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-16 20:05 [PATCHv2 0/5] Speed up repacking when lots of pack-kept objects Nathaniel Filardo
2019-03-16 20:05 ` [PATCHv2 1/5] count-objects: report statistics about kept packs Nathaniel Filardo
2019-03-16 20:05 ` [PATCHv2 2/5] revision walk: optionally use sparse reachability Nathaniel Filardo
2019-03-16 20:05 ` [PATCHv2 3/5] repack: add --sparse and pass to pack-objects Nathaniel Filardo
2019-03-16 20:05 ` [PATCHv2 4/5] repack: optionally assume transitive kept packs Nathaniel Filardo
2019-03-16 20:05 ` [PATCHv2 5/5] builtin/gc: add --assume-pack-keep-transitive Nathaniel Filardo

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).