Merge "libsnapshot: Implement CowWriterV3::EmitzeroBlocks." into main
This commit is contained in:
commit
9f53082e3b
6 changed files with 84 additions and 4 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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_{};
|
||||
|
|
Loading…
Reference in a new issue