rocksdb/db/wide/wide_column_serialization_test.cc
Levi Tamasi c73d2a9d18 Add API for writing wide-column entities (#10242)
Summary:
The patch builds on https://github.com/facebook/rocksdb/pull/9915 and adds
a new API called `PutEntity` that can be used to write a wide-column entity
to the database. The new API is added to both `DB` and `WriteBatch`. Note
that currently there is no way to retrieve these entities; more precisely, all
read APIs (`Get`, `MultiGet`, and iterator) return `NotSupported` when they
encounter a wide-column entity that is required to answer a query. Read-side
support (as well as other missing functionality like `Merge`, compaction filter,
and timestamp support) will be added in later PRs.

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

Test Plan: `make check`

Reviewed By: riversand963

Differential Revision: D37369748

Pulled By: ltamasi

fbshipit-source-id: 7f5e412359ed7a400fd80b897dae5599dbcd685d
2022-06-25 15:30:47 -07:00

309 lines
7.9 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, SerializeDuplicateError) {
WideColumns columns{{"foo", "bar"}, {"foo", "baz"}};
std::string output;
ASSERT_TRUE(
WideColumnSerialization::Serialize(columns, output).IsCorruption());
}
TEST(WideColumnSerializationTest, SerializeOutOfOrderError) {
WideColumns columns{{"hello", "world"}, {"foo", "bar"}};
std::string output;
ASSERT_TRUE(
WideColumnSerialization::Serialize(columns, output).IsCorruption());
}
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();
}