Thread (31 messages) 31 messages, 2 authors, 1d ago
WARM1d

[PATCH v2 10/12] builtin/gc: refactor ODB optimizations to operate on "files" source

From: Patrick Steinhardt <hidden>
Date: 2026-07-13 05:52:42
Subsystem: the rest · Maintainer: Linus Torvalds

We have a couple of functions that are implementation details of how the
"files" object database source performs optimizations. These functions
often use global state like `the_repository` and implicitly derive the
source they are supposed to optimize.

Refactor these interfaces to accept a "files" source directly. This will
make it easier to move around the whole logic into "odb/source-files.c"
in a subsequent step.

Signed-off-by: Patrick Steinhardt <redacted>
---
 builtin/gc.c | 79 +++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 41 insertions(+), 38 deletions(-)
diff --git a/builtin/gc.c b/builtin/gc.c
index e119930adc..3207182488 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -428,9 +428,8 @@ static int rerere_gc_condition(struct gc_config *cfg UNUSED)
 	return should_gc;
 }
 
-static int too_many_loose_objects(int limit)
+static int too_many_loose_objects(struct odb_source_files *files, int limit)
 {
-	struct odb_source_files *files = odb_source_files_downcast(the_repository->objects->sources);
 	/*
 	 * This is weird, but stems from legacy behaviour: the GC auto
 	 * threshold was always essentially interpreted as if it was rounded up
@@ -446,19 +445,21 @@ static int too_many_loose_objects(int limit)
 	return loose_count > auto_threshold;
 }
 
-static struct packed_git *find_base_packs(struct string_list *packs,
+static struct packed_git *find_base_packs(struct odb_source_files *files,
+					  struct string_list *packs,
 					  unsigned long limit)
 {
-	struct packed_git *p, *base = NULL;
+	struct packfile_list_entry *e;
+	struct packed_git *base = NULL;
 
-	repo_for_each_pack(the_repository, p) {
-		if (!p->pack_local || p->is_cruft)
+	for (e = packfile_store_get_packs(files->packed); e; e = e->next) {
+		if (e->pack->is_cruft)
 			continue;
 		if (limit) {
-			if (p->pack_size >= limit)
-				string_list_append(packs, p->pack_name);
-		} else if (!base || base->pack_size < p->pack_size) {
-			base = p;
+			if (e->pack->pack_size >= limit)
+				string_list_append(packs, e->pack->pack_name);
+		} else if (!base || base->pack_size < e->pack->pack_size) {
+			base = e->pack;
 		}
 	}
 
@@ -468,18 +469,16 @@ static struct packed_git *find_base_packs(struct string_list *packs,
 	return base;
 }
 
-static int too_many_packs(int gc_auto_pack_limit)
+static int too_many_packs(struct odb_source_files *files, int gc_auto_pack_limit)
 {
-	struct packed_git *p;
+	struct packfile_list_entry *e;
 	int cnt = 0;
 
 	if (gc_auto_pack_limit <= 0)
 		return 0;
 
-	repo_for_each_pack(the_repository, p) {
-		if (!p->pack_local)
-			continue;
-		if (p->pack_keep)
+	for (e = packfile_store_get_packs(files->packed); e; e = e->next) {
+		if (e->pack->pack_keep)
 			continue;
 		/*
 		 * Perhaps check the size of the pack and count only
@@ -535,15 +534,16 @@ static uint64_t total_ram(void)
 	return 0;
 }
 
-static uint64_t estimate_repack_memory(struct packed_git *pack)
+static uint64_t estimate_repack_memory(struct odb_source_files *files,
+				       struct packed_git *pack)
 {
 	unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
 	unsigned long delta_base_cache_limit = DEFAULT_DELTA_BASE_CACHE_LIMIT;
 	unsigned long nr_objects;
 	size_t os_cache, heap;
 
-	if (odb_count_objects(the_repository->objects,
-			      ODB_COUNT_OBJECTS_APPROXIMATE, &nr_objects) < 0)
+	if (odb_source_count_objects(&files->base, ODB_COUNT_OBJECTS_APPROXIMATE,
+				     &nr_objects) < 0)
 		return 0;
 
 	if (!pack || !nr_objects)
@@ -679,6 +679,8 @@ static void add_repack_incremental_option(struct strvec *args)
 static bool odb_optimize_required(struct object_database *odb,
 				  const struct odb_optimize_options *opts)
 {
+	struct odb_source_files *files = odb_source_files_downcast(odb->sources);
+
 	switch (opts->strategy) {
 	case ODB_OPTIMIZE_INCREMENTAL: {
 		int gc_auto_threshold = 6700;
@@ -693,8 +695,8 @@ static bool odb_optimize_required(struct object_database *odb,
 		 */
 		if (gc_auto_threshold <= 0)
 			return false;
-		if (!too_many_packs(gc_auto_pack_limit) &&
-		    !too_many_loose_objects(gc_auto_threshold))
+		if (!too_many_packs(files, gc_auto_pack_limit) &&
+		    !too_many_loose_objects(files, gc_auto_threshold))
 			return false;
 
 		return true;
@@ -739,7 +741,7 @@ static bool odb_optimize_required(struct object_database *odb,
 		 * Otherwise, we estimate the number of loose objects to determine
 		 * whether we want to create a new packfile or not.
 		 */
-		if (too_many_loose_objects(auto_value)) {
+		if (too_many_loose_objects(files, auto_value)) {
 			ret = true;
 			goto out;
 		}
@@ -886,21 +888,22 @@ static int gc_foreground_tasks(struct maintenance_run_opts *opts,
 static int odb_optimize(struct object_database *odb,
 			const struct odb_optimize_options *opts)
 {
+	struct odb_source_files *files = odb_source_files_downcast(odb->sources);
 	struct child_process repack_cmd = CHILD_PROCESS_INIT;
 	unsigned long big_pack_threshold = 0;
 	int gc_auto_threshold = 6700;
 	int gc_auto_pack_limit = 50;
 	int ret;
 
-	repo_config_get_int(the_repository, "gc.auto", &gc_auto_threshold);
-	repo_config_get_int(the_repository, "gc.autopacklimit", &gc_auto_pack_limit);
-	repo_config_get_ulong(the_repository, "gc.bigpackthreshold", &big_pack_threshold);
+	repo_config_get_int(odb->repo, "gc.auto", &gc_auto_threshold);
+	repo_config_get_int(odb->repo, "gc.autopacklimit", &gc_auto_pack_limit);
+	repo_config_get_ulong(odb->repo, "gc.bigpackthreshold", &big_pack_threshold);
 
 	if (odb->repo->repository_format_precious_objects)
 		return 0;
 
 	repack_cmd.git_cmd = 1;
-	repack_cmd.odb_to_close = the_repository->objects;
+	repack_cmd.odb_to_close = odb->repo->objects;
 
 	strvec_pushl(&repack_cmd.args, "repack", "-d", "-l", NULL);
 	if (opts->flags & ODB_OPTIMIZE_NO_REUSE_DELTAS)
@@ -930,29 +933,29 @@ static int odb_optimize(struct object_database *odb,
 
 			if (opts->keep_largest_pack != -1) {
 				if (opts->keep_largest_pack)
-					find_base_packs(&keep_pack, 0);
+					find_base_packs(files, &keep_pack, 0);
 			} else if (big_pack_threshold) {
-				find_base_packs(&keep_pack, big_pack_threshold);
+				find_base_packs(files, &keep_pack, big_pack_threshold);
 			}
 
 			add_repack_all_option(opts, &keep_pack, &repack_cmd.args);
 			string_list_clear(&keep_pack, 0);
 		} else {
-			if (too_many_packs(gc_auto_pack_limit)) {
+			if (too_many_packs(files, gc_auto_pack_limit)) {
 				struct string_list keep_pack = STRING_LIST_INIT_NODUP;
 
 				if (big_pack_threshold) {
-					find_base_packs(&keep_pack, big_pack_threshold);
+					find_base_packs(files, &keep_pack, big_pack_threshold);
 					if (keep_pack.nr >= gc_auto_pack_limit) {
 						string_list_clear(&keep_pack, 0);
-						find_base_packs(&keep_pack, 0);
+						find_base_packs(files, &keep_pack, 0);
 					}
 				} else {
-					struct packed_git *p = find_base_packs(&keep_pack, 0);
+					struct packed_git *p = find_base_packs(files, &keep_pack, 0);
 					uint64_t mem_have, mem_want;
 
 					mem_have = total_ram();
-					mem_want = estimate_repack_memory(p);
+					mem_want = estimate_repack_memory(files, p);
 
 					/*
 					 * Only allow 1/2 of memory for pack-objects, leave
@@ -981,10 +984,10 @@ static int odb_optimize(struct object_database *odb,
 		struct existing_packs existing_packs = EXISTING_PACKS_INIT;
 		struct string_list kept_packs = STRING_LIST_INIT_DUP;
 
-		repo_config_get_int(the_repository, "maintenance.geometric-repack.splitFactor",
+		repo_config_get_int(odb->repo, "maintenance.geometric-repack.splitFactor",
 				    &geometry.split_factor);
 
-		existing_packs.repo = the_repository;
+		existing_packs.repo = odb->repo;
 		existing_packs_collect(&existing_packs, &kept_packs);
 		pack_geometry_init(&geometry, &existing_packs, &po_args);
 		pack_geometry_split(&geometry);
@@ -995,7 +998,7 @@ static int odb_optimize(struct object_database *odb,
 		} else {
 			add_repack_all_option(opts, NULL, &repack_cmd.args);
 		}
-		if (the_repository->settings.core_multi_pack_index)
+		if (odb->repo->settings.core_multi_pack_index)
 			strvec_push(&repack_cmd.args, "--write-midx");
 
 		existing_packs_release(&existing_packs);
@@ -1020,7 +1023,7 @@ static int odb_optimize(struct object_database *odb,
 		strvec_push(&prune_cmd.args, opts->prune_expire);
 		if (!(opts->flags & ODB_OPTIMIZE_VERBOSE))
 			strvec_push(&prune_cmd.args, "--no-progress");
-		if (repo_has_promisor_remote(the_repository))
+		if (repo_has_promisor_remote(odb->repo))
 			strvec_push(&prune_cmd.args,
 				    "--exclude-promisor-objects");
 		prune_cmd.git_cmd = 1;
@@ -1031,7 +1034,7 @@ static int odb_optimize(struct object_database *odb,
 		}
 	}
 
-	if (opts->flags & ODB_OPTIMIZE_AUTO && too_many_loose_objects(gc_auto_threshold))
+	if (opts->flags & ODB_OPTIMIZE_AUTO && too_many_loose_objects(files, gc_auto_threshold))
 		warning(_("There are too many unreachable loose objects; "
 			"run 'git prune' to remove them."));
 
-- 
2.55.0.313.g8d093f411d.dirty
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help