Skip to content

Commit 13d7b59

Browse files
author
Ferenc Szabo
committed
swarm/network: fix data race in fetcher_test.go
Problem: Let's say TestA() and TestB() was started right after each other. TestA() called `go Fetcher.run(ctx)` (read: searchTimeout), on test completion the context was cancelled, but the test did not wait for goroutine termination. Test(B) started by modifying searchTimeout (write). Solution: Let's just store searchTimeout on the Fetcher struct and change the package var (default) to const (thread-safe). Alternative (almost) solution: The above could have been solved by (little ugly, more complex) waitGroups. However that would have not work for TestFetcherFactory. As fetcherFactory.New()starts a goroutine inside it's body without providing a way for clear termination. (We did not want to modify the interface for this one, as we think the unclean termination does not cause a problem in this case in production.) fixes ethersphere/swarm#1109
1 parent bad8c1e commit 13d7b59

File tree

2 files changed

+16
-17
lines changed

2 files changed

+16
-17
lines changed

swarm/network/fetcher.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,17 @@ import (
2626
"github.com/ethereum/go-ethereum/swarm/storage"
2727
)
2828

29-
var searchTimeout = 1 * time.Second
29+
const (
30+
defaultSearchTimeout = 1 * time.Second
31+
// maximum number of forwarded requests (hops), to make sure requests are not
32+
// forwarded forever in peer loops
33+
maxHopCount uint8 = 20
34+
)
3035

3136
// Time to consider peer to be skipped.
3237
// Also used in stream delivery.
3338
var RequestTimeout = 10 * time.Second
3439

35-
var maxHopCount uint8 = 20 // maximum number of forwarded requests (hops), to make sure requests are not forwarded forever in peer loops
36-
3740
type RequestFunc func(context.Context, *Request) (*enode.ID, chan struct{}, error)
3841

3942
// Fetcher is created when a chunk is not found locally. It starts a request handler loop once and
@@ -47,6 +50,7 @@ type Fetcher struct {
4750
addr storage.Address // the address of the chunk to be fetched
4851
offerC chan *enode.ID // channel of sources (peer node id strings)
4952
requestC chan uint8 // channel for incoming requests (with the hopCount value in it)
53+
searchTimeout time.Duration
5054
skipCheck bool
5155
}
5256

@@ -118,6 +122,7 @@ func NewFetcher(addr storage.Address, rf RequestFunc, skipCheck bool) *Fetcher {
118122
protoRequestFunc: rf,
119123
offerC: make(chan *enode.ID),
120124
requestC: make(chan uint8),
125+
searchTimeout: defaultSearchTimeout,
121126
skipCheck: skipCheck,
122127
}
123128
}
@@ -232,7 +237,7 @@ func (f *Fetcher) run(ctx context.Context, peers *sync.Map) {
232237
// if wait channel is not set, set it to a timer
233238
if requested {
234239
if wait == nil {
235-
wait = time.NewTimer(searchTimeout)
240+
wait = time.NewTimer(f.searchTimeout)
236241
defer wait.Stop()
237242
waitC = wait.C
238243
} else {
@@ -243,8 +248,8 @@ func (f *Fetcher) run(ctx context.Context, peers *sync.Map) {
243248
default:
244249
}
245250
}
246-
// reset the timer to go off after searchTimeout
247-
wait.Reset(searchTimeout)
251+
// reset the timer to go off after defaultSearchTimeout
252+
wait.Reset(f.searchTimeout)
248253
}
249254
}
250255
doRequest = false

swarm/network/fetcher_test.go

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -284,15 +284,11 @@ func TestFetcherRetryOnTimeout(t *testing.T) {
284284
requester := newMockRequester()
285285
addr := make([]byte, 32)
286286
fetcher := NewFetcher(addr, requester.doRequest, true)
287+
// set searchTimeOut to low value so the test is quicker
288+
fetcher.searchTimeout = 250 * time.Millisecond
287289

288290
peersToSkip := &sync.Map{}
289291

290-
// set searchTimeOut to low value so the test is quicker
291-
defer func(t time.Duration) {
292-
searchTimeout = t
293-
}(searchTimeout)
294-
searchTimeout = 250 * time.Millisecond
295-
296292
ctx, cancel := context.WithCancel(context.Background())
297293
defer cancel()
298294

@@ -359,11 +355,9 @@ func TestFetcherRequestQuitRetriesRequest(t *testing.T) {
359355
addr := make([]byte, 32)
360356
fetcher := NewFetcher(addr, requester.doRequest, true)
361357

362-
// make sure searchTimeout is long so it is sure the request is not retried because of timeout
363-
defer func(t time.Duration) {
364-
searchTimeout = t
365-
}(searchTimeout)
366-
searchTimeout = 10 * time.Second
358+
// make sure the searchTimeout is long so it is sure the request is not
359+
// retried because of timeout
360+
fetcher.searchTimeout = 10 * time.Second
367361

368362
peersToSkip := &sync.Map{}
369363

0 commit comments

Comments
 (0)