forked from libp2p/go-libp2p-pubsub
/
backoff.go
71 lines (59 loc) · 1.35 KB
/
backoff.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package pubsub
import (
"sync"
"time"
"github.com/libp2p/go-libp2p-core/peer"
)
const (
MinBackoffDelay = 100 * time.Millisecond
MaxBackoffDelay = 10 * time.Second
TimeToLive = 10 * time.Minute
BackoffMultiplier = 2
)
type backoffHistory struct {
duration time.Duration
lastTried time.Time
}
type backoff struct {
mu sync.Mutex
info map[peer.ID]*backoffHistory
ct int // size threshold that kicks off the cleaner
}
func newBackoff(sizeThreshold int) *backoff {
return &backoff{
mu: sync.Mutex{},
ct: sizeThreshold,
info: make(map[peer.ID]*backoffHistory),
}
}
func (b *backoff) updateAndGet(id peer.ID) time.Duration {
b.mu.Lock()
defer b.mu.Unlock()
h, ok := b.info[id]
if !ok || time.Since(h.lastTried) > TimeToLive {
// first request goes immediately.
h = &backoffHistory{
duration: time.Duration(0),
}
} else if h.duration < MinBackoffDelay {
h.duration = MinBackoffDelay
} else if h.duration < MaxBackoffDelay {
h.duration = time.Duration(BackoffMultiplier * h.duration)
if h.duration > MaxBackoffDelay || h.duration < 0 {
h.duration = MaxBackoffDelay
}
}
h.lastTried = time.Now()
b.info[id] = h
if len(b.info) > b.ct {
b.cleanup()
}
return h.duration
}
func (b *backoff) cleanup() {
for id, h := range b.info {
if time.Since(h.lastTried) > TimeToLive {
delete(b.info, id)
}
}
}