DFSOutputStream

        客户端负责数据写入处理的核心类是DFSOutputStream,该类是DFSClient的内部类,同时它的内部包含三个内部类:数据包发送器DataStreamer、数据包确认处理器ResponseProcessor和数据包封装器Packet。

      class DFSOutputStream extends FSOutputSummer implements Syncable{}

 

private Socket s; //客户端与副本复制流水线中第一个存储节点的连接

boolean closed = false; //写操作是否关闭

private String src; // 文件路径

private DataOutputStream blockStream; // 写入数据的IO流

private DataInputStream blockReplyStream; //读取数据包确认的IO流

private Block block; private Token accessToken;

private DataChecksum checksum; //数据校验和

private LinkedList dataQueue = new LinkedList(); //等待发送的数据包队列

private LinkedList ackQueue = new LinkedList(); //等待接受的数据包队列

private Packet currentPacket = null;

private int maxPackets = 80; // each packet 64K, total 5MB

// private int maxPackets = 1000; // each packet 64K, total 64MB

private DataStreamer streamer = new DataStreamer(); //数据包发送

private ResponseProcessor response = null; //数据包确认接受,一个数据块对应一个确认处理线程

private long bytesCurBlock = 0; // bytes writen in current block

private int packetSize = 0; // write packet size, including the header.

private int chunksPerPacket = 0; //一个数据包最多包含多少个校验块

private DatanodeInfo[] nodes = null; // list of targets for current block

private ArrayList excludedNodes = new ArrayList();

private volatile boolean hasError = false; private volatile int errorIndex = 0;//出错的数据节点

private volatile IOException lastException = null; private long artificialSlowdown = 0;

private long lastFlushOffset = 0; // offset when flush was invoked

private boolean persistBlocks = false; // persist blocks on namenode

private int recoveryErrorCount = 0; // number of times block recovery failed

private int maxRecoveryErrorCount = 5; // try block recovery 5 times

private volatile boolean appendChunk = false; // appending to existing partial block

private long initialFileSize = 0; // at time of file open private Progressable progress;

private short blockReplication; // replication factor of file

 

private class Packet {

客户端向第一个存储节点发送的数据是按照数据包的形式来组织的,以此来提高网络IO的效

ByteBuffer buffer;            
byte[]  buf;                  // 数据缓存区   
long    seqno;               // 数据包在数据块中的序列号   
long    offsetInBlock;       // 数据包在数据块中的偏移位置   
boolean lastPacketInBlock;   // 是否是数据块的最后一个数据包   
int     numChunks;           // 数据包当前存放了多少个校验块   
int     maxChunks;           // 数据包最多可有多少个校验块   
int     dataStart;                // 数据在该数据包中的开始位置   
int     dataPos;              // 当前的数据写入位置  
int     checksumStart;        // 校验数据在该数据包中的开始位置   
int     checksumPos;          // 当前的校验数据写入位置

 方法有

writeData:将数据写入到缓冲区中 writeChecksum:将checksum写入到缓冲区中 getBuffer:将数据从buf拷贝到buffer

DataStreamer把dataQueue队列中的packet发送到目标数据节点上。

private class DataStreamer extends Daemon {  

 DataStreamer从namenode取回块的id和位置,并将packet发送给datanode。当所有的packet发送完毕,并收到每个块的ack,DataStreamer关闭当前块当没有Block或申请的一个Block已满时,它会调用ClientProtocol的addBlock远程方法向NameNode申请一个LocatedBlock,也就是要知道它应该要把这个Block的packet发送到那些DataNode节点上。另外,用户不能一味的发送数据,否则缓存扛不住,所以就有一个限制了,也就是总的缓存数据不能超过maxPackets个packet。

 

客户端都要确认每一个数据包是否被所有的存储节点所真确接受了,如果有一个存储节点没有真确接受,则客户端就需要立即回复当前数据

 

private class ResponseProcessor extends Thread {  

 

ResponseProcessor负责处理datanode返回的应答,当一个packet的应答到达时,该packet从ackQueue中删除。关键的属性有如下这些:

closed:ResponseProcessor是否关闭

targets:目标datanode,每个packet只有收到targets所表示的所有datanode的ack才算数据发送成功

lastPacketInBlock:是否是块的最后一个packet

 

你可能感兴趣的:(Hadoop)