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

Commit 2bf1da5d authored by Kelvin Zhang's avatar Kelvin Zhang
Browse files

Shove CowOperation type into source_info

We can shove type into source info to save 8 bits in per cow operation.
We only need 4 bits inside of source_info to enumerate all the types of
Cow Operation. Since CowOperationV3 is not used on disk(just yet) , we
can make format changes.

This CL is mechanical:
    1. Remove tye .type field from CowOperation struct
    2. Add a type() getter method to CowOperation struct
    3. Replace all existing usage of `type` member with the new getter

No functional changes, just refactorings.

Test: th
Bug: 304602386
Bug: 313962438

Change-Id: I85d89c71fc6afede12ea299a4a3e3b2184ea2d8b
parent 58beb4a6
Loading
Loading
Loading
Loading
+28 −11
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <limits>
#include <optional>
#include <string_view>
#include <type_traits>

namespace android {
namespace snapshot {
@@ -194,11 +195,12 @@ struct CowOperationV2 {
    uint64_t source;
} __attribute__((packed));

static constexpr uint64_t kCowOpSourceInfoDataMask = (1ULL << 48) - 1;
static constexpr uint64_t kCowOpSourceInfoTypeBit = 60;
static constexpr uint64_t kCowOpSourceInfoTypeNumBits = 4;
static constexpr uint64_t kCowOpSourceInfoTypeMask = (1ULL << kCowOpSourceInfoTypeNumBits) - 1;
// The on disk format of cow (currently ==  CowOperation)
struct CowOperationV3 {
    // The operation code (see the constants and structures below).
    CowOperationType type;

