Merge "libsnapshot: Changes to AddCopy() API" am: ad5cc05ca2
Original change: https://android-review.googlesource.com/c/platform/system/core/+/2261080 Change-Id: I3a87da1b2828615261137bea2190b950f00f22ce Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
d3c48d800c
6 changed files with 92 additions and 26 deletions
|
|
@ -52,8 +52,9 @@ class ICowWriter {
|
||||||
virtual ~ICowWriter() {}
|
virtual ~ICowWriter() {}
|
||||||
|
|
||||||
// Encode an operation that copies the contents of |old_block| to the
|
// Encode an operation that copies the contents of |old_block| to the
|
||||||
// location of |new_block|.
|
// location of |new_block|. 'num_blocks' is the number of contiguous
|
||||||
bool AddCopy(uint64_t new_block, uint64_t old_block);
|
// 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.
|
// 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);
|
bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size);
|
||||||
|
|
@ -84,7 +85,7 @@ class ICowWriter {
|
||||||
const CowOptions& options() { return options_; }
|
const CowOptions& options() { return options_; }
|
||||||
|
|
||||||
protected:
|
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 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,
|
virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size,
|
||||||
uint32_t old_block, uint16_t offset) = 0;
|
uint32_t old_block, uint16_t offset) = 0;
|
||||||
|
|
@ -122,7 +123,7 @@ class CowWriter : public ICowWriter {
|
||||||
uint32_t GetCowVersion() { return header_.major_version; }
|
uint32_t GetCowVersion() { return header_.major_version; }
|
||||||
|
|
||||||
protected:
|
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 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,
|
virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size,
|
||||||
uint32_t old_block, uint16_t offset) override;
|
uint32_t old_block, uint16_t offset) override;
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ class MockSnapshotWriter : public ISnapshotWriter {
|
||||||
// Returns true if AddCopy() operations are supported.
|
// Returns true if AddCopy() operations are supported.
|
||||||
MOCK_METHOD(bool, SupportsCopyOperation, (), (const override));
|
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, EmitRawBlocks, (uint64_t, const void*, size_t), (override));
|
||||||
MOCK_METHOD(bool, EmitXorBlocks, (uint32_t, const void*, size_t, uint32_t, uint16_t),
|
MOCK_METHOD(bool, EmitXorBlocks, (uint32_t, const void*, size_t, uint32_t, uint16_t),
|
||||||
(override));
|
(override));
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ class CompressedSnapshotWriter final : public ISnapshotWriter {
|
||||||
bool VerifyMergeOps() const noexcept;
|
bool VerifyMergeOps() const noexcept;
|
||||||
|
|
||||||
protected:
|
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 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,
|
bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block,
|
||||||
uint16_t offset) override;
|
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 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,
|
bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block,
|
||||||
uint16_t offset) override;
|
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 EmitLabel(uint64_t label) override;
|
||||||
bool EmitSequenceData(size_t num_ops, const uint32_t* data) override;
|
bool EmitSequenceData(size_t num_ops, const uint32_t* data) override;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,48 @@ class StringSink : public IByteSink {
|
||||||
std::string stream_;
|
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) {
|
TEST_F(CowTest, ReadWrite) {
|
||||||
CowOptions options;
|
CowOptions options;
|
||||||
options.cluster_ops = 0;
|
options.cluster_ops = 0;
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,16 @@ static_assert(sizeof(off_t) == sizeof(uint64_t));
|
||||||
using android::base::borrowed_fd;
|
using android::base::borrowed_fd;
|
||||||
using android::base::unique_fd;
|
using android::base::unique_fd;
|
||||||
|
|
||||||
bool ICowWriter::AddCopy(uint64_t new_block, uint64_t old_block) {
|
bool ICowWriter::AddCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks) {
|
||||||
if (!ValidateNewBlock(new_block)) {
|
CHECK(num_blocks != 0);
|
||||||
return false;
|
|
||||||
|
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) {
|
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();
|
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_);
|
CHECK(!merge_in_progress_);
|
||||||
CowOperation op = {};
|
|
||||||
op.type = kCowCopyOp;
|
for (size_t i = 0; i < num_blocks; i++) {
|
||||||
op.new_block = new_block;
|
CowOperation op = {};
|
||||||
op.source = old_block;
|
op.type = kCowCopyOp;
|
||||||
return WriteOperation(op);
|
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) {
|
bool CowWriter::EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) {
|
||||||
|
|
|
||||||
|
|
@ -111,8 +111,9 @@ std::unique_ptr<FileDescriptor> CompressedSnapshotWriter::OpenReader() {
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompressedSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
|
bool CompressedSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block,
|
||||||
return cow_->AddCopy(new_block, 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,
|
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;
|
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();
|
auto source_fd = GetSourceFd();
|
||||||
if (source_fd < 0) {
|
if (source_fd < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string buffer(options_.block_size, 0);
|
CHECK(num_blocks != 0);
|
||||||
uint64_t offset = old_block * options_.block_size;
|
|
||||||
if (!android::base::ReadFullyAtOffset(source_fd, buffer.data(), buffer.size(), offset)) {
|
for (size_t i = 0; i < num_blocks; i++) {
|
||||||
PLOG(ERROR) << "EmitCopy read";
|
std::string buffer(options_.block_size, 0);
|
||||||
return false;
|
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) {
|
bool OnlineKernelSnapshotWriter::EmitLabel(uint64_t) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue