packfile: move packfile store into object source

The packfile store is a member of `struct object_database`, which means that we have a single store per database. This doesn't really make much sense though: each source connected to the database has its own set of packfiles, so there is a conceptual mismatch here. This hasn't really caused much of a problem in the past, but with the advent of pluggable object databases this is becoming more of a problem because some of the sources may not even use packfiles in the first place. Move the packfile store down by one level from the object database into the object database source. This ensures that each source now has its own packfile store, and we can eventually start to abstract it away entirely so that the caller doesn't even know what kind of store it uses. Note that we only need to adjust a relatively small number of callers, way less than one might expect. This is because most callers are using `repo_for_each_pack()`, which handles enumeration of all packfiles that exist in the repository. So for now, none of these callers need to be adapted. The remaining callers that iterate through the packfiles directly and that need adjustment are those that are a bit more tangled with packfiles. These will be adjusted over time. Note that this patch only moves the packfile store, and there is still a bunch of functions that seemingly operate on a packfile store but that end up iterating over all sources. These will be adjusted in subsequent commits. 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 84f0e60b28de69d1ccb7a51b729af6202b6cf4c8
11 files changed +243 -145
builtin/fast-import.c
+23 -14
@@ -900,7 +900,7 @@ static void end_packfile(void)
900 idx_name = keep_pack(create_index());
901
902 /* Register the packfile with core git's machinery. */
903 - new_p = packfile_store_load_pack(pack_data->repo->objects->packfiles,
903 + new_p = packfile_store_load_pack(pack_data->repo->objects->sources->packfiles,
904 idx_name, 1);
905 if (!new_p)
906 die(_("core Git rejected index %s"), idx_name);
@@ -955,7 +955,7 @@ static int store_object(
955 struct object_id *oidout,
956 uintmax_t mark)
957 {
958 - struct packfile_store *packs = the_repository->objects->packfiles;
958 + struct odb_source *source;
959 void *out, *delta;
960 struct object_entry *e;
961 unsigned char hdr[96];
@@ -979,7 +979,11 @@ static int store_object(
979 if (e->idx.offset) {
980 duplicate_count_by_type[type]++;
981 return 1;
982 - } else if (packfile_list_find_oid(packfile_store_get_packs(packs), &oid)) {
982 + }
983 +
984 + for (source = the_repository->objects->sources; source; source = source->next) {
985 + if (!packfile_list_find_oid(packfile_store_get_packs(source->packfiles), &oid))
986 + continue;
987 e->type = type;
988 e->pack_id = MAX_PACK_ID;
989 e->idx.offset = 1; /* just not zero! */
@@ -1096,10 +1100,10 @@ static void truncate_pack(struct hashfile_checkpoint *checkpoint)
1100
1101 static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
1102 {
1099 - struct packfile_store *packs = the_repository->objects->packfiles;
1103 size_t in_sz = 64 * 1024, out_sz = 64 * 1024;
1104 unsigned char *in_buf = xmalloc(in_sz);
1105 unsigned char *out_buf = xmalloc(out_sz);
1106 + struct odb_source *source;
1107 struct object_entry *e;
1108 struct object_id oid;
1109 unsigned long hdrlen;
@@ -1179,24 +1183,29 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
1183 if (e->idx.offset) {
1184 duplicate_count_by_type[OBJ_BLOB]++;
1185 truncate_pack(&checkpoint);
1186 + goto out;
1187 + }
1188
1183 - } else if (packfile_list_find_oid(packfile_store_get_packs(packs), &oid)) {
1189 + for (source = the_repository->objects->sources; source; source = source->next) {
1190 + if (!packfile_list_find_oid(packfile_store_get_packs(source->packfiles), &oid))
1191 + continue;
1192 e->type = OBJ_BLOB;
1193 e->pack_id = MAX_PACK_ID;
1194 e->idx.offset = 1; /* just not zero! */
1195 duplicate_count_by_type[OBJ_BLOB]++;
1196 truncate_pack(&checkpoint);
1189 -
1190 - } else {
1191 - e->depth = 0;
1192 - e->type = OBJ_BLOB;
1193 - e->pack_id = pack_id;
1194 - e->idx.offset = offset;
1195 - e->idx.crc32 = crc32_end(pack_file);
1196 - object_count++;
1197 - object_count_by_type[OBJ_BLOB]++;
1197 + goto out;
1198 }
1199
1200 + e->depth = 0;
1201 + e->type = OBJ_BLOB;
1202 + e->pack_id = pack_id;
1203 + e->idx.offset = offset;
1204 + e->idx.crc32 = crc32_end(pack_file);
1205 + object_count++;
1206 + object_count_by_type[OBJ_BLOB]++;
1207 +
1208 +out:
1209 free(in_buf);
1210 free(out_buf);
1211 }
builtin/grep.c
+5 -1
@@ -1213,8 +1213,12 @@ int cmd_grep(int argc,
1213 */
1214 if (recurse_submodules)
1215 repo_read_gitmodules(the_repository, 1);
1216 + /*
1217 + * Note: `packfile_store_prepare()` prepares stores from all
1218 + * sources. This will be fixed in a subsequent commit.
1219 + */
1220 if (startup_info->have_repository)
1217 - packfile_store_prepare(the_repository->objects->packfiles);
1221 + packfile_store_prepare(the_repository->objects->sources->packfiles);
1222
1223 start_threads(&opt);
1224 } else {
builtin/index-pack.c
+1 -1
@@ -1638,7 +1638,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
1638 hash, "idx", 1);
1639
1640 if (do_fsck_object && startup_info->have_repository)
1641 - packfile_store_load_pack(the_repository->objects->packfiles,
1641 + packfile_store_load_pack(the_repository->objects->sources->packfiles,
1642 final_index_name, 0);
1643
1644 if (!from_stdin) {
builtin/pack-objects.c
+51 -45
@@ -1529,49 +1529,53 @@ 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 = packfile_store_get_kept_pack_cache(r->objects->packfiles, flags);
1532 + struct odb_source *source;
1533
1534 - for (; *cache; cache++) {
1535 - struct packed_git *p = *cache;
1536 - off_t ofs;
1537 - uint32_t candidate_mtime;
1534 + for (source = r->objects->sources; source; source = source->next) {
1535 + struct packed_git **cache = packfile_store_get_kept_pack_cache(source->packfiles, flags);
1536
1539 - ofs = find_pack_entry_one(oid, p);
1540 - if (!ofs)
1541 - continue;
1537 + for (; *cache; cache++) {
1538 + struct packed_git *p = *cache;
1539 + off_t ofs;
1540 + uint32_t candidate_mtime;
1541
1543 - /*
1544 - * We have a copy of the object 'oid' in a non-cruft
1545 - * pack. We can avoid packing an additional copy
1546 - * regardless of what the existing copy's mtime is since
1547 - * it is outside of a cruft pack.
1548 - */
1549 - if (!p->is_cruft)
1550 - return 0;
1551 -
1552 - /*
1553 - * If we have a copy of the object 'oid' in a cruft
1554 - * pack, then either read the cruft pack's mtime for
1555 - * that object, or, if that can't be loaded, assume the
1556 - * pack's mtime itself.
1557 - */
1558 - if (!load_pack_mtimes(p)) {
1559 - uint32_t pos;
1560 - if (offset_to_pack_pos(p, ofs, &pos) < 0)
1542 + ofs = find_pack_entry_one(oid, p);
1543 + if (!ofs)
1544 continue;
1562 - candidate_mtime = nth_packed_mtime(p, pos);
1563 - } else {
1564 - candidate_mtime = p->mtime;
1565 - }
1545
1567 - /*
1568 - * We have a surviving copy of the object in a cruft
1569 - * pack whose mtime is greater than or equal to the one
1570 - * we are considering. We can thus avoid packing an
1571 - * additional copy of that object.
1572 - */
1573 - if (mtime <= candidate_mtime)
1574 - return 0;
1546 + /*
1547 + * We have a copy of the object 'oid' in a non-cruft
1548 + * pack. We can avoid packing an additional copy
1549 + * regardless of what the existing copy's mtime is since
1550 + * it is outside of a cruft pack.
1551 + */
1552 + if (!p->is_cruft)
1553 + return 0;
1554 +
1555 + /*
1556 + * If we have a copy of the object 'oid' in a cruft
1557 + * pack, then either read the cruft pack's mtime for
1558 + * that object, or, if that can't be loaded, assume the
1559 + * pack's mtime itself.
1560 + */
1561 + if (!load_pack_mtimes(p)) {
1562 + uint32_t pos;
1563 + if (offset_to_pack_pos(p, ofs, &pos) < 0)
1564 + continue;
1565 + candidate_mtime = nth_packed_mtime(p, pos);
1566 + } else {
1567 + candidate_mtime = p->mtime;
1568 + }
1569 +
1570 + /*
1571 + * We have a surviving copy of the object in a cruft
1572 + * pack whose mtime is greater than or equal to the one
1573 + * we are considering. We can thus avoid packing an
1574 + * additional copy of that object.
1575 + */
1576 + if (mtime <= candidate_mtime)
1577 + return 0;
1578 + }
1579 }
1580
1581 return -1;
@@ -1749,13 +1753,15 @@ static int want_object_in_pack_mtime(const struct object_id *oid,
1753 }
1754 }
1755
1752 - for (e = the_repository->objects->packfiles->packs.head; e; e = e->next) {
1753 - struct packed_git *p = e->pack;
1754 - want = want_object_in_pack_one(p, oid, exclude, found_pack, found_offset, found_mtime);
1755 - if (!exclude && want > 0)
1756 - packfile_list_prepend(&the_repository->objects->packfiles->packs, p);
1757 - if (want != -1)
1758 - return want;
1756 + for (source = the_repository->objects->sources; source; source = source->next) {
1757 + for (e = source->packfiles->packs.head; e; e = e->next) {
1758 + struct packed_git *p = e->pack;
1759 + want = want_object_in_pack_one(p, oid, exclude, found_pack, found_offset, found_mtime);
1760 + if (!exclude && want > 0)
1761 + packfile_list_prepend(&source->packfiles->packs, p);
1762 + if (want != -1)
1763 + return want;
1764 + }
1765 }
1766
1767 if (uri_protocols.nr) {
http.c
+1 -1
@@ -2544,7 +2544,7 @@ void http_install_packfile(struct packed_git *p,
2544 struct packfile_list *list_to_remove_from)
2545 {
2546 packfile_list_remove(list_to_remove_from, p);
2547 - packfile_store_add_pack(the_repository->objects->packfiles, p);
2547 + packfile_store_add_pack(the_repository->objects->sources->packfiles, p);
2548 }
2549
2550 struct http_pack_request *new_http_pack_request(
midx.c
+2 -3
@@ -95,7 +95,7 @@ static int midx_read_object_offsets(const unsigned char *chunk_start,
95
96 struct multi_pack_index *get_multi_pack_index(struct odb_source *source)
97 {
98 - packfile_store_prepare(source->odb->packfiles);
98 + packfile_store_prepare(source->packfiles);
99 return source->midx;
100 }
101
@@ -447,7 +447,6 @@ static uint32_t midx_for_pack(struct multi_pack_index **_m,
447 int prepare_midx_pack(struct multi_pack_index *m,
448 uint32_t pack_int_id)
449 {
450 - struct repository *r = m->source->odb->repo;
450 struct strbuf pack_name = STRBUF_INIT;
451 struct packed_git *p;
452
@@ -460,7 +459,7 @@ int prepare_midx_pack(struct multi_pack_index *m,
459
460 strbuf_addf(&pack_name, "%s/pack/%s", m->source->path,
461 m->pack_names[pack_int_id]);
463 - p = packfile_store_load_pack(r->objects->packfiles,
462 + p = packfile_store_load_pack(m->source->packfiles,
463 pack_name.buf, m->source->local);
464 strbuf_release(&pack_name);
465
odb.c
+18 -18
@@ -155,6 +155,7 @@ static struct odb_source *odb_source_new(struct object_database *odb,
155 source->local = local;
156 source->path = xstrdup(path);
157 source->loose = odb_source_loose_new(source);
158 + source->packfiles = packfile_store_new(source);
159
160 return source;
161 }
@@ -373,6 +374,7 @@ static void odb_source_free(struct odb_source *source)
374 {
375 free(source->path);
376 odb_source_loose_free(source->loose);
377 + packfile_store_free(source->packfiles);
378 free(source);
379 }
380
@@ -704,19 +706,19 @@ static int do_oid_object_info_extended(struct object_database *odb,
706 while (1) {
707 struct odb_source *source;
708
707 - if (!packfile_store_read_object_info(odb->packfiles, real, oi, flags))
708 - return 0;
709 -
709 /* Most likely it's a loose object. */
711 - for (source = odb->sources; source; source = source->next)
712 - if (!odb_source_loose_read_object_info(source, real, oi, flags))
710 + for (source = odb->sources; source; source = source->next) {
711 + if (!packfile_store_read_object_info(source->packfiles, real, oi, flags) ||
712 + !odb_source_loose_read_object_info(source, real, oi, flags))
713 return 0;
714 + }
715
716 /* Not a loose object; someone else may have just packed it. */
717 if (!(flags & OBJECT_INFO_QUICK)) {
718 odb_reprepare(odb->repo->objects);
718 - if (!packfile_store_read_object_info(odb->packfiles, real, oi, flags))
719 - return 0;
719 + for (source = odb->sources; source; source = source->next)
720 + if (!packfile_store_read_object_info(source->packfiles, real, oi, flags))
721 + return 0;
722 }
723
724 /*
@@ -975,13 +977,14 @@ int odb_freshen_object(struct object_database *odb,
977 {
978 struct odb_source *source;
979
978 - if (packfile_store_freshen_object(odb->packfiles, oid))
979 - return 1;
980 -
980 odb_prepare_alternates(odb);
982 - for (source = odb->sources; source; source = source->next)
981 + for (source = odb->sources; source; source = source->next) {
982 + if (packfile_store_freshen_object(source->packfiles, oid))
983 + return 1;
984 +
985 if (odb_source_loose_freshen_object(source, oid))
986 return 1;
987 + }
988
989 return 0;
990 }
@@ -1064,7 +1067,6 @@ struct object_database *odb_new(struct repository *repo,
1067 o->sources = odb_source_new(o, primary_source, true);
1068 o->sources_tail = &o->sources->next;
1069 o->alternate_db = xstrdup_or_null(secondary_sources);
1067 - o->packfiles = packfile_store_new(o->sources);
1070
1071 free(to_free);
1072
@@ -1077,9 +1079,8 @@ void odb_close(struct object_database *o)
1079 {
1080 struct odb_source *source;
1081
1080 - packfile_store_close(o->packfiles);
1081 -
1082 for (source = o->sources; source; source = source->next) {
1083 + packfile_store_close(source->packfiles);
1084 if (source->midx)
1085 close_midx(source->midx);
1086 source->midx = NULL;
@@ -1118,7 +1119,6 @@ void odb_free(struct object_database *o)
1119 free((char *) o->cached_objects[i].value.buf);
1120 free(o->cached_objects);
1121
1121 - packfile_store_free(o->packfiles);
1122 string_list_clear(&o->submodule_source_paths, 0);
1123
1124 chdir_notify_unregister(NULL, odb_update_commondir, o);
@@ -1141,13 +1141,13 @@ void odb_reprepare(struct object_database *o)
1141 o->loaded_alternates = 0;
1142 odb_prepare_alternates(o);
1143
1144 - for (source = o->sources; source; source = source->next)
1144 + for (source = o->sources; source; source = source->next) {
1145 odb_source_loose_reprepare(source);
1146 + packfile_store_reprepare(source->packfiles);
1147 + }
1148
1149 o->approximate_object_count_valid = 0;
1150
1149 - packfile_store_reprepare(o->packfiles);
1150 -
1151 obj_read_unlock();
1152 }
1153
odb.h
+3 -3
@@ -51,6 +51,9 @@ struct odb_source {
51 /* Private state for loose objects. */
52 struct odb_source_loose *loose;
53
54 + /* Should only be accessed directly by packfile.c and midx.c. */
55 + struct packfile_store *packfiles;
56 +
57 /*
58 * private data
59 *
@@ -128,9 +131,6 @@ struct object_database {
131 struct commit_graph *commit_graph;
132 unsigned commit_graph_attempted : 1; /* if loading has been attempted */
133
131 - /* Should only be accessed directly by packfile.c and midx.c. */
132 - struct packfile_store *packfiles;
133 -
134 /*
135 * This is meant to hold a *small* number of objects that you would
136 * want odb_read_object() to be able to return, but yet you do not want
odb/streaming.c
+4 -5
@@ -185,13 +185,12 @@ static int istream_source(struct odb_read_stream **out,
185 {
186 struct odb_source *source;
187
188 - if (!packfile_store_read_object_stream(out, odb->packfiles, oid))
189 - return 0;
190 -
188 odb_prepare_alternates(odb);
192 - for (source = odb->sources; source; source = source->next)
193 - if (!odb_source_loose_read_object_stream(out, source, oid))
189 + for (source = odb->sources; source; source = source->next) {
190 + if (!packfile_store_read_object_stream(out, source->packfiles, oid) ||
191 + !odb_source_loose_read_object_stream(out, source, oid))
192 return 0;
193 + }
194
195 return open_istream_incore(out, odb, oid);
196 }
packfile.c
+81 -46
@@ -357,12 +357,14 @@ static void scan_windows(struct packed_git *p,
357
358 static int unuse_one_window(struct object_database *odb)
359 {
360 + struct odb_source *source;
361 struct packfile_list_entry *e;
362 struct packed_git *lru_p = NULL;
363 struct pack_window *lru_w = NULL, *lru_l = NULL;
364
364 - for (e = odb->packfiles->packs.head; e; e = e->next)
365 - scan_windows(e->pack, &lru_p, &lru_w, &lru_l);
365 + for (source = odb->sources; source; source = source->next)
366 + for (e = source->packfiles->packs.head; e; e = e->next)
367 + scan_windows(e->pack, &lru_p, &lru_w, &lru_l);
368
369 if (lru_p) {
370 munmap(lru_w->base, lru_w->len);
@@ -528,15 +530,18 @@ static void find_lru_pack(struct packed_git *p, struct packed_git **lru_p, struc
530
531 static int close_one_pack(struct repository *r)
532 {
533 + struct odb_source *source;
534 struct packfile_list_entry *e;
535 struct packed_git *lru_p = NULL;
536 struct pack_window *mru_w = NULL;
537 int accept_windows_inuse = 1;
538
536 - for (e = r->objects->packfiles->packs.head; e; e = e->next) {
537 - if (e->pack->pack_fd == -1)
538 - continue;
539 - find_lru_pack(e->pack, &lru_p, &mru_w, &accept_windows_inuse);
539 + for (source = r->objects->sources; source; source = source->next) {
540 + for (e = source->packfiles->packs.head; e; e = e->next) {
541 + if (e->pack->pack_fd == -1)
542 + continue;
543 + find_lru_pack(e->pack, &lru_p, &mru_w, &accept_windows_inuse);
544 + }
545 }
546
547 if (lru_p)
@@ -987,7 +992,7 @@ static void prepare_pack(const char *full_name, size_t full_name_len,
992 if (strip_suffix_mem(full_name, &base_len, ".idx") &&
993 !(data->source->midx && midx_contains_pack(data->source->midx, file_name))) {
994 char *trimmed_path = xstrndup(full_name, full_name_len);
990 - packfile_store_load_pack(data->source->odb->packfiles,
995 + packfile_store_load_pack(data->source->packfiles,
996 trimmed_path, data->source->local);
997 free(trimmed_path);
998 }
@@ -1245,11 +1250,15 @@ void mark_bad_packed_object(struct packed_git *p, const struct object_id *oid)
1250 const struct packed_git *has_packed_and_bad(struct repository *r,
1251 const struct object_id *oid)
1252 {
1248 - struct packfile_list_entry *e;
1253 + struct odb_source *source;
1254 +
1255 + for (source = r->objects->sources; source; source = source->next) {
1256 + struct packfile_list_entry *e;
1257 + for (e = source->packfiles->packs.head; e; e = e->next)
1258 + if (oidset_contains(&e->pack->bad_objects, oid))
1259 + return e->pack;
1260 + }
1261
1250 - for (e = r->objects->packfiles->packs.head; e; e = e->next)
1251 - if (oidset_contains(&e->pack->bad_objects, oid))
1252 - return e->pack;
1262 return NULL;
1263 }
1264
@@ -2089,26 +2098,32 @@ static int find_pack_entry(struct repository *r,
2098 const struct object_id *oid,
2099 struct pack_entry *e)
2100 {
2092 - struct packfile_list_entry *l;
2101 + struct odb_source *source;
2102
2094 - packfile_store_prepare(r->objects->packfiles);
2103 + /*
2104 + * Note: `packfile_store_prepare()` prepares stores from all sources.
2105 + * This will be fixed in a subsequent commit.
2106 + */
2107 + packfile_store_prepare(r->objects->sources->packfiles);
2108
2096 - for (struct odb_source *source = r->objects->sources; source; source = source->next)
2109 + for (source = r->objects->sources; source; source = source->next)
2110 if (source->midx && fill_midx_entry(source->midx, oid, e))
2111 return 1;
2112
2100 - if (!r->objects->packfiles->packs.head)
2101 - return 0;
2113 + for (source = r->objects->sources; source; source = source->next) {
2114 + struct packfile_list_entry *l;
2115
2103 - for (l = r->objects->packfiles->packs.head; l; l = l->next) {
2104 - struct packed_git *p = l->pack;
2116 + for (l = source->packfiles->packs.head; l; l = l->next) {
2117 + struct packed_git *p = l->pack;
2118
2106 - if (!p->multi_pack_index && fill_pack_entry(oid, e, p)) {
2107 - if (!r->objects->packfiles->skip_mru_updates)
2108 - packfile_list_prepend(&r->objects->packfiles->packs, p);
2109 - return 1;
2119 + if (!p->multi_pack_index && fill_pack_entry(oid, e, p)) {
2120 + if (!source->packfiles->skip_mru_updates)
2121 + packfile_list_prepend(&source->packfiles->packs, p);
2122 + return 1;
2123 + }
2124 }
2125 }
2126 +
2127 return 0;
2128 }
2129
@@ -2216,12 +2231,18 @@ int find_kept_pack_entry(struct repository *r,
2231 unsigned flags,
2232 struct pack_entry *e)
2233 {
2219 - struct packed_git **cache = packfile_store_get_kept_pack_cache(r->objects->packfiles, flags);
2234 + struct odb_source *source;
2235
2221 - for (; *cache; cache++) {
2222 - struct packed_git *p = *cache;
2223 - if (fill_pack_entry(oid, e, p))
2224 - return 1;
2236 + for (source = r->objects->sources; source; source = source->next) {
2237 + struct packed_git **cache;
2238 +
2239 + cache = packfile_store_get_kept_pack_cache(source->packfiles, flags);
2240 +
2241 + for (; *cache; cache++) {
2242 + struct packed_git *p = *cache;
2243 + if (fill_pack_entry(oid, e, p))
2244 + return 1;
2245 + }
2246 }
2247
2248 return 0;
@@ -2287,32 +2308,46 @@ int for_each_object_in_pack(struct packed_git *p,
2308 int for_each_packed_object(struct repository *repo, each_packed_object_fn cb,
2309 void *data, enum for_each_object_flags flags)
2310 {
2290 - struct packed_git *p;
2311 + struct odb_source *source;
2312 int r = 0;
2313 int pack_errors = 0;
2314
2294 - repo->objects->packfiles->skip_mru_updates = true;
2295 - repo_for_each_pack(repo, p) {
2296 - if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
2297 - continue;
2298 - if ((flags & FOR_EACH_OBJECT_PROMISOR_ONLY) &&
2299 - !p->pack_promisor)
2300 - continue;
2301 - if ((flags & FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS) &&
2302 - p->pack_keep_in_core)
2303 - continue;
2304 - if ((flags & FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS) &&
2305 - p->pack_keep)
2306 - continue;
2307 - if (open_pack_index(p)) {
2308 - pack_errors = 1;
2309 - continue;
2315 + odb_prepare_alternates(repo->objects);
2316 +
2317 + for (source = repo->objects->sources; source; source = source->next) {
2318 + struct packfile_list_entry *e;
2319 +
2320 + source->packfiles->skip_mru_updates = true;
2321 +
2322 + for (e = packfile_store_get_packs(source->packfiles); e; e = e->next) {
2323 + struct packed_git *p = e->pack;
2324 +
2325 + if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
2326 + continue;
2327 + if ((flags & FOR_EACH_OBJECT_PROMISOR_ONLY) &&
2328 + !p->pack_promisor)
2329 + continue;
2330 + if ((flags & FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS) &&
2331 + p->pack_keep_in_core)
2332 + continue;
2333 + if ((flags & FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS) &&
2334 + p->pack_keep)
2335 + continue;
2336 + if (open_pack_index(p)) {
2337 + pack_errors = 1;
2338 + continue;
2339 + }
2340 +
2341 + r = for_each_object_in_pack(p, cb, data, flags);
2342 + if (r)
2343 + break;
2344 }
2311 - r = for_each_object_in_pack(p, cb, data, flags);
2345 +
2346 + source->packfiles->skip_mru_updates = false;
2347 +
2348 if (r)
2349 break;
2350 }
2315 - repo->objects->packfiles->skip_mru_updates = false;
2351
2352 return r ? r : pack_errors;
2353 }
packfile.h
+54 -8
@@ -5,6 +5,7 @@
5 #include "object.h"
6 #include "odb.h"
7 #include "oidset.h"
8 +#include "repository.h"
9 #include "strmap.h"
10
11 /* in odb.h */
@@ -170,14 +171,65 @@ void packfile_store_reprepare(struct packfile_store *store);
171 void packfile_store_add_pack(struct packfile_store *store,
172 struct packed_git *pack);
173
174 +/*
175 + * Get all packs managed by the given store, including packfiles that are
176 + * referenced by multi-pack indices.
177 + */
178 +struct packfile_list_entry *packfile_store_get_packs(struct packfile_store *store);
179 +
180 +struct repo_for_each_pack_data {
181 + struct odb_source *source;
182 + struct packfile_list_entry *entry;
183 +};
184 +
185 +static inline struct repo_for_each_pack_data repo_for_eack_pack_data_init(struct repository *repo)
186 +{
187 + struct repo_for_each_pack_data data = { 0 };
188 +
189 + odb_prepare_alternates(repo->objects);
190 +
191 + for (struct odb_source *source = repo->objects->sources; source; source = source->next) {
192 + struct packfile_list_entry *entry = packfile_store_get_packs(source->packfiles);
193 + if (!entry)
194 + continue;
195 + data.source = source;
196 + data.entry = entry;
197 + break;
198 + }
199 +
200 + return data;
201 +}
202 +
203 +static inline void repo_for_each_pack_data_next(struct repo_for_each_pack_data *data)
204 +{
205 + struct odb_source *source;
206 +
207 + data->entry = data->entry->next;
208 + if (data->entry)
209 + return;
210 +
211 + for (source = data->source->next; source; source = source->next) {
212 + struct packfile_list_entry *entry = packfile_store_get_packs(source->packfiles);
213 + if (!entry)
214 + continue;
215 + data->source = source;
216 + data->entry = entry;
217 + return;
218 + }
219 +
220 + data->source = NULL;
221 + data->entry = NULL;
222 +}
223 +
224 /*
225 * Load and iterate through all packs of the given repository. This helper
226 * function will yield packfiles from all object sources connected to the
227 * repository.
228 */
229 #define repo_for_each_pack(repo, p) \
179 - for (struct packfile_list_entry *e = packfile_store_get_packs(repo->objects->packfiles); \
180 - ((p) = (e ? e->pack : NULL)); e = e->next)
230 + for (struct repo_for_each_pack_data eack_pack_data = repo_for_eack_pack_data_init(repo); \
231 + ((p) = (eack_pack_data.entry ? eack_pack_data.entry->pack : NULL)); \
232 + repo_for_each_pack_data_next(&eack_pack_data))
233
234 int packfile_store_read_object_stream(struct odb_read_stream **out,
235 struct packfile_store *store,
@@ -194,12 +246,6 @@ int packfile_store_read_object_info(struct packfile_store *store,
246 struct object_info *oi,
247 unsigned flags);
248
197 -/*
198 - * Get all packs managed by the given store, including packfiles that are
199 - * referenced by multi-pack indices.
200 - */
201 -struct packfile_list_entry *packfile_store_get_packs(struct packfile_store *store);
202 -
249 /*
250 * Open the packfile and add it to the store if it isn't yet known. Returns
251 * either the newly opened packfile or the preexisting packfile. Returns a