integrate NetworkFailureInjector and add first test

- rework socket pipeline to transform protobuf into case classes and
  back
- introduce NetworkOp messages for that purpose
- make API asynchronous (because it is, really) and add Done
  notification for all server operations; enter(...) is still
  synchronous, because that is its only purpose in life
- factor out mkPipeline in NettyRemoteTransport, enabling the very slick
  TestConductorTransport (essentially a one-liner)
- switch NetworkFailureInjector from Channel{Up,Down}streamHandler to
  subclassing SimpleChannelHandler, because otherwise deadlocks
  occurred, not sure why (but SCH is the recommended way from the netty
  docs, so there may well be a reason)
This commit is contained in:
Roland 2012-05-04 22:33:08 +02:00
parent 0314b9abbb
commit 9266ac451b
15 changed files with 538 additions and 269 deletions

View file

@ -30,14 +30,12 @@ class NettyRemoteServer(val netty: NettyRemoteTransport) {
Executors.newCachedThreadPool(netty.system.threadFactory),
Executors.newCachedThreadPool(netty.system.threadFactory))
private val executionHandler = new ExecutionHandler(netty.executor)
// group of open channels, used for clean-up
private val openChannels: ChannelGroup = new DefaultDisposableChannelGroup("akka-remote-server")
private val bootstrap = {
val b = new ServerBootstrap(factory)
b.setPipelineFactory(makePipeline())
b.setPipelineFactory(netty.mkPipeline(new RemoteServerHandler(openChannels, netty), false))
b.setOption("backlog", settings.Backlog)
b.setOption("tcpNoDelay", true)
b.setOption("child.keepAlive", true)
@ -45,8 +43,6 @@ class NettyRemoteServer(val netty: NettyRemoteTransport) {
b
}
protected def makePipeline(): ChannelPipelineFactory = new RemoteServerPipelineFactory(openChannels, executionHandler, netty)
@volatile
private[akka] var channel: Channel = _
@ -79,26 +75,6 @@ class NettyRemoteServer(val netty: NettyRemoteTransport) {
}
}
class RemoteServerPipelineFactory(
val openChannels: ChannelGroup,
val executionHandler: ExecutionHandler,
val netty: NettyRemoteTransport) extends ChannelPipelineFactory {
import netty.settings
def getPipeline: ChannelPipeline = {
val lenDec = new LengthFieldBasedFrameDecoder(settings.MessageFrameSize, 0, 4, 0, 4)
val lenPrep = new LengthFieldPrepender(4)
val messageDec = new RemoteMessageDecoder
val messageEnc = new RemoteMessageEncoder(netty)
val authenticator = if (settings.RequireCookie) new RemoteServerAuthenticationHandler(settings.SecureCookie) :: Nil else Nil
val remoteServer = new RemoteServerHandler(openChannels, netty)
val stages: List[ChannelHandler] = lenDec :: messageDec :: lenPrep :: messageEnc :: executionHandler :: authenticator ::: remoteServer :: Nil
new StaticChannelPipeline(stages: _*)
}
}
@ChannelHandler.Sharable
class RemoteServerAuthenticationHandler(secureCookie: Option[String]) extends SimpleChannelUpstreamHandler {
val authenticated = new AnyRef