Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion core/src/main/scala/kafka/api/ApiUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kafka.api
package kafka.api

import java.nio._
import java.nio.channels.GatheringByteChannel
import kafka.common._
import org.apache.kafka.common.network.TransportLayer

/**
* Helper functions specific to parsing or serializing requests and responses
Expand Down Expand Up @@ -107,5 +109,10 @@ object ApiUtils {
throw new KafkaException(name + " has value " + value + " which is not in the range " + range + ".")
else value
}

private[api] def hasPendingWrites(channel: GatheringByteChannel): Boolean = channel match {
case t: TransportLayer => t.hasPendingWrites
case _ => false
}

}
56 changes: 35 additions & 21 deletions core/src/main/scala/kafka/api/FetchResponse.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ import kafka.common.{TopicAndPartition, ErrorMapping}
import kafka.message.{MessageSet, ByteBufferMessageSet}
import kafka.api.ApiUtils._
import org.apache.kafka.common.KafkaException
import org.apache.kafka.common.network.TransportLayer
import org.apache.kafka.common.network.Send
import org.apache.kafka.common.network.MultiSend
import org.apache.kafka.common.network.{SSLTransportLayer, TransportLayer, Send, MultiSend}

import scala.collection._

Expand Down Expand Up @@ -55,6 +53,7 @@ case class FetchResponsePartitionData(error: Short = ErrorMapping.NoError, hw: L

class PartitionDataSend(val partitionId: Int,
val partitionData: FetchResponsePartitionData) extends Send {
private val emptyBuffer = ByteBuffer.allocate(0)
private val messageSize = partitionData.messages.sizeInBytes
private var messagesSentSize = 0
private var pending = false
Expand All @@ -71,15 +70,20 @@ class PartitionDataSend(val partitionId: Int,

override def writeTo(channel: GatheringByteChannel): Long = {
var written = 0L
if(buffer.hasRemaining)
if (buffer.hasRemaining)
written += channel.write(buffer)
if (!buffer.hasRemaining && messagesSentSize < messageSize) {
val bytesSent = partitionData.messages.writeTo(channel, messagesSentSize, messageSize - messagesSentSize)
messagesSentSize += bytesSent
written += bytesSent
if (!buffer.hasRemaining) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NP: could this just be
if (buffer.hasRemaining)
written += channel.write(buffer)
else{...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because the buffer is mutated.

if (messagesSentSize < messageSize) {
val bytesSent = partitionData.messages.writeTo(channel, messagesSentSize, messageSize - messagesSentSize)
messagesSentSize += bytesSent
written += bytesSent
}
if (messagesSentSize >= messageSize && hasPendingWrites(channel))
channel.write(emptyBuffer)
}
if (channel.isInstanceOf[TransportLayer])
pending = channel.asInstanceOf[TransportLayer].hasPendingWrites

pending = hasPendingWrites(channel)

written
}

Expand Down Expand Up @@ -112,6 +116,8 @@ case class TopicData(topic: String, partitionData: Map[Int, FetchResponsePartiti

class TopicDataSend(val dest: String, val topicData: TopicData) extends Send {

private val emptyBuffer = ByteBuffer.allocate(0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that we can just reference ErrorMapping.EmptyByteBuffer?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could do that. A few concerns: it's a bit strange that the empty buffer lives in ErrorMapping, it doesn't seem to be used anywhere at the moment and ByteBuffer has a number of mutation methods (although most of them don't do anything for an empty buffer). If you think it's worth having a shared empty buffer, maybe we could put it in ApiUtils as a private[api] value?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Then what you had is fine. Did the unit tests pass?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they passed when I ran them locally.


private var sent = 0L

private var pending = false
Expand All @@ -135,14 +141,16 @@ class TopicDataSend(val dest: String, val topicData: TopicData) extends Send {
throw new KafkaException("This operation cannot be completed on a complete request.")

var written = 0L
if(buffer.hasRemaining)
if (buffer.hasRemaining)
written += channel.write(buffer)
if(!buffer.hasRemaining && !sends.completed) {
written += sends.writeTo(channel)
if (!buffer.hasRemaining) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as above

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explained above, mutation makes code harder to reason about, I know. :)

if (!sends.completed)
written += sends.writeTo(channel)
if (sends.completed && hasPendingWrites(channel))
written += channel.write(emptyBuffer)
}

if (channel.isInstanceOf[TransportLayer])
pending = channel.asInstanceOf[TransportLayer].hasPendingWrites
pending = hasPendingWrites(channel)

sent += written
written
Expand Down Expand Up @@ -245,6 +253,9 @@ case class FetchResponse(correlationId: Int,


class FetchResponseSend(val dest: String, val fetchResponse: FetchResponse) extends Send {

private val emptyBuffer = ByteBuffer.allocate(0)

private val payloadSize = fetchResponse.sizeInBytes

private var sent = 0L
Expand Down Expand Up @@ -272,15 +283,18 @@ class FetchResponseSend(val dest: String, val fetchResponse: FetchResponse) exte
throw new KafkaException("This operation cannot be completed on a complete request.")

var written = 0L
if(buffer.hasRemaining)

if (buffer.hasRemaining)
written += channel.write(buffer)
if(!buffer.hasRemaining && !sends.completed) {
written += sends.writeTo(channel)
if (!buffer.hasRemaining) {
if (!sends.completed)
written += sends.writeTo(channel)
if (sends.completed && hasPendingWrites(channel))
written += channel.write(emptyBuffer)
}
sent += written

if (channel.isInstanceOf[TransportLayer])
pending = channel.asInstanceOf[TransportLayer].hasPendingWrites
sent += written
pending = hasPendingWrites(channel)

written
}
Expand Down