mirror of https://github.com/vacp2p/nim-libp2p.git
Properly track and close mplex handlers (#166)
* Properly track and close mplex handlers * Avoid verbose warnings * Fix tryAndWarn trace issue * Handle LPEOF in lpchannel close
This commit is contained in:
parent
618e01eba3
commit
005e088405
|
@ -19,7 +19,8 @@ macro checkFutures*[T](futs: seq[Future[T]], exclude: untyped = []): untyped =
|
||||||
if res.failed:
|
if res.failed:
|
||||||
let exc = res.readError()
|
let exc = res.readError()
|
||||||
# We still don't abort but warn
|
# We still don't abort but warn
|
||||||
warn "Something went wrong in a future", error=exc.name, msg = exc.msg
|
warn "Something went wrong in a future", error=exc.name
|
||||||
|
trace "Exception message", msg=exc.msg
|
||||||
else:
|
else:
|
||||||
quote do:
|
quote do:
|
||||||
for res in `futs`:
|
for res in `futs`:
|
||||||
|
@ -28,10 +29,11 @@ macro checkFutures*[T](futs: seq[Future[T]], exclude: untyped = []): untyped =
|
||||||
let exc = res.readError()
|
let exc = res.readError()
|
||||||
for i in 0..<`nexclude`:
|
for i in 0..<`nexclude`:
|
||||||
if exc of `exclude`[i]:
|
if exc of `exclude`[i]:
|
||||||
trace "Ignoring an error (no warning)", error=exc.name, msg = exc.msg
|
trace "Ignoring an error (no warning)", error=exc.name, msg=exc.msg
|
||||||
break check
|
break check
|
||||||
# We still don't abort but warn
|
# We still don't abort but warn
|
||||||
warn "Something went wrong in a future", error=exc.name, msg = exc.msg
|
warn "Something went wrong in a future", error=exc.name
|
||||||
|
trace "Exception message", msg=exc.msg
|
||||||
|
|
||||||
proc allFuturesThrowing*[T](args: varargs[Future[T]]): Future[void] =
|
proc allFuturesThrowing*[T](args: varargs[Future[T]]): Future[void] =
|
||||||
var futs: seq[Future[T]]
|
var futs: seq[Future[T]]
|
||||||
|
@ -59,4 +61,4 @@ template tryAndWarn*(msg: static[string]; body: untyped): untyped =
|
||||||
except CancelledError as ex:
|
except CancelledError as ex:
|
||||||
raise ex
|
raise ex
|
||||||
except CatchableError as ex:
|
except CatchableError as ex:
|
||||||
warn "ignored an error", name=ex.name, msg=msg
|
warn "Ignored an error", name=ex.name, msg=msg
|
||||||
|
|
|
@ -92,7 +92,14 @@ proc open*(s: LPChannel): Future[void] =
|
||||||
|
|
||||||
method close*(s: LPChannel) {.async, gcsafe.} =
|
method close*(s: LPChannel) {.async, gcsafe.} =
|
||||||
s.closedLocal = true
|
s.closedLocal = true
|
||||||
|
# If remote is closed
|
||||||
|
# EOF will happepn here
|
||||||
|
# We can safely ignore in that case
|
||||||
|
# s.closed won't be true sadly
|
||||||
|
try:
|
||||||
await s.closeMessage()
|
await s.closeMessage()
|
||||||
|
except LPStreamEOFError:
|
||||||
|
discard
|
||||||
|
|
||||||
proc resetMessage(s: LPChannel) {.async.} =
|
proc resetMessage(s: LPChannel) {.async.} =
|
||||||
await s.conn.writeMsg(s.id, s.resetCode)
|
await s.conn.writeMsg(s.id, s.resetCode)
|
||||||
|
|
|
@ -29,6 +29,7 @@ type
|
||||||
Mplex* = ref object of Muxer
|
Mplex* = ref object of Muxer
|
||||||
remote*: Table[uint64, LPChannel]
|
remote*: Table[uint64, LPChannel]
|
||||||
local*: Table[uint64, LPChannel]
|
local*: Table[uint64, LPChannel]
|
||||||
|
handlers*: array[2, Table[uint64, Future[void]]]
|
||||||
currentId*: uint64
|
currentId*: uint64
|
||||||
maxChannels*: uint64
|
maxChannels*: uint64
|
||||||
|
|
||||||
|
@ -52,15 +53,23 @@ proc newStreamInternal*(m: Mplex,
|
||||||
result = newChannel(id, m.connection, initiator, name, lazy = lazy)
|
result = newChannel(id, m.connection, initiator, name, lazy = lazy)
|
||||||
m.getChannelList(initiator)[id] = result
|
m.getChannelList(initiator)[id] = result
|
||||||
|
|
||||||
proc cleanupChann(m: Mplex, chann: LPChannel, initiator: bool) {.async, inline.} =
|
proc cleanupChann(m: Mplex, chann: LPChannel, initiator: bool) {.async.} =
|
||||||
## call the channel's `close` to signal the
|
## call the channel's `close` to signal the
|
||||||
## remote that the channel is closing
|
## remote that the channel is closing
|
||||||
if not isNil(chann) and not chann.closed:
|
if not isNil(chann) and not chann.closed:
|
||||||
|
trace "cleaning up channel", id = chann.id
|
||||||
await chann.close()
|
await chann.close()
|
||||||
await chann.cleanUp()
|
await chann.cleanUp()
|
||||||
m.getChannelList(initiator).del(chann.id)
|
m.getChannelList(initiator).del(chann.id)
|
||||||
trace "cleaned up channel", id = chann.id
|
trace "cleaned up channel", id = chann.id
|
||||||
|
|
||||||
|
proc cleanupChann(chann: LPChannel) {.async.} =
|
||||||
|
trace "cleaning up channel", id = chann.id
|
||||||
|
await chann.reset()
|
||||||
|
await chann.close()
|
||||||
|
await chann.cleanUp()
|
||||||
|
trace "cleaned up channel", id = chann.id
|
||||||
|
|
||||||
method handle*(m: Mplex) {.async, gcsafe.} =
|
method handle*(m: Mplex) {.async, gcsafe.} =
|
||||||
trace "starting mplex main loop"
|
trace "starting mplex main loop"
|
||||||
try:
|
try:
|
||||||
|
@ -85,7 +94,7 @@ method handle*(m: Mplex) {.async, gcsafe.} =
|
||||||
of MessageType.New:
|
of MessageType.New:
|
||||||
let name = cast[string](data)
|
let name = cast[string](data)
|
||||||
channel = await m.newStreamInternal(false, id, name)
|
channel = await m.newStreamInternal(false, id, name)
|
||||||
trace "created channel", id = id, name = name, inititator = true
|
trace "created channel", id = id, name = name, inititator = initiator
|
||||||
if not isNil(m.streamHandler):
|
if not isNil(m.streamHandler):
|
||||||
let stream = newConnection(channel)
|
let stream = newConnection(channel)
|
||||||
stream.peerInfo = m.connection.peerInfo
|
stream.peerInfo = m.connection.peerInfo
|
||||||
|
@ -93,13 +102,13 @@ method handle*(m: Mplex) {.async, gcsafe.} =
|
||||||
proc handler() {.async.} =
|
proc handler() {.async.} =
|
||||||
tryAndWarn "mplex channel handler":
|
tryAndWarn "mplex channel handler":
|
||||||
await m.streamHandler(stream)
|
await m.streamHandler(stream)
|
||||||
# TODO closing stream
|
if not initiator:
|
||||||
# or doing cleanupChann
|
await m.cleanupChann(channel, false)
|
||||||
# will make go interop tests fail
|
|
||||||
# need to investigate why
|
|
||||||
|
|
||||||
asynccheck handler()
|
if not initiator:
|
||||||
continue
|
m.handlers[0][id] = handler()
|
||||||
|
else:
|
||||||
|
m.handlers[1][id] = handler()
|
||||||
of MessageType.MsgIn, MessageType.MsgOut:
|
of MessageType.MsgIn, MessageType.MsgOut:
|
||||||
trace "pushing data to channel", id = id,
|
trace "pushing data to channel", id = id,
|
||||||
initiator = initiator,
|
initiator = initiator,
|
||||||
|
@ -162,10 +171,16 @@ method close*(m: Mplex) {.async, gcsafe.} =
|
||||||
|
|
||||||
let
|
let
|
||||||
futs = await allFinished(
|
futs = await allFinished(
|
||||||
toSeq(m.remote.values).mapIt(it.reset()) &
|
toSeq(m.remote.values).mapIt(it.cleanupChann()) &
|
||||||
toSeq(m.local.values).mapIt(it.reset()))
|
toSeq(m.local.values).mapIt(it.cleanupChann()) &
|
||||||
|
toSeq(m.handlers[0].values).mapIt(it) &
|
||||||
|
toSeq(m.handlers[1].values).mapIt(it))
|
||||||
|
|
||||||
checkFutures(futs)
|
checkFutures(futs)
|
||||||
|
|
||||||
|
m.handlers[0].clear()
|
||||||
|
m.handlers[1].clear()
|
||||||
m.remote.clear()
|
m.remote.clear()
|
||||||
m.local.clear()
|
m.local.clear()
|
||||||
|
|
||||||
|
trace "mplex muxer closed"
|
||||||
|
|
Loading…
Reference in New Issue