我们都知道,TFS的写文件流程是由TFS Client来发起的,所以我们就从TFS Client出发。

首先来讲在Tfs Client都发生了什么事情?

1. TFS Client使用int putFile(TfsFile &tfsfile, VSTRING ¶m, int unique)函数将一个本地文件写入TFS中。其中tfsfile作为本次写入操作的tfs文件的句柄,param中包含本地文件名,包含但并不一定包含tfs文件名和后缀名,unique参数指示接下来调用TfsFile的saveUniqueFile还是saveFile接口,两者区别在于是否需要查询并更新排重数据库。我们暂时follow TfsFile的saveFile()接口。

2.TfsFile的saveFile(char *filename, char *tfsname, char *suffix)接口主要作用是打开本地文件,将其内容读入临时缓冲区,然后使用tfsOpen打开TfsFile,接下来调用tfsWrite()接口将每次读到的内容写入tfs,最后调用tfsClose()完成整个写本地文件到TFS的流程。

3.TfsFile的tfsOpen(char *fileName, char *suffix, int mode)接口首先会从fileName中得到一个block id和fileid,如果fileName指针为NULL,则blockid和fileid均为0,或者为某个指定的blockid或者fileid,换句话说就是TfsClient知道要把数据写到什么位置上去。但是如果blockid和fileid均为0,则需要调用TfsSession的createBlockInfo接口,从NameServer获得一个可写的BlockId,这个功能实际是由TfsSession的getBlockInfoEx()接口完成,它向NameServer发送一个GetBlockInfoMessage来获取一个可以写入的blockid或者询问请求中包含的blockid是否可以写入,以及该block在哪个DataServer上。NameServer如何处理这个消息由下文给出。

3.TfsFile的tfsWrite()接口首先要判断本次写入操作的TfsFile句柄是否是打开状态,以及打开模式是否为WRITE_MODE。然后组装一个WriteDataMessage,将这个Message发送到DataServer。

4.TfsFile的tfsClose()接口的功能是向DataServer发送CloseFileMessage。DataServer如何处理3,4中提到的两种消息下文给出。

接下来我们看NameServer如何处理GetBlockInfoMessage。

1.NameServer在接受到GetBlockInfoMessage后,会把这个消息push到taskQueueThread_的一个消息队列中去。taskQueueThread实际是一个线程组。每个线程启动后的动作就是尝试从消息队列冲取出Message,然后交给bool FSNameSystem::handlePacketQueue(tbnet::Packet *packet, void *args)处理。

2.bool FSNameSystem::handlePacketQueue()根据取得消息的类型为GET_BLOCK_INFO_MESSAGE,调用getBlockInfo()函数进行处理。该函数首先从metaManagement中获取Meta数据,判断集群中的dataserver数量是否为0,如果为0,直接向客户端发送一条错误信息,否则构造一个SetBlockInfoMessage作为对本次消息处理的回复消息。如果需要一个新的blockid,需要先判断这个block是否正在进行复制或者compact操作。如果有,则直接返回给客户端一个错误消息。否则调用int32_t MetaManagement::writeBlockInfo(uint32_t& blockId, int32_t mode,
uint32_t& version, uint32_t & leaseId, VUINT64& serverList)更新meta data。接下来需要注册一个leaseid,同时获取blockid所对应的DataServer list。