18
18
#define MIDX_HASH_LEN 20
19
19
#define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + MIDX_HASH_LEN)
20
20
21
- #define MIDX_MAX_CHUNKS 3
21
+ #define MIDX_MAX_CHUNKS 5
22
22
#define MIDX_CHUNK_ALIGNMENT 4
23
23
#define MIDX_CHUNKID_PACKNAMES 0x504e414d /* "PNAM" */
24
24
#define MIDX_CHUNKID_OIDFANOUT 0x4f494446 /* "OIDF" */
25
25
#define MIDX_CHUNKID_OIDLOOKUP 0x4f49444c /* "OIDL" */
26
+ #define MIDX_CHUNKID_OBJECTOFFSETS 0x4f4f4646 /* "OOFF" */
27
+ #define MIDX_CHUNKID_LARGEOFFSETS 0x4c4f4646 /* "LOFF" */
26
28
#define MIDX_CHUNKLOOKUP_WIDTH (sizeof(uint32_t) + sizeof(uint64_t))
27
29
#define MIDX_CHUNK_FANOUT_SIZE (sizeof(uint32_t) * 256)
30
+ #define MIDX_CHUNK_OFFSET_WIDTH (2 * sizeof(uint32_t))
31
+ #define MIDX_CHUNK_LARGE_OFFSET_WIDTH (sizeof(uint64_t))
32
+ #define MIDX_LARGE_OFFSET_NEEDED 0x80000000
28
33
29
34
static char * get_midx_filename (const char * object_dir )
30
35
{
@@ -112,6 +117,14 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir)
112
117
m -> chunk_oid_lookup = m -> data + chunk_offset ;
113
118
break ;
114
119
120
+ case MIDX_CHUNKID_OBJECTOFFSETS :
121
+ m -> chunk_object_offsets = m -> data + chunk_offset ;
122
+ break ;
123
+
124
+ case MIDX_CHUNKID_LARGEOFFSETS :
125
+ m -> chunk_large_offsets = m -> data + chunk_offset ;
126
+ break ;
127
+
115
128
case 0 :
116
129
die (_ ("terminating multi-pack-index chunk id appears earlier than expected" ));
117
130
break ;
@@ -131,6 +144,8 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir)
131
144
die (_ ("multi-pack-index missing required OID fanout chunk" ));
132
145
if (!m -> chunk_oid_lookup )
133
146
die (_ ("multi-pack-index missing required OID lookup chunk" ));
147
+ if (!m -> chunk_object_offsets )
148
+ die (_ ("multi-pack-index missing required object offsets chunk" ));
134
149
135
150
m -> num_objects = ntohl (m -> chunk_oid_fanout [255 ]);
136
151
@@ -454,6 +469,56 @@ static size_t write_midx_oid_lookup(struct hashfile *f, unsigned char hash_len,
454
469
return written ;
455
470
}
456
471
472
+ static size_t write_midx_object_offsets (struct hashfile * f , int large_offset_needed ,
473
+ struct pack_midx_entry * objects , uint32_t nr_objects )
474
+ {
475
+ struct pack_midx_entry * list = objects ;
476
+ uint32_t i , nr_large_offset = 0 ;
477
+ size_t written = 0 ;
478
+
479
+ for (i = 0 ; i < nr_objects ; i ++ ) {
480
+ struct pack_midx_entry * obj = list ++ ;
481
+
482
+ hashwrite_be32 (f , obj -> pack_int_id );
483
+
484
+ if (large_offset_needed && obj -> offset >> 31 )
485
+ hashwrite_be32 (f , MIDX_LARGE_OFFSET_NEEDED | nr_large_offset ++ );
486
+ else if (!large_offset_needed && obj -> offset >> 32 )
487
+ BUG ("object %s requires a large offset (%" PRIx64 ") but the MIDX is not writing large offsets!" ,
488
+ oid_to_hex (& obj -> oid ),
489
+ obj -> offset );
490
+ else
491
+ hashwrite_be32 (f , (uint32_t )obj -> offset );
492
+
493
+ written += MIDX_CHUNK_OFFSET_WIDTH ;
494
+ }
495
+
496
+ return written ;
497
+ }
498
+
499
+ static size_t write_midx_large_offsets (struct hashfile * f , uint32_t nr_large_offset ,
500
+ struct pack_midx_entry * objects , uint32_t nr_objects )
501
+ {
502
+ struct pack_midx_entry * list = objects ;
503
+ size_t written = 0 ;
504
+
505
+ while (nr_large_offset ) {
506
+ struct pack_midx_entry * obj = list ++ ;
507
+ uint64_t offset = obj -> offset ;
508
+
509
+ if (!(offset >> 31 ))
510
+ continue ;
511
+
512
+ hashwrite_be32 (f , offset >> 32 );
513
+ hashwrite_be32 (f , offset & 0xffffffffUL );
514
+ written += 2 * sizeof (uint32_t );
515
+
516
+ nr_large_offset -- ;
517
+ }
518
+
519
+ return written ;
520
+ }
521
+
457
522
int write_midx_file (const char * object_dir )
458
523
{
459
524
unsigned char cur_chunk , num_chunks = 0 ;
@@ -466,8 +531,9 @@ int write_midx_file(const char *object_dir)
466
531
uint64_t written = 0 ;
467
532
uint32_t chunk_ids [MIDX_MAX_CHUNKS + 1 ];
468
533
uint64_t chunk_offsets [MIDX_MAX_CHUNKS + 1 ];
469
- uint32_t nr_entries ;
534
+ uint32_t nr_entries , num_large_offsets = 0 ;
470
535
struct pack_midx_entry * entries = NULL ;
536
+ int large_offsets_needed = 0 ;
471
537
472
538
midx_name = get_midx_filename (object_dir );
473
539
if (safe_create_leading_directories (midx_name )) {
@@ -494,13 +560,19 @@ int write_midx_file(const char *object_dir)
494
560
sort_packs_by_name (packs .names , packs .nr , pack_perm );
495
561
496
562
entries = get_sorted_entries (packs .list , pack_perm , packs .nr , & nr_entries );
563
+ for (i = 0 ; i < nr_entries ; i ++ ) {
564
+ if (entries [i ].offset > 0x7fffffff )
565
+ num_large_offsets ++ ;
566
+ if (entries [i ].offset > 0xffffffff )
567
+ large_offsets_needed = 1 ;
568
+ }
497
569
498
570
hold_lock_file_for_update (& lk , midx_name , LOCK_DIE_ON_ERROR );
499
571
f = hashfd (lk .tempfile -> fd , lk .tempfile -> filename .buf );
500
572
FREE_AND_NULL (midx_name );
501
573
502
574
cur_chunk = 0 ;
503
- num_chunks = 3 ;
575
+ num_chunks = large_offsets_needed ? 5 : 4 ;
504
576
505
577
written = write_midx_header (f , num_chunks , packs .nr );
506
578
@@ -516,9 +588,21 @@ int write_midx_file(const char *object_dir)
516
588
chunk_offsets [cur_chunk ] = chunk_offsets [cur_chunk - 1 ] + MIDX_CHUNK_FANOUT_SIZE ;
517
589
518
590
cur_chunk ++ ;
519
- chunk_ids [cur_chunk ] = 0 ;
591
+ chunk_ids [cur_chunk ] = MIDX_CHUNKID_OBJECTOFFSETS ;
520
592
chunk_offsets [cur_chunk ] = chunk_offsets [cur_chunk - 1 ] + nr_entries * MIDX_HASH_LEN ;
521
593
594
+ cur_chunk ++ ;
595
+ chunk_offsets [cur_chunk ] = chunk_offsets [cur_chunk - 1 ] + nr_entries * MIDX_CHUNK_OFFSET_WIDTH ;
596
+ if (large_offsets_needed ) {
597
+ chunk_ids [cur_chunk ] = MIDX_CHUNKID_LARGEOFFSETS ;
598
+
599
+ cur_chunk ++ ;
600
+ chunk_offsets [cur_chunk ] = chunk_offsets [cur_chunk - 1 ] +
601
+ num_large_offsets * MIDX_CHUNK_LARGE_OFFSET_WIDTH ;
602
+ }
603
+
604
+ chunk_ids [cur_chunk ] = 0 ;
605
+
522
606
for (i = 0 ; i <= num_chunks ; i ++ ) {
523
607
if (i && chunk_offsets [i ] < chunk_offsets [i - 1 ])
524
608
BUG ("incorrect chunk offsets: %" PRIu64 " before %" PRIu64 ,
@@ -556,6 +640,14 @@ int write_midx_file(const char *object_dir)
556
640
written += write_midx_oid_lookup (f , MIDX_HASH_LEN , entries , nr_entries );
557
641
break ;
558
642
643
+ case MIDX_CHUNKID_OBJECTOFFSETS :
644
+ written += write_midx_object_offsets (f , large_offsets_needed , entries , nr_entries );
645
+ break ;
646
+
647
+ case MIDX_CHUNKID_LARGEOFFSETS :
648
+ written += write_midx_large_offsets (f , num_large_offsets , entries , nr_entries );
649
+ break ;
650
+
559
651
default :
560
652
BUG ("trying to write unknown chunk id %" PRIx32 ,
561
653
chunk_ids [i ]);
0 commit comments