diff --git a/fs_mgr/libsnapshot/cow_reader.cpp b/fs_mgr/libsnapshot/cow_reader.cpp index 44a423cf7..7199b3829 100644 --- a/fs_mgr/libsnapshot/cow_reader.cpp +++ b/fs_mgr/libsnapshot/cow_reader.cpp @@ -250,6 +250,8 @@ bool CowReader::ParseOps(std::optional label) { } ops_ = ops_buffer; + ops_->shrink_to_fit(); + return true; } diff --git a/fs_mgr/libsnapshot/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd.cpp index f1fcb70a4..5ef9e29ed 100644 --- a/fs_mgr/libsnapshot/snapuserd.cpp +++ b/fs_mgr/libsnapshot/snapuserd.cpp @@ -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(); @@ -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++; @@ -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 diff --git a/fs_mgr/libsnapshot/snapuserd.h b/fs_mgr/libsnapshot/snapuserd.h index 6ce64d80e..933536442 100644 --- a/fs_mgr/libsnapshot/snapuserd.h +++ b/fs_mgr/libsnapshot/snapuserd.h @@ -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::iterator& it); + std::vector>::iterator& it); // Processing COW operations bool ProcessCowOp(const CowOperation* cow_op); @@ -164,16 +164,21 @@ class Snapuserd : public std::enable_shared_from_this { bool InitializeWorkers(); std::shared_ptr GetSharedPtr() { return shared_from_this(); } - std::map& GetChunkMap() { return chunk_map_; } + std::vector>& GetChunkVec() { return chunk_vec_; } const std::vector>& GetMetadataVec() const { return vec_; } + static bool compare(std::pair p1, + std::pair p2) { + return p1.first < p2.first; + } + private: std::vector> 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); } @@ -197,15 +202,9 @@ class Snapuserd : public std::enable_shared_from_this { // mapping of old-chunk to new-chunk std::vector> 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 chunk_map_; + // chunk_vec stores the pseudo mapping of sector + // to COW operations. + std::vector> chunk_vec_; std::mutex lock_; diff --git a/fs_mgr/libsnapshot/snapuserd_worker.cpp b/fs_mgr/libsnapshot/snapuserd_worker.cpp index 16f47fe35..1002569e0 100644 --- a/fs_mgr/libsnapshot/snapuserd_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd_worker.cpp @@ -185,12 +185,13 @@ bool WorkerThread::ProcessCowOp(const CowOperation* cow_op) { return false; } -int WorkerThread::ReadUnalignedSector(sector_t sector, size_t size, - std::map::iterator& it) { +int WorkerThread::ReadUnalignedSector( + sector_t sector, size_t size, + std::vector>::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; @@ -223,7 +224,8 @@ int WorkerThread::ReadUnalignedSector(sector_t sector, size_t size, * */ int WorkerThread::ReadData(sector_t sector, size_t size) { - std::map& chunk_map = snapuserd_->GetChunkMap(); + std::vector>& chunk_vec = snapuserd_->GetChunkVec(); + std::vector>::iterator it; /* * chunk_map stores COW operation at 4k granularity. * If the requested IO with the sector falls on the 4k @@ -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::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; } @@ -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& chunk_map = snapuserd_->GetChunkMap(); + std::vector>& chunk_vec = snapuserd_->GetChunkVec(); // Find the operations which are merged in this cycle. while ((unmerged_exceptions + merged_ops_cur_iter) < exceptions_per_area_) { @@ -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); @@ -510,14 +524,18 @@ bool WorkerThread::DmuserWriteRequest() { return true; } - std::map& chunk_map = snapuserd_->GetChunkMap(); + std::vector>& 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); @@ -550,7 +568,7 @@ bool WorkerThread::DmuserReadRequest() { size_t remaining_size = header->len; loff_t offset = 0; sector_t sector = header->sector; - std::map& chunk_map = snapuserd_->GetChunkMap(); + std::vector>& chunk_vec = snapuserd_->GetChunkVec(); do { size_t read_size = std::min(PAYLOAD_SIZE, remaining_size); @@ -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;