odb/source-packed: wire up `for_each_object()` callback
Move `packfile_store_for_each_object()` and its associated helpers from "packfile.c" into "odb/source-packed.c" and wire it up as the `for_each_object()` callback of the "packed" source. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Patrick Steinhardt committed
Jun 17, 2026 at 08:39 UTC
7ed53cde288a1e5558acac33f2d89f17b81618e2
7 files changed
+269
-280
builtin/cat-file.c
+2
-2
@@ -916,8 +916,8 @@ static void batch_each_object(struct batch_options *opt,
916
917
for (source = the_repository->objects->sources; source; source = source->next) {
918
struct odb_source_files *files = odb_source_files_downcast(source);
919
- int ret = packfile_store_for_each_object(files->packed, &oi,
920
- batch_one_object_oi, &payload, &opts);
919
+ int ret = odb_source_for_each_object(&files->packed->base, &oi,
920
+ batch_one_object_oi, &payload, &opts);
921
if (ret)
922
break;
923
}
builtin/pack-objects.c
+2
-2
@@ -4503,8 +4503,8 @@ static void add_objects_in_unpacked_packs(void)
4503
if (!source->local)
4504
continue;
4505
4506
- if (packfile_store_for_each_object(files->packed, &oi,
4507
- add_object_in_unpacked_pack, NULL, &opts))
4506
+ if (odb_source_for_each_object(&files->packed->base, &oi,
4507
+ add_object_in_unpacked_pack, NULL, &opts))
4508
die(_("cannot open pack index"));
4509
}
4510
}
commit-graph.c
+2
-2
@@ -2016,8 +2016,8 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)
2016
odb_prepare_alternates(ctx->r->objects);
2017
for (source = ctx->r->objects->sources; source; source = source->next) {
2018
struct odb_source_files *files = odb_source_files_downcast(source);
2019
- packfile_store_for_each_object(files->packed, &oi, add_packed_commits_oi,
2020
- ctx, &opts);
2019
+ odb_source_for_each_object(&files->packed->base, &oi, add_packed_commits_oi,
2020
+ ctx, &opts);
2021
}
2022
2023
if (ctx->progress_done < ctx->approx_nr_objects)
odb/source-files.c
+1
-1
@@ -88,7 +88,7 @@ static int odb_source_files_for_each_object(struct odb_source *source,
88
return ret;
89
}
90
91
- ret = packfile_store_for_each_object(files->packed, request, cb, cb_data, opts);
91
+ ret = odb_source_for_each_object(&files->packed->base, request, cb, cb_data, opts);
92
if (ret)
93
return ret;
94
odb/source-packed.c
+258
@@ -81,6 +81,263 @@ static int odb_source_packed_read_object_stream(struct odb_read_stream **out,
81
return packfile_read_object_stream(out, oid, e.p, e.offset);
82
}
83
84
+struct odb_source_packed_for_each_object_wrapper_data {
85
+ struct odb_source_packed *store;
86
+ const struct object_info *request;
87
+ odb_for_each_object_cb cb;
88
+ void *cb_data;
89
+};
90
+
91
+static int odb_source_packed_for_each_object_wrapper(const struct object_id *oid,
92
+ struct packed_git *pack,
93
+ uint32_t index_pos,
94
+ void *cb_data)
95
+{
96
+ struct odb_source_packed_for_each_object_wrapper_data *data = cb_data;
97
+
98
+ if (data->request) {
99
+ off_t offset = nth_packed_object_offset(pack, index_pos);
100
+ struct object_info oi = *data->request;
101
+
102
+ if (packed_object_info_with_index_pos(pack, offset,
103
+ &index_pos, &oi) < 0) {
104
+ mark_bad_packed_object(pack, oid);
105
+ return -1;
106
+ }
107
+
108
+ return data->cb(oid, &oi, data->cb_data);
109
+ } else {
110
+ return data->cb(oid, NULL, data->cb_data);
111
+ }
112
+}
113
+
114
+static int match_hash(unsigned len, const unsigned char *a, const unsigned char *b)
115
+{
116
+ do {
117
+ if (*a != *b)
118
+ return 0;
119
+ a++;
120
+ b++;
121
+ len -= 2;
122
+ } while (len > 1);
123
+ if (len)
124
+ if ((*a ^ *b) & 0xf0)
125
+ return 0;
126
+ return 1;
127
+}
128
+
129
+static int for_each_prefixed_object_in_midx(
130
+ struct odb_source_packed *store,
131
+ struct multi_pack_index *m,
132
+ const struct odb_for_each_object_options *opts,
133
+ struct odb_source_packed_for_each_object_wrapper_data *data)
134
+{
135
+ int ret;
136
+
137
+ for (; m; m = m->base_midx) {
138
+ uint32_t num, i, first = 0;
139
+ int len = opts->prefix_hex_len > m->source->odb->repo->hash_algo->hexsz ?
140
+ m->source->odb->repo->hash_algo->hexsz : opts->prefix_hex_len;
141
+
142
+ if (!m->num_objects)
143
+ continue;
144
+
145
+ num = m->num_objects + m->num_objects_in_base;
146
+
147
+ bsearch_one_midx(opts->prefix, m, &first);
148
+
149
+ /*
150
+ * At this point, "first" is the location of the lowest
151
+ * object with an object name that could match "opts->prefix".
152
+ * See if we have 0, 1 or more objects that actually match(es).
153
+ */
154
+ for (i = first; i < num; i++) {
155
+ const struct object_id *current = NULL;
156
+ struct object_id oid;
157
+
158
+ current = nth_midxed_object_oid(&oid, m, i);
159
+
160
+ if (!match_hash(len, opts->prefix->hash, current->hash))
161
+ break;
162
+
163
+ if (data->request) {
164
+ struct object_info oi = *data->request;
165
+
166
+ ret = odb_source_read_object_info(&store->base, current,
167
+ &oi, 0);
168
+ if (ret)
169
+ goto out;
170
+
171
+ ret = data->cb(&oid, &oi, data->cb_data);
172
+ if (ret)
173
+ goto out;
174
+ } else {
175
+ ret = data->cb(&oid, NULL, data->cb_data);
176
+ if (ret)
177
+ goto out;
178
+ }
179
+ }
180
+ }
181
+
182
+ ret = 0;
183
+
184
+out:
185
+ return ret;
186
+}
187
+
188
+static int for_each_prefixed_object_in_pack(
189
+ struct odb_source_packed *store,
190
+ struct packed_git *p,
191
+ const struct odb_for_each_object_options *opts,
192
+ struct odb_source_packed_for_each_object_wrapper_data *data)
193
+{
194
+ uint32_t num, i, first = 0;
195
+ int len = opts->prefix_hex_len > p->repo->hash_algo->hexsz ?
196
+ p->repo->hash_algo->hexsz : opts->prefix_hex_len;
197
+ int ret;
198
+
199
+ num = p->num_objects;
200
+ bsearch_pack(opts->prefix, p, &first);
201
+
202
+ /*
203
+ * At this point, "first" is the location of the lowest object
204
+ * with an object name that could match "bin_pfx". See if we have
205
+ * 0, 1 or more objects that actually match(es).
206
+ */
207
+ for (i = first; i < num; i++) {
208
+ struct object_id oid;
209
+
210
+ nth_packed_object_id(&oid, p, i);
211
+ if (!match_hash(len, opts->prefix->hash, oid.hash))
212
+ break;
213
+
214
+ if (data->request) {
215
+ struct object_info oi = *data->request;
216
+
217
+ ret = odb_source_read_object_info(&store->base, &oid, &oi, 0);
218
+ if (ret)
219
+ goto out;
220
+
221
+ ret = data->cb(&oid, &oi, data->cb_data);
222
+ if (ret)
223
+ goto out;
224
+ } else {
225
+ ret = data->cb(&oid, NULL, data->cb_data);
226
+ if (ret)
227
+ goto out;
228
+ }
229
+ }
230
+
231
+ ret = 0;
232
+
233
+out:
234
+ return ret;
235
+}
236
+
237
+static int odb_source_packed_for_each_prefixed_object(
238
+ struct odb_source_packed *store,
239
+ const struct odb_for_each_object_options *opts,
240
+ struct odb_source_packed_for_each_object_wrapper_data *data)
241
+{
242
+ struct packfile_list_entry *e;
243
+ struct multi_pack_index *m;
244
+ bool pack_errors = false;
245
+ int ret;
246
+
247
+ if (opts->flags)
248
+ BUG("flags unsupported");
249
+
250
+ store->skip_mru_updates = true;
251
+
252
+ m = get_multi_pack_index(&store->files->base);
253
+ if (m) {
254
+ ret = for_each_prefixed_object_in_midx(store, m, opts, data);
255
+ if (ret)
256
+ goto out;
257
+ }
258
+
259
+ for (e = packfile_store_get_packs(store); e; e = e->next) {
260
+ if (e->pack->multi_pack_index)
261
+ continue;
262
+
263
+ if (open_pack_index(e->pack)) {
264
+ pack_errors = true;
265
+ continue;
266
+ }
267
+
268
+ if (!e->pack->num_objects)
269
+ continue;
270
+
271
+ ret = for_each_prefixed_object_in_pack(store, e->pack, opts, data);
272
+ if (ret)
273
+ goto out;
274
+ }
275
+
276
+ ret = 0;
277
+
278
+out:
279
+ store->skip_mru_updates = false;
280
+ if (!ret && pack_errors)
281
+ ret = -1;
282
+ return ret;
283
+}
284
+
285
+static int odb_source_packed_for_each_object(struct odb_source *source,
286
+ const struct object_info *request,
287
+ odb_for_each_object_cb cb,
288
+ void *cb_data,
289
+ const struct odb_for_each_object_options *opts)
290
+{
291
+ struct odb_source_packed *packed = odb_source_packed_downcast(source);
292
+ struct odb_source_packed_for_each_object_wrapper_data data = {
293
+ .store = packed,
294
+ .request = request,
295
+ .cb = cb,
296
+ .cb_data = cb_data,
297
+ };
298
+ struct packfile_list_entry *e;
299
+ int pack_errors = 0, ret;
300
+
301
+ if (opts->prefix)
302
+ return odb_source_packed_for_each_prefixed_object(packed, opts, &data);
303
+
304
+ packed->skip_mru_updates = true;
305
+
306
+ for (e = packfile_store_get_packs(packed); e; e = e->next) {
307
+ struct packed_git *p = e->pack;
308
+
309
+ if ((opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
310
+ continue;
311
+ if ((opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY) &&
312
+ !p->pack_promisor)
313
+ continue;
314
+ if ((opts->flags & ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS) &&
315
+ p->pack_keep_in_core)
316
+ continue;
317
+ if ((opts->flags & ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS) &&
318
+ p->pack_keep)
319
+ continue;
320
+ if (open_pack_index(p)) {
321
+ pack_errors = 1;
322
+ continue;
323
+ }
324
+
325
+ ret = for_each_object_in_pack(p, odb_source_packed_for_each_object_wrapper,
326
+ &data, opts->flags);
327
+ if (ret)
328
+ goto out;
329
+ }
330
+
331
+ ret = 0;
332
+
333
+out:
334
+ packed->skip_mru_updates = false;
335
+
336
+ if (!ret && pack_errors)
337
+ ret = -1;
338
+ return ret;
339
+}
340
+
341
void (*report_garbage)(unsigned seen_bits, const char *path);
342
343
static void report_helper(const struct string_list *list,
@@ -291,6 +548,7 @@ struct odb_source_packed *odb_source_packed_new(struct odb_source_files *parent)
548
packed->base.reprepare = odb_source_packed_reprepare;
549
packed->base.read_object_info = odb_source_packed_read_object_info;
550
packed->base.read_object_stream = odb_source_packed_read_object_stream;
551
+ packed->base.for_each_object = odb_source_packed_for_each_object;
552
553
if (!is_absolute_path(parent->base.path))
554
chdir_notify_register(NULL, odb_source_packed_reparent, packed);
packfile.c
+2
-258
@@ -1362,8 +1362,8 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
1362
hashmap_add(&delta_base_cache, &ent->ent);
1363
}
1364
1365
-static int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_offset,
1366
- uint32_t *maybe_index_pos, struct object_info *oi)
1365
+int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_offset,
1366
+ uint32_t *maybe_index_pos, struct object_info *oi)
1367
{
1368
struct pack_window *w_curs = NULL;
1369
size_t size;
@@ -2068,262 +2068,6 @@ int for_each_object_in_pack(struct packed_git *p,
2068
return r;
2069
}
2070
2071
-struct odb_source_packed_for_each_object_wrapper_data {
2072
- struct odb_source_packed *store;
2073
- const struct object_info *request;
2074
- odb_for_each_object_cb cb;
2075
- void *cb_data;
2076
-};
2077
-
2078
-static int packfile_store_for_each_object_wrapper(const struct object_id *oid,
2079
- struct packed_git *pack,
2080
- uint32_t index_pos,
2081
- void *cb_data)
2082
-{
2083
- struct odb_source_packed_for_each_object_wrapper_data *data = cb_data;
2084
-
2085
- if (data->request) {
2086
- off_t offset = nth_packed_object_offset(pack, index_pos);
2087
- struct object_info oi = *data->request;
2088
-
2089
- if (packed_object_info_with_index_pos(pack, offset,
2090
- &index_pos, &oi) < 0) {
2091
- mark_bad_packed_object(pack, oid);
2092
- return -1;
2093
- }
2094
-
2095
- return data->cb(oid, &oi, data->cb_data);
2096
- } else {
2097
- return data->cb(oid, NULL, data->cb_data);
2098
- }
2099
-}
2100
-
2101
-static int match_hash(unsigned len, const unsigned char *a, const unsigned char *b)
2102
-{
2103
- do {
2104
- if (*a != *b)
2105
- return 0;
2106
- a++;
2107
- b++;
2108
- len -= 2;
2109
- } while (len > 1);
2110
- if (len)
2111
- if ((*a ^ *b) & 0xf0)
2112
- return 0;
2113
- return 1;
2114
-}
2115
-
2116
-static int for_each_prefixed_object_in_midx(
2117
- struct odb_source_packed *store,
2118
- struct multi_pack_index *m,
2119
- const struct odb_for_each_object_options *opts,
2120
- struct odb_source_packed_for_each_object_wrapper_data *data)
2121
-{
2122
- int ret;
2123
-
2124
- for (; m; m = m->base_midx) {
2125
- uint32_t num, i, first = 0;
2126
- int len = opts->prefix_hex_len > m->source->odb->repo->hash_algo->hexsz ?
2127
- m->source->odb->repo->hash_algo->hexsz : opts->prefix_hex_len;
2128
-
2129
- if (!m->num_objects)
2130
- continue;
2131
-
2132
- num = m->num_objects + m->num_objects_in_base;
2133
-
2134
- bsearch_one_midx(opts->prefix, m, &first);
2135
-
2136
- /*
2137
- * At this point, "first" is the location of the lowest
2138
- * object with an object name that could match "opts->prefix".
2139
- * See if we have 0, 1 or more objects that actually match(es).
2140
- */
2141
- for (i = first; i < num; i++) {
2142
- const struct object_id *current = NULL;
2143
- struct object_id oid;
2144
-
2145
- current = nth_midxed_object_oid(&oid, m, i);
2146
-
2147
- if (!match_hash(len, opts->prefix->hash, current->hash))
2148
- break;
2149
-
2150
- if (data->request) {
2151
- struct object_info oi = *data->request;
2152
-
2153
- ret = odb_source_read_object_info(&store->base, current,
2154
- &oi, 0);
2155
- if (ret)
2156
- goto out;
2157
-
2158
- ret = data->cb(&oid, &oi, data->cb_data);
2159
- if (ret)
2160
- goto out;
2161
- } else {
2162
- ret = data->cb(&oid, NULL, data->cb_data);
2163
- if (ret)
2164
- goto out;
2165
- }
2166
- }
2167
- }
2168
-
2169
- ret = 0;
2170
-
2171
-out:
2172
- return ret;
2173
-}
2174
-
2175
-static int for_each_prefixed_object_in_pack(
2176
- struct odb_source_packed *store,
2177
- struct packed_git *p,
2178
- const struct odb_for_each_object_options *opts,
2179
- struct odb_source_packed_for_each_object_wrapper_data *data)
2180
-{
2181
- uint32_t num, i, first = 0;
2182
- int len = opts->prefix_hex_len > p->repo->hash_algo->hexsz ?
2183
- p->repo->hash_algo->hexsz : opts->prefix_hex_len;
2184
- int ret;
2185
-
2186
- num = p->num_objects;
2187
- bsearch_pack(opts->prefix, p, &first);
2188
-
2189
- /*
2190
- * At this point, "first" is the location of the lowest object
2191
- * with an object name that could match "bin_pfx". See if we have
2192
- * 0, 1 or more objects that actually match(es).
2193
- */
2194
- for (i = first; i < num; i++) {
2195
- struct object_id oid;
2196
-
2197
- nth_packed_object_id(&oid, p, i);
2198
- if (!match_hash(len, opts->prefix->hash, oid.hash))
2199
- break;
2200
-
2201
- if (data->request) {
2202
- struct object_info oi = *data->request;
2203
-
2204
- ret = odb_source_read_object_info(&store->base, &oid, &oi, 0);
2205
- if (ret)
2206
- goto out;
2207
-
2208
- ret = data->cb(&oid, &oi, data->cb_data);
2209
- if (ret)
2210
- goto out;
2211
- } else {
2212
- ret = data->cb(&oid, NULL, data->cb_data);
2213
- if (ret)
2214
- goto out;
2215
- }
2216
- }
2217
-
2218
- ret = 0;
2219
-
2220
-out:
2221
- return ret;
2222
-}
2223
-
2224
-static int packfile_store_for_each_prefixed_object(
2225
- struct odb_source_packed *store,
2226
- const struct odb_for_each_object_options *opts,
2227
- struct odb_source_packed_for_each_object_wrapper_data *data)
2228
-{
2229
- struct packfile_list_entry *e;
2230
- struct multi_pack_index *m;
2231
- bool pack_errors = false;
2232
- int ret;
2233
-
2234
- if (opts->flags)
2235
- BUG("flags unsupported");
2236
-
2237
- store->skip_mru_updates = true;
2238
-
2239
- m = get_multi_pack_index(&store->files->base);
2240
- if (m) {
2241
- ret = for_each_prefixed_object_in_midx(store, m, opts, data);
2242
- if (ret)
2243
- goto out;
2244
- }
2245
-
2246
- for (e = packfile_store_get_packs(store); e; e = e->next) {
2247
- if (e->pack->multi_pack_index)
2248
- continue;
2249
-
2250
- if (open_pack_index(e->pack)) {
2251
- pack_errors = true;
2252
- continue;
2253
- }
2254
-
2255
- if (!e->pack->num_objects)
2256
- continue;
2257
-
2258
- ret = for_each_prefixed_object_in_pack(store, e->pack, opts, data);
2259
- if (ret)
2260
- goto out;
2261
- }
2262
-
2263
- ret = 0;
2264
-
2265
-out:
2266
- store->skip_mru_updates = false;
2267
- if (!ret && pack_errors)
2268
- ret = -1;
2269
- return ret;
2270
-}
2271
-
2272
-int packfile_store_for_each_object(struct odb_source_packed *store,
2273
- const struct object_info *request,
2274
- odb_for_each_object_cb cb,
2275
- void *cb_data,
2276
- const struct odb_for_each_object_options *opts)
2277
-{
2278
- struct odb_source_packed_for_each_object_wrapper_data data = {
2279
- .store = store,
2280
- .request = request,
2281
- .cb = cb,
2282
- .cb_data = cb_data,
2283
- };
2284
- struct packfile_list_entry *e;
2285
- int pack_errors = 0, ret;
2286
-
2287
- if (opts->prefix)
2288
- return packfile_store_for_each_prefixed_object(store, opts, &data);
2289
-
2290
- store->skip_mru_updates = true;
2291
-
2292
- for (e = packfile_store_get_packs(store); e; e = e->next) {
2293
- struct packed_git *p = e->pack;
2294
-
2295
- if ((opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
2296
- continue;
2297
- if ((opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY) &&
2298
- !p->pack_promisor)
2299
- continue;
2300
- if ((opts->flags & ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS) &&
2301
- p->pack_keep_in_core)
2302
- continue;
2303
- if ((opts->flags & ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS) &&
2304
- p->pack_keep)
2305
- continue;
2306
- if (open_pack_index(p)) {
2307
- pack_errors = 1;
2308
- continue;
2309
- }
2310
-
2311
- ret = for_each_object_in_pack(p, packfile_store_for_each_object_wrapper,
2312
- &data, opts->flags);
2313
- if (ret)
2314
- goto out;
2315
- }
2316
-
2317
- ret = 0;
2318
-
2319
-out:
2320
- store->skip_mru_updates = false;
2321
-
2322
- if (!ret && pack_errors)
2323
- ret = -1;
2324
- return ret;
2325
-}
2326
-
2071
static int extend_abbrev_len(const struct object_id *a,
2072
const struct object_id *b,
2073
unsigned *out)
packfile.h
+2
-15
@@ -227,21 +227,6 @@ int for_each_object_in_pack(struct packed_git *p,
227
each_packed_object_fn, void *data,
228
enum odb_for_each_object_flags flags);
229
230
-/*
231
- * Iterate through all packed objects in the given packfile store and invoke
232
- * the callback function for each of them. If an object info request is given,
233
- * then the object info will be read for every individual object and passed to
234
- * the callback as if `packfile_store_read_object_info()` was called for the
235
- * object.
236
- *
237
- * The flags parameter is a combination of `odb_for_each_object_flags`.
238
- */
239
-int packfile_store_for_each_object(struct odb_source_packed *store,
240
- const struct object_info *request,
241
- odb_for_each_object_cb cb,
242
- void *cb_data,
243
- const struct odb_for_each_object_options *opts);
244
-
230
int packfile_store_find_abbrev_len(struct odb_source_packed *store,
231
const struct object_id *oid,
232
unsigned min_len,
@@ -354,6 +339,8 @@ extern int do_check_packed_object_crc;
339
*/
340
int packed_object_info(struct packed_git *pack,
341
off_t offset, struct object_info *);
342
+int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_offset,
343
+ uint32_t *maybe_index_pos, struct object_info *oi);
344
345
void mark_bad_packed_object(struct packed_git *, const struct object_id *);
346
const struct packed_git *has_packed_and_bad(struct repository *, const struct object_id *);