Merge "libsnapshot: Changes to AddCopy() API"

This commit is contained in:
Akilesh Kailash 2022-10-19 20:56:20 +00:00 committed by Gerrit Code Review
commit ad5cc05ca2
6 changed files with 92 additions and 26 deletions

View file

@ -52,8 +52,9 @@ class ICowWriter {
virtual ~ICowWriter() {}
// Encode an operation that copies the contents of |old_block| to the
// location of |new_block|.
bool AddCopy(uint64_t new_block, uint64_t old_block);
// location of |new_block|. 'num_blocks' is the number of contiguous
// COPY operations from |old_block| to |new_block|.
bool AddCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1);
// Encode a sequence of raw blocks. |size| must be a multiple of the block size.
bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size);
@ -84,7 +85,7 @@ class ICowWriter {
const CowOptions& options() { return options_; }
protected:
virtual bool EmitCopy(uint64_t new_block, uint64_t old_block) = 0;
virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) = 0;
virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) = 0;
virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size,
uint32_t old_block, uint16_t offset) = 0;
@ -122,7 +123,7 @@ class CowWriter : public ICowWriter {
uint32_t GetCowVersion() { return header_.major_version; }
protected:
virtual bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override;
virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size,
uint32_t old_block, uint16_t offset) override;

View file

@ -34,7 +34,7 @@ class MockSnapshotWriter : public ISnapshotWriter {
// Returns true if AddCopy() operations are supported.
MOCK_METHOD(bool, SupportsCopyOperation, (), (const override));
MOCK_METHOD(bool, EmitCopy, (uint64_t, uint64_t), (override));
MOCK_METHOD(bool, EmitCopy, (uint64_t, uint64_t, uint64_t), (override));
MOCK_METHOD(bool, EmitRawBlocks, (uint64_t, const void*, size_t), (override));
MOCK_METHOD(bool, EmitXorBlocks, (uint32_t, const void*, size_t, uint32_t, uint16_t),
(override));

View file

@ -74,7 +74,7 @@ class CompressedSnapshotWriter final : public ISnapshotWriter {
bool VerifyMergeOps() const noexcept;
protected:
bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override;
bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block,
uint16_t offset) override;
@ -113,7 +113,7 @@ class OnlineKernelSnapshotWriter final : public ISnapshotWriter {
bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block,
uint16_t offset) override;
bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override;
bool EmitLabel(uint64_t label) override;
bool EmitSequenceData(size_t num_ops, const uint32_t* data) override;

View file

@ -62,6 +62,48 @@ class StringSink : public IByteSink {
std::string stream_;
};
TEST_F(CowTest, CopyContiguous) {
CowOptions options;
options.cluster_ops = 0;
CowWriter writer(options);
ASSERT_TRUE(writer.Initialize(cow_->fd));
ASSERT_TRUE(writer.AddCopy(10, 1000, 100));
ASSERT_TRUE(writer.Finalize());
ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
CowReader reader;
CowHeader header;
CowFooter footer;
ASSERT_TRUE(reader.Parse(cow_->fd));
ASSERT_TRUE(reader.GetHeader(&header));
ASSERT_TRUE(reader.GetFooter(&footer));
ASSERT_EQ(header.magic, kCowMagicNumber);
ASSERT_EQ(header.major_version, kCowVersionMajor);
ASSERT_EQ(header.minor_version, kCowVersionMinor);
ASSERT_EQ(header.block_size, options.block_size);
ASSERT_EQ(footer.op.num_ops, 100);
auto iter = reader.GetOpIter();
ASSERT_NE(iter, nullptr);
ASSERT_FALSE(iter->Done());
size_t i = 0;
while (!iter->Done()) {
auto op = &iter->Get();
ASSERT_EQ(op->type, kCowCopyOp);
ASSERT_EQ(op->compression, kCowCompressNone);
ASSERT_EQ(op->data_length, 0);
ASSERT_EQ(op->new_block, 10 + i);
ASSERT_EQ(op->source, 1000 + i);
iter->Next();
i += 1;
}
ASSERT_EQ(i, 100);
}
TEST_F(CowTest, ReadWrite) {
CowOptions options;
options.cluster_ops = 0;

View file

@ -38,11 +38,16 @@ static_assert(sizeof(off_t) == sizeof(uint64_t));
using android::base::borrowed_fd;
using android::base::unique_fd;
bool ICowWriter::AddCopy(uint64_t new_block, uint64_t old_block) {
if (!ValidateNewBlock(new_block)) {
return false;
bool ICowWriter::AddCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks) {
CHECK(num_blocks != 0);
for (size_t i = 0; i < num_blocks; i++) {
if (!ValidateNewBlock(new_block + i)) {
return false;
}
}
return EmitCopy(new_block, old_block);
return EmitCopy(new_block, old_block, num_blocks);
}
bool ICowWriter::AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) {
@ -286,13 +291,20 @@ bool CowWriter::OpenForAppend(uint64_t label) {
return EmitClusterIfNeeded();
}
bool CowWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
bool CowWriter::EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks) {
CHECK(!merge_in_progress_);
CowOperation op = {};
op.type = kCowCopyOp;
op.new_block = new_block;
op.source = old_block;
return WriteOperation(op);
for (size_t i = 0; i < num_blocks; i++) {
CowOperation op = {};
op.type = kCowCopyOp;
op.new_block = new_block + i;
op.source = old_block + i;
if (!WriteOperation(op)) {
return false;
}
}
return true;
}
bool CowWriter::EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) {

View file

@ -111,8 +111,9 @@ std::unique_ptr<FileDescriptor> CompressedSnapshotWriter::OpenReader() {
return reader;
}
bool CompressedSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
return cow_->AddCopy(new_block, old_block);
bool CompressedSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block,
uint64_t num_blocks) {
return cow_->AddCopy(new_block, old_block, num_blocks);
}
bool CompressedSnapshotWriter::EmitRawBlocks(uint64_t new_block_start, const void* data,
@ -191,19 +192,29 @@ bool OnlineKernelSnapshotWriter::EmitZeroBlocks(uint64_t new_block_start, uint64
return true;
}
bool OnlineKernelSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
bool OnlineKernelSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block,
uint64_t num_blocks) {
auto source_fd = GetSourceFd();
if (source_fd < 0) {
return false;
}
std::string buffer(options_.block_size, 0);
uint64_t offset = old_block * options_.block_size;
if (!android::base::ReadFullyAtOffset(source_fd, buffer.data(), buffer.size(), offset)) {
PLOG(ERROR) << "EmitCopy read";
return false;
CHECK(num_blocks != 0);
for (size_t i = 0; i < num_blocks; i++) {
std::string buffer(options_.block_size, 0);
uint64_t offset = (old_block + i) * options_.block_size;
if (!android::base::ReadFullyAtOffset(source_fd, buffer.data(), buffer.size(), offset)) {
PLOG(ERROR) << "EmitCopy read";
return false;
}
if (!EmitRawBlocks(new_block + i, buffer.data(), buffer.size())) {
PLOG(ERROR) << "EmitRawBlocks failed";
return false;
}
}
return EmitRawBlocks(new_block, buffer.data(), buffer.size());
return true;
}
bool OnlineKernelSnapshotWriter::EmitLabel(uint64_t) {