在DFSClient写文件的时候,对于文件的每一个block,生成一个pipeline,然后按照这个pipeline进行数据传输,但是可能在数据传输过程中,DFSClient发生中断,例如断网等,此时该block在NameNode中处于UnderConstruction状态,该block所在的文件的写锁(通过LeaseManager实现)被该DFSClient占据着,无法释放。为此LeaseManager会对超过一定时间不活跃的DFSClient所占用的文件进行Recovery。
同时,BlockInfoUnderConstruction类有一个成员变量replicas用于存放“expected DataNodes which make up of the pipeline for that Block”. 该成员变量是在pipeline生成之后构造的,也就是说它并不用于指导生成pipeline,它的用途即用于Recovery。需要说明的是,在BlockInfoUnderConstruction的基类BlockInfo中有一个变量triplets用于存在block所有的replication所处的DataNodeStorageInfo。replicas记录的是"expected DataNodes",而triplets记录的是“stored DataNodes”。
Recovery大致过程如下:
1)发生在NameNode中的部分
1. 若文件的所有block都已经处于completed状态,则close文件,并将文件从leaseManager移出,即释放写锁,Recovery过程结束;
2. 若文件的最后一个block处于committed状态,则意味着该block已经写完毕,只是replication数目不够,只需等待block replication流程将该block复制足够的备份即可;
3. 若文件的最后一个block处于UnderConstruction/UnderRecovery状态,则从block的replicas中选择出一个DataNode作为本次Recovery的Primary DataNode;当被选择出的DataNode在下次向NameNode heartbeat时,NameNode会给其返还DNA_RECOVERBLOCK命令
2)发生在DataNode中的部分
1. DataNode在收到DNA_RECOVERBLOCK命令之后,给该命令的中携带的每一个target DataNode发送RPC调用,检测那些DataNode上面是否有对应的block;
2. 对于存在这个block的DN(DataNode),检测这些block的状态,找出长度最小的block,并将所有DN上的这个block都truncate到最小长度;
3. 给NameNode发送commitBlockSynchronization RPC调用,通知NameNode,NameNode会将文件最后一个block标记为committed状态或completed状态,并关闭文件,LeaseManager释放该文件的写锁。