Loading fs_mgr/libsnapshot/cow_reader.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -250,6 +250,8 @@ bool CowReader::ParseOps(std::optional<uint64_t> label) { } ops_ = ops_buffer; ops_->shrink_to_fit(); return true; } Loading fs_mgr/libsnapshot/snapuserd.cpp +8 −2 Original line number Diff line number Diff line Loading @@ -230,7 +230,7 @@ bool Snapuserd::ReadMetadata() { // Store operation pointer. chunk_map_[ChunkToSector(data_chunk_id)] = cow_op; chunk_vec_.push_back(std::make_pair(ChunkToSector(data_chunk_id), cow_op)); num_ops += 1; offset += sizeof(struct disk_exception); cowop_riter_->Next(); Loading Loading @@ -422,7 +422,7 @@ bool Snapuserd::ReadMetadata() { de->new_chunk = data_chunk_id; // Store operation pointer. chunk_map_[ChunkToSector(data_chunk_id)] = it->second; chunk_vec_.push_back(std::make_pair(ChunkToSector(data_chunk_id), it->second)); offset += sizeof(struct disk_exception); num_ops += 1; copy_ops++; Loading Loading @@ -468,6 +468,12 @@ bool Snapuserd::ReadMetadata() { << "Areas : " << vec_.size(); } chunk_vec_.shrink_to_fit(); vec_.shrink_to_fit(); // Sort the vector based on sectors as we need this during un-aligned access std::sort(chunk_vec_.begin(), chunk_vec_.end(), compare); SNAP_LOG(INFO) << "ReadMetadata completed. Final-chunk-id: " << data_chunk_id << " Num Sector: " << ChunkToSector(data_chunk_id) << " Replace-ops: " << replace_ops << " Zero-ops: " << zero_ops Loading fs_mgr/libsnapshot/snapuserd.h +11 −12 Original line number Diff line number Diff line Loading @@ -108,7 +108,7 @@ class WorkerThread { bool ProcessIORequest(); int ReadData(sector_t sector, size_t size); int ReadUnalignedSector(sector_t sector, size_t size, std::map<sector_t, const CowOperation*>::iterator& it); std::vector<std::pair<sector_t, const CowOperation*>>::iterator& it); // Processing COW operations bool ProcessCowOp(const CowOperation* cow_op); Loading Loading @@ -164,16 +164,21 @@ class Snapuserd : public std::enable_shared_from_this<Snapuserd> { bool InitializeWorkers(); std::shared_ptr<Snapuserd> GetSharedPtr() { return shared_from_this(); } std::map<sector_t, const CowOperation*>& GetChunkMap() { return chunk_map_; } std::vector<std::pair<sector_t, const CowOperation*>>& GetChunkVec() { return chunk_vec_; } const std::vector<std::unique_ptr<uint8_t[]>>& GetMetadataVec() const { return vec_; } static bool compare(std::pair<sector_t, const CowOperation*> p1, std::pair<sector_t, const CowOperation*> p2) { return p1.first < p2.first; } private: std::vector<std::unique_ptr<WorkerThread>> worker_threads_; bool ReadMetadata(); bool IsChunkIdMetadata(chunk_t chunk); chunk_t GetNextAllocatableChunkId(chunk_t chunk_id); bool ReadMetadata(); sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; } chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; } bool IsBlockAligned(int read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); } Loading @@ -197,15 +202,9 @@ class Snapuserd : public std::enable_shared_from_this<Snapuserd> { // mapping of old-chunk to new-chunk std::vector<std::unique_ptr<uint8_t[]>> vec_; // Key - Sector // Value - cow operation // // chunk_map stores the pseudo mapping of sector // to COW operations. Each COW op is 4k; however, // we can get a read request which are as small // as 512 bytes. Hence, we need to binary search // in the chunk_map to find the nearest COW op. std::map<sector_t, const CowOperation*> chunk_map_; // chunk_vec stores the pseudo mapping of sector // to COW operations. std::vector<std::pair<sector_t, const CowOperation*>> chunk_vec_; std::mutex lock_; Loading fs_mgr/libsnapshot/snapuserd_worker.cpp +35 −15 Original line number Diff line number Diff line Loading @@ -185,12 +185,13 @@ bool WorkerThread::ProcessCowOp(const CowOperation* cow_op) { return false; } int WorkerThread::ReadUnalignedSector(sector_t sector, size_t size, std::map<sector_t, const CowOperation*>::iterator& it) { int WorkerThread::ReadUnalignedSector( sector_t sector, size_t size, std::vector<std::pair<sector_t, const CowOperation*>>::iterator& it) { size_t skip_sector_size = 0; SNAP_LOG(DEBUG) << "ReadUnalignedSector: sector " << sector << " size: " << size << " Aligned sector: " << it->second; << " Aligned sector: " << it->first; if (!ProcessCowOp(it->second)) { SNAP_LOG(ERROR) << "ReadUnalignedSector: " << sector << " failed of size: " << size; Loading Loading @@ -223,7 +224,8 @@ int WorkerThread::ReadUnalignedSector(sector_t sector, size_t size, * */ int WorkerThread::ReadData(sector_t sector, size_t size) { std::map<sector_t, const CowOperation*>& chunk_map = snapuserd_->GetChunkMap(); std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec(); std::vector<std::pair<sector_t, const CowOperation*>>::iterator it; /* * chunk_map stores COW operation at 4k granularity. * If the requested IO with the sector falls on the 4k Loading @@ -234,10 +236,16 @@ int WorkerThread::ReadData(sector_t sector, size_t size) { * then we will have the find the nearest COW operation * and chop the 4K block to fetch the requested sector. */ std::map<sector_t, const CowOperation*>::iterator it = chunk_map.find(sector); if (it == chunk_map.end()) { it = chunk_map.lower_bound(sector); if (it != chunk_map.begin()) { it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(), std::make_pair(sector, nullptr), Snapuserd::compare); CHECK(it != chunk_vec.end()); // We didn't find the required sector; hence find the previous sector // as lower_bound will gives us the value greater than // the requested sector if (it->first != sector) { if (it != chunk_vec.begin()) { --it; } Loading Loading @@ -380,7 +388,7 @@ loff_t WorkerThread::GetMergeStartOffset(void* merged_buffer, void* unmerged_buf int WorkerThread::GetNumberOfMergedOps(void* merged_buffer, void* unmerged_buffer, loff_t offset, int unmerged_exceptions) { int merged_ops_cur_iter = 0; std::map<sector_t, const CowOperation*>& chunk_map = snapuserd_->GetChunkMap(); std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec(); // Find the operations which are merged in this cycle. while ((unmerged_exceptions + merged_ops_cur_iter) < exceptions_per_area_) { Loading @@ -395,7 +403,13 @@ int WorkerThread::GetNumberOfMergedOps(void* merged_buffer, void* unmerged_buffe if (cow_de->new_chunk != 0) { merged_ops_cur_iter += 1; offset += sizeof(struct disk_exception); const CowOperation* cow_op = chunk_map[ChunkToSector(cow_de->new_chunk)]; auto it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(), std::make_pair(ChunkToSector(cow_de->new_chunk), nullptr), Snapuserd::compare); CHECK(it != chunk_vec.end()); CHECK(it->first == ChunkToSector(cow_de->new_chunk)); const CowOperation* cow_op = it->second; CHECK(cow_op != nullptr); CHECK(cow_op->new_block == cow_de->old_chunk); Loading Loading @@ -510,14 +524,18 @@ bool WorkerThread::DmuserWriteRequest() { return true; } std::map<sector_t, const CowOperation*>& chunk_map = snapuserd_->GetChunkMap(); std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec(); size_t remaining_size = header->len; size_t read_size = std::min(PAYLOAD_SIZE, remaining_size); CHECK(read_size == BLOCK_SZ) << "DmuserWriteRequest: read_size: " << read_size; CHECK(header->sector > 0); chunk_t chunk = SectorToChunk(header->sector); CHECK(chunk_map.find(header->sector) == chunk_map.end()); auto it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(), std::make_pair(header->sector, nullptr), Snapuserd::compare); bool not_found = (it == chunk_vec.end() || it->first != header->sector); CHECK(not_found); void* buffer = bufsink_.GetPayloadBuffer(read_size); CHECK(buffer != nullptr); Loading Loading @@ -550,7 +568,7 @@ bool WorkerThread::DmuserReadRequest() { size_t remaining_size = header->len; loff_t offset = 0; sector_t sector = header->sector; std::map<sector_t, const CowOperation*>& chunk_map = snapuserd_->GetChunkMap(); std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec(); do { size_t read_size = std::min(PAYLOAD_SIZE, remaining_size); Loading @@ -568,8 +586,10 @@ bool WorkerThread::DmuserReadRequest() { ConstructKernelCowHeader(); SNAP_LOG(DEBUG) << "Kernel header constructed"; } else { if (!offset && (read_size == BLOCK_SZ) && chunk_map.find(header->sector) == chunk_map.end()) { auto it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(), std::make_pair(header->sector, nullptr), Snapuserd::compare); bool not_found = (it == chunk_vec.end() || it->first != header->sector); if (!offset && (read_size == BLOCK_SZ) && not_found) { if (!ReadDiskExceptions(chunk, read_size)) { SNAP_LOG(ERROR) << "ReadDiskExceptions failed for chunk id: " << chunk << "Sector: " << header->sector; Loading Loading
fs_mgr/libsnapshot/cow_reader.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -250,6 +250,8 @@ bool CowReader::ParseOps(std::optional<uint64_t> label) { } ops_ = ops_buffer; ops_->shrink_to_fit(); return true; } Loading
fs_mgr/libsnapshot/snapuserd.cpp +8 −2 Original line number Diff line number Diff line Loading @@ -230,7 +230,7 @@ bool Snapuserd::ReadMetadata() { // Store operation pointer. chunk_map_[ChunkToSector(data_chunk_id)] = cow_op; chunk_vec_.push_back(std::make_pair(ChunkToSector(data_chunk_id), cow_op)); num_ops += 1; offset += sizeof(struct disk_exception); cowop_riter_->Next(); Loading Loading @@ -422,7 +422,7 @@ bool Snapuserd::ReadMetadata() { de->new_chunk = data_chunk_id; // Store operation pointer. chunk_map_[ChunkToSector(data_chunk_id)] = it->second; chunk_vec_.push_back(std::make_pair(ChunkToSector(data_chunk_id), it->second)); offset += sizeof(struct disk_exception); num_ops += 1; copy_ops++; Loading Loading @@ -468,6 +468,12 @@ bool Snapuserd::ReadMetadata() { << "Areas : " << vec_.size(); } chunk_vec_.shrink_to_fit(); vec_.shrink_to_fit(); // Sort the vector based on sectors as we need this during un-aligned access std::sort(chunk_vec_.begin(), chunk_vec_.end(), compare); SNAP_LOG(INFO) << "ReadMetadata completed. Final-chunk-id: " << data_chunk_id << " Num Sector: " << ChunkToSector(data_chunk_id) << " Replace-ops: " << replace_ops << " Zero-ops: " << zero_ops Loading
fs_mgr/libsnapshot/snapuserd.h +11 −12 Original line number Diff line number Diff line Loading @@ -108,7 +108,7 @@ class WorkerThread { bool ProcessIORequest(); int ReadData(sector_t sector, size_t size); int ReadUnalignedSector(sector_t sector, size_t size, std::map<sector_t, const CowOperation*>::iterator& it); std::vector<std::pair<sector_t, const CowOperation*>>::iterator& it); // Processing COW operations bool ProcessCowOp(const CowOperation* cow_op); Loading Loading @@ -164,16 +164,21 @@ class Snapuserd : public std::enable_shared_from_this<Snapuserd> { bool InitializeWorkers(); std::shared_ptr<Snapuserd> GetSharedPtr() { return shared_from_this(); } std::map<sector_t, const CowOperation*>& GetChunkMap() { return chunk_map_; } std::vector<std::pair<sector_t, const CowOperation*>>& GetChunkVec() { return chunk_vec_; } const std::vector<std::unique_ptr<uint8_t[]>>& GetMetadataVec() const { return vec_; } static bool compare(std::pair<sector_t, const CowOperation*> p1, std::pair<sector_t, const CowOperation*> p2) { return p1.first < p2.first; } private: std::vector<std::unique_ptr<WorkerThread>> worker_threads_; bool ReadMetadata(); bool IsChunkIdMetadata(chunk_t chunk); chunk_t GetNextAllocatableChunkId(chunk_t chunk_id); bool ReadMetadata(); sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; } chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; } bool IsBlockAligned(int read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); } Loading @@ -197,15 +202,9 @@ class Snapuserd : public std::enable_shared_from_this<Snapuserd> { // mapping of old-chunk to new-chunk std::vector<std::unique_ptr<uint8_t[]>> vec_; // Key - Sector // Value - cow operation // // chunk_map stores the pseudo mapping of sector // to COW operations. Each COW op is 4k; however, // we can get a read request which are as small // as 512 bytes. Hence, we need to binary search // in the chunk_map to find the nearest COW op. std::map<sector_t, const CowOperation*> chunk_map_; // chunk_vec stores the pseudo mapping of sector // to COW operations. std::vector<std::pair<sector_t, const CowOperation*>> chunk_vec_; std::mutex lock_; Loading
fs_mgr/libsnapshot/snapuserd_worker.cpp +35 −15 Original line number Diff line number Diff line Loading @@ -185,12 +185,13 @@ bool WorkerThread::ProcessCowOp(const CowOperation* cow_op) { return false; } int WorkerThread::ReadUnalignedSector(sector_t sector, size_t size, std::map<sector_t, const CowOperation*>::iterator& it) { int WorkerThread::ReadUnalignedSector( sector_t sector, size_t size, std::vector<std::pair<sector_t, const CowOperation*>>::iterator& it) { size_t skip_sector_size = 0; SNAP_LOG(DEBUG) << "ReadUnalignedSector: sector " << sector << " size: " << size << " Aligned sector: " << it->second; << " Aligned sector: " << it->first; if (!ProcessCowOp(it->second)) { SNAP_LOG(ERROR) << "ReadUnalignedSector: " << sector << " failed of size: " << size; Loading Loading @@ -223,7 +224,8 @@ int WorkerThread::ReadUnalignedSector(sector_t sector, size_t size, * */ int WorkerThread::ReadData(sector_t sector, size_t size) { std::map<sector_t, const CowOperation*>& chunk_map = snapuserd_->GetChunkMap(); std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec(); std::vector<std::pair<sector_t, const CowOperation*>>::iterator it; /* * chunk_map stores COW operation at 4k granularity. * If the requested IO with the sector falls on the 4k Loading @@ -234,10 +236,16 @@ int WorkerThread::ReadData(sector_t sector, size_t size) { * then we will have the find the nearest COW operation * and chop the 4K block to fetch the requested sector. */ std::map<sector_t, const CowOperation*>::iterator it = chunk_map.find(sector); if (it == chunk_map.end()) { it = chunk_map.lower_bound(sector); if (it != chunk_map.begin()) { it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(), std::make_pair(sector, nullptr), Snapuserd::compare); CHECK(it != chunk_vec.end()); // We didn't find the required sector; hence find the previous sector // as lower_bound will gives us the value greater than // the requested sector if (it->first != sector) { if (it != chunk_vec.begin()) { --it; } Loading Loading @@ -380,7 +388,7 @@ loff_t WorkerThread::GetMergeStartOffset(void* merged_buffer, void* unmerged_buf int WorkerThread::GetNumberOfMergedOps(void* merged_buffer, void* unmerged_buffer, loff_t offset, int unmerged_exceptions) { int merged_ops_cur_iter = 0; std::map<sector_t, const CowOperation*>& chunk_map = snapuserd_->GetChunkMap(); std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec(); // Find the operations which are merged in this cycle. while ((unmerged_exceptions + merged_ops_cur_iter) < exceptions_per_area_) { Loading @@ -395,7 +403,13 @@ int WorkerThread::GetNumberOfMergedOps(void* merged_buffer, void* unmerged_buffe if (cow_de->new_chunk != 0) { merged_ops_cur_iter += 1; offset += sizeof(struct disk_exception); const CowOperation* cow_op = chunk_map[ChunkToSector(cow_de->new_chunk)]; auto it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(), std::make_pair(ChunkToSector(cow_de->new_chunk), nullptr), Snapuserd::compare); CHECK(it != chunk_vec.end()); CHECK(it->first == ChunkToSector(cow_de->new_chunk)); const CowOperation* cow_op = it->second; CHECK(cow_op != nullptr); CHECK(cow_op->new_block == cow_de->old_chunk); Loading Loading @@ -510,14 +524,18 @@ bool WorkerThread::DmuserWriteRequest() { return true; } std::map<sector_t, const CowOperation*>& chunk_map = snapuserd_->GetChunkMap(); std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec(); size_t remaining_size = header->len; size_t read_size = std::min(PAYLOAD_SIZE, remaining_size); CHECK(read_size == BLOCK_SZ) << "DmuserWriteRequest: read_size: " << read_size; CHECK(header->sector > 0); chunk_t chunk = SectorToChunk(header->sector); CHECK(chunk_map.find(header->sector) == chunk_map.end()); auto it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(), std::make_pair(header->sector, nullptr), Snapuserd::compare); bool not_found = (it == chunk_vec.end() || it->first != header->sector); CHECK(not_found); void* buffer = bufsink_.GetPayloadBuffer(read_size); CHECK(buffer != nullptr); Loading Loading @@ -550,7 +568,7 @@ bool WorkerThread::DmuserReadRequest() { size_t remaining_size = header->len; loff_t offset = 0; sector_t sector = header->sector; std::map<sector_t, const CowOperation*>& chunk_map = snapuserd_->GetChunkMap(); std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec(); do { size_t read_size = std::min(PAYLOAD_SIZE, remaining_size); Loading @@ -568,8 +586,10 @@ bool WorkerThread::DmuserReadRequest() { ConstructKernelCowHeader(); SNAP_LOG(DEBUG) << "Kernel header constructed"; } else { if (!offset && (read_size == BLOCK_SZ) && chunk_map.find(header->sector) == chunk_map.end()) { auto it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(), std::make_pair(header->sector, nullptr), Snapuserd::compare); bool not_found = (it == chunk_vec.end() || it->first != header->sector); if (!offset && (read_size == BLOCK_SZ) && not_found) { if (!ReadDiskExceptions(chunk, read_size)) { SNAP_LOG(ERROR) << "ReadDiskExceptions failed for chunk id: " << chunk << "Sector: " << header->sector; Loading