Merge "libsnapshot: Parser v3 implementation" into main
This commit is contained in:
commit
cdb935e95f
6 changed files with 81 additions and 25 deletions
|
@ -99,8 +99,10 @@ struct CowHeaderV3 : public CowHeader {
|
|||
uint64_t sequence_buffer_offset;
|
||||
// Size, in bytes, of the CowResumePoint buffer.
|
||||
uint32_t resume_buffer_size;
|
||||
// Size, in bytes, of the CowOperation buffer.
|
||||
uint32_t op_buffer_size;
|
||||
// Number of CowOperationV3 structs in the operation buffer, currently and total
|
||||
// region size.
|
||||
uint32_t op_count;
|
||||
uint32_t op_count_max;
|
||||
// Compression Algorithm
|
||||
uint32_t compression_algorithm;
|
||||
} __attribute__((packed));
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "cow_decompress.h"
|
||||
#include "parser_v2.h"
|
||||
#include "parser_v3.h"
|
||||
|
||||
namespace android {
|
||||
namespace snapshot {
|
||||
|
@ -132,6 +133,7 @@ bool CowReader::Parse(android::base::borrowed_fd fd, std::optional<uint64_t> lab
|
|||
parser = std::make_unique<CowParserV2>();
|
||||
break;
|
||||
case 3:
|
||||
parser = std::make_unique<CowParserV3>();
|
||||
break;
|
||||
default:
|
||||
LOG(ERROR) << "Unknown version: " << header_.prefix.major_version;
|
||||
|
|
|
@ -24,15 +24,58 @@ namespace snapshot {
|
|||
using android::base::borrowed_fd;
|
||||
|
||||
bool CowParserV3::Parse(borrowed_fd fd, const CowHeaderV3& header, std::optional<uint64_t> label) {
|
||||
LOG(ERROR) << "this function should never be called";
|
||||
if (fd.get() || sizeof(header) > 0 || label) return false;
|
||||
return false;
|
||||
auto pos = lseek(fd.get(), 0, SEEK_END);
|
||||
if (pos < 0) {
|
||||
PLOG(ERROR) << "lseek end failed";
|
||||
return false;
|
||||
}
|
||||
fd_size_ = pos;
|
||||
header_ = header;
|
||||
|
||||
if (header_.footer_size != 0) {
|
||||
LOG(ERROR) << "Footer size isn't 0, read " << header_.footer_size;
|
||||
return false;
|
||||
}
|
||||
if (header_.op_size != sizeof(CowOperationV3)) {
|
||||
LOG(ERROR) << "Operation size unknown, read " << header_.op_size << ", expected "
|
||||
<< sizeof(CowOperationV3);
|
||||
return false;
|
||||
}
|
||||
if (header_.cluster_ops != 0) {
|
||||
LOG(ERROR) << "Cluster ops not supported in v3";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header_.prefix.major_version != 3 || header_.prefix.minor_version != 0) {
|
||||
LOG(ERROR) << "Header version mismatch, "
|
||||
<< "major version: " << header_.prefix.major_version
|
||||
<< ", expected: " << kCowVersionMajor
|
||||
<< ", minor version: " << header_.prefix.minor_version
|
||||
<< ", expected: " << kCowVersionMinor;
|
||||
return false;
|
||||
}
|
||||
|
||||
return ParseOps(fd, label);
|
||||
}
|
||||
|
||||
bool CowParserV3::ParseOps(android::base::borrowed_fd fd, std::optional<uint64_t> label) {
|
||||
LOG(ERROR) << "this function should never be called";
|
||||
if (fd.get() || label) return false;
|
||||
return false;
|
||||
bool CowParserV3::ParseOps(borrowed_fd fd, std::optional<uint64_t> label) {
|
||||
ops_ = std::make_shared<std::vector<CowOperationV3>>();
|
||||
ops_->resize(header_.op_count);
|
||||
|
||||
const off_t offset = header_.prefix.header_size + header_.buffer_size;
|
||||
if (!android::base::ReadFullyAtOffset(fd, ops_->data(), ops_->size() * sizeof(CowOperationV3),
|
||||
offset)) {
|
||||
PLOG(ERROR) << "read ops failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
// :TODO: sequence buffer & resume buffer follow
|
||||
// Once we implement labels, we'll have to discard unused ops and adjust
|
||||
// the header as needed.
|
||||
CHECK(!label);
|
||||
|
||||
ops_->shrink_to_fit();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CowParserV3::Translate(TranslatedCowOps* out) {
|
||||
|
|
|
@ -37,7 +37,7 @@ using testing::AssertionSuccess;
|
|||
namespace android {
|
||||
namespace snapshot {
|
||||
|
||||
class CowOperationV3Test : public ::testing::Test {
|
||||
class CowTestV3 : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() override {
|
||||
cow_ = std::make_unique<TemporaryFile>();
|
||||
|
@ -51,7 +51,7 @@ class CowOperationV3Test : public ::testing::Test {
|
|||
std::unique_ptr<TemporaryFile> cow_;
|
||||
};
|
||||
|
||||
TEST_F(CowOperationV3Test, CowHeaderV2Test) {
|
||||
TEST_F(CowTestV3, CowHeaderV2Test) {
|
||||
CowOptions options;
|
||||
options.cluster_ops = 5;
|
||||
options.num_merge_ops = 1;
|
||||
|
@ -67,11 +67,27 @@ TEST_F(CowOperationV3Test, CowHeaderV2Test) {
|
|||
|
||||
const auto& header = reader.GetHeader();
|
||||
ASSERT_EQ(header.prefix.magic, kCowMagicNumber);
|
||||
ASSERT_EQ(header.prefix.major_version, kCowVersionMajor);
|
||||
ASSERT_EQ(header.prefix.minor_version, kCowVersionMinor);
|
||||
ASSERT_EQ(header.prefix.major_version, 2);
|
||||
ASSERT_EQ(header.prefix.minor_version, 0);
|
||||
ASSERT_EQ(header.block_size, options.block_size);
|
||||
ASSERT_EQ(header.cluster_ops, options.cluster_ops);
|
||||
}
|
||||
|
||||
TEST_F(CowTestV3, Header) {
|
||||
CowOptions options;
|
||||
auto writer = CreateCowWriter(3, options, GetCowFd());
|
||||
ASSERT_TRUE(writer->Finalize());
|
||||
|
||||
CowReader reader;
|
||||
ASSERT_TRUE(reader.Parse(cow_->fd));
|
||||
|
||||
const auto& header = reader.GetHeader();
|
||||
ASSERT_EQ(header.prefix.magic, kCowMagicNumber);
|
||||
ASSERT_EQ(header.prefix.major_version, 3);
|
||||
ASSERT_EQ(header.prefix.minor_version, 0);
|
||||
ASSERT_EQ(header.block_size, options.block_size);
|
||||
ASSERT_EQ(header.cluster_ops, 0);
|
||||
}
|
||||
|
||||
} // namespace snapshot
|
||||
} // namespace android
|
||||
} // namespace android
|
||||
|
|
|
@ -78,7 +78,8 @@ void CowWriterV3::SetupHeaders() {
|
|||
// during COW size estimation
|
||||
header_.sequence_buffer_offset = 0;
|
||||
header_.resume_buffer_size = 0;
|
||||
header_.op_buffer_size = 0;
|
||||
header_.op_count = 0;
|
||||
header_.op_count_max = 0;
|
||||
header_.compression_algorithm = kCowCompressNone;
|
||||
return;
|
||||
}
|
||||
|
@ -159,10 +160,6 @@ bool CowWriterV3::OpenForWrite() {
|
|||
LOG(ERROR) << "Header sync failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
next_op_pos_ = 0;
|
||||
next_data_pos_ = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -205,8 +202,7 @@ bool CowWriterV3::EmitSequenceData(size_t num_ops, const uint32_t* data) {
|
|||
}
|
||||
|
||||
bool CowWriterV3::Finalize() {
|
||||
LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called";
|
||||
return false;
|
||||
return Sync();
|
||||
}
|
||||
|
||||
uint64_t CowWriterV3::GetCowSize() {
|
||||
|
|
|
@ -46,12 +46,9 @@ class CowWriterV3 : public CowWriterBase {
|
|||
private:
|
||||
CowHeaderV3 header_{};
|
||||
CowCompression compression_;
|
||||
|
||||
// in the case that we are using one thread for compression, we can store and re-use the same
|
||||
// compressor
|
||||
|
||||
uint64_t next_op_pos_ = 0;
|
||||
uint64_t next_data_pos_ = 0;
|
||||
|
||||
int num_compress_threads_ = 1;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue