WriteBlockHeader headerToReceive = new WriteBlockHeader(
versionAndOpcode);
headerToReceive.readFields(in);
int namespaceid = headerToReceive.getNamespaceId();
Block block = new Block(headerToReceive.getBlockId(),
dataXceiverServer.estimateBlockSize, headerToReceive.getGenStamp());
LOG.info("Receiving block " + block +
" src: " + remoteAddress +
" dest: " + localAddress);
int pipelineSize = headerToReceive.getPipelineDepth(); // num of datanodes in entire pipeline
boolean isRecovery = headerToReceive.isRecoveryFlag(); // is this part of recovery?
String client = headerToReceive.getClientName(); // working on behalf of this client
boolean hasSrcDataNode = headerToReceive.isHasSrcDataNode(); // is src node info present
if (hasSrcDataNode) {
srcDataNode = headerToReceive.getSrcDataNode();
}
int numTargets = headerToReceive.getNumTargets();
DatanodeInfo targets[] = headerToReceive.getNodes();
DataOutputStream mirrorOut = null; // stream to next target
DataInputStream mirrorIn = null; // reply from next target
DataOutputStream replyOut = null; // stream to prev target
Socket mirrorSock = null; // socket to next target
BlockReceiver blockReceiver = null; // responsible for data handling
String mirrorNode = null; // the name:port of next target
String firstBadLink = ""; // first datanode that failed in connection setup
updateCurrentThreadName("receiving block " + block + " client=" + client);
try {
// open a block receiver and check if the block does not exist
blockReceiver = new BlockReceiver(namespaceid, block, in,
s.getRemoteSocketAddress().toString(),
s.getLocalSocketAddress().toString(),
isRecovery, client, srcDataNode, datanode);
// get a connection back to the previous target
replyOut = new DataOutputStream(new BufferedOutputStream(
NetUtils.getOutputStream(s, datanode.socketWriteTimeout),
SMALL_BUFFER_SIZE));
//
// Open network conn to backup machine, if
// appropriate
//
if (targets.length > 0) {
InetSocketAddress mirrorTarget = null;
// Connect to backup machine
mirrorNode = targets[0].getName();
mirrorTarget = NetUtils.createSocketAddr(mirrorNode);
mirrorSock = datanode.newSocket();
try {
int timeoutValue = datanode.socketTimeout +
(datanode.socketReadExtentionTimeout * numTargets);
int writeTimeout = datanode.socketWriteTimeout +
(datanode.socketWriteExtentionTimeout * numTargets);
NetUtils.connect(mirrorSock, mirrorTarget, timeoutValue);
mirrorSock.setSoTimeout(timeoutValue);
mirrorSock.setSendBufferSize(DEFAULT_DATA_SOCKET_SIZE);
mirrorOut = new DataOutputStream(
new BufferedOutputStream(
NetUtils.getOutputStream(mirrorSock, writeTimeout),
SMALL_BUFFER_SIZE));
mirrorIn = new DataInputStream(NetUtils.getInputStream(mirrorSock));
// Write header: Copied from DFSClient.java!
WriteBlockHeader headerToSend = new WriteBlockHeader(
DataTransferProtocol.DATA_TRANSFER_VERSION, namespaceid,
block.getBlockId(), block.getGenerationStamp(), pipelineSize,
isRecovery, hasSrcDataNode, srcDataNode, targets.length - 1, targets,
client);
headerToSend.writeVersionAndOpCode(mirrorOut);
headerToSend.write(mirrorOut);
blockReceiver.writeChecksumHeader(mirrorOut);
mirrorOut.flush();
// read connect ack (only for clients, not for replication req)
if (client.length() != 0) {
firstBadLink = Text.readString(mirrorIn);
if (LOG.isDebugEnabled() || firstBadLink.length() > 0) {
LOG.info("Datanode " + targets.length +
" got response for connect ack " +
" from downstream datanode with firstbadlink as " +
firstBadLink);
}
}
} catch (IOException e) {
if (client.length() != 0) {
Text.writeString(replyOut, mirrorNode);
replyOut.flush();
}
IOUtils.closeStream(mirrorOut);
mirrorOut = null;
IOUtils.closeStream(mirrorIn);
mirrorIn = null;
IOUtils.closeSocket(mirrorSock);
mirrorSock = null;
if (client.length() > 0) {
throw e;
} else {
LOG.info(datanode.getDatanodeInfo() + ":Exception transfering block " +
block + " to mirror " + mirrorNode +
". continuing without the mirror.\n" +
StringUtils.stringifyException(e));
}
}
}
// send connect ack back to source (only for clients)
if (client.length() != 0) {
if (LOG.isDebugEnabled() || firstBadLink.length() > 0) {
LOG.info("Datanode " + targets.length +
" forwarding connect ack to upstream firstbadlink is " +
firstBadLink);
}
Text.writeString(replyOut, firstBadLink);
replyOut.flush();
}
// receive the block and mirror to the next target
String mirrorAddr = (mirrorSock == null) ? null : mirrorNode;
long totalReceiveSize = blockReceiver.receiveBlock(mirrorOut, mirrorIn, replyOut,
mirrorAddr, null, targets.length);
// if this write is for a replication request (and not
// from a client), then confirm block. For client-writes,
// the block is finalized in the PacketResponder.
if (client.length() == 0) {
datanode.notifyNamenodeReceivedBlock(namespaceid, block, null);
LOG.info("Received block " + block +
" src: " + remoteAddress +
" dest: " + localAddress +
" of size " + block.getNumBytes());
} else {
// Log the fact that the block has been received by this datanode and
// has been written to the local disk on this datanode.
LOG.info("Received Block " + block +
" src: " + remoteAddress +
" dest: " + localAddress +
" of size " + block.getNumBytes() +
" and written to local disk");
}
if (datanode.blockScanner != null) {
datanode.blockScanner.addBlock(namespaceid, block);