/*
* The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
* (the "License"). You may not use this work except in compliance with the License, which is
* available at www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied, as more fully set forth in the License.
*
* See the NOTICE file distributed with this work for information regarding copyright ownership.
*/
package alluxio.worker.netty;
import alluxio.metrics.MetricsSystem;
import alluxio.network.protocol.RPCProtoMessage;
import alluxio.network.protocol.databuffer.DataBuffer;
import alluxio.network.protocol.databuffer.DataFileChannel;
import alluxio.network.protocol.databuffer.DataNettyBufferV2;
import alluxio.proto.dataserver.Protocol;
import alluxio.worker.block.BlockWorker;
import alluxio.worker.block.io.BlockReader;
import alluxio.worker.block.io.LocalFileBlockReader;
import com.codahale.metrics.Counter;
import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.concurrent.ExecutorService;
import javax.annotation.concurrent.NotThreadSafe;
/**
* This handler handles block read request. Check more information in {@link DataServerReadHandler}.
*/
@NotThreadSafe
final class DataServerBlockReadHandler extends DataServerReadHandler {
private static final Logger LOG = LoggerFactory.getLogger(DataServerBlockReadHandler.class);
/** The Block Worker which handles blocks stored in the Alluxio storage of the worker. */
private final BlockWorker mWorker;
/** The transfer type used by the data server. */
private final FileTransferType mTransferType;
/**
* The block read request internal representation.
*/
private final class BlockReadRequestInternal extends ReadRequestInternal {
final BlockReader mBlockReader;
/**
* Creates an instance of {@link BlockReadRequestInternal}.
*
* @param request the block read request
*/
BlockReadRequestInternal(Protocol.ReadRequest request) throws Exception {
super(request.getId(), request.getOffset(), request.getOffset() + request.getLength(),
request.getPacketSize());
mBlockReader = mWorker
.readBlockRemote(request.getSessionId(), request.getId(), request.getLockId());
mWorker.accessBlock(request.getSessionId(), mId);
((FileChannel) mBlockReader.getChannel()).position(mStart);
}
@Override
public void close() throws IOException {
if (mBlockReader != null) {
mBlockReader.close();
}
}
}
/**
* Creates an instance of {@link DataServerReadHandler}.
*
* @param executorService the executor service to run {@link PacketReader}s
* @param blockWorker the block worker
* @param fileTransferType the file transfer type
*/
DataServerBlockReadHandler(ExecutorService executorService, BlockWorker blockWorker,
FileTransferType fileTransferType) {
super(executorService);
mWorker = blockWorker;
mTransferType = fileTransferType;
}
@Override
protected boolean acceptMessage(Object object) {
if (!super.acceptMessage(object)) {
return false;
}
Protocol.ReadRequest request = ((RPCProtoMessage) object).getMessage().asReadRequest();
return request.getType() == Protocol.RequestType.ALLUXIO_BLOCK;
}
@Override
protected void initializeRequest(Protocol.ReadRequest request) throws Exception {
mRequest = new BlockReadRequestInternal(request);
}
@Override
protected DataBuffer getDataBuffer(Channel channel, long offset, int len) throws IOException {
LocalFileBlockReader blockReader =
(LocalFileBlockReader) ((BlockReadRequestInternal) mRequest).mBlockReader;
Preconditions.checkArgument(blockReader.getChannel() instanceof FileChannel,
"Only FileChannel is supported!");
switch (mTransferType) {
case MAPPED:
ByteBuf buf = channel.alloc().buffer(len, len);
try {
FileChannel fileChannel = (FileChannel) blockReader.getChannel();
Preconditions.checkState(fileChannel.position() == offset);
while (buf.writableBytes() > 0
&& buf.writeBytes(fileChannel, buf.writableBytes()) != -1) {
}
return new DataNettyBufferV2(buf);
} catch (Throwable e) {
buf.release();
throw e;
}
case TRANSFER: // intend to fall through as TRANSFER is the default type.
default:
return new DataFileChannel(new File(blockReader.getFilePath()), offset, len);
}
}
@Override
protected void incrementMetrics(long bytesRead) {
Metrics.BYTES_READ_REMOTE.inc(bytesRead);
}
/**
* Class that contains metrics for BlockDataServerHandler.
*/
private static final class Metrics {
private static final Counter BYTES_READ_REMOTE = MetricsSystem.workerCounter("BytesReadRemote");
private Metrics() {
} // prevent instantiation
}
}