TFS文件系統寫入文件分析
對TFS文件系統的寫入文件的關鍵代碼做下分析.
(1). 寫文件消息包函數
int DataManagement::write_data(const WriteDataInfo& write_info, const int32_t lease_id, int32_t& version, const char* data_buffer, UpdateBlockType& repair) { TBSYS_LOG(DEBUG, "write data. blockid: %u, fileid: %" PRI64_PREFIX "u, filenumber: %" PRI64_PREFIX "u, lease: %d", write_info.block_id_, write_info.file_id_, write_info.file_number_, lease_id); //if the first fragment, check version if (0 == write_info.offset_) { //如果是初始,首先獲得邏輯塊 LogicBlock* logic_block = BlockFileManager::get_instance()->get_logic_block(write_info.block_id_); if (NULL == logic_block) { TBSYS_LOG(ERROR, "blockid: %u is not exist.", write_info.block_id_); return EXIT_NO_LOGICBLOCK_ERROR; } int ret = logic_block->check_block_version(version, repair); if (TFS_SUCCESS != ret) { TBSYS_LOG(DEBUG, "check_block_version error. blockid: %u, ret: %d", write_info.block_id_, ret); return ret; } } //通過文件號從data_file_map_中進行查找 data_file_mutex_.lock(); DataFileMapIter bit = data_file_map_.find(write_info.file_number_); DataFile* datafile = NULL; if (bit != data_file_map_.end()) { datafile = bit->second; } else { //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; } //找不到的話,插入到data_file_map_中 datafile = new DataFile(write_info.file_number_); data_file_map_.insert(DataFileMap::value_type(write_info.file_number_, datafile)); } if (NULL == datafile) { TBSYS_LOG(ERROR, "datafile is null. blockid: %u, fileid: %" PRI64_PREFIX "u, filenumber: %" PRI64_PREFIX "u", write_info.block_id_, write_info.file_id_, write_info.file_number_); data_file_mutex_.unlock(); return EXIT_DATA_FILE_ERROR; } //設置數據文件最後更新時間 datafile->set_last_update(); data_file_mutex_.unlock(); //寫入到數據文件中,參數:寫入的數據長度,偏移量 int32_t write_len = datafile->set_data(data_buffer, write_info.length_, write_info.offset_); if (write_len != write_info.length_) { TBSYS_LOG( ERROR, "Datafile write error. blockid: %u, fileid: %" PRI64_PREFIX "u, filenumber: %" PRI64_PREFIX "u, req writelen: %d, actual writelen: %d", write_info.block_id_, write_info.file_id_, write_info.file_number_, write_info.length_, write_len); erase_data_file(write_info.file_number_); return EXIT_DATA_FILE_ERROR; } return TFS_SUCCESS; } |
當將文件分消息包寫入時,具體的過程是寫入一個臨時文件中:
int DataFile::set_data(const char *data, const int32_t len, const int32_t offset) { if (len <= 0) { return TFS_SUCCESS; } //相當於累計寫入的字節數 int32_t length = offset + len; //WRITE_DATA_TMPBUF_SIZE=2M,以這個大小作爲寫入文件的緩衝區 if (length > WRITE_DATA_TMPBUF_SIZE) // write to file if length is large then max_read_size { if (fd_ == -1) { fd_ = open(tmp_file_name_, O_RDWR | O_CREAT | O_TRUNC, 0600); if (fd_ == -1) { TBSYS_LOG(ERROR, "open file fail: %s, %s", tmp_file_name_, strerror(errno)); return TFS_ERROR; } //先將之前的內容寫完 if (write(fd_, data_, length_) != length_) { TBSYS_LOG(ERROR, "write file fail: %s, length_: %d, error:%s", tmp_file_name_, length_, strerror(errno)); return TFS_ERROR; } } if (lseek(fd_, offset, SEEK_SET) == -1) { TBSYS_LOG(ERROR, "lseek file fail: %s, offset: %d", tmp_file_name_, offset); return TFS_ERROR; } if (write(fd_, data, len) != len) { TBSYS_LOG(ERROR, "write file fail: %s, len: %d", tmp_file_name_, len); return TFS_ERROR; } } else { memcpy(data_ + offset, data, len); } // 記錄前一次寫入的長度 if (length > length_) { length_ = length; } return len; } |
(2).寫文件消息包完畢後,在執行關閉寫操作,這個時候文件才實際從臨時文件寫入到數據塊中
//寫文件完畢後關閉操作 int DataManagement::close_write_file(const CloseFileInfo& closefileInfo, int32_t& write_file_size) { uint32_t block_id = closefileInfo.block_id_; uint64_t file_id = closefileInfo.file_id_; uint64_t file_number = closefileInfo.file_number_; uint32_t crc = closefileInfo.crc_; TBSYS_LOG(DEBUG, "close write file, blockid: %u, fileid: %" PRI64_PREFIX "u, filenumber: %" PRI64_PREFIX "u, crc: %u", block_id, file_id, file_number, crc); //find datafile DataFile* datafile = NULL; data_file_mutex_.lock(); DataFileMapIter bit = data_file_map_.find(file_number); if (bit != data_file_map_.end()) { datafile = bit->second; } //lease expire if (NULL == datafile) { TBSYS_LOG(ERROR, "Datafile is null. blockid: %u, fileid: %" PRI64_PREFIX "u, filenumber: %" PRI64_PREFIX "u", block_id, file_id, file_number); data_file_mutex_.unlock(); return EXIT_DATAFILE_EXPIRE_ERROR; } datafile->set_last_update(); datafile->add_ref(); data_file_mutex_.unlock(); //比較循環校驗碼 uint32_t datafile_crc = datafile->get_crc(); if (crc != datafile_crc) { TBSYS_LOG( ERROR, "Datafile crc error. blockid: %u, fileid: %" PRI64_PREFIX "u, filenumber: %" PRI64_PREFIX "u, local crc: %u, msg crc: %u", block_id, file_id, file_number, datafile_crc, crc); datafile->sub_ref(); erase_data_file(file_number); return EXIT_DATA_FILE_ERROR; } write_file_size = datafile->get_length(); //先查找邏輯塊 LogicBlock* logic_block = BlockFileManager::get_instance()->get_logic_block(block_id); if (NULL == logic_block) { datafile->sub_ref(); erase_data_file(file_number); TBSYS_LOG(ERROR, "blockid: %u is not exist.", block_id); return EXIT_NO_LOGICBLOCK_ERROR; } int64_t time_start = tbsys::CTimeUtil::getTime(); //邏輯塊關閉寫文件 int ret = logic_block->close_write_file(file_id, datafile, datafile_crc); if (TFS_SUCCESS != ret) { datafile->sub_ref(); erase_data_file(file_number); return ret; }
int64_t time_end = tbsys::CTimeUtil::getTime(); //記錄寫超時日誌 if (time_end - time_start > SYSPARAM_DATASERVER.max_io_warn_time_) { TBSYS_LOG(WARN, "write file cost time: blockid: %u, fileid: %" PRI64_PREFIX "u, cost time: %" PRI64_PREFIX "d", block_id, file_id, time_end - time_start); } // success, gc datafile // close tmp file, release opened file handle // datafile , bit->second point to same thing, once delete // bit->second, datafile will be obseleted immediately. // 刪除文件號對應的迭代器,刪除臨時文件 datafile->sub_ref(); erase_data_file(file_number); return TFS_SUCCESS; } |
(3). 邏輯塊關閉寫文件
//邏輯塊關閉寫文件操作 int LogicBlock::close_write_file(const uint64_t inner_file_id, DataFile* datafile, const uint32_t crc) { ScopedRWLock scoped_lock(rw_lock_, WRITE_LOCKER); RawMeta file_meta; //首先根據文件號判斷是否已經寫入 int ret = index_handle_->read_segment_meta(inner_file_id, file_meta); if (TFS_SUCCESS == ret) { TBSYS_LOG(INFO, "file exist, update! blockid: %u, fileid: %" PRI64_PREFIX "u", logic_block_id_, inner_file_id); } RawMeta bak_file_meta(file_meta); //獲得要寫入的文件長度 int32_t file_size = datafile->get_length(); FileInfo tfs_file_info, old_file_info; tfs_file_info.id_ = inner_file_id; tfs_file_info.size_ = file_size + sizeof(FileInfo); tfs_file_info.flag_ = 0; tfs_file_info.modify_time_ = time(NULL); tfs_file_info.create_time_ = time(NULL); tfs_file_info.crc_ = crc; bool need_update_meta = true, commit_offset = true; //commit OperType oper_type = C_OPER_UPDATE; int32_t old_size = 0, block_offset = 0; //如果是第一次寫文件,顯然不滿足條件,index_handle_->read_segment_meta(inner_file_id, file_meta)取不到值的 //第二次對同一文件作修改操作,index_handle_->read_segment_meta(inner_file_id, file_meta)就能取到值 if (file_meta.get_file_id() == inner_file_id) { TBSYS_LOG(INFO, "write file. fileid equal. blockid: %u, fileid: %" PRI64_PREFIX "u", logic_block_id_, inner_file_id); //取得舊文件的FileInfo old_file_info信息 ret = data_handle_->read_segment_info(&old_file_info, file_meta.get_offset()); if (TFS_SUCCESS != ret) { TBSYS_LOG(ERROR, "read FileInfo fail, blockid: %u, fileid: %" PRI64_PREFIX "u, ret: %d", logic_block_id_, inner_file_id, ret); } else //read successful { //獲得舊文件的創建時間來作爲重新寫入文件的創建時間 tfs_file_info.create_time_ = old_file_info.create_time_; //獲得重新寫入文件需要寫入的尺寸 int32_t require_size = file_size + sizeof(FileInfo); if (require_size > old_file_info.usize_) { old_size = old_file_info.usize_; //如果新尺寸大於舊文件的尺寸,那麼重新寫入的文件在索引文件偏移量設置爲最後,追加寫入 block_offset = index_handle_->get_block_data_offset(); TBSYS_LOG( INFO, "update file. require size: %d > origin size: %d. need reallocate, blockid: %u, fileid: %" PRI64_PREFIX "u, offset: %d", require_size, old_size, logic_block_id_, inner_file_id, block_offset); tfs_file_info.offset_ = block_offset; tfs_file_info.usize_ = require_size; file_meta.set_offset(block_offset); //偏移量設置在索引中追加最後寫入 } else { commit_offset = false; //索引文件的偏移量不必更新 //如果小於舊文件的尺寸,重新寫入文件的偏移量沿用舊文件的偏移量 tfs_file_info.offset_ = file_meta.get_offset(); tfs_file_info.usize_ = old_file_info.usize_; } //modify meta size file_meta.set_size(require_size); index_handle_->update_segment_meta(file_meta.get_key(), file_meta); } } //寫入第一個文件是oper_type = C_OPER_INSERT //更新文件是兩者是相等的 if (file_meta.get_file_id() != inner_file_id || ret) { need_update_meta = false; oper_type = C_OPER_INSERT; old_size = 0; tfs_file_info.usize_ = file_size + sizeof(FileInfo); //得到索引塊的偏移量:初始新增文件時塊偏移位置是 block_offset = index_handle_->get_block_data_offset(); tfs_file_info.offset_ = block_offset; file_meta.set_key(inner_file_id); file_meta.set_size(file_size + sizeof(FileInfo)); file_meta.set_offset(block_offset); //索引文件中寫入元數據 ret = index_handle_->write_segment_meta(file_meta.get_key(), file_meta); if (TFS_SUCCESS != ret) { return ret; } } char* tmp_data_buffer = NULL; int32_t read_len = 0, read_offset = 0; int32_t write_len = 0, write_offset = 0; do { //參數:源文件大小+sizeof(FileInfo),在塊中的偏移量 //塊的組織形式: 物理主塊+多個物理擴展塊 //從而形成塊前綴的這種關係: //uint32_t logic_blockid_; //邏輯塊id //uint32_t prev_physic_blockid_; //前一個物理塊id //uint32_t next_physic_blockid_; //後一個物理塊id ret = extend_block(file_meta.get_size(), file_meta.get_offset()); if (TFS_SUCCESS != ret) break; //從臨時數據文件讀取數據 while ((tmp_data_buffer = datafile->get_data(NULL, &read_len, read_offset)) != NULL) { if (read_len < 0 || (read_len + read_offset) > file_size) { TBSYS_LOG(ERROR, "getdata fail, blockid: %u, fileid: %" PRI64_PREFIX "u, size: %d, offset: %d, rlen: %d", logic_block_id_, inner_file_id, file_size, read_offset, read_len); ret = TFS_ERROR; break; } if (0 == read_len) { break; } write_len = read_len; if (0 == read_offset) { write_len += sizeof(FileInfo); } if (write_offset + write_len > file_meta.get_size()) { ret = EXIT_WRITE_OFFSET_ERROR; break; } //先寫FileInfo結構信息 //file_meta.get_offset():第一次寫入爲,第二次寫入值是第一次的file_size + sizeof(FileInfo), //第三次寫入又是累計第一次+第二次的值作爲偏移量 if (0 == read_offset) { char* tmp_write_buffer = new char[write_len]; memcpy(tmp_write_buffer, &tfs_file_info, sizeof(FileInfo)); memcpy(tmp_write_buffer + sizeof(FileInfo), tmp_data_buffer, read_len); ret = data_handle_->write_segment_data(tmp_write_buffer, write_len, file_meta.get_offset() + write_offset); delete[] tmp_write_buffer; } else { //在寫實際的數據文件 ret = data_handle_->write_segment_data(tmp_data_buffer, write_len, file_meta.get_offset() + write_offset); } //check ret(if disk error) if (TFS_SUCCESS != ret) { TBSYS_LOG( ERROR, "blockid: %u write data error, fileid: %" PRI64_PREFIX "u, size: %d offset: %d, rlen: %d, oldsize: %d, ret: %d", logic_block_id_, inner_file_id, file_size, read_offset, read_len, old_size, ret); break; } read_offset += read_len; write_offset += write_len; } if (TFS_SUCCESS != ret) break; if (oper_type == C_OPER_INSERT) { ret = index_handle_->update_block_info(C_OPER_INSERT, file_meta.get_size()); if (TFS_SUCCESS != ret) break; } else if (oper_type == C_OPER_UPDATE) { //如果是重新寫入文件,那麼就是先做一個刪除的操作,在做一個更新的操作 //(1).如果重新寫入的文件比之前的舊文件要小,那麼將在舊文件哪裏重新寫; //(2).如果重新寫入的文件比之前的舊文件要小,那麼將在物理塊後面追加重新寫; // 但是在索引文件裏面,設置的偏移量,尺寸已經變爲新文件寫入的信息了,因此查找時也是找到的重新寫過的新文件 if (0 != old_size) { ret = index_handle_->update_block_info(C_OPER_DELETE, old_size); if (TFS_SUCCESS != ret) break; ret = index_handle_->update_block_info(C_OPER_UPDATE, file_meta.get_size()); if (TFS_SUCCESS != ret) break; } else { ret = index_handle_->update_block_info(C_OPER_UPDATE, 0); if (TFS_SUCCESS != ret) break; } } } while (0); TBSYS_LOG(DEBUG, "close write file, blockid: %u, fileid: %" PRI64_PREFIX "u, ret: %d", logic_block_id_, inner_file_id, ret); if (TFS_SUCCESS != ret) //error occur { if (need_update_meta) { //rollback index_handle_->update_segment_meta(bak_file_meta.get_key(), bak_file_meta); } } else { if (commit_offset) { //塊數據的偏移量:第一次寫入文件爲,第二次作爲元數據file_meta.set_offset(block_offset)的起始偏移 //第三時是累計第一次+第二次的值作爲偏移量,次以此類推 index_handle_->commit_block_data_offset(file_size + sizeof(FileInfo)); } } //flush index index_handle_->flush(); return ret; } |
(4).在TFS中數據塊的組織形式是: 一個物理主塊+多個物理擴展塊
//擴展塊 int LogicBlock::extend_block(const int32_t size, const int32_t offset) { int32_t retry_times = MAX_EXTEND_TIMES; //extend retry_times extend block in one call while (retry_times) { //如果超過了avail_data_size_,新生成擴展塊 if (offset + size > avail_data_size_) //need extend block { TBSYS_LOG(INFO, "blockid: %u need ext block. offset: %d, datalen: %d, availsize: %d, data curr offset: %d, retry: %d", logic_block_id_, offset, size, avail_data_size_, index_handle_->get_block_data_offset(), retry_times);
uint32_t physical_ext_blockid = 0; uint32_t physical_blockid = 0; // get the last prev block id of this logic block std::list<PhysicalBlock*>* physcial_blk_list = &physical_block_list_; if (0 == physcial_blk_list->size()) { TBSYS_LOG(ERROR, "blockid: %u physical block list is empty!", logic_block_id_); return EXIT_PHYSICALBLOCK_NUM_ERROR; } //可見是直接取的列表的最後一個元素,來形成這種塊前綴的關係 physical_blockid = physcial_blk_list->back()->get_physic_block_id(); // new one ext block PhysicalBlock* tmp_physic_block = NULL; int ret = BlockFileManager::get_instance()->new_ext_block(logic_block_id_, physical_blockid, physical_ext_blockid, &tmp_physic_block); if (TFS_SUCCESS != ret) return ret; //然後又將新生成的插入physical_block_list_中去,這樣新生成的就是最後一個元素了, //再次進行擴展時就會取到它本身 physical_block_list_.push_back(tmp_physic_block); avail_data_size_ += tmp_physic_block->get_total_data_len(); } else { break; } --retry_times; }
if (0 == retry_times) { TBSYS_LOG(ERROR, "blockid: %u extend block too much!", logic_block_id_); return EXIT_PHYSICALBLOCK_NUM_ERROR; } return TFS_SUCCESS; } |
(5). 新生成擴展塊
//新生成擴展塊 int BlockFileManager::new_ext_block(const uint32_t logic_block_id, const uint32_t physical_block_id, uint32_t& ext_physical_block_id, PhysicalBlock **physic_block) { ScopedRWLock scoped_lock(rw_lock_, WRITE_LOCKER); int ret = TFS_SUCCESS; BlockType block_type; if (0 != physical_block_id) { block_type = C_EXT_BLOCK; } else { return EXIT_NO_LOGICBLOCK_ERROR; }
LogicBlockMapIter mit = logic_blocks_.find(logic_block_id); if (mit == logic_blocks_.end()) { return EXIT_NO_LOGICBLOCK_ERROR; } //找到一個沒有被佔用的擴展塊號 ret = find_avail_block(ext_physical_block_id, block_type); if (TFS_SUCCESS != ret) return ret;
PhysicalBlockMapIter pmit = physcial_blocks_.find(ext_physical_block_id); if (pmit != physcial_blocks_.end()) { TBSYS_LOG(ERROR, "physical block conflict. fatal error! ext physical blockid: %u", ext_physical_block_id); assert(false); } //make sure physical_block_id is exist pmit = physcial_blocks_.find(physical_block_id); if (pmit == physcial_blocks_.end()) { TBSYS_LOG(ERROR, "can not find physical blockid: %u", physical_block_id); assert(false); }
if (NULL == pmit->second) { TBSYS_LOG(ERROR, "physical blockid: %u point null", physical_block_id); assert(false); } normal_bit_map_->set(ext_physical_block_id); PhysicalBlock* tmp_physical_block = new PhysicalBlock(ext_physical_block_id, super_block_.mount_point_, super_block_.extend_block_size_, C_EXT_BLOCK); //設置新生成的擴展塊的塊前綴:填寫前一個物理塊號 tmp_physical_block->set_block_prefix(logic_block_id, physical_block_id, 0); TBSYS_LOG(INFO, "new ext block. logic blockid: %u, prev physical blockid: %u, now physical blockid: %u", logic_block_id, physical_block_id, ext_physical_block_id); do { //write physical block info to disk ret = tmp_physical_block->dump_block_prefix(); if (TFS_SUCCESS != ret) break; //取前面的物理塊,設置塊前綴:填寫後一個物理塊號 //構造prev_physic_block,ext_physic_blockid_這種關係,在將block_prefix這種關係寫入磁盤 PhysicalBlock* prev_physic_block = pmit->second; prev_physic_block->set_next_block(ext_physical_block_id); //write prev block info to disk ret = prev_physic_block->dump_block_prefix(); if (TFS_SUCCESS != ret) break; ret = super_block_impl_->write_bit_map(normal_bit_map_, error_bit_map_); if (TFS_SUCCESS != ret) break; //update superblock info ++super_block_.used_extend_block_count_; ret = super_block_impl_->write_super_blk(super_block_); if (TFS_SUCCESS != ret) break; //sync to disk ret = super_block_impl_->flush_file(); if (TFS_SUCCESS != ret) break; physcial_blocks_.insert(PhysicalBlockMap::value_type(ext_physical_block_id, tmp_physical_block)); (*physic_block) = tmp_physical_block; } while (0);
if (TFS_SUCCESS != ret) { TBSYS_LOG(ERROR, "new ext block error! logic blockid: %u. ret: %d", logic_block_id, ret); tbsys::gDelete(tmp_physical_block); } return ret; } |
(6). 找到一個沒有被佔用的擴展塊號
//查找可用的塊 int BlockFileManager::find_avail_block(uint32_t& ext_physical_block_id, const BlockType block_type) { int32_t i = 1; int32_t size = super_block_.main_block_count_; //如果是擴展塊類型,起始小標需要跳過前面的主塊 if (C_EXT_BLOCK == block_type) { i = super_block_.main_block_count_ + 1; size += super_block_.extend_block_count_; } bool hit_block = false; for (; i <= size; ++i) { //查找得到一個未使用的塊 if (!normal_bit_map_->test(i)) { //並且不會在錯誤的位圖中出現 if (error_bit_map_->test(i)) //skip error block { continue; } hit_block = true; break; } } // find nothing if (!hit_block) { TBSYS_LOG(ERROR, "block is exhausted! blocktype: %d/n", block_type); return EXIT_BLOCK_EXHAUST_ERROR; } TBSYS_LOG(DEBUG, "find avail blockid: %u/n", i); ext_physical_block_id = i; return TFS_SUCCESS; } |
(7).實際寫物理塊DataHandle類的方法:
int DataHandle::write_segment_data(const char* buf, const int32_t nbytes, const int32_t offset) { if (NULL == buf) { return EXIT_POINTER_NULL; } PhysicalBlock* tmp_physical_block = NULL; int32_t inner_offset = 0; int32_t written_len = 0, writting_len = 0; int ret = TFS_SUCCESS; while (written_len < nbytes) { //嘗試一次性寫完 writting_len = nbytes - written_len; //offset + written_len= 偏移量+累計寫入的字節數 ret = choose_physic_block(&tmp_physical_block, offset + written_len, inner_offset, writting_len); if (TFS_SUCCESS != ret) return ret; //參數:寫入緩衝,寫入的自己數,物理塊內部的偏移量 ret = tmp_physical_block->pwrite_data(buf + written_len, writting_len, inner_offset); if (TFS_SUCCESS != ret) return ret; written_len += writting_len; } return ret; } |
//讀取實際的文件數據過程 int DataHandle::read_segment_data(char* buf, const int32_t nbytes, const int32_t offset) { if (NULL == buf) { return EXIT_POINTER_NULL; } PhysicalBlock* tmp_physical_block = NULL; int32_t inner_offset = 0; int32_t has_read_len = 0, reading_len = 0; int ret = TFS_SUCCESS; while (has_read_len < nbytes) { //每次都嘗試一次性讀取完剩餘的字節數 reading_len = nbytes - has_read_len; //根據offset + has_read_len偏移量,選取一個物理塊,並且確定實際讀取是在這個物理塊內部的偏移量 ret = choose_physic_block(&tmp_physical_block, offset + has_read_len, inner_offset, reading_len); if (TFS_SUCCESS != ret) return ret; //從選中的物理塊中從內部偏移inner_offset開始讀取reading_len字節的數據,拷貝到輸出buf + has_read_len緩衝中 ret = tmp_physical_block->pread_data(buf + has_read_len, reading_len, inner_offset); if (TFS_SUCCESS != ret) return ret; has_read_len += reading_len; }
return ret; } |
//選擇一個可寫的物理塊 int DataHandle::choose_physic_block(PhysicalBlock** tmp_physical_block, const int32_t offset, int32_t& inner_offset, int32_t& inner_len) { std::list<PhysicalBlock*>* physic_block_list = logic_block_->get_physic_block_list(); std::list<PhysicalBlock*>::iterator lit = physic_block_list->begin(); int32_t sum_offset = 0; int32_t prev_sum_offset = 0; int32_t data_len = 0; for (; lit != physic_block_list->end(); ++lit) { data_len = (*lit)->get_total_data_len(); //累加各個物理塊的數據長度 sum_offset += data_len; //一個文件可能分佈在:一個物理主塊+多個擴展塊 //offset= 偏移量(寫入的起始位置)+累計寫入的字節數,確定寫入的開始位置 if (offset < sum_offset) { //取這一個物理塊 *tmp_physical_block = (*lit); //計算這個物理塊的內部偏移量,比如說一個邏輯塊對應一個物理主塊,兩個物理擴展塊 //寫文件時,前兩個物理塊被寫滿,到第三個,這裏確定第三個物理塊內部的偏移量 inner_offset = offset - prev_sum_offset; //比如初始寫入時:offset + written_len =offset+0,inner_len=writting_len=嘗試一次性寫完的字節數, //如果大於數據長度,那麼writting_len值就會改變,取實際能夠寫入的字節數 if ((offset + inner_len) > sum_offset) { inner_len = sum_offset - offset; } break; } prev_sum_offset += data_len; } //can not find if (lit == physic_block_list->end()) { return EXIT_PHYSIC_BLOCK_OFFSET_ERROR; }
return TFS_SUCCESS; } |