libsnapshot: Add cluster breaks after ops
Previously, we'd check if a new cluster was needed before we added a Cow Operation. This would cause an op's associated data to go to the wrong location, so instead we check if we'll need a new cluster after writing each op. Bug: 172026020 Test: cow_api_test (ClusterCompressGz) Change-Id: Ia43afedcfd430961b34f5914da4265b89e6fadb9
This commit is contained in:
parent
819ca32a0a
commit
770099bde1
2 changed files with 69 additions and 5 deletions
|
|
@ -171,6 +171,70 @@ TEST_F(CowTest, CompressGz) {
|
|||
ASSERT_TRUE(iter->Done());
|
||||
}
|
||||
|
||||
TEST_F(CowTest, ClusterCompressGz) {
|
||||
CowOptions options;
|
||||
options.compression = "gz";
|
||||
options.cluster_ops = 2;
|
||||
CowWriter writer(options);
|
||||
|
||||
ASSERT_TRUE(writer.Initialize(cow_->fd));
|
||||
|
||||
std::string data = "This is some data, believe it";
|
||||
data.resize(options.block_size, '\0');
|
||||
ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
|
||||
|
||||
std::string data2 = "More data!";
|
||||
data2.resize(options.block_size, '\0');
|
||||
ASSERT_TRUE(writer.AddRawBlocks(51, data2.data(), data2.size()));
|
||||
|
||||
ASSERT_TRUE(writer.Finalize());
|
||||
|
||||
ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
|
||||
|
||||
CowReader reader;
|
||||
ASSERT_TRUE(reader.Parse(cow_->fd));
|
||||
|
||||
auto iter = reader.GetOpIter();
|
||||
ASSERT_NE(iter, nullptr);
|
||||
ASSERT_FALSE(iter->Done());
|
||||
auto op = &iter->Get();
|
||||
|
||||
StringSink sink;
|
||||
|
||||
ASSERT_EQ(op->type, kCowReplaceOp);
|
||||
ASSERT_EQ(op->compression, kCowCompressGz);
|
||||
ASSERT_EQ(op->data_length, 56); // compressed!
|
||||
ASSERT_EQ(op->new_block, 50);
|
||||
ASSERT_TRUE(reader.ReadData(*op, &sink));
|
||||
ASSERT_EQ(sink.stream(), data);
|
||||
|
||||
iter->Next();
|
||||
ASSERT_FALSE(iter->Done());
|
||||
op = &iter->Get();
|
||||
|
||||
ASSERT_EQ(op->type, kCowClusterOp);
|
||||
|
||||
iter->Next();
|
||||
ASSERT_FALSE(iter->Done());
|
||||
op = &iter->Get();
|
||||
|
||||
sink.Reset();
|
||||
ASSERT_EQ(op->compression, kCowCompressGz);
|
||||
ASSERT_EQ(op->data_length, 41); // compressed!
|
||||
ASSERT_EQ(op->new_block, 51);
|
||||
ASSERT_TRUE(reader.ReadData(*op, &sink));
|
||||
ASSERT_EQ(sink.stream(), data2);
|
||||
|
||||
iter->Next();
|
||||
ASSERT_FALSE(iter->Done());
|
||||
op = &iter->Get();
|
||||
|
||||
ASSERT_EQ(op->type, kCowClusterOp);
|
||||
|
||||
iter->Next();
|
||||
ASSERT_TRUE(iter->Done());
|
||||
}
|
||||
|
||||
TEST_F(CowTest, CompressTwoBlocks) {
|
||||
CowOptions options;
|
||||
options.compression = "gz";
|
||||
|
|
|
|||
|
|
@ -433,11 +433,6 @@ bool CowWriter::GetDataPos(uint64_t* pos) {
|
|||
}
|
||||
|
||||
bool CowWriter::WriteOperation(const CowOperation& op, const void* data, size_t size) {
|
||||
// If there isn't room for this op and the cluster end op, end the current cluster
|
||||
if (cluster_size_ && op.type != kCowClusterOp &&
|
||||
cluster_size_ < current_cluster_size_ + 2 * sizeof(op)) {
|
||||
if (!EmitCluster()) return false;
|
||||
}
|
||||
if (lseek(fd_.get(), next_op_pos_, SEEK_SET) < 0) {
|
||||
PLOG(ERROR) << "lseek failed for writing operation.";
|
||||
return false;
|
||||
|
|
@ -449,6 +444,11 @@ bool CowWriter::WriteOperation(const CowOperation& op, const void* data, size_t
|
|||
if (!WriteRawData(data, size)) return false;
|
||||
}
|
||||
AddOperation(op);
|
||||
// If there isn't room for another op and the cluster end op, end the current cluster
|
||||
if (cluster_size_ && op.type != kCowClusterOp &&
|
||||
cluster_size_ < current_cluster_size_ + 2 * sizeof(op)) {
|
||||
if (!EmitCluster()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue