TFS分布式文件系统学习总结(4)-文件写流程详解

本小节主要对TFS分布式文件系统客户端写文件的流程进行讲解,在这里先上主要操作流程图:

在这里我们分四个请求的思路去分析:

1、GET_BLOCK_INFO_MESSAGE REQ/ACK:

(1) client端发送请求流程(创建文件):
client端调用tfs_open()函数触发消息GET_BLOCK_INFO_MESSAGE为例,由于是创建文件所以通过tfs_open解码出来的block_id和file_id均为0,client
会把block_id、file_id为0的信息发送给nameserver端。详细代码如下:

int TfsFile::tfs_open(const char *file_name, const char *suffix, const int32_t mode):

int TfsFile::tfs_open(const char *file_name, const char *suffix, const int32_t mode)
{
    mode_ = mode;
    conv_name(file_name, suffix);	// 将文件名file_name转换为block_id_, file_id_
    int32_t iret = tfs_open(block_id_, file_id_, mode_);	// 若file_name为NULL,则block_id_, file_id_均为0
    if (iret != TFS_SUCCESS)
    {
        return iret;
    }

	... ...
}

int TfsFile::tfs_open(const uint32_t block_id, const uint64_t file_id, const int32_t mode):

int TfsFile::tfs_open(const uint32_t block_id, const uint64_t file_id, const int32_t mode) {

	... ...
	ds_list_.clear();
	
	if (mode == READ_MODE) {
		if (session_->get_block_info(block_id_, ds_list_) != TFS_SUCCESS)
		{
			... ...
		}
	}
	else if (mode == UNLINK_MODE) {
		... ...
	}
	else {
		// 进入WRITE_MODE逻辑
		uint32_t current_block_id = block_id_;
		int32_t flag = BLOCK_WRITE | BLOCK_CREATE;
		if ((mode_ & NEWBLK_MODE))
			flag |= BLOCK_NEWBLK;
		if ((mode_ & NOLEASE_MODE))
			flag |= BLOCK_NOLEASE;
		if (session_->create_block_info(current_block_id, ds_list_, flag, fail_servers_) != TFS_SUCCESS) {
			if (ds_list_.size() == 0 || current_block_id == 0) {
				snprintf(error_message_, ERR_MSG_SIZE, "create block(%u) fail in nameserver", block_id_);
				return TFS_ERROR;
			}
		}
		if (block_id_ == 0) {
			block_id_ = current_block_id;
			mode_ |= APPEND_MODE;
		}
	}
	if (block_id_ == 0 || ds_list_.size() == 0) {
		snprintf(error_message_, ERR_MSG_SIZE, "block(%u),is invalid, dataserver size(%u)", block_id_,
			static_cast<uint32_t> (ds_list_.size()));
		return TFS_ERROR;
	}
	if ((mode_ & READ_MODE)) {
		if (file_id_ == 0) {
			;
		}
		pri_ds_index_ = static_cast<int32_t>(file_id_ % ds_list_.size());
	}
	else {
		pri_ds_index_ = 0;
	}
	
	if (connect_ds() != TFS_SUCCESS) {
		snprintf(error_message_, ERR_MSG_SIZE, "connect to dataserver fail.");
		if ((mode_ & APPEND_MODE))
			fail_servers_.push_bakc(ds_list_[0]);
		return TFS_ERROR;
	}
	fali_servers_.clear();
	
	if ((mode_ & WRITE_MODE)) {
		int32_t ret = create_filename();
		if (ret != TFS_SUCCESS) {
			CLIENT_POOL.release_client(client_);
			TBSYS_LOG(ERROR, "create file name fail(%d)", ret);
			return ret;
		}
		if (file_id_ == 0) {
			snprintf(error_message_, ERR_MSG_SIZE, "create file name fail, fileid == 0");
			CLIENT_POOL.release_client(client_);
			return TFS_ERROR;
		}
	}
	offset_ = 0;
	eof_ = TFS_FILE_EOF_FLAG_NO;
	crc_ = 0;
	is_open_flag_ = TFS_FILE_OPEN_FLAG_YES;
	return TFS_SUCCESS;
}

该函数有几个流程需要整理下:

(1) 当WRITE_MODE时会调用create_block_info函数去向nameserver申请dataserver的主从可写块信息,这里值得说明的是参数上带了fail_server_指明了client端上次请求失败的块信息,以避免nameserver不要再返回上次失败的块了以提高写成功率。

(2) 当nameserver返回可写块信息(包括:块对应的服务器地址,块id)后,会调用connect_ds函数来检测主块是否成功通讯。

上述步骤就完成了第一个流程的所有逻辑了,函数的后半截是关于消息CREATE_FILENAME_MESSAGE流程的。

 

2、CREATE_FILENAME_MESSAGE REQ/ACK:

当流程一完成后,会调用create_filename函数,从而进行CREATE_FILENAME_MESSAGE的处理流程,下面我们分client侧和dataserver侧两方面进行介绍。

(1) client侧逻辑:

携带这对应dataserver的block_id,让dataserver在对应block上分配存储文件的空间,dataserver返回对应的block的file_id和file_number信息。

(2) dataserver侧逻辑:

获取到client端发送的CREATE_FILENAME_MESSAGE后,dataserver在指定的block_id的块中分配的file_id,并携带block_id、file_id、file_number(共64字节,高32位由IP地址+端口号、低32位为文件序号)返回给client端。这里的block_id、file_id相当于一个提供给client端写文件的句柄,后面如果要写入数据的话就带上block_id、file_id就相当于定位到一个文件写入数据。

 

3、WRITE_DATA_MESSAGE REQ/ACK:

(1) client侧逻辑:

client端需要发送两份三元组信息:

1) 代表写入机器物理磁盘的信息{block_id、file_id、file_number}

2) 代表写入数据的信息{数据、数据长度、数据对应文件偏移}

(2) dataserver收到消息后,会做下列三步操作:

1) 通过收到的file_id找到对应的缓存并将写入的数据拷贝到DataFile缓存中(若写入该文件累计的数据长度大于2M了,就会先写入tmp文件)。注意如果还没有到client端调用close是不会将数据写入磁盘的,这里可以认为是方便做写事务失败的回滚操作,同时也提高响应性能。

2) 将写数据以post的方式(发送后不等待结果立即返回)发送给对block块的从dataserver上,这里因为考虑到性能的原因如果都要等到从dataserver回复的话速度就会慢很多。从dataserver接收到该消息后执行的操作跟主的一致,就是差了post的这一步骤。

3) 当把写数据都post给所有的从dataserver完毕后,反馈操作状态给client端。

 

4、CLOSE_FILE_MESSAGE REQ/ACK:

这里不叙述关于client端执行流程,重点来描述dataserver在收到CLOSE_FILE_MESSAGE的执行流程,具体的执行流程如下:

(1) 检测file_number对应的DataFile文件数据缓存,若没有则说明该块的租约已过期,直接返回失败给client端。

(2) 检测client的crc跟接收到的crc是否一致,若不一致则直接返回失败给client端。

(3) 通过file_id去找对应的逻辑块信息,若找不到则直接返回失败给client端。

(4) 去对应的逻辑快里面向对应的物理块进行写操作,若物理块空间不够则需扩容后再继续进行写操作,若真的无法写入则直接返回失败给client端

(5) 当写入文件数据完毕后,就要对相应的元数据信息进行更新,从中包括index索引以及superblock信息。

(6) 当上述步骤都成功完成后,就以send(等待从dataserver返回才继续后续操作)的方式把该消息传递给从dataserver,然后主dataserver再通知nameserver完成写入操作。最后将操作信息反馈给client端。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值