    // If this operation reads from the data section of the COW, this contains
    // the length.
    uint16_t data_length;
@@ -206,6 +208,10 @@ struct CowOperationV3 {
    // The block of data in the new image that this operation modifies.
    uint32_t new_block;

    // source_info with have the following layout
    // |---4 bits ---| ---12 bits---| --- 48 bits ---|
    // |--- type --- | -- unused -- | --- source --- |
    //
    // The value of |source| depends on the operation code.
    //
    // CopyOp: a 32-bit block location in the source image.
@@ -217,9 +223,26 @@ struct CowOperationV3 {
    // For ops other than Label:
    //  Bits 47-62 are reserved and must be zero.
    // A block is compressed if it’s data is < block_sz
    uint64_t source_info;
    uint64_t source_info_;
    constexpr uint64_t source() const { return source_info_ & kCowOpSourceInfoDataMask; }
    constexpr void set_source(uint64_t source) {
        source_info_ |= source & kCowOpSourceInfoDataMask;
    }
    constexpr CowOperationType type() const {
        // this is a mask to grab the first 4 bits of a 64 bit integer
        const auto type = (source_info_ >> kCowOpSourceInfoTypeBit) & kCowOpSourceInfoTypeMask;
        return static_cast<CowOperationType>(type);
    }
    constexpr void set_type(CowOperationType type) {
        source_info_ |= (static_cast<uint64_t>(type) & kCowOpSourceInfoTypeMask)
                        << kCowOpSourceInfoTypeBit;
    }
} __attribute__((packed));

// Ensure that getters/setters added to CowOperationV3 does not increases size
// of CowOperationV3 struct(no virtual method tables added).
static_assert(std::is_trivially_copyable_v<CowOperationV3>);
static_assert(std::is_standard_layout_v<CowOperationV3>);
static_assert(sizeof(CowOperationV2) == sizeof(CowFooterOperation));

enum CowCompressionAlgorithm : uint8_t {
@@ -238,12 +261,6 @@ static constexpr uint8_t kCowReadAheadNotStarted = 0;
static constexpr uint8_t kCowReadAheadInProgress = 1;
static constexpr uint8_t kCowReadAheadDone = 2;

static constexpr uint64_t kCowOpSourceInfoDataMask = (1ULL << 48) - 1;

static inline uint64_t GetCowOpSourceInfoData(const CowOperation& op) {
    return op.source_info & kCowOpSourceInfoDataMask;
}

static constexpr off_t GetSequenceOffset(const CowHeaderV3& header) {
    return header.prefix.header_size + header.buffer_size;
}
@@ -284,7 +301,7 @@ static constexpr uint64_t BUFFER_REGION_DEFAULT_SIZE = (1ULL << 21);

std::ostream& operator<<(std::ostream& os, CowOperationV2 const& arg);

std::ostream& operator<<(std::ostream& os, CowOperation const& arg);
std::ostream& operator<<(std::ostream& os, CowOperationV3 const& arg);

std::ostream& operator<<(std::ostream& os, ResumePoint const& arg);

+11 −12
Original line number Diff line number Diff line
@@ -80,22 +80,21 @@ std::ostream& operator<<(std::ostream& os, CowOperationV2 const& op) {
    return os;
}

std::ostream& operator<<(std::ostream& os, CowOperation const& op) {
std::ostream& operator<<(std::ostream& os, CowOperationV3 const& op) {
    os << "CowOperation(";
    EmitCowTypeString(os, op.type);
    if (op.type == kCowReplaceOp || op.type == kCowXorOp || op.type == kCowSequenceOp) {
    EmitCowTypeString(os, op.type());
    if (op.type() == kCowReplaceOp || op.type() == kCowXorOp || op.type() == kCowSequenceOp) {
        os << ", data_length:" << op.data_length;
    }
    if (op.type != kCowClusterOp && op.type != kCowSequenceOp && op.type != kCowLabelOp) {
    if (op.type() != kCowClusterOp && op.type() != kCowSequenceOp && op.type() != kCowLabelOp) {
        os << ", new_block:" << op.new_block;
    }
    if (op.type == kCowXorOp || op.type == kCowReplaceOp || op.type == kCowCopyOp) {
        os << ", source:" << (op.source_info & kCowOpSourceInfoDataMask);
    } else if (op.type == kCowClusterOp) {
        os << ", cluster_data:" << (op.source_info & kCowOpSourceInfoDataMask);
    } else {
        os << ", label:0x" << android::base::StringPrintf("%" PRIx64, op.source_info);
    if (op.type() == kCowXorOp || op.type() == kCowReplaceOp || op.type() == kCowCopyOp) {
        os << ", source:" << op.source();
    } else if (op.type() == kCowClusterOp) {
        os << ", cluster_data:" << op.source();
    }
    // V3 op stores resume points in header, so CowOp can never be Label.
    os << ")";
    return os;
}
@@ -126,7 +125,7 @@ int64_t GetNextDataOffset(const CowOperationV2& op, uint32_t cluster_ops) {
}

bool IsMetadataOp(const CowOperation& op) {
    switch (op.type) {
    switch (op.type()) {
        case kCowLabelOp:
        case kCowClusterOp:
        case kCowFooterOp:
@@ -138,7 +137,7 @@ bool IsMetadataOp(const CowOperation& op) {
}

bool IsOrderedOp(const CowOperation& op) {
    switch (op.type) {
    switch (op.type()) {
        case kCowCopyOp:
        case kCowXorOp:
            return true;
+8 −8
Original line number Diff line number Diff line
@@ -345,7 +345,7 @@ bool CowReader::GetSequenceDataV2(std::vector<uint32_t>* merge_op_blocks,
    for (size_t i = 0; i < ops_->size(); i++) {
        auto& current_op = ops_->data()[i];

        if (current_op.type == kCowSequenceOp) {
        if (current_op.type() == kCowSequenceOp) {
            size_t seq_len = current_op.data_length / sizeof(uint32_t);

            merge_op_blocks->resize(merge_op_blocks->size() + seq_len);
@@ -637,11 +637,11 @@ std::unique_ptr<ICowOpIter> CowReader::GetMergeOpIter(bool ignore_progress) {
}

bool CowReader::GetRawBytes(const CowOperation* op, void* buffer, size_t len, size_t* read) {
    switch (op->type) {
    switch (op->type()) {
        case kCowSequenceOp:
        case kCowReplaceOp:
        case kCowXorOp:
            return GetRawBytes(GetCowOpSourceInfoData(*op), buffer, len, read);
            return GetRawBytes(op->source(), buffer, len, read);
        default:
            LOG(ERROR) << "Cannot get raw bytes of non-data op: " << *op;
            return false;
@@ -730,10 +730,10 @@ ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_
    }

    uint64_t offset;
    if (op->type == kCowXorOp) {
    if (op->type() == kCowXorOp) {
        offset = xor_data_loc_->at(op->new_block);
    } else {
        offset = GetCowOpSourceInfoData(*op);
        offset = op->source();
    }
    if (!decompressor ||
        ((op->data_length == header_.block_size) && (header_.prefix.major_version == 3))) {
@@ -747,12 +747,12 @@ ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_
}

bool CowReader::GetSourceOffset(const CowOperation* op, uint64_t* source_offset) {
    switch (op->type) {
    switch (op->type()) {
        case kCowCopyOp:
            *source_offset = GetCowOpSourceInfoData(*op) * header_.block_size;
            *source_offset = op->source() * header_.block_size;
            return true;
        case kCowXorOp:
            *source_offset = GetCowOpSourceInfoData(*op);
            *source_offset = op->source();
            return true;
        default:
            return false;
+7 −7
Original line number Diff line number Diff line
@@ -199,7 +199,7 @@ static bool Inspect(const std::string& path) {

        if (!FLAGS_silent && FLAGS_show_ops) std::cout << *op << "\n";

        if ((FLAGS_decompress || extract_to >= 0) && op->type == kCowReplaceOp) {
        if ((FLAGS_decompress || extract_to >= 0) && op->type() == kCowReplaceOp) {
            if (reader.ReadData(op, buffer.data(), buffer.size()) < 0) {
                std::cerr << "Failed to decompress for :" << *op << "\n";
                success = false;
@@ -213,12 +213,12 @@ static bool Inspect(const std::string& path) {
                    return false;
                }
            }
        } else if (extract_to >= 0 && !IsMetadataOp(*op) && op->type != kCowZeroOp) {
        } else if (extract_to >= 0 && !IsMetadataOp(*op) && op->type() != kCowZeroOp) {
            PLOG(ERROR) << "Cannot extract op yet: " << *op;
            return false;
        }

        if (op->type == kCowSequenceOp && FLAGS_show_merge_sequence) {
        if (op->type() == kCowSequenceOp && FLAGS_show_merge_sequence) {
            size_t read;
            std::vector<uint32_t> merge_op_blocks;
            size_t seq_len = op->data_length / sizeof(uint32_t);
@@ -236,13 +236,13 @@ static bool Inspect(const std::string& path) {
            }
        }

        if (op->type == kCowCopyOp) {
        if (op->type() == kCowCopyOp) {
            copy_ops++;
        } else if (op->type == kCowReplaceOp) {
        } else if (op->type() == kCowReplaceOp) {
            replace_ops++;
        } else if (op->type == kCowZeroOp) {
        } else if (op->type() == kCowZeroOp) {
            zero_ops++;
        } else if (op->type == kCowXorOp) {
        } else if (op->type() == kCowXorOp) {
            xor_ops++;
        }

+3 −3
Original line number Diff line number Diff line
@@ -205,7 +205,7 @@ bool CowParserV2::Translate(TranslatedCowOps* out) {
        const auto& v2_op = v2_ops_->at(i);

        auto& new_op = out->ops->at(i);
        new_op.type = v2_op.type;
        new_op.set_type(v2_op.type);
        new_op.data_length = v2_op.data_length;

        if (v2_op.new_block > std::numeric_limits<uint32_t>::max()) {
@@ -215,7 +215,7 @@ bool CowParserV2::Translate(TranslatedCowOps* out) {
        new_op.new_block = v2_op.new_block;

        uint64_t source_info = v2_op.source;
        if (new_op.type != kCowLabelOp) {
        if (new_op.type() != kCowLabelOp) {
            source_info &= kCowOpSourceInfoDataMask;
            if (source_info != v2_op.source) {
                LOG(ERROR) << "Out-of-range source value in COW op: " << v2_op;
@@ -232,7 +232,7 @@ bool CowParserV2::Translate(TranslatedCowOps* out) {
                return false;
            }
        }
        new_op.source_info = source_info;
        new_op.set_source(source_info);
    }

    out->header = header_;
Loading