|
@@ -1,6 +1,7 @@
|
|
|
package plumbing
|
|
|
|
|
|
import (
|
|
|
+ "fmt"
|
|
|
"path/filepath"
|
|
|
"sort"
|
|
|
"strings"
|
|
@@ -28,6 +29,9 @@ type RenameAnalysis struct {
|
|
|
// set it to the default value of 80 (80%).
|
|
|
SimilarityThreshold int
|
|
|
|
|
|
+ // Timeout is the maximum time allowed to spend computing renames in a single commit.
|
|
|
+ Timeout time.Duration
|
|
|
+
|
|
|
repository *git.Repository
|
|
|
|
|
|
l core.Logger
|
|
@@ -39,10 +43,18 @@ const (
|
|
|
// CGit's default is 50%. Ours is 80% because 50% can be too computationally expensive.
|
|
|
RenameAnalysisDefaultThreshold = 80
|
|
|
|
|
|
+ // RenameAnalysisDefaultTimeout is the default value of RenameAnalysis.Timeout (in milliseconds).
|
|
|
+ RenameAnalysisDefaultTimeout = 60000
|
|
|
+
|
|
|
// ConfigRenameAnalysisSimilarityThreshold is the name of the configuration option
|
|
|
// (RenameAnalysis.Configure()) which sets the similarity threshold.
|
|
|
ConfigRenameAnalysisSimilarityThreshold = "RenameAnalysis.SimilarityThreshold"
|
|
|
|
|
|
+ // ConfigRenameAnalysisTimeout is the name of the configuration option
|
|
|
+ // (RenameAnalysis.Configure()) which sets the maximum time allowed to spend
|
|
|
+ // computing renames in a single commit.
|
|
|
+ ConfigRenameAnalysisTimeout = "RenameAnalysis.Timeout"
|
|
|
+
|
|
|
// RenameAnalysisMinimumSize is the minimum size of a blob to be considered.
|
|
|
RenameAnalysisMinimumSize = 32
|
|
|
|
|
@@ -84,7 +96,13 @@ func (ra *RenameAnalysis) ListConfigurationOptions() []core.ConfigurationOption
|
|
|
Description: "The threshold on the similarity index used to detect renames.",
|
|
|
Flag: "M",
|
|
|
Type: core.IntConfigurationOption,
|
|
|
- Default: RenameAnalysisDefaultThreshold},
|
|
|
+ Default: RenameAnalysisDefaultThreshold}, {
|
|
|
+ Name: ConfigRenameAnalysisTimeout,
|
|
|
+ Description: "The maximum time (milliseconds) allowed to spend computing " +
|
|
|
+ "renames in a single commit. 0 sets the default.",
|
|
|
+ Flag: "renames-timeout",
|
|
|
+ Type: core.IntConfigurationOption,
|
|
|
+ Default: RenameAnalysisDefaultTimeout},
|
|
|
}
|
|
|
return options[:]
|
|
|
}
|
|
@@ -97,6 +115,12 @@ func (ra *RenameAnalysis) Configure(facts map[string]interface{}) error {
|
|
|
if val, exists := facts[ConfigRenameAnalysisSimilarityThreshold].(int); exists {
|
|
|
ra.SimilarityThreshold = val
|
|
|
}
|
|
|
+ if val, exists := facts[ConfigRenameAnalysisTimeout].(int); exists {
|
|
|
+ if val < 0 {
|
|
|
+ return fmt.Errorf("negative renames detection timeout is not allowed: %d", val)
|
|
|
+ }
|
|
|
+ ra.Timeout = time.Duration(val) * time.Millisecond
|
|
|
+ }
|
|
|
return nil
|
|
|
}
|
|
|
|
|
@@ -109,6 +133,9 @@ func (ra *RenameAnalysis) Initialize(repository *git.Repository) error {
|
|
|
RenameAnalysisDefaultThreshold)
|
|
|
ra.SimilarityThreshold = RenameAnalysisDefaultThreshold
|
|
|
}
|
|
|
+ if ra.Timeout == 0 {
|
|
|
+ ra.Timeout = time.Duration(RenameAnalysisDefaultTimeout) * time.Millisecond
|
|
|
+ }
|
|
|
ra.repository = repository
|
|
|
return nil
|
|
|
}
|
|
@@ -119,6 +146,7 @@ func (ra *RenameAnalysis) Initialize(repository *git.Repository) error {
|
|
|
// This function returns the mapping with analysis results. The keys must be the same as
|
|
|
// in Provides(). If there was an error, nil is returned.
|
|
|
func (ra *RenameAnalysis) Consume(deps map[string]interface{}) (map[string]interface{}, error) {
|
|
|
+ beginTime := time.Now()
|
|
|
changes := deps[DependencyTreeChanges].(object.Changes)
|
|
|
cache := deps[DependencyBlobCache].(map[plumbing.Hash]*CachedBlob)
|
|
|
|
|
@@ -225,7 +253,7 @@ func (ra *RenameAnalysis) Consume(deps map[string]interface{}) (map[string]inter
|
|
|
}()
|
|
|
aStart := 0
|
|
|
// we will try to find a matching added blob for each deleted blob
|
|
|
- for d := 0; d < deletedBlobsA.Len(); d++ {
|
|
|
+ for d := 0; d < deletedBlobsA.Len() && time.Now().Sub(beginTime) < ra.Timeout; d++ {
|
|
|
myBlob := cache[deletedBlobsA[d].change.From.TreeEntry.Hash]
|
|
|
mySize := deletedBlobsA[d].size
|
|
|
myName := filepath.Base(deletedBlobsA[d].change.From.Name)
|
|
@@ -283,7 +311,7 @@ func (ra *RenameAnalysis) Consume(deps map[string]interface{}) (map[string]inter
|
|
|
wg.Done()
|
|
|
}()
|
|
|
dStart := 0
|
|
|
- for a := 0; a < addedBlobsB.Len(); a++ {
|
|
|
+ for a := 0; a < addedBlobsB.Len() && time.Now().Sub(beginTime) < ra.Timeout; a++ {
|
|
|
myBlob := cache[addedBlobsB[a].change.To.TreeEntry.Hash]
|
|
|
mySize := addedBlobsB[a].size
|
|
|
myName := filepath.Base(addedBlobsB[a].change.To.Name)
|