Merge pull request #105 from ethersphere/network-testing-framework-lock-fixes

Prevent various deadlocks
This commit is contained in:
Viktor Trón 2017-06-25 23:58:35 +02:00 committed by GitHub
commit 8863324fff
4 changed files with 59 additions and 84 deletions

View file

@ -228,7 +228,7 @@ func (self *Peer) Send(msg interface{}) error {
if !found { if !found {
return errorf(ErrInvalidMsgType, "%v", code) return errorf(ErrInvalidMsgType, "%v", code)
} }
log.Trace(fmt.Sprintf("=> msg #%d TO %v : %v", code, self.ID(), msg)) log.Trace(fmt.Sprintf("=> msg %s#%d TO %v : %v", self.spec.Name, code, self.ID(), msg))
return p2p.Send(self.rw, code, msg) return p2p.Send(self.rw, code, msg)
} }
@ -257,7 +257,7 @@ func (self *Peer) handleIncoming(handle func(msg interface{}) error) error {
if err := msg.Decode(val); err != nil { if err := msg.Decode(val); err != nil {
return errorf(ErrDecode, "<= %v: %v", msg, err) return errorf(ErrDecode, "<= %v: %v", msg, err)
} }
log.Trace(fmt.Sprintf("<= %v FROM %v %T %v", msg, self.ID(), val, val)) log.Trace(fmt.Sprintf("<= %s/%v FROM %v %T %v", self.spec.Name, msg, self.ID(), val, val))
// call the registered handler callbacks // call the registered handler callbacks
// a registered callback take the decoded message as argument as an interface // a registered callback take the decoded message as argument as an interface
@ -280,29 +280,24 @@ func (self *Peer) Handshake(ctx context.Context, hs interface{}) (interface{}, e
} }
errc := make(chan error, 2) errc := make(chan error, 2)
go func() { go func() {
if err := self.Send(hs); err != nil { errc <- self.Send(hs)
errc <- errorf(ErrHandshake, "cannot send: %v", err)
}
}() }()
hsc := make(chan interface{}) var rhs interface{}
go func() { go func() {
var rhs interface{} errc <- self.handleIncoming(func(msg interface{}) error {
err := self.handleIncoming(func(msg interface{}) error {
rhs = msg rhs = msg
return nil return nil
}) })
if err != nil {
errc <- err
return
}
hsc <- rhs
}() }()
select { for i := 0; i < 2; i++ {
case rhs := <-hsc: select {
return rhs, nil case err := <-errc:
case <-ctx.Done(): if err != nil {
return nil, ctx.Err() return nil, errorf(ErrHandshake, err.Error())
case err := <-errc: }
return nil, err case <-ctx.Done():
return nil, ctx.Err()
}
} }
return rhs, nil
} }

View file

@ -548,7 +548,11 @@ running:
c.flags |= trustedConn c.flags |= trustedConn
} }
// TODO: track in-progress inbound node IDs (pre-Peer) to avoid dialing them. // TODO: track in-progress inbound node IDs (pre-Peer) to avoid dialing them.
c.cont <- srv.encHandshakeChecks(peers, c) select {
case c.cont <- srv.encHandshakeChecks(peers, c):
case <-srv.quit:
break running
}
case c := <-srv.addpeer: case c := <-srv.addpeer:
// At this point the connection is past the protocol handshake. // At this point the connection is past the protocol handshake.
// Its capabilities are known and the remote identity is verified. // Its capabilities are known and the remote identity is verified.
@ -569,7 +573,11 @@ running:
// The dialer logic relies on the assumption that // The dialer logic relies on the assumption that
// dial tasks complete after the peer has been added or // dial tasks complete after the peer has been added or
// discarded. Unblock the task last. // discarded. Unblock the task last.
c.cont <- err select {
case c.cont <- err:
case <-srv.quit:
break running
}
case pd := <-srv.delpeer: case pd := <-srv.delpeer:
// A peer disconnected. // A peer disconnected.
d := common.PrettyDuration(mclock.Now() - pd.created) d := common.PrettyDuration(mclock.Now() - pd.created)

View file

