Commit 0f7357ec authored by Kirill Smelkov's avatar Kirill Smelkov

go/*: Adapt to xnet.Networker changes wrt Listen and cancellation

See

	go123@3354b401
and

	go123@b03d65ff

The wrapping logic in LinkListener and requireIdentifyHello goes away
because Accept from xnet now supports cancellation.
parent d58a606f
...@@ -24,7 +24,6 @@ import ( ...@@ -24,7 +24,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
stdnet "net"
"net/url" "net/url"
"os" "os"
"os/exec" "os/exec"
...@@ -218,8 +217,8 @@ type NEOGoSrv struct { ...@@ -218,8 +217,8 @@ type NEOGoSrv struct {
cancel func() // to stop spawned nodes cancel func() // to stop spawned nodes
serveWG *xsync.WorkGroup // services are spawned under serveWG serveWG *xsync.WorkGroup // services are spawned under serveWG
Ml stdnet.Listener // M listens here Ml xnet.Listener // M listens here
Sl stdnet.Listener // S listens here Sl xnet.Listener // S listens here
M *Master // M service M *Master // M service
S *Storage // S service S *Storage // S service
Sback *bsqlite.Backend // S backend Sback *bsqlite.Backend // S backend
...@@ -249,8 +248,8 @@ func StartNEOGoSrv(opt NEOSrvOptions) (_ *NEOGoSrv, err error) { ...@@ -249,8 +248,8 @@ func StartNEOGoSrv(opt NEOSrvOptions) (_ *NEOGoSrv, err error) {
net := xnet.NetPlain("tcp") // FIXME net := xnet.NetPlain("tcp") // FIXME
n.Ml, err = net.Listen(""); if err != nil { return nil, err } n.Ml, err = net.Listen(ctx, ""); if err != nil { return nil, err }
n.Sl, err = net.Listen(""); if err != nil { return nil, err } n.Sl, err = net.Listen(ctx, ""); if err != nil { return nil, err }
n.M = NewMaster(opt.name, net) n.M = NewMaster(opt.name, net)
......
...@@ -25,10 +25,10 @@ import ( ...@@ -25,10 +25,10 @@ import (
"flag" "flag"
"fmt" "fmt"
"io" "io"
stdnet "net"
"os" "os"
"lab.nexedi.com/kirr/go123/prog" "lab.nexedi.com/kirr/go123/prog"
"lab.nexedi.com/kirr/go123/xnet"
"lab.nexedi.com/kirr/neo/go/neo" "lab.nexedi.com/kirr/neo/go/neo"
) )
...@@ -70,7 +70,7 @@ func masterMain(argv []string) { ...@@ -70,7 +70,7 @@ func masterMain(argv []string) {
ctx := context.Background() ctx := context.Background()
err = listenAndServe(ctx, net, *bind, func(ctx context.Context, l stdnet.Listener) error { err = listenAndServe(ctx, net, *bind, func(ctx context.Context, l xnet.Listener) error {
master := neo.NewMaster(*cluster, net) master := neo.NewMaster(*cluster, net)
return master.Run(ctx, l) return master.Run(ctx, l)
}) })
......
...@@ -24,7 +24,6 @@ import ( ...@@ -24,7 +24,6 @@ import (
"bytes" "bytes"
"context" "context"
"flag" "flag"
stdnet "net"
"net/http" "net/http"
"io" "io"
"fmt" "fmt"
...@@ -103,8 +102,8 @@ func neoMatch(r io.Reader) bool { ...@@ -103,8 +102,8 @@ func neoMatch(r io.Reader) bool {
// default HTTP mux. // default HTTP mux.
// //
// Default HTTP mux can be assumed to contain /debug/pprof and the like. // Default HTTP mux can be assumed to contain /debug/pprof and the like.
func listenAndServe(ctx context.Context, net xnet.Networker, laddr string, serve func(ctx context.Context, l stdnet.Listener) error) error { func listenAndServe(ctx context.Context, net xnet.Networker, laddr string, serve func(ctx context.Context, l xnet.Listener) error) error {
l, err := net.Listen(laddr) l, err := net.Listen(ctx, laddr)
if err != nil { if err != nil {
return err return err
} }
...@@ -114,7 +113,7 @@ func listenAndServe(ctx context.Context, net xnet.Networker, laddr string, serve ...@@ -114,7 +113,7 @@ func listenAndServe(ctx context.Context, net xnet.Networker, laddr string, serve
log.Infof(ctx, "listening at %s ...", l.Addr()) log.Infof(ctx, "listening at %s ...", l.Addr())
log.Flush() // XXX ok? log.Flush() // XXX ok?
mux := cmux.New(l) mux := cmux.New(xnet.BindCtxL(l, ctx))
neoL := mux.Match(neoMatch) neoL := mux.Match(neoMatch)
httpL := mux.Match(cmux.HTTP1(), cmux.HTTP2()) // XXX verify http2 works httpL := mux.Match(cmux.HTTP1(), cmux.HTTP2()) // XXX verify http2 works
miscL := mux.Match(cmux.Any()) miscL := mux.Match(cmux.Any())
...@@ -127,7 +126,7 @@ func listenAndServe(ctx context.Context, net xnet.Networker, laddr string, serve ...@@ -127,7 +126,7 @@ func listenAndServe(ctx context.Context, net xnet.Networker, laddr string, serve
}) })
wg.Go(func(ctx context.Context) error { wg.Go(func(ctx context.Context) error {
return serve(ctx, neoL) return serve(ctx, xnet.WithCtxL(neoL))
}) })
wg.Go(func(ctx context.Context) error { wg.Go(func(ctx context.Context) error {
......
...@@ -24,13 +24,13 @@ import ( ...@@ -24,13 +24,13 @@ import (
"context" "context"
"flag" "flag"
"fmt" "fmt"
stdnet "net"
"io" "io"
"os" "os"
"runtime" "runtime"
"strings" "strings"
"lab.nexedi.com/kirr/go123/prog" "lab.nexedi.com/kirr/go123/prog"
"lab.nexedi.com/kirr/go123/xnet"
"lab.nexedi.com/kirr/neo/go/neo" "lab.nexedi.com/kirr/neo/go/neo"
"lab.nexedi.com/kirr/neo/go/neo/storage" "lab.nexedi.com/kirr/neo/go/neo/storage"
...@@ -110,7 +110,7 @@ func storageMain(argv []string) { ...@@ -110,7 +110,7 @@ func storageMain(argv []string) {
prog.Fatal(err) prog.Fatal(err)
} }
err = listenAndServe(ctx, net, *bind, func(ctx context.Context, l stdnet.Listener) error { err = listenAndServe(ctx, net, *bind, func(ctx context.Context, l xnet.Listener) error {
stor := neo.NewStorage(*cluster, master, net, back) stor := neo.NewStorage(*cluster, master, net, back)
return stor.Run(ctx, l) return stor.Run(ctx, l)
}) })
......
...@@ -24,7 +24,6 @@ import ( ...@@ -24,7 +24,6 @@ import (
"context" "context"
stderrors "errors" stderrors "errors"
"fmt" "fmt"
stdnet "net"
"sync" "sync"
"time" "time"
...@@ -130,7 +129,7 @@ func (m *Master) setClusterState(state proto.ClusterState) { ...@@ -130,7 +129,7 @@ func (m *Master) setClusterState(state proto.ClusterState) {
// Run starts master node and runs it until ctx is cancelled or fatal error. // Run starts master node and runs it until ctx is cancelled or fatal error.
// //
// The master will be serving incoming connections on l. // The master will be serving incoming connections on l.
func (m *Master) Run(ctx context.Context, l stdnet.Listener) (err error) { func (m *Master) Run(ctx context.Context, l xnet.Listener) (err error) {
addr := l.Addr() addr := l.Addr()
defer task.Runningf(&ctx, "master(%v)", addr)(&err) defer task.Runningf(&ctx, "master(%v)", addr)(&err)
......
...@@ -173,90 +173,22 @@ type Listener interface { ...@@ -173,90 +173,22 @@ type Listener interface {
// requireIdentifyHello wraps inner LinkListener into ^^^ Listener. // requireIdentifyHello wraps inner LinkListener into ^^^ Listener.
func requireIdentifyHello(inner neonet.LinkListener) Listener { func requireIdentifyHello(inner neonet.LinkListener) Listener {
l := &listener{ return &listener{l: inner}
l: inner,
acceptq: make(chan accepted),
closed: make(chan struct{}),
}
go l.run()
return l
} }
type listener struct { type listener struct {
l neonet.LinkListener l neonet.LinkListener
acceptq chan accepted
closed chan struct {}
}
type accepted struct {
req *neonet.Request
idReq *proto.RequestIdentification
err error
}
func (l *listener) Close() error {
err := l.l.Close()
close(l.closed)
return err
}
func (l *listener) run() {
for {
// stop on close
select {
case <-l.closed:
return
default:
}
// XXX add backpressure on too much incoming connections without client .Accept ?
// XXX do not let err go to .accept() - handle here? (but here
// we do not know with which severety and context to log)
link, err := l.l.Accept()
go l.accept(link, err)
}
}
func (l *listener) accept(link *neonet.NodeLink, err error) {
res := make(chan accepted, 1)
go func() {
req, idReq, err := l.accept1(context.Background(), link, err) // XXX ctx cancel on l close?
res <- accepted{req, idReq, err}
}()
// wait for accept1 result & resend it to .acceptq
// close link in case of listening cancel or error
//
// the only case when link stays alive is when acceptance was
// successful and link ownership is passed to Accept.
ok := false
select {
case <-l.closed:
case a := <-res:
select {
case l.acceptq <- a:
ok = (a.err == nil)
case <-l.closed:
}
}
if !ok && link != nil {
link.Close()
}
} }
func (l *listener) accept1(ctx context.Context, link *neonet.NodeLink, err0 error) (_ *neonet.Request, _ *proto.RequestIdentification, err error) { func (l *listener) Accept(ctx context.Context) (_ *neonet.Request, _ *proto.RequestIdentification, err error) {
if err0 != nil { link, err := l.l.Accept(ctx)
return nil, nil, err0 if err != nil {
return nil, nil, err
} }
defer xerr.Context(&err, "identify") // XXX -> task.ErrContext?
// identify peer // identify peer
// the first conn must come with RequestIdentification packet // the first conn must come with RequestIdentification packet
defer xerr.Context(&err, "identify") // XXX -> task.ErrContext?
req, err := link.Recv1(/*ctx*/) req, err := link.Recv1(/*ctx*/)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
...@@ -272,24 +204,8 @@ func (l *listener) accept1(ctx context.Context, link *neonet.NodeLink, err0 erro ...@@ -272,24 +204,8 @@ func (l *listener) accept1(ctx context.Context, link *neonet.NodeLink, err0 erro
return nil, nil, emsg return nil, nil, emsg
} }
func (l *listener) Accept(ctx context.Context) (*neonet.Request, *proto.RequestIdentification, error) { func (l *listener) Close() error { return l.l.Close() }
select{ func (l *listener) Addr() net.Addr { return l.l.Addr() }
case <-l.closed:
// we know raw listener is already closed - return proper error about it
_, err := l.l.Accept()
return nil, nil, err
case <-ctx.Done():
return nil, nil, ctx.Err()
case a := <-l.acceptq:
return a.req, a.idReq, a.err
}
}
func (l *listener) Addr() net.Addr {
return l.l.Addr()
}
// ---------------------------------------- // ----------------------------------------
......
...@@ -147,8 +147,8 @@ func DialLink(ctx context.Context, net xnet.Networker, addr string) (*NodeLink, ...@@ -147,8 +147,8 @@ func DialLink(ctx context.Context, net xnet.Networker, addr string) (*NodeLink,
// ListenLink starts listening on laddr for incoming connections and wraps them as NodeLink. // ListenLink starts listening on laddr for incoming connections and wraps them as NodeLink.
// //
// The listener accepts only those connections that pass NEO protocol handshake. // The listener accepts only those connections that pass NEO protocol handshake.
func ListenLink(net xnet.Networker, laddr string) (LinkListener, error) { func ListenLink(ctx context.Context, net xnet.Networker, laddr string) (LinkListener, error) {
rawl, err := net.Listen(laddr) rawl, err := net.Listen(ctx, laddr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -160,82 +160,30 @@ func ListenLink(net xnet.Networker, laddr string) (LinkListener, error) { ...@@ -160,82 +160,30 @@ func ListenLink(net xnet.Networker, laddr string) (LinkListener, error) {
// net.Listener and wraps them as NodeLink. // net.Listener and wraps them as NodeLink.
// //
// The listener accepts only those connections that pass NEO protocol handshake. // The listener accepts only those connections that pass NEO protocol handshake.
func NewLinkListener(inner net.Listener) LinkListener { func NewLinkListener(inner xnet.Listener) LinkListener {
l := &linkListener{ return &linkListener{l: inner}
l: inner,
acceptq: make(chan linkAccepted),
closed: make(chan struct{}),
}
go l.run()
return l
} }
// LinkListener is net.Listener adapted to return handshaked NodeLink on Accept. // LinkListener is xnet.Listener adapted to return handshaked NodeLink on Accept.
type LinkListener interface { type LinkListener interface {
// from net.Listener: // from xnet.Listener:
Close() error Close() error
Addr() net.Addr Addr() net.Addr
// Accept returns new incoming connection wrapped into NodeLink. // Accept returns new incoming connection wrapped into NodeLink.
// It accepts only those connections which pass NEO protocol handshake. // It accepts only those connections which pass NEO protocol handshake.
Accept() (*NodeLink, error) Accept(ctx context.Context) (*NodeLink, error)
} }
// linkListener implements LinkListener. // linkListener implements LinkListener.
type linkListener struct { type linkListener struct {
l net.Listener l xnet.Listener
acceptq chan linkAccepted
closed chan struct{}
}
type linkAccepted struct {
link *NodeLink
err error
}
func (l *linkListener) Close() error {
err := l.l.Close()
close(l.closed)
return err
}
func (l *linkListener) run() {
// context that cancels when listener stops
runCtx, runCancel := context.WithCancel(context.Background())
defer runCancel()
for {
// stop on close
select {
case <-l.closed:
return
default:
}
// XXX add backpressure on too much incoming connections without client .Accept ?
conn, err := l.l.Accept()
go l.accept(runCtx, conn, err)
}
} }
func (l *linkListener) accept(ctx context.Context, conn net.Conn, err error) { func (l *linkListener) Accept(ctx context.Context) (*NodeLink, error) {
link, err := l.accept1(ctx, conn, err)
select {
case l.acceptq <- linkAccepted{link, err}:
// ok
case <-l.closed:
// shutdown
if link != nil {
link.Close()
}
}
}
func (l *linkListener) accept1(ctx context.Context, conn net.Conn, err error) (*NodeLink, error) {
// XXX err ctx? // XXX err ctx?
conn, err := l.l.Accept(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -249,18 +197,5 @@ func (l *linkListener) accept1(ctx context.Context, conn net.Conn, err error) (* ...@@ -249,18 +197,5 @@ func (l *linkListener) accept1(ctx context.Context, conn net.Conn, err error) (*
return link, nil return link, nil
} }
func (l *linkListener) Accept() (*NodeLink, error) { func (l *linkListener) Close() error { return l.l.Close() }
select { func (l *linkListener) Addr() net.Addr { return l.l.Addr() }
case <-l.closed:
// we know raw listener is already closed - return proper error about it
_, err := l.l.Accept()
return nil, err
case a := <-l.acceptq:
return a.link, a.err
}
}
func (l *linkListener) Addr() net.Addr {
return l.l.Addr()
}
...@@ -23,7 +23,6 @@ package neo ...@@ -23,7 +23,6 @@ package neo
import ( import (
"context" "context"
"fmt" "fmt"
stdnet "net"
"sync" "sync"
"time" "time"
...@@ -83,7 +82,7 @@ func NewStorage(clusterName, masterAddr string, net xnet.Networker, back storage ...@@ -83,7 +82,7 @@ func NewStorage(clusterName, masterAddr string, net xnet.Networker, back storage
// commands it to shutdown. // commands it to shutdown.
// //
// The storage will be serving incoming connections on l. // The storage will be serving incoming connections on l.
func (stor *Storage) Run(ctx context.Context, l stdnet.Listener) (err error) { func (stor *Storage) Run(ctx context.Context, l xnet.Listener) (err error) {
addr := l.Addr() addr := l.Addr()
defer task.Runningf(&ctx, "storage(%v)", addr)(&err) defer task.Runningf(&ctx, "storage(%v)", addr)(&err)
......
// Copyright (C) 2017-2018 Nexedi SA and Contributors. // Copyright (C) 2017-2020 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com> // Kirill Smelkov <kirr@nexedi.com>
// //
// This program is free software: you can Use, Study, Modify and Redistribute // This program is free software: you can Use, Study, Modify and Redistribute
...@@ -219,7 +219,7 @@ func tNewStorage(clusterName, masterAddr, serveAddr string, net xnet.Networker, ...@@ -219,7 +219,7 @@ func tNewStorage(clusterName, masterAddr, serveAddr string, net xnet.Networker,
} }
func (s *tStorage) Run(ctx context.Context) error { func (s *tStorage) Run(ctx context.Context) error {
l, err := s.node.Net.Listen(s.serveAddr) l, err := s.node.Net.Listen(ctx, s.serveAddr)
if err != nil { if err != nil {
return err return err
} }
...@@ -247,7 +247,7 @@ func tNewMaster(clusterName, serveAddr string, net xnet.Networker) *tMaster { ...@@ -247,7 +247,7 @@ func tNewMaster(clusterName, serveAddr string, net xnet.Networker) *tMaster {
} }
func (m *tMaster) Run(ctx context.Context) error { func (m *tMaster) Run(ctx context.Context) error {
l, err := m.node.Net.Listen(m.serveAddr) l, err := m.node.Net.Listen(ctx, m.serveAddr)
if err != nil { if err != nil {
return err return err
} }
......
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