packet的大小,65557,一个packet有127个chunk,一个chunk有512字节,他的checksum为4个字节,
写入的时候,每512个字节调用一次加入到packet(最后一个可以不满512字节,close或者flush的时候)
每个block有多个packet, 默认64M
客户端发送读取请求在DFSClient的newBlockReader中
调用namenode增加一个新的块
org.apache.hadoop.hdfs.protocol.ClientProtocol.addBlock
调用namenode定位一个块
public abstract org.apache.hadoop.hdfs.protocol.LocatedBlock
向namenode申请create一个文件:
public abstract void org.apache.hadoop.hdfs.protocol.ClientProtocol.create
inode体系是用loadfsimage中来的,也可能中途增加再写入回去。
ResponseProcessor会处理ack队列,BlockReceiver的verifyChunks会校验chekcsum
向本地磁盘写入数据和向另外一个datanode发送数据都在BlockReceiver的receivePacket()中,先向datanode发送数据,然后本地再校验checksum和写入数据到磁盘,退出这个方法后,再向datanode写一个0,表示传送完成。
每次写入数据到磁盘(一次receive后,都会向PacketResponder的ackQueue入队一个ack消息,然后另外一个线程取出来,并且如果不是最后一个datanode,就等待后面的datanode的ack。然后再看是否这个block全部搞完了,搞完了就通知下namenode,在发送ack到前面一个datanode或者客户端)
在blockReceiver.receiveBlock方法中,主要完成两件事情
a.启动一个PacketResponder
b.receivePacket
a.将消息转发给下一台
b.写入文件到临时文件
c.向PacketResponder的队列加入一个消息
PacketResponder从队列取本地或者下一台的返回(本地的直接从队列取出,下一台的从mirrorIn中取出)
lastPacketInBlock的判断方式是:
boolean lastPacketInBlock = (buf.get() != 0); (看下包的协议是怎么规定的)
当发现是最后一个packet的时候,调用:
datanode.data.finalizeBlock(block);
这里会将临时目录的文件移动到current目录,并删除临时目录的文件.
writer.syncFs();是刷新数据到服务器的临时目录上
writer.close();是让服务器完成finalizeBlock的动作,然后才可以查询到。
这里先写临时目录,很大一个原因是这样拷贝一次后,新的快将是一个连续的磁盘快,提高后来读取的效率。
事实上,hbse的每次hlog的写入,都是writer.syncFs();写入到服务器上去了的。然后在日志滚动等的时候调用writer.close()正式完成写入。当然,如果写入的log大小超过了一个块,也会写到服务器上并可以查询的。因为上面的分析中,是lastpacket(of a block)的时候从临时变为正式。但这些快都是一个文件的,只有rollLog后才会有新的文件.
inode体系没有datanode的信息,在FSNameSystem.getBlockLocationsInternal中(读取文件的块信息),从FSNameSystem的blocksMap中取出来的。放在DatanodeDescriptor中,再把DatanodeDescriptor各个放到machineSet,最后和block一起创建LocatedBlock,把所有的快放到LocatedBlocks中,再通过clusterMap排序后返回.