Refactor off COW header v3

Cow reader will store header v3 in memory. ReadCowHeader can remain
mostly unchanged since the cow prefix is the same.
header->prefix.header_size will then tell us if we're reading a v3 or v2
header. v3 header is strictly a superset of v2 header so we can read a
v2 header into a v3 struct.

Added a test case to test_v3 where we write a header using v2_writer and
ensure CowReader is able to read it.

Test: cow_api_test
Change-Id: I142f18d871322930b7dc341c342c8b63a481341c
This commit is contained in:
Daniel Zheng 2023-10-16 20:12:56 -07:00
parent f2270d2bb6
commit 7a9e007a01
6 changed files with 38 additions and 8 deletions

View file

@ -172,7 +172,7 @@ class CowReader final : public ICowReader {
android::base::unique_fd owned_fd_;
android::base::borrowed_fd fd_;
CowHeader header_;
CowHeaderV3 header_;
std::optional<CowFooter> footer_;
uint64_t fd_size_;
std::optional<uint64_t> last_label_;
@ -188,7 +188,10 @@ class CowReader final : public ICowReader {
uint8_t compression_type_ = kCowCompressNone;
};
bool ReadCowHeader(android::base::borrowed_fd fd, CowHeader* header);
// Though this function takes in a CowHeaderV3, the struct could be populated as a v1/v2 CowHeader.
// The extra fields will just be filled as 0. V3 header is strictly a superset of v1/v2 header and
// contains all of the latter's field
bool ReadCowHeader(android::base::borrowed_fd fd, CowHeaderV3* header);
} // namespace snapshot
} // namespace android

View file

@ -28,12 +28,13 @@
#include <zlib.h>
#include "cow_decompress.h"
#include "libsnapshot/cow_format.h"
#include "parser_v2.h"
namespace android {
namespace snapshot {
bool ReadCowHeader(android::base::borrowed_fd fd, CowHeader* header) {
bool ReadCowHeader(android::base::borrowed_fd fd, CowHeaderV3* header) {
if (lseek(fd.get(), 0, SEEK_SET) < 0) {
PLOG(ERROR) << "lseek header failed";
return false;
@ -49,9 +50,9 @@ bool ReadCowHeader(android::base::borrowed_fd fd, CowHeader* header) {
<< "Expected: " << kCowMagicNumber;
return false;
}
if (header->prefix.header_size > sizeof(CowHeader)) {
if (header->prefix.header_size > sizeof(CowHeaderV3)) {
LOG(ERROR) << "Unknown CowHeader size (got " << header->prefix.header_size
<< " bytes, expected at most " << sizeof(CowHeader) << " bytes)";
<< " bytes, expected at most " << sizeof(CowHeaderV3) << " bytes)";
return false;
}

View file

@ -90,7 +90,7 @@ static bool ShowRawOpStreamV2(borrowed_fd fd, const CowHeader& header) {
}
static bool ShowRawOpStream(borrowed_fd fd) {
CowHeader header;
CowHeaderV3 header;
if (!ReadCowHeader(fd, &header)) {
LOG(ERROR) << "parse header failed";
return false;

View file

@ -26,7 +26,9 @@
#include <libsnapshot/cow_writer.h>
#include "cow_decompress.h"
#include "libsnapshot/cow_format.h"
#include "writer_v2.h"
#include "writer_v3.h"
using android::base::unique_fd;
using testing::AssertionFailure;
using testing::AssertionResult;
@ -49,5 +51,27 @@ class CowOperationV3Test : public ::testing::Test {
std::unique_ptr<TemporaryFile> cow_;
};
TEST_F(CowOperationV3Test, CowHeaderV2Test) {
CowOptions options;
options.cluster_ops = 5;
options.num_merge_ops = 1;
options.block_size = 4096;
std::string data = "This is some data, believe it";
data.resize(options.block_size, '\0');
auto writer_v2 = std::make_unique<CowWriterV2>(options, GetCowFd());
ASSERT_TRUE(writer_v2->Initialize());
ASSERT_TRUE(writer_v2->Finalize());
CowReader reader;
ASSERT_TRUE(reader.Parse(cow_->fd));
const auto& header = reader.GetHeader();
ASSERT_EQ(header.prefix.magic, kCowMagicNumber);
ASSERT_EQ(header.prefix.major_version, kCowVersionMajor);
ASSERT_EQ(header.prefix.minor_version, kCowVersionMinor);
ASSERT_EQ(header.block_size, options.block_size);
ASSERT_EQ(header.cluster_ops, options.cluster_ops);
}
} // namespace snapshot
} // namespace android

View file

@ -269,9 +269,11 @@ bool CowWriterV2::OpenForWrite() {
}
bool CowWriterV2::OpenForAppend(uint64_t label) {
if (!ReadCowHeader(fd_, &header_)) {
CowHeaderV3 header_v3;
if (!ReadCowHeader(fd_, &header_v3)) {
return false;
}
header_ = header_v3;
CowParserV2 parser;
if (!parser.Parse(fd_, header_, {label})) {

View file

@ -3658,7 +3658,7 @@ std::unique_ptr<ICowWriter> SnapshotManager::OpenCompressedSnapshotWriter(
return nullptr;
}
CowHeader header;
CowHeaderV3 header;
if (!ReadCowHeader(cow_fd, &header)) {
LOG(ERROR) << "OpenCompressedSnapshotWriter: read header failed";
return nullptr;