rocksdb/db/wide/wide_column_serialization_test.cc
Levi Tamasi e9c74bc474 Add wide column serialization primitives (#9915)
Summary:
The patch adds some low-level logic that can be used to serialize/deserialize
a sorted vector of wide columns to/from a simple binary searchable string
representation. Currently, there is no user-facing API; this will be implemented in
subsequent stages.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/9915

Test Plan: `make check`

Reviewed By: siying

Differential Revision: D35978076

Pulled By: ltamasi

fbshipit-source-id: 33f5f6628ec3bcd8c8beab363b1978ac047a8788
2022-06-03 20:54:48 -07:00

293 lines
7.4 KiB
C++

// Copyright (c) Meta Platforms, Inc. and affiliates.
// This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).
#include "db/wide/wide_column_serialization.h"
#include "test_util/testharness.h"
#include "util/coding.h"
namespace ROCKSDB_NAMESPACE {
TEST(WideColumnSerializationTest, Construct) {
constexpr char foo[] = "foo";
constexpr char bar[] = "bar";
const std::string foo_str(foo);
const std::string bar_str(bar);
const Slice foo_slice(foo_str);
const Slice bar_slice(bar_str);
{
WideColumn column(foo, bar);
ASSERT_EQ(column.name(), foo);
ASSERT_EQ(column.value(), bar);
}
{
WideColumn column(foo_str, bar);
ASSERT_EQ(column.name(), foo_str);
ASSERT_EQ(column.value(), bar);
}
{
WideColumn column(foo_slice, bar);
ASSERT_EQ(column.name(), foo_slice);
ASSERT_EQ(column.value(), bar);
}
{
WideColumn column(foo, bar_str);
ASSERT_EQ(column.name(), foo);
ASSERT_EQ(column.value(), bar_str);
}
{
WideColumn column(foo_str, bar_str);
ASSERT_EQ(column.name(), foo_str);
ASSERT_EQ(column.value(), bar_str);
}
{
WideColumn column(foo_slice, bar_str);
ASSERT_EQ(column.name(), foo_slice);
ASSERT_EQ(column.value(), bar_str);
}
{
WideColumn column(foo, bar_slice);
ASSERT_EQ(column.name(), foo);
ASSERT_EQ(column.value(), bar_slice);
}
{
WideColumn column(foo_str, bar_slice);
ASSERT_EQ(column.name(), foo_str);
ASSERT_EQ(column.value(), bar_slice);
}
{
WideColumn column(foo_slice, bar_slice);
ASSERT_EQ(column.name(), foo_slice);
ASSERT_EQ(column.value(), bar_slice);
}
{
constexpr char foo_name[] = "foo_name";
constexpr char bar_value[] = "bar_value";
WideColumn column(std::piecewise_construct,
std::forward_as_tuple(foo_name, sizeof(foo) - 1),
std::forward_as_tuple(bar_value, sizeof(bar) - 1));
ASSERT_EQ(column.name(), foo);
ASSERT_EQ(column.value(), bar);
}
}
TEST(WideColumnSerializationTest, SerializeDeserialize) {
WideColumns columns{{"foo", "bar"}, {"hello", "world"}};
std::string output;
ASSERT_OK(WideColumnSerialization::Serialize(columns, output));
Slice input(output);
WideColumns deserialized_columns;
ASSERT_OK(WideColumnSerialization::Deserialize(input, deserialized_columns));
ASSERT_EQ(columns, deserialized_columns);
{
const auto it = WideColumnSerialization::Find(deserialized_columns, "foo");
ASSERT_NE(it, deserialized_columns.cend());
ASSERT_EQ(*it, deserialized_columns.front());
}
{
const auto it =
WideColumnSerialization::Find(deserialized_columns, "hello");
ASSERT_NE(it, deserialized_columns.cend());
ASSERT_EQ(*it, deserialized_columns.back());
}
{
const auto it =
WideColumnSerialization::Find(deserialized_columns, "fubar");
ASSERT_EQ(it, deserialized_columns.cend());
}
{
const auto it =
WideColumnSerialization::Find(deserialized_columns, "snafu");
ASSERT_EQ(it, deserialized_columns.cend());
}
}
TEST(WideColumnSerializationTest, DeserializeVersionError) {
// Can't decode version
std::string buf;
Slice input(buf);
WideColumns columns;
const Status s = WideColumnSerialization::Deserialize(input, columns);
ASSERT_TRUE(s.IsCorruption());
ASSERT_TRUE(std::strstr(s.getState(), "version"));
}
TEST(WideColumnSerializationTest, DeserializeUnsupportedVersion) {
// Unsupported version
constexpr uint32_t future_version = 1000;
std::string buf;
PutVarint32(&buf, future_version);
Slice input(buf);
WideColumns columns;
const Status s = WideColumnSerialization::Deserialize(input, columns);
ASSERT_TRUE(s.IsNotSupported());
ASSERT_TRUE(std::strstr(s.getState(), "version"));
}
TEST(WideColumnSerializationTest, DeserializeNumberOfColumnsError) {
// Can't decode number of columns
std::string buf;
PutVarint32(&buf, WideColumnSerialization::kCurrentVersion);
Slice input(buf);
WideColumns columns;
const Status s = WideColumnSerialization::Deserialize(input, columns);
ASSERT_TRUE(s.IsCorruption());
ASSERT_TRUE(std::strstr(s.getState(), "number"));
}
TEST(WideColumnSerializationTest, DeserializeColumnsError) {
std::string buf;
PutVarint32(&buf, WideColumnSerialization::kCurrentVersion);
constexpr uint32_t num_columns = 2;
PutVarint32(&buf, num_columns);
// Can't decode the first column name
{
Slice input(buf);
WideColumns columns;
const Status s = WideColumnSerialization::Deserialize(input, columns);
ASSERT_TRUE(s.IsCorruption());
ASSERT_TRUE(std::strstr(s.getState(), "name"));
}
constexpr char first_column_name[] = "foo";
PutLengthPrefixedSlice(&buf, first_column_name);
// Can't decode the size of the first column value
{
Slice input(buf);
WideColumns columns;
const Status s = WideColumnSerialization::Deserialize(input, columns);
ASSERT_TRUE(s.IsCorruption());
ASSERT_TRUE(std::strstr(s.getState(), "value size"));
}
constexpr uint32_t first_value_size = 16;
PutVarint32(&buf, first_value_size);
// Can't decode the second column name
{
Slice input(buf);
WideColumns columns;
const Status s = WideColumnSerialization::Deserialize(input, columns);
ASSERT_TRUE(s.IsCorruption());
ASSERT_TRUE(std::strstr(s.getState(), "name"));
}
constexpr char second_column_name[] = "hello";
PutLengthPrefixedSlice(&buf, second_column_name);
// Can't decode the size of the second column value
{
Slice input(buf);
WideColumns columns;
const Status s = WideColumnSerialization::Deserialize(input, columns);
ASSERT_TRUE(s.IsCorruption());
ASSERT_TRUE(std::strstr(s.getState(), "value size"));
}
constexpr uint32_t second_value_size = 64;
PutVarint32(&buf, second_value_size);
// Can't decode the payload of the first column
{
Slice input(buf);
WideColumns columns;
const Status s = WideColumnSerialization::Deserialize(input, columns);
ASSERT_TRUE(s.IsCorruption());
ASSERT_TRUE(std::strstr(s.getState(), "payload"));
}
buf.append(first_value_size, '0');
// Can't decode the payload of the second column
{
Slice input(buf);
WideColumns columns;
const Status s = WideColumnSerialization::Deserialize(input, columns);
ASSERT_TRUE(s.IsCorruption());
ASSERT_TRUE(std::strstr(s.getState(), "payload"));
}
buf.append(second_value_size, 'x');
// Success
{
Slice input(buf);
WideColumns columns;
ASSERT_OK(WideColumnSerialization::Deserialize(input, columns));
}
}
TEST(WideColumnSerializationTest, DeserializeColumnsOutOfOrder) {
std::string buf;
PutVarint32(&buf, WideColumnSerialization::kCurrentVersion);
constexpr uint32_t num_columns = 2;
PutVarint32(&buf, num_columns);
constexpr char first_column_name[] = "b";
PutLengthPrefixedSlice(&buf, first_column_name);
constexpr uint32_t first_value_size = 16;
PutVarint32(&buf, first_value_size);
constexpr char second_column_name[] = "a";
PutLengthPrefixedSlice(&buf, second_column_name);
Slice input(buf);
WideColumns columns;
const Status s = WideColumnSerialization::Deserialize(input, columns);
ASSERT_TRUE(s.IsCorruption());
ASSERT_TRUE(std::strstr(s.getState(), "order"));
}
} // namespace ROCKSDB_NAMESPACE
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}