@ -74,14 +74,29 @@ func (s *SimAdapter) NewNode(config *NodeConfig) (Node, error) {
} }
} }
node := &SimNode{ n, err := node.New(&node.Config{
P2P: p2p.Config{
PrivateKey: config.PrivateKey,
MaxPeers: math.MaxInt32,
NoDiscovery: true,
Dialer: s,
EnableMsgEvents: false,
},
NoUSB: true,
})
if err != nil {
return nil, err
}
simNode := &SimNode{
ID: id, ID: id,
config: config, config: config,
node: n,
adapter: s, adapter: s,
running: make(map[string]node.Service), running: make(map[string]node.Service),
} }
s.nodes[id] = node s.nodes[id] = simNode
return node, nil return simNode, nil
} }
func (s *SimAdapter) Dial(dest *discover.Node) (conn net.Conn, err error) { func (s *SimAdapter) Dial(dest *discover.Node) (conn net.Conn, err error) {
@ -99,17 +114,11 @@ func (s *SimAdapter) Dial(dest *discover.Node) (conn net.Conn, err error) {
} }
func (s *SimAdapter) DialRPC(id discover.NodeID) (*rpc.Client, error) { func (s *SimAdapter) DialRPC(id discover.NodeID) (*rpc.Client, error) {
simNode, ok := s.GetNode(id) node, ok := s.GetNode(id)
if !ok { if !ok {
return nil, fmt.Errorf("unknown node: %s", id) return nil, fmt.Errorf("unknown node: %s", id)
} }
simNode.lock.RLock() handler, err := node.node.RPCHandler()
node := simNode.node
simNode.lock.RUnlock()
if node == nil {
return nil, errors.New("node not started")
}
handler, err := node.RPCHandler()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -164,13 +173,7 @@ func (self *SimNode) Client() (*rpc.Client, error) {
// ServeRPC serves RPC requests over the given connection by creating an // ServeRPC serves RPC requests over the given connection by creating an
// in-process client to the node's RPC server // in-process client to the node's RPC server
func (self *SimNode) ServeRPC(conn net.Conn) error { func (self *SimNode) ServeRPC(conn net.Conn) error {
self.lock.RLock() handler, err := self.node.RPCHandler()
node := self.node
self.lock.RUnlock()
if node == nil {
return errors.New("node not started")
}
handler, err := node.RPCHandler()
if err != nil { if err != nil {
return err return err
} }
@ -181,9 +184,12 @@ func (self *SimNode) ServeRPC(conn net.Conn) error {
// Snapshots creates snapshots of the services by calling the // Snapshots creates snapshots of the services by calling the
// simulation_snapshot RPC method // simulation_snapshot RPC method
func (self *SimNode) Snapshots() (map[string][]byte, error) { func (self *SimNode) Snapshots() (map[string][]byte, error) {
self.lock.Lock() self.lock.RLock()
services := self.running services := make(map[string]node.Service, len(self.running))
self.lock.Unlock() for name, service := range self.running {
services[name] = service
}
self.lock.RUnlock()
if len(services) == 0 { if len(services) == 0 {
return nil, errors.New("no running services") return nil, errors.New("no running services")
} }
@ -206,10 +212,6 @@ func (self *SimNode) Snapshots() (map[string][]byte, error) {
func (self *SimNode) Start(snapshots map[string][]byte) error { func (self *SimNode) Start(snapshots map[string][]byte) error {
self.lock.Lock() self.lock.Lock()
defer self.lock.Unlock() defer self.lock.Unlock()
if self.node != nil {
return errors.New("node already started")
}
newService := func(name string) func(ctx *node.ServiceContext) (node.Service, error) { newService := func(name string) func(ctx *node.ServiceContext) (node.Service, error) {
return func(nodeCtx *node.ServiceContext) (node.Service, error) { return func(nodeCtx *node.ServiceContext) (node.Service, error) {
ctx := &ServiceContext{ ctx := &ServiceContext{
@ -230,59 +232,34 @@ func (self *SimNode) Start(snapshots map[string][]byte) error {
} }
} }
node, err := node.New(&node.Config{
P2P: p2p.Config{
PrivateKey: self.config.PrivateKey,
MaxPeers: math.MaxInt32,
NoDiscovery: true,
Dialer: self.adapter,
EnableMsgEvents: false,
},
NoUSB: true,
})
if err != nil {
return err
}
for _, name := range self.config.Services { for _, name := range self.config.Services {
if err := node.Register(newService(name)); err != nil { if err := self.node.Register(newService(name)); err != nil {
return err return err
} }
} }
if err := node.Start(); err != nil { if err := self.node.Start(); err != nil {
return err return err
} }
// create an in-process RPC client // create an in-process RPC client
handler, err := node.RPCHandler() handler, err := self.node.RPCHandler()
if err != nil { if err != nil {
return err return err
} }
self.client = rpc.DialInProc(handler) self.client = rpc.DialInProc(handler)
self.node = node
return nil return nil
} }
func (self *SimNode) Stop() error { func (self *SimNode) Stop() error {
self.lock.Lock() return self.node.Stop()
defer self.lock.Unlock()
if self.node == nil {
return nil
}
if err := self.node.Stop(); err != nil {
return err
}
self.node = nil
return nil
} }
// Services returns the underlying services // Services returns the underlying services
func (self *SimNode) Services() []node.Service { func (self *SimNode) Services() []node.Service {
self.lock.Lock() self.lock.RLock()
defer self.lock.Unlock() defer self.lock.RUnlock()
services := make([]node.Service, 0, len(self.running)) services := make([]node.Service, 0, len(self.running))
for _, service := range self.running { for _, service := range self.running {
services = append(services, service) services = append(services, service)
@ -291,11 +268,6 @@ func (self *SimNode) Services() []node.Service {
} }
func (self *SimNode) Server() *p2p.Server { func (self *SimNode) Server() *p2p.Server {
self.lock.Lock()
defer self.lock.Unlock()
if self.node == nil {
return nil
}
return self.node.Server() return self.node.Server()
} }

View file

@ -595,7 +595,7 @@ func (k *Kademlia) gotNearestNeighbours(peers [][]byte) (got bool) {
for _, p := range peers { for _, p := range peers {
pm[string(p)] = true pm[string(p)] = true
} }
k.EachConn(nil, 255, func(p OverlayConn, po int, nn bool) bool { k.eachConn(nil, 255, func(p OverlayConn, po int, nn bool) bool {
if !nn { if !nn {
return false return false
} }