packfile: refactor kept-pack cache to work with packfile stores

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. While at it, rename both the function and flags specific to the kept-pack cache so that they can be properly attributed to the respective subsystems. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Jan 9, 2026 at 09:33 UTC 085de91b951a40b2b8ce35f8bfa182d4f5bcea6b
5 files changed +48 -36
builtin/pack-objects.c
+6 -6
@@ -1529,9 +1529,9 @@ static int want_cruft_object_mtime(struct repository *r,
1529 const struct object_id *oid,
1530 unsigned flags, uint32_t mtime)
1531 {
1532 - struct packed_git **cache;
1532 + struct packed_git **cache = packfile_store_get_kept_pack_cache(r->objects->packfiles, flags);
1533
1534 - for (cache = kept_pack_cache(r, flags); *cache; cache++) {
1534 + for (; *cache; cache++) {
1535 struct packed_git *p = *cache;
1536 off_t ofs;
1537 uint32_t candidate_mtime;
@@ -1624,9 +1624,9 @@ static int want_found_object(const struct object_id *oid, int exclude,
1624 */
1625 unsigned flags = 0;
1626 if (ignore_packed_keep_on_disk)
1627 - flags |= ON_DISK_KEEP_PACKS;
1627 + flags |= KEPT_PACK_ON_DISK;
1628 if (ignore_packed_keep_in_core)
1629 - flags |= IN_CORE_KEEP_PACKS;
1629 + flags |= KEPT_PACK_IN_CORE;
1630
1631 /*
1632 * 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)
3931 * an optimization during delta selection.
3932 */
3933 revs.no_kept_objects = 1;
3934 - revs.keep_pack_cache_flags |= IN_CORE_KEEP_PACKS;
3934 + revs.keep_pack_cache_flags |= KEPT_PACK_IN_CORE;
3935 revs.blob_objects = 1;
3936 revs.tree_objects = 1;
3937 revs.tag_objects = 1;
@@ -4030,7 +4030,7 @@ static void show_cruft_commit(struct commit *commit, void *data)
4030
4031 static int cruft_include_check_obj(struct object *obj, void *data UNUSED)
4032 {
4033 - return !has_object_kept_pack(to_pack.repo, &obj->oid, IN_CORE_KEEP_PACKS);
4033 + return !has_object_kept_pack(to_pack.repo, &obj->oid, KEPT_PACK_IN_CORE);
4034 }
4035
4036 static int cruft_include_check(struct commit *commit, void *data)
packfile.c
+20 -17
@@ -2164,25 +2164,26 @@ int packfile_store_read_object_info(struct packfile_store *store,
2164 return 0;
2165 }
2166
2167 -static void maybe_invalidate_kept_pack_cache(struct repository *r,
2167 +static void maybe_invalidate_kept_pack_cache(struct packfile_store *store,
2168 unsigned flags)
2169 {
2170 - if (!r->objects->packfiles->kept_cache.packs)
2170 + if (!store->kept_cache.packs)
2171 return;
2172 - if (r->objects->packfiles->kept_cache.flags == flags)
2172 + if (store->kept_cache.flags == flags)
2173 return;
2174 - FREE_AND_NULL(r->objects->packfiles->kept_cache.packs);
2175 - r->objects->packfiles->kept_cache.flags = 0;
2174 + FREE_AND_NULL(store->kept_cache.packs);
2175 + store->kept_cache.flags = 0;
2176 }
2177
2178 -struct packed_git **kept_pack_cache(struct repository *r, unsigned flags)
2178 +struct packed_git **packfile_store_get_kept_pack_cache(struct packfile_store *store,
2179 + unsigned flags)
2180 {
2180 - maybe_invalidate_kept_pack_cache(r, flags);
2181 + maybe_invalidate_kept_pack_cache(store, flags);
2182
2182 - if (!r->objects->packfiles->kept_cache.packs) {
2183 + if (!store->kept_cache.packs) {
2184 struct packed_git **packs = NULL;
2185 + struct packfile_list_entry *e;
2186 size_t nr = 0, alloc = 0;
2185 - struct packed_git *p;
2187
2188 /*
2189 * 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)
2193 * covers, one kept and one not kept, but the midx returns only
2194 * the non-kept version.
2195 */
2195 - repo_for_each_pack(r, p) {
2196 - if ((p->pack_keep && (flags & ON_DISK_KEEP_PACKS)) ||
2197 - (p->pack_keep_in_core && (flags & IN_CORE_KEEP_PACKS))) {
2196 + for (e = packfile_store_get_packs(store); e; e = e->next) {
2197 + struct packed_git *p = e->pack;
2198 +
2199 + if ((p->pack_keep && (flags & KEPT_PACK_ON_DISK)) ||
2200 + (p->pack_keep_in_core && (flags & KEPT_PACK_IN_CORE))) {
2201 ALLOC_GROW(packs, nr + 1, alloc);
2202 packs[nr++] = p;
2203 }
@@ -2202,11 +2205,11 @@ struct packed_git **kept_pack_cache(struct repository *r, unsigned flags)
2205 ALLOC_GROW(packs, nr + 1, alloc);
2206 packs[nr] = NULL;
2207
2205 - r->objects->packfiles->kept_cache.packs = packs;
2206 - r->objects->packfiles->kept_cache.flags = flags;
2208 + store->kept_cache.packs = packs;
2209 + store->kept_cache.flags = flags;
2210 }
2211
2209 - return r->objects->packfiles->kept_cache.packs;
2212 + return store->kept_cache.packs;
2213 }
2214
2215 int find_kept_pack_entry(struct repository *r,
@@ -2214,9 +2217,9 @@ int find_kept_pack_entry(struct repository *r,
2217 unsigned flags,
2218 struct pack_entry *e)
2219 {
2217 - struct packed_git **cache;
2220 + struct packed_git **cache = packfile_store_get_kept_pack_cache(r->objects->packfiles, flags);
2221
2219 - for (cache = kept_pack_cache(r, flags); *cache; cache++) {
2222 + for (; *cache; cache++) {
2223 struct packed_git *p = *cache;
2224 if (fill_pack_entry(oid, e, p))
2225 return 1;
packfile.h
+17 -8
@@ -90,9 +90,10 @@ struct packfile_store {
90 * is an on-disk ".keep" file or because they are marked as "kept" in
91 * memory.
92 *
93 - * Should not be accessed directly, but via `kept_pack_cache()`. The
94 - * list of packs gets invalidated when the stored flags and the flags
95 - * passed to `kept_pack_cache()` mismatch.
93 + * Should not be accessed directly, but via
94 + * `packfile_store_get_kept_pack_cache()`. The list of packs gets
95 + * invalidated when the stored flags and the flags passed to
96 + * `packfile_store_get_kept_pack_cache()` mismatch.
97 */
98 struct {
99 struct packed_git **packs;
@@ -210,6 +211,19 @@ struct packed_git *packfile_store_load_pack(struct packfile_store *store,
211 int packfile_store_freshen_object(struct packfile_store *store,
212 const struct object_id *oid);
213
214 +enum kept_pack_type {
215 + KEPT_PACK_ON_DISK = (1 << 0),
216 + KEPT_PACK_IN_CORE = (1 << 1),
217 +};
218 +
219 +/*
220 + * Retrieve the cache of kept packs from the given packfile store. Accepts a
221 + * combination of `kept_pack_type` flags. The cache is computed on demand and
222 + * will be recomputed whenever the flags change.
223 + */
224 +struct packed_git **packfile_store_get_kept_pack_cache(struct packfile_store *store,
225 + unsigned flags);
226 +
227 struct pack_window {
228 struct pack_window *next;
229 unsigned char *base;
@@ -385,9 +399,6 @@ int packed_object_info(struct repository *r,
399 void mark_bad_packed_object(struct packed_git *, const struct object_id *);
400 const struct packed_git *has_packed_and_bad(struct repository *, const struct object_id *);
401
388 -#define ON_DISK_KEEP_PACKS 1
389 -#define IN_CORE_KEEP_PACKS 2
390 -
402 /*
403 * Iff a pack file in the given repository contains the object named by sha1,
404 * return true and store its location to e.
@@ -398,8 +409,6 @@ int has_object_pack(struct repository *r, const struct object_id *oid);
409 int has_object_kept_pack(struct repository *r, const struct object_id *oid,
410 unsigned flags);
411
401 -struct packed_git **kept_pack_cache(struct repository *r, unsigned flags);
402 -
412 /*
413 * Return 1 if an object in a promisor packfile is or refers to the given
414 * object, 0 otherwise.
reachable.c
+1 -1
@@ -242,7 +242,7 @@ static int want_recent_object(struct recent_data *data,
242 const struct object_id *oid)
243 {
244 if (data->ignore_in_core_kept_packs &&
245 - has_object_kept_pack(data->revs->repo, oid, IN_CORE_KEEP_PACKS))
245 + has_object_kept_pack(data->revs->repo, oid, KEPT_PACK_IN_CORE))
246 return 0;
247 return 1;
248 }
revision.c
+4 -4
@@ -2541,14 +2541,14 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
2541 die(_("--unpacked=<packfile> no longer supported"));
2542 } else if (!strcmp(arg, "--no-kept-objects")) {
2543 revs->no_kept_objects = 1;
2544 - revs->keep_pack_cache_flags |= IN_CORE_KEEP_PACKS;
2545 - revs->keep_pack_cache_flags |= ON_DISK_KEEP_PACKS;
2544 + revs->keep_pack_cache_flags |= KEPT_PACK_IN_CORE;
2545 + revs->keep_pack_cache_flags |= KEPT_PACK_ON_DISK;
2546 } else if (skip_prefix(arg, "--no-kept-objects=", &optarg)) {
2547 revs->no_kept_objects = 1;
2548 if (!strcmp(optarg, "in-core"))
2549 - revs->keep_pack_cache_flags |= IN_CORE_KEEP_PACKS;
2549 + revs->keep_pack_cache_flags |= KEPT_PACK_IN_CORE;
2550 if (!strcmp(optarg, "on-disk"))
2551 - revs->keep_pack_cache_flags |= ON_DISK_KEEP_PACKS;
2551 + revs->keep_pack_cache_flags |= KEPT_PACK_ON_DISK;
2552 } else if (!strcmp(arg, "-r")) {
2553 revs->diff = 1;
2554 revs->diffopt.flags.recursive = 1;