TFS源码(基于1.3.1)分析--存储流程

File的存储分为3步,open,write和close

1、open会检查chunk和id的相关属性,也就是和nameserver进行通信,如果chunkid和fileid为0,则nameserver会分配chunkid,dataserver会分配fileid(在write的时候分配fileid)。

nameserver会根据chunkid和fileid,查找该chunk的版本,租约id以及合适的ds列表。

int MetaManager::write_block_info(uint32_t& block_id, int32_t mode, uint32_t& lease_id, int32_t& version,
        VUINT64& ds_list)
    {
     ...........
      block_id为0,也就是分配一个新的chunk,用来存储
      if ((block_id == 0)
          && (mode & BLOCK_CREATE))
      {
        VINT64 fail_ds;
//这里选择block的时候,并没有通过file的具体大小选择合适的block,应该在策略上有一定的问题,但是TFS有虚拟块的概念,可以通过虚拟块来规避部分的问题
        block_id = elect_write_block(fail_ds);
........................................

//采用了存储分组的方式,二次索引(不确定)
      BlockChunkPtr ptr = meta_mgr_.get_block_chunk(block_id);
      ptr->mutex_.rdlock();
      BlockCollect* block_collect = ptr->find(block_id);

//如果该chunkid没有dataserver服务器,直接返回失败
      if (block_collect->get_ds()->size() == 0)
      {
        ptr->mutex_.unlock();
        TBSYS_LOG(ERROR, "add new block(%u) failed, dataserver not found", block_id);
        return EXIT_NO_DATASERVER;
      }


//获取chunk的version已经对应的dataserver列表
      version = block_collect->get_block_info()->version_;
      ds_list.assign(block_collect->get_ds()->begin(), block_collect->get_ds()->end());

//获取一个租约
      if (!(mode & BLOCK_NOLEASE))
      {
        lease_id = lease_mgr_.register_lease(block_id);
        if (lease_id == WriteLease::INVALID_LEASE)
        {
          TBSYS_LOG(ERROR, "lease not found by block id(%u)", block_id);
          return EXIT_CANNOT_GET_LEASE;
        }
      }
      return TFS_SUCCESS;
    }

从这些里面我们可以看出,系统的负载均衡策略并没有体现出来,没有根据file大小以及dataserver的负载信息进行动态的分配,而是随机的选择dataserver

同时如果是新增文件的时候,nameserver为其分配一个chunkid,而fileid是由dataserver进行分配的


2、open后,client通过与nameserver交互,拿到需要的信息后,与dataserver进行交互,写入数据到dataserver

 int DataManagement::write_data(const WriteDataInfo& write_info, const int32_t lease_id, int32_t& version,
        const char* data_buffer, UpdateBlockType& repair)
    {
//如果是刚开始写,则需要检查chunkid的版本,TFS不支持随机写入,所以第一次写入可以使用offset进行判断
      if (0 == write_info.offset_)
      {
        LogicBlock* logic_block = BlockFileManager::get_instance()->get_logic_block(write_info.block_id_);
.............................................
         int ret = logic_block->check_block_version(version, repair);
......................................
      }


//开始写数据,如果文件比较大,数据流是分段传输的,首先需要找到第一次写入时的缓存数据,数据的写入是先全部写入缓存,然后全部刷入磁盘
      DataFileMapIter bit = data_file_map_.find(write_info.file_number_);
      DataFile* datafile = NULL;
      if (bit != data_file_map_.end())
      {
        datafile = bit->second;
      }
      else                      // not found
      {
        // control datafile size
        if (data_file_map_.size() >= static_cast<uint32_t> (SYSPARAM_DATASERVER.max_datafile_nums_))
        {
          TBSYS_LOG(ERROR, "blockid: %u, datafile nums: %u is large than default.", write_info.block_id_,
              data_file_map_.size());
          data_file_mutex_.unlock();
          return EXIT_DATAFILE_OVERLOAD;
       }
........................................................................

      // 开始写入数据,这里有个需要注意的地方,当file比较大的时候,系统会把数据存储在磁盘临时文件,而不是内存缓存,这个文件大小临界值暂设置为2M
      int32_t write_len = datafile->set_data(data_buffer, write_info.length_, write_info.offset_);
      if (write_len != write_info.length_)
      {
        erase_data_file(write_info.file_number_);
        return EXIT_DATA_FILE_ERROR;
      }
      return TFS_SUCCESS;
    }

完成主dataserver数据写入后(分批写入),会将数据传送到slave 的dataserver

TFS与GFS不同之处在于,TFS是主dataserver采用异步的方式,将数据发送到全部slave,也就是1-n的方式,而GFS是采用流水的方式,也就是1-1-1-1的方式。

 message->set_server(Slave_Server_Role);
  message->set_lease_id(lease_id);
  message->set_block_version(version);
ret = post_message_to_server(message, message->get_ds_list());

3、数据在写入完成后,client会发送close的命令,dataserver将数据刷入磁盘

int DataManagement::close_write_file(const CloseFileInfo& closefileInfo, int32_t& write_file_size)
    {
1、找到接收到的数据
.......................................
      DataFileMapIter bit = data_file_map_.find(file_number);
      if (bit != data_file_map_.end())
      {
        datafile = bit->second;
      }
..............................................
2、设置属性
      datafile->set_last_update();
      datafile->add_ref();
      data_file_mutex_.unlock();

3、计算crc值
      //compare crc
      uint32_t datafile_crc = datafile->get_crc();
......................................
      write_file_size = datafile->get_length();

    //找到chunk的具体信息,准备写数据了
      LogicBlock* logic_block = BlockFileManager::get_instance()->get_logic_block(block_id);
................................................

      TIMER_START();
//这个写数据的时候,有几个特殊的地方,上面我们提到过,nameserver选择chunk的时候,不会根据文件的大小进行判断,那么如果一个文件的大小超过了chunk的剩余存储空//间,TFS的处理流程:
//TFS会使用虚拟块,系统会申请虚拟块存储空间,系统默认最多申请30个虚拟块,如果30个虚拟块都不满足需要的空间,则返回失败。如果申请到需要的存储空间,则file在///物理存储上会分布多个文件内,但在逻辑存储上,依然存储在同一个chunk上,同时chunk的大小会增加
//也就是说,TFS支持存储大小超过64M的文件,但由于文件分片无法跨服务器存储,无法支持真正的大文件存储
      int ret = logic_block->close_write_file(file_id, datafile, datafile_crc);
..................................................
      datafile->sub_ref();
      erase_data_file(file_number);
      return TFS_SUCCESS;
     }




   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值