Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5338d0b2 authored by Akilesh Kailash's avatar Akilesh Kailash Committed by Gerrit Code Review
Browse files

Merge "libsnapshot:snapuserd: Cut down memory usage"

parents 5463f859 3e807e96
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -250,6 +250,8 @@ bool CowReader::ParseOps(std::optional<uint64_t> label) {
    }

    ops_ = ops_buffer;
    ops_->shrink_to_fit();

    return true;
}

+8 −2
Original line number Diff line number Diff line
@@ -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
+11 −12
Original line number Diff line number Diff line
@@ -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);
@@ -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); }
@@ -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_;

+35 −15
Original line number Diff line number Diff line
@@ -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;
@@ -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
@@ -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;
        }

@@ -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_) {
@@ -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<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);
@@ -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);

@@ -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;