packfile: split up responsibilities of `reprepare_packed_git()`

In `reprepare_packed_git()` we perform a couple of operations: - We reload alternate object directories. - We clear the loose object cache. - We reprepare packfiles. While the logic is hosted in "packfile.c", it clearly reaches into other subsystems that aren't related to packfiles. Split up the responsibility and introduce `odb_reprepare()` which now becomes responsible for repreparing the whole object database. The existing `reprepare_packed_git()` function is refactored accordingly and only cares about reloading the packfile store now. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Sep 23, 2025 at 12:17 UTC 78237ea53d6546aeab7adb2c7547a1177311ccde
13 files changed +55 -35
builtin/backfill.c
+1 -1
@@ -53,7 +53,7 @@ static void download_batch(struct backfill_context *ctx)
53 * We likely have a new packfile. Add it to the packed list to
54 * avoid possible duplicate downloads of the same objects.
55 */
56 - reprepare_packed_git(ctx->repo);
56 + odb_reprepare(ctx->repo->objects);
57 }
58
59 static int fill_missing_blobs(const char *path UNUSED,
builtin/gc.c
+2 -2
@@ -1042,7 +1042,7 @@ int cmd_gc(int argc,
1042 die(FAILED_RUN, "rerere");
1043
1044 report_garbage = report_pack_garbage;
1045 - reprepare_packed_git(the_repository);
1045 + odb_reprepare(the_repository->objects);
1046 if (pack_garbage.nr > 0) {
1047 close_object_store(the_repository->objects);
1048 clean_pack_garbage();
@@ -1491,7 +1491,7 @@ static off_t get_auto_pack_size(void)
1491 struct packed_git *p;
1492 struct repository *r = the_repository;
1493
1494 - reprepare_packed_git(r);
1494 + odb_reprepare(r->objects);
1495 for (p = get_all_packs(r); p; p = p->next) {
1496 if (p->pack_size > max_size) {
1497 second_largest_size = max_size;
builtin/receive-pack.c
+1 -1
@@ -2389,7 +2389,7 @@ static const char *unpack(int err_fd, struct shallow_info *si)
2389 status = finish_command(&child);
2390 if (status)
2391 return "index-pack abnormal exit";
2392 - reprepare_packed_git(the_repository);
2392 + odb_reprepare(the_repository->objects);
2393 }
2394 return NULL;
2395 }
builtin/repack.c
+1 -1
@@ -1685,7 +1685,7 @@ int cmd_repack(int argc,
1685 goto cleanup;
1686 }
1687
1688 - reprepare_packed_git(the_repository);
1688 + odb_reprepare(the_repository->objects);
1689
1690 if (delete_redundant) {
1691 int opts = 0;
bulk-checkin.c
+1 -1
@@ -90,7 +90,7 @@ clear_exit:
90
91 strbuf_release(&packname);
92 /* Make objects we just wrote available to ourselves */
93 - reprepare_packed_git(the_repository);
93 + odb_reprepare(the_repository->objects);
94 }
95
96 /*
connected.c
+1 -1
@@ -72,7 +72,7 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
72 * Before checking for promisor packs, be sure we have the
73 * latest pack-files loaded into memory.
74 */
75 - reprepare_packed_git(the_repository);
75 + odb_reprepare(the_repository->objects);
76 do {
77 struct packed_git *p;
78
fetch-pack.c
+2 -2
@@ -1983,7 +1983,7 @@ static void update_shallow(struct fetch_pack_args *args,
1983 * remote is shallow, but this is a clone, there are
1984 * no objects in repo to worry about. Accept any
1985 * shallow points that exist in the pack (iow in repo
1986 - * after get_pack() and reprepare_packed_git())
1986 + * after get_pack() and odb_reprepare())
1987 */
1988 struct oid_array extra = OID_ARRAY_INIT;
1989 struct object_id *oid = si->shallow->oid;
@@ -2108,7 +2108,7 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
2108 ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought,
2109 &si, pack_lockfiles);
2110 }
2111 - reprepare_packed_git(the_repository);
2111 + odb_reprepare(the_repository->objects);
2112
2113 if (!args->cloning && args->deepen) {
2114 struct check_connected_options opt = CHECK_CONNECTED_INIT;
object-name.c
+1 -1
@@ -596,7 +596,7 @@ static enum get_oid_result get_short_oid(struct repository *r,
596 * or migrated from loose to packed.
597 */
598 if (status == MISSING_OBJECT) {
599 - reprepare_packed_git(r);
599 + odb_reprepare(r->objects);
600 find_short_object_filename(&ds);
601 find_short_packed_object(&ds);
602 status = finish_object_disambiguation(&ds, oid);
odb.c
+26 -1
@@ -694,7 +694,7 @@ static int do_oid_object_info_extended(struct object_database *odb,
694
695 /* Not a loose object; someone else may have just packed it. */
696 if (!(flags & OBJECT_INFO_QUICK)) {
697 - reprepare_packed_git(odb->repo);
697 + odb_reprepare(odb->repo->objects);
698 if (find_pack_entry(odb->repo, real, &e))
699 break;
700 }
@@ -1040,3 +1040,28 @@ void odb_clear(struct object_database *o)
1040
1041 string_list_clear(&o->submodule_source_paths, 0);
1042 }
1043 +
1044 +void odb_reprepare(struct object_database *o)
1045 +{
1046 + struct odb_source *source;
1047 +
1048 + obj_read_lock();
1049 +
1050 + /*
1051 + * Reprepare alt odbs, in case the alternates file was modified
1052 + * during the course of this process. This only _adds_ odbs to
1053 + * the linked list, so existing odbs will continue to exist for
1054 + * the lifetime of the process.
1055 + */
1056 + o->loaded_alternates = 0;
1057 + odb_prepare_alternates(o);
1058 +
1059 + for (source = o->sources; source; source = source->next)
1060 + odb_clear_loose_cache(source);
1061 +
1062 + o->approximate_object_count_valid = 0;
1063 +
1064 + packfile_store_reprepare(o->packfiles);
1065 +
1066 + obj_read_unlock();
1067 +}
odb.h
+6
@@ -161,6 +161,12 @@ struct object_database {
161 struct object_database *odb_new(struct repository *repo);
162 void odb_clear(struct object_database *o);
163
164 +/*
165 + * Clear caches, reload alternates and then reload object sources so that new
166 + * objects may become accessible.
167 + */
168 +void odb_reprepare(struct object_database *o);
169 +
170 /*
171 * Find source by its object directory path. Returns a `NULL` pointer in case
172 * the source could not be found.
packfile.c
+4 -22
@@ -1002,28 +1002,10 @@ static void packfile_store_prepare(struct packfile_store *store)
1002 store->initialized = true;
1003 }
1004
1005 -void reprepare_packed_git(struct repository *r)
1005 +void packfile_store_reprepare(struct packfile_store *store)
1006 {
1007 - struct odb_source *source;
1008 -
1009 - obj_read_lock();
1010 -
1011 - /*
1012 - * Reprepare alt odbs, in case the alternates file was modified
1013 - * during the course of this process. This only _adds_ odbs to
1014 - * the linked list, so existing odbs will continue to exist for
1015 - * the lifetime of the process.
1016 - */
1017 - r->objects->loaded_alternates = 0;
1018 - odb_prepare_alternates(r->objects);
1019 -
1020 - for (source = r->objects->sources; source; source = source->next)
1021 - odb_clear_loose_cache(source);
1022 -
1023 - r->objects->approximate_object_count_valid = 0;
1024 - r->objects->packfiles->initialized = false;
1025 - packfile_store_prepare(r->objects->packfiles);
1026 - obj_read_unlock();
1007 + store->initialized = false;
1008 + packfile_store_prepare(store);
1009 }
1010
1011 struct packed_git *get_packed_git(struct repository *r)
@@ -1144,7 +1126,7 @@ unsigned long get_size_from_delta(struct packed_git *p,
1126 *
1127 * Other worrying sections could be the call to close_pack_fd(),
1128 * which can close packs even with in-use windows, and to
1147 - * reprepare_packed_git(). Regarding the former, mmap doc says:
1129 + * odb_reprepare(). Regarding the former, mmap doc says:
1130 * "closing the file descriptor does not unmap the region". And
1131 * for the latter, it won't re-open already available packs.
1132 */
packfile.h
+8 -1
@@ -112,6 +112,14 @@ void packfile_store_free(struct packfile_store *store);
112 */
113 void packfile_store_close(struct packfile_store *store);
114
115 +/*
116 + * Clear the packfile caches and try to look up any new packfiles that have
117 + * appeared since last preparing the packfiles store.
118 + *
119 + * This function must be called under the `odb_read_lock()`.
120 + */
121 +void packfile_store_reprepare(struct packfile_store *store);
122 +
123 struct pack_window {
124 struct pack_window *next;
125 unsigned char *base;
@@ -188,7 +196,6 @@ int for_each_packed_object(struct repository *repo, each_packed_object_fn cb,
196 #define PACKDIR_FILE_GARBAGE 4
197 extern void (*report_garbage)(unsigned seen_bits, const char *path);
198
191 -void reprepare_packed_git(struct repository *r);
199 void install_packed_git(struct repository *r, struct packed_git *pack);
200
201 struct packed_git *get_packed_git(struct repository *r);
transport-helper.c
+1 -1
@@ -450,7 +450,7 @@ static int fetch_with_fetch(struct transport *transport,
450 }
451 strbuf_release(&buf);
452
453 - reprepare_packed_git(the_repository);
453 + odb_reprepare(the_repository->objects);
454 return 0;
455 }
456