/src/git/pack-bitmap-write.c
Line | Count | Source |
1 | | #define DISABLE_SIGN_COMPARE_WARNINGS |
2 | | |
3 | | #include "git-compat-util.h" |
4 | | #include "environment.h" |
5 | | #include "gettext.h" |
6 | | #include "hex.h" |
7 | | #include "odb.h" |
8 | | #include "commit.h" |
9 | | #include "diff.h" |
10 | | #include "revision.h" |
11 | | #include "progress.h" |
12 | | #include "pack.h" |
13 | | #include "pack-bitmap.h" |
14 | | #include "hash-lookup.h" |
15 | | #include "pack-objects.h" |
16 | | #include "path.h" |
17 | | #include "commit-reach.h" |
18 | | #include "prio-queue.h" |
19 | | #include "trace2.h" |
20 | | #include "tree.h" |
21 | | #include "tree-walk.h" |
22 | | #include "pseudo-merge.h" |
23 | | #include "oid-array.h" |
24 | | #include "config.h" |
25 | | #include "alloc.h" |
26 | | #include "refs.h" |
27 | | #include "strmap.h" |
28 | | #include "midx.h" |
29 | | #include "pack-revindex.h" |
30 | | |
31 | | struct bitmapped_commit { |
32 | | struct commit *commit; |
33 | | struct ewah_bitmap *bitmap; |
34 | | struct ewah_bitmap *write_as; |
35 | | struct ewah_bitmap *pseudo_merge_parents; |
36 | | int flags; |
37 | | int xor_offset; |
38 | | uint32_t commit_pos; |
39 | | unsigned pseudo_merge : 1; |
40 | | }; |
41 | | |
42 | | static inline int bitmap_writer_nr_selected_commits(struct bitmap_writer *writer) |
43 | 0 | { |
44 | 0 | return writer->selected_nr - writer->pseudo_merges_nr; |
45 | 0 | } |
46 | | |
47 | | void bitmap_writer_init(struct bitmap_writer *writer, struct repository *r, |
48 | | struct packing_data *pdata, |
49 | | struct multi_pack_index *midx) |
50 | 0 | { |
51 | 0 | memset(writer, 0, sizeof(struct bitmap_writer)); |
52 | 0 | if (writer->bitmaps) |
53 | 0 | BUG("bitmap writer already initialized"); |
54 | 0 | writer->repo = r; |
55 | 0 | writer->bitmaps = kh_init_oid_map(); |
56 | 0 | writer->pseudo_merge_commits = kh_init_oid_map(); |
57 | 0 | writer->to_pack = pdata; |
58 | 0 | writer->midx = midx; |
59 | |
|
60 | 0 | string_list_init_dup(&writer->pseudo_merge_groups); |
61 | |
|
62 | 0 | load_pseudo_merges_from_config(r, &writer->pseudo_merge_groups); |
63 | 0 | } |
64 | | |
65 | | static void free_pseudo_merge_commit_idx(struct pseudo_merge_commit_idx *idx) |
66 | 0 | { |
67 | 0 | if (!idx) |
68 | 0 | return; |
69 | 0 | free(idx->pseudo_merge); |
70 | 0 | free(idx); |
71 | 0 | } |
72 | | |
73 | | static void pseudo_merge_group_release_cb(void *payload, const char *name UNUSED) |
74 | 0 | { |
75 | 0 | pseudo_merge_group_release(payload); |
76 | 0 | free(payload); |
77 | 0 | } |
78 | | |
79 | | void bitmap_writer_free(struct bitmap_writer *writer) |
80 | 0 | { |
81 | 0 | uint32_t i; |
82 | 0 | struct pseudo_merge_commit_idx *idx; |
83 | |
|
84 | 0 | if (!writer) |
85 | 0 | return; |
86 | | |
87 | 0 | ewah_free(writer->commits); |
88 | 0 | ewah_free(writer->trees); |
89 | 0 | ewah_free(writer->blobs); |
90 | 0 | ewah_free(writer->tags); |
91 | |
|
92 | 0 | kh_destroy_oid_map(writer->bitmaps); |
93 | 0 | free(writer->pos_cache); |
94 | |
|
95 | 0 | kh_foreach_value(writer->pseudo_merge_commits, idx, |
96 | 0 | free_pseudo_merge_commit_idx(idx)); |
97 | 0 | kh_destroy_oid_map(writer->pseudo_merge_commits); |
98 | 0 | string_list_clear_func(&writer->pseudo_merge_groups, |
99 | 0 | pseudo_merge_group_release_cb); |
100 | |
|
101 | 0 | for (i = 0; i < writer->selected_nr; i++) { |
102 | 0 | struct bitmapped_commit *bc = &writer->selected[i]; |
103 | 0 | if (bc->write_as != bc->bitmap) |
104 | 0 | ewah_free(bc->write_as); |
105 | 0 | ewah_free(bc->bitmap); |
106 | 0 | ewah_free(bc->pseudo_merge_parents); |
107 | 0 | } |
108 | 0 | free(writer->selected); |
109 | 0 | } |
110 | | |
111 | | void bitmap_writer_show_progress(struct bitmap_writer *writer, int show) |
112 | 0 | { |
113 | 0 | writer->show_progress = show; |
114 | 0 | } |
115 | | |
116 | | /** |
117 | | * Build the initial type index for the packfile or multi-pack-index |
118 | | */ |
119 | | void bitmap_writer_build_type_index(struct bitmap_writer *writer, |
120 | | struct pack_idx_entry **index) |
121 | 0 | { |
122 | 0 | uint32_t i; |
123 | 0 | uint32_t base_objects = 0; |
124 | |
|
125 | 0 | if (writer->midx) |
126 | 0 | base_objects = writer->midx->num_objects + |
127 | 0 | writer->midx->num_objects_in_base; |
128 | |
|
129 | 0 | writer->commits = ewah_new(); |
130 | 0 | writer->trees = ewah_new(); |
131 | 0 | writer->blobs = ewah_new(); |
132 | 0 | writer->tags = ewah_new(); |
133 | 0 | ALLOC_ARRAY(writer->to_pack->in_pack_pos, writer->to_pack->nr_objects); |
134 | |
|
135 | 0 | for (i = 0; i < writer->to_pack->nr_objects; ++i) { |
136 | 0 | struct object_entry *entry = (struct object_entry *)index[i]; |
137 | 0 | enum object_type real_type; |
138 | |
|
139 | 0 | oe_set_in_pack_pos(writer->to_pack, entry, i); |
140 | |
|
141 | 0 | switch (oe_type(entry)) { |
142 | 0 | case OBJ_COMMIT: |
143 | 0 | case OBJ_TREE: |
144 | 0 | case OBJ_BLOB: |
145 | 0 | case OBJ_TAG: |
146 | 0 | real_type = oe_type(entry); |
147 | 0 | break; |
148 | | |
149 | 0 | default: |
150 | 0 | real_type = odb_read_object_info(writer->to_pack->repo->objects, |
151 | 0 | &entry->idx.oid, NULL); |
152 | 0 | break; |
153 | 0 | } |
154 | | |
155 | 0 | switch (real_type) { |
156 | 0 | case OBJ_COMMIT: |
157 | 0 | ewah_set(writer->commits, i + base_objects); |
158 | 0 | break; |
159 | | |
160 | 0 | case OBJ_TREE: |
161 | 0 | ewah_set(writer->trees, i + base_objects); |
162 | 0 | break; |
163 | | |
164 | 0 | case OBJ_BLOB: |
165 | 0 | ewah_set(writer->blobs, i + base_objects); |
166 | 0 | break; |
167 | | |
168 | 0 | case OBJ_TAG: |
169 | 0 | ewah_set(writer->tags, i + base_objects); |
170 | 0 | break; |
171 | | |
172 | 0 | default: |
173 | 0 | die("Missing type information for %s (%d/%d)", |
174 | 0 | oid_to_hex(&entry->idx.oid), real_type, |
175 | 0 | oe_type(entry)); |
176 | 0 | } |
177 | 0 | } |
178 | 0 | } |
179 | | |
180 | | int bitmap_writer_has_bitmapped_object_id(struct bitmap_writer *writer, |
181 | | const struct object_id *oid) |
182 | 0 | { |
183 | 0 | return kh_get_oid_map(writer->bitmaps, *oid) != kh_end(writer->bitmaps); |
184 | 0 | } |
185 | | |
186 | | /** |
187 | | * Compute the actual bitmaps |
188 | | */ |
189 | | |
190 | | void bitmap_writer_push_commit(struct bitmap_writer *writer, |
191 | | struct commit *commit, unsigned pseudo_merge) |
192 | 0 | { |
193 | 0 | if (writer->selected_nr >= writer->selected_alloc) { |
194 | 0 | writer->selected_alloc = (writer->selected_alloc + 32) * 2; |
195 | 0 | REALLOC_ARRAY(writer->selected, writer->selected_alloc); |
196 | 0 | } |
197 | |
|
198 | 0 | if (!pseudo_merge) { |
199 | 0 | int hash_ret; |
200 | 0 | khiter_t hash_pos = kh_put_oid_map(writer->bitmaps, |
201 | 0 | commit->object.oid, |
202 | 0 | &hash_ret); |
203 | |
|
204 | 0 | if (!hash_ret) |
205 | 0 | die(_("duplicate entry when writing bitmap index: %s"), |
206 | 0 | oid_to_hex(&commit->object.oid)); |
207 | 0 | kh_value(writer->bitmaps, hash_pos) = NULL; |
208 | 0 | } |
209 | | |
210 | 0 | writer->selected[writer->selected_nr].commit = commit; |
211 | 0 | writer->selected[writer->selected_nr].bitmap = NULL; |
212 | 0 | writer->selected[writer->selected_nr].write_as = NULL; |
213 | 0 | writer->selected[writer->selected_nr].flags = 0; |
214 | 0 | writer->selected[writer->selected_nr].pseudo_merge = pseudo_merge; |
215 | 0 | writer->selected[writer->selected_nr].pseudo_merge_parents = NULL; |
216 | |
|
217 | 0 | writer->selected_nr++; |
218 | 0 | } |
219 | | |
220 | | struct bitmap_pos_cache_entry { |
221 | | struct object_id oid; |
222 | | uint32_t pos; |
223 | | }; |
224 | | |
225 | 0 | #define BITMAP_POS_MIN_CACHE_SIZE (1U << 10) |
226 | 0 | #define BITMAP_POS_MAX_CACHE_SIZE (1U << 21) |
227 | 0 | #define BITMAP_POS_CACHE_VALID (1U << 31) |
228 | | |
229 | | static void bitmap_writer_init_pos_cache(struct bitmap_writer *writer) |
230 | 0 | { |
231 | 0 | if (writer->pos_cache) |
232 | 0 | return; |
233 | | |
234 | 0 | writer->pos_cache_nr = BITMAP_POS_MIN_CACHE_SIZE; |
235 | |
|
236 | 0 | while (writer->pos_cache_nr < writer->to_pack->nr_objects && |
237 | 0 | writer->pos_cache_nr < BITMAP_POS_MAX_CACHE_SIZE) |
238 | 0 | writer->pos_cache_nr <<= 1; |
239 | |
|
240 | 0 | CALLOC_ARRAY(writer->pos_cache, writer->pos_cache_nr); |
241 | 0 | } |
242 | | |
243 | | static size_t bitmap_writer_pos_cache_slot(struct bitmap_writer *writer, |
244 | | const struct object_id *oid) |
245 | 0 | { |
246 | 0 | return oidhash(oid) & (writer->pos_cache_nr - 1); |
247 | 0 | } |
248 | | |
249 | | static bool bitmap_writer_pos_cache_valid(struct bitmap_writer *writer, |
250 | | size_t slot) |
251 | 0 | { |
252 | 0 | return !!(writer->pos_cache[slot].pos & BITMAP_POS_CACHE_VALID); |
253 | 0 | } |
254 | | |
255 | | static int find_cached_object_pos(struct bitmap_writer *writer, |
256 | | const struct object_id *oid, uint32_t *pos) |
257 | 0 | { |
258 | 0 | size_t slot = bitmap_writer_pos_cache_slot(writer, oid); |
259 | |
|
260 | 0 | if (bitmap_writer_pos_cache_valid(writer, slot) && |
261 | 0 | oideq(&writer->pos_cache[slot].oid, oid)) { |
262 | 0 | writer->pos_cache_hits++; |
263 | 0 | *pos = writer->pos_cache[slot].pos & ~BITMAP_POS_CACHE_VALID; |
264 | 0 | return 1; |
265 | 0 | } |
266 | | |
267 | 0 | writer->pos_cache_misses++; |
268 | 0 | return 0; |
269 | 0 | } |
270 | | |
271 | | static uint32_t store_cached_object_pos(struct bitmap_writer *writer, |
272 | | const struct object_id *oid, |
273 | | uint32_t pos) |
274 | 0 | { |
275 | 0 | size_t slot; |
276 | |
|
277 | 0 | if (pos & BITMAP_POS_CACHE_VALID) |
278 | 0 | return pos; /* too large to cache */ |
279 | | |
280 | 0 | slot = bitmap_writer_pos_cache_slot(writer, oid); |
281 | |
|
282 | 0 | oidcpy(&writer->pos_cache[slot].oid, oid); |
283 | 0 | writer->pos_cache[slot].pos = pos | BITMAP_POS_CACHE_VALID; |
284 | |
|
285 | 0 | return pos; |
286 | 0 | } |
287 | | |
288 | | static uint32_t find_object_pos(struct bitmap_writer *writer, |
289 | | const struct object_id *oid, int *found) |
290 | 0 | { |
291 | 0 | struct object_entry *entry; |
292 | 0 | uint32_t pos; |
293 | |
|
294 | 0 | bitmap_writer_init_pos_cache(writer); |
295 | |
|
296 | 0 | if (find_cached_object_pos(writer, oid, &pos)) { |
297 | 0 | if (found) |
298 | 0 | *found = 1; |
299 | 0 | return pos; |
300 | 0 | } |
301 | | |
302 | 0 | entry = packlist_find(writer->to_pack, oid); |
303 | 0 | if (entry) { |
304 | 0 | uint32_t base_objects = 0; |
305 | |
|
306 | 0 | if (writer->midx) |
307 | 0 | base_objects = writer->midx->num_objects + |
308 | 0 | writer->midx->num_objects_in_base; |
309 | 0 | pos = oe_in_pack_pos(writer->to_pack, entry) + base_objects; |
310 | 0 | } else if (writer->midx) { |
311 | 0 | uint32_t at; |
312 | |
|
313 | 0 | if (!bsearch_midx(oid, writer->midx, &at)) |
314 | 0 | goto missing; |
315 | 0 | if (midx_to_pack_pos(writer->midx, at, &pos) < 0) |
316 | 0 | goto missing; |
317 | 0 | } else { |
318 | 0 | goto missing; |
319 | 0 | } |
320 | | |
321 | 0 | if (found) |
322 | 0 | *found = 1; |
323 | 0 | return store_cached_object_pos(writer, oid, pos); |
324 | | |
325 | 0 | missing: |
326 | 0 | if (found) |
327 | 0 | *found = 0; |
328 | 0 | warning("Failed to write bitmap index. Packfile doesn't have full closure " |
329 | 0 | "(object %s is missing)", oid_to_hex(oid)); |
330 | 0 | return 0; |
331 | 0 | } |
332 | | |
333 | | static int bitmapped_commit_date_cmp(const void *_a, const void *_b) |
334 | 0 | { |
335 | 0 | const struct bitmapped_commit *a = _a; |
336 | 0 | const struct bitmapped_commit *b = _b; |
337 | |
|
338 | 0 | if (a->commit->date < b->commit->date) |
339 | 0 | return -1; |
340 | 0 | if (a->commit->date > b->commit->date) |
341 | 0 | return 1; |
342 | 0 | return 0; |
343 | 0 | } |
344 | | |
345 | | static void compute_xor_offsets(struct bitmap_writer *writer) |
346 | 0 | { |
347 | 0 | static const int MAX_XOR_OFFSET_SEARCH = 10; |
348 | |
|
349 | 0 | int i, next = 0; |
350 | 0 | int nr = bitmap_writer_nr_selected_commits(writer); |
351 | |
|
352 | 0 | if (nr > 1) { |
353 | 0 | QSORT(writer->selected, nr, bitmapped_commit_date_cmp); |
354 | |
|
355 | 0 | for (i = 0; i < nr; i++) { |
356 | 0 | struct bitmapped_commit *stored = &writer->selected[i]; |
357 | 0 | khiter_t hash_pos = kh_get_oid_map(writer->bitmaps, |
358 | 0 | stored->commit->object.oid); |
359 | |
|
360 | 0 | if (hash_pos == kh_end(writer->bitmaps)) |
361 | 0 | BUG("selected commit missing from bitmap map: %s", |
362 | 0 | oid_to_hex(&stored->commit->object.oid)); |
363 | | |
364 | 0 | kh_value(writer->bitmaps, hash_pos) = stored; |
365 | 0 | } |
366 | 0 | } |
367 | | |
368 | 0 | while (next < writer->selected_nr) { |
369 | 0 | struct bitmapped_commit *stored = &writer->selected[next]; |
370 | 0 | int best_offset = 0; |
371 | 0 | struct ewah_bitmap *best_bitmap = stored->bitmap; |
372 | 0 | struct ewah_bitmap *test_xor; |
373 | |
|
374 | 0 | if (stored->pseudo_merge) |
375 | 0 | goto next; |
376 | | |
377 | 0 | for (i = 1; i <= MAX_XOR_OFFSET_SEARCH; ++i) { |
378 | 0 | int curr = next - i; |
379 | |
|
380 | 0 | if (curr < 0) |
381 | 0 | break; |
382 | 0 | if (writer->selected[curr].pseudo_merge) |
383 | 0 | continue; |
384 | | |
385 | 0 | test_xor = ewah_pool_new(); |
386 | 0 | ewah_xor(writer->selected[curr].bitmap, stored->bitmap, test_xor); |
387 | |
|
388 | 0 | if (test_xor->buffer_size < best_bitmap->buffer_size) { |
389 | 0 | if (best_bitmap != stored->bitmap) |
390 | 0 | ewah_pool_free(best_bitmap); |
391 | |
|
392 | 0 | best_bitmap = test_xor; |
393 | 0 | best_offset = i; |
394 | 0 | } else { |
395 | 0 | ewah_pool_free(test_xor); |
396 | 0 | } |
397 | 0 | } |
398 | |
|
399 | 0 | next: |
400 | 0 | stored->xor_offset = best_offset; |
401 | 0 | stored->write_as = best_bitmap; |
402 | |
|
403 | 0 | next++; |
404 | 0 | } |
405 | 0 | } |
406 | | |
407 | | struct bb_commit { |
408 | | struct commit_list *reverse_edges; |
409 | | struct bitmap *commit_mask; |
410 | | struct bitmap *bitmap; |
411 | | unsigned selected:1, |
412 | | maximal:1, |
413 | | pseudo_merge:1; |
414 | | unsigned idx; /* within selected array */ |
415 | | }; |
416 | | |
417 | | static void clear_bb_commit(struct bb_commit *commit) |
418 | 0 | { |
419 | 0 | commit_list_free(commit->reverse_edges); |
420 | 0 | bitmap_free(commit->commit_mask); |
421 | 0 | bitmap_free(commit->bitmap); |
422 | 0 | } |
423 | | |
424 | 0 | define_commit_slab(bb_data, struct bb_commit); Unexecuted instantiation: pack-bitmap-write.c:init_bb_data_with_stride Unexecuted instantiation: pack-bitmap-write.c:bb_data_at_peek Unexecuted instantiation: pack-bitmap-write.c:clear_bb_data |
425 | 0 |
|
426 | 0 | struct bitmap_builder { |
427 | 0 | struct bb_data data; |
428 | 0 | struct commit_stack commits; |
429 | 0 | }; |
430 | 0 |
|
431 | 0 | static void bitmap_builder_init(struct bitmap_builder *bb, |
432 | 0 | struct bitmap_writer *writer, |
433 | 0 | struct bitmap_index *old_bitmap) |
434 | 0 | { |
435 | 0 | struct rev_info revs; |
436 | 0 | struct commit *commit; |
437 | 0 | struct commit_list *reusable = NULL; |
438 | 0 | struct commit_list *r; |
439 | 0 | unsigned int i, num_maximal = 0; |
440 | |
|
441 | 0 | init_bb_data(&bb->data); |
442 | 0 | commit_stack_init(&bb->commits); |
443 | |
|
444 | 0 | reset_revision_walk(); |
445 | 0 | repo_init_revisions(writer->to_pack->repo, &revs, NULL); |
446 | 0 | revs.topo_order = 1; |
447 | 0 | revs.first_parent_only = 1; |
448 | |
|
449 | 0 | for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++) { |
450 | 0 | struct bitmapped_commit *bc = &writer->selected[i]; |
451 | 0 | struct bb_commit *ent = bb_data_at(&bb->data, bc->commit); |
452 | |
|
453 | 0 | if (bc->pseudo_merge) |
454 | 0 | BUG("unexpected pseudo-merge at %"PRIuMAX, |
455 | 0 | (uintmax_t)i); |
456 | | |
457 | 0 | ent->selected = 1; |
458 | 0 | ent->maximal = 1; |
459 | 0 | ent->pseudo_merge = 0; |
460 | 0 | ent->idx = i; |
461 | |
|
462 | 0 | ent->commit_mask = bitmap_new(); |
463 | 0 | bitmap_set(ent->commit_mask, i); |
464 | |
|
465 | 0 | add_pending_object(&revs, &bc->commit->object, ""); |
466 | 0 | } |
467 | | |
468 | 0 | if (prepare_revision_walk(&revs)) |
469 | 0 | die("revision walk setup failed"); |
470 | | |
471 | 0 | while ((commit = get_revision(&revs))) { |
472 | 0 | struct commit_list *p = commit->parents; |
473 | 0 | struct bb_commit *c_ent; |
474 | |
|
475 | 0 | parse_commit_or_die(commit); |
476 | |
|
477 | 0 | c_ent = bb_data_at(&bb->data, commit); |
478 | | |
479 | | /* |
480 | | * If there is no commit_mask, there is no reason to iterate |
481 | | * over this commit; it is not selected (if it were, it would |
482 | | * not have a blank commit mask) and all its children have |
483 | | * existing bitmaps (see the comment starting with "This commit |
484 | | * has an existing bitmap" below), so it does not contribute |
485 | | * anything to the final bitmap file or its descendants. |
486 | | */ |
487 | 0 | if (!c_ent->commit_mask) |
488 | 0 | continue; |
489 | | |
490 | 0 | if (old_bitmap && bitmap_for_commit(old_bitmap, commit)) { |
491 | | /* |
492 | | * This commit has an existing bitmap, so we can |
493 | | * get its bits immediately without an object |
494 | | * walk. That is, it is reusable as-is and there is no |
495 | | * need to continue walking beyond it. |
496 | | * |
497 | | * Mark it as such and add it to bb->commits separately |
498 | | * to avoid allocating a position in the commit mask. |
499 | | */ |
500 | 0 | commit_list_insert(commit, &reusable); |
501 | 0 | goto next; |
502 | 0 | } |
503 | | |
504 | 0 | if (c_ent->maximal) { |
505 | 0 | num_maximal++; |
506 | 0 | commit_stack_push(&bb->commits, commit); |
507 | 0 | } |
508 | |
|
509 | 0 | if (p) { |
510 | 0 | struct bb_commit *p_ent = bb_data_at(&bb->data, p->item); |
511 | 0 | int c_not_p, p_not_c; |
512 | |
|
513 | 0 | if (!p_ent->commit_mask) { |
514 | 0 | p_ent->commit_mask = bitmap_new(); |
515 | 0 | c_not_p = 1; |
516 | 0 | p_not_c = 0; |
517 | 0 | } else { |
518 | 0 | c_not_p = bitmap_is_subset(c_ent->commit_mask, p_ent->commit_mask); |
519 | 0 | p_not_c = bitmap_is_subset(p_ent->commit_mask, c_ent->commit_mask); |
520 | 0 | } |
521 | |
|
522 | 0 | if (!c_not_p) |
523 | 0 | continue; |
524 | | |
525 | 0 | bitmap_or(p_ent->commit_mask, c_ent->commit_mask); |
526 | |
|
527 | 0 | if (p_not_c) |
528 | 0 | p_ent->maximal = 1; |
529 | 0 | else { |
530 | 0 | p_ent->maximal = 0; |
531 | 0 | commit_list_free(p_ent->reverse_edges); |
532 | 0 | p_ent->reverse_edges = NULL; |
533 | 0 | } |
534 | |
|
535 | 0 | if (c_ent->maximal) { |
536 | 0 | commit_list_insert(commit, &p_ent->reverse_edges); |
537 | 0 | } else { |
538 | 0 | struct commit_list *cc = c_ent->reverse_edges; |
539 | |
|
540 | 0 | for (; cc; cc = cc->next) { |
541 | 0 | if (!commit_list_contains(cc->item, p_ent->reverse_edges)) |
542 | 0 | commit_list_insert(cc->item, &p_ent->reverse_edges); |
543 | 0 | } |
544 | 0 | } |
545 | 0 | } |
546 | | |
547 | 0 | next: |
548 | 0 | bitmap_free(c_ent->commit_mask); |
549 | 0 | c_ent->commit_mask = NULL; |
550 | 0 | } |
551 | | |
552 | 0 | for (r = reusable; r; r = r->next) { |
553 | 0 | commit_stack_push(&bb->commits, r->item); |
554 | 0 | } |
555 | |
|
556 | 0 | trace2_data_intmax("pack-bitmap-write", writer->repo, |
557 | 0 | "num_selected_commits", writer->selected_nr); |
558 | 0 | trace2_data_intmax("pack-bitmap-write", writer->repo, |
559 | 0 | "num_maximal_commits", num_maximal); |
560 | |
|
561 | 0 | release_revisions(&revs); |
562 | 0 | commit_list_free(reusable); |
563 | 0 | } |
564 | | |
565 | | static void bitmap_builder_clear(struct bitmap_builder *bb) |
566 | 0 | { |
567 | 0 | deep_clear_bb_data(&bb->data, clear_bb_commit); |
568 | 0 | commit_stack_clear(&bb->commits); |
569 | 0 | } |
570 | | |
571 | | static int fill_bitmap_tree(struct bitmap_writer *writer, |
572 | | struct bitmap *bitmap, |
573 | | struct tree *tree, |
574 | | uint32_t pos) |
575 | 0 | { |
576 | 0 | int found; |
577 | 0 | struct tree_desc desc; |
578 | 0 | struct name_entry entry; |
579 | |
|
580 | 0 | bitmap_set(bitmap, pos); |
581 | |
|
582 | 0 | if (repo_parse_tree(writer->repo, tree) < 0) |
583 | 0 | die("unable to load tree object %s", |
584 | 0 | oid_to_hex(&tree->object.oid)); |
585 | 0 | init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size); |
586 | |
|
587 | 0 | while (tree_entry(&desc, &entry)) { |
588 | 0 | switch (object_type(entry.mode)) { |
589 | 0 | case OBJ_TREE: |
590 | 0 | pos = find_object_pos(writer, &entry.oid, &found); |
591 | 0 | if (!found) |
592 | 0 | return -1; |
593 | 0 | if (bitmap_get(bitmap, pos)) { |
594 | | /* |
595 | | * If our bit is already set, then there |
596 | | * is nothing to do. Both this tree and |
597 | | * all of its children will be set. |
598 | | */ |
599 | 0 | break; |
600 | 0 | } |
601 | | |
602 | 0 | if (fill_bitmap_tree(writer, bitmap, |
603 | 0 | lookup_tree(writer->repo, |
604 | 0 | &entry.oid), pos) < 0) |
605 | 0 | return -1; |
606 | 0 | break; |
607 | 0 | case OBJ_BLOB: |
608 | 0 | pos = find_object_pos(writer, &entry.oid, &found); |
609 | 0 | if (!found) |
610 | 0 | return -1; |
611 | 0 | bitmap_set(bitmap, pos); |
612 | 0 | break; |
613 | 0 | default: |
614 | | /* Gitlink, etc; not reachable */ |
615 | 0 | break; |
616 | 0 | } |
617 | 0 | } |
618 | | |
619 | 0 | free_tree_buffer(tree); |
620 | 0 | return 0; |
621 | 0 | } |
622 | | |
623 | | static int reused_bitmaps_nr; |
624 | | static int reused_pseudo_merge_bitmaps_nr; |
625 | | static int pseudo_merge_bitmap_nr; |
626 | | static int pseudo_merge_bitmap_parents; |
627 | | |
628 | | static int fill_bitmap_commit_calls_nr; |
629 | | static int fill_bitmap_commit_found_ancestor_nr; |
630 | | |
631 | | static int fill_bitmap_commit(struct bitmap_writer *writer, |
632 | | struct bb_commit *ent, |
633 | | struct commit *commit, |
634 | | struct prio_queue *queue, |
635 | | struct prio_queue *tree_queue, |
636 | | struct bitmap_index *old_bitmap, |
637 | | const uint32_t *mapping) |
638 | 0 | { |
639 | 0 | struct commit *c; |
640 | 0 | struct tree *t; |
641 | 0 | int found; |
642 | 0 | int from_pseudo_merge = commit->object.flags & BITMAP_PSEUDO_MERGE; |
643 | 0 | uint32_t pos; |
644 | |
|
645 | 0 | if (ent->pseudo_merge) |
646 | 0 | BUG("unexpected pseudo-merge commit in fill_bitmap_commit()"); |
647 | | |
648 | 0 | fill_bitmap_commit_calls_nr++; |
649 | |
|
650 | 0 | if (!ent->bitmap) |
651 | 0 | ent->bitmap = bitmap_new(); |
652 | |
|
653 | 0 | prio_queue_put(queue, commit); |
654 | |
|
655 | 0 | while ((c = prio_queue_get(queue))) { |
656 | 0 | struct commit_list *p; |
657 | |
|
658 | 0 | if (old_bitmap && mapping) { |
659 | 0 | struct ewah_bitmap *old; |
660 | 0 | struct bitmap *remapped = bitmap_new(); |
661 | |
|
662 | 0 | old = bitmap_for_commit(old_bitmap, c); |
663 | | /* |
664 | | * If this commit has an old bitmap, then translate that |
665 | | * bitmap and add its bits to this one. No need to walk |
666 | | * parents or the tree for this commit. |
667 | | */ |
668 | 0 | if (old && !rebuild_bitmap(mapping, old, remapped)) { |
669 | 0 | bitmap_or(ent->bitmap, remapped); |
670 | 0 | bitmap_free(remapped); |
671 | 0 | reused_bitmaps_nr++; |
672 | 0 | continue; |
673 | 0 | } |
674 | 0 | bitmap_free(remapped); |
675 | 0 | } |
676 | | |
677 | | /* |
678 | | * If we encounter an ancestor for which we have already |
679 | | * computed a bitmap during this build (i.e. a regular |
680 | | * selected commit processed earlier in topo order), we can |
681 | | * short-circuit the walk: its stored bitmap already covers |
682 | | * the commit itself, its tree, and all of its ancestors. |
683 | | */ |
684 | 0 | if (c != commit) { |
685 | 0 | khiter_t hash_pos = kh_get_oid_map(writer->bitmaps, |
686 | 0 | c->object.oid); |
687 | 0 | if (hash_pos != kh_end(writer->bitmaps)) { |
688 | 0 | struct bitmapped_commit *stored = |
689 | 0 | kh_value(writer->bitmaps, hash_pos); |
690 | 0 | if (stored && stored->bitmap) { |
691 | 0 | fill_bitmap_commit_found_ancestor_nr++; |
692 | 0 | bitmap_or_ewah(ent->bitmap, |
693 | 0 | stored->bitmap); |
694 | 0 | continue; |
695 | 0 | } |
696 | 0 | } |
697 | 0 | } |
698 | | |
699 | | /* |
700 | | * Mark ourselves and queue our tree. The commit |
701 | | * walk ensures we cover all parents. |
702 | | */ |
703 | 0 | if (!(c->object.flags & BITMAP_PSEUDO_MERGE)) { |
704 | 0 | struct tree *tree; |
705 | |
|
706 | 0 | if (from_pseudo_merge && !c->object.parsed) { |
707 | | /* |
708 | | * Commits reachable from selected |
709 | | * non-pseudo-merges are already parsed |
710 | | * by the regular bitmap build. |
711 | | * |
712 | | * However, pseudo-merge fills can also |
713 | | * reach commits that were not covered |
714 | | * there, so parse any such leftovers |
715 | | * before reading their tree or parents. |
716 | | */ |
717 | 0 | if (repo_parse_commit(writer->repo, c)) |
718 | 0 | return -1; |
719 | 0 | } |
720 | | |
721 | 0 | pos = find_object_pos(writer, &c->object.oid, &found); |
722 | 0 | if (!found) |
723 | 0 | return -1; |
724 | 0 | bitmap_set(ent->bitmap, pos); |
725 | |
|
726 | 0 | tree = repo_get_commit_tree(writer->repo, c); |
727 | 0 | if (!tree) |
728 | 0 | return -1; |
729 | 0 | prio_queue_put(tree_queue, tree); |
730 | 0 | } |
731 | | |
732 | 0 | for (p = c->parents; p; p = p->next) { |
733 | 0 | pos = find_object_pos(writer, &p->item->object.oid, |
734 | 0 | &found); |
735 | 0 | if (!found) |
736 | 0 | return -1; |
737 | 0 | if (!bitmap_get(ent->bitmap, pos)) { |
738 | 0 | bitmap_set(ent->bitmap, pos); |
739 | 0 | prio_queue_put(queue, p->item); |
740 | 0 | } |
741 | 0 | } |
742 | 0 | } |
743 | | |
744 | 0 | while ((t = prio_queue_get(tree_queue))) { |
745 | 0 | int found; |
746 | |
|
747 | 0 | pos = find_object_pos(writer, &t->object.oid, &found); |
748 | 0 | if (!found) |
749 | 0 | return -1; |
750 | 0 | if (bitmap_get(ent->bitmap, pos)) { |
751 | | /* |
752 | | * If our bit is already set, then there is |
753 | | * nothing to do. Both this tree and all of its |
754 | | * children will be set. |
755 | | */ |
756 | 0 | continue; |
757 | 0 | } |
758 | | |
759 | 0 | if (fill_bitmap_tree(writer, ent->bitmap, t, pos) < 0) |
760 | 0 | return -1; |
761 | 0 | } |
762 | 0 | return 0; |
763 | 0 | } |
764 | | |
765 | | static int reuse_pseudo_merge_bitmap(struct bitmap_index *old_bitmap, |
766 | | const uint32_t *mapping, |
767 | | struct commit *merge, |
768 | | struct ewah_bitmap **out) |
769 | 0 | { |
770 | 0 | struct ewah_bitmap *old; |
771 | 0 | struct bitmap *remapped; |
772 | |
|
773 | 0 | if (!old_bitmap || !mapping) |
774 | 0 | return 0; |
775 | | |
776 | 0 | old = pseudo_merge_bitmap_for_commit(old_bitmap, merge); |
777 | 0 | if (!old) |
778 | 0 | return 0; |
779 | | |
780 | 0 | remapped = bitmap_new(); |
781 | 0 | if (rebuild_bitmap(mapping, old, remapped) < 0) { |
782 | 0 | bitmap_free(remapped); |
783 | 0 | return 0; |
784 | 0 | } |
785 | | |
786 | 0 | *out = bitmap_to_ewah(remapped); |
787 | 0 | bitmap_free(remapped); |
788 | 0 | reused_pseudo_merge_bitmaps_nr++; |
789 | 0 | return 1; |
790 | 0 | } |
791 | | |
792 | | static int build_pseudo_merge_bitmap(struct bitmap_writer *writer, |
793 | | struct bitmap_index *old_bitmap, |
794 | | const uint32_t *mapping, |
795 | | struct commit *merge, |
796 | | struct ewah_bitmap **out) |
797 | 0 | { |
798 | 0 | struct bb_commit ent = { 0 }; |
799 | 0 | struct prio_queue queue = { NULL }; |
800 | 0 | struct prio_queue tree_queue = { NULL }; |
801 | 0 | unsigned parents = commit_list_count(merge->parents); |
802 | 0 | int ret; |
803 | |
|
804 | 0 | ent.bitmap = bitmap_new(); |
805 | |
|
806 | 0 | pseudo_merge_bitmap_nr++; |
807 | 0 | pseudo_merge_bitmap_parents += parents; |
808 | |
|
809 | 0 | if (reuse_pseudo_merge_bitmap(old_bitmap, mapping, merge, out)) { |
810 | 0 | ret = 0; |
811 | 0 | goto done; |
812 | 0 | } |
813 | | |
814 | 0 | ret = fill_bitmap_commit(writer, &ent, merge, &queue, &tree_queue, |
815 | 0 | old_bitmap, mapping); |
816 | |
|
817 | 0 | if (!ret) |
818 | 0 | *out = bitmap_to_ewah(ent.bitmap); |
819 | |
|
820 | 0 | done: |
821 | 0 | bitmap_free(ent.bitmap); |
822 | 0 | clear_prio_queue(&queue); |
823 | 0 | clear_prio_queue(&tree_queue); |
824 | |
|
825 | 0 | return ret; |
826 | 0 | } |
827 | | |
828 | | static int build_pseudo_merge_bitmaps(struct bitmap_writer *writer, |
829 | | struct bitmap_index *old_bitmap, |
830 | | const uint32_t *mapping, |
831 | | int *nr_stored) |
832 | 0 | { |
833 | 0 | size_t i = bitmap_writer_nr_selected_commits(writer); |
834 | 0 | int ret = 0; |
835 | |
|
836 | 0 | if (!writer->pseudo_merges_nr) |
837 | 0 | return 0; |
838 | | |
839 | 0 | trace2_region_enter("pack-bitmap-write", "building_pseudo_merge_bitmaps", |
840 | 0 | writer->repo); |
841 | |
|
842 | 0 | for (; i < writer->selected_nr; i++) { |
843 | 0 | struct bitmapped_commit *merge = &writer->selected[i]; |
844 | 0 | struct commit_list *p; |
845 | 0 | struct bitmap *parents = bitmap_new(); |
846 | 0 | struct ewah_bitmap *objects = NULL; |
847 | |
|
848 | 0 | if (!merge->pseudo_merge) |
849 | 0 | BUG("found non-pseudo merge commit at %"PRIuMAX, |
850 | 0 | (uintmax_t)i); |
851 | | |
852 | 0 | for (p = merge->commit->parents; p; p = p->next) { |
853 | 0 | int found; |
854 | 0 | uint32_t pos = find_object_pos(writer, |
855 | 0 | &p->item->object.oid, |
856 | 0 | &found); |
857 | 0 | if (!found) { |
858 | 0 | bitmap_free(parents); |
859 | 0 | ret = -1; |
860 | 0 | goto done; |
861 | 0 | } |
862 | 0 | bitmap_set(parents, pos); |
863 | 0 | } |
864 | | |
865 | 0 | merge->pseudo_merge_parents = bitmap_to_ewah(parents); |
866 | 0 | bitmap_free(parents); |
867 | |
|
868 | 0 | if (build_pseudo_merge_bitmap(writer, old_bitmap, mapping, |
869 | 0 | merge->commit, &objects) < 0) { |
870 | 0 | ret = -1; |
871 | 0 | goto done; |
872 | 0 | } |
873 | 0 | merge->bitmap = objects; |
874 | |
|
875 | 0 | (*nr_stored)++; |
876 | 0 | display_progress(writer->progress, *nr_stored); |
877 | 0 | } |
878 | | |
879 | 0 | done: |
880 | 0 | trace2_region_leave("pack-bitmap-write", "building_pseudo_merge_bitmaps", |
881 | 0 | writer->repo); |
882 | |
|
883 | 0 | trace2_data_intmax("pack-bitmap-write", writer->repo, |
884 | 0 | "pseudo_merge_bitmap_nr", |
885 | 0 | pseudo_merge_bitmap_nr); |
886 | 0 | trace2_data_intmax("pack-bitmap-write", writer->repo, |
887 | 0 | "building_bitmaps_pseudo_merge_reused", |
888 | 0 | reused_pseudo_merge_bitmaps_nr); |
889 | 0 | trace2_data_intmax("pack-bitmap-write", writer->repo, |
890 | 0 | "pseudo_merge_bitmap_parents", |
891 | 0 | pseudo_merge_bitmap_parents); |
892 | |
|
893 | 0 | return ret; |
894 | 0 | } |
895 | | |
896 | | static void store_selected(struct bitmap_writer *writer, |
897 | | struct bb_commit *ent, struct commit *commit) |
898 | 0 | { |
899 | 0 | struct bitmapped_commit *stored = &writer->selected[ent->idx]; |
900 | 0 | khiter_t hash_pos; |
901 | |
|
902 | 0 | stored->bitmap = bitmap_to_ewah(ent->bitmap); |
903 | |
|
904 | 0 | if (ent->pseudo_merge) |
905 | 0 | return; |
906 | | |
907 | 0 | hash_pos = kh_get_oid_map(writer->bitmaps, commit->object.oid); |
908 | 0 | if (hash_pos == kh_end(writer->bitmaps)) |
909 | 0 | die(_("attempted to store non-selected commit: '%s'"), |
910 | 0 | oid_to_hex(&commit->object.oid)); |
911 | | |
912 | 0 | kh_value(writer->bitmaps, hash_pos) = stored; |
913 | 0 | } |
914 | | |
915 | | int bitmap_writer_build(struct bitmap_writer *writer) |
916 | 0 | { |
917 | 0 | struct bitmap_builder bb; |
918 | 0 | size_t i; |
919 | 0 | int nr_stored = 0; /* for progress */ |
920 | 0 | struct prio_queue queue = { compare_commits_by_gen_then_commit_date }; |
921 | 0 | struct prio_queue tree_queue = { NULL }; |
922 | 0 | struct bitmap_index *old_bitmap; |
923 | 0 | uint32_t *mapping = NULL; |
924 | 0 | int closed = 1; /* until proven otherwise */ |
925 | |
|
926 | 0 | if (writer->show_progress) |
927 | 0 | writer->progress = start_progress(writer->repo, |
928 | 0 | "Building bitmaps", |
929 | 0 | writer->selected_nr); |
930 | |
|
931 | 0 | writer->pos_cache_hits = 0; |
932 | 0 | writer->pos_cache_misses = 0; |
933 | |
|
934 | 0 | trace2_region_enter("pack-bitmap-write", "building_bitmaps_total", |
935 | 0 | writer->repo); |
936 | |
|
937 | 0 | old_bitmap = prepare_bitmap_git(writer->to_pack->repo); |
938 | 0 | if (old_bitmap) |
939 | 0 | mapping = create_bitmap_mapping(old_bitmap, writer->to_pack); |
940 | 0 | else |
941 | 0 | mapping = NULL; |
942 | |
|
943 | 0 | bitmap_builder_init(&bb, writer, old_bitmap); |
944 | 0 | for (i = bb.commits.nr; i > 0; i--) { |
945 | 0 | struct commit *commit = bb.commits.items[i-1]; |
946 | 0 | struct bb_commit *ent = bb_data_at(&bb.data, commit); |
947 | 0 | struct commit *child; |
948 | 0 | int reused = 0; |
949 | |
|
950 | 0 | if (fill_bitmap_commit(writer, ent, commit, &queue, &tree_queue, |
951 | 0 | old_bitmap, mapping) < 0) { |
952 | 0 | closed = 0; |
953 | 0 | break; |
954 | 0 | } |
955 | | |
956 | 0 | if (ent->selected) { |
957 | 0 | store_selected(writer, ent, commit); |
958 | 0 | nr_stored++; |
959 | 0 | display_progress(writer->progress, nr_stored); |
960 | 0 | } |
961 | |
|
962 | 0 | while ((child = pop_commit(&ent->reverse_edges))) { |
963 | 0 | struct bb_commit *child_ent = |
964 | 0 | bb_data_at(&bb.data, child); |
965 | |
|
966 | 0 | if (child_ent->bitmap) |
967 | 0 | bitmap_or(child_ent->bitmap, ent->bitmap); |
968 | 0 | else if (reused) |
969 | 0 | child_ent->bitmap = bitmap_dup(ent->bitmap); |
970 | 0 | else { |
971 | 0 | child_ent->bitmap = ent->bitmap; |
972 | 0 | reused = 1; |
973 | 0 | } |
974 | 0 | } |
975 | 0 | if (!reused) |
976 | 0 | bitmap_free(ent->bitmap); |
977 | 0 | ent->bitmap = NULL; |
978 | 0 | } |
979 | 0 | if (closed && |
980 | 0 | build_pseudo_merge_bitmaps(writer, old_bitmap, mapping, |
981 | 0 | &nr_stored) < 0) |
982 | 0 | closed = 0; |
983 | 0 | clear_prio_queue(&queue); |
984 | 0 | clear_prio_queue(&tree_queue); |
985 | 0 | bitmap_builder_clear(&bb); |
986 | 0 | free_bitmap_index(old_bitmap); |
987 | 0 | free(mapping); |
988 | |
|
989 | 0 | trace2_region_leave("pack-bitmap-write", "building_bitmaps_total", |
990 | 0 | writer->repo); |
991 | 0 | trace2_data_intmax("pack-bitmap-write", writer->repo, |
992 | 0 | "building_bitmaps_reused", reused_bitmaps_nr); |
993 | 0 | trace2_data_intmax("pack-bitmap-write", writer->repo, |
994 | 0 | "fill_bitmap_commit_calls_nr", |
995 | 0 | fill_bitmap_commit_calls_nr); |
996 | 0 | trace2_data_intmax("pack-bitmap-write", writer->repo, |
997 | 0 | "fill_bitmap_commit_found_ancestor_nr", |
998 | 0 | fill_bitmap_commit_found_ancestor_nr); |
999 | 0 | trace2_data_intmax("pack-bitmap-write", writer->repo, |
1000 | 0 | "bitmap_pos_cache_hits", writer->pos_cache_hits); |
1001 | 0 | trace2_data_intmax("pack-bitmap-write", writer->repo, |
1002 | 0 | "bitmap_pos_cache_misses", writer->pos_cache_misses); |
1003 | |
|
1004 | 0 | stop_progress(&writer->progress); |
1005 | |
|
1006 | 0 | if (closed) |
1007 | 0 | compute_xor_offsets(writer); |
1008 | 0 | return closed ? 0 : -1; |
1009 | 0 | } |
1010 | | |
1011 | | /** |
1012 | | * Select the commits that will be bitmapped |
1013 | | */ |
1014 | | static inline unsigned int next_commit_index(unsigned int idx) |
1015 | 0 | { |
1016 | 0 | static const unsigned int MIN_COMMITS = 100; |
1017 | 0 | static const unsigned int MAX_COMMITS = 5000; |
1018 | |
|
1019 | 0 | static const unsigned int MUST_REGION = 100; |
1020 | 0 | static const unsigned int MIN_REGION = 20000; |
1021 | |
|
1022 | 0 | unsigned int offset, next; |
1023 | |
|
1024 | 0 | if (idx <= MUST_REGION) |
1025 | 0 | return 0; |
1026 | | |
1027 | 0 | if (idx <= MIN_REGION) { |
1028 | 0 | offset = idx - MUST_REGION; |
1029 | 0 | return (offset < MIN_COMMITS) ? offset : MIN_COMMITS; |
1030 | 0 | } |
1031 | | |
1032 | 0 | offset = idx - MIN_REGION; |
1033 | 0 | next = (offset < MAX_COMMITS) ? offset : MAX_COMMITS; |
1034 | |
|
1035 | 0 | return (next > MIN_COMMITS) ? next : MIN_COMMITS; |
1036 | 0 | } |
1037 | | |
1038 | | static int date_compare(const void *_a, const void *_b) |
1039 | 0 | { |
1040 | 0 | struct commit *a = *(struct commit **)_a; |
1041 | 0 | struct commit *b = *(struct commit **)_b; |
1042 | 0 | return (long)b->date - (long)a->date; |
1043 | 0 | } |
1044 | | |
1045 | | void bitmap_writer_select_commits(struct bitmap_writer *writer, |
1046 | | struct commit **indexed_commits, |
1047 | | unsigned int indexed_commits_nr) |
1048 | 0 | { |
1049 | 0 | unsigned int i = 0, j, next; |
1050 | |
|
1051 | 0 | QSORT(indexed_commits, indexed_commits_nr, date_compare); |
1052 | |
|
1053 | 0 | if (indexed_commits_nr < 100) { |
1054 | 0 | for (i = 0; i < indexed_commits_nr; ++i) |
1055 | 0 | bitmap_writer_push_commit(writer, indexed_commits[i], 0); |
1056 | |
|
1057 | 0 | select_pseudo_merges(writer); |
1058 | |
|
1059 | 0 | return; |
1060 | 0 | } |
1061 | | |
1062 | 0 | if (writer->show_progress) |
1063 | 0 | writer->progress = start_progress(writer->repo, |
1064 | 0 | "Selecting bitmap commits", 0); |
1065 | |
|
1066 | 0 | for (;;) { |
1067 | 0 | struct commit *chosen = NULL; |
1068 | |
|
1069 | 0 | next = next_commit_index(i); |
1070 | |
|
1071 | 0 | if (i + next >= indexed_commits_nr) |
1072 | 0 | break; |
1073 | | |
1074 | 0 | if (next == 0) { |
1075 | 0 | chosen = indexed_commits[i]; |
1076 | 0 | } else { |
1077 | 0 | chosen = indexed_commits[i + next]; |
1078 | |
|
1079 | 0 | for (j = 0; j <= next; ++j) { |
1080 | 0 | struct commit *cm = indexed_commits[i + j]; |
1081 | |
|
1082 | 0 | if ((cm->object.flags & NEEDS_BITMAP) != 0) { |
1083 | 0 | chosen = cm; |
1084 | 0 | break; |
1085 | 0 | } |
1086 | | |
1087 | 0 | if (cm->parents && cm->parents->next) |
1088 | 0 | chosen = cm; |
1089 | 0 | } |
1090 | 0 | } |
1091 | |
|
1092 | 0 | bitmap_writer_push_commit(writer, chosen, 0); |
1093 | |
|
1094 | 0 | i += next + 1; |
1095 | 0 | display_progress(writer->progress, i); |
1096 | 0 | } |
1097 | |
|
1098 | 0 | stop_progress(&writer->progress); |
1099 | |
|
1100 | 0 | select_pseudo_merges(writer); |
1101 | 0 | } |
1102 | | |
1103 | | |
1104 | | static int hashwrite_ewah_helper(void *f, const void *buf, size_t len) |
1105 | 0 | { |
1106 | | /* hashwrite will die on error */ |
1107 | 0 | hashwrite(f, buf, len); |
1108 | 0 | return len; |
1109 | 0 | } |
1110 | | |
1111 | | /** |
1112 | | * Write the bitmap index to disk |
1113 | | */ |
1114 | | static inline void dump_bitmap(struct hashfile *f, struct ewah_bitmap *bitmap) |
1115 | 0 | { |
1116 | 0 | if (ewah_serialize_to(bitmap, hashwrite_ewah_helper, f) < 0) |
1117 | 0 | die("Failed to write bitmap index"); |
1118 | 0 | } |
1119 | | |
1120 | | static const struct object_id *oid_access(size_t pos, const void *table) |
1121 | 0 | { |
1122 | 0 | const struct pack_idx_entry * const *index = table; |
1123 | 0 | return &index[pos]->oid; |
1124 | 0 | } |
1125 | | |
1126 | | static void write_selected_commits_v1(struct bitmap_writer *writer, |
1127 | | struct hashfile *f, off_t *offsets) |
1128 | 0 | { |
1129 | 0 | int i; |
1130 | |
|
1131 | 0 | for (i = 0; i < bitmap_writer_nr_selected_commits(writer); ++i) { |
1132 | 0 | struct bitmapped_commit *stored = &writer->selected[i]; |
1133 | 0 | if (stored->pseudo_merge) |
1134 | 0 | BUG("unexpected pseudo-merge among selected: %s", |
1135 | 0 | oid_to_hex(&stored->commit->object.oid)); |
1136 | | |
1137 | 0 | if (offsets) |
1138 | 0 | offsets[i] = hashfile_total(f); |
1139 | |
|
1140 | 0 | hashwrite_be32(f, stored->commit_pos); |
1141 | 0 | hashwrite_u8(f, stored->xor_offset); |
1142 | 0 | hashwrite_u8(f, stored->flags); |
1143 | |
|
1144 | 0 | dump_bitmap(f, stored->write_as); |
1145 | 0 | } |
1146 | 0 | } |
1147 | | |
1148 | | static int pseudo_merge_commit_pos_cmp(const void *_va, const void *_vb, |
1149 | | void *_data) |
1150 | 0 | { |
1151 | 0 | struct bitmap_writer *writer = _data; |
1152 | 0 | uint32_t pos_a = find_object_pos(writer, _va, NULL); |
1153 | 0 | uint32_t pos_b = find_object_pos(writer, _vb, NULL); |
1154 | |
|
1155 | 0 | if (pos_a < pos_b) |
1156 | 0 | return -1; |
1157 | 0 | if (pos_a > pos_b) |
1158 | 0 | return 1; |
1159 | 0 | return 0; |
1160 | 0 | } |
1161 | | |
1162 | | static void write_pseudo_merges(struct bitmap_writer *writer, |
1163 | | struct hashfile *f) |
1164 | 0 | { |
1165 | 0 | struct oid_array commits = OID_ARRAY_INIT; |
1166 | 0 | off_t *pseudo_merge_ofs = NULL; |
1167 | 0 | off_t start, table_start, next_ext; |
1168 | |
|
1169 | 0 | uint32_t base = bitmap_writer_nr_selected_commits(writer); |
1170 | 0 | size_t i, j = 0; |
1171 | |
|
1172 | 0 | CALLOC_ARRAY(pseudo_merge_ofs, writer->pseudo_merges_nr); |
1173 | |
|
1174 | 0 | start = hashfile_total(f); |
1175 | |
|
1176 | 0 | for (i = 0; i < writer->pseudo_merges_nr; i++) { |
1177 | 0 | struct bitmapped_commit *merge = &writer->selected[base + i]; |
1178 | |
|
1179 | 0 | if (!merge->pseudo_merge) |
1180 | 0 | BUG("found non-pseudo merge commit at %"PRIuMAX, (uintmax_t)i); |
1181 | | |
1182 | 0 | if (!merge->pseudo_merge_parents || !merge->bitmap) |
1183 | 0 | BUG("missing pseudo-merge bitmap for commit %s", |
1184 | 0 | oid_to_hex(&merge->commit->object.oid)); |
1185 | | |
1186 | 0 | pseudo_merge_ofs[i] = hashfile_total(f); |
1187 | 0 | dump_bitmap(f, merge->pseudo_merge_parents); |
1188 | 0 | dump_bitmap(f, merge->bitmap); |
1189 | 0 | } |
1190 | | |
1191 | 0 | next_ext = st_add(hashfile_total(f), |
1192 | 0 | st_mult(kh_size(writer->pseudo_merge_commits), |
1193 | 0 | sizeof(uint32_t) + sizeof(uint64_t))); |
1194 | |
|
1195 | 0 | table_start = hashfile_total(f); |
1196 | |
|
1197 | 0 | commits.alloc = kh_size(writer->pseudo_merge_commits); |
1198 | 0 | CALLOC_ARRAY(commits.oid, commits.alloc); |
1199 | |
|
1200 | 0 | for (i = kh_begin(writer->pseudo_merge_commits); i != kh_end(writer->pseudo_merge_commits); i++) { |
1201 | 0 | if (!kh_exist(writer->pseudo_merge_commits, i)) |
1202 | 0 | continue; |
1203 | 0 | oid_array_append(&commits, &kh_key(writer->pseudo_merge_commits, i)); |
1204 | 0 | } |
1205 | | |
1206 | | /* |
1207 | | * Sort the commits by their bit position so that the lookup |
1208 | | * table can be binary searched by the reader (see |
1209 | | * find_pseudo_merge()). |
1210 | | */ |
1211 | 0 | QSORT_S(commits.oid, commits.nr, pseudo_merge_commit_pos_cmp, writer); |
1212 | | |
1213 | | /* write lookup table (non-extended) */ |
1214 | 0 | for (i = 0; i < commits.nr; i++) { |
1215 | 0 | int hash_pos; |
1216 | 0 | struct pseudo_merge_commit_idx *c; |
1217 | |
|
1218 | 0 | hash_pos = kh_get_oid_map(writer->pseudo_merge_commits, |
1219 | 0 | commits.oid[i]); |
1220 | 0 | if (hash_pos == kh_end(writer->pseudo_merge_commits)) |
1221 | 0 | BUG("could not find pseudo-merge commit %s", |
1222 | 0 | oid_to_hex(&commits.oid[i])); |
1223 | | |
1224 | 0 | c = kh_value(writer->pseudo_merge_commits, hash_pos); |
1225 | |
|
1226 | 0 | hashwrite_be32(f, find_object_pos(writer, &commits.oid[i], |
1227 | 0 | NULL)); |
1228 | 0 | if (c->nr == 1) |
1229 | 0 | hashwrite_be64(f, pseudo_merge_ofs[c->pseudo_merge[0]]); |
1230 | 0 | else if (c->nr > 1) { |
1231 | 0 | if (next_ext & ((uint64_t)1<<63)) |
1232 | 0 | die(_("too many pseudo-merges")); |
1233 | 0 | hashwrite_be64(f, next_ext | ((uint64_t)1<<63)); |
1234 | 0 | next_ext = st_add3(next_ext, |
1235 | 0 | sizeof(uint32_t), |
1236 | 0 | st_mult(c->nr, sizeof(uint64_t))); |
1237 | 0 | } else |
1238 | 0 | BUG("expected commit '%s' to have at least one " |
1239 | 0 | "pseudo-merge", oid_to_hex(&commits.oid[i])); |
1240 | 0 | } |
1241 | | |
1242 | | /* write lookup table (extended) */ |
1243 | 0 | for (i = 0; i < commits.nr; i++) { |
1244 | 0 | int hash_pos; |
1245 | 0 | struct pseudo_merge_commit_idx *c; |
1246 | |
|
1247 | 0 | hash_pos = kh_get_oid_map(writer->pseudo_merge_commits, |
1248 | 0 | commits.oid[i]); |
1249 | 0 | if (hash_pos == kh_end(writer->pseudo_merge_commits)) |
1250 | 0 | BUG("could not find pseudo-merge commit %s", |
1251 | 0 | oid_to_hex(&commits.oid[i])); |
1252 | | |
1253 | 0 | c = kh_value(writer->pseudo_merge_commits, hash_pos); |
1254 | 0 | if (c->nr == 1) |
1255 | 0 | continue; |
1256 | | |
1257 | 0 | hashwrite_be32(f, c->nr); |
1258 | 0 | for (j = 0; j < c->nr; j++) |
1259 | 0 | hashwrite_be64(f, pseudo_merge_ofs[c->pseudo_merge[j]]); |
1260 | 0 | } |
1261 | | |
1262 | | /* write positions for all pseudo merges */ |
1263 | 0 | for (i = 0; i < writer->pseudo_merges_nr; i++) |
1264 | 0 | hashwrite_be64(f, pseudo_merge_ofs[i]); |
1265 | |
|
1266 | 0 | hashwrite_be32(f, writer->pseudo_merges_nr); |
1267 | 0 | hashwrite_be32(f, kh_size(writer->pseudo_merge_commits)); |
1268 | 0 | hashwrite_be64(f, table_start - start); |
1269 | 0 | hashwrite_be64(f, hashfile_total(f) - start + sizeof(uint64_t)); |
1270 | |
|
1271 | 0 | oid_array_clear(&commits); |
1272 | 0 | free(pseudo_merge_ofs); |
1273 | 0 | } |
1274 | | |
1275 | | static int table_cmp(const void *_va, const void *_vb, void *_data) |
1276 | 0 | { |
1277 | 0 | struct bitmap_writer *writer = _data; |
1278 | 0 | struct bitmapped_commit *a = &writer->selected[*(uint32_t *)_va]; |
1279 | 0 | struct bitmapped_commit *b = &writer->selected[*(uint32_t *)_vb]; |
1280 | |
|
1281 | 0 | if (a->commit_pos < b->commit_pos) |
1282 | 0 | return -1; |
1283 | 0 | else if (a->commit_pos > b->commit_pos) |
1284 | 0 | return 1; |
1285 | | |
1286 | 0 | return 0; |
1287 | 0 | } |
1288 | | |
1289 | | static void write_lookup_table(struct bitmap_writer *writer, struct hashfile *f, |
1290 | | off_t *offsets) |
1291 | 0 | { |
1292 | 0 | uint32_t i; |
1293 | 0 | uint32_t *table, *table_inv; |
1294 | |
|
1295 | 0 | ALLOC_ARRAY(table, bitmap_writer_nr_selected_commits(writer)); |
1296 | 0 | ALLOC_ARRAY(table_inv, bitmap_writer_nr_selected_commits(writer)); |
1297 | |
|
1298 | 0 | for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++) |
1299 | 0 | table[i] = i; |
1300 | | |
1301 | | /* |
1302 | | * At the end of this sort table[j] = i means that the i'th |
1303 | | * bitmap corresponds to j'th bitmapped commit (among the selected |
1304 | | * commits) in lex order of OIDs. |
1305 | | */ |
1306 | 0 | QSORT_S(table, bitmap_writer_nr_selected_commits(writer), table_cmp, writer); |
1307 | | |
1308 | | /* table_inv helps us discover that relationship (i'th bitmap |
1309 | | * to j'th commit by j = table_inv[i]) |
1310 | | */ |
1311 | 0 | for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++) |
1312 | 0 | table_inv[table[i]] = i; |
1313 | |
|
1314 | 0 | trace2_region_enter("pack-bitmap-write", "writing_lookup_table", writer->repo); |
1315 | 0 | for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++) { |
1316 | 0 | struct bitmapped_commit *selected = &writer->selected[table[i]]; |
1317 | 0 | uint32_t xor_offset = selected->xor_offset; |
1318 | 0 | uint32_t xor_row; |
1319 | |
|
1320 | 0 | if (xor_offset) { |
1321 | | /* |
1322 | | * xor_index stores the index (in the bitmap entries) |
1323 | | * of the corresponding xor bitmap. But we need to convert |
1324 | | * this index into lookup table's index. So, table_inv[xor_index] |
1325 | | * gives us the index position w.r.t. the lookup table. |
1326 | | * |
1327 | | * If "k = table[i] - xor_offset" then the xor base is the k'th |
1328 | | * bitmap. `table_inv[k]` gives us the position of that bitmap |
1329 | | * in the lookup table. |
1330 | | */ |
1331 | 0 | uint32_t xor_index = table[i] - xor_offset; |
1332 | 0 | xor_row = table_inv[xor_index]; |
1333 | 0 | } else { |
1334 | 0 | xor_row = 0xffffffff; |
1335 | 0 | } |
1336 | |
|
1337 | 0 | hashwrite_be32(f, writer->selected[table[i]].commit_pos); |
1338 | 0 | hashwrite_be64(f, (uint64_t)offsets[table[i]]); |
1339 | 0 | hashwrite_be32(f, xor_row); |
1340 | 0 | } |
1341 | 0 | trace2_region_leave("pack-bitmap-write", "writing_lookup_table", writer->repo); |
1342 | |
|
1343 | 0 | free(table); |
1344 | 0 | free(table_inv); |
1345 | 0 | } |
1346 | | |
1347 | | static void write_hash_cache(struct hashfile *f, |
1348 | | struct pack_idx_entry **index, |
1349 | | uint32_t index_nr) |
1350 | 0 | { |
1351 | 0 | uint32_t i; |
1352 | |
|
1353 | 0 | for (i = 0; i < index_nr; ++i) { |
1354 | 0 | struct object_entry *entry = (struct object_entry *)index[i]; |
1355 | 0 | hashwrite_be32(f, entry->hash); |
1356 | 0 | } |
1357 | 0 | } |
1358 | | |
1359 | | void bitmap_writer_set_checksum(struct bitmap_writer *writer, |
1360 | | const unsigned char *sha1) |
1361 | 0 | { |
1362 | 0 | hashcpy(writer->pack_checksum, sha1, writer->repo->hash_algo); |
1363 | 0 | } |
1364 | | |
1365 | | void bitmap_writer_finish(struct bitmap_writer *writer, |
1366 | | struct pack_idx_entry **index, |
1367 | | const char *filename, |
1368 | | uint16_t options) |
1369 | 0 | { |
1370 | 0 | static uint16_t default_version = 1; |
1371 | 0 | static uint16_t flags = BITMAP_OPT_FULL_DAG; |
1372 | 0 | struct strbuf tmp_file = STRBUF_INIT; |
1373 | 0 | struct hashfile *f; |
1374 | 0 | off_t *offsets = NULL; |
1375 | 0 | uint32_t i, base_objects; |
1376 | |
|
1377 | 0 | struct bitmap_disk_header header; |
1378 | |
|
1379 | 0 | int fd = odb_mkstemp(writer->repo->objects, &tmp_file, |
1380 | 0 | "pack/tmp_bitmap_XXXXXX"); |
1381 | |
|
1382 | 0 | if (writer->pseudo_merges_nr) |
1383 | 0 | options |= BITMAP_OPT_PSEUDO_MERGES; |
1384 | |
|
1385 | 0 | f = hashfd(writer->repo->hash_algo, fd, tmp_file.buf); |
1386 | |
|
1387 | 0 | memcpy(header.magic, BITMAP_IDX_SIGNATURE, sizeof(BITMAP_IDX_SIGNATURE)); |
1388 | 0 | header.version = htons(default_version); |
1389 | 0 | header.options = htons(flags | options); |
1390 | 0 | header.entry_count = htonl(bitmap_writer_nr_selected_commits(writer)); |
1391 | 0 | hashcpy(header.checksum, writer->pack_checksum, writer->repo->hash_algo); |
1392 | |
|
1393 | 0 | hashwrite(f, &header, sizeof(header) - GIT_MAX_RAWSZ + writer->repo->hash_algo->rawsz); |
1394 | 0 | dump_bitmap(f, writer->commits); |
1395 | 0 | dump_bitmap(f, writer->trees); |
1396 | 0 | dump_bitmap(f, writer->blobs); |
1397 | 0 | dump_bitmap(f, writer->tags); |
1398 | |
|
1399 | 0 | if (options & BITMAP_OPT_LOOKUP_TABLE) |
1400 | 0 | CALLOC_ARRAY(offsets, writer->to_pack->nr_objects); |
1401 | |
|
1402 | 0 | if (writer->midx) |
1403 | 0 | base_objects = writer->midx->num_objects + |
1404 | 0 | writer->midx->num_objects_in_base; |
1405 | 0 | else |
1406 | 0 | base_objects = 0; |
1407 | |
|
1408 | 0 | for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++) { |
1409 | 0 | struct bitmapped_commit *stored = &writer->selected[i]; |
1410 | 0 | int commit_pos = oid_pos(&stored->commit->object.oid, index, |
1411 | 0 | writer->to_pack->nr_objects, |
1412 | 0 | oid_access); |
1413 | |
|
1414 | 0 | if (commit_pos < 0) |
1415 | 0 | BUG("trying to write commit not in index"); |
1416 | 0 | stored->commit_pos = commit_pos + base_objects; |
1417 | 0 | } |
1418 | | |
1419 | 0 | write_selected_commits_v1(writer, f, offsets); |
1420 | |
|
1421 | 0 | if (options & BITMAP_OPT_PSEUDO_MERGES) |
1422 | 0 | write_pseudo_merges(writer, f); |
1423 | |
|
1424 | 0 | if (options & BITMAP_OPT_LOOKUP_TABLE) |
1425 | 0 | write_lookup_table(writer, f, offsets); |
1426 | |
|
1427 | 0 | if (options & BITMAP_OPT_HASH_CACHE) |
1428 | 0 | write_hash_cache(f, index, writer->to_pack->nr_objects); |
1429 | |
|
1430 | 0 | finalize_hashfile(f, NULL, FSYNC_COMPONENT_PACK_METADATA, |
1431 | 0 | CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE); |
1432 | |
|
1433 | 0 | if (adjust_shared_perm(writer->repo, tmp_file.buf)) |
1434 | 0 | die_errno("unable to make temporary bitmap file readable"); |
1435 | | |
1436 | 0 | if (rename(tmp_file.buf, filename)) |
1437 | 0 | die_errno("unable to rename temporary bitmap file to '%s'", filename); |
1438 | | |
1439 | 0 | strbuf_release(&tmp_file); |
1440 | 0 | free(offsets); |
1441 | 0 | } |