TcpConnection: forward received data to handler immediately without concatenating buffers

For these reasons:

 - pipeline effect will allow to start processing on the first part of the
   data immediately in parallel
 - data in `Received` messages is now always a simple ByteStrings which will
   improve iteration speed in the next layer
 - code becomes simpler
This commit is contained in:
Johannes Rudolph 2013-04-03 16:10:49 +02:00
parent 88f7e28c6b
commit fc6b7830a9
2 changed files with 18 additions and 29 deletions

View file

@ -122,7 +122,7 @@ private[io] abstract class TcpConnection(val channel: SocketChannel,
}
def doRead(handler: ActorRef, closeCommander: Option[ActorRef]): Unit = {
@tailrec def innerRead(buffer: ByteBuffer, receivedData: ByteString, remainingLimit: Int): ReadResult =
@tailrec def innerRead(buffer: ByteBuffer, remainingLimit: Int): ReadResult =
if (remainingLimit > 0) {
// never read more than the configured limit
buffer.clear()
@ -131,33 +131,22 @@ private[io] abstract class TcpConnection(val channel: SocketChannel,
val readBytes = channel.read(buffer)
buffer.flip()
val totalData = receivedData ++ ByteString(buffer)
if (TraceLogging) log.debug("Read [{}] bytes.", readBytes)
if (readBytes > 0) handler ! Received(ByteString(buffer))
readBytes match {
case `maxBufferSpace` innerRead(buffer, totalData, remainingLimit - maxBufferSpace)
case x if totalData.length > 0 GotCompleteData(totalData)
case 0 NoData
case -1 EndOfStream
case `maxBufferSpace` innerRead(buffer, remainingLimit - maxBufferSpace)
case x if x >= 0 AllRead
case -1 EndOfStream
case _
throw new IllegalStateException("Unexpected value returned from read: " + readBytes)
}
} else MoreDataWaiting(receivedData)
} else MoreDataWaiting
val buffer = bufferPool.acquire()
try innerRead(buffer, ByteString.empty, ReceivedMessageSizeLimit) match {
case NoData
if (TraceLogging) log.debug("Read nothing.")
selector ! ReadInterest
case GotCompleteData(data)
if (TraceLogging) log.debug("Read [{}] bytes.", data.length)
handler ! Received(data)
selector ! ReadInterest
case MoreDataWaiting(data)
if (TraceLogging) log.debug("Read [{}] bytes. More data waiting.", data.length)
handler ! Received(data)
self ! ChannelReadable
try innerRead(buffer, ReceivedMessageSizeLimit) match {
case AllRead selector ! ReadInterest
case MoreDataWaiting self ! ChannelReadable
case EndOfStream
if (TraceLogging) log.debug("Read returned end-of-stream")
doCloseConnection(handler, closeCommander, closeReason)
@ -307,10 +296,9 @@ private[io] abstract class TcpConnection(val channel: SocketChannel,
*/
private[io] object TcpConnection {
sealed trait ReadResult
object NoData extends ReadResult
object EndOfStream extends ReadResult
case class GotCompleteData(data: ByteString) extends ReadResult
case class MoreDataWaiting(data: ByteString) extends ReadResult
object AllRead extends ReadResult
object MoreDataWaiting extends ReadResult
/**
* Used to transport information to the postStop method to notify