git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 03/10] packfile: refactor kept-pack cache to work with packfile stores

From
Patrick Steinhardt <ps@pks.im>
Date
Dec 15, 2025, 07:36 UTC
Message-ID
<20251215-b4-pks-pack-store-via-source-v1-3-433aac465295@pks.im>
In-Reply-To
<20251215-b4-pks-pack-store-via-source-v1-0-433aac465295@pks.im>

The kept pack cache is a cache of packfiles that are marked as kept either via an accompanying ".kept" file or via an in-memory flag. The cache can be retrieved via `kept_pack_cache()`, where one needs to pass in a repository.

Ultimately though the kept-pack cache is a property of the packfile store, and this causes problems in a subsequent commit where we want to move down the packfile store to be a per-object-source entity.

Prepare for this and refactor the kept-pack cache to work on top of a packfile store instead.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/pack-objects.c | 12 ++++++------
 packfile.c             | 37 ++++++++++++++++++++-----------------
 packfile.h             | 18 +++++++++++++-----
 reachable.c            |  2 +-
 revision.c             |  8 ++++----
 5 files changed, 44 insertions(+), 33 deletions(-)
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 1ce8d6ee21..e86b8f387a 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1529,9 +1529,9 @@ static int want_cruft_object_mtime(struct repository *r,
 				   const struct object_id *oid,
 				   unsigned flags, uint32_t mtime)
 {
-	struct packed_git **cache;
+	struct packed_git **cache = packfile_store_get_kept_pack_cache(r->objects->packfiles, flags);
 
-	for (cache = kept_pack_cache(r, flags); *cache; cache++) {
+	for (; *cache; cache++) {
 		struct packed_git *p = *cache;
 		off_t ofs;
 		uint32_t candidate_mtime;
@@ -1624,9 +1624,9 @@ static int want_found_object(const struct object_id *oid, int exclude,
 		 */
 		unsigned flags = 0;
 		if (ignore_packed_keep_on_disk)
-			flags |= ON_DISK_KEEP_PACKS;
+			flags |= KEPT_PACK_ON_DISK;
 		if (ignore_packed_keep_in_core)
-			flags |= IN_CORE_KEEP_PACKS;
+			flags |= KEPT_PACK_IN_CORE;
 
 		/*
 		 * If the object is in a pack that we want to ignore, *and* we
@@ -3931,7 +3931,7 @@ static void read_stdin_packs(enum stdin_packs_mode mode, int rev_list_unpacked)
 	 * an optimization during delta selection.
 	 */
 	revs.no_kept_objects = 1;
-	revs.keep_pack_cache_flags |= IN_CORE_KEEP_PACKS;
+	revs.keep_pack_cache_flags |= KEPT_PACK_IN_CORE;
 	revs.blob_objects = 1;
 	revs.tree_objects = 1;
 	revs.tag_objects = 1;
@@ -4030,7 +4030,7 @@ static void show_cruft_commit(struct commit *commit, void *data)
 
 static int cruft_include_check_obj(struct object *obj, void *data UNUSED)
 {
-	return !has_object_kept_pack(to_pack.repo, &obj->oid, IN_CORE_KEEP_PACKS);
+	return !has_object_kept_pack(to_pack.repo, &obj->oid, KEPT_PACK_IN_CORE);
 }
 
 static int cruft_include_check(struct commit *commit, void *data)
diff --git a/packfile.c b/packfile.c
index ab86afa01d..191344eb1c 100644
--- a/packfile.c
+++ b/packfile.c
@@ -2164,25 +2164,26 @@ int packfile_store_read_object_info(struct packfile_store *store,
 	return 0;
 }
 
-static void maybe_invalidate_kept_pack_cache(struct repository *r,
+static void maybe_invalidate_kept_pack_cache(struct packfile_store *store,
 					     unsigned flags)
 {
-	if (!r->objects->packfiles->kept_cache.packs)
+	if (!store->kept_cache.packs)
 		return;
-	if (r->objects->packfiles->kept_cache.flags == flags)
+	if (store->kept_cache.flags == flags)
 		return;
-	FREE_AND_NULL(r->objects->packfiles->kept_cache.packs);
-	r->objects->packfiles->kept_cache.flags = 0;
+	FREE_AND_NULL(store->kept_cache.packs);
+	store->kept_cache.flags = 0;
 }
 
-struct packed_git **kept_pack_cache(struct repository *r, unsigned flags)
+struct packed_git **packfile_store_get_kept_pack_cache(struct packfile_store *store,
+						       unsigned flags)
 {
-	maybe_invalidate_kept_pack_cache(r, flags);
+	maybe_invalidate_kept_pack_cache(store, flags);
 
-	if (!r->objects->packfiles->kept_cache.packs) {
+	if (!store->kept_cache.packs) {
 		struct packed_git **packs = NULL;
+		struct packfile_list_entry *e;
 		size_t nr = 0, alloc = 0;
-		struct packed_git *p;
 
 		/*
 		 * We want "all" packs here, because we need to cover ones that
@@ -2192,9 +2193,11 @@ struct packed_git **kept_pack_cache(struct repository *r, unsigned flags)
 		 * covers, one kept and one not kept, but the midx returns only
 		 * the non-kept version.
 		 */
-		repo_for_each_pack(r, p) {
-			if ((p->pack_keep && (flags & ON_DISK_KEEP_PACKS)) ||
-			    (p->pack_keep_in_core && (flags & IN_CORE_KEEP_PACKS))) {
+		for (e = packfile_store_get_packs(store); e; e = e->next) {
+			struct packed_git *p = e->pack;
+
+			if ((p->pack_keep && (flags & KEPT_PACK_ON_DISK)) ||
+			    (p->pack_keep_in_core && (flags & KEPT_PACK_IN_CORE))) {
 				ALLOC_GROW(packs, nr + 1, alloc);
 				packs[nr++] = p;
 			}
@@ -2202,11 +2205,11 @@ struct packed_git **kept_pack_cache(struct repository *r, unsigned flags)
 		ALLOC_GROW(packs, nr + 1, alloc);
 		packs[nr] = NULL;
 
-		r->objects->packfiles->kept_cache.packs = packs;
-		r->objects->packfiles->kept_cache.flags = flags;
+		store->kept_cache.packs = packs;
+		store->kept_cache.flags = flags;
 	}
 
-	return r->objects->packfiles->kept_cache.packs;
+	return store->kept_cache.packs;
 }
 
 int find_kept_pack_entry(struct repository *r,
@@ -2214,9 +2217,9 @@ int find_kept_pack_entry(struct repository *r,
 			 unsigned flags,
 			 struct pack_entry *e)
 {
-	struct packed_git **cache;
+	struct packed_git **cache = packfile_store_get_kept_pack_cache(r->objects->packfiles, flags);
 
-	for (cache = kept_pack_cache(r, flags); *cache; cache++) {
+	for (; *cache; cache++) {
 		struct packed_git *p = *cache;
 		if (fill_pack_entry(oid, e, p))
 			return 1;
diff --git a/packfile.h b/packfile.h
index 33cc1c1654..701a3b4946 100644
--- a/packfile.h
+++ b/packfile.h
@@ -210,6 +210,19 @@ struct packed_git *packfile_store_load_pack(struct packfile_store *store,
 int packfile_store_freshen_object(struct packfile_store *store,
 				  const struct object_id *oid);
 
+enum kept_pack_type {
+	KEPT_PACK_ON_DISK = (1 << 0),
+	KEPT_PACK_IN_CORE = (1 << 1),
+};
+
+/*
+ * Retrieve the cache of kept packs from the given packfile store. Accepts a
+ * combination of `kept_pack_type` flags. The cache is computed on demand and
+ * will be recomputed whenever the flags change.
+ */
+struct packed_git **packfile_store_get_kept_pack_cache(struct packfile_store *store,
+						       unsigned flags);
+
 struct pack_window {
 	struct pack_window *next;
 	unsigned char *base;
@@ -385,9 +398,6 @@ int packed_object_info(struct repository *r,
 void mark_bad_packed_object(struct packed_git *, const struct object_id *);
 const struct packed_git *has_packed_and_bad(struct repository *, const struct object_id *);
 
-#define ON_DISK_KEEP_PACKS 1
-#define IN_CORE_KEEP_PACKS 2
-
 /*
  * Iff a pack file in the given repository contains the object named by sha1,
  * return true and store its location to e.
@@ -398,8 +408,6 @@ int has_object_pack(struct repository *r, const struct object_id *oid);
 int has_object_kept_pack(struct repository *r, const struct object_id *oid,
 			 unsigned flags);
 
-struct packed_git **kept_pack_cache(struct repository *r, unsigned flags);
-
 /*
  * Return 1 if an object in a promisor packfile is or refers to the given
  * object, 0 otherwise.
diff --git a/reachable.c b/reachable.c
index b753c39553..4b532039d5 100644
--- a/reachable.c
+++ b/reachable.c
@@ -242,7 +242,7 @@ static int want_recent_object(struct recent_data *data,
 			      const struct object_id *oid)
 {
 	if (data->ignore_in_core_kept_packs &&
-	    has_object_kept_pack(data->revs->repo, oid, IN_CORE_KEEP_PACKS))
+	    has_object_kept_pack(data->revs->repo, oid, KEPT_PACK_IN_CORE))
 		return 0;
 	return 1;
 }
diff --git a/revision.c b/revision.c
index 5f0850ae5c..64d223a7c6 100644
--- a/revision.c
+++ b/revision.c
@@ -2541,14 +2541,14 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
 		die(_("--unpacked=<packfile> no longer supported"));
 	} else if (!strcmp(arg, "--no-kept-objects")) {
 		revs->no_kept_objects = 1;
-		revs->keep_pack_cache_flags |= IN_CORE_KEEP_PACKS;
-		revs->keep_pack_cache_flags |= ON_DISK_KEEP_PACKS;
+		revs->keep_pack_cache_flags |= KEPT_PACK_IN_CORE;
+		revs->keep_pack_cache_flags |= KEPT_PACK_ON_DISK;
 	} else if (skip_prefix(arg, "--no-kept-objects=", &optarg)) {
 		revs->no_kept_objects = 1;
 		if (!strcmp(optarg, "in-core"))
-			revs->keep_pack_cache_flags |= IN_CORE_KEEP_PACKS;
+			revs->keep_pack_cache_flags |= KEPT_PACK_IN_CORE;
 		if (!strcmp(optarg, "on-disk"))
-			revs->keep_pack_cache_flags |= ON_DISK_KEEP_PACKS;
+			revs->keep_pack_cache_flags |= KEPT_PACK_ON_DISK;
 	} else if (!strcmp(arg, "-r")) {
 		revs->diff = 1;
 		revs->diffopt.flags.recursive = 1;
-- 
2.52.0.351.gbe84eed79e.dirty
Previous: Justin ToblerNext: Justin Tobler
Message 7 of 52 in “Start tracking packfiles per object database source”
  1. 00/10 Start tracking packfiles per object database sourcePatrick Steinhardt, Dec 15, 2025
  2. 01/10 packfile: create store via its owning sourcePatrick Steinhardt, Dec 15, 2025
  3. Justin ToblerDec 15, 2025
  4. Patrick SteinhardtDec 16, 2025
  5. 02/10 packfile: pass source to `prepare_pack()`Patrick Steinhardt, Dec 15, 2025
  6. Justin ToblerDec 15, 2025
  7. 03/10 packfile: refactor kept-pack cache to work with packfile storesPatrick Steinhardt, Dec 15, 2025
  8. Justin ToblerDec 15, 2025
  9. Patrick SteinhardtDec 16, 2025
  10. 04/10 packfile: refactor misleading code when unusing pack windowsPatrick Steinhardt, Dec 15, 2025
  11. 05/10 packfile: move packfile store into object sourcePatrick Steinhardt, Dec 15, 2025
  12. Justin ToblerDec 18, 2025
  13. Patrick SteinhardtDec 18, 2025
  14. 06/10 packfile: only prepare owning store in `packfile_store_get_packs()`Patrick Steinhardt, Dec 15, 2025
  15. Justin ToblerDec 18, 2025
  16. 07/10 packfile: only prepare owning store in `packfile_store_prepare()`Patrick Steinhardt, Dec 15, 2025
  17. 08/10 packfile: inline `find_kept_pack_entry()`Patrick Steinhardt, Dec 15, 2025
  18. Justin ToblerDec 18, 2025
  19. Patrick SteinhardtDec 18, 2025
  20. 09/10 packfile: refactor `find_pack_entry()` to work on the packfile storePatrick Steinhardt, Dec 15, 2025
  21. 10/10 packfile: move MIDX into packfile storePatrick Steinhardt, Dec 15, 2025
  22. 00/10 Start tracking packfiles per object database sourcePatrick Steinhardt, Dec 18, 2025
  23. 01/10 packfile: create store via its owning sourcePatrick Steinhardt, Dec 18, 2025
  24. 02/10 packfile: pass source to `prepare_pack()`Patrick Steinhardt, Dec 18, 2025
  25. 03/10 packfile: refactor kept-pack cache to work with packfile storesPatrick Steinhardt, Dec 18, 2025
  26. Toon ClaesJan 6, 2026
  27. 04/10 packfile: refactor misleading code when unusing pack windowsPatrick Steinhardt, Dec 18, 2025
  28. Toon ClaesJan 7, 2026
  29. 05/10 packfile: move packfile store into object sourcePatrick Steinhardt, Dec 18, 2025
  30. Toon ClaesJan 7, 2026
  31. 06/10 packfile: only prepare owning store in `packfile_store_get_packs()`Patrick Steinhardt, Dec 18, 2025
  32. 07/10 packfile: only prepare owning store in `packfile_store_prepare()`Patrick Steinhardt, Dec 18, 2025
  33. Toon ClaesJan 7, 2026
  34. 08/10 packfile: inline `find_kept_pack_entry()`Patrick Steinhardt, Dec 18, 2025
  35. Kristoffer HaugsbakkJan 8, 2026
  36. Patrick SteinhardtJan 9, 2026
  37. 09/10 packfile: refactor `find_pack_entry()` to work on the packfile storePatrick Steinhardt, Dec 18, 2025
  38. 10/10 packfile: move MIDX into packfile storePatrick Steinhardt, Dec 18, 2025
  39. 00/10 Start tracking packfiles per object database sourcePatrick Steinhardt, Jan 9, 2026
  40. 01/10 packfile: create store via its owning sourcePatrick Steinhardt, Jan 9, 2026
  41. 02/10 packfile: pass source to `prepare_pack()`Patrick Steinhardt, Jan 9, 2026
  42. 03/10 packfile: refactor kept-pack cache to work with packfile storesPatrick Steinhardt, Jan 9, 2026
  43. 04/10 packfile: refactor misleading code when unusing pack windowsPatrick Steinhardt, Jan 9, 2026
  44. Karthik NayakJan 12, 2026
  45. 05/10 packfile: move packfile store into object sourcePatrick Steinhardt, Jan 9, 2026
  46. 06/10 packfile: only prepare owning store in `packfile_store_get_packs()`Patrick Steinhardt, Jan 9, 2026
  47. 07/10 packfile: only prepare owning store in `packfile_store_prepare()`Patrick Steinhardt, Jan 9, 2026
  48. 08/10 packfile: inline `find_kept_pack_entry()`Patrick Steinhardt, Jan 9, 2026
  49. 09/10 packfile: refactor `find_pack_entry()` to work on the packfile storePatrick Steinhardt, Jan 9, 2026
  50. 10/10 packfile: move MIDX into packfile storePatrick Steinhardt, Jan 9, 2026
  51. Junio C HamanoJan 11, 2026
  52. Justin ToblerJan 12, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.