Hadoop HDFS源码学习笔记(六)--fetchBlockByteRange

client端需要从datanode端读取数据,当顺序的读取block的时候,会调用到fetchBlockByteRange函数,该函数中,有一个死循环,在循环内部首先使用函数getBlockAt()获得最新的block的信息,然后选择要链接的datanode的信息得到DNAddrPair类型的对象,从该结构中得到DatanodeInfo以及datanode的InetSocketAddress,然后调用函数getBlockReader函数获得一个BlockReader类型的对象。

getBlockReader函数分析:

1、首先根据dnAddr判断是否在client端有跟该datanode的cache的连接,如果存在cache的连接,则会调用DFSClient的getLocalBlockReader函数来执行后续的操作,先不分析这类情况。

2、for循环,主要目的是允许retry连接,次数为3

循环中:

(1)根据dnAddr去一个SocketCache类型的变量中去取得cache的Socket

如果不能从socketCache中得到cache的Socket,则会使用DFSClient的socketFactory的createSocket函数创建一个新的socket,然后执行connect连接操作

(2)调用BlockReaderFactory的newBlockReader方法new一个BlockReader类型的对象,单步跟踪进去,发现又进行了一次封装,facoty类函数封装了RemoteBlockReader2的newBlockReader方法,在该方法内部,使用NetUtils的getOutputSream方法返回了一个(OutputStream)SocketOutputStream对象,利用该对象创建了一个BufferedOutputStream,然后利用该对象创建了一个DataOutputStream对象out,然后利用out创建了一个Sender对象,调用sender的readBlock方法。

Sender的readBlock方法,得到了一个OpReadBlockProto对象,并创建了该对象的header的PB的Message,然后调用自身的send函数,发送了一个ReanBlock类型的命令,在send函数中调用了DataOutputStream的Flush函数。

回到RemoteBlockReader2的newBlockReader方法:创建了一个SocketInputStream对象,然后利用该对象创建了一个DataInputStream类型的对象,之后创建了一系列的response,checksum的proto的message信息,创建的datachecksum对象,并对firstChunkOffset进行了验证检测。

然后调用RemoteBlockReader2的构造函数,创建了一个RemoteBlockReader2的对象,然后返回

(3)调用RemoteBlockReader2的readAll方法,该方法封装了BlockReaderUtil的readAll方法, readAll方法,则又循环读入,封装的是RemoteBlockReader2的read方法,在read方法内部,首先判断,一个java.nio.ByteBufer类型的curPacketBuf是否为null,或者(jana.nio.ByteBuffer类型的curDataSlice的remaining为0,且bytesNeededToFinish大于0)则会调用RemoteBlockReader2的readNextPacket()方法。在readNextPacket函数中调用了函数readPacketHeader方法,该方法最终会使用到ReadableByteChannel类型的RemoteBlockReader2的in成员变量来读取packet的header,并将读取过来的ByteBuffer类型的headerBuf中的packetheader字段放入到PacketHeader类型的成员变量curHeader中。

调用resetPacketBuffer函数,根据计算出来的checksumsLen和packetheader中的dataLen重设curPacketBuf以及curDataSlice的字段内容。调用readChannelFully函数从socket连接中读取数据到curPacketBuf中。然后根据用户请求的offset和得到的packetHeader中存储的该packet在block中的offset计算得到应该读取的position,然后利用该newPos对curDataSlice进行position设置。注意在radChannelFuly函数之后会根据curHeader存放的当前packet中的data的length来更新bytesNeededToFini。sh成员变量,直到该变量小于0才判定已经读完用户请求长度的数据,然后接受最后一个空包,然后发送给datanode一个readResult。

跳出到RemoteBlockReader2的read函数中,会发现首先需要判断当前的packet中的dataLen和用户请求的len的长度大小,得到小的一个值nRead,然后从curdataSlice数组中获得nRead长度的数据。然后就跳回到BlockReaderUtil的readAll函数中,该函数会根据当前的nRead值以及之前的累积读到的数据长度和用户请求的len来判定是否继续执行read操作。

至此就使用BlockReader读取了用户请求的数据,然后会关闭当前的BlockReader,并返回,到目前就完成的fecthBlockByteRange的函数操作,从之前的分析可以了解到,该函数执行的操作是根据block的元数据信息从一个datanode上读取block中的数据

现将在该追踪过程中画的序列图和相关类图附上,以便理清思路,源码就不贴了,因为这次用的是23的代码,本机上没有,是在台式机上追踪的,两台电脑没互通呵呵。

相关阅读:

Hadoop HDFS源码学习笔记(六)--fetchBlockByteRange

Hadoop HDFS源码学习笔记(六)--fetchBlockByteRange

相关推荐