mirror of
https://github.com/ipfs/kubo.git
synced 2025-06-23 13:44:27 +08:00
rewrite of backoff mechanism
License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com>
This commit is contained in:
@ -420,18 +420,18 @@ func TestDialBackoffClears(t *testing.T) {
|
||||
}
|
||||
s1.peers.AddAddrs(s2.local, ifaceAddrs1, peer.PermanentAddrTTL)
|
||||
|
||||
before = time.Now()
|
||||
if _, err := s1.Dial(ctx, s2.local); err == nil {
|
||||
t.Fatal("should have failed to dial backed off peer")
|
||||
}
|
||||
|
||||
time.Sleep(baseBackoffTime)
|
||||
|
||||
if c, err := s1.Dial(ctx, s2.local); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
c.Close()
|
||||
t.Log("correctly connected")
|
||||
}
|
||||
duration = time.Now().Sub(before)
|
||||
|
||||
if duration >= dt {
|
||||
// t.Error("took too long", duration, dt)
|
||||
}
|
||||
|
||||
if s1.backf.Backoff(s2.local) {
|
||||
t.Error("s2 should no longer be on backoff")
|
||||
|
@ -147,44 +147,71 @@ func (ds *dialsync) Unlock(dst peer.ID) {
|
||||
// dialbackoff.Clear(p)
|
||||
// }
|
||||
//
|
||||
|
||||
type dialbackoff struct {
|
||||
entries map[peer.ID]struct{}
|
||||
entries map[peer.ID]*backoffPeer
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
type backoffPeer struct {
|
||||
tries int
|
||||
until time.Time
|
||||
}
|
||||
|
||||
func (db *dialbackoff) init() {
|
||||
if db.entries == nil {
|
||||
db.entries = make(map[peer.ID]struct{})
|
||||
db.entries = make(map[peer.ID]*backoffPeer)
|
||||
}
|
||||
}
|
||||
|
||||
// Backoff returns whether the client should backoff from dialing
|
||||
// peeer p
|
||||
func (db *dialbackoff) Backoff(p peer.ID) bool {
|
||||
// peer p
|
||||
func (db *dialbackoff) Backoff(p peer.ID) (backoff bool) {
|
||||
db.lock.Lock()
|
||||
defer db.lock.Unlock()
|
||||
db.init()
|
||||
_, found := db.entries[p]
|
||||
db.lock.Unlock()
|
||||
return found
|
||||
bp, found := db.entries[p]
|
||||
if found && time.Now().Before(bp.until) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
const baseBackoffTime = time.Second * 5
|
||||
const maxBackoffTime = time.Minute * 5
|
||||
|
||||
// AddBackoff lets other nodes know that we've entered backoff with
|
||||
// peer p, so dialers should not wait unnecessarily. We still will
|
||||
// attempt to dial with one goroutine, in case we get through.
|
||||
func (db *dialbackoff) AddBackoff(p peer.ID) {
|
||||
db.lock.Lock()
|
||||
defer db.lock.Unlock()
|
||||
db.init()
|
||||
db.entries[p] = struct{}{}
|
||||
db.lock.Unlock()
|
||||
bp, ok := db.entries[p]
|
||||
if !ok {
|
||||
db.entries[p] = &backoffPeer{
|
||||
tries: 1,
|
||||
until: time.Now().Add(baseBackoffTime),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
expTimeAdd := time.Second * time.Duration(bp.tries*bp.tries)
|
||||
if expTimeAdd > maxBackoffTime {
|
||||
expTimeAdd = maxBackoffTime
|
||||
}
|
||||
bp.until = time.Now().Add(baseBackoffTime + expTimeAdd)
|
||||
bp.tries++
|
||||
}
|
||||
|
||||
// Clear removes a backoff record. Clients should call this after a
|
||||
// successful Dial.
|
||||
func (db *dialbackoff) Clear(p peer.ID) {
|
||||
db.lock.Lock()
|
||||
defer db.lock.Unlock()
|
||||
db.init()
|
||||
delete(db.entries, p)
|
||||
db.lock.Unlock()
|
||||
}
|
||||
|
||||
// Dial connects to a peer.
|
||||
|
@ -138,5 +138,8 @@ func (s *Swarm) connHandler(c *ps.Conn) *Conn {
|
||||
return nil
|
||||
}
|
||||
|
||||
// if a peer dials us, remove from dial backoff.
|
||||
s.backf.Clear(sc.RemotePeer())
|
||||
|
||||
return sc
|
||||
}
|
||||
|
Reference in New Issue
Block a user