Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neo
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
Kirill Smelkov
neo
Commits
c818ce8a
Commit
c818ce8a
authored
Apr 26, 2017
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
X fixup/polish after NodeLink.Accept rework
parent
65b17bdc
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
42 additions
and
71 deletions
+42
-71
go/neo/connection.go
go/neo/connection.go
+26
-59
go/neo/connection_test.go
go/neo/connection_test.go
+16
-12
No files found.
go/neo/connection.go
View file @
c818ce8a
...
...
@@ -2,17 +2,21 @@
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version
2
, or (at your
// it under the terms of the GNU General Public License version
3
, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Open Source Initiative approved licenses and Convey
// the resulting work. Corresponding source of such a combination shall include
// the source code for all other software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// NEO. Connection management
package
neo
// Connection management
import
(
"context"
...
...
@@ -33,14 +37,11 @@ import (
//
// New connection can be created with .NewConn() . Once connection is
// created and data is sent over it, on peer's side another corresponding
// new connection will be created - accepting first packet "request" - and all XXX -> Accept
// further communication send/receive exchange will be happening in between
// those 2 connections.
// new connection can be accepted via .Accept(), and all further communication
// send/receive exchange will be happening in between those 2 connections.
//
// For a node to be able to accept new incoming connection it has to register XXX -> Accept
// corresponding handler with .HandleNewConn() . Without such handler
// registered the node will be able to only initiate new connections, not
// accept new ones from its peer.
// For a node to be able to accept new incoming connection it has to have
// "server" role - see NewNodeLink() for details.
//
// A NodeLink has to be explicitly closed, once it is no longer needed.
//
...
...
@@ -52,10 +53,7 @@ type NodeLink struct {
connTab
map
[
uint32
]
*
Conn
// connId -> Conn associated with connId
nextConnId
uint32
// next connId to use for Conn initiated by us
serveWg
sync
.
WaitGroup
// for serve{Send,Recv}
// handleWg sync.WaitGroup // for spawned handlers
// handleNewConn func(conn *Conn) // handler for new connections
serveWg
sync
.
WaitGroup
// for serve{Send,Recv}
acceptq
chan
*
Conn
// queue of incoming connections for Accept
// = nil if NodeLink is not accepting connections
...
...
@@ -95,10 +93,13 @@ const (
// NewNodeLink makes a new NodeLink from already established net.Conn
//
// Role specifies how to treat our role on the link - either as client or
// server one. The difference in between client and server roles is only in XXX + acceptq
// how connection ids are allocated for connections initiated at our side:
// there is no conflict in identifiers if one side always allocates them as
// even (server) and its peer as odd (client).
// server one. The difference in between client and server roles are in:
//
// 1. how connection ids are allocated for connections initiated at our side:
// there is no conflict in identifiers if one side always allocates them as
// even (server) and its peer as odd (client).
//
// 2. NodeLink.Accept() works only on server side.
//
// Usually server role should be used for connections created via
// net.Listen/net.Accept and client role for connections created via net.Dial.
...
...
@@ -135,8 +136,6 @@ func NewNodeLink(conn net.Conn, role LinkRole) *NodeLink {
// Close closes node-node link.
// IO on connections established over it is automatically interrupted with an error.
func
(
nl
*
NodeLink
)
Close
()
error
{
// XXX what with .acceptq ?
// mark all active Conns as closed
nl
.
connMu
.
Lock
()
defer
nl
.
connMu
.
Unlock
()
...
...
@@ -153,9 +152,6 @@ func (nl *NodeLink) Close() error {
// wait for serve{Send,Recv} to complete
nl
.
serveWg
.
Wait
()
// XXX do we want to also Wait for handlers here?
// (problem is peerLink is closed first so this might cause handlers to see errors)
return
err
}
...
...
@@ -233,7 +229,7 @@ func (nl *NodeLink) recvPkt() (*PktBuf, error) {
func
(
nl
*
NodeLink
)
newConn
(
connId
uint32
)
*
Conn
{
c
:=
&
Conn
{
nodeLink
:
nl
,
connId
:
connId
,
rxq
:
make
(
chan
*
PktBuf
),
rxq
:
make
(
chan
*
PktBuf
),
// TODO buffering
txerr
:
make
(
chan
error
,
1
),
// NOTE non-blocking - see Conn.Send
closed
:
make
(
chan
struct
{}),
}
...
...
@@ -241,7 +237,7 @@ func (nl *NodeLink) newConn(connId uint32) *Conn {
return
c
}
// NewConn creates
a
connection on top of node-node link
// NewConn creates
new
connection on top of node-node link
func
(
nl
*
NodeLink
)
NewConn
()
*
Conn
{
nl
.
connMu
.
Lock
()
defer
nl
.
connMu
.
Unlock
()
...
...
@@ -253,7 +249,7 @@ func (nl *NodeLink) NewConn() *Conn {
return
c
}
// Err
ClosedLink is the error indicated for oper
tions on closed NodeLink
// Err
LinkClosed is the error indicated for opera
tions on closed NodeLink
var
ErrLinkClosed
=
errors
.
New
(
"node link closed"
)
var
ErrLinkNoListen
=
errors
.
New
(
"node link is not listening for incoming connections"
)
...
...
@@ -268,7 +264,6 @@ func (nl *NodeLink) Accept() (*Conn, error) {
case
<-
nl
.
closed
:
return
nil
,
ErrLinkClosed
// XXX + op = Accept ?
// XXX check acceptq != nil ?
case
c
:=
<-
nl
.
acceptq
:
return
c
,
nil
}
...
...
@@ -294,16 +289,15 @@ func (nl *NodeLink) serveRecv() {
// pkt.ConnId -> Conn
connId
:=
ntoh32
(
pkt
.
Header
()
.
ConnId
)
// var handleNewConn func(conn *Conn)
nl
.
connMu
.
Lock
()
conn
:=
nl
.
connTab
[
connId
]
if
conn
==
nil
{
//handleNewConn = nl.handleNewConn // XXX -> Accept
//if handleNewConn != nil {
if
nl
.
acceptq
!=
nil
{
// we are accepting new incoming connection
conn
=
nl
.
newConn
(
connId
)
// XXX what if Accept exited because of just recently close(nl.closed)?
// -> check nl.closed here too ?
nl
.
acceptq
<-
conn
}
}
...
...
@@ -315,32 +309,13 @@ func (nl *NodeLink) serveRecv() {
continue
}
// // XXX -> accept
// // we are accepting new incoming connection - spawn
// // connection-serving goroutine
// if handleNewConn != nil {
// // TODO avoid spawning goroutine for each new Ask request -
// // - by keeping pool of read inactive goroutine / conn pool ?
// // XXX rework interface for this to be Accept-like ?
// go func() {
// nl.handleWg.Add(1)
// defer nl.handleWg.Done()
// handleNewConn(conn)
// }()
// }
// route packet to serving goroutine handler
// XXX what if Conn.Recv exited because of just recently close(nl.closed) ?
// -> check nl.closed here too ?
conn
.
rxq
<-
pkt
}
}
// // wait for all handlers spawned for accepted connections to complete
// // XXX naming -> WaitHandlers ?
// func (nl *NodeLink) Wait() {
// nl.handleWg.Wait()
// }
// request to transmit a packet. Result error goes back to errch
type
txReq
struct
{
...
...
@@ -369,14 +344,6 @@ runloop:
}
}
// // XXX move to NodeLink ctor ?
// // Set handler for new incoming connections
// func (nl *NodeLink) HandleNewConn(h func(*Conn)) {
// nl.connMu.Lock()
// defer nl.connMu.Unlock()
// nl.handleNewConn = h // NOTE can change handler at runtime XXX do we need this?
// }
// ErrClosedConn is the error indicated for read/write operations on closed Conn
var
ErrClosedConn
=
errors
.
New
(
"read/write on closed connection"
)
...
...
@@ -460,7 +427,7 @@ func (c *Conn) Close() error {
}
// for conv
i
nience: Dial/Listen
// for conv
e
nience: Dial/Listen
// Dial connects to address on named network and wrap the connection as NodeLink
// TODO +tls.Config
...
...
go/neo/connection_test.go
View file @
c818ce8a
...
...
@@ -2,17 +2,21 @@
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version
2
, or (at your
// it under the terms of the GNU General Public License version
3
, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Open Source Initiative approved licenses and Convey
// the resulting work. Corresponding source of such a combination shall include
// the source code for all other software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// NEO. Connection management. Tests
package
neo
// Connection management. Tests
import
(
"bytes"
...
...
@@ -56,6 +60,12 @@ func xclose(c io.Closer) {
exc
.
Raiseif
(
err
)
}
func
xaccept
(
nl
*
NodeLink
)
*
Conn
{
c
,
err
:=
nl
.
Accept
()
exc
.
Raiseif
(
err
)
return
c
}
func
xsend
(
c
*
Conn
,
pkt
*
PktBuf
)
{
err
:=
c
.
Send
(
pkt
)
exc
.
Raiseif
(
err
)
...
...
@@ -287,10 +297,8 @@ func TestNodeLink(t *testing.T) {
// Conn accept + exchange
nl1
,
nl2
=
nodeLinkPipe
()
wg
=
WorkGroup
()
//nl2.HandleNewConn(func(c *Conn) {
wg
.
Gox
(
func
()
{
c
,
err
:=
nl2
.
Accept
()
// XXX -> xaccept ?
exc
.
Raiseif
(
err
)
c
:=
xaccept
(
nl2
)
pkt
:=
xrecv
(
c
)
xverifyPkt
(
pkt
,
c
.
connId
,
33
,
[]
byte
(
"ping"
))
...
...
@@ -312,14 +320,13 @@ func TestNodeLink(t *testing.T) {
xsend
(
c
,
mkpkt
(
35
,
[]
byte
(
"ping2"
)))
pkt
=
xrecv
(
c
)
xverifyPkt
(
pkt
,
c
.
connId
,
36
,
[]
byte
(
"pong2"
))
//nl2.Wait()
xwait
(
wg
)
xclose
(
c
)
xclose
(
nl1
)
xclose
(
nl2
)
// test 2 channels with replies com
m
ing in reversed time order
// test 2 channels with replies coming in reversed time order
nl1
,
nl2
=
nodeLinkPipe
()
wg
=
WorkGroup
()
replyOrder
:=
map
[
uint16
]
struct
{
// "order" in which to process requests
...
...
@@ -331,11 +338,9 @@ func TestNodeLink(t *testing.T) {
}
close
(
replyOrder
[
2
]
.
start
)
//nl2.HandleNewConn(func(c *Conn) {
wg
.
Gox
(
func
()
{
for
_
=
range
replyOrder
{
c
,
err
:=
nl2
.
Accept
()
exc
.
Raiseif
(
err
)
c
:=
xaccept
(
nl2
)
wg
.
Gox
(
func
()
{
pkt
:=
xrecv
(
c
)
...
...
@@ -368,7 +373,6 @@ func TestNodeLink(t *testing.T) {
}
xechoWait
(
c2
,
2
)
xechoWait
(
c1
,
1
)
//nl2.Wait()
xwait
(
wg
)
xclose
(
c1
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment