Merge "libsnapshot: Remove Initialize(fd, APPEND)"
This commit is contained in:
commit
d021544d04
5 changed files with 46 additions and 111 deletions
|
|
@ -271,7 +271,7 @@ TEST_F(CowTest, GetSize) {
|
|||
ASSERT_EQ(buf.st_size, writer.GetCowSize());
|
||||
}
|
||||
|
||||
TEST_F(CowTest, Append) {
|
||||
TEST_F(CowTest, AppendLabelSmall) {
|
||||
CowOptions options;
|
||||
auto writer = std::make_unique<CowWriter>(options);
|
||||
ASSERT_TRUE(writer->Initialize(cow_->fd));
|
||||
|
|
@ -279,12 +279,13 @@ TEST_F(CowTest, Append) {
|
|||
std::string data = "This is some data, believe it";
|
||||
data.resize(options.block_size, '\0');
|
||||
ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
|
||||
ASSERT_TRUE(writer->AddLabel(3));
|
||||
ASSERT_TRUE(writer->Finalize());
|
||||
|
||||
ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
|
||||
|
||||
writer = std::make_unique<CowWriter>(options);
|
||||
ASSERT_TRUE(writer->Initialize(cow_->fd, CowWriter::OpenMode::APPEND));
|
||||
ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 3));
|
||||
|
||||
std::string data2 = "More data!";
|
||||
data2.resize(options.block_size, '\0');
|
||||
|
|
@ -297,11 +298,12 @@ TEST_F(CowTest, Append) {
|
|||
ASSERT_EQ(fstat(cow_->fd, &buf), 0);
|
||||
ASSERT_EQ(buf.st_size, writer->GetCowSize());
|
||||
|
||||
// Read back both operations.
|
||||
// Read back both operations, and label.
|
||||
CowReader reader;
|
||||
uint64_t label;
|
||||
ASSERT_TRUE(reader.Parse(cow_->fd));
|
||||
ASSERT_FALSE(reader.GetLastLabel(&label));
|
||||
ASSERT_TRUE(reader.GetLastLabel(&label));
|
||||
ASSERT_EQ(label, 3);
|
||||
|
||||
StringSink sink;
|
||||
|
||||
|
|
@ -317,6 +319,13 @@ TEST_F(CowTest, Append) {
|
|||
iter->Next();
|
||||
sink.Reset();
|
||||
|
||||
ASSERT_FALSE(iter->Done());
|
||||
op = &iter->Get();
|
||||
ASSERT_EQ(op->type, kCowLabelOp);
|
||||
ASSERT_EQ(op->source, 3);
|
||||
|
||||
iter->Next();
|
||||
|
||||
ASSERT_FALSE(iter->Done());
|
||||
op = &iter->Get();
|
||||
ASSERT_EQ(op->type, kCowReplaceOp);
|
||||
|
|
@ -327,33 +336,26 @@ TEST_F(CowTest, Append) {
|
|||
ASSERT_TRUE(iter->Done());
|
||||
}
|
||||
|
||||
TEST_F(CowTest, AppendCorrupted) {
|
||||
TEST_F(CowTest, AppendLabelMissing) {
|
||||
CowOptions options;
|
||||
auto writer = std::make_unique<CowWriter>(options);
|
||||
ASSERT_TRUE(writer->Initialize(cow_->fd));
|
||||
|
||||
ASSERT_TRUE(writer->AddLabel(0));
|
||||
std::string data = "This is some data, believe it";
|
||||
data.resize(options.block_size, '\0');
|
||||
ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
|
||||
ASSERT_TRUE(writer->AddLabel(0));
|
||||
ASSERT_TRUE(writer->AddZeroBlocks(50, 1));
|
||||
ASSERT_TRUE(writer->Finalize());
|
||||
// Drop the tail end of the header. Last entry may be corrupted.
|
||||
ftruncate(cow_->fd, writer->GetCowSize() - 5);
|
||||
ASSERT_TRUE(writer->AddLabel(1));
|
||||
// Drop the tail end of the last op header, corrupting it.
|
||||
ftruncate(cow_->fd, writer->GetCowSize() - sizeof(CowFooter) - 3);
|
||||
|
||||
ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
|
||||
|
||||
writer = std::make_unique<CowWriter>(options);
|
||||
ASSERT_TRUE(writer->Initialize(cow_->fd, CowWriter::OpenMode::APPEND));
|
||||
ASSERT_FALSE(writer->InitializeAppend(cow_->fd, 1));
|
||||
ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 0));
|
||||
|
||||
ASSERT_TRUE(writer->AddZeroBlocks(51, 1));
|
||||
ASSERT_TRUE(writer->AddLabel(1));
|
||||
|
||||
std::string data2 = "More data!";
|
||||
data2.resize(options.block_size, '\0');
|
||||
ASSERT_TRUE(writer->AddRawBlocks(52, data2.data(), data2.size()));
|
||||
ASSERT_TRUE(writer->AddLabel(2));
|
||||
|
||||
ASSERT_TRUE(writer->Finalize());
|
||||
|
||||
ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
|
||||
|
|
@ -362,7 +364,7 @@ TEST_F(CowTest, AppendCorrupted) {
|
|||
ASSERT_EQ(fstat(cow_->fd, &buf), 0);
|
||||
ASSERT_EQ(buf.st_size, writer->GetCowSize());
|
||||
|
||||
// Read back all three operations.
|
||||
// Read back both operations.
|
||||
CowReader reader;
|
||||
ASSERT_TRUE(reader.Parse(cow_->fd));
|
||||
|
||||
|
|
@ -373,15 +375,6 @@ TEST_F(CowTest, AppendCorrupted) {
|
|||
|
||||
ASSERT_FALSE(iter->Done());
|
||||
auto op = &iter->Get();
|
||||
ASSERT_EQ(op->type, kCowReplaceOp);
|
||||
ASSERT_TRUE(reader.ReadData(*op, &sink));
|
||||
ASSERT_EQ(sink.stream(), data);
|
||||
|
||||
iter->Next();
|
||||
sink.Reset();
|
||||
|
||||
ASSERT_FALSE(iter->Done());
|
||||
op = &iter->Get();
|
||||
ASSERT_EQ(op->type, kCowLabelOp);
|
||||
ASSERT_EQ(op->source, 0);
|
||||
|
||||
|
|
@ -393,27 +386,6 @@ TEST_F(CowTest, AppendCorrupted) {
|
|||
|
||||
iter->Next();
|
||||
|
||||
ASSERT_FALSE(iter->Done());
|
||||
op = &iter->Get();
|
||||
ASSERT_EQ(op->type, kCowLabelOp);
|
||||
ASSERT_EQ(op->source, 1);
|
||||
|
||||
iter->Next();
|
||||
|
||||
ASSERT_FALSE(iter->Done());
|
||||
op = &iter->Get();
|
||||
ASSERT_EQ(op->type, kCowReplaceOp);
|
||||
ASSERT_TRUE(reader.ReadData(*op, &sink));
|
||||
ASSERT_EQ(sink.stream(), data2);
|
||||
|
||||
iter->Next();
|
||||
|
||||
ASSERT_FALSE(iter->Done());
|
||||
op = &iter->Get();
|
||||
ASSERT_EQ(op->type, kCowLabelOp);
|
||||
ASSERT_EQ(op->source, 2);
|
||||
iter->Next();
|
||||
|
||||
ASSERT_TRUE(iter->Done());
|
||||
}
|
||||
|
||||
|
|
@ -429,7 +401,7 @@ TEST_F(CowTest, AppendExtendedCorrupted) {
|
|||
ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
|
||||
ASSERT_TRUE(writer->AddLabel(6));
|
||||
|
||||
// fail to write the footer
|
||||
// fail to write the footer. Cow Format does not know if Label 6 is valid
|
||||
|
||||
ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
|
||||
|
||||
|
|
@ -443,7 +415,7 @@ TEST_F(CowTest, AppendExtendedCorrupted) {
|
|||
ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
|
||||
|
||||
writer = std::make_unique<CowWriter>(options);
|
||||
ASSERT_TRUE(writer->Initialize(cow_->fd, CowWriter::OpenMode::APPEND));
|
||||
ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 5));
|
||||
|
||||
ASSERT_TRUE(writer->Finalize());
|
||||
|
||||
|
|
|
|||
|
|
@ -125,25 +125,17 @@ bool CowWriter::SetFd(android::base::borrowed_fd fd) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CowWriter::Initialize(unique_fd&& fd, OpenMode mode) {
|
||||
bool CowWriter::Initialize(unique_fd&& fd) {
|
||||
owned_fd_ = std::move(fd);
|
||||
return Initialize(borrowed_fd{owned_fd_}, mode);
|
||||
return Initialize(borrowed_fd{owned_fd_});
|
||||
}
|
||||
|
||||
bool CowWriter::Initialize(borrowed_fd fd, OpenMode mode) {
|
||||
bool CowWriter::Initialize(borrowed_fd fd) {
|
||||
if (!SetFd(fd) || !ParseOptions()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case OpenMode::WRITE:
|
||||
return OpenForWrite();
|
||||
case OpenMode::APPEND:
|
||||
return OpenForAppend();
|
||||
default:
|
||||
LOG(ERROR) << "Unknown open mode in CowWriter";
|
||||
return false;
|
||||
}
|
||||
return OpenForWrite();
|
||||
}
|
||||
|
||||
bool CowWriter::InitializeAppend(android::base::unique_fd&& fd, uint64_t label) {
|
||||
|
|
@ -182,17 +174,15 @@ bool CowWriter::OpenForWrite() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CowWriter::OpenForAppend(std::optional<uint64_t> label) {
|
||||
bool CowWriter::OpenForAppend(uint64_t label) {
|
||||
auto reader = std::make_unique<CowReader>();
|
||||
bool incomplete = false;
|
||||
bool add_next = false;
|
||||
std::queue<CowOperation> toAdd;
|
||||
bool found_label = false;
|
||||
|
||||
if (!reader->Parse(fd_) || !reader->GetHeader(&header_)) {
|
||||
return false;
|
||||
}
|
||||
incomplete = !reader->GetFooter(&footer_);
|
||||
reader->GetFooter(&footer_);
|
||||
|
||||
options_.block_size = header_.block_size;
|
||||
|
||||
|
|
@ -203,36 +193,16 @@ bool CowWriter::OpenForAppend(std::optional<uint64_t> label) {
|
|||
|
||||
auto iter = reader->GetOpIter();
|
||||
while (!iter->Done() && !found_label) {
|
||||
CowOperation op = iter->Get();
|
||||
const CowOperation& op = iter->Get();
|
||||
|
||||
if (op.type == kCowFooterOp) break;
|
||||
if (label.has_value()) {
|
||||
if (op.type == kCowFooterOp) break;
|
||||
if (op.type == kCowLabelOp) {
|
||||
if (op.source == label) found_label = true;
|
||||
}
|
||||
AddOperation(op);
|
||||
} else {
|
||||
if (incomplete) {
|
||||
// Last set of labeled operations may be corrupt. Wait to add it.
|
||||
// We always sync after a label. If we see ops after a label, we
|
||||
// can infer that sync must have completed.
|
||||
if (add_next) {
|
||||
add_next = false;
|
||||
while (!toAdd.empty()) {
|
||||
AddOperation(toAdd.front());
|
||||
toAdd.pop();
|
||||
}
|
||||
}
|
||||
toAdd.push(op);
|
||||
if (op.type == kCowLabelOp) add_next = true;
|
||||
} else {
|
||||
AddOperation(op);
|
||||
}
|
||||
}
|
||||
if (op.type == kCowLabelOp && op.source == label) found_label = true;
|
||||
AddOperation(op);
|
||||
|
||||
iter->Next();
|
||||
}
|
||||
|
||||
if (label.has_value() && !found_label) {
|
||||
if (!found_label) {
|
||||
LOG(ERROR) << "Failed to find last label";
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,19 +82,15 @@ class ICowWriter {
|
|||
|
||||
class CowWriter : public ICowWriter {
|
||||
public:
|
||||
enum class OpenMode { WRITE, APPEND };
|
||||
|
||||
explicit CowWriter(const CowOptions& options);
|
||||
|
||||
// Set up the writer.
|
||||
// If opening for write, the file starts from the beginning.
|
||||
// If opening for append, if the file has a footer, we start appending to the last op.
|
||||
// If the footer isn't found, the last label is considered corrupt, and dropped.
|
||||
// The file starts from the beginning.
|
||||
//
|
||||
// If fd is < 0, the CowWriter will be opened against /dev/null. This is for
|
||||
// computing COW sizes without using storage space.
|
||||
bool Initialize(android::base::unique_fd&& fd, OpenMode mode = OpenMode::WRITE);
|
||||
bool Initialize(android::base::borrowed_fd fd, OpenMode mode = OpenMode::WRITE);
|
||||
bool Initialize(android::base::unique_fd&& fd);
|
||||
bool Initialize(android::base::borrowed_fd fd);
|
||||
// Set up a writer, assuming that the given label is the last valid label.
|
||||
// This will result in dropping any labels that occur after the given on, and will fail
|
||||
// if the given label does not appear.
|
||||
|
|
@ -115,7 +111,7 @@ class CowWriter : public ICowWriter {
|
|||
void SetupHeaders();
|
||||
bool ParseOptions();
|
||||
bool OpenForWrite();
|
||||
bool OpenForAppend(std::optional<uint64_t> label = std::nullopt);
|
||||
bool OpenForAppend(uint64_t label);
|
||||
bool GetDataPos(uint64_t* pos);
|
||||
bool WriteRawData(const void* data, size_t size);
|
||||
bool WriteOperation(const CowOperation& op, const void* data = nullptr, size_t size = 0);
|
||||
|
|
|
|||
|
|
@ -42,9 +42,9 @@ class ISnapshotWriter : public ICowWriter {
|
|||
// Open the writer in write mode (no append).
|
||||
virtual bool Initialize() = 0;
|
||||
|
||||
// Open the writer in append mode, optionally with the last label to resume
|
||||
// Open the writer in append mode, with the last label to resume
|
||||
// from. See CowWriter::InitializeAppend.
|
||||
virtual bool InitializeAppend(std::optional<uint64_t> label = {}) = 0;
|
||||
virtual bool InitializeAppend(uint64_t label) = 0;
|
||||
|
||||
virtual std::unique_ptr<FileDescriptor> OpenReader() = 0;
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ class CompressedSnapshotWriter : public ISnapshotWriter {
|
|||
bool SetCowDevice(android::base::unique_fd&& cow_device);
|
||||
|
||||
bool Initialize() override;
|
||||
bool InitializeAppend(std::optional<uint64_t> label = {}) override;
|
||||
bool InitializeAppend(uint64_t label) override;
|
||||
bool Finalize() override;
|
||||
uint64_t GetCowSize() override;
|
||||
std::unique_ptr<FileDescriptor> OpenReader() override;
|
||||
|
|
@ -92,7 +92,7 @@ class OnlineKernelSnapshotWriter : public ISnapshotWriter {
|
|||
void SetSnapshotDevice(android::base::unique_fd&& snapshot_fd, uint64_t cow_size);
|
||||
|
||||
bool Initialize() override { return true; }
|
||||
bool InitializeAppend(std::optional<uint64_t>) override { return true; }
|
||||
bool InitializeAppend(uint64_t) override { return true; }
|
||||
|
||||
bool Finalize() override;
|
||||
uint64_t GetCowSize() override { return cow_size_; }
|
||||
|
|
|
|||
|
|
@ -113,14 +113,11 @@ bool CompressedSnapshotWriter::EmitLabel(uint64_t label) {
|
|||
}
|
||||
|
||||
bool CompressedSnapshotWriter::Initialize() {
|
||||
return cow_->Initialize(cow_device_, CowWriter::OpenMode::WRITE);
|
||||
return cow_->Initialize(cow_device_);
|
||||
}
|
||||
|
||||
bool CompressedSnapshotWriter::InitializeAppend(std::optional<uint64_t> label) {
|
||||
if (label) {
|
||||
return cow_->InitializeAppend(cow_device_, *label);
|
||||
}
|
||||
return cow_->Initialize(cow_device_, CowWriter::OpenMode::APPEND);
|
||||
bool CompressedSnapshotWriter::InitializeAppend(uint64_t label) {
|
||||
return cow_->InitializeAppend(cow_device_, label);
|
||||
}
|
||||
|
||||
OnlineKernelSnapshotWriter::OnlineKernelSnapshotWriter(const CowOptions& options)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue