snapuserd: Add XorSink

We can compute the xor while decompessing by computing it within a
buffer. This would allow us to use a smaller buffer than the full block
size if we wish to cut down on the extra memory required.

Bug: 177104308
Test: cow_snapuserd_test (Snapuserd_Test.xor_buffer)
Change-Id: Id18505841c77340760cea2d20e83454f1142b9b5
This commit is contained in:
Daniel Rosenberg 2021-07-12 21:41:23 -07:00
parent d091522de9
commit edf7c667da
3 changed files with 76 additions and 0 deletions

View file

@ -1039,6 +1039,35 @@ void CowSnapuserdMetadataTest::ValidateMetadata() {
}
}
TEST(Snapuserd_Test, xor_buffer) {
std::string data = "Test String";
std::string jumbled = {0x0C, 0x2A, 0x21, 0x54, 0x73, 0x27, 0x06, 0x1B, 0x07, 0x09, 0x46};
std::string result = "XOR String!";
BufferSink sink;
XorSink xor_sink;
sink.Initialize(sizeof(struct dm_user_header) + 10);
int buffsize = 5;
xor_sink.Initialize(&sink, buffsize);
void* buff = sink.GetPayloadBuffer(data.length());
memcpy(buff, data.data(), data.length());
size_t actual;
size_t count = 0;
while (count < data.length()) {
void* xor_buff = xor_sink.GetBuffer(10, &actual);
ASSERT_EQ(actual, buffsize);
ASSERT_NE(xor_buff, nullptr);
memcpy(xor_buff, jumbled.data() + count, buffsize);
xor_sink.ReturnData(xor_buff, actual);
count += actual;
}
std::string answer = reinterpret_cast<char*>(sink.GetPayloadBufPtr());
ASSERT_EQ(answer, result);
}
TEST(Snapuserd_Test, Snapshot_Metadata) {
CowSnapuserdMetadataTest harness;
harness.Setup();

View file

@ -107,6 +107,20 @@ class BufferSink : public IByteSink {
size_t buffer_size_;
};
class XorSink : public IByteSink {
public:
void Initialize(BufferSink* sink, size_t size);
void Reset();
void* GetBuffer(size_t requested, size_t* actual) override;
bool ReturnData(void* buffer, size_t len) override;
private:
BufferSink* bufsink_;
std::unique_ptr<uint8_t[]> buffer_;
size_t buffer_size_;
size_t returned_;
};
class Snapuserd;
class ReadAheadThread {

View file

@ -71,6 +71,39 @@ void* BufferSink::GetPayloadBufPtr() {
return msg->payload.buf;
}
void XorSink::Initialize(BufferSink* sink, size_t size) {
bufsink_ = sink;
buffer_size_ = size;
returned_ = 0;
buffer_ = std::make_unique<uint8_t[]>(size);
}
void XorSink::Reset() {
returned_ = 0;
}
void* XorSink::GetBuffer(size_t requested, size_t* actual) {
if (requested > buffer_size_) {
*actual = buffer_size_;
} else {
*actual = requested;
}
return buffer_.get();
}
bool XorSink::ReturnData(void* buffer, size_t len) {
uint8_t* xor_data = reinterpret_cast<uint8_t*>(buffer);
uint8_t* buff = reinterpret_cast<uint8_t*>(bufsink_->GetPayloadBuffer(len + returned_));
if (buff == nullptr) {
return false;
}
for (size_t i = 0; i < len; i++) {
buff[returned_ + i] ^= xor_data[i];
}
returned_ += len;
return true;
}
WorkerThread::WorkerThread(const std::string& cow_device, const std::string& backing_device,
const std::string& control_device, const std::string& misc_name,
std::shared_ptr<Snapuserd> snapuserd) {