Merge "libsnapshot: Implement CowWriterV3::EmitzeroBlocks." into main

This commit is contained in:
Daniel Zheng 2023-11-02 21:52:18 +00:00 committed by Gerrit Code Review
commit 9f53082e3b
6 changed files with 84 additions and 4 deletions

View file

@ -145,6 +145,7 @@ class CowReader final : public ICowReader {
size_t ignore_bytes = 0) override;
CowHeader& GetHeader() override { return header_; }
const CowHeaderV3& header_v3() const { return header_; }
bool GetRawBytes(const CowOperation* op, void* buffer, size_t len, size_t* read);
bool GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read);

View file

@ -54,6 +54,9 @@ struct CowOptions {
// Batch write cluster ops
bool batch_write = false;
// Size of the cow operation buffer; used in v3 only.
uint32_t op_count_max = 0;
};
// Interface for writing to a snapuserd COW. All operations are ordered; merges

View file

@ -89,5 +89,36 @@ TEST_F(CowTestV3, Header) {
ASSERT_EQ(header.cluster_ops, 0);
}
TEST_F(CowTestV3, ZeroOp) {
CowOptions options;
options.op_count_max = 20;
auto writer = CreateCowWriter(3, options, GetCowFd());
ASSERT_TRUE(writer->AddZeroBlocks(1, 2));
ASSERT_TRUE(writer->Finalize());
CowReader reader;
ASSERT_TRUE(reader.Parse(cow_->fd));
ASSERT_EQ(reader.header_v3().op_count, 2);
auto iter = reader.GetOpIter();
ASSERT_NE(iter, nullptr);
ASSERT_FALSE(iter->AtEnd());
auto op = iter->Get();
ASSERT_EQ(op->type, kCowZeroOp);
ASSERT_EQ(op->data_length, 0);
ASSERT_EQ(op->new_block, 1);
ASSERT_EQ(op->source_info, 0);
iter->Next();
ASSERT_FALSE(iter->AtEnd());
op = iter->Get();
ASSERT_EQ(op->type, kCowZeroOp);
ASSERT_EQ(op->data_length, 0);
ASSERT_EQ(op->new_block, 2);
ASSERT_EQ(op->source_info, 0);
}
} // namespace snapshot
} // namespace android

View file

@ -62,6 +62,8 @@ class CowWriterBase : public ICowWriter {
bool InitFd();
bool ValidateNewBlock(uint64_t new_block);
bool IsEstimating() const { return is_dev_null_; }
CowOptions options_;
android::base::unique_fd fd_;

View file

@ -155,6 +155,7 @@ bool CowWriterV3::OpenForWrite() {
return false;
}
}
header_.op_count_max = options_.op_count_max;
if (!Sync()) {
LOG(ERROR) << "Header sync failed";
@ -184,9 +185,17 @@ bool CowWriterV3::EmitXorBlocks(uint32_t new_block_start, const void* data, size
}
bool CowWriterV3::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called";
if (new_block_start && num_blocks) return false;
return false;
for (uint64_t i = 0; i < num_blocks; i++) {
CowOperationV3 op;
op.type = kCowZeroOp;
op.data_length = 0;
op.new_block = new_block_start + i;
op.source_info = 0;
if (!WriteOperation(op)) {
return false;
}
}
return true;
}
bool CowWriterV3::EmitLabel(uint64_t label) {
@ -201,7 +210,33 @@ bool CowWriterV3::EmitSequenceData(size_t num_ops, const uint32_t* data) {
return false;
}
bool CowWriterV3::WriteOperation(const CowOperationV3& op) {
if (IsEstimating()) {
header_.op_count++;
header_.op_count_max++;
return true;
}
if (header_.op_count + 1 > header_.op_count_max) {
LOG(ERROR) << "Maximum number of ops reached: " << header_.op_count_max;
return false;
}
const off_t offset = GetOpOffset(header_.op_count);
if (!android::base::WriteFullyAtOffset(fd_, &op, sizeof(op), offset)) {
return false;
}
header_.op_count++;
return true;
}
bool CowWriterV3::Finalize() {
CHECK_GE(header_.prefix.header_size, sizeof(CowHeaderV3));
CHECK_LE(header_.prefix.header_size, sizeof(header_));
if (!android::base::WriteFullyAtOffset(fd_, &header_, header_.prefix.header_size, 0)) {
return false;
}
return Sync();
}

View file

@ -14,7 +14,8 @@
#pragma once
#include <future>
#include <android-base/logging.h>
#include "writer_base.h"
namespace android {
@ -42,6 +43,13 @@ class CowWriterV3 : public CowWriterBase {
void SetupHeaders();
bool ParseOptions();
bool OpenForWrite();
bool WriteOperation(const CowOperationV3& op);
off_t GetOpOffset(uint32_t op_index) const {
CHECK_LT(op_index, header_.op_count_max);
return header_.prefix.header_size + header_.buffer_size +
(op_index * sizeof(CowOperationV3));
}
private:
CowHeaderV3 header_{};