1
1
package plumbing
2
2
3
3
import (
4
+ "fmt"
4
5
"path/filepath"
5
6
"sort"
6
7
"strings"
@@ -28,6 +29,9 @@ type RenameAnalysis struct {
28
29
// set it to the default value of 80 (80%).
29
30
SimilarityThreshold int
30
31
32
+ // Timeout is the maximum time allowed to spend computing renames in a single commit.
33
+ Timeout time.Duration
34
+
31
35
repository * git.Repository
32
36
33
37
l core.Logger
@@ -39,10 +43,18 @@ const (
39
43
// CGit's default is 50%. Ours is 80% because 50% can be too computationally expensive.
40
44
RenameAnalysisDefaultThreshold = 80
41
45
46
+ // RenameAnalysisDefaultTimeout is the default value of RenameAnalysis.Timeout (in milliseconds).
47
+ RenameAnalysisDefaultTimeout = 60000
48
+
42
49
// ConfigRenameAnalysisSimilarityThreshold is the name of the configuration option
43
50
// (RenameAnalysis.Configure()) which sets the similarity threshold.
44
51
ConfigRenameAnalysisSimilarityThreshold = "RenameAnalysis.SimilarityThreshold"
45
52
53
+ // ConfigRenameAnalysisTimeout is the name of the configuration option
54
+ // (RenameAnalysis.Configure()) which sets the maximum time allowed to spend
55
+ // computing renames in a single commit.
56
+ ConfigRenameAnalysisTimeout = "RenameAnalysis.Timeout"
57
+
46
58
// RenameAnalysisMinimumSize is the minimum size of a blob to be considered.
47
59
RenameAnalysisMinimumSize = 32
48
60
@@ -84,7 +96,13 @@ func (ra *RenameAnalysis) ListConfigurationOptions() []core.ConfigurationOption
84
96
Description : "The threshold on the similarity index used to detect renames." ,
85
97
Flag : "M" ,
86
98
Type : core .IntConfigurationOption ,
87
- Default : RenameAnalysisDefaultThreshold },
99
+ Default : RenameAnalysisDefaultThreshold }, {
100
+ Name : ConfigRenameAnalysisTimeout ,
101
+ Description : "The maximum time (milliseconds) allowed to spend computing " +
102
+ "renames in a single commit. 0 sets the default." ,
103
+ Flag : "renames-timeout" ,
104
+ Type : core .IntConfigurationOption ,
105
+ Default : RenameAnalysisDefaultTimeout },
88
106
}
89
107
return options [:]
90
108
}
@@ -97,6 +115,12 @@ func (ra *RenameAnalysis) Configure(facts map[string]interface{}) error {
97
115
if val , exists := facts [ConfigRenameAnalysisSimilarityThreshold ].(int ); exists {
98
116
ra .SimilarityThreshold = val
99
117
}
118
+ if val , exists := facts [ConfigRenameAnalysisTimeout ].(int ); exists {
119
+ if val < 0 {
120
+ return fmt .Errorf ("negative renames detection timeout is not allowed: %d" , val )
121
+ }
122
+ ra .Timeout = time .Duration (val ) * time .Millisecond
123
+ }
100
124
return nil
101
125
}
102
126
@@ -109,6 +133,9 @@ func (ra *RenameAnalysis) Initialize(repository *git.Repository) error {
109
133
RenameAnalysisDefaultThreshold )
110
134
ra .SimilarityThreshold = RenameAnalysisDefaultThreshold
111
135
}
136
+ if ra .Timeout == 0 {
137
+ ra .Timeout = time .Duration (RenameAnalysisDefaultTimeout ) * time .Millisecond
138
+ }
112
139
ra .repository = repository
113
140
return nil
114
141
}
@@ -119,6 +146,7 @@ func (ra *RenameAnalysis) Initialize(repository *git.Repository) error {
119
146
// This function returns the mapping with analysis results. The keys must be the same as
120
147
// in Provides(). If there was an error, nil is returned.
121
148
func (ra * RenameAnalysis ) Consume (deps map [string ]interface {}) (map [string ]interface {}, error ) {
149
+ beginTime := time .Now ()
122
150
changes := deps [DependencyTreeChanges ].(object.Changes )
123
151
cache := deps [DependencyBlobCache ].(map [plumbing.Hash ]* CachedBlob )
124
152
@@ -225,7 +253,7 @@ func (ra *RenameAnalysis) Consume(deps map[string]interface{}) (map[string]inter
225
253
}()
226
254
aStart := 0
227
255
// we will try to find a matching added blob for each deleted blob
228
- for d := 0 ; d < deletedBlobsA .Len (); d ++ {
256
+ for d := 0 ; d < deletedBlobsA .Len () && time . Now (). Sub ( beginTime ) < ra . Timeout ; d ++ {
229
257
myBlob := cache [deletedBlobsA [d ].change .From .TreeEntry .Hash ]
230
258
mySize := deletedBlobsA [d ].size
231
259
myName := filepath .Base (deletedBlobsA [d ].change .From .Name )
@@ -283,7 +311,7 @@ func (ra *RenameAnalysis) Consume(deps map[string]interface{}) (map[string]inter
283
311
wg .Done ()
284
312
}()
285
313
dStart := 0
286
- for a := 0 ; a < addedBlobsB .Len (); a ++ {
314
+ for a := 0 ; a < addedBlobsB .Len () && time . Now (). Sub ( beginTime ) < ra . Timeout ; a ++ {
287
315
myBlob := cache [addedBlobsB [a ].change .To .TreeEntry .Hash ]
288
316
mySize := addedBlobsB [a ].size
289
317
myName := filepath .Base (addedBlobsB [a ].change .To .Name )
0 commit comments