TFS文件系統寫文件分析

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;

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章