mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-26 19:42:23 +00:00
parent
dc62046019
commit
631f166709
4 changed files with 30 additions and 5 deletions
|
@ -1,7 +1,9 @@
|
||||||
package network
|
package network
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/network/capability"
|
"github.com/nspcc-dev/neo-go/pkg/network/capability"
|
||||||
|
@ -17,6 +19,7 @@ const (
|
||||||
type Discoverer interface {
|
type Discoverer interface {
|
||||||
BackFill(...string)
|
BackFill(...string)
|
||||||
Close()
|
Close()
|
||||||
|
GetFanOut() int
|
||||||
PoolCount() int
|
PoolCount() int
|
||||||
RequestRemote(int)
|
RequestRemote(int)
|
||||||
RegisterBadAddr(string)
|
RegisterBadAddr(string)
|
||||||
|
@ -46,6 +49,7 @@ type DefaultDiscovery struct {
|
||||||
goodAddrs map[string]capability.Capabilities
|
goodAddrs map[string]capability.Capabilities
|
||||||
unconnectedAddrs map[string]int
|
unconnectedAddrs map[string]int
|
||||||
attempted map[string]bool
|
attempted map[string]bool
|
||||||
|
optimalFanOut int32
|
||||||
isDead bool
|
isDead bool
|
||||||
requestCh chan int
|
requestCh chan int
|
||||||
pool chan string
|
pool chan string
|
||||||
|
@ -196,9 +200,21 @@ func (d *DefaultDiscovery) RegisterConnectedAddr(addr string) {
|
||||||
d.lock.Unlock()
|
d.lock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetFanOut returns the optimal number of nodes to broadcast packets to.
|
||||||
|
func (d *DefaultDiscovery) GetFanOut() int {
|
||||||
|
return int(atomic.LoadInt32(&d.optimalFanOut))
|
||||||
|
}
|
||||||
|
|
||||||
// updateNetSize updates network size estimation metric. Must be called under read lock.
|
// updateNetSize updates network size estimation metric. Must be called under read lock.
|
||||||
func (d *DefaultDiscovery) updateNetSize() {
|
func (d *DefaultDiscovery) updateNetSize() {
|
||||||
updateNetworkSizeMetric(len(d.connectedAddrs) + len(d.unconnectedAddrs))
|
var netsize = len(d.connectedAddrs) + len(d.unconnectedAddrs) + 1 // 1 for the node itself.
|
||||||
|
var fanOut = 2.5 * math.Log(float64(netsize-1)) // -1 for the number of potential peers.
|
||||||
|
if netsize == 2 { // log(1) == 0.
|
||||||
|
fanOut = 1 // But we still want to push messages to the peer.
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic.StoreInt32(&d.optimalFanOut, int32(fanOut+0.5)) // Truncating conversion, hence +0.5.
|
||||||
|
updateNetworkSizeMetric(netsize)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultDiscovery) tryAddress(addr string) {
|
func (d *DefaultDiscovery) tryAddress(addr string) {
|
||||||
|
|
|
@ -74,6 +74,7 @@ func TestDefaultDiscoverer(t *testing.T) {
|
||||||
assert.Equal(t, 0, len(d.BadPeers()))
|
assert.Equal(t, 0, len(d.BadPeers()))
|
||||||
require.Equal(t, set1, set1D)
|
require.Equal(t, set1, set1D)
|
||||||
}
|
}
|
||||||
|
require.Equal(t, 2, d.GetFanOut())
|
||||||
|
|
||||||
// Request should make goroutines dial our addresses draining the pool.
|
// Request should make goroutines dial our addresses draining the pool.
|
||||||
d.RequestRemote(len(set1))
|
d.RequestRemote(len(set1))
|
||||||
|
|
|
@ -40,6 +40,11 @@ func (d *testDiscovery) RegisterBadAddr(addr string) {
|
||||||
defer d.Unlock()
|
defer d.Unlock()
|
||||||
d.bad = append(d.bad, addr)
|
d.bad = append(d.bad, addr)
|
||||||
}
|
}
|
||||||
|
func (d *testDiscovery) GetFanOut() int {
|
||||||
|
d.Lock()
|
||||||
|
defer d.Unlock()
|
||||||
|
return len(d.connected) + len(d.backfill)
|
||||||
|
}
|
||||||
func (d *testDiscovery) RegisterGoodAddr(string, capability.Capabilities) {}
|
func (d *testDiscovery) RegisterGoodAddr(string, capability.Capabilities) {}
|
||||||
func (d *testDiscovery) RegisterConnectedAddr(addr string) {
|
func (d *testDiscovery) RegisterConnectedAddr(addr string) {
|
||||||
d.Lock()
|
d.Lock()
|
||||||
|
|
|
@ -1363,8 +1363,12 @@ func (s *Server) iteratePeersWithSendMsg(msg *Message, send func(Peer, context.C
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var replies = make(chan error, peerN) // Cache is there just to make goroutines exit faster.
|
var (
|
||||||
var ctx, cancel = context.WithTimeout(context.Background(), s.TimePerBlock/2)
|
// Optimal number of recipients.
|
||||||
|
enoughN = s.discovery.GetFanOut()
|
||||||
|
replies = make(chan error, peerN) // Cache is there just to make goroutines exit faster.
|
||||||
|
ctx, cancel = context.WithTimeout(context.Background(), s.TimePerBlock/2)
|
||||||
|
)
|
||||||
for _, peer := range peers {
|
for _, peer := range peers {
|
||||||
go func(p Peer, ctx context.Context, pkt []byte) {
|
go func(p Peer, ctx context.Context, pkt []byte) {
|
||||||
// Do this before packet is sent, reader thread can get the reply before this routine wakes up.
|
// Do this before packet is sent, reader thread can get the reply before this routine wakes up.
|
||||||
|
@ -1383,8 +1387,7 @@ func (s *Server) iteratePeersWithSendMsg(msg *Message, send func(Peer, context.C
|
||||||
if sentN+deadN == peerN {
|
if sentN+deadN == peerN {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// Send to 2/3 of good peers.
|
if sentN >= enoughN && ctx.Err() == nil {
|
||||||
if 3*sentN >= 2*(peerN-deadN) && ctx.Err() == nil {
|
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue