Commit 988ab6cb authored by Łukasz Magiera's avatar Łukasz Magiera

limiter: cleanup the code

parent c1461238
...@@ -34,12 +34,13 @@ func (dj *dialJob) cancelled() bool { ...@@ -34,12 +34,13 @@ func (dj *dialJob) cancelled() bool {
} }
type dialLimiter struct { type dialLimiter struct {
rllock sync.Mutex lk sync.Mutex
fdConsuming int fdConsuming int
fdLimit int fdLimit int
waitingOnFd []*dialJob waitingOnFd []*dialJob
dialFunc func(context.Context, peer.ID, ma.Multiaddr) (transport.Conn, error) dialFunc dialfunc
activePerPeer map[peer.ID]int activePerPeer map[peer.ID]int
perPeerLimit int perPeerLimit int
...@@ -62,26 +63,26 @@ func newDialLimiterWithParams(df dialfunc, fdLimit, perPeerLimit int) *dialLimit ...@@ -62,26 +63,26 @@ func newDialLimiterWithParams(df dialfunc, fdLimit, perPeerLimit int) *dialLimit
} }
} }
func (dl *dialLimiter) finishedDial(dj *dialJob) { // freeFDToken frees FD token and if there are any schedules another waiting dialJob
dl.rllock.Lock() // in it's place
defer dl.rllock.Unlock() func (dl *dialLimiter) freeFDToken() {
dl.fdConsuming--
if addrutil.IsFDCostlyTransport(dj.addr) {
dl.fdConsuming-- if len(dl.waitingOnFd) > 0 {
next := dl.waitingOnFd[0]
if len(dl.waitingOnFd) > 0 { dl.waitingOnFd[0] = nil // clear out memory
next := dl.waitingOnFd[0] dl.waitingOnFd = dl.waitingOnFd[1:]
dl.waitingOnFd[0] = nil // clear out memory if len(dl.waitingOnFd) == 0 {
dl.waitingOnFd = dl.waitingOnFd[1:] dl.waitingOnFd = nil // clear out memory
if len(dl.waitingOnFd) == 0 {
dl.waitingOnFd = nil // clear out memory
}
dl.fdConsuming++
go dl.executeDial(next)
} }
dl.fdConsuming++
// we already have activePerPeer token at this point so we can just dial
go dl.executeDial(next)
} }
}
func (dl *dialLimiter) freePeerToken(dj *dialJob) {
// release tokens in reverse order than we take them // release tokens in reverse order than we take them
dl.activePerPeer[dj.peer]-- dl.activePerPeer[dj.peer]--
if dl.activePerPeer[dj.peer] == 0 { if dl.activePerPeer[dj.peer] == 0 {
...@@ -91,45 +92,31 @@ func (dl *dialLimiter) finishedDial(dj *dialJob) { ...@@ -91,45 +92,31 @@ func (dl *dialLimiter) finishedDial(dj *dialJob) {
waitlist := dl.waitingOnPeerLimit[dj.peer] waitlist := dl.waitingOnPeerLimit[dj.peer]
if !dj.success && len(waitlist) > 0 { if !dj.success && len(waitlist) > 0 {
next := waitlist[0] next := waitlist[0]
if len(waitlist) == 1 { if len(waitlist) == 1 {
delete(dl.waitingOnPeerLimit, dj.peer) delete(dl.waitingOnPeerLimit, next.peer)
} else { } else {
waitlist[0] = nil // clear out memory waitlist[0] = nil // clear out memory
dl.waitingOnPeerLimit[dj.peer] = waitlist[1:] dl.waitingOnPeerLimit[next.peer] = waitlist[1:]
} }
dl.activePerPeer[dj.peer]++ // just kidding, we still want this token
if addrutil.IsFDCostlyTransport(next.addr) { dl.activePerPeer[next.peer]++ // just kidding, we still want this token
if dl.fdConsuming >= dl.fdLimit {
dl.waitingOnFd = append(dl.waitingOnFd, next)
return
}
// take token
dl.fdConsuming++
}
// can kick this off right here, dials in this list already dl.addCheckFdLimit(next)
// have the other tokens needed
go dl.executeDial(next)
} }
} }
// AddDialJob tries to take the needed tokens for starting the given dial job. func (dl *dialLimiter) finishedDial(dj *dialJob) {
// If it acquires all needed tokens, it immediately starts the dial, otherwise dl.lk.Lock()
// it will put it on the waitlist for the requested token. defer dl.lk.Unlock()
func (dl *dialLimiter) AddDialJob(dj *dialJob) {
dl.rllock.Lock()
defer dl.rllock.Unlock()
if dl.activePerPeer[dj.peer] >= dl.perPeerLimit { if addrutil.IsFDCostlyTransport(dj.addr) {
wlist := dl.waitingOnPeerLimit[dj.peer] dl.freeFDToken()
dl.waitingOnPeerLimit[dj.peer] = append(wlist, dj)
return
} }
dl.activePerPeer[dj.peer]++
dl.freePeerToken(dj)
}
func (dl *dialLimiter) addCheckFdLimit(dj *dialJob) {
if addrutil.IsFDCostlyTransport(dj.addr) { if addrutil.IsFDCostlyTransport(dj.addr) {
if dl.fdConsuming >= dl.fdLimit { if dl.fdConsuming >= dl.fdLimit {
dl.waitingOnFd = append(dl.waitingOnFd, dj) dl.waitingOnFd = append(dl.waitingOnFd, dj)
...@@ -140,15 +127,35 @@ func (dl *dialLimiter) AddDialJob(dj *dialJob) { ...@@ -140,15 +127,35 @@ func (dl *dialLimiter) AddDialJob(dj *dialJob) {
dl.fdConsuming++ dl.fdConsuming++
} }
// take second needed token and start dial!
go dl.executeDial(dj) go dl.executeDial(dj)
} }
func (dl *dialLimiter) addCheckPeerLimit(dj *dialJob) {
if dl.activePerPeer[dj.peer] >= dl.perPeerLimit {
wlist := dl.waitingOnPeerLimit[dj.peer]
dl.waitingOnPeerLimit[dj.peer] = append(wlist, dj)
return
}
dl.activePerPeer[dj.peer]++
dl.addCheckFdLimit(dj)
}
// AddDialJob tries to take the needed tokens for starting the given dial job.
// If it acquires all needed tokens, it immediately starts the dial, otherwise
// it will put it on the waitlist for the requested token.
func (dl *dialLimiter) AddDialJob(dj *dialJob) {
dl.lk.Lock()
defer dl.lk.Unlock()
dl.addCheckPeerLimit(dj)
}
func (dl *dialLimiter) clearAllPeerDials(p peer.ID) { func (dl *dialLimiter) clearAllPeerDials(p peer.ID) {
dl.rllock.Lock() dl.lk.Lock()
defer dl.rllock.Unlock() defer dl.lk.Unlock()
delete(dl.waitingOnPeerLimit, p) delete(dl.waitingOnPeerLimit, p)
// NB: the waitingOnFd list doesnt need to be cleaned out here, we will // NB: the waitingOnFd list doesn't need to be cleaned out here, we will
// remove them as we encounter them because they are 'cancelled' at this // remove them as we encounter them because they are 'cancelled' at this
// point // point
} }
......
...@@ -378,9 +378,9 @@ func TestFDLimitUnderflow(t *testing.T) { ...@@ -378,9 +378,9 @@ func TestFDLimitUnderflow(t *testing.T) {
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
l.rllock.Lock() l.lk.Lock()
fdConsuming := l.fdConsuming fdConsuming := l.fdConsuming
l.rllock.Unlock() l.lk.Unlock()
if fdConsuming < 0 { if fdConsuming < 0 {
t.Fatalf("l.fdConsuming < 0") t.Fatalf("l.fdConsuming < 0")
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment