Merge "libsnapshot: Changes to AddCopy() API"
This commit is contained in:
commit
ad5cc05ca2
6 changed files with 92 additions and 26 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue