@@ -87,13 +87,13 @@ struct diff_score {
87
87
short name_score ;
88
88
};
89
89
90
- struct prefetch_options {
90
+ struct inexact_prefetch_options {
91
91
struct repository * repo ;
92
92
int skip_unmodified ;
93
93
};
94
- static void prefetch (void * prefetch_options )
94
+ static void inexact_prefetch (void * prefetch_options )
95
95
{
96
- struct prefetch_options * options = prefetch_options ;
96
+ struct inexact_prefetch_options * options = prefetch_options ;
97
97
int i ;
98
98
struct oid_array to_fetch = OID_ARRAY_INIT ;
99
99
@@ -126,7 +126,7 @@ static int estimate_similarity(struct repository *r,
126
126
struct diff_filespec * src ,
127
127
struct diff_filespec * dst ,
128
128
int minimum_score ,
129
- int skip_unmodified )
129
+ struct diff_populate_filespec_options * dpf_opt )
130
130
{
131
131
/* src points at a file that existed in the original tree (or
132
132
* optionally a file in the destination tree) and dst points
@@ -143,15 +143,6 @@ static int estimate_similarity(struct repository *r,
143
143
*/
144
144
unsigned long max_size , delta_size , base_size , src_copied , literal_added ;
145
145
int score ;
146
- struct diff_populate_filespec_options dpf_options = {
147
- .check_size_only = 1
148
- };
149
- struct prefetch_options prefetch_options = {r , skip_unmodified };
150
-
151
- if (r == the_repository && has_promisor_remote ()) {
152
- dpf_options .missing_object_cb = prefetch ;
153
- dpf_options .missing_object_data = & prefetch_options ;
154
- }
155
146
156
147
/* We deal only with regular files. Symlink renames are handled
157
148
* only when they are exact matches --- in other words, no edits
@@ -169,11 +160,13 @@ static int estimate_similarity(struct repository *r,
169
160
* is a possible size - we really should have a flag to
170
161
* say whether the size is valid or not!)
171
162
*/
163
+ dpf_opt -> check_size_only = 1 ;
164
+
172
165
if (!src -> cnt_data &&
173
- diff_populate_filespec (r , src , & dpf_options ))
166
+ diff_populate_filespec (r , src , dpf_opt ))
174
167
return 0 ;
175
168
if (!dst -> cnt_data &&
176
- diff_populate_filespec (r , dst , & dpf_options ))
169
+ diff_populate_filespec (r , dst , dpf_opt ))
177
170
return 0 ;
178
171
179
172
max_size = ((src -> size > dst -> size ) ? src -> size : dst -> size );
@@ -191,11 +184,11 @@ static int estimate_similarity(struct repository *r,
191
184
if (max_size * (MAX_SCORE - minimum_score ) < delta_size * MAX_SCORE )
192
185
return 0 ;
193
186
194
- dpf_options . check_size_only = 0 ;
187
+ dpf_opt -> check_size_only = 0 ;
195
188
196
- if (!src -> cnt_data && diff_populate_filespec (r , src , & dpf_options ))
189
+ if (!src -> cnt_data && diff_populate_filespec (r , src , dpf_opt ))
197
190
return 0 ;
198
- if (!dst -> cnt_data && diff_populate_filespec (r , dst , & dpf_options ))
191
+ if (!dst -> cnt_data && diff_populate_filespec (r , dst , dpf_opt ))
199
192
return 0 ;
200
193
201
194
if (diffcore_count_changes (r , src , dst ,
@@ -823,6 +816,78 @@ static int idx_possible_rename(char *filename, struct dir_rename_info *info)
823
816
return idx ;
824
817
}
825
818
819
+ struct basename_prefetch_options {
820
+ struct repository * repo ;
821
+ struct strintmap * relevant_sources ;
822
+ struct strintmap * sources ;
823
+ struct strintmap * dests ;
824
+ struct dir_rename_info * info ;
825
+ };
826
+ static void basename_prefetch (void * prefetch_options )
827
+ {
828
+ struct basename_prefetch_options * options = prefetch_options ;
829
+ struct strintmap * relevant_sources = options -> relevant_sources ;
830
+ struct strintmap * sources = options -> sources ;
831
+ struct strintmap * dests = options -> dests ;
832
+ struct dir_rename_info * info = options -> info ;
833
+ int i ;
834
+ struct oid_array to_fetch = OID_ARRAY_INIT ;
835
+
836
+ /*
837
+ * TODO: The following loops mirror the code/logic from
838
+ * find_basename_matches(), though not quite exactly. Maybe
839
+ * abstract the iteration logic out somehow?
840
+ */
841
+ for (i = 0 ; i < rename_src_nr ; ++ i ) {
842
+ char * filename = rename_src [i ].p -> one -> path ;
843
+ const char * base = NULL ;
844
+ intptr_t src_index ;
845
+ intptr_t dst_index ;
846
+
847
+ /* Skip irrelevant sources */
848
+ if (relevant_sources &&
849
+ !strintmap_contains (relevant_sources , filename ))
850
+ continue ;
851
+
852
+ /*
853
+ * If the basename is unique among remaining sources, then
854
+ * src_index will equal 'i' and we can attempt to match it
855
+ * to a unique basename in the destinations. Otherwise,
856
+ * use directory rename heuristics, if possible.
857
+ */
858
+ base = get_basename (filename );
859
+ src_index = strintmap_get (sources , base );
860
+ assert (src_index == -1 || src_index == i );
861
+
862
+ if (strintmap_contains (dests , base )) {
863
+ struct diff_filespec * one , * two ;
864
+
865
+ /* Find a matching destination, if possible */
866
+ dst_index = strintmap_get (dests , base );
867
+ if (src_index == -1 || dst_index == -1 ) {
868
+ src_index = i ;
869
+ dst_index = idx_possible_rename (filename , info );
870
+ }
871
+ if (dst_index == -1 )
872
+ continue ;
873
+
874
+ /* Ignore this dest if already used in a rename */
875
+ if (rename_dst [dst_index ].is_rename )
876
+ continue ; /* already used previously */
877
+
878
+ one = rename_src [src_index ].p -> one ;
879
+ two = rename_dst [dst_index ].p -> two ;
880
+
881
+ /* Add the pairs */
882
+ diff_add_if_missing (options -> repo , & to_fetch , two );
883
+ diff_add_if_missing (options -> repo , & to_fetch , one );
884
+ }
885
+ }
886
+
887
+ promisor_remote_get_direct (options -> repo , to_fetch .oid , to_fetch .nr );
888
+ oid_array_clear (& to_fetch );
889
+ }
890
+
826
891
static int find_basename_matches (struct diff_options * options ,
827
892
int minimum_score ,
828
893
struct dir_rename_info * info ,
@@ -862,18 +927,18 @@ static int find_basename_matches(struct diff_options *options,
862
927
int i , renames = 0 ;
863
928
struct strintmap sources ;
864
929
struct strintmap dests ;
865
-
866
- /*
867
- * The prefeteching stuff wants to know if it can skip prefetching
868
- * blobs that are unmodified...and will then do a little extra work
869
- * to verify that the oids are indeed different before prefetching.
870
- * Unmodified blobs are only relevant when doing copy detection;
871
- * when limiting to rename detection, diffcore_rename[_extended]()
872
- * will never be called with unmodified source paths fed to us, so
873
- * the extra work necessary to check if rename_src entries are
874
- * unmodified would be a small waste.
875
- */
876
- int skip_unmodified = 0 ;
930
+ struct diff_populate_filespec_options dpf_options = {
931
+ . check_binary = 0 ,
932
+ . missing_object_cb = NULL ,
933
+ . missing_object_data = NULL
934
+ };
935
+ struct basename_prefetch_options prefetch_options = {
936
+ . repo = options -> repo ,
937
+ . relevant_sources = relevant_sources ,
938
+ . sources = & sources ,
939
+ . dests = & dests ,
940
+ . info = info
941
+ } ;
877
942
878
943
/*
879
944
* Create maps of basename -> fullname(s) for remaining sources and
@@ -910,6 +975,11 @@ static int find_basename_matches(struct diff_options *options,
910
975
strintmap_set (& dests , base , i );
911
976
}
912
977
978
+ if (options -> repo == the_repository && has_promisor_remote ()) {
979
+ dpf_options .missing_object_cb = basename_prefetch ;
980
+ dpf_options .missing_object_data = & prefetch_options ;
981
+ }
982
+
913
983
/* Now look for basename matchups and do similarity estimation */
914
984
for (i = 0 ; i < rename_src_nr ; ++ i ) {
915
985
char * filename = rename_src [i ].p -> one -> path ;
@@ -953,7 +1023,7 @@ static int find_basename_matches(struct diff_options *options,
953
1023
one = rename_src [src_index ].p -> one ;
954
1024
two = rename_dst [dst_index ].p -> two ;
955
1025
score = estimate_similarity (options -> repo , one , two ,
956
- minimum_score , skip_unmodified );
1026
+ minimum_score , & dpf_options );
957
1027
958
1028
/* If sufficiently similar, record as rename pair */
959
1029
if (score < minimum_score )
@@ -1272,6 +1342,14 @@ void diffcore_rename_extended(struct diff_options *options,
1272
1342
int num_sources , want_copies ;
1273
1343
struct progress * progress = NULL ;
1274
1344
struct dir_rename_info info ;
1345
+ struct diff_populate_filespec_options dpf_options = {
1346
+ .check_binary = 0 ,
1347
+ .missing_object_cb = NULL ,
1348
+ .missing_object_data = NULL
1349
+ };
1350
+ struct inexact_prefetch_options prefetch_options = {
1351
+ .repo = options -> repo
1352
+ };
1275
1353
1276
1354
trace2_region_enter ("diff" , "setup" , options -> repo );
1277
1355
info .setup = 0 ;
@@ -1433,6 +1511,13 @@ void diffcore_rename_extended(struct diff_options *options,
1433
1511
(uint64_t )num_destinations * (uint64_t )num_sources );
1434
1512
}
1435
1513
1514
+ /* Finish setting up dpf_options */
1515
+ prefetch_options .skip_unmodified = skip_unmodified ;
1516
+ if (options -> repo == the_repository && has_promisor_remote ()) {
1517
+ dpf_options .missing_object_cb = inexact_prefetch ;
1518
+ dpf_options .missing_object_data = & prefetch_options ;
1519
+ }
1520
+
1436
1521
CALLOC_ARRAY (mx , st_mult (NUM_CANDIDATE_PER_DST , num_destinations ));
1437
1522
for (dst_cnt = i = 0 ; i < rename_dst_nr ; i ++ ) {
1438
1523
struct diff_filespec * two = rename_dst [i ].p -> two ;
@@ -1458,7 +1543,7 @@ void diffcore_rename_extended(struct diff_options *options,
1458
1543
this_src .score = estimate_similarity (options -> repo ,
1459
1544
one , two ,
1460
1545
minimum_score ,
1461
- skip_unmodified );
1546
+ & dpf_options );
1462
1547
this_src .name_score = basename_same (one , two );
1463
1548
this_src .dst = i ;
1464
1549
this_src .src = j ;
0 commit comments