Skip to content

Commit 6959c0d

Browse files
authored
Merge pull request #343 from vmarkovtsev/master
Add --renames-timeout
2 parents 9c2eaa7 + 1b86739 commit 6959c0d

File tree

3 files changed

+45
-5
lines changed

3 files changed

+45
-5
lines changed

internal/plumbing/renames.go

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package plumbing
22

33
import (
4+
"fmt"
45
"path/filepath"
56
"sort"
67
"strings"
@@ -28,6 +29,9 @@ type RenameAnalysis struct {
2829
// set it to the default value of 80 (80%).
2930
SimilarityThreshold int
3031

32+
// Timeout is the maximum time allowed to spend computing renames in a single commit.
33+
Timeout time.Duration
34+
3135
repository *git.Repository
3236

3337
l core.Logger
@@ -39,10 +43,18 @@ const (
3943
// CGit's default is 50%. Ours is 80% because 50% can be too computationally expensive.
4044
RenameAnalysisDefaultThreshold = 80
4145

46+
// RenameAnalysisDefaultTimeout is the default value of RenameAnalysis.Timeout (in milliseconds).
47+
RenameAnalysisDefaultTimeout = 60000
48+
4249
// ConfigRenameAnalysisSimilarityThreshold is the name of the configuration option
4350
// (RenameAnalysis.Configure()) which sets the similarity threshold.
4451
ConfigRenameAnalysisSimilarityThreshold = "RenameAnalysis.SimilarityThreshold"
4552

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+
4658
// RenameAnalysisMinimumSize is the minimum size of a blob to be considered.
4759
RenameAnalysisMinimumSize = 32
4860

@@ -84,7 +96,13 @@ func (ra *RenameAnalysis) ListConfigurationOptions() []core.ConfigurationOption
8496
Description: "The threshold on the similarity index used to detect renames.",
8597
Flag: "M",
8698
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},
88106
}
89107
return options[:]
90108
}
@@ -97,6 +115,12 @@ func (ra *RenameAnalysis) Configure(facts map[string]interface{}) error {
97115
if val, exists := facts[ConfigRenameAnalysisSimilarityThreshold].(int); exists {
98116
ra.SimilarityThreshold = val
99117
}
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+
}
100124
return nil
101125
}
102126

@@ -109,6 +133,9 @@ func (ra *RenameAnalysis) Initialize(repository *git.Repository) error {
109133
RenameAnalysisDefaultThreshold)
110134
ra.SimilarityThreshold = RenameAnalysisDefaultThreshold
111135
}
136+
if ra.Timeout == 0 {
137+
ra.Timeout = time.Duration(RenameAnalysisDefaultTimeout) * time.Millisecond
138+
}
112139
ra.repository = repository
113140
return nil
114141
}
@@ -119,6 +146,7 @@ func (ra *RenameAnalysis) Initialize(repository *git.Repository) error {
119146
// This function returns the mapping with analysis results. The keys must be the same as
120147
// in Provides(). If there was an error, nil is returned.
121148
func (ra *RenameAnalysis) Consume(deps map[string]interface{}) (map[string]interface{}, error) {
149+
beginTime := time.Now()
122150
changes := deps[DependencyTreeChanges].(object.Changes)
123151
cache := deps[DependencyBlobCache].(map[plumbing.Hash]*CachedBlob)
124152

@@ -225,7 +253,7 @@ func (ra *RenameAnalysis) Consume(deps map[string]interface{}) (map[string]inter
225253
}()
226254
aStart := 0
227255
// 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++ {
229257
myBlob := cache[deletedBlobsA[d].change.From.TreeEntry.Hash]
230258
mySize := deletedBlobsA[d].size
231259
myName := filepath.Base(deletedBlobsA[d].change.From.Name)
@@ -283,7 +311,7 @@ func (ra *RenameAnalysis) Consume(deps map[string]interface{}) (map[string]inter
283311
wg.Done()
284312
}()
285313
dStart := 0
286-
for a := 0; a < addedBlobsB.Len(); a++ {
314+
for a := 0; a < addedBlobsB.Len() && time.Now().Sub(beginTime) < ra.Timeout; a++ {
287315
myBlob := cache[addedBlobsB[a].change.To.TreeEntry.Hash]
288316
mySize := addedBlobsB[a].size
289317
myName := filepath.Base(addedBlobsB[a].change.To.Name)

internal/plumbing/renames_test.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"path"
99
"sync"
1010
"testing"
11+
"time"
1112

1213
"github.com/stretchr/testify/assert"
1314
"gopkg.in/src-d/go-git.v4/plumbing"
@@ -31,21 +32,25 @@ func TestRenameAnalysisMeta(t *testing.T) {
3132
assert.Equal(t, ra.Requires()[0], DependencyBlobCache)
3233
assert.Equal(t, ra.Requires()[1], DependencyTreeChanges)
3334
opts := ra.ListConfigurationOptions()
34-
assert.Len(t, opts, 1)
35+
assert.Len(t, opts, 2)
3536
assert.Equal(t, opts[0].Name, ConfigRenameAnalysisSimilarityThreshold)
37+
assert.Equal(t, opts[1].Name, ConfigRenameAnalysisTimeout)
3638
ra.SimilarityThreshold = 0
3739

3840
assert.NoError(t, ra.Configure(map[string]interface{}{
3941
ConfigRenameAnalysisSimilarityThreshold: 70,
42+
ConfigRenameAnalysisTimeout: 1000,
4043
}))
4144
assert.Equal(t, ra.SimilarityThreshold, 70)
45+
assert.Equal(t, ra.Timeout, time.Second)
4246

4347
logger := core.NewLogger()
4448
assert.NoError(t, ra.Configure(map[string]interface{}{
4549
core.ConfigLogger: logger,
4650
}))
4751
assert.Equal(t, logger, ra.l)
4852
assert.Equal(t, ra.SimilarityThreshold, 70)
53+
assert.Equal(t, ra.Timeout, time.Second)
4954
}
5055

5156
func TestRenameAnalysisRegistration(t *testing.T) {
@@ -138,6 +143,13 @@ func TestRenameAnalysisConsume(t *testing.T) {
138143
assert.Nil(t, err)
139144
renamed = res[DependencyTreeChanges].(object.Changes)
140145
assert.Equal(t, len(renamed), 3)
146+
147+
ra.SimilarityThreshold = 37
148+
ra.Timeout = time.Microsecond
149+
res, err = ra.Consume(deps)
150+
assert.Nil(t, err)
151+
renamed = res[DependencyTreeChanges].(object.Changes)
152+
assert.Equal(t, len(renamed), 3)
141153
}
142154

143155
func TestSortableChanges(t *testing.T) {

python/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
description="Python companion for github.com/src-d/hercules to visualize the results.",
2323
long_description=long_description,
2424
long_description_content_type="text/markdown",
25-
version="10.7.1",
25+
version="10.7.2",
2626
license="Apache-2.0",
2727
author="source{d}",
2828
author_email="[email protected]",

0 commit comments

Comments
 (0)