@@ -649,28 +649,98 @@ static const struct object_id *oid_access(size_t pos, const void *table)
649649}
650650
651651static void write_selected_commits_v1 (struct hashfile * f ,
652- struct pack_idx_entry * * index ,
653- uint32_t index_nr )
652+ uint32_t * commit_positions ,
653+ off_t * offsets )
654654{
655655 int i ;
656656
657657 for (i = 0 ; i < writer .selected_nr ; ++ i ) {
658658 struct bitmapped_commit * stored = & writer .selected [i ];
659659
660- int commit_pos =
661- oid_pos ( & stored -> commit -> object . oid , index , index_nr , oid_access );
660+ if ( offsets )
661+ offsets [ i ] = hashfile_total ( f );
662662
663- if (commit_pos < 0 )
664- BUG ("trying to write commit not in index" );
665-
666- hashwrite_be32 (f , commit_pos );
663+ hashwrite_be32 (f , commit_positions [i ]);
667664 hashwrite_u8 (f , stored -> xor_offset );
668665 hashwrite_u8 (f , stored -> flags );
669666
670667 dump_bitmap (f , stored -> write_as );
671668 }
672669}
673670
671+ static int table_cmp (const void * _va , const void * _vb , void * _data )
672+ {
673+ uint32_t * commit_positions = _data ;
674+ uint32_t a = commit_positions [* (uint32_t * )_va ];
675+ uint32_t b = commit_positions [* (uint32_t * )_vb ];
676+
677+ if (a > b )
678+ return 1 ;
679+ else if (a < b )
680+ return -1 ;
681+
682+ return 0 ;
683+ }
684+
685+ static void write_lookup_table (struct hashfile * f ,
686+ uint32_t * commit_positions ,
687+ off_t * offsets )
688+ {
689+ uint32_t i ;
690+ uint32_t * table , * table_inv ;
691+
692+ ALLOC_ARRAY (table , writer .selected_nr );
693+ ALLOC_ARRAY (table_inv , writer .selected_nr );
694+
695+ for (i = 0 ; i < writer .selected_nr ; i ++ )
696+ table [i ] = i ;
697+
698+ /*
699+ * At the end of this sort table[j] = i means that the i'th
700+ * bitmap corresponds to j'th bitmapped commit (among the selected
701+ * commits) in lex order of OIDs.
702+ */
703+ QSORT_S (table , writer .selected_nr , table_cmp , commit_positions );
704+
705+ /* table_inv helps us discover that relationship (i'th bitmap
706+ * to j'th commit by j = table_inv[i])
707+ */
708+ for (i = 0 ; i < writer .selected_nr ; i ++ )
709+ table_inv [table [i ]] = i ;
710+
711+ trace2_region_enter ("pack-bitmap-write" , "writing_lookup_table" , the_repository );
712+ for (i = 0 ; i < writer .selected_nr ; i ++ ) {
713+ struct bitmapped_commit * selected = & writer .selected [table [i ]];
714+ uint32_t xor_offset = selected -> xor_offset ;
715+ uint32_t xor_row ;
716+
717+ if (xor_offset ) {
718+ /*
719+ * xor_index stores the index (in the bitmap entries)
720+ * of the corresponding xor bitmap. But we need to convert
721+ * this index into lookup table's index. So, table_inv[xor_index]
722+ * gives us the index position w.r.t. the lookup table.
723+ *
724+ * If "k = table[i] - xor_offset" then the xor base is the k'th
725+ * bitmap. `table_inv[k]` gives us the position of that bitmap
726+ * in the lookup table.
727+ */
728+ uint32_t xor_index = table [i ] - xor_offset ;
729+ xor_row = table_inv [xor_index ];
730+ } else {
731+ xor_row = 0xffffffff ;
732+ }
733+
734+ hashwrite_be32 (f , commit_positions [table [i ]]);
735+ hashwrite_be64 (f , (uint64_t )offsets [table [i ]]);
736+ hashwrite_be32 (f , xor_row );
737+ }
738+ trace2_region_leave ("pack-bitmap-write" , "writing_lookup_table" , the_repository );
739+
740+ free (table );
741+ free (table_inv );
742+ }
743+
674744static void write_hash_cache (struct hashfile * f ,
675745 struct pack_idx_entry * * index ,
676746 uint32_t index_nr )
@@ -697,6 +767,9 @@ void bitmap_writer_finish(struct pack_idx_entry **index,
697767 static uint16_t flags = BITMAP_OPT_FULL_DAG ;
698768 struct strbuf tmp_file = STRBUF_INIT ;
699769 struct hashfile * f ;
770+ uint32_t * commit_positions = NULL ;
771+ off_t * offsets = NULL ;
772+ uint32_t i ;
700773
701774 struct bitmap_disk_header header ;
702775
@@ -715,7 +788,26 @@ void bitmap_writer_finish(struct pack_idx_entry **index,
715788 dump_bitmap (f , writer .trees );
716789 dump_bitmap (f , writer .blobs );
717790 dump_bitmap (f , writer .tags );
718- write_selected_commits_v1 (f , index , index_nr );
791+
792+ if (options & BITMAP_OPT_LOOKUP_TABLE )
793+ CALLOC_ARRAY (offsets , index_nr );
794+
795+ ALLOC_ARRAY (commit_positions , writer .selected_nr );
796+
797+ for (i = 0 ; i < writer .selected_nr ; i ++ ) {
798+ struct bitmapped_commit * stored = & writer .selected [i ];
799+ int commit_pos = oid_pos (& stored -> commit -> object .oid , index , index_nr , oid_access );
800+
801+ if (commit_pos < 0 )
802+ BUG (_ ("trying to write commit not in index" ));
803+
804+ commit_positions [i ] = commit_pos ;
805+ }
806+
807+ write_selected_commits_v1 (f , commit_positions , offsets );
808+
809+ if (options & BITMAP_OPT_LOOKUP_TABLE )
810+ write_lookup_table (f , commit_positions , offsets );
719811
720812 if (options & BITMAP_OPT_HASH_CACHE )
721813 write_hash_cache (f , index , index_nr );
@@ -730,4 +822,6 @@ void bitmap_writer_finish(struct pack_idx_entry **index,
730822 die_errno ("unable to rename temporary bitmap file to '%s'" , filename );
731823
732824 strbuf_release (& tmp_file );
825+ free (commit_positions );
826+ free (offsets );
733827}
0 commit comments