/** * Copyright 2016 LinkedIn Corp. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ package com.github.ambry.network; import com.github.ambry.utils.SystemTime; import com.github.ambry.utils.Time; import java.io.IOException; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Transmission used to speak plain text to the underlying channel. */ public class PlainTextTransmission extends Transmission { private static final Logger logger = LoggerFactory.getLogger(PlainTextTransmission.class); public PlainTextTransmission(String connectionId, SocketChannel socketChannel, SelectionKey key, Time time, NetworkMetrics metrics) { super(connectionId, socketChannel, key, time, metrics); } /** * Prepare is a no op for Plaintext * @throws IOException */ @Override public void prepare() throws IOException { } /** * Plain text channel is always ready to accept read and write calls * @return true */ @Override public boolean ready() { return true; } /** * Reads a sequence of bytes from the channel into the {@link NetworkReceive} * * @return true if the read is complete, false otherwise * @throws IOException if some other I/O error occurs */ @Override public boolean read() throws IOException { if (!hasReceive()) { networkReceive = new NetworkReceive(getConnectionId(), new BoundedByteBufferReceive(), time); } long startTimeMs = SystemTime.getInstance().milliseconds(); long bytesRead = networkReceive.getReceivedBytes().readFrom(socketChannel); long readTimeMs = SystemTime.getInstance().milliseconds() - startTimeMs; logger.trace("Bytes read " + bytesRead + " from {} using key {} Time: {}", socketChannel.socket().getRemoteSocketAddress(), getConnectionId(), readTimeMs); if (bytesRead > 0) { metrics.plaintextReceiveTimePerKB.update(readTimeMs * 1024 / bytesRead); } return networkReceive.getReceivedBytes().isReadComplete(); } /** * Writes a sequence of bytes to the channel from the payload in {@link NetworkSend} * * @return true if {@link Send} in {@link NetworkSend} is completely written to the channel, false otherwise * @throws IOException If some other I/O error occurs */ @Override public boolean write() throws IOException { Send send = networkSend.getPayload(); if (send == null) { throw new IllegalStateException("Registered for write interest but no response attached to key."); } long startTimeMs = SystemTime.getInstance().milliseconds(); long bytesWritten = send.writeTo(socketChannel); long writeTimeMs = SystemTime.getInstance().milliseconds() - startTimeMs; logger.trace("Bytes written {} to {} using key {} Time: {}", bytesWritten, socketChannel.socket().getRemoteSocketAddress(), getConnectionId(), writeTimeMs); if (bytesWritten > 0) { metrics.plaintextSendTimePerKB.update(writeTimeMs * 1024 / bytesWritten); } return send.isSendComplete(); } /** * Close the connection for the socket channel */ @Override public void close() { clearReceive(); clearSend(); key.attach(null); key.cancel(); try { socketChannel.socket().close(); socketChannel.close(); } catch (IOException e) { metrics.selectorCloseSocketErrorCount.inc(); logger.error("Exception closing connection to node {}:", getConnectionId(), e); } } /** * Actions to be taken on completion of {@link Send} in {@link NetworkSend} */ @Override public void onSendComplete() { long sendTimeMs = SystemTime.getInstance().milliseconds() - networkSend.getSendStartTimeInMs(); networkSend.onSendComplete(); double sendBytesRate = networkSend.getPayload().sizeInBytes() / ((double) sendTimeMs / SystemTime.MsPerSec); metrics.plaintextSendBytesRate.mark((long) sendBytesRate); } /** * Actions to be taken on completion of {@link BoundedByteBufferReceive} in {@link NetworkReceive} */ @Override public void onReceiveComplete() { long receiveTimeMs = SystemTime.getInstance().milliseconds() - networkReceive.getReceiveStartTimeInMs(); double receiveBytesRate = networkReceive.getReceivedBytes().sizeRead() / ((double) receiveTimeMs / SystemTime.MsPerSec); metrics.plaintextReceiveBytesRate.mark((long) receiveBytesRate); } }