@@ -92,10 +92,11 @@ 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 ;
99
+ static int allow_pack_reuse = 1 ;
99
100
static enum {
100
101
WRITE_BITMAP_FALSE = 0 ,
101
102
WRITE_BITMAP_QUIET ,
@@ -784,57 +785,185 @@ static struct object_entry **compute_write_order(void)
784
785
return wo ;
785
786
}
786
787
787
- 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 )
825
+ {
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
+ }
836
+
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
+ }
844
+
845
+ static void write_reused_pack_one (size_t pos , struct hashfile * out ,
846
+ struct pack_window * * w_curs )
788
847
{
789
- unsigned char buffer [ 8192 ] ;
790
- off_t to_write , total ;
791
- int fd ;
848
+ off_t offset , next , cur ;
849
+ enum object_type type ;
850
+ unsigned long size ;
792
851
793
- if (! is_pack_valid ( reuse_packfile ))
794
- die ( _ ( "packfile is invalid: %s" ), reuse_packfile -> pack_name ) ;
852
+ offset = reuse_packfile -> revindex [ pos ]. offset ;
853
+ next = reuse_packfile -> revindex [ pos + 1 ]. offset ;
795
854
796
- fd = git_open (reuse_packfile -> pack_name );
797
- if (fd < 0 )
798
- die_errno (_ ("unable to open packfile for reuse: %s" ),
799
- reuse_packfile -> pack_name );
855
+ record_reused_object (offset , offset - hashfile_total (out ));
800
856
801
- if (lseek (fd , sizeof (struct pack_header ), SEEK_SET ) == -1 )
802
- die_errno (_ ("unable to seek in reused packfile" ));
857
+ cur = offset ;
858
+ type = unpack_object_header (reuse_packfile , w_curs , & cur , & size );
859
+ assert (type >= 0 );
803
860
804
- if (reuse_packfile_offset < 0 )
805
- reuse_packfile_offset = reuse_packfile -> pack_size - the_hash_algo -> rawsz ;
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
+ }
806
885
807
- total = to_write = reuse_packfile_offset - sizeof (struct pack_header );
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 ;
808
893
809
- while ( to_write ) {
810
- int read_pack = xread ( fd , buffer , sizeof ( buffer ) );
894
+ len = encode_in_pack_object_header ( header , sizeof ( header ),
895
+ OBJ_OFS_DELTA , size );
811
896
812
- if (read_pack <= 0 )
813
- die_errno (_ ("unable to read from reused packfile" ));
897
+ i = sizeof (ofs_header ) - 1 ;
898
+ ofs_header [i ] = ofs & 127 ;
899
+ while (ofs >>= 7 )
900
+ ofs_header [-- i ] = 128 | (-- ofs & 127 );
814
901
815
- if (read_pack > to_write )
816
- read_pack = to_write ;
902
+ ofs_len = sizeof (ofs_header ) - i ;
817
903
818
- hashwrite (f , buffer , read_pack );
819
- to_write -= read_pack ;
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 );
820
937
821
- /*
822
- * We don't know the actual number of objects written,
823
- * only how many bytes written, how many bytes total, and
824
- * how many objects total. So we can fake it by pretending all
825
- * objects we are writing are the same size. This gives us a
826
- * smooth progress meter, and at the end it matches the true
827
- * answer.
828
- */
829
- written = reuse_packfile_objects *
830
- (((double )(total - to_write )) / total );
831
938
display_progress (progress_state , written );
832
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 );
833
955
834
- close (fd );
835
- written = reuse_packfile_objects ;
836
- display_progress (progress_state , written );
837
- return reuse_packfile_offset - sizeof (struct pack_header );
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
+ }
965
+
966
+ unuse_pack (& w_curs );
838
967
}
839
968
840
969
static const char no_split_warning [] = N_ (
@@ -867,11 +996,9 @@ static void write_pack_file(void)
867
996
offset = write_pack_header (f , nr_remaining );
868
997
869
998
if (reuse_packfile ) {
870
- off_t packfile_size ;
871
999
assert (pack_to_stdout );
872
-
873
- packfile_size = write_reused_pack (f );
874
- offset += packfile_size ;
1000
+ write_reused_pack (f );
1001
+ offset = hashfile_total (f );
875
1002
}
876
1003
877
1004
nr_written = 0 ;
@@ -1000,6 +1127,10 @@ static int have_duplicate_entry(const struct object_id *oid,
1000
1127
{
1001
1128
struct object_entry * entry ;
1002
1129
1130
+ if (reuse_packfile_bitmap &&
1131
+ bitmap_walk_contains (bitmap_git , reuse_packfile_bitmap , oid ))
1132
+ return 1 ;
1133
+
1003
1134
entry = packlist_find (& to_pack , oid );
1004
1135
if (!entry )
1005
1136
return 0 ;
@@ -2552,6 +2683,13 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
2552
2683
free (p );
2553
2684
}
2554
2685
2686
+ static int obj_is_packed (const struct object_id * oid )
2687
+ {
2688
+ return packlist_find (& to_pack , oid ) ||
2689
+ (reuse_packfile_bitmap &&
2690
+ bitmap_walk_contains (bitmap_git , reuse_packfile_bitmap , oid ));
2691
+ }
2692
+
2555
2693
static void add_tag_chain (const struct object_id * oid )
2556
2694
{
2557
2695
struct tag * tag ;
@@ -2563,7 +2701,7 @@ static void add_tag_chain(const struct object_id *oid)
2563
2701
* it was included via bitmaps, we would not have parsed it
2564
2702
* previously).
2565
2703
*/
2566
- if (packlist_find ( & to_pack , oid ))
2704
+ if (obj_is_packed ( oid ))
2567
2705
return ;
2568
2706
2569
2707
tag = lookup_tag (the_repository , oid );
@@ -2587,7 +2725,7 @@ static int add_ref_tag(const char *path, const struct object_id *oid, int flag,
2587
2725
2588
2726
if (starts_with (path , "refs/tags/" ) && /* is a tag? */
2589
2727
!peel_ref (path , & peeled ) && /* peelable? */
2590
- packlist_find ( & to_pack , & peeled )) /* object packed? */
2728
+ obj_is_packed ( & peeled )) /* object packed? */
2591
2729
add_tag_chain (oid );
2592
2730
return 0 ;
2593
2731
}
@@ -2655,6 +2793,7 @@ static void prepare_pack(int window, int depth)
2655
2793
2656
2794
if (nr_deltas && n > 1 ) {
2657
2795
unsigned nr_done = 0 ;
2796
+
2658
2797
if (progress )
2659
2798
progress_state = start_progress (_ ("Compressing objects" ),
2660
2799
nr_deltas );
@@ -2699,6 +2838,10 @@ static int git_pack_config(const char *k, const char *v, void *cb)
2699
2838
use_bitmap_index_default = git_config_bool (k , v );
2700
2839
return 0 ;
2701
2840
}
2841
+ if (!strcmp (k , "pack.allowpackreuse" )) {
2842
+ allow_pack_reuse = git_config_bool (k , v );
2843
+ return 0 ;
2844
+ }
2702
2845
if (!strcmp (k , "pack.threads" )) {
2703
2846
delta_search_threads = git_config_int (k , v );
2704
2847
if (delta_search_threads < 0 )
@@ -3030,8 +3173,8 @@ static void loosen_unused_packed_objects(void)
3030
3173
*/
3031
3174
static int pack_options_allow_reuse (void )
3032
3175
{
3033
- return pack_to_stdout &&
3034
- allow_ofs_delta &&
3176
+ return allow_pack_reuse &&
3177
+ pack_to_stdout &&
3035
3178
!ignore_packed_keep_on_disk &&
3036
3179
!ignore_packed_keep_in_core &&
3037
3180
(!local || !have_non_local_packs ) &&
@@ -3048,7 +3191,7 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
3048
3191
bitmap_git ,
3049
3192
& reuse_packfile ,
3050
3193
& reuse_packfile_objects ,
3051
- & reuse_packfile_offset )) {
3194
+ & reuse_packfile_bitmap )) {
3052
3195
assert (reuse_packfile_objects );
3053
3196
nr_result += reuse_packfile_objects ;
3054
3197
display_progress (progress_state , nr_result );
@@ -3509,7 +3652,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
3509
3652
if (progress )
3510
3653
fprintf_ln (stderr ,
3511
3654
_ ("Total %" PRIu32 " (delta %" PRIu32 "),"
3512
- " reused %" PRIu32 " (delta %" PRIu32 ")" ),
3513
- written , written_delta , reused , reused_delta );
3655
+ " reused %" PRIu32 " (delta %" PRIu32 "),"
3656
+ " pack-reused %" PRIu32 ),
3657
+ written , written_delta , reused , reused_delta ,
3658
+ reuse_packfile_objects );
3514
3659
return 0 ;
3515
3660
}
0 commit comments