midx-write: move writing-related functions from midx.c
Introduce a new midx-write.c source file, which holds all of the functionality from the MIDX sub-system related to writing new MIDX files. Similar to the relationship between "pack-bitmap.c" and "pack-bitmap-write.c", this source file will hold code that is specific to writing MIDX files as opposed to reading them (the latter will remain in midx.c). Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Taylor Blau committed
Apr 1, 2024 at 17:16 UTC
748b88a0214d4f65fd56d4728234ea86dbcfffd6
4 files changed
+1711
-1695
Makefile
+1
@@ -1075,6 +1075,7 @@ LIB_OBJS += merge-ort-wrappers.o
1075
LIB_OBJS += merge-recursive.o
1076
LIB_OBJS += merge.o
1077
LIB_OBJS += midx.o
1078
+LIB_OBJS += midx-write.o
1079
LIB_OBJS += name-hash.o
1080
LIB_OBJS += negotiator/default.o
1081
LIB_OBJS += negotiator/noop.o
midx-write.c
new
+1521
@@ -0,0 +1,1521 @@
1
+#include "git-compat-util.h"
2
+#include "abspath.h"
3
+#include "config.h"
4
+#include "hex.h"
5
+#include "lockfile.h"
6
+#include "packfile.h"
7
+#include "object-file.h"
8
+#include "hash-lookup.h"
9
+#include "midx.h"
10
+#include "progress.h"
11
+#include "trace2.h"
12
+#include "run-command.h"
13
+#include "chunk-format.h"
14
+#include "pack-bitmap.h"
15
+#include "refs.h"
16
+#include "revision.h"
17
+#include "list-objects.h"
18
+
19
+#define PACK_EXPIRED UINT_MAX
20
+#define BITMAP_POS_UNKNOWN (~((uint32_t)0))
21
+#define MIDX_CHUNK_FANOUT_SIZE (sizeof(uint32_t) * 256)
22
+#define MIDX_CHUNK_LARGE_OFFSET_WIDTH (sizeof(uint64_t))
23
+
24
+extern int midx_checksum_valid(struct multi_pack_index *m);
25
+extern void clear_midx_files_ext(const char *object_dir, const char *ext,
26
+ unsigned char *keep_hash);
27
+extern int cmp_idx_or_pack_name(const char *idx_or_pack_name,
28
+ const char *idx_name);
29
+
30
+static size_t write_midx_header(struct hashfile *f,
31
+ unsigned char num_chunks,
32
+ uint32_t num_packs)
33
+{
34
+ hashwrite_be32(f, MIDX_SIGNATURE);
35
+ hashwrite_u8(f, MIDX_VERSION);
36
+ hashwrite_u8(f, oid_version(the_hash_algo));
37
+ hashwrite_u8(f, num_chunks);
38
+ hashwrite_u8(f, 0); /* unused */
39
+ hashwrite_be32(f, num_packs);
40
+
41
+ return MIDX_HEADER_SIZE;
42
+}
43
+
44
+struct pack_info {
45
+ uint32_t orig_pack_int_id;
46
+ char *pack_name;
47
+ struct packed_git *p;
48
+
49
+ uint32_t bitmap_pos;
50
+ uint32_t bitmap_nr;
51
+
52
+ unsigned expired : 1;
53
+};
54
+
55
+static void fill_pack_info(struct pack_info *info,
56
+ struct packed_git *p, const char *pack_name,
57
+ uint32_t orig_pack_int_id)
58
+{
59
+ memset(info, 0, sizeof(struct pack_info));
60
+
61
+ info->orig_pack_int_id = orig_pack_int_id;
62
+ info->pack_name = xstrdup(pack_name);
63
+ info->p = p;
64
+ info->bitmap_pos = BITMAP_POS_UNKNOWN;
65
+}
66
+
67
+static int pack_info_compare(const void *_a, const void *_b)
68
+{
69
+ struct pack_info *a = (struct pack_info *)_a;
70
+ struct pack_info *b = (struct pack_info *)_b;
71
+ return strcmp(a->pack_name, b->pack_name);
72
+}
73
+
74
+static int idx_or_pack_name_cmp(const void *_va, const void *_vb)
75
+{
76
+ const char *pack_name = _va;
77
+ const struct pack_info *compar = _vb;
78
+
79
+ return cmp_idx_or_pack_name(pack_name, compar->pack_name);
80
+}
81
+
82
+struct write_midx_context {
83
+ struct pack_info *info;
84
+ size_t nr;
85
+ size_t alloc;
86
+ struct multi_pack_index *m;
87
+ struct progress *progress;
88
+ unsigned pack_paths_checked;
89
+
90
+ struct pack_midx_entry *entries;
91
+ size_t entries_nr;
92
+
93
+ uint32_t *pack_perm;
94
+ uint32_t *pack_order;
95
+ unsigned large_offsets_needed:1;
96
+ uint32_t num_large_offsets;
97
+
98
+ int preferred_pack_idx;
99
+
100
+ struct string_list *to_include;
101
+};
102
+
103
+static void add_pack_to_midx(const char *full_path, size_t full_path_len,
104
+ const char *file_name, void *data)
105
+{
106
+ struct write_midx_context *ctx = data;
107
+ struct packed_git *p;
108
+
109
+ if (ends_with(file_name, ".idx")) {
110
+ display_progress(ctx->progress, ++ctx->pack_paths_checked);
111
+ /*
112
+ * Note that at most one of ctx->m and ctx->to_include are set,
113
+ * so we are testing midx_contains_pack() and
114
+ * string_list_has_string() independently (guarded by the
115
+ * appropriate NULL checks).
116
+ *
117
+ * We could support passing to_include while reusing an existing
118
+ * MIDX, but don't currently since the reuse process drags
119
+ * forward all packs from an existing MIDX (without checking
120
+ * whether or not they appear in the to_include list).
121
+ *
122
+ * If we added support for that, these next two conditional
123
+ * should be performed independently (likely checking
124
+ * to_include before the existing MIDX).
125
+ */
126
+ if (ctx->m && midx_contains_pack(ctx->m, file_name))
127
+ return;
128
+ else if (ctx->to_include &&
129
+ !string_list_has_string(ctx->to_include, file_name))
130
+ return;
131
+
132
+ ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc);
133
+
134
+ p = add_packed_git(full_path, full_path_len, 0);
135
+ if (!p) {
136
+ warning(_("failed to add packfile '%s'"),
137
+ full_path);
138
+ return;
139
+ }
140
+
141
+ if (open_pack_index(p)) {
142
+ warning(_("failed to open pack-index '%s'"),
143
+ full_path);
144
+ close_pack(p);
145
+ free(p);
146
+ return;
147
+ }
148
+
149
+ fill_pack_info(&ctx->info[ctx->nr], p, file_name, ctx->nr);
150
+ ctx->nr++;
151
+ }
152
+}
153
+
154
+struct pack_midx_entry {
155
+ struct object_id oid;
156
+ uint32_t pack_int_id;
157
+ time_t pack_mtime;
158
+ uint64_t offset;
159
+ unsigned preferred : 1;
160
+};
161
+
162
+static int midx_oid_compare(const void *_a, const void *_b)
163
+{
164
+ const struct pack_midx_entry *a = (const struct pack_midx_entry *)_a;
165
+ const struct pack_midx_entry *b = (const struct pack_midx_entry *)_b;
166
+ int cmp = oidcmp(&a->oid, &b->oid);
167
+
168
+ if (cmp)
169
+ return cmp;
170
+
171
+ /* Sort objects in a preferred pack first when multiple copies exist. */
172
+ if (a->preferred > b->preferred)
173
+ return -1;
174
+ if (a->preferred < b->preferred)
175
+ return 1;
176
+
177
+ if (a->pack_mtime > b->pack_mtime)
178
+ return -1;
179
+ else if (a->pack_mtime < b->pack_mtime)
180
+ return 1;
181
+
182
+ return a->pack_int_id - b->pack_int_id;
183
+}
184
+
185
+static int nth_midxed_pack_midx_entry(struct multi_pack_index *m,
186
+ struct pack_midx_entry *e,
187
+ uint32_t pos)
188
+{
189
+ if (pos >= m->num_objects)
190
+ return 1;
191
+
192
+ nth_midxed_object_oid(&e->oid, m, pos);
193
+ e->pack_int_id = nth_midxed_pack_int_id(m, pos);
194
+ e->offset = nth_midxed_offset(m, pos);
195
+
196
+ /* consider objects in midx to be from "old" packs */
197
+ e->pack_mtime = 0;
198
+ return 0;
199
+}
200
+
201
+static void fill_pack_entry(uint32_t pack_int_id,
202
+ struct packed_git *p,
203
+ uint32_t cur_object,
204
+ struct pack_midx_entry *entry,
205
+ int preferred)
206
+{
207
+ if (nth_packed_object_id(&entry->oid, p, cur_object) < 0)
208
+ die(_("failed to locate object %d in packfile"), cur_object);
209
+
210
+ entry->pack_int_id = pack_int_id;
211
+ entry->pack_mtime = p->mtime;
212
+
213
+ entry->offset = nth_packed_object_offset(p, cur_object);
214
+ entry->preferred = !!preferred;
215
+}
216
+
217
+struct midx_fanout {
218
+ struct pack_midx_entry *entries;
219
+ size_t nr, alloc;
220
+};
221
+
222
+static void midx_fanout_grow(struct midx_fanout *fanout, size_t nr)
223
+{
224
+ if (nr < fanout->nr)
225
+ BUG("negative growth in midx_fanout_grow() (%"PRIuMAX" < %"PRIuMAX")",
226
+ (uintmax_t)nr, (uintmax_t)fanout->nr);
227
+ ALLOC_GROW(fanout->entries, nr, fanout->alloc);
228
+}
229
+
230
+static void midx_fanout_sort(struct midx_fanout *fanout)
231
+{
232
+ QSORT(fanout->entries, fanout->nr, midx_oid_compare);
233
+}
234
+
235
+static void midx_fanout_add_midx_fanout(struct midx_fanout *fanout,
236
+ struct multi_pack_index *m,
237
+ uint32_t cur_fanout,
238
+ int preferred_pack)
239
+{
240
+ uint32_t start = 0, end;
241
+ uint32_t cur_object;
242
+
243
+ if (cur_fanout)
244
+ start = ntohl(m->chunk_oid_fanout[cur_fanout - 1]);
245
+ end = ntohl(m->chunk_oid_fanout[cur_fanout]);
246
+
247
+ for (cur_object = start; cur_object < end; cur_object++) {
248
+ if ((preferred_pack > -1) &&
249
+ (preferred_pack == nth_midxed_pack_int_id(m, cur_object))) {
250
+ /*
251
+ * Objects from preferred packs are added
252
+ * separately.
253
+ */
254
+ continue;
255
+ }
256
+
257
+ midx_fanout_grow(fanout, fanout->nr + 1);
258
+ nth_midxed_pack_midx_entry(m,
259
+ &fanout->entries[fanout->nr],
260
+ cur_object);
261
+ fanout->entries[fanout->nr].preferred = 0;
262
+ fanout->nr++;
263
+ }
264
+}
265
+
266
+static void midx_fanout_add_pack_fanout(struct midx_fanout *fanout,
267
+ struct pack_info *info,
268
+ uint32_t cur_pack,
269
+ int preferred,
270
+ uint32_t cur_fanout)
271
+{
272
+ struct packed_git *pack = info[cur_pack].p;
273
+ uint32_t start = 0, end;
274
+ uint32_t cur_object;
275
+
276
+ if (cur_fanout)
277
+ start = get_pack_fanout(pack, cur_fanout - 1);
278
+ end = get_pack_fanout(pack, cur_fanout);
279
+
280
+ for (cur_object = start; cur_object < end; cur_object++) {
281
+ midx_fanout_grow(fanout, fanout->nr + 1);
282
+ fill_pack_entry(cur_pack,
283
+ info[cur_pack].p,
284
+ cur_object,
285
+ &fanout->entries[fanout->nr],
286
+ preferred);
287
+ fanout->nr++;
288
+ }
289
+}
290
+
291
+/*
292
+ * It is possible to artificially get into a state where there are many
293
+ * duplicate copies of objects. That can create high memory pressure if
294
+ * we are to create a list of all objects before de-duplication. To reduce
295
+ * this memory pressure without a significant performance drop, automatically
296
+ * group objects by the first byte of their object id. Use the IDX fanout
297
+ * tables to group the data, copy to a local array, then sort.
298
+ *
299
+ * Copy only the de-duplicated entries (selected by most-recent modified time
300
+ * of a packfile containing the object).
301
+ */
302
+static struct pack_midx_entry *get_sorted_entries(struct multi_pack_index *m,
303
+ struct pack_info *info,
304
+ uint32_t nr_packs,
305
+ size_t *nr_objects,
306
+ int preferred_pack)
307
+{
308
+ uint32_t cur_fanout, cur_pack, cur_object;
309
+ size_t alloc_objects, total_objects = 0;
310
+ struct midx_fanout fanout = { 0 };
311
+ struct pack_midx_entry *deduplicated_entries = NULL;
312
+ uint32_t start_pack = m ? m->num_packs : 0;
313
+
314
+ for (cur_pack = start_pack; cur_pack < nr_packs; cur_pack++)
315
+ total_objects = st_add(total_objects,
316
+ info[cur_pack].p->num_objects);
317
+
318
+ /*
319
+ * As we de-duplicate by fanout value, we expect the fanout
320
+ * slices to be evenly distributed, with some noise. Hence,
321
+ * allocate slightly more than one 256th.
322
+ */
323
+ alloc_objects = fanout.alloc = total_objects > 3200 ? total_objects / 200 : 16;
324
+
325
+ ALLOC_ARRAY(fanout.entries, fanout.alloc);
326
+ ALLOC_ARRAY(deduplicated_entries, alloc_objects);
327
+ *nr_objects = 0;
328
+
329
+ for (cur_fanout = 0; cur_fanout < 256; cur_fanout++) {
330
+ fanout.nr = 0;
331
+
332
+ if (m)
333
+ midx_fanout_add_midx_fanout(&fanout, m, cur_fanout,
334
+ preferred_pack);
335
+
336
+ for (cur_pack = start_pack; cur_pack < nr_packs; cur_pack++) {
337
+ int preferred = cur_pack == preferred_pack;
338
+ midx_fanout_add_pack_fanout(&fanout,
339
+ info, cur_pack,
340
+ preferred, cur_fanout);
341
+ }
342
+
343
+ if (-1 < preferred_pack && preferred_pack < start_pack)
344
+ midx_fanout_add_pack_fanout(&fanout, info,
345
+ preferred_pack, 1,
346
+ cur_fanout);
347
+
348
+ midx_fanout_sort(&fanout);
349
+
350
+ /*
351
+ * The batch is now sorted by OID and then mtime (descending).
352
+ * Take only the first duplicate.
353
+ */
354
+ for (cur_object = 0; cur_object < fanout.nr; cur_object++) {
355
+ if (cur_object && oideq(&fanout.entries[cur_object - 1].oid,
356
+ &fanout.entries[cur_object].oid))
357
+ continue;
358
+
359
+ ALLOC_GROW(deduplicated_entries, st_add(*nr_objects, 1),
360
+ alloc_objects);
361
+ memcpy(&deduplicated_entries[*nr_objects],
362
+ &fanout.entries[cur_object],
363
+ sizeof(struct pack_midx_entry));
364
+ (*nr_objects)++;
365
+ }
366
+ }
367
+
368
+ free(fanout.entries);
369
+ return deduplicated_entries;
370
+}
371
+
372
+static int write_midx_pack_names(struct hashfile *f, void *data)
373
+{
374
+ struct write_midx_context *ctx = data;
375
+ uint32_t i;
376
+ unsigned char padding[MIDX_CHUNK_ALIGNMENT];
377
+ size_t written = 0;
378
+
379
+ for (i = 0; i < ctx->nr; i++) {
380
+ size_t writelen;
381
+
382
+ if (ctx->info[i].expired)
383
+ continue;
384
+
385
+ if (i && strcmp(ctx->info[i].pack_name, ctx->info[i - 1].pack_name) <= 0)
386
+ BUG("incorrect pack-file order: %s before %s",
387
+ ctx->info[i - 1].pack_name,
388
+ ctx->info[i].pack_name);
389
+
390
+ writelen = strlen(ctx->info[i].pack_name) + 1;
391
+ hashwrite(f, ctx->info[i].pack_name, writelen);
392
+ written += writelen;
393
+ }
394
+
395
+ /* add padding to be aligned */
396
+ i = MIDX_CHUNK_ALIGNMENT - (written % MIDX_CHUNK_ALIGNMENT);
397
+ if (i < MIDX_CHUNK_ALIGNMENT) {
398
+ memset(padding, 0, sizeof(padding));
399
+ hashwrite(f, padding, i);
400
+ }
401
+
402
+ return 0;
403
+}
404
+
405
+static int write_midx_bitmapped_packs(struct hashfile *f, void *data)
406
+{
407
+ struct write_midx_context *ctx = data;
408
+ size_t i;
409
+
410
+ for (i = 0; i < ctx->nr; i++) {
411
+ struct pack_info *pack = &ctx->info[i];
412
+ if (pack->expired)
413
+ continue;
414
+
415
+ if (pack->bitmap_pos == BITMAP_POS_UNKNOWN && pack->bitmap_nr)
416
+ BUG("pack '%s' has no bitmap position, but has %d bitmapped object(s)",
417
+ pack->pack_name, pack->bitmap_nr);
418
+
419
+ hashwrite_be32(f, pack->bitmap_pos);
420
+ hashwrite_be32(f, pack->bitmap_nr);
421
+ }
422
+ return 0;
423
+}
424
+
425
+static int write_midx_oid_fanout(struct hashfile *f,
426
+ void *data)
427
+{
428
+ struct write_midx_context *ctx = data;
429
+ struct pack_midx_entry *list = ctx->entries;
430
+ struct pack_midx_entry *last = ctx->entries + ctx->entries_nr;
431
+ uint32_t count = 0;
432
+ uint32_t i;
433
+
434
+ /*
435
+ * Write the first-level table (the list is sorted,
436
+ * but we use a 256-entry lookup to be able to avoid
437
+ * having to do eight extra binary search iterations).
438
+ */
439
+ for (i = 0; i < 256; i++) {
440
+ struct pack_midx_entry *next = list;
441
+
442
+ while (next < last && next->oid.hash[0] == i) {
443
+ count++;
444
+ next++;
445
+ }
446
+
447
+ hashwrite_be32(f, count);
448
+ list = next;
449
+ }
450
+
451
+ return 0;
452
+}
453
+
454
+static int write_midx_oid_lookup(struct hashfile *f,
455
+ void *data)
456
+{
457
+ struct write_midx_context *ctx = data;
458
+ unsigned char hash_len = the_hash_algo->rawsz;
459
+ struct pack_midx_entry *list = ctx->entries;
460
+ uint32_t i;
461
+
462
+ for (i = 0; i < ctx->entries_nr; i++) {
463
+ struct pack_midx_entry *obj = list++;
464
+
465
+ if (i < ctx->entries_nr - 1) {
466
+ struct pack_midx_entry *next = list;
467
+ if (oidcmp(&obj->oid, &next->oid) >= 0)
468
+ BUG("OIDs not in order: %s >= %s",
469
+ oid_to_hex(&obj->oid),
470
+ oid_to_hex(&next->oid));
471
+ }
472
+
473
+ hashwrite(f, obj->oid.hash, (int)hash_len);
474
+ }
475
+
476
+ return 0;
477
+}
478
+
479
+static int write_midx_object_offsets(struct hashfile *f,
480
+ void *data)
481
+{
482
+ struct write_midx_context *ctx = data;
483
+ struct pack_midx_entry *list = ctx->entries;
484
+ uint32_t i, nr_large_offset = 0;
485
+
486
+ for (i = 0; i < ctx->entries_nr; i++) {
487
+ struct pack_midx_entry *obj = list++;
488
+
489
+ if (ctx->pack_perm[obj->pack_int_id] == PACK_EXPIRED)
490
+ BUG("object %s is in an expired pack with int-id %d",
491
+ oid_to_hex(&obj->oid),
492
+ obj->pack_int_id);
493
+
494
+ hashwrite_be32(f, ctx->pack_perm[obj->pack_int_id]);
495
+
496
+ if (ctx->large_offsets_needed && obj->offset >> 31)
497
+ hashwrite_be32(f, MIDX_LARGE_OFFSET_NEEDED | nr_large_offset++);
498
+ else if (!ctx->large_offsets_needed && obj->offset >> 32)
499
+ BUG("object %s requires a large offset (%"PRIx64") but the MIDX is not writing large offsets!",
500
+ oid_to_hex(&obj->oid),
501
+ obj->offset);
502
+ else
503
+ hashwrite_be32(f, (uint32_t)obj->offset);
504
+ }
505
+
506
+ return 0;
507
+}
508
+
509
+static int write_midx_large_offsets(struct hashfile *f,
510
+ void *data)
511
+{
512
+ struct write_midx_context *ctx = data;
513
+ struct pack_midx_entry *list = ctx->entries;
514
+ struct pack_midx_entry *end = ctx->entries + ctx->entries_nr;
515
+ uint32_t nr_large_offset = ctx->num_large_offsets;
516
+
517
+ while (nr_large_offset) {
518
+ struct pack_midx_entry *obj;
519
+ uint64_t offset;
520
+
521
+ if (list >= end)
522
+ BUG("too many large-offset objects");
523
+
524
+ obj = list++;
525
+ offset = obj->offset;
526
+
527
+ if (!(offset >> 31))
528
+ continue;
529
+
530
+ hashwrite_be64(f, offset);
531
+
532
+ nr_large_offset--;
533
+ }
534
+
535
+ return 0;
536
+}
537
+
538
+static int write_midx_revindex(struct hashfile *f,
539
+ void *data)
540
+{
541
+ struct write_midx_context *ctx = data;
542
+ uint32_t i;
543
+
544
+ for (i = 0; i < ctx->entries_nr; i++)
545
+ hashwrite_be32(f, ctx->pack_order[i]);
546
+
547
+ return 0;
548
+}
549
+
550
+struct midx_pack_order_data {
551
+ uint32_t nr;
552
+ uint32_t pack;
553
+ off_t offset;
554
+};
555
+
556
+static int midx_pack_order_cmp(const void *va, const void *vb)
557
+{
558
+ const struct midx_pack_order_data *a = va, *b = vb;
559
+ if (a->pack < b->pack)
560
+ return -1;
561
+ else if (a->pack > b->pack)
562
+ return 1;
563
+ else if (a->offset < b->offset)
564
+ return -1;
565
+ else if (a->offset > b->offset)
566
+ return 1;
567
+ else
568
+ return 0;
569
+}
570
+
571
+static uint32_t *midx_pack_order(struct write_midx_context *ctx)
572
+{
573
+ struct midx_pack_order_data *data;
574
+ uint32_t *pack_order;
575
+ uint32_t i;
576
+
577
+ trace2_region_enter("midx", "midx_pack_order", the_repository);
578
+
579
+ ALLOC_ARRAY(data, ctx->entries_nr);
580
+ for (i = 0; i < ctx->entries_nr; i++) {
581
+ struct pack_midx_entry *e = &ctx->entries[i];
582
+ data[i].nr = i;
583
+ data[i].pack = ctx->pack_perm[e->pack_int_id];
584
+ if (!e->preferred)
585
+ data[i].pack |= (1U << 31);
586
+ data[i].offset = e->offset;
587
+ }
588
+
589
+ QSORT(data, ctx->entries_nr, midx_pack_order_cmp);
590
+
591
+ ALLOC_ARRAY(pack_order, ctx->entries_nr);
592
+ for (i = 0; i < ctx->entries_nr; i++) {
593
+ struct pack_midx_entry *e = &ctx->entries[data[i].nr];
594
+ struct pack_info *pack = &ctx->info[ctx->pack_perm[e->pack_int_id]];
595
+ if (pack->bitmap_pos == BITMAP_POS_UNKNOWN)
596
+ pack->bitmap_pos = i;
597
+ pack->bitmap_nr++;
598
+ pack_order[i] = data[i].nr;
599
+ }
600
+ for (i = 0; i < ctx->nr; i++) {
601
+ struct pack_info *pack = &ctx->info[ctx->pack_perm[i]];
602
+ if (pack->bitmap_pos == BITMAP_POS_UNKNOWN)
603
+ pack->bitmap_pos = 0;
604
+ }
605
+ free(data);
606
+
607
+ trace2_region_leave("midx", "midx_pack_order", the_repository);
608
+
609
+ return pack_order;
610
+}
611
+
612
+static void write_midx_reverse_index(char *midx_name, unsigned char *midx_hash,
613
+ struct write_midx_context *ctx)
614
+{
615
+ struct strbuf buf = STRBUF_INIT;
616
+ const char *tmp_file;
617
+
618
+ trace2_region_enter("midx", "write_midx_reverse_index", the_repository);
619
+
620
+ strbuf_addf(&buf, "%s-%s.rev", midx_name, hash_to_hex(midx_hash));
621
+
622
+ tmp_file = write_rev_file_order(NULL, ctx->pack_order, ctx->entries_nr,
623
+ midx_hash, WRITE_REV);
624
+
625
+ if (finalize_object_file(tmp_file, buf.buf))
626
+ die(_("cannot store reverse index file"));
627
+
628
+ strbuf_release(&buf);
629
+
630
+ trace2_region_leave("midx", "write_midx_reverse_index", the_repository);
631
+}
632
+
633
+static void prepare_midx_packing_data(struct packing_data *pdata,
634
+ struct write_midx_context *ctx)
635
+{
636
+ uint32_t i;
637
+
638
+ trace2_region_enter("midx", "prepare_midx_packing_data", the_repository);
639
+
640
+ memset(pdata, 0, sizeof(struct packing_data));
641
+ prepare_packing_data(the_repository, pdata);
642
+
643
+ for (i = 0; i < ctx->entries_nr; i++) {
644
+ struct pack_midx_entry *from = &ctx->entries[ctx->pack_order[i]];
645
+ struct object_entry *to = packlist_alloc(pdata, &from->oid);
646
+
647
+ oe_set_in_pack(pdata, to,
648
+ ctx->info[ctx->pack_perm[from->pack_int_id]].p);
649
+ }
650
+
651
+ trace2_region_leave("midx", "prepare_midx_packing_data", the_repository);
652
+}
653
+
654
+static int add_ref_to_pending(const char *refname,
655
+ const struct object_id *oid,
656
+ int flag, void *cb_data)
657
+{
658
+ struct rev_info *revs = (struct rev_info*)cb_data;
659
+ struct object_id peeled;
660
+ struct object *object;
661
+
662
+ if ((flag & REF_ISSYMREF) && (flag & REF_ISBROKEN)) {
663
+ warning("symbolic ref is dangling: %s", refname);
664
+ return 0;
665
+ }
666
+
667
+ if (!peel_iterated_oid(oid, &peeled))
668
+ oid = &peeled;
669
+
670
+ object = parse_object_or_die(oid, refname);
671
+ if (object->type != OBJ_COMMIT)
672
+ return 0;
673
+
674
+ add_pending_object(revs, object, "");
675
+ if (bitmap_is_preferred_refname(revs->repo, refname))
676
+ object->flags |= NEEDS_BITMAP;
677
+ return 0;
678
+}
679
+
680
+struct bitmap_commit_cb {
681
+ struct commit **commits;
682
+ size_t commits_nr, commits_alloc;
683
+
684
+ struct write_midx_context *ctx;
685
+};
686
+
687
+static const struct object_id *bitmap_oid_access(size_t index,
688
+ const void *_entries)
689
+{
690
+ const struct pack_midx_entry *entries = _entries;
691
+ return &entries[index].oid;
692
+}
693
+
694
+static void bitmap_show_commit(struct commit *commit, void *_data)
695
+{
696
+ struct bitmap_commit_cb *data = _data;
697
+ int pos = oid_pos(&commit->object.oid, data->ctx->entries,
698
+ data->ctx->entries_nr,
699
+ bitmap_oid_access);
700
+ if (pos < 0)
701
+ return;
702
+
703
+ ALLOC_GROW(data->commits, data->commits_nr + 1, data->commits_alloc);
704
+ data->commits[data->commits_nr++] = commit;
705
+}
706
+
707
+static int read_refs_snapshot(const char *refs_snapshot,
708
+ struct rev_info *revs)
709
+{
710
+ struct strbuf buf = STRBUF_INIT;
711
+ struct object_id oid;
712
+ FILE *f = xfopen(refs_snapshot, "r");
713
+
714
+ while (strbuf_getline(&buf, f) != EOF) {
715
+ struct object *object;
716
+ int preferred = 0;
717
+ char *hex = buf.buf;
718
+ const char *end = NULL;
719
+
720
+ if (buf.len && *buf.buf == '+') {
721
+ preferred = 1;
722
+ hex = &buf.buf[1];
723
+ }
724
+
725
+ if (parse_oid_hex(hex, &oid, &end) < 0)
726
+ die(_("could not parse line: %s"), buf.buf);
727
+ if (*end)
728
+ die(_("malformed line: %s"), buf.buf);
729
+
730
+ object = parse_object_or_die(&oid, NULL);
731
+ if (preferred)
732
+ object->flags |= NEEDS_BITMAP;
733
+
734
+ add_pending_object(revs, object, "");
735
+ }
736
+
737
+ fclose(f);
738
+ strbuf_release(&buf);
739
+ return 0;
740
+}
741
+static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr_p,
742
+ const char *refs_snapshot,
743
+ struct write_midx_context *ctx)
744
+{
745
+ struct rev_info revs;
746
+ struct bitmap_commit_cb cb = {0};
747
+
748
+ trace2_region_enter("midx", "find_commits_for_midx_bitmap",
749
+ the_repository);
750
+
751
+ cb.ctx = ctx;
752
+
753
+ repo_init_revisions(the_repository, &revs, NULL);
754
+ if (refs_snapshot) {
755
+ read_refs_snapshot(refs_snapshot, &revs);
756
+ } else {
757
+ setup_revisions(0, NULL, &revs, NULL);
758
+ for_each_ref(add_ref_to_pending, &revs);
759
+ }
760
+
761
+ /*
762
+ * Skipping promisor objects here is intentional, since it only excludes
763
+ * them from the list of reachable commits that we want to select from
764
+ * when computing the selection of MIDX'd commits to receive bitmaps.
765
+ *
766
+ * Reachability bitmaps do require that their objects be closed under
767
+ * reachability, but fetching any objects missing from promisors at this
768
+ * point is too late. But, if one of those objects can be reached from
769
+ * an another object that is included in the bitmap, then we will
770
+ * complain later that we don't have reachability closure (and fail
771
+ * appropriately).
772
+ */
773
+ fetch_if_missing = 0;
774
+ revs.exclude_promisor_objects = 1;
775
+
776
+ if (prepare_revision_walk(&revs))
777
+ die(_("revision walk setup failed"));
778
+
779
+ traverse_commit_list(&revs, bitmap_show_commit, NULL, &cb);
780
+ if (indexed_commits_nr_p)
781
+ *indexed_commits_nr_p = cb.commits_nr;
782
+
783
+ release_revisions(&revs);
784
+
785
+ trace2_region_leave("midx", "find_commits_for_midx_bitmap",
786
+ the_repository);
787
+
788
+ return cb.commits;
789
+}
790
+
791
+static int write_midx_bitmap(const char *midx_name,
792
+ const unsigned char *midx_hash,
793
+ struct packing_data *pdata,
794
+ struct commit **commits,
795
+ uint32_t commits_nr,
796
+ uint32_t *pack_order,
797
+ unsigned flags)
798
+{
799
+ int ret, i;
800
+ uint16_t options = 0;
801
+ struct pack_idx_entry **index;
802
+ char *bitmap_name = xstrfmt("%s-%s.bitmap", midx_name,
803
+ hash_to_hex(midx_hash));
804
+
805
+ trace2_region_enter("midx", "write_midx_bitmap", the_repository);
806
+
807
+ if (flags & MIDX_WRITE_BITMAP_HASH_CACHE)
808
+ options |= BITMAP_OPT_HASH_CACHE;
809
+
810
+ if (flags & MIDX_WRITE_BITMAP_LOOKUP_TABLE)
811
+ options |= BITMAP_OPT_LOOKUP_TABLE;
812
+
813
+ /*
814
+ * Build the MIDX-order index based on pdata.objects (which is already
815
+ * in MIDX order; c.f., 'midx_pack_order_cmp()' for the definition of
816
+ * this order).
817
+ */
818
+ ALLOC_ARRAY(index, pdata->nr_objects);
819
+ for (i = 0; i < pdata->nr_objects; i++)
820
+ index[i] = &pdata->objects[i].idx;
821
+
822
+ bitmap_writer_show_progress(flags & MIDX_PROGRESS);
823
+ bitmap_writer_build_type_index(pdata, index, pdata->nr_objects);
824
+
825
+ /*
826
+ * bitmap_writer_finish expects objects in lex order, but pack_order
827
+ * gives us exactly that. use it directly instead of re-sorting the
828
+ * array.
829
+ *
830
+ * This changes the order of objects in 'index' between
831
+ * bitmap_writer_build_type_index and bitmap_writer_finish.
832
+ *
833
+ * The same re-ordering takes place in the single-pack bitmap code via
834
+ * write_idx_file(), which is called by finish_tmp_packfile(), which
835
+ * happens between bitmap_writer_build_type_index() and
836
+ * bitmap_writer_finish().
837
+ */
838
+ for (i = 0; i < pdata->nr_objects; i++)
839
+ index[pack_order[i]] = &pdata->objects[i].idx;
840
+
841
+ bitmap_writer_select_commits(commits, commits_nr, -1);
842
+ ret = bitmap_writer_build(pdata);
843
+ if (ret < 0)
844
+ goto cleanup;
845
+
846
+ bitmap_writer_set_checksum(midx_hash);
847
+ bitmap_writer_finish(index, pdata->nr_objects, bitmap_name, options);
848
+
849
+cleanup:
850
+ free(index);
851
+ free(bitmap_name);
852
+
853
+ trace2_region_leave("midx", "write_midx_bitmap", the_repository);
854
+
855
+ return ret;
856
+}
857
+
858
+static struct multi_pack_index *lookup_multi_pack_index(struct repository *r,
859
+ const char *object_dir)
860
+{
861
+ struct multi_pack_index *result = NULL;
862
+ struct multi_pack_index *cur;
863
+ char *obj_dir_real = real_pathdup(object_dir, 1);
864
+ struct strbuf cur_path_real = STRBUF_INIT;
865
+
866
+ /* Ensure the given object_dir is local, or a known alternate. */
867
+ find_odb(r, obj_dir_real);
868
+
869
+ for (cur = get_multi_pack_index(r); cur; cur = cur->next) {
870
+ strbuf_realpath(&cur_path_real, cur->object_dir, 1);
871
+ if (!strcmp(obj_dir_real, cur_path_real.buf)) {
872
+ result = cur;
873
+ goto cleanup;
874
+ }
875
+ }
876
+
877
+cleanup:
878
+ free(obj_dir_real);
879
+ strbuf_release(&cur_path_real);
880
+ return result;
881
+}
882
+
883
+static int write_midx_internal(const char *object_dir,
884
+ struct string_list *packs_to_include,
885
+ struct string_list *packs_to_drop,
886
+ const char *preferred_pack_name,
887
+ const char *refs_snapshot,
888
+ unsigned flags)
889
+{
890
+ struct strbuf midx_name = STRBUF_INIT;
891
+ unsigned char midx_hash[GIT_MAX_RAWSZ];
892
+ uint32_t i;
893
+ struct hashfile *f = NULL;
894
+ struct lock_file lk;
895
+ struct write_midx_context ctx = { 0 };
896
+ int bitmapped_packs_concat_len = 0;
897
+ int pack_name_concat_len = 0;
898
+ int dropped_packs = 0;
899
+ int result = 0;
900
+ struct chunkfile *cf;
901
+
902
+ trace2_region_enter("midx", "write_midx_internal", the_repository);
903
+
904
+ get_midx_filename(&midx_name, object_dir);
905
+ if (safe_create_leading_directories(midx_name.buf))
906
+ die_errno(_("unable to create leading directories of %s"),
907
+ midx_name.buf);
908
+
909
+ if (!packs_to_include) {
910
+ /*
911
+ * Only reference an existing MIDX when not filtering which
912
+ * packs to include, since all packs and objects are copied
913
+ * blindly from an existing MIDX if one is present.
914
+ */
915
+ ctx.m = lookup_multi_pack_index(the_repository, object_dir);
916
+ }
917
+
918
+ if (ctx.m && !midx_checksum_valid(ctx.m)) {
919
+ warning(_("ignoring existing multi-pack-index; checksum mismatch"));
920
+ ctx.m = NULL;
921
+ }
922
+
923
+ ctx.nr = 0;
924
+ ctx.alloc = ctx.m ? ctx.m->num_packs : 16;
925
+ ctx.info = NULL;
926
+ ALLOC_ARRAY(ctx.info, ctx.alloc);
927
+
928
+ if (ctx.m) {
929
+ for (i = 0; i < ctx.m->num_packs; i++) {
930
+ ALLOC_GROW(ctx.info, ctx.nr + 1, ctx.alloc);
931
+
932
+ if (flags & MIDX_WRITE_REV_INDEX) {
933
+ /*
934
+ * If generating a reverse index, need to have
935
+ * packed_git's loaded to compare their
936
+ * mtimes and object count.
937
+ */
938
+ if (prepare_midx_pack(the_repository, ctx.m, i)) {
939
+ error(_("could not load pack"));
940
+ result = 1;
941
+ goto cleanup;
942
+ }
943
+
944
+ if (open_pack_index(ctx.m->packs[i]))
945
+ die(_("could not open index for %s"),
946
+ ctx.m->packs[i]->pack_name);
947
+ }
948
+
949
+ fill_pack_info(&ctx.info[ctx.nr++], ctx.m->packs[i],
950
+ ctx.m->pack_names[i], i);
951
+ }
952
+ }
953
+
954
+ ctx.pack_paths_checked = 0;
955
+ if (flags & MIDX_PROGRESS)
956
+ ctx.progress = start_delayed_progress(_("Adding packfiles to multi-pack-index"), 0);
957
+ else
958
+ ctx.progress = NULL;
959
+
960
+ ctx.to_include = packs_to_include;
961
+
962
+ for_each_file_in_pack_dir(object_dir, add_pack_to_midx, &ctx);
963
+ stop_progress(&ctx.progress);
964
+
965
+ if ((ctx.m && ctx.nr == ctx.m->num_packs) &&
966
+ !(packs_to_include || packs_to_drop)) {
967
+ struct bitmap_index *bitmap_git;
968
+ int bitmap_exists;
969
+ int want_bitmap = flags & MIDX_WRITE_BITMAP;
970
+
971
+ bitmap_git = prepare_midx_bitmap_git(ctx.m);
972
+ bitmap_exists = bitmap_git && bitmap_is_midx(bitmap_git);
973
+ free_bitmap_index(bitmap_git);
974
+
975
+ if (bitmap_exists || !want_bitmap) {
976
+ /*
977
+ * The correct MIDX already exists, and so does a
978
+ * corresponding bitmap (or one wasn't requested).
979
+ */
980
+ if (!want_bitmap)
981
+ clear_midx_files_ext(object_dir, ".bitmap",
982
+ NULL);
983
+ goto cleanup;
984
+ }
985
+ }
986
+
987
+ if (preferred_pack_name) {
988
+ ctx.preferred_pack_idx = -1;
989
+
990
+ for (i = 0; i < ctx.nr; i++) {
991
+ if (!cmp_idx_or_pack_name(preferred_pack_name,
992
+ ctx.info[i].pack_name)) {
993
+ ctx.preferred_pack_idx = i;
994
+ break;
995
+ }
996
+ }
997
+
998
+ if (ctx.preferred_pack_idx == -1)
999
+ warning(_("unknown preferred pack: '%s'"),
1000
+ preferred_pack_name);
1001
+ } else if (ctx.nr &&
1002
+ (flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP))) {
1003
+ struct packed_git *oldest = ctx.info[ctx.preferred_pack_idx].p;
1004
+ ctx.preferred_pack_idx = 0;
1005
+
1006
+ if (packs_to_drop && packs_to_drop->nr)
1007
+ BUG("cannot write a MIDX bitmap during expiration");
1008
+
1009
+ /*
1010
+ * set a preferred pack when writing a bitmap to ensure that
1011
+ * the pack from which the first object is selected in pseudo
1012
+ * pack-order has all of its objects selected from that pack
1013
+ * (and not another pack containing a duplicate)
1014
+ */
1015
+ for (i = 1; i < ctx.nr; i++) {
1016
+ struct packed_git *p = ctx.info[i].p;
1017
+
1018
+ if (!oldest->num_objects || p->mtime < oldest->mtime) {
1019
+ oldest = p;
1020
+ ctx.preferred_pack_idx = i;
1021
+ }
1022
+ }
1023
+
1024
+ if (!oldest->num_objects) {
1025
+ /*
1026
+ * If all packs are empty; unset the preferred index.
1027
+ * This is acceptable since there will be no duplicate
1028
+ * objects to resolve, so the preferred value doesn't
1029
+ * matter.
1030
+ */
1031
+ ctx.preferred_pack_idx = -1;
1032
+ }
1033
+ } else {
1034
+ /*
1035
+ * otherwise don't mark any pack as preferred to avoid
1036
+ * interfering with expiration logic below
1037
+ */
1038
+ ctx.preferred_pack_idx = -1;
1039
+ }
1040
+
1041
+ if (ctx.preferred_pack_idx > -1) {
1042
+ struct packed_git *preferred = ctx.info[ctx.preferred_pack_idx].p;
1043
+ if (!preferred->num_objects) {
1044
+ error(_("cannot select preferred pack %s with no objects"),
1045
+ preferred->pack_name);
1046
+ result = 1;
1047
+ goto cleanup;
1048
+ }
1049
+ }
1050
+
1051
+ ctx.entries = get_sorted_entries(ctx.m, ctx.info, ctx.nr, &ctx.entries_nr,
1052
+ ctx.preferred_pack_idx);
1053
+
1054
+ ctx.large_offsets_needed = 0;
1055
+ for (i = 0; i < ctx.entries_nr; i++) {
1056
+ if (ctx.entries[i].offset > 0x7fffffff)
1057
+ ctx.num_large_offsets++;
1058
+ if (ctx.entries[i].offset > 0xffffffff)
1059
+ ctx.large_offsets_needed = 1;
1060
+ }
1061
+
1062
+ QSORT(ctx.info, ctx.nr, pack_info_compare);
1063
+
1064
+ if (packs_to_drop && packs_to_drop->nr) {
1065
+ int drop_index = 0;
1066
+ int missing_drops = 0;
1067
+
1068
+ for (i = 0; i < ctx.nr && drop_index < packs_to_drop->nr; i++) {
1069
+ int cmp = strcmp(ctx.info[i].pack_name,
1070
+ packs_to_drop->items[drop_index].string);
1071
+
1072
+ if (!cmp) {
1073
+ drop_index++;
1074
+ ctx.info[i].expired = 1;
1075
+ } else if (cmp > 0) {
1076
+ error(_("did not see pack-file %s to drop"),
1077
+ packs_to_drop->items[drop_index].string);
1078
+ drop_index++;
1079
+ missing_drops++;
1080
+ i--;
1081
+ } else {
1082
+ ctx.info[i].expired = 0;
1083
+ }
1084
+ }
1085
+
1086
+ if (missing_drops) {
1087
+ result = 1;
1088
+ goto cleanup;
1089
+ }
1090
+ }
1091
+
1092
+ /*
1093
+ * pack_perm stores a permutation between pack-int-ids from the
1094
+ * previous multi-pack-index to the new one we are writing:
1095
+ *
1096
+ * pack_perm[old_id] = new_id
1097
+ */
1098
+ ALLOC_ARRAY(ctx.pack_perm, ctx.nr);
1099
+ for (i = 0; i < ctx.nr; i++) {
1100
+ if (ctx.info[i].expired) {
1101
+ dropped_packs++;
1102
+ ctx.pack_perm[ctx.info[i].orig_pack_int_id] = PACK_EXPIRED;
1103
+ } else {
1104
+ ctx.pack_perm[ctx.info[i].orig_pack_int_id] = i - dropped_packs;
1105
+ }
1106
+ }
1107
+
1108
+ for (i = 0; i < ctx.nr; i++) {
1109
+ if (ctx.info[i].expired)
1110
+ continue;
1111
+ pack_name_concat_len += strlen(ctx.info[i].pack_name) + 1;
1112
+ bitmapped_packs_concat_len += 2 * sizeof(uint32_t);
1113
+ }
1114
+
1115
+ /* Check that the preferred pack wasn't expired (if given). */
1116
+ if (preferred_pack_name) {
1117
+ struct pack_info *preferred = bsearch(preferred_pack_name,
1118
+ ctx.info, ctx.nr,
1119
+ sizeof(*ctx.info),
1120
+ idx_or_pack_name_cmp);
1121
+ if (preferred) {
1122
+ uint32_t perm = ctx.pack_perm[preferred->orig_pack_int_id];
1123
+ if (perm == PACK_EXPIRED)
1124
+ warning(_("preferred pack '%s' is expired"),
1125
+ preferred_pack_name);
1126
+ }
1127
+ }
1128
+
1129
+ if (pack_name_concat_len % MIDX_CHUNK_ALIGNMENT)
1130
+ pack_name_concat_len += MIDX_CHUNK_ALIGNMENT -
1131
+ (pack_name_concat_len % MIDX_CHUNK_ALIGNMENT);
1132
+
1133
+ hold_lock_file_for_update(&lk, midx_name.buf, LOCK_DIE_ON_ERROR);
1134
+ f = hashfd(get_lock_file_fd(&lk), get_lock_file_path(&lk));
1135
+
1136
+ if (ctx.nr - dropped_packs == 0) {
1137
+ error(_("no pack files to index."));
1138
+ result = 1;
1139
+ goto cleanup;
1140
+ }
1141
+
1142
+ if (!ctx.entries_nr) {
1143
+ if (flags & MIDX_WRITE_BITMAP)
1144
+ warning(_("refusing to write multi-pack .bitmap without any objects"));
1145
+ flags &= ~(MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP);
1146
+ }
1147
+
1148
+ cf = init_chunkfile(f);
1149
+
1150
+ add_chunk(cf, MIDX_CHUNKID_PACKNAMES, pack_name_concat_len,
1151
+ write_midx_pack_names);
1152
+ add_chunk(cf, MIDX_CHUNKID_OIDFANOUT, MIDX_CHUNK_FANOUT_SIZE,
1153
+ write_midx_oid_fanout);
1154
+ add_chunk(cf, MIDX_CHUNKID_OIDLOOKUP,
1155
+ st_mult(ctx.entries_nr, the_hash_algo->rawsz),
1156
+ write_midx_oid_lookup);
1157
+ add_chunk(cf, MIDX_CHUNKID_OBJECTOFFSETS,
1158
+ st_mult(ctx.entries_nr, MIDX_CHUNK_OFFSET_WIDTH),
1159
+ write_midx_object_offsets);
1160
+
1161
+ if (ctx.large_offsets_needed)
1162
+ add_chunk(cf, MIDX_CHUNKID_LARGEOFFSETS,
1163
+ st_mult(ctx.num_large_offsets,
1164
+ MIDX_CHUNK_LARGE_OFFSET_WIDTH),
1165
+ write_midx_large_offsets);
1166
+
1167
+ if (flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP)) {
1168
+ ctx.pack_order = midx_pack_order(&ctx);
1169
+ add_chunk(cf, MIDX_CHUNKID_REVINDEX,
1170
+ st_mult(ctx.entries_nr, sizeof(uint32_t)),
1171
+ write_midx_revindex);
1172
+ add_chunk(cf, MIDX_CHUNKID_BITMAPPEDPACKS,
1173
+ bitmapped_packs_concat_len,
1174
+ write_midx_bitmapped_packs);
1175
+ }
1176
+
1177
+ write_midx_header(f, get_num_chunks(cf), ctx.nr - dropped_packs);
1178
+ write_chunkfile(cf, &ctx);
1179
+
1180
+ finalize_hashfile(f, midx_hash, FSYNC_COMPONENT_PACK_METADATA,
1181
+ CSUM_FSYNC | CSUM_HASH_IN_STREAM);
1182
+ free_chunkfile(cf);
1183
+
1184
+ if (flags & MIDX_WRITE_REV_INDEX &&
1185
+ git_env_bool("GIT_TEST_MIDX_WRITE_REV", 0))
1186
+ write_midx_reverse_index(midx_name.buf, midx_hash, &ctx);
1187
+
1188
+ if (flags & MIDX_WRITE_BITMAP) {
1189
+ struct packing_data pdata;
1190
+ struct commit **commits;
1191
+ uint32_t commits_nr;
1192
+
1193
+ if (!ctx.entries_nr)
1194
+ BUG("cannot write a bitmap without any objects");
1195
+
1196
+ prepare_midx_packing_data(&pdata, &ctx);
1197
+
1198
+ commits = find_commits_for_midx_bitmap(&commits_nr, refs_snapshot, &ctx);
1199
+
1200
+ /*
1201
+ * The previous steps translated the information from
1202
+ * 'entries' into information suitable for constructing
1203
+ * bitmaps. We no longer need that array, so clear it to
1204
+ * reduce memory pressure.
1205
+ */
1206
+ FREE_AND_NULL(ctx.entries);
1207
+ ctx.entries_nr = 0;
1208
+
1209
+ if (write_midx_bitmap(midx_name.buf, midx_hash, &pdata,
1210
+ commits, commits_nr, ctx.pack_order,
1211
+ flags) < 0) {
1212
+ error(_("could not write multi-pack bitmap"));
1213
+ result = 1;
1214
+ clear_packing_data(&pdata);
1215
+ free(commits);
1216
+ goto cleanup;
1217
+ }
1218
+
1219
+ clear_packing_data(&pdata);
1220
+ free(commits);
1221
+ }
1222
+ /*
1223
+ * NOTE: Do not use ctx.entries beyond this point, since it might
1224
+ * have been freed in the previous if block.
1225
+ */
1226
+
1227
+ if (ctx.m)
1228
+ close_object_store(the_repository->objects);
1229
+
1230
+ if (commit_lock_file(&lk) < 0)
1231
+ die_errno(_("could not write multi-pack-index"));
1232
+
1233
+ clear_midx_files_ext(object_dir, ".bitmap", midx_hash);
1234
+ clear_midx_files_ext(object_dir, ".rev", midx_hash);
1235
+
1236
+cleanup:
1237
+ for (i = 0; i < ctx.nr; i++) {
1238
+ if (ctx.info[i].p) {
1239
+ close_pack(ctx.info[i].p);
1240
+ free(ctx.info[i].p);
1241
+ }
1242
+ free(ctx.info[i].pack_name);
1243
+ }
1244
+
1245
+ free(ctx.info);
1246
+ free(ctx.entries);
1247
+ free(ctx.pack_perm);
1248
+ free(ctx.pack_order);
1249
+ strbuf_release(&midx_name);
1250
+
1251
+ trace2_region_leave("midx", "write_midx_internal", the_repository);
1252
+
1253
+ return result;
1254
+}
1255
+
1256
+int write_midx_file(const char *object_dir,
1257
+ const char *preferred_pack_name,
1258
+ const char *refs_snapshot,
1259
+ unsigned flags)
1260
+{
1261
+ return write_midx_internal(object_dir, NULL, NULL, preferred_pack_name,
1262
+ refs_snapshot, flags);
1263
+}
1264
+
1265
+int write_midx_file_only(const char *object_dir,
1266
+ struct string_list *packs_to_include,
1267
+ const char *preferred_pack_name,
1268
+ const char *refs_snapshot,
1269
+ unsigned flags)
1270
+{
1271
+ return write_midx_internal(object_dir, packs_to_include, NULL,
1272
+ preferred_pack_name, refs_snapshot, flags);
1273
+}
1274
+
1275
+int expire_midx_packs(struct repository *r, const char *object_dir, unsigned flags)
1276
+{
1277
+ uint32_t i, *count, result = 0;
1278
+ struct string_list packs_to_drop = STRING_LIST_INIT_DUP;
1279
+ struct multi_pack_index *m = lookup_multi_pack_index(r, object_dir);
1280
+ struct progress *progress = NULL;
1281
+
1282
+ if (!m)
1283
+ return 0;
1284
+
1285
+ CALLOC_ARRAY(count, m->num_packs);
1286
+
1287
+ if (flags & MIDX_PROGRESS)
1288
+ progress = start_delayed_progress(_("Counting referenced objects"),
1289
+ m->num_objects);
1290
+ for (i = 0; i < m->num_objects; i++) {
1291
+ int pack_int_id = nth_midxed_pack_int_id(m, i);
1292
+ count[pack_int_id]++;
1293
+ display_progress(progress, i + 1);
1294
+ }
1295
+ stop_progress(&progress);
1296
+
1297
+ if (flags & MIDX_PROGRESS)
1298
+ progress = start_delayed_progress(_("Finding and deleting unreferenced packfiles"),
1299
+ m->num_packs);
1300
+ for (i = 0; i < m->num_packs; i++) {
1301
+ char *pack_name;
1302
+ display_progress(progress, i + 1);
1303
+
1304
+ if (count[i])
1305
+ continue;
1306
+
1307
+ if (prepare_midx_pack(r, m, i))
1308
+ continue;
1309
+
1310
+ if (m->packs[i]->pack_keep || m->packs[i]->is_cruft)
1311
+ continue;
1312
+
1313
+ pack_name = xstrdup(m->packs[i]->pack_name);
1314
+ close_pack(m->packs[i]);
1315
+
1316
+ string_list_insert(&packs_to_drop, m->pack_names[i]);
1317
+ unlink_pack_path(pack_name, 0);
1318
+ free(pack_name);
1319
+ }
1320
+ stop_progress(&progress);
1321
+
1322
+ free(count);
1323
+
1324
+ if (packs_to_drop.nr)
1325
+ result = write_midx_internal(object_dir, NULL, &packs_to_drop, NULL, NULL, flags);
1326
+
1327
+ string_list_clear(&packs_to_drop, 0);
1328
+
1329
+ return result;
1330
+}
1331
+
1332
+struct repack_info {
1333
+ timestamp_t mtime;
1334
+ uint32_t referenced_objects;
1335
+ uint32_t pack_int_id;
1336
+};
1337
+
1338
+static int compare_by_mtime(const void *a_, const void *b_)
1339
+{
1340
+ const struct repack_info *a, *b;
1341
+
1342
+ a = (const struct repack_info *)a_;
1343
+ b = (const struct repack_info *)b_;
1344
+
1345
+ if (a->mtime < b->mtime)
1346
+ return -1;
1347
+ if (a->mtime > b->mtime)
1348
+ return 1;
1349
+ return 0;
1350
+}
1351
+
1352
+static int fill_included_packs_all(struct repository *r,
1353
+ struct multi_pack_index *m,
1354
+ unsigned char *include_pack)
1355
+{
1356
+ uint32_t i, count = 0;
1357
+ int pack_kept_objects = 0;
1358
+
1359
+ repo_config_get_bool(r, "repack.packkeptobjects", &pack_kept_objects);
1360
+
1361
+ for (i = 0; i < m->num_packs; i++) {
1362
+ if (prepare_midx_pack(r, m, i))
1363
+ continue;
1364
+ if (!pack_kept_objects && m->packs[i]->pack_keep)
1365
+ continue;
1366
+ if (m->packs[i]->is_cruft)
1367
+ continue;
1368
+
1369
+ include_pack[i] = 1;
1370
+ count++;
1371
+ }
1372
+
1373
+ return count < 2;
1374
+}
1375
+
1376
+static int fill_included_packs_batch(struct repository *r,
1377
+ struct multi_pack_index *m,
1378
+ unsigned char *include_pack,
1379
+ size_t batch_size)
1380
+{
1381
+ uint32_t i, packs_to_repack;
1382
+ size_t total_size;
1383
+ struct repack_info *pack_info;
1384
+ int pack_kept_objects = 0;
1385
+
1386
+ CALLOC_ARRAY(pack_info, m->num_packs);
1387
+
1388
+ repo_config_get_bool(r, "repack.packkeptobjects", &pack_kept_objects);
1389
+
1390
+ for (i = 0; i < m->num_packs; i++) {
1391
+ pack_info[i].pack_int_id = i;
1392
+
1393
+ if (prepare_midx_pack(r, m, i))
1394
+ continue;
1395
+
1396
+ pack_info[i].mtime = m->packs[i]->mtime;
1397
+ }
1398
+
1399
+ for (i = 0; i < m->num_objects; i++) {
1400
+ uint32_t pack_int_id = nth_midxed_pack_int_id(m, i);
1401
+ pack_info[pack_int_id].referenced_objects++;
1402
+ }
1403
+
1404
+ QSORT(pack_info, m->num_packs, compare_by_mtime);
1405
+
1406
+ total_size = 0;
1407
+ packs_to_repack = 0;
1408
+ for (i = 0; total_size < batch_size && i < m->num_packs; i++) {
1409
+ int pack_int_id = pack_info[i].pack_int_id;
1410
+ struct packed_git *p = m->packs[pack_int_id];
1411
+ size_t expected_size;
1412
+
1413
+ if (!p)
1414
+ continue;
1415
+ if (!pack_kept_objects && p->pack_keep)
1416
+ continue;
1417
+ if (p->is_cruft)
1418
+ continue;
1419
+ if (open_pack_index(p) || !p->num_objects)
1420
+ continue;
1421
+
1422
+ expected_size = st_mult(p->pack_size,
1423
+ pack_info[i].referenced_objects);
1424
+ expected_size /= p->num_objects;
1425
+
1426
+ if (expected_size >= batch_size)
1427
+ continue;
1428
+
1429
+ packs_to_repack++;
1430
+ total_size += expected_size;
1431
+ include_pack[pack_int_id] = 1;
1432
+ }
1433
+
1434
+ free(pack_info);
1435
+
1436
+ if (packs_to_repack < 2)
1437
+ return 1;
1438
+
1439
+ return 0;
1440
+}
1441
+
1442
+int midx_repack(struct repository *r, const char *object_dir, size_t batch_size, unsigned flags)
1443
+{
1444
+ int result = 0;
1445
+ uint32_t i;
1446
+ unsigned char *include_pack;
1447
+ struct child_process cmd = CHILD_PROCESS_INIT;
1448
+ FILE *cmd_in;
1449
+ struct multi_pack_index *m = lookup_multi_pack_index(r, object_dir);
1450
+
1451
+ /*
1452
+ * When updating the default for these configuration
1453
+ * variables in builtin/repack.c, these must be adjusted
1454
+ * to match.
1455
+ */
1456
+ int delta_base_offset = 1;
1457
+ int use_delta_islands = 0;
1458
+
1459
+ if (!m)
1460
+ return 0;
1461
+
1462
+ CALLOC_ARRAY(include_pack, m->num_packs);
1463
+
1464
+ if (batch_size) {
1465
+ if (fill_included_packs_batch(r, m, include_pack, batch_size))
1466
+ goto cleanup;
1467
+ } else if (fill_included_packs_all(r, m, include_pack))
1468
+ goto cleanup;
1469
+
1470
+ repo_config_get_bool(r, "repack.usedeltabaseoffset", &delta_base_offset);
1471
+ repo_config_get_bool(r, "repack.usedeltaislands", &use_delta_islands);
1472
+
1473
+ strvec_push(&cmd.args, "pack-objects");
1474
+
1475
+ strvec_pushf(&cmd.args, "%s/pack/pack", object_dir);
1476
+
1477
+ if (delta_base_offset)
1478
+ strvec_push(&cmd.args, "--delta-base-offset");
1479
+ if (use_delta_islands)
1480
+ strvec_push(&cmd.args, "--delta-islands");
1481
+
1482
+ if (flags & MIDX_PROGRESS)
1483
+ strvec_push(&cmd.args, "--progress");
1484
+ else
1485
+ strvec_push(&cmd.args, "-q");
1486
+
1487
+ cmd.git_cmd = 1;
1488
+ cmd.in = cmd.out = -1;
1489
+
1490
+ if (start_command(&cmd)) {
1491
+ error(_("could not start pack-objects"));
1492
+ result = 1;
1493
+ goto cleanup;
1494
+ }
1495
+
1496
+ cmd_in = xfdopen(cmd.in, "w");
1497
+
1498
+ for (i = 0; i < m->num_objects; i++) {
1499
+ struct object_id oid;
1500
+ uint32_t pack_int_id = nth_midxed_pack_int_id(m, i);
1501
+
1502
+ if (!include_pack[pack_int_id])
1503
+ continue;
1504
+
1505
+ nth_midxed_object_oid(&oid, m, i);
1506
+ fprintf(cmd_in, "%s\n", oid_to_hex(&oid));
1507
+ }
1508
+ fclose(cmd_in);
1509
+
1510
+ if (finish_command(&cmd)) {
1511
+ error(_("could not finish pack-objects"));
1512
+ result = 1;
1513
+ goto cleanup;
1514
+ }
1515
+
1516
+ result = write_midx_internal(object_dir, NULL, NULL, NULL, NULL, flags);
1517
+
1518
+cleanup:
1519
+ free(include_pack);
1520
+ return result;
1521
+}
midx.c
+170
-1695
@@ -1,52 +1,22 @@
1
#include "git-compat-util.h"
2
-#include "abspath.h"
2
#include "config.h"
4
-#include "csum-file.h"
3
#include "dir.h"
6
-#include "gettext.h"
4
#include "hex.h"
8
-#include "lockfile.h"
5
#include "packfile.h"
6
#include "object-file.h"
11
-#include "object-store-ll.h"
7
#include "hash-lookup.h"
8
#include "midx.h"
9
#include "progress.h"
10
#include "trace2.h"
16
-#include "run-command.h"
17
-#include "repository.h"
11
#include "chunk-format.h"
19
-#include "pack.h"
12
#include "pack-bitmap.h"
21
-#include "refs.h"
22
-#include "revision.h"
23
-#include "list-objects.h"
13
#include "pack-revindex.h"
14
26
-#define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */
27
-#define MIDX_VERSION 1
28
-#define MIDX_BYTE_FILE_VERSION 4
29
-#define MIDX_BYTE_HASH_VERSION 5
30
-#define MIDX_BYTE_NUM_CHUNKS 6
31
-#define MIDX_BYTE_NUM_PACKS 8
32
-#define MIDX_HEADER_SIZE 12
33
-#define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + the_hash_algo->rawsz)
34
-
35
-#define MIDX_CHUNK_ALIGNMENT 4
36
-#define MIDX_CHUNKID_PACKNAMES 0x504e414d /* "PNAM" */
37
-#define MIDX_CHUNKID_BITMAPPEDPACKS 0x42544d50 /* "BTMP" */
38
-#define MIDX_CHUNKID_OIDFANOUT 0x4f494446 /* "OIDF" */
39
-#define MIDX_CHUNKID_OIDLOOKUP 0x4f49444c /* "OIDL" */
40
-#define MIDX_CHUNKID_OBJECTOFFSETS 0x4f4f4646 /* "OOFF" */
41
-#define MIDX_CHUNKID_LARGEOFFSETS 0x4c4f4646 /* "LOFF" */
42
-#define MIDX_CHUNKID_REVINDEX 0x52494458 /* "RIDX" */
43
-#define MIDX_CHUNK_FANOUT_SIZE (sizeof(uint32_t) * 256)
44
-#define MIDX_CHUNK_OFFSET_WIDTH (2 * sizeof(uint32_t))
45
-#define MIDX_CHUNK_LARGE_OFFSET_WIDTH (sizeof(uint64_t))
46
-#define MIDX_CHUNK_BITMAPPED_PACKS_WIDTH (2 * sizeof(uint32_t))
47
-#define MIDX_LARGE_OFFSET_NEEDED 0x80000000
48
-
49
-#define PACK_EXPIRED UINT_MAX
15
+int midx_checksum_valid(struct multi_pack_index *m);
16
+void clear_midx_files_ext(const char *object_dir, const char *ext,
17
+ unsigned char *keep_hash);
18
+int cmp_idx_or_pack_name(const char *idx_or_pack_name,
19
+ const char *idx_name);
20
21
const unsigned char *get_midx_checksum(struct multi_pack_index *m)
22
{
@@ -115,6 +85,8 @@ static int midx_read_object_offsets(const unsigned char *chunk_start,
85
return 0;
86
}
87
88
+#define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + the_hash_algo->rawsz)
89
+
90
struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local)
91
{
92
struct multi_pack_index *m = NULL;
@@ -294,6 +266,8 @@ int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, uint32_t
266
return 0;
267
}
268
269
+#define MIDX_CHUNK_BITMAPPED_PACKS_WIDTH (2 * sizeof(uint32_t))
270
+
271
int nth_bitmapped_pack(struct repository *r, struct multi_pack_index *m,
272
struct bitmapped_pack *bp, uint32_t pack_int_id)
273
{
@@ -400,8 +374,8 @@ int fill_midx_entry(struct repository *r,
374
}
375
376
/* Match "foo.idx" against either "foo.pack" _or_ "foo.idx". */
403
-static int cmp_idx_or_pack_name(const char *idx_or_pack_name,
404
- const char *idx_name)
377
+int cmp_idx_or_pack_name(const char *idx_or_pack_name,
378
+ const char *idx_name)
379
{
380
/* Skip past any initial matching prefix. */
381
while (*idx_name && *idx_name == *idx_or_pack_name) {
@@ -508,1731 +482,232 @@ int prepare_multi_pack_index_one(struct repository *r, const char *object_dir, i
482
return 0;
483
}
484
511
-static size_t write_midx_header(struct hashfile *f,
512
- unsigned char num_chunks,
513
- uint32_t num_packs)
514
-{
515
- hashwrite_be32(f, MIDX_SIGNATURE);
516
- hashwrite_u8(f, MIDX_VERSION);
517
- hashwrite_u8(f, oid_version(the_hash_algo));
518
- hashwrite_u8(f, num_chunks);
519
- hashwrite_u8(f, 0); /* unused */
520
- hashwrite_be32(f, num_packs);
521
-
522
- return MIDX_HEADER_SIZE;
523
-}
524
-
525
-#define BITMAP_POS_UNKNOWN (~((uint32_t)0))
526
-
527
-struct pack_info {
528
- uint32_t orig_pack_int_id;
529
- char *pack_name;
530
- struct packed_git *p;
531
-
532
- uint32_t bitmap_pos;
533
- uint32_t bitmap_nr;
534
-
535
- unsigned expired : 1;
536
-};
537
-
538
-static void fill_pack_info(struct pack_info *info,
539
- struct packed_git *p, const char *pack_name,
540
- uint32_t orig_pack_int_id)
541
-{
542
- memset(info, 0, sizeof(struct pack_info));
543
-
544
- info->orig_pack_int_id = orig_pack_int_id;
545
- info->pack_name = xstrdup(pack_name);
546
- info->p = p;
547
- info->bitmap_pos = BITMAP_POS_UNKNOWN;
548
-}
549
-
550
-static int pack_info_compare(const void *_a, const void *_b)
551
-{
552
- struct pack_info *a = (struct pack_info *)_a;
553
- struct pack_info *b = (struct pack_info *)_b;
554
- return strcmp(a->pack_name, b->pack_name);
555
-}
556
-
557
-static int idx_or_pack_name_cmp(const void *_va, const void *_vb)
485
+int midx_checksum_valid(struct multi_pack_index *m)
486
{
559
- const char *pack_name = _va;
560
- const struct pack_info *compar = _vb;
561
-
562
- return cmp_idx_or_pack_name(pack_name, compar->pack_name);
487
+ return hashfile_checksum_valid(m->data, m->data_len);
488
}
489
565
-struct write_midx_context {
566
- struct pack_info *info;
567
- size_t nr;
568
- size_t alloc;
569
- struct multi_pack_index *m;
570
- struct progress *progress;
571
- unsigned pack_paths_checked;
572
-
573
- struct pack_midx_entry *entries;
574
- size_t entries_nr;
575
-
576
- uint32_t *pack_perm;
577
- uint32_t *pack_order;
578
- unsigned large_offsets_needed:1;
579
- uint32_t num_large_offsets;
580
-
581
- int preferred_pack_idx;
582
-
583
- struct string_list *to_include;
490
+struct clear_midx_data {
491
+ char *keep;
492
+ const char *ext;
493
};
494
586
-static void add_pack_to_midx(const char *full_path, size_t full_path_len,
587
- const char *file_name, void *data)
495
+static void clear_midx_file_ext(const char *full_path, size_t full_path_len UNUSED,
496
+ const char *file_name, void *_data)
497
{
589
- struct write_midx_context *ctx = data;
590
- struct packed_git *p;
591
-
592
- if (ends_with(file_name, ".idx")) {
593
- display_progress(ctx->progress, ++ctx->pack_paths_checked);
594
- /*
595
- * Note that at most one of ctx->m and ctx->to_include are set,
596
- * so we are testing midx_contains_pack() and
597
- * string_list_has_string() independently (guarded by the
598
- * appropriate NULL checks).
599
- *
600
- * We could support passing to_include while reusing an existing
601
- * MIDX, but don't currently since the reuse process drags
602
- * forward all packs from an existing MIDX (without checking
603
- * whether or not they appear in the to_include list).
604
- *
605
- * If we added support for that, these next two conditional
606
- * should be performed independently (likely checking
607
- * to_include before the existing MIDX).
608
- */
609
- if (ctx->m && midx_contains_pack(ctx->m, file_name))
610
- return;
611
- else if (ctx->to_include &&
612
- !string_list_has_string(ctx->to_include, file_name))
613
- return;
614
-
615
- ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc);
616
-
617
- p = add_packed_git(full_path, full_path_len, 0);
618
- if (!p) {
619
- warning(_("failed to add packfile '%s'"),
620
- full_path);
621
- return;
622
- }
498
+ struct clear_midx_data *data = _data;
499
624
- if (open_pack_index(p)) {
625
- warning(_("failed to open pack-index '%s'"),
626
- full_path);
627
- close_pack(p);
628
- free(p);
629
- return;
630
- }
500
+ if (!(starts_with(file_name, "multi-pack-index-") &&
501
+ ends_with(file_name, data->ext)))
502
+ return;
503
+ if (data->keep && !strcmp(data->keep, file_name))
504
+ return;
505
632
- fill_pack_info(&ctx->info[ctx->nr], p, file_name, ctx->nr);
633
- ctx->nr++;
634
- }
506
+ if (unlink(full_path))
507
+ die_errno(_("failed to remove %s"), full_path);
508
}
509
637
-struct pack_midx_entry {
638
- struct object_id oid;
639
- uint32_t pack_int_id;
640
- time_t pack_mtime;
641
- uint64_t offset;
642
- unsigned preferred : 1;
643
-};
644
-
645
-static int midx_oid_compare(const void *_a, const void *_b)
510
+void clear_midx_files_ext(const char *object_dir, const char *ext,
511
+ unsigned char *keep_hash)
512
{
647
- const struct pack_midx_entry *a = (const struct pack_midx_entry *)_a;
648
- const struct pack_midx_entry *b = (const struct pack_midx_entry *)_b;
649
- int cmp = oidcmp(&a->oid, &b->oid);
650
-
651
- if (cmp)
652
- return cmp;
513
+ struct clear_midx_data data;
514
+ memset(&data, 0, sizeof(struct clear_midx_data));
515
654
- /* Sort objects in a preferred pack first when multiple copies exist. */
655
- if (a->preferred > b->preferred)
656
- return -1;
657
- if (a->preferred < b->preferred)
658
- return 1;
516
+ if (keep_hash)
517
+ data.keep = xstrfmt("multi-pack-index-%s%s",
518
+ hash_to_hex(keep_hash), ext);
519
+ data.ext = ext;
520
660
- if (a->pack_mtime > b->pack_mtime)
661
- return -1;
662
- else if (a->pack_mtime < b->pack_mtime)
663
- return 1;
521
+ for_each_file_in_pack_dir(object_dir,
522
+ clear_midx_file_ext,
523
+ &data);
524
665
- return a->pack_int_id - b->pack_int_id;
525
+ free(data.keep);
526
}
527
668
-static int nth_midxed_pack_midx_entry(struct multi_pack_index *m,
669
- struct pack_midx_entry *e,
670
- uint32_t pos)
528
+void clear_midx_file(struct repository *r)
529
{
672
- if (pos >= m->num_objects)
673
- return 1;
530
+ struct strbuf midx = STRBUF_INIT;
531
675
- nth_midxed_object_oid(&e->oid, m, pos);
676
- e->pack_int_id = nth_midxed_pack_int_id(m, pos);
677
- e->offset = nth_midxed_offset(m, pos);
532
+ get_midx_filename(&midx, r->objects->odb->path);
533
679
- /* consider objects in midx to be from "old" packs */
680
- e->pack_mtime = 0;
681
- return 0;
682
-}
534
+ if (r->objects && r->objects->multi_pack_index) {
535
+ close_midx(r->objects->multi_pack_index);
536
+ r->objects->multi_pack_index = NULL;
537
+ }
538
684
-static void fill_pack_entry(uint32_t pack_int_id,
685
- struct packed_git *p,
686
- uint32_t cur_object,
687
- struct pack_midx_entry *entry,
688
- int preferred)
689
-{
690
- if (nth_packed_object_id(&entry->oid, p, cur_object) < 0)
691
- die(_("failed to locate object %d in packfile"), cur_object);
539
+ if (remove_path(midx.buf))
540
+ die(_("failed to clear multi-pack-index at %s"), midx.buf);
541
693
- entry->pack_int_id = pack_int_id;
694
- entry->pack_mtime = p->mtime;
542
+ clear_midx_files_ext(r->objects->odb->path, ".bitmap", NULL);
543
+ clear_midx_files_ext(r->objects->odb->path, ".rev", NULL);
544
696
- entry->offset = nth_packed_object_offset(p, cur_object);
697
- entry->preferred = !!preferred;
545
+ strbuf_release(&midx);
546
}
547
700
-struct midx_fanout {
701
- struct pack_midx_entry *entries;
702
- size_t nr, alloc;
703
-};
548
+static int verify_midx_error;
549
705
-static void midx_fanout_grow(struct midx_fanout *fanout, size_t nr)
550
+__attribute__((format (printf, 1, 2)))
551
+static void midx_report(const char *fmt, ...)
552
{
707
- if (nr < fanout->nr)
708
- BUG("negative growth in midx_fanout_grow() (%"PRIuMAX" < %"PRIuMAX")",
709
- (uintmax_t)nr, (uintmax_t)fanout->nr);
710
- ALLOC_GROW(fanout->entries, nr, fanout->alloc);
553
+ va_list ap;
554
+ verify_midx_error = 1;
555
+ va_start(ap, fmt);
556
+ vfprintf(stderr, fmt, ap);
557
+ fprintf(stderr, "\n");
558
+ va_end(ap);
559
}
560
713
-static void midx_fanout_sort(struct midx_fanout *fanout)
561
+struct pair_pos_vs_id
562
{
715
- QSORT(fanout->entries, fanout->nr, midx_oid_compare);
716
-}
563
+ uint32_t pos;
564
+ uint32_t pack_int_id;
565
+};
566
718
-static void midx_fanout_add_midx_fanout(struct midx_fanout *fanout,
719
- struct multi_pack_index *m,
720
- uint32_t cur_fanout,
721
- int preferred_pack)
567
+static int compare_pair_pos_vs_id(const void *_a, const void *_b)
568
{
723
- uint32_t start = 0, end;
724
- uint32_t cur_object;
725
-
726
- if (cur_fanout)
727
- start = ntohl(m->chunk_oid_fanout[cur_fanout - 1]);
728
- end = ntohl(m->chunk_oid_fanout[cur_fanout]);
729
-
730
- for (cur_object = start; cur_object < end; cur_object++) {
731
- if ((preferred_pack > -1) &&
732
- (preferred_pack == nth_midxed_pack_int_id(m, cur_object))) {
733
- /*
734
- * Objects from preferred packs are added
735
- * separately.
736
- */
737
- continue;
738
- }
739
-
740
- midx_fanout_grow(fanout, fanout->nr + 1);
741
- nth_midxed_pack_midx_entry(m,
742
- &fanout->entries[fanout->nr],
743
- cur_object);
744
- fanout->entries[fanout->nr].preferred = 0;
745
- fanout->nr++;
746
- }
747
-}
569
+ struct pair_pos_vs_id *a = (struct pair_pos_vs_id *)_a;
570
+ struct pair_pos_vs_id *b = (struct pair_pos_vs_id *)_b;
571
749
-static void midx_fanout_add_pack_fanout(struct midx_fanout *fanout,
750
- struct pack_info *info,
751
- uint32_t cur_pack,
752
- int preferred,
753
- uint32_t cur_fanout)
754
-{
755
- struct packed_git *pack = info[cur_pack].p;
756
- uint32_t start = 0, end;
757
- uint32_t cur_object;
758
-
759
- if (cur_fanout)
760
- start = get_pack_fanout(pack, cur_fanout - 1);
761
- end = get_pack_fanout(pack, cur_fanout);
762
-
763
- for (cur_object = start; cur_object < end; cur_object++) {
764
- midx_fanout_grow(fanout, fanout->nr + 1);
765
- fill_pack_entry(cur_pack,
766
- info[cur_pack].p,
767
- cur_object,
768
- &fanout->entries[fanout->nr],
769
- preferred);
770
- fanout->nr++;
771
- }
572
+ return b->pack_int_id - a->pack_int_id;
573
}
574
575
/*
775
- * It is possible to artificially get into a state where there are many
776
- * duplicate copies of objects. That can create high memory pressure if
777
- * we are to create a list of all objects before de-duplication. To reduce
778
- * this memory pressure without a significant performance drop, automatically
779
- * group objects by the first byte of their object id. Use the IDX fanout
780
- * tables to group the data, copy to a local array, then sort.
781
- *
782
- * Copy only the de-duplicated entries (selected by most-recent modified time
783
- * of a packfile containing the object).
576
+ * Limit calls to display_progress() for performance reasons.
577
+ * The interval here was arbitrarily chosen.
578
*/
785
-static struct pack_midx_entry *get_sorted_entries(struct multi_pack_index *m,
786
- struct pack_info *info,
787
- uint32_t nr_packs,
788
- size_t *nr_objects,
789
- int preferred_pack)
790
-{
791
- uint32_t cur_fanout, cur_pack, cur_object;
792
- size_t alloc_objects, total_objects = 0;
793
- struct midx_fanout fanout = { 0 };
794
- struct pack_midx_entry *deduplicated_entries = NULL;
795
- uint32_t start_pack = m ? m->num_packs : 0;
796
-
797
- for (cur_pack = start_pack; cur_pack < nr_packs; cur_pack++)
798
- total_objects = st_add(total_objects,
799
- info[cur_pack].p->num_objects);
800
-
801
- /*
802
- * As we de-duplicate by fanout value, we expect the fanout
803
- * slices to be evenly distributed, with some noise. Hence,
804
- * allocate slightly more than one 256th.
805
- */
806
- alloc_objects = fanout.alloc = total_objects > 3200 ? total_objects / 200 : 16;
807
-
808
- ALLOC_ARRAY(fanout.entries, fanout.alloc);
809
- ALLOC_ARRAY(deduplicated_entries, alloc_objects);
810
- *nr_objects = 0;
811
-
812
- for (cur_fanout = 0; cur_fanout < 256; cur_fanout++) {
813
- fanout.nr = 0;
814
-
815
- if (m)
816
- midx_fanout_add_midx_fanout(&fanout, m, cur_fanout,
817
- preferred_pack);
579
+#define SPARSE_PROGRESS_INTERVAL (1 << 12)
580
+#define midx_display_sparse_progress(progress, n) \
581
+ do { \
582
+ uint64_t _n = (n); \
583
+ if ((_n & (SPARSE_PROGRESS_INTERVAL - 1)) == 0) \
584
+ display_progress(progress, _n); \
585
+ } while (0)
586
819
- for (cur_pack = start_pack; cur_pack < nr_packs; cur_pack++) {
820
- int preferred = cur_pack == preferred_pack;
821
- midx_fanout_add_pack_fanout(&fanout,
822
- info, cur_pack,
823
- preferred, cur_fanout);
824
- }
587
+int verify_midx_file(struct repository *r, const char *object_dir, unsigned flags)
588
+{
589
+ struct pair_pos_vs_id *pairs = NULL;
590
+ uint32_t i;
591
+ struct progress *progress = NULL;
592
+ struct multi_pack_index *m = load_multi_pack_index(object_dir, 1);
593
+ verify_midx_error = 0;
594
826
- if (-1 < preferred_pack && preferred_pack < start_pack)
827
- midx_fanout_add_pack_fanout(&fanout, info,
828
- preferred_pack, 1,
829
- cur_fanout);
595
+ if (!m) {
596
+ int result = 0;
597
+ struct stat sb;
598
+ struct strbuf filename = STRBUF_INIT;
599
831
- midx_fanout_sort(&fanout);
600
+ get_midx_filename(&filename, object_dir);
601
833
- /*
834
- * The batch is now sorted by OID and then mtime (descending).
835
- * Take only the first duplicate.
836
- */
837
- for (cur_object = 0; cur_object < fanout.nr; cur_object++) {
838
- if (cur_object && oideq(&fanout.entries[cur_object - 1].oid,
839
- &fanout.entries[cur_object].oid))
840
- continue;
841
-
842
- ALLOC_GROW(deduplicated_entries, st_add(*nr_objects, 1),
843
- alloc_objects);
844
- memcpy(&deduplicated_entries[*nr_objects],
845
- &fanout.entries[cur_object],
846
- sizeof(struct pack_midx_entry));
847
- (*nr_objects)++;
602
+ if (!stat(filename.buf, &sb)) {
603
+ error(_("multi-pack-index file exists, but failed to parse"));
604
+ result = 1;
605
}
606
+ strbuf_release(&filename);
607
+ return result;
608
}
609
851
- free(fanout.entries);
852
- return deduplicated_entries;
853
-}
854
-
855
-static int write_midx_pack_names(struct hashfile *f, void *data)
856
-{
857
- struct write_midx_context *ctx = data;
858
- uint32_t i;
859
- unsigned char padding[MIDX_CHUNK_ALIGNMENT];
860
- size_t written = 0;
861
-
862
- for (i = 0; i < ctx->nr; i++) {
863
- size_t writelen;
864
-
865
- if (ctx->info[i].expired)
866
- continue;
610
+ if (!midx_checksum_valid(m))
611
+ midx_report(_("incorrect checksum"));
612
868
- if (i && strcmp(ctx->info[i].pack_name, ctx->info[i - 1].pack_name) <= 0)
869
- BUG("incorrect pack-file order: %s before %s",
870
- ctx->info[i - 1].pack_name,
871
- ctx->info[i].pack_name);
613
+ if (flags & MIDX_PROGRESS)
614
+ progress = start_delayed_progress(_("Looking for referenced packfiles"),
615
+ m->num_packs);
616
+ for (i = 0; i < m->num_packs; i++) {
617
+ if (prepare_midx_pack(r, m, i))
618
+ midx_report("failed to load pack in position %d", i);
619
873
- writelen = strlen(ctx->info[i].pack_name) + 1;
874
- hashwrite(f, ctx->info[i].pack_name, writelen);
875
- written += writelen;
620
+ display_progress(progress, i + 1);
621
}
622
+ stop_progress(&progress);
623
878
- /* add padding to be aligned */
879
- i = MIDX_CHUNK_ALIGNMENT - (written % MIDX_CHUNK_ALIGNMENT);
880
- if (i < MIDX_CHUNK_ALIGNMENT) {
881
- memset(padding, 0, sizeof(padding));
882
- hashwrite(f, padding, i);
624
+ if (m->num_objects == 0) {
625
+ midx_report(_("the midx contains no oid"));
626
+ /*
627
+ * Remaining tests assume that we have objects, so we can
628
+ * return here.
629
+ */
630
+ goto cleanup;
631
}
632
885
- return 0;
886
-}
887
-
888
-static int write_midx_bitmapped_packs(struct hashfile *f, void *data)
889
-{
890
- struct write_midx_context *ctx = data;
891
- size_t i;
633
+ if (flags & MIDX_PROGRESS)
634
+ progress = start_sparse_progress(_("Verifying OID order in multi-pack-index"),
635
+ m->num_objects - 1);
636
+ for (i = 0; i < m->num_objects - 1; i++) {
637
+ struct object_id oid1, oid2;
638
893
- for (i = 0; i < ctx->nr; i++) {
894
- struct pack_info *pack = &ctx->info[i];
895
- if (pack->expired)
896
- continue;
639
+ nth_midxed_object_oid(&oid1, m, i);
640
+ nth_midxed_object_oid(&oid2, m, i + 1);
641
898
- if (pack->bitmap_pos == BITMAP_POS_UNKNOWN && pack->bitmap_nr)
899
- BUG("pack '%s' has no bitmap position, but has %d bitmapped object(s)",
900
- pack->pack_name, pack->bitmap_nr);
642
+ if (oidcmp(&oid1, &oid2) >= 0)
643
+ midx_report(_("oid lookup out of order: oid[%d] = %s >= %s = oid[%d]"),
644
+ i, oid_to_hex(&oid1), oid_to_hex(&oid2), i + 1);
645
902
- hashwrite_be32(f, pack->bitmap_pos);
903
- hashwrite_be32(f, pack->bitmap_nr);
646
+ midx_display_sparse_progress(progress, i + 1);
647
}
905
- return 0;
906
-}
907
-
908
-static int write_midx_oid_fanout(struct hashfile *f,
909
- void *data)
910
-{
911
- struct write_midx_context *ctx = data;
912
- struct pack_midx_entry *list = ctx->entries;
913
- struct pack_midx_entry *last = ctx->entries + ctx->entries_nr;
914
- uint32_t count = 0;
915
- uint32_t i;
648
+ stop_progress(&progress);
649
650
/*
918
- * Write the first-level table (the list is sorted,
919
- * but we use a 256-entry lookup to be able to avoid
920
- * having to do eight extra binary search iterations).
921
- */
922
- for (i = 0; i < 256; i++) {
923
- struct pack_midx_entry *next = list;
651
+ * Create an array mapping each object to its packfile id. Sort it
652
+ * to group the objects by packfile. Use this permutation to visit
653
+ * each of the objects and only require 1 packfile to be open at a
654
+ * time.
655
+ */
656
+ ALLOC_ARRAY(pairs, m->num_objects);
657
+ for (i = 0; i < m->num_objects; i++) {
658
+ pairs[i].pos = i;
659
+ pairs[i].pack_int_id = nth_midxed_pack_int_id(m, i);
660
+ }
661
925
- while (next < last && next->oid.hash[0] == i) {
926
- count++;
927
- next++;
928
- }
662
+ if (flags & MIDX_PROGRESS)
663
+ progress = start_sparse_progress(_("Sorting objects by packfile"),
664
+ m->num_objects);
665
+ display_progress(progress, 0); /* TODO: Measure QSORT() progress */
666
+ QSORT(pairs, m->num_objects, compare_pair_pos_vs_id);
667
+ stop_progress(&progress);
668
930
- hashwrite_be32(f, count);
931
- list = next;
932
- }
669
+ if (flags & MIDX_PROGRESS)
670
+ progress = start_sparse_progress(_("Verifying object offsets"), m->num_objects);
671
+ for (i = 0; i < m->num_objects; i++) {
672
+ struct object_id oid;
673
+ struct pack_entry e;
674
+ off_t m_offset, p_offset;
675
934
- return 0;
935
-}
676
+ if (i > 0 && pairs[i-1].pack_int_id != pairs[i].pack_int_id &&
677
+ m->packs[pairs[i-1].pack_int_id])
678
+ {
679
+ close_pack_fd(m->packs[pairs[i-1].pack_int_id]);
680
+ close_pack_index(m->packs[pairs[i-1].pack_int_id]);
681
+ }
682
937
-static int write_midx_oid_lookup(struct hashfile *f,
938
- void *data)
939
-{
940
- struct write_midx_context *ctx = data;
941
- unsigned char hash_len = the_hash_algo->rawsz;
942
- struct pack_midx_entry *list = ctx->entries;
943
- uint32_t i;
683
+ nth_midxed_object_oid(&oid, m, pairs[i].pos);
684
945
- for (i = 0; i < ctx->entries_nr; i++) {
946
- struct pack_midx_entry *obj = list++;
685
+ if (!fill_midx_entry(r, &oid, &e, m)) {
686
+ midx_report(_("failed to load pack entry for oid[%d] = %s"),
687
+ pairs[i].pos, oid_to_hex(&oid));
688
+ continue;
689
+ }
690
948
- if (i < ctx->entries_nr - 1) {
949
- struct pack_midx_entry *next = list;
950
- if (oidcmp(&obj->oid, &next->oid) >= 0)
951
- BUG("OIDs not in order: %s >= %s",
952
- oid_to_hex(&obj->oid),
953
- oid_to_hex(&next->oid));
691
+ if (open_pack_index(e.p)) {
692
+ midx_report(_("failed to load pack-index for packfile %s"),
693
+ e.p->pack_name);
694
+ break;
695
}
696
956
- hashwrite(f, obj->oid.hash, (int)hash_len);
957
- }
697
+ m_offset = e.offset;
698
+ p_offset = find_pack_entry_one(oid.hash, e.p);
699
959
- return 0;
960
-}
700
+ if (m_offset != p_offset)
701
+ midx_report(_("incorrect object offset for oid[%d] = %s: %"PRIx64" != %"PRIx64),
702
+ pairs[i].pos, oid_to_hex(&oid), m_offset, p_offset);
703
962
-static int write_midx_object_offsets(struct hashfile *f,
963
- void *data)
964
-{
965
- struct write_midx_context *ctx = data;
966
- struct pack_midx_entry *list = ctx->entries;
967
- uint32_t i, nr_large_offset = 0;
968
-
969
- for (i = 0; i < ctx->entries_nr; i++) {
970
- struct pack_midx_entry *obj = list++;
971
-
972
- if (ctx->pack_perm[obj->pack_int_id] == PACK_EXPIRED)
973
- BUG("object %s is in an expired pack with int-id %d",
974
- oid_to_hex(&obj->oid),
975
- obj->pack_int_id);
976
-
977
- hashwrite_be32(f, ctx->pack_perm[obj->pack_int_id]);
978
-
979
- if (ctx->large_offsets_needed && obj->offset >> 31)
980
- hashwrite_be32(f, MIDX_LARGE_OFFSET_NEEDED | nr_large_offset++);
981
- else if (!ctx->large_offsets_needed && obj->offset >> 32)
982
- BUG("object %s requires a large offset (%"PRIx64") but the MIDX is not writing large offsets!",
983
- oid_to_hex(&obj->oid),
984
- obj->offset);
985
- else
986
- hashwrite_be32(f, (uint32_t)obj->offset);
704
+ midx_display_sparse_progress(progress, i + 1);
705
}
706
+ stop_progress(&progress);
707
989
- return 0;
990
-}
991
-
992
-static int write_midx_large_offsets(struct hashfile *f,
993
- void *data)
994
-{
995
- struct write_midx_context *ctx = data;
996
- struct pack_midx_entry *list = ctx->entries;
997
- struct pack_midx_entry *end = ctx->entries + ctx->entries_nr;
998
- uint32_t nr_large_offset = ctx->num_large_offsets;
999
-
1000
- while (nr_large_offset) {
1001
- struct pack_midx_entry *obj;
1002
- uint64_t offset;
1003
-
1004
- if (list >= end)
1005
- BUG("too many large-offset objects");
1006
-
1007
- obj = list++;
1008
- offset = obj->offset;
1009
-
1010
- if (!(offset >> 31))
1011
- continue;
1012
-
1013
- hashwrite_be64(f, offset);
1014
-
1015
- nr_large_offset--;
1016
- }
1017
-
1018
- return 0;
1019
-}
1020
-
1021
-static int write_midx_revindex(struct hashfile *f,
1022
- void *data)
1023
-{
1024
- struct write_midx_context *ctx = data;
1025
- uint32_t i;
1026
-
1027
- for (i = 0; i < ctx->entries_nr; i++)
1028
- hashwrite_be32(f, ctx->pack_order[i]);
1029
-
1030
- return 0;
1031
-}
1032
-
1033
-struct midx_pack_order_data {
1034
- uint32_t nr;
1035
- uint32_t pack;
1036
- off_t offset;
1037
-};
1038
-
1039
-static int midx_pack_order_cmp(const void *va, const void *vb)
1040
-{
1041
- const struct midx_pack_order_data *a = va, *b = vb;
1042
- if (a->pack < b->pack)
1043
- return -1;
1044
- else if (a->pack > b->pack)
1045
- return 1;
1046
- else if (a->offset < b->offset)
1047
- return -1;
1048
- else if (a->offset > b->offset)
1049
- return 1;
1050
- else
1051
- return 0;
1052
-}
1053
-
1054
-static uint32_t *midx_pack_order(struct write_midx_context *ctx)
1055
-{
1056
- struct midx_pack_order_data *data;
1057
- uint32_t *pack_order;
1058
- uint32_t i;
1059
-
1060
- trace2_region_enter("midx", "midx_pack_order", the_repository);
1061
-
1062
- ALLOC_ARRAY(data, ctx->entries_nr);
1063
- for (i = 0; i < ctx->entries_nr; i++) {
1064
- struct pack_midx_entry *e = &ctx->entries[i];
1065
- data[i].nr = i;
1066
- data[i].pack = ctx->pack_perm[e->pack_int_id];
1067
- if (!e->preferred)
1068
- data[i].pack |= (1U << 31);
1069
- data[i].offset = e->offset;
1070
- }
1071
-
1072
- QSORT(data, ctx->entries_nr, midx_pack_order_cmp);
1073
-
1074
- ALLOC_ARRAY(pack_order, ctx->entries_nr);
1075
- for (i = 0; i < ctx->entries_nr; i++) {
1076
- struct pack_midx_entry *e = &ctx->entries[data[i].nr];
1077
- struct pack_info *pack = &ctx->info[ctx->pack_perm[e->pack_int_id]];
1078
- if (pack->bitmap_pos == BITMAP_POS_UNKNOWN)
1079
- pack->bitmap_pos = i;
1080
- pack->bitmap_nr++;
1081
- pack_order[i] = data[i].nr;
1082
- }
1083
- for (i = 0; i < ctx->nr; i++) {
1084
- struct pack_info *pack = &ctx->info[ctx->pack_perm[i]];
1085
- if (pack->bitmap_pos == BITMAP_POS_UNKNOWN)
1086
- pack->bitmap_pos = 0;
1087
- }
1088
- free(data);
1089
-
1090
- trace2_region_leave("midx", "midx_pack_order", the_repository);
1091
-
1092
- return pack_order;
1093
-}
1094
-
1095
-static void write_midx_reverse_index(char *midx_name, unsigned char *midx_hash,
1096
- struct write_midx_context *ctx)
1097
-{
1098
- struct strbuf buf = STRBUF_INIT;
1099
- const char *tmp_file;
1100
-
1101
- trace2_region_enter("midx", "write_midx_reverse_index", the_repository);
1102
-
1103
- strbuf_addf(&buf, "%s-%s.rev", midx_name, hash_to_hex(midx_hash));
1104
-
1105
- tmp_file = write_rev_file_order(NULL, ctx->pack_order, ctx->entries_nr,
1106
- midx_hash, WRITE_REV);
1107
-
1108
- if (finalize_object_file(tmp_file, buf.buf))
1109
- die(_("cannot store reverse index file"));
1110
-
1111
- strbuf_release(&buf);
1112
-
1113
- trace2_region_leave("midx", "write_midx_reverse_index", the_repository);
1114
-}
1115
-
1116
-static void clear_midx_files_ext(const char *object_dir, const char *ext,
1117
- unsigned char *keep_hash);
1118
-
1119
-static int midx_checksum_valid(struct multi_pack_index *m)
1120
-{
1121
- return hashfile_checksum_valid(m->data, m->data_len);
1122
-}
1123
-
1124
-static void prepare_midx_packing_data(struct packing_data *pdata,
1125
- struct write_midx_context *ctx)
1126
-{
1127
- uint32_t i;
1128
-
1129
- trace2_region_enter("midx", "prepare_midx_packing_data", the_repository);
1130
-
1131
- memset(pdata, 0, sizeof(struct packing_data));
1132
- prepare_packing_data(the_repository, pdata);
1133
-
1134
- for (i = 0; i < ctx->entries_nr; i++) {
1135
- struct pack_midx_entry *from = &ctx->entries[ctx->pack_order[i]];
1136
- struct object_entry *to = packlist_alloc(pdata, &from->oid);
1137
-
1138
- oe_set_in_pack(pdata, to,
1139
- ctx->info[ctx->pack_perm[from->pack_int_id]].p);
1140
- }
1141
-
1142
- trace2_region_leave("midx", "prepare_midx_packing_data", the_repository);
1143
-}
1144
-
1145
-static int add_ref_to_pending(const char *refname,
1146
- const struct object_id *oid,
1147
- int flag, void *cb_data)
1148
-{
1149
- struct rev_info *revs = (struct rev_info*)cb_data;
1150
- struct object_id peeled;
1151
- struct object *object;
1152
-
1153
- if ((flag & REF_ISSYMREF) && (flag & REF_ISBROKEN)) {
1154
- warning("symbolic ref is dangling: %s", refname);
1155
- return 0;
1156
- }
1157
-
1158
- if (!peel_iterated_oid(oid, &peeled))
1159
- oid = &peeled;
1160
-
1161
- object = parse_object_or_die(oid, refname);
1162
- if (object->type != OBJ_COMMIT)
1163
- return 0;
1164
-
1165
- add_pending_object(revs, object, "");
1166
- if (bitmap_is_preferred_refname(revs->repo, refname))
1167
- object->flags |= NEEDS_BITMAP;
1168
- return 0;
1169
-}
1170
-
1171
-struct bitmap_commit_cb {
1172
- struct commit **commits;
1173
- size_t commits_nr, commits_alloc;
1174
-
1175
- struct write_midx_context *ctx;
1176
-};
1177
-
1178
-static const struct object_id *bitmap_oid_access(size_t index,
1179
- const void *_entries)
1180
-{
1181
- const struct pack_midx_entry *entries = _entries;
1182
- return &entries[index].oid;
1183
-}
1184
-
1185
-static void bitmap_show_commit(struct commit *commit, void *_data)
1186
-{
1187
- struct bitmap_commit_cb *data = _data;
1188
- int pos = oid_pos(&commit->object.oid, data->ctx->entries,
1189
- data->ctx->entries_nr,
1190
- bitmap_oid_access);
1191
- if (pos < 0)
1192
- return;
1193
-
1194
- ALLOC_GROW(data->commits, data->commits_nr + 1, data->commits_alloc);
1195
- data->commits[data->commits_nr++] = commit;
1196
-}
1197
-
1198
-static int read_refs_snapshot(const char *refs_snapshot,
1199
- struct rev_info *revs)
1200
-{
1201
- struct strbuf buf = STRBUF_INIT;
1202
- struct object_id oid;
1203
- FILE *f = xfopen(refs_snapshot, "r");
1204
-
1205
- while (strbuf_getline(&buf, f) != EOF) {
1206
- struct object *object;
1207
- int preferred = 0;
1208
- char *hex = buf.buf;
1209
- const char *end = NULL;
1210
-
1211
- if (buf.len && *buf.buf == '+') {
1212
- preferred = 1;
1213
- hex = &buf.buf[1];
1214
- }
1215
-
1216
- if (parse_oid_hex(hex, &oid, &end) < 0)
1217
- die(_("could not parse line: %s"), buf.buf);
1218
- if (*end)
1219
- die(_("malformed line: %s"), buf.buf);
1220
-
1221
- object = parse_object_or_die(&oid, NULL);
1222
- if (preferred)
1223
- object->flags |= NEEDS_BITMAP;
1224
-
1225
- add_pending_object(revs, object, "");
1226
- }
1227
-
1228
- fclose(f);
1229
- strbuf_release(&buf);
1230
- return 0;
1231
-}
1232
-
1233
-static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr_p,
1234
- const char *refs_snapshot,
1235
- struct write_midx_context *ctx)
1236
-{
1237
- struct rev_info revs;
1238
- struct bitmap_commit_cb cb = {0};
1239
-
1240
- trace2_region_enter("midx", "find_commits_for_midx_bitmap",
1241
- the_repository);
1242
-
1243
- cb.ctx = ctx;
1244
-
1245
- repo_init_revisions(the_repository, &revs, NULL);
1246
- if (refs_snapshot) {
1247
- read_refs_snapshot(refs_snapshot, &revs);
1248
- } else {
1249
- setup_revisions(0, NULL, &revs, NULL);
1250
- for_each_ref(add_ref_to_pending, &revs);
1251
- }
1252
-
1253
- /*
1254
- * Skipping promisor objects here is intentional, since it only excludes
1255
- * them from the list of reachable commits that we want to select from
1256
- * when computing the selection of MIDX'd commits to receive bitmaps.
1257
- *
1258
- * Reachability bitmaps do require that their objects be closed under
1259
- * reachability, but fetching any objects missing from promisors at this
1260
- * point is too late. But, if one of those objects can be reached from
1261
- * an another object that is included in the bitmap, then we will
1262
- * complain later that we don't have reachability closure (and fail
1263
- * appropriately).
1264
- */
1265
- fetch_if_missing = 0;
1266
- revs.exclude_promisor_objects = 1;
1267
-
1268
- if (prepare_revision_walk(&revs))
1269
- die(_("revision walk setup failed"));
1270
-
1271
- traverse_commit_list(&revs, bitmap_show_commit, NULL, &cb);
1272
- if (indexed_commits_nr_p)
1273
- *indexed_commits_nr_p = cb.commits_nr;
1274
-
1275
- release_revisions(&revs);
1276
-
1277
- trace2_region_leave("midx", "find_commits_for_midx_bitmap",
1278
- the_repository);
1279
-
1280
- return cb.commits;
1281
-}
1282
-
1283
-static int write_midx_bitmap(const char *midx_name,
1284
- const unsigned char *midx_hash,
1285
- struct packing_data *pdata,
1286
- struct commit **commits,
1287
- uint32_t commits_nr,
1288
- uint32_t *pack_order,
1289
- unsigned flags)
1290
-{
1291
- int ret, i;
1292
- uint16_t options = 0;
1293
- struct pack_idx_entry **index;
1294
- char *bitmap_name = xstrfmt("%s-%s.bitmap", midx_name,
1295
- hash_to_hex(midx_hash));
1296
-
1297
- trace2_region_enter("midx", "write_midx_bitmap", the_repository);
1298
-
1299
- if (flags & MIDX_WRITE_BITMAP_HASH_CACHE)
1300
- options |= BITMAP_OPT_HASH_CACHE;
1301
-
1302
- if (flags & MIDX_WRITE_BITMAP_LOOKUP_TABLE)
1303
- options |= BITMAP_OPT_LOOKUP_TABLE;
1304
-
1305
- /*
1306
- * Build the MIDX-order index based on pdata.objects (which is already
1307
- * in MIDX order; c.f., 'midx_pack_order_cmp()' for the definition of
1308
- * this order).
1309
- */
1310
- ALLOC_ARRAY(index, pdata->nr_objects);
1311
- for (i = 0; i < pdata->nr_objects; i++)
1312
- index[i] = &pdata->objects[i].idx;
1313
-
1314
- bitmap_writer_show_progress(flags & MIDX_PROGRESS);
1315
- bitmap_writer_build_type_index(pdata, index, pdata->nr_objects);
1316
-
1317
- /*
1318
- * bitmap_writer_finish expects objects in lex order, but pack_order
1319
- * gives us exactly that. use it directly instead of re-sorting the
1320
- * array.
1321
- *
1322
- * This changes the order of objects in 'index' between
1323
- * bitmap_writer_build_type_index and bitmap_writer_finish.
1324
- *
1325
- * The same re-ordering takes place in the single-pack bitmap code via
1326
- * write_idx_file(), which is called by finish_tmp_packfile(), which
1327
- * happens between bitmap_writer_build_type_index() and
1328
- * bitmap_writer_finish().
1329
- */
1330
- for (i = 0; i < pdata->nr_objects; i++)
1331
- index[pack_order[i]] = &pdata->objects[i].idx;
1332
-
1333
- bitmap_writer_select_commits(commits, commits_nr, -1);
1334
- ret = bitmap_writer_build(pdata);
1335
- if (ret < 0)
1336
- goto cleanup;
1337
-
1338
- bitmap_writer_set_checksum(midx_hash);
1339
- bitmap_writer_finish(index, pdata->nr_objects, bitmap_name, options);
1340
-
1341
-cleanup:
1342
- free(index);
1343
- free(bitmap_name);
1344
-
1345
- trace2_region_leave("midx", "write_midx_bitmap", the_repository);
1346
-
1347
- return ret;
1348
-}
1349
-
1350
-static struct multi_pack_index *lookup_multi_pack_index(struct repository *r,
1351
- const char *object_dir)
1352
-{
1353
- struct multi_pack_index *result = NULL;
1354
- struct multi_pack_index *cur;
1355
- char *obj_dir_real = real_pathdup(object_dir, 1);
1356
- struct strbuf cur_path_real = STRBUF_INIT;
1357
-
1358
- /* Ensure the given object_dir is local, or a known alternate. */
1359
- find_odb(r, obj_dir_real);
1360
-
1361
- for (cur = get_multi_pack_index(r); cur; cur = cur->next) {
1362
- strbuf_realpath(&cur_path_real, cur->object_dir, 1);
1363
- if (!strcmp(obj_dir_real, cur_path_real.buf)) {
1364
- result = cur;
1365
- goto cleanup;
1366
- }
1367
- }
1368
-
1369
-cleanup:
1370
- free(obj_dir_real);
1371
- strbuf_release(&cur_path_real);
1372
- return result;
1373
-}
1374
-
1375
-static int write_midx_internal(const char *object_dir,
1376
- struct string_list *packs_to_include,
1377
- struct string_list *packs_to_drop,
1378
- const char *preferred_pack_name,
1379
- const char *refs_snapshot,
1380
- unsigned flags)
1381
-{
1382
- struct strbuf midx_name = STRBUF_INIT;
1383
- unsigned char midx_hash[GIT_MAX_RAWSZ];
1384
- uint32_t i;
1385
- struct hashfile *f = NULL;
1386
- struct lock_file lk;
1387
- struct write_midx_context ctx = { 0 };
1388
- int bitmapped_packs_concat_len = 0;
1389
- int pack_name_concat_len = 0;
1390
- int dropped_packs = 0;
1391
- int result = 0;
1392
- struct chunkfile *cf;
1393
-
1394
- trace2_region_enter("midx", "write_midx_internal", the_repository);
1395
-
1396
- get_midx_filename(&midx_name, object_dir);
1397
- if (safe_create_leading_directories(midx_name.buf))
1398
- die_errno(_("unable to create leading directories of %s"),
1399
- midx_name.buf);
1400
-
1401
- if (!packs_to_include) {
1402
- /*
1403
- * Only reference an existing MIDX when not filtering which
1404
- * packs to include, since all packs and objects are copied
1405
- * blindly from an existing MIDX if one is present.
1406
- */
1407
- ctx.m = lookup_multi_pack_index(the_repository, object_dir);
1408
- }
1409
-
1410
- if (ctx.m && !midx_checksum_valid(ctx.m)) {
1411
- warning(_("ignoring existing multi-pack-index; checksum mismatch"));
1412
- ctx.m = NULL;
1413
- }
1414
-
1415
- ctx.nr = 0;
1416
- ctx.alloc = ctx.m ? ctx.m->num_packs : 16;
1417
- ctx.info = NULL;
1418
- ALLOC_ARRAY(ctx.info, ctx.alloc);
1419
-
1420
- if (ctx.m) {
1421
- for (i = 0; i < ctx.m->num_packs; i++) {
1422
- ALLOC_GROW(ctx.info, ctx.nr + 1, ctx.alloc);
1423
-
1424
- if (flags & MIDX_WRITE_REV_INDEX) {
1425
- /*
1426
- * If generating a reverse index, need to have
1427
- * packed_git's loaded to compare their
1428
- * mtimes and object count.
1429
- */
1430
- if (prepare_midx_pack(the_repository, ctx.m, i)) {
1431
- error(_("could not load pack"));
1432
- result = 1;
1433
- goto cleanup;
1434
- }
1435
-
1436
- if (open_pack_index(ctx.m->packs[i]))
1437
- die(_("could not open index for %s"),
1438
- ctx.m->packs[i]->pack_name);
1439
- }
1440
-
1441
- fill_pack_info(&ctx.info[ctx.nr++], ctx.m->packs[i],
1442
- ctx.m->pack_names[i], i);
1443
- }
1444
- }
1445
-
1446
- ctx.pack_paths_checked = 0;
1447
- if (flags & MIDX_PROGRESS)
1448
- ctx.progress = start_delayed_progress(_("Adding packfiles to multi-pack-index"), 0);
1449
- else
1450
- ctx.progress = NULL;
1451
-
1452
- ctx.to_include = packs_to_include;
1453
-
1454
- for_each_file_in_pack_dir(object_dir, add_pack_to_midx, &ctx);
1455
- stop_progress(&ctx.progress);
1456
-
1457
- if ((ctx.m && ctx.nr == ctx.m->num_packs) &&
1458
- !(packs_to_include || packs_to_drop)) {
1459
- struct bitmap_index *bitmap_git;
1460
- int bitmap_exists;
1461
- int want_bitmap = flags & MIDX_WRITE_BITMAP;
1462
-
1463
- bitmap_git = prepare_midx_bitmap_git(ctx.m);
1464
- bitmap_exists = bitmap_git && bitmap_is_midx(bitmap_git);
1465
- free_bitmap_index(bitmap_git);
1466
-
1467
- if (bitmap_exists || !want_bitmap) {
1468
- /*
1469
- * The correct MIDX already exists, and so does a
1470
- * corresponding bitmap (or one wasn't requested).
1471
- */
1472
- if (!want_bitmap)
1473
- clear_midx_files_ext(object_dir, ".bitmap",
1474
- NULL);
1475
- goto cleanup;
1476
- }
1477
- }
1478
-
1479
- if (preferred_pack_name) {
1480
- ctx.preferred_pack_idx = -1;
1481
-
1482
- for (i = 0; i < ctx.nr; i++) {
1483
- if (!cmp_idx_or_pack_name(preferred_pack_name,
1484
- ctx.info[i].pack_name)) {
1485
- ctx.preferred_pack_idx = i;
1486
- break;
1487
- }
1488
- }
1489
-
1490
- if (ctx.preferred_pack_idx == -1)
1491
- warning(_("unknown preferred pack: '%s'"),
1492
- preferred_pack_name);
1493
- } else if (ctx.nr &&
1494
- (flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP))) {
1495
- struct packed_git *oldest = ctx.info[ctx.preferred_pack_idx].p;
1496
- ctx.preferred_pack_idx = 0;
1497
-
1498
- if (packs_to_drop && packs_to_drop->nr)
1499
- BUG("cannot write a MIDX bitmap during expiration");
1500
-
1501
- /*
1502
- * set a preferred pack when writing a bitmap to ensure that
1503
- * the pack from which the first object is selected in pseudo
1504
- * pack-order has all of its objects selected from that pack
1505
- * (and not another pack containing a duplicate)
1506
- */
1507
- for (i = 1; i < ctx.nr; i++) {
1508
- struct packed_git *p = ctx.info[i].p;
1509
-
1510
- if (!oldest->num_objects || p->mtime < oldest->mtime) {
1511
- oldest = p;
1512
- ctx.preferred_pack_idx = i;
1513
- }
1514
- }
1515
-
1516
- if (!oldest->num_objects) {
1517
- /*
1518
- * If all packs are empty; unset the preferred index.
1519
- * This is acceptable since there will be no duplicate
1520
- * objects to resolve, so the preferred value doesn't
1521
- * matter.
1522
- */
1523
- ctx.preferred_pack_idx = -1;
1524
- }
1525
- } else {
1526
- /*
1527
- * otherwise don't mark any pack as preferred to avoid
1528
- * interfering with expiration logic below
1529
- */
1530
- ctx.preferred_pack_idx = -1;
1531
- }
1532
-
1533
- if (ctx.preferred_pack_idx > -1) {
1534
- struct packed_git *preferred = ctx.info[ctx.preferred_pack_idx].p;
1535
- if (!preferred->num_objects) {
1536
- error(_("cannot select preferred pack %s with no objects"),
1537
- preferred->pack_name);
1538
- result = 1;
1539
- goto cleanup;
1540
- }
1541
- }
1542
-
1543
- ctx.entries = get_sorted_entries(ctx.m, ctx.info, ctx.nr, &ctx.entries_nr,
1544
- ctx.preferred_pack_idx);
1545
-
1546
- ctx.large_offsets_needed = 0;
1547
- for (i = 0; i < ctx.entries_nr; i++) {
1548
- if (ctx.entries[i].offset > 0x7fffffff)
1549
- ctx.num_large_offsets++;
1550
- if (ctx.entries[i].offset > 0xffffffff)
1551
- ctx.large_offsets_needed = 1;
1552
- }
1553
-
1554
- QSORT(ctx.info, ctx.nr, pack_info_compare);
1555
-
1556
- if (packs_to_drop && packs_to_drop->nr) {
1557
- int drop_index = 0;
1558
- int missing_drops = 0;
1559
-
1560
- for (i = 0; i < ctx.nr && drop_index < packs_to_drop->nr; i++) {
1561
- int cmp = strcmp(ctx.info[i].pack_name,
1562
- packs_to_drop->items[drop_index].string);
1563
-
1564
- if (!cmp) {
1565
- drop_index++;
1566
- ctx.info[i].expired = 1;
1567
- } else if (cmp > 0) {
1568
- error(_("did not see pack-file %s to drop"),
1569
- packs_to_drop->items[drop_index].string);
1570
- drop_index++;
1571
- missing_drops++;
1572
- i--;
1573
- } else {
1574
- ctx.info[i].expired = 0;
1575
- }
1576
- }
1577
-
1578
- if (missing_drops) {
1579
- result = 1;
1580
- goto cleanup;
1581
- }
1582
- }
1583
-
1584
- /*
1585
- * pack_perm stores a permutation between pack-int-ids from the
1586
- * previous multi-pack-index to the new one we are writing:
1587
- *
1588
- * pack_perm[old_id] = new_id
1589
- */
1590
- ALLOC_ARRAY(ctx.pack_perm, ctx.nr);
1591
- for (i = 0; i < ctx.nr; i++) {
1592
- if (ctx.info[i].expired) {
1593
- dropped_packs++;
1594
- ctx.pack_perm[ctx.info[i].orig_pack_int_id] = PACK_EXPIRED;
1595
- } else {
1596
- ctx.pack_perm[ctx.info[i].orig_pack_int_id] = i - dropped_packs;
1597
- }
1598
- }
1599
-
1600
- for (i = 0; i < ctx.nr; i++) {
1601
- if (ctx.info[i].expired)
1602
- continue;
1603
- pack_name_concat_len += strlen(ctx.info[i].pack_name) + 1;
1604
- bitmapped_packs_concat_len += 2 * sizeof(uint32_t);
1605
- }
1606
-
1607
- /* Check that the preferred pack wasn't expired (if given). */
1608
- if (preferred_pack_name) {
1609
- struct pack_info *preferred = bsearch(preferred_pack_name,
1610
- ctx.info, ctx.nr,
1611
- sizeof(*ctx.info),
1612
- idx_or_pack_name_cmp);
1613
- if (preferred) {
1614
- uint32_t perm = ctx.pack_perm[preferred->orig_pack_int_id];
1615
- if (perm == PACK_EXPIRED)
1616
- warning(_("preferred pack '%s' is expired"),
1617
- preferred_pack_name);
1618
- }
1619
- }
1620
-
1621
- if (pack_name_concat_len % MIDX_CHUNK_ALIGNMENT)
1622
- pack_name_concat_len += MIDX_CHUNK_ALIGNMENT -
1623
- (pack_name_concat_len % MIDX_CHUNK_ALIGNMENT);
1624
-
1625
- hold_lock_file_for_update(&lk, midx_name.buf, LOCK_DIE_ON_ERROR);
1626
- f = hashfd(get_lock_file_fd(&lk), get_lock_file_path(&lk));
1627
-
1628
- if (ctx.nr - dropped_packs == 0) {
1629
- error(_("no pack files to index."));
1630
- result = 1;
1631
- goto cleanup;
1632
- }
1633
-
1634
- if (!ctx.entries_nr) {
1635
- if (flags & MIDX_WRITE_BITMAP)
1636
- warning(_("refusing to write multi-pack .bitmap without any objects"));
1637
- flags &= ~(MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP);
1638
- }
1639
-
1640
- cf = init_chunkfile(f);
1641
-
1642
- add_chunk(cf, MIDX_CHUNKID_PACKNAMES, pack_name_concat_len,
1643
- write_midx_pack_names);
1644
- add_chunk(cf, MIDX_CHUNKID_OIDFANOUT, MIDX_CHUNK_FANOUT_SIZE,
1645
- write_midx_oid_fanout);
1646
- add_chunk(cf, MIDX_CHUNKID_OIDLOOKUP,
1647
- st_mult(ctx.entries_nr, the_hash_algo->rawsz),
1648
- write_midx_oid_lookup);
1649
- add_chunk(cf, MIDX_CHUNKID_OBJECTOFFSETS,
1650
- st_mult(ctx.entries_nr, MIDX_CHUNK_OFFSET_WIDTH),
1651
- write_midx_object_offsets);
1652
-
1653
- if (ctx.large_offsets_needed)
1654
- add_chunk(cf, MIDX_CHUNKID_LARGEOFFSETS,
1655
- st_mult(ctx.num_large_offsets,
1656
- MIDX_CHUNK_LARGE_OFFSET_WIDTH),
1657
- write_midx_large_offsets);
1658
-
1659
- if (flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP)) {
1660
- ctx.pack_order = midx_pack_order(&ctx);
1661
- add_chunk(cf, MIDX_CHUNKID_REVINDEX,
1662
- st_mult(ctx.entries_nr, sizeof(uint32_t)),
1663
- write_midx_revindex);
1664
- add_chunk(cf, MIDX_CHUNKID_BITMAPPEDPACKS,
1665
- bitmapped_packs_concat_len,
1666
- write_midx_bitmapped_packs);
1667
- }
1668
-
1669
- write_midx_header(f, get_num_chunks(cf), ctx.nr - dropped_packs);
1670
- write_chunkfile(cf, &ctx);
1671
-
1672
- finalize_hashfile(f, midx_hash, FSYNC_COMPONENT_PACK_METADATA,
1673
- CSUM_FSYNC | CSUM_HASH_IN_STREAM);
1674
- free_chunkfile(cf);
1675
-
1676
- if (flags & MIDX_WRITE_REV_INDEX &&
1677
- git_env_bool("GIT_TEST_MIDX_WRITE_REV", 0))
1678
- write_midx_reverse_index(midx_name.buf, midx_hash, &ctx);
1679
-
1680
- if (flags & MIDX_WRITE_BITMAP) {
1681
- struct packing_data pdata;
1682
- struct commit **commits;
1683
- uint32_t commits_nr;
1684
-
1685
- if (!ctx.entries_nr)
1686
- BUG("cannot write a bitmap without any objects");
1687
-
1688
- prepare_midx_packing_data(&pdata, &ctx);
1689
-
1690
- commits = find_commits_for_midx_bitmap(&commits_nr, refs_snapshot, &ctx);
1691
-
1692
- /*
1693
- * The previous steps translated the information from
1694
- * 'entries' into information suitable for constructing
1695
- * bitmaps. We no longer need that array, so clear it to
1696
- * reduce memory pressure.
1697
- */
1698
- FREE_AND_NULL(ctx.entries);
1699
- ctx.entries_nr = 0;
1700
-
1701
- if (write_midx_bitmap(midx_name.buf, midx_hash, &pdata,
1702
- commits, commits_nr, ctx.pack_order,
1703
- flags) < 0) {
1704
- error(_("could not write multi-pack bitmap"));
1705
- result = 1;
1706
- clear_packing_data(&pdata);
1707
- free(commits);
1708
- goto cleanup;
1709
- }
1710
-
1711
- clear_packing_data(&pdata);
1712
- free(commits);
1713
- }
1714
- /*
1715
- * NOTE: Do not use ctx.entries beyond this point, since it might
1716
- * have been freed in the previous if block.
1717
- */
1718
-
1719
- if (ctx.m)
1720
- close_object_store(the_repository->objects);
1721
-
1722
- if (commit_lock_file(&lk) < 0)
1723
- die_errno(_("could not write multi-pack-index"));
1724
-
1725
- clear_midx_files_ext(object_dir, ".bitmap", midx_hash);
1726
- clear_midx_files_ext(object_dir, ".rev", midx_hash);
1727
-
1728
-cleanup:
1729
- for (i = 0; i < ctx.nr; i++) {
1730
- if (ctx.info[i].p) {
1731
- close_pack(ctx.info[i].p);
1732
- free(ctx.info[i].p);
1733
- }
1734
- free(ctx.info[i].pack_name);
1735
- }
1736
-
1737
- free(ctx.info);
1738
- free(ctx.entries);
1739
- free(ctx.pack_perm);
1740
- free(ctx.pack_order);
1741
- strbuf_release(&midx_name);
1742
-
1743
- trace2_region_leave("midx", "write_midx_internal", the_repository);
1744
-
1745
- return result;
1746
-}
1747
-
1748
-int write_midx_file(const char *object_dir,
1749
- const char *preferred_pack_name,
1750
- const char *refs_snapshot,
1751
- unsigned flags)
1752
-{
1753
- return write_midx_internal(object_dir, NULL, NULL, preferred_pack_name,
1754
- refs_snapshot, flags);
1755
-}
1756
-
1757
-int write_midx_file_only(const char *object_dir,
1758
- struct string_list *packs_to_include,
1759
- const char *preferred_pack_name,
1760
- const char *refs_snapshot,
1761
- unsigned flags)
1762
-{
1763
- return write_midx_internal(object_dir, packs_to_include, NULL,
1764
- preferred_pack_name, refs_snapshot, flags);
1765
-}
1766
-
1767
-struct clear_midx_data {
1768
- char *keep;
1769
- const char *ext;
1770
-};
1771
-
1772
-static void clear_midx_file_ext(const char *full_path, size_t full_path_len UNUSED,
1773
- const char *file_name, void *_data)
1774
-{
1775
- struct clear_midx_data *data = _data;
1776
-
1777
- if (!(starts_with(file_name, "multi-pack-index-") &&
1778
- ends_with(file_name, data->ext)))
1779
- return;
1780
- if (data->keep && !strcmp(data->keep, file_name))
1781
- return;
1782
-
1783
- if (unlink(full_path))
1784
- die_errno(_("failed to remove %s"), full_path);
1785
-}
1786
-
1787
-static void clear_midx_files_ext(const char *object_dir, const char *ext,
1788
- unsigned char *keep_hash)
1789
-{
1790
- struct clear_midx_data data;
1791
- memset(&data, 0, sizeof(struct clear_midx_data));
1792
-
1793
- if (keep_hash)
1794
- data.keep = xstrfmt("multi-pack-index-%s%s",
1795
- hash_to_hex(keep_hash), ext);
1796
- data.ext = ext;
1797
-
1798
- for_each_file_in_pack_dir(object_dir,
1799
- clear_midx_file_ext,
1800
- &data);
1801
-
1802
- free(data.keep);
1803
-}
1804
-
1805
-void clear_midx_file(struct repository *r)
1806
-{
1807
- struct strbuf midx = STRBUF_INIT;
1808
-
1809
- get_midx_filename(&midx, r->objects->odb->path);
1810
-
1811
- if (r->objects && r->objects->multi_pack_index) {
1812
- close_midx(r->objects->multi_pack_index);
1813
- r->objects->multi_pack_index = NULL;
1814
- }
1815
-
1816
- if (remove_path(midx.buf))
1817
- die(_("failed to clear multi-pack-index at %s"), midx.buf);
1818
-
1819
- clear_midx_files_ext(r->objects->odb->path, ".bitmap", NULL);
1820
- clear_midx_files_ext(r->objects->odb->path, ".rev", NULL);
1821
-
1822
- strbuf_release(&midx);
1823
-}
1824
-
1825
-static int verify_midx_error;
1826
-
1827
-__attribute__((format (printf, 1, 2)))
1828
-static void midx_report(const char *fmt, ...)
1829
-{
1830
- va_list ap;
1831
- verify_midx_error = 1;
1832
- va_start(ap, fmt);
1833
- vfprintf(stderr, fmt, ap);
1834
- fprintf(stderr, "\n");
1835
- va_end(ap);
1836
-}
1837
-
1838
-struct pair_pos_vs_id
1839
-{
1840
- uint32_t pos;
1841
- uint32_t pack_int_id;
1842
-};
1843
-
1844
-static int compare_pair_pos_vs_id(const void *_a, const void *_b)
1845
-{
1846
- struct pair_pos_vs_id *a = (struct pair_pos_vs_id *)_a;
1847
- struct pair_pos_vs_id *b = (struct pair_pos_vs_id *)_b;
1848
-
1849
- return b->pack_int_id - a->pack_int_id;
1850
-}
1851
-
1852
-/*
1853
- * Limit calls to display_progress() for performance reasons.
1854
- * The interval here was arbitrarily chosen.
1855
- */
1856
-#define SPARSE_PROGRESS_INTERVAL (1 << 12)
1857
-#define midx_display_sparse_progress(progress, n) \
1858
- do { \
1859
- uint64_t _n = (n); \
1860
- if ((_n & (SPARSE_PROGRESS_INTERVAL - 1)) == 0) \
1861
- display_progress(progress, _n); \
1862
- } while (0)
1863
-
1864
-int verify_midx_file(struct repository *r, const char *object_dir, unsigned flags)
1865
-{
1866
- struct pair_pos_vs_id *pairs = NULL;
1867
- uint32_t i;
1868
- struct progress *progress = NULL;
1869
- struct multi_pack_index *m = load_multi_pack_index(object_dir, 1);
1870
- verify_midx_error = 0;
1871
-
1872
- if (!m) {
1873
- int result = 0;
1874
- struct stat sb;
1875
- struct strbuf filename = STRBUF_INIT;
1876
-
1877
- get_midx_filename(&filename, object_dir);
1878
-
1879
- if (!stat(filename.buf, &sb)) {
1880
- error(_("multi-pack-index file exists, but failed to parse"));
1881
- result = 1;
1882
- }
1883
- strbuf_release(&filename);
1884
- return result;
1885
- }
1886
-
1887
- if (!midx_checksum_valid(m))
1888
- midx_report(_("incorrect checksum"));
1889
-
1890
- if (flags & MIDX_PROGRESS)
1891
- progress = start_delayed_progress(_("Looking for referenced packfiles"),
1892
- m->num_packs);
1893
- for (i = 0; i < m->num_packs; i++) {
1894
- if (prepare_midx_pack(r, m, i))
1895
- midx_report("failed to load pack in position %d", i);
1896
-
1897
- display_progress(progress, i + 1);
1898
- }
1899
- stop_progress(&progress);
1900
-
1901
- if (m->num_objects == 0) {
1902
- midx_report(_("the midx contains no oid"));
1903
- /*
1904
- * Remaining tests assume that we have objects, so we can
1905
- * return here.
1906
- */
1907
- goto cleanup;
1908
- }
1909
-
1910
- if (flags & MIDX_PROGRESS)
1911
- progress = start_sparse_progress(_("Verifying OID order in multi-pack-index"),
1912
- m->num_objects - 1);
1913
- for (i = 0; i < m->num_objects - 1; i++) {
1914
- struct object_id oid1, oid2;
1915
-
1916
- nth_midxed_object_oid(&oid1, m, i);
1917
- nth_midxed_object_oid(&oid2, m, i + 1);
1918
-
1919
- if (oidcmp(&oid1, &oid2) >= 0)
1920
- midx_report(_("oid lookup out of order: oid[%d] = %s >= %s = oid[%d]"),
1921
- i, oid_to_hex(&oid1), oid_to_hex(&oid2), i + 1);
1922
-
1923
- midx_display_sparse_progress(progress, i + 1);
1924
- }
1925
- stop_progress(&progress);
1926
-
1927
- /*
1928
- * Create an array mapping each object to its packfile id. Sort it
1929
- * to group the objects by packfile. Use this permutation to visit
1930
- * each of the objects and only require 1 packfile to be open at a
1931
- * time.
1932
- */
1933
- ALLOC_ARRAY(pairs, m->num_objects);
1934
- for (i = 0; i < m->num_objects; i++) {
1935
- pairs[i].pos = i;
1936
- pairs[i].pack_int_id = nth_midxed_pack_int_id(m, i);
1937
- }
1938
-
1939
- if (flags & MIDX_PROGRESS)
1940
- progress = start_sparse_progress(_("Sorting objects by packfile"),
1941
- m->num_objects);
1942
- display_progress(progress, 0); /* TODO: Measure QSORT() progress */
1943
- QSORT(pairs, m->num_objects, compare_pair_pos_vs_id);
1944
- stop_progress(&progress);
1945
-
1946
- if (flags & MIDX_PROGRESS)
1947
- progress = start_sparse_progress(_("Verifying object offsets"), m->num_objects);
1948
- for (i = 0; i < m->num_objects; i++) {
1949
- struct object_id oid;
1950
- struct pack_entry e;
1951
- off_t m_offset, p_offset;
1952
-
1953
- if (i > 0 && pairs[i-1].pack_int_id != pairs[i].pack_int_id &&
1954
- m->packs[pairs[i-1].pack_int_id])
1955
- {
1956
- close_pack_fd(m->packs[pairs[i-1].pack_int_id]);
1957
- close_pack_index(m->packs[pairs[i-1].pack_int_id]);
1958
- }
1959
-
1960
- nth_midxed_object_oid(&oid, m, pairs[i].pos);
1961
-
1962
- if (!fill_midx_entry(r, &oid, &e, m)) {
1963
- midx_report(_("failed to load pack entry for oid[%d] = %s"),
1964
- pairs[i].pos, oid_to_hex(&oid));
1965
- continue;
1966
- }
1967
-
1968
- if (open_pack_index(e.p)) {
1969
- midx_report(_("failed to load pack-index for packfile %s"),
1970
- e.p->pack_name);
1971
- break;
1972
- }
1973
-
1974
- m_offset = e.offset;
1975
- p_offset = find_pack_entry_one(oid.hash, e.p);
1976
-
1977
- if (m_offset != p_offset)
1978
- midx_report(_("incorrect object offset for oid[%d] = %s: %"PRIx64" != %"PRIx64),
1979
- pairs[i].pos, oid_to_hex(&oid), m_offset, p_offset);
1980
-
1981
- midx_display_sparse_progress(progress, i + 1);
1982
- }
1983
- stop_progress(&progress);
1984
-
1985
-cleanup:
1986
- free(pairs);
1987
- close_midx(m);
708
+cleanup:
709
+ free(pairs);
710
+ close_midx(m);
711
712
return verify_midx_error;
713
}
1991
-
1992
-int expire_midx_packs(struct repository *r, const char *object_dir, unsigned flags)
1993
-{
1994
- uint32_t i, *count, result = 0;
1995
- struct string_list packs_to_drop = STRING_LIST_INIT_DUP;
1996
- struct multi_pack_index *m = lookup_multi_pack_index(r, object_dir);
1997
- struct progress *progress = NULL;
1998
-
1999
- if (!m)
2000
- return 0;
2001
-
2002
- CALLOC_ARRAY(count, m->num_packs);
2003
-
2004
- if (flags & MIDX_PROGRESS)
2005
- progress = start_delayed_progress(_("Counting referenced objects"),
2006
- m->num_objects);
2007
- for (i = 0; i < m->num_objects; i++) {
2008
- int pack_int_id = nth_midxed_pack_int_id(m, i);
2009
- count[pack_int_id]++;
2010
- display_progress(progress, i + 1);
2011
- }
2012
- stop_progress(&progress);
2013
-
2014
- if (flags & MIDX_PROGRESS)
2015
- progress = start_delayed_progress(_("Finding and deleting unreferenced packfiles"),
2016
- m->num_packs);
2017
- for (i = 0; i < m->num_packs; i++) {
2018
- char *pack_name;
2019
- display_progress(progress, i + 1);
2020
-
2021
- if (count[i])
2022
- continue;
2023
-
2024
- if (prepare_midx_pack(r, m, i))
2025
- continue;
2026
-
2027
- if (m->packs[i]->pack_keep || m->packs[i]->is_cruft)
2028
- continue;
2029
-
2030
- pack_name = xstrdup(m->packs[i]->pack_name);
2031
- close_pack(m->packs[i]);
2032
-
2033
- string_list_insert(&packs_to_drop, m->pack_names[i]);
2034
- unlink_pack_path(pack_name, 0);
2035
- free(pack_name);
2036
- }
2037
- stop_progress(&progress);
2038
-
2039
- free(count);
2040
-
2041
- if (packs_to_drop.nr)
2042
- result = write_midx_internal(object_dir, NULL, &packs_to_drop, NULL, NULL, flags);
2043
-
2044
- string_list_clear(&packs_to_drop, 0);
2045
-
2046
- return result;
2047
-}
2048
-
2049
-struct repack_info {
2050
- timestamp_t mtime;
2051
- uint32_t referenced_objects;
2052
- uint32_t pack_int_id;
2053
-};
2054
-
2055
-static int compare_by_mtime(const void *a_, const void *b_)
2056
-{
2057
- const struct repack_info *a, *b;
2058
-
2059
- a = (const struct repack_info *)a_;
2060
- b = (const struct repack_info *)b_;
2061
-
2062
- if (a->mtime < b->mtime)
2063
- return -1;
2064
- if (a->mtime > b->mtime)
2065
- return 1;
2066
- return 0;
2067
-}
2068
-
2069
-static int fill_included_packs_all(struct repository *r,
2070
- struct multi_pack_index *m,
2071
- unsigned char *include_pack)
2072
-{
2073
- uint32_t i, count = 0;
2074
- int pack_kept_objects = 0;
2075
-
2076
- repo_config_get_bool(r, "repack.packkeptobjects", &pack_kept_objects);
2077
-
2078
- for (i = 0; i < m->num_packs; i++) {
2079
- if (prepare_midx_pack(r, m, i))
2080
- continue;
2081
- if (!pack_kept_objects && m->packs[i]->pack_keep)
2082
- continue;
2083
- if (m->packs[i]->is_cruft)
2084
- continue;
2085
-
2086
- include_pack[i] = 1;
2087
- count++;
2088
- }
2089
-
2090
- return count < 2;
2091
-}
2092
-
2093
-static int fill_included_packs_batch(struct repository *r,
2094
- struct multi_pack_index *m,
2095
- unsigned char *include_pack,
2096
- size_t batch_size)
2097
-{
2098
- uint32_t i, packs_to_repack;
2099
- size_t total_size;
2100
- struct repack_info *pack_info;
2101
- int pack_kept_objects = 0;
2102
-
2103
- CALLOC_ARRAY(pack_info, m->num_packs);
2104
-
2105
- repo_config_get_bool(r, "repack.packkeptobjects", &pack_kept_objects);
2106
-
2107
- for (i = 0; i < m->num_packs; i++) {
2108
- pack_info[i].pack_int_id = i;
2109
-
2110
- if (prepare_midx_pack(r, m, i))
2111
- continue;
2112
-
2113
- pack_info[i].mtime = m->packs[i]->mtime;
2114
- }
2115
-
2116
- for (i = 0; i < m->num_objects; i++) {
2117
- uint32_t pack_int_id = nth_midxed_pack_int_id(m, i);
2118
- pack_info[pack_int_id].referenced_objects++;
2119
- }
2120
-
2121
- QSORT(pack_info, m->num_packs, compare_by_mtime);
2122
-
2123
- total_size = 0;
2124
- packs_to_repack = 0;
2125
- for (i = 0; total_size < batch_size && i < m->num_packs; i++) {
2126
- int pack_int_id = pack_info[i].pack_int_id;
2127
- struct packed_git *p = m->packs[pack_int_id];
2128
- size_t expected_size;
2129
-
2130
- if (!p)
2131
- continue;
2132
- if (!pack_kept_objects && p->pack_keep)
2133
- continue;
2134
- if (p->is_cruft)
2135
- continue;
2136
- if (open_pack_index(p) || !p->num_objects)
2137
- continue;
2138
-
2139
- expected_size = st_mult(p->pack_size,
2140
- pack_info[i].referenced_objects);
2141
- expected_size /= p->num_objects;
2142
-
2143
- if (expected_size >= batch_size)
2144
- continue;
2145
-
2146
- packs_to_repack++;
2147
- total_size += expected_size;
2148
- include_pack[pack_int_id] = 1;
2149
- }
2150
-
2151
- free(pack_info);
2152
-
2153
- if (packs_to_repack < 2)
2154
- return 1;
2155
-
2156
- return 0;
2157
-}
2158
-
2159
-int midx_repack(struct repository *r, const char *object_dir, size_t batch_size, unsigned flags)
2160
-{
2161
- int result = 0;
2162
- uint32_t i;
2163
- unsigned char *include_pack;
2164
- struct child_process cmd = CHILD_PROCESS_INIT;
2165
- FILE *cmd_in;
2166
- struct multi_pack_index *m = lookup_multi_pack_index(r, object_dir);
2167
-
2168
- /*
2169
- * When updating the default for these configuration
2170
- * variables in builtin/repack.c, these must be adjusted
2171
- * to match.
2172
- */
2173
- int delta_base_offset = 1;
2174
- int use_delta_islands = 0;
2175
-
2176
- if (!m)
2177
- return 0;
2178
-
2179
- CALLOC_ARRAY(include_pack, m->num_packs);
2180
-
2181
- if (batch_size) {
2182
- if (fill_included_packs_batch(r, m, include_pack, batch_size))
2183
- goto cleanup;
2184
- } else if (fill_included_packs_all(r, m, include_pack))
2185
- goto cleanup;
2186
-
2187
- repo_config_get_bool(r, "repack.usedeltabaseoffset", &delta_base_offset);
2188
- repo_config_get_bool(r, "repack.usedeltaislands", &use_delta_islands);
2189
-
2190
- strvec_push(&cmd.args, "pack-objects");
2191
-
2192
- strvec_pushf(&cmd.args, "%s/pack/pack", object_dir);
2193
-
2194
- if (delta_base_offset)
2195
- strvec_push(&cmd.args, "--delta-base-offset");
2196
- if (use_delta_islands)
2197
- strvec_push(&cmd.args, "--delta-islands");
2198
-
2199
- if (flags & MIDX_PROGRESS)
2200
- strvec_push(&cmd.args, "--progress");
2201
- else
2202
- strvec_push(&cmd.args, "-q");
2203
-
2204
- cmd.git_cmd = 1;
2205
- cmd.in = cmd.out = -1;
2206
-
2207
- if (start_command(&cmd)) {
2208
- error(_("could not start pack-objects"));
2209
- result = 1;
2210
- goto cleanup;
2211
- }
2212
-
2213
- cmd_in = xfdopen(cmd.in, "w");
2214
-
2215
- for (i = 0; i < m->num_objects; i++) {
2216
- struct object_id oid;
2217
- uint32_t pack_int_id = nth_midxed_pack_int_id(m, i);
2218
-
2219
- if (!include_pack[pack_int_id])
2220
- continue;
2221
-
2222
- nth_midxed_object_oid(&oid, m, i);
2223
- fprintf(cmd_in, "%s\n", oid_to_hex(&oid));
2224
- }
2225
- fclose(cmd_in);
2226
-
2227
- if (finish_command(&cmd)) {
2228
- error(_("could not finish pack-objects"));
2229
- result = 1;
2230
- goto cleanup;
2231
- }
2232
-
2233
- result = write_midx_internal(object_dir, NULL, NULL, NULL, NULL, flags);
2234
-
2235
-cleanup:
2236
- free(include_pack);
2237
- return result;
2238
-}
midx.h
+19
@@ -8,6 +8,25 @@ struct pack_entry;
8
struct repository;
9
struct bitmapped_pack;
10
11
+#define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */
12
+#define MIDX_VERSION 1
13
+#define MIDX_BYTE_FILE_VERSION 4
14
+#define MIDX_BYTE_HASH_VERSION 5
15
+#define MIDX_BYTE_NUM_CHUNKS 6
16
+#define MIDX_BYTE_NUM_PACKS 8
17
+#define MIDX_HEADER_SIZE 12
18
+
19
+#define MIDX_CHUNK_ALIGNMENT 4
20
+#define MIDX_CHUNKID_PACKNAMES 0x504e414d /* "PNAM" */
21
+#define MIDX_CHUNKID_BITMAPPEDPACKS 0x42544d50 /* "BTMP" */
22
+#define MIDX_CHUNKID_OIDFANOUT 0x4f494446 /* "OIDF" */
23
+#define MIDX_CHUNKID_OIDLOOKUP 0x4f49444c /* "OIDL" */
24
+#define MIDX_CHUNKID_OBJECTOFFSETS 0x4f4f4646 /* "OOFF" */
25
+#define MIDX_CHUNKID_LARGEOFFSETS 0x4c4f4646 /* "LOFF" */
26
+#define MIDX_CHUNKID_REVINDEX 0x52494458 /* "RIDX" */
27
+#define MIDX_CHUNK_OFFSET_WIDTH (2 * sizeof(uint32_t))
28
+#define MIDX_LARGE_OFFSET_NEEDED 0x80000000
29
+
30
#define GIT_TEST_MULTI_PACK_INDEX "GIT_TEST_MULTI_PACK_INDEX"
31
#define GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP \
32
"GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP"