@@ -92,7 +92,7 @@ static struct progress *progress_state;
92
92
93
93
static struct packed_git * reuse_packfile ;
94
94
static uint32_t reuse_packfile_objects ;
95
- static off_t reuse_packfile_offset ;
95
+ static struct bitmap * reuse_packfile_bitmap ;
96
96
97
97
static int use_bitmap_index_default = 1 ;
98
98
static int use_bitmap_index = -1 ;
@@ -785,57 +785,185 @@ static struct object_entry **compute_write_order(void)
785
785
return wo ;
786
786
}
787
787
788
- static off_t write_reused_pack (struct hashfile * f )
788
+
789
+ /*
790
+ * A reused set of objects. All objects in a chunk have the same
791
+ * relative position in the original packfile and the generated
792
+ * packfile.
793
+ */
794
+
795
+ static struct reused_chunk {
796
+ /* The offset of the first object of this chunk in the original
797
+ * packfile. */
798
+ off_t original ;
799
+ /* The offset of the first object of this chunk in the generated
800
+ * packfile minus "original". */
801
+ off_t difference ;
802
+ } * reused_chunks ;
803
+ static int reused_chunks_nr ;
804
+ static int reused_chunks_alloc ;
805
+
806
+ static void record_reused_object (off_t where , off_t offset )
807
+ {
808
+ if (reused_chunks_nr && reused_chunks [reused_chunks_nr - 1 ].difference == offset )
809
+ return ;
810
+
811
+ ALLOC_GROW (reused_chunks , reused_chunks_nr + 1 ,
812
+ reused_chunks_alloc );
813
+ reused_chunks [reused_chunks_nr ].original = where ;
814
+ reused_chunks [reused_chunks_nr ].difference = offset ;
815
+ reused_chunks_nr ++ ;
816
+ }
817
+
818
+ /*
819
+ * Binary search to find the chunk that "where" is in. Note
820
+ * that we're not looking for an exact match, just the first
821
+ * chunk that contains it (which implicitly ends at the start
822
+ * of the next chunk.
823
+ */
824
+ static off_t find_reused_offset (off_t where )
789
825
{
790
- unsigned char buffer [8192 ];
791
- off_t to_write , total ;
792
- int fd ;
826
+ int lo = 0 , hi = reused_chunks_nr ;
827
+ while (lo < hi ) {
828
+ int mi = lo + ((hi - lo ) / 2 );
829
+ if (where == reused_chunks [mi ].original )
830
+ return reused_chunks [mi ].difference ;
831
+ if (where < reused_chunks [mi ].original )
832
+ hi = mi ;
833
+ else
834
+ lo = mi + 1 ;
835
+ }
793
836
794
- if (!is_pack_valid (reuse_packfile ))
795
- die (_ ("packfile is invalid: %s" ), reuse_packfile -> pack_name );
837
+ /*
838
+ * The first chunk starts at zero, so we can't have gone below
839
+ * there.
840
+ */
841
+ assert (lo );
842
+ return reused_chunks [lo - 1 ].difference ;
843
+ }
796
844
797
- fd = git_open (reuse_packfile -> pack_name );
798
- if (fd < 0 )
799
- die_errno (_ ("unable to open packfile for reuse: %s" ),
800
- reuse_packfile -> pack_name );
845
+ static void write_reused_pack_one (size_t pos , struct hashfile * out ,
846
+ struct pack_window * * w_curs )
847
+ {
848
+ off_t offset , next , cur ;
849
+ enum object_type type ;
850
+ unsigned long size ;
801
851
802
- if ( lseek ( fd , sizeof ( struct pack_header ), SEEK_SET ) == -1 )
803
- die_errno ( _ ( "unable to seek in reused packfile" )) ;
852
+ offset = reuse_packfile -> revindex [ pos ]. offset ;
853
+ next = reuse_packfile -> revindex [ pos + 1 ]. offset ;
804
854
805
- if (reuse_packfile_offset < 0 )
806
- reuse_packfile_offset = reuse_packfile -> pack_size - the_hash_algo -> rawsz ;
855
+ record_reused_object (offset , offset - hashfile_total (out ));
807
856
808
- total = to_write = reuse_packfile_offset - sizeof (struct pack_header );
857
+ cur = offset ;
858
+ type = unpack_object_header (reuse_packfile , w_curs , & cur , & size );
859
+ assert (type >= 0 );
809
860
810
- while (to_write ) {
811
- int read_pack = xread (fd , buffer , sizeof (buffer ));
861
+ if (type == OBJ_OFS_DELTA ) {
862
+ off_t base_offset ;
863
+ off_t fixup ;
864
+
865
+ unsigned char header [MAX_PACK_OBJECT_HEADER ];
866
+ unsigned len ;
867
+
868
+ base_offset = get_delta_base (reuse_packfile , w_curs , & cur , type , offset );
869
+ assert (base_offset != 0 );
870
+
871
+ /* Convert to REF_DELTA if we must... */
872
+ if (!allow_ofs_delta ) {
873
+ int base_pos = find_revindex_position (reuse_packfile , base_offset );
874
+ const unsigned char * base_sha1 =
875
+ nth_packed_object_sha1 (reuse_packfile ,
876
+ reuse_packfile -> revindex [base_pos ].nr );
877
+
878
+ len = encode_in_pack_object_header (header , sizeof (header ),
879
+ OBJ_REF_DELTA , size );
880
+ hashwrite (out , header , len );
881
+ hashwrite (out , base_sha1 , 20 );
882
+ copy_pack_data (out , reuse_packfile , w_curs , cur , next - cur );
883
+ return ;
884
+ }
812
885
813
- if (read_pack <= 0 )
814
- die_errno (_ ("unable to read from reused packfile" ));
886
+ /* Otherwise see if we need to rewrite the offset... */
887
+ fixup = find_reused_offset (offset ) -
888
+ find_reused_offset (base_offset );
889
+ if (fixup ) {
890
+ unsigned char ofs_header [10 ];
891
+ unsigned i , ofs_len ;
892
+ off_t ofs = offset - base_offset - fixup ;
815
893
816
- if ( read_pack > to_write )
817
- read_pack = to_write ;
894
+ len = encode_in_pack_object_header ( header , sizeof ( header ),
895
+ OBJ_OFS_DELTA , size ) ;
818
896
819
- hashwrite (f , buffer , read_pack );
820
- to_write -= read_pack ;
897
+ i = sizeof (ofs_header ) - 1 ;
898
+ ofs_header [i ] = ofs & 127 ;
899
+ while (ofs >>= 7 )
900
+ ofs_header [-- i ] = 128 | (-- ofs & 127 );
901
+
902
+ ofs_len = sizeof (ofs_header ) - i ;
903
+
904
+ hashwrite (out , header , len );
905
+ hashwrite (out , ofs_header + sizeof (ofs_header ) - ofs_len , ofs_len );
906
+ copy_pack_data (out , reuse_packfile , w_curs , cur , next - cur );
907
+ return ;
908
+ }
909
+
910
+ /* ...otherwise we have no fixup, and can write it verbatim */
911
+ }
912
+
913
+ copy_pack_data (out , reuse_packfile , w_curs , offset , next - offset );
914
+ }
915
+
916
+ static size_t write_reused_pack_verbatim (struct hashfile * out ,
917
+ struct pack_window * * w_curs )
918
+ {
919
+ size_t pos = 0 ;
920
+
921
+ while (pos < reuse_packfile_bitmap -> word_alloc &&
922
+ reuse_packfile_bitmap -> words [pos ] == (eword_t )~0 )
923
+ pos ++ ;
924
+
925
+ if (pos ) {
926
+ off_t to_write ;
927
+
928
+ written = (pos * BITS_IN_EWORD );
929
+ to_write = reuse_packfile -> revindex [written ].offset
930
+ - sizeof (struct pack_header );
931
+
932
+ /* We're recording one chunk, not one object. */
933
+ record_reused_object (sizeof (struct pack_header ), 0 );
934
+ hashflush (out );
935
+ copy_pack_data (out , reuse_packfile , w_curs ,
936
+ sizeof (struct pack_header ), to_write );
821
937
822
- /*
823
- * We don't know the actual number of objects written,
824
- * only how many bytes written, how many bytes total, and
825
- * how many objects total. So we can fake it by pretending all
826
- * objects we are writing are the same size. This gives us a
827
- * smooth progress meter, and at the end it matches the true
828
- * answer.
829
- */
830
- written = reuse_packfile_objects *
831
- (((double )(total - to_write )) / total );
832
938
display_progress (progress_state , written );
833
939
}
940
+ return pos ;
941
+ }
942
+
943
+ static void write_reused_pack (struct hashfile * f )
944
+ {
945
+ size_t i = 0 ;
946
+ uint32_t offset ;
947
+ struct pack_window * w_curs = NULL ;
948
+
949
+ if (allow_ofs_delta )
950
+ i = write_reused_pack_verbatim (f , & w_curs );
951
+
952
+ for (; i < reuse_packfile_bitmap -> word_alloc ; ++ i ) {
953
+ eword_t word = reuse_packfile_bitmap -> words [i ];
954
+ size_t pos = (i * BITS_IN_EWORD );
955
+
956
+ for (offset = 0 ; offset < BITS_IN_EWORD ; ++ offset ) {
957
+ if ((word >> offset ) == 0 )
958
+ break ;
959
+
960
+ offset += ewah_bit_ctz64 (word >> offset );
961
+ write_reused_pack_one (pos + offset , f , & w_curs );
962
+ display_progress (progress_state , ++ written );
963
+ }
964
+ }
834
965
835
- close (fd );
836
- written = reuse_packfile_objects ;
837
- display_progress (progress_state , written );
838
- return reuse_packfile_offset - sizeof (struct pack_header );
966
+ unuse_pack (& w_curs );
839
967
}
840
968
841
969
static const char no_split_warning [] = N_ (
@@ -868,11 +996,9 @@ static void write_pack_file(void)
868
996
offset = write_pack_header (f , nr_remaining );
869
997
870
998
if (reuse_packfile ) {
871
- off_t packfile_size ;
872
999
assert (pack_to_stdout );
873
-
874
- packfile_size = write_reused_pack (f );
875
- offset += packfile_size ;
1000
+ write_reused_pack (f );
1001
+ offset = hashfile_total (f );
876
1002
}
877
1003
878
1004
nr_written = 0 ;
@@ -2677,6 +2803,7 @@ static void prepare_pack(int window, int depth)
2677
2803
2678
2804
if (nr_deltas && n > 1 ) {
2679
2805
unsigned nr_done = 0 ;
2806
+
2680
2807
if (progress )
2681
2808
progress_state = start_progress (_ ("Compressing objects" ),
2682
2809
nr_deltas );
@@ -3062,7 +3189,6 @@ static int pack_options_allow_reuse(void)
3062
3189
{
3063
3190
return allow_pack_reuse &&
3064
3191
pack_to_stdout &&
3065
- allow_ofs_delta &&
3066
3192
!ignore_packed_keep_on_disk &&
3067
3193
!ignore_packed_keep_in_core &&
3068
3194
(!local || !have_non_local_packs ) &&
@@ -3079,7 +3205,7 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
3079
3205
bitmap_git ,
3080
3206
& reuse_packfile ,
3081
3207
& reuse_packfile_objects ,
3082
- & reuse_packfile_offset )) {
3208
+ & reuse_packfile_bitmap )) {
3083
3209
assert (reuse_packfile_objects );
3084
3210
nr_result += reuse_packfile_objects ;
3085
3211
display_progress (progress_state , nr_result );
0 commit comments