760e9a94de
Summary: Currently RocksDB silently ignores this issue and doesn't compress the data. Based on discussion, we agree that this is pretty bad because it can cause confusion for our users. This patch fails DB::Open() if we don't support the compression that is specified in the options. Test Plan: make check with LZ4 not present. If Snappy is not present all tests will just fail because Snappy is our default library. We should make Snappy the requirement, since without it our default DB::Open() fails. Reviewers: sdong, MarkCallaghan, rven, yhchiang Reviewed By: yhchiang Subscribers: dhruba, leveldb Differential Revision: https://reviews.facebook.net/D39687
291 lines
9.5 KiB
C++
291 lines
9.5 KiB
C++
// Copyright (c) 2013, Facebook, Inc. All rights reserved.
|
|
// This source code is licensed under the BSD-style license found in the
|
|
// LICENSE file in the root directory of this source tree. An additional grant
|
|
// of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
#include <set>
|
|
|
|
#include "rocksdb/utilities/spatial_db.h"
|
|
#include "util/compression.h"
|
|
#include "util/testharness.h"
|
|
#include "util/testutil.h"
|
|
#include "util/random.h"
|
|
|
|
namespace rocksdb {
|
|
namespace spatial {
|
|
|
|
class SpatialDBTest : public testing::Test {
|
|
public:
|
|
SpatialDBTest() {
|
|
dbname_ = test::TmpDir() + "/spatial_db_test";
|
|
DestroyDB(dbname_, Options());
|
|
}
|
|
|
|
void AssertCursorResults(BoundingBox<double> bbox, const std::string& index,
|
|
const std::vector<std::string>& blobs) {
|
|
Cursor* c = db_->Query(ReadOptions(), bbox, index);
|
|
ASSERT_OK(c->status());
|
|
std::multiset<std::string> b;
|
|
for (auto x : blobs) {
|
|
b.insert(x);
|
|
}
|
|
|
|
while (c->Valid()) {
|
|
auto itr = b.find(c->blob().ToString());
|
|
ASSERT_TRUE(itr != b.end());
|
|
b.erase(itr);
|
|
c->Next();
|
|
}
|
|
ASSERT_EQ(b.size(), 0U);
|
|
ASSERT_OK(c->status());
|
|
delete c;
|
|
}
|
|
|
|
std::string dbname_;
|
|
SpatialDB* db_;
|
|
};
|
|
|
|
TEST_F(SpatialDBTest, FeatureSetSerializeTest) {
|
|
if (!LZ4_Supported()) {
|
|
return;
|
|
}
|
|
FeatureSet fs;
|
|
|
|
fs.Set("a", std::string("b"));
|
|
fs.Set("x", static_cast<uint64_t>(3));
|
|
fs.Set("y", false);
|
|
fs.Set("n", Variant()); // null
|
|
fs.Set("m", 3.25);
|
|
|
|
ASSERT_TRUE(fs.Find("w") == fs.end());
|
|
ASSERT_TRUE(fs.Find("x") != fs.end());
|
|
ASSERT_TRUE((*fs.Find("x")).second == Variant(static_cast<uint64_t>(3)));
|
|
ASSERT_TRUE((*fs.Find("y")).second != Variant(true));
|
|
std::set<std::string> keys({"a", "x", "y", "n", "m"});
|
|
for (const auto& x : fs) {
|
|
ASSERT_TRUE(keys.find(x.first) != keys.end());
|
|
keys.erase(x.first);
|
|
}
|
|
ASSERT_EQ(keys.size(), 0U);
|
|
|
|
std::string serialized;
|
|
fs.Serialize(&serialized);
|
|
|
|
FeatureSet deserialized;
|
|
ASSERT_TRUE(deserialized.Deserialize(serialized));
|
|
|
|
ASSERT_TRUE(deserialized.Contains("a"));
|
|
ASSERT_EQ(deserialized.Get("a").type(), Variant::kString);
|
|
ASSERT_EQ(deserialized.Get("a").get_string(), "b");
|
|
ASSERT_TRUE(deserialized.Contains("x"));
|
|
ASSERT_EQ(deserialized.Get("x").type(), Variant::kInt);
|
|
ASSERT_EQ(deserialized.Get("x").get_int(), static_cast<uint64_t>(3));
|
|
ASSERT_TRUE(deserialized.Contains("y"));
|
|
ASSERT_EQ(deserialized.Get("y").type(), Variant::kBool);
|
|
ASSERT_EQ(deserialized.Get("y").get_bool(), false);
|
|
ASSERT_TRUE(deserialized.Contains("n"));
|
|
ASSERT_EQ(deserialized.Get("n").type(), Variant::kNull);
|
|
ASSERT_TRUE(deserialized.Contains("m"));
|
|
ASSERT_EQ(deserialized.Get("m").type(), Variant::kDouble);
|
|
ASSERT_EQ(deserialized.Get("m").get_double(), 3.25);
|
|
|
|
// corrupted serialization
|
|
serialized = serialized.substr(0, serialized.size() - 3);
|
|
deserialized.Clear();
|
|
ASSERT_TRUE(!deserialized.Deserialize(serialized));
|
|
}
|
|
|
|
TEST_F(SpatialDBTest, TestNextID) {
|
|
if (!LZ4_Supported()) {
|
|
return;
|
|
}
|
|
ASSERT_OK(SpatialDB::Create(
|
|
SpatialDBOptions(), dbname_,
|
|
{SpatialIndexOptions("simple", BoundingBox<double>(0, 0, 100, 100), 2)}));
|
|
|
|
ASSERT_OK(SpatialDB::Open(SpatialDBOptions(), dbname_, &db_));
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(5, 5, 10, 10),
|
|
"one", FeatureSet(), {"simple"}));
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(10, 10, 15, 15),
|
|
"two", FeatureSet(), {"simple"}));
|
|
delete db_;
|
|
|
|
ASSERT_OK(SpatialDB::Open(SpatialDBOptions(), dbname_, &db_));
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(55, 55, 65, 65),
|
|
"three", FeatureSet(), {"simple"}));
|
|
delete db_;
|
|
|
|
ASSERT_OK(SpatialDB::Open(SpatialDBOptions(), dbname_, &db_));
|
|
AssertCursorResults(BoundingBox<double>(0, 0, 100, 100), "simple",
|
|
{"one", "two", "three"});
|
|
delete db_;
|
|
}
|
|
|
|
TEST_F(SpatialDBTest, FeatureSetTest) {
|
|
if (!LZ4_Supported()) {
|
|
return;
|
|
}
|
|
ASSERT_OK(SpatialDB::Create(
|
|
SpatialDBOptions(), dbname_,
|
|
{SpatialIndexOptions("simple", BoundingBox<double>(0, 0, 100, 100), 2)}));
|
|
ASSERT_OK(SpatialDB::Open(SpatialDBOptions(), dbname_, &db_));
|
|
|
|
FeatureSet fs;
|
|
fs.Set("a", std::string("b"));
|
|
fs.Set("c", std::string("d"));
|
|
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(5, 5, 10, 10),
|
|
"one", fs, {"simple"}));
|
|
|
|
Cursor* c =
|
|
db_->Query(ReadOptions(), BoundingBox<double>(5, 5, 10, 10), "simple");
|
|
|
|
ASSERT_TRUE(c->Valid());
|
|
ASSERT_EQ(c->blob().compare("one"), 0);
|
|
FeatureSet returned = c->feature_set();
|
|
ASSERT_TRUE(returned.Contains("a"));
|
|
ASSERT_TRUE(!returned.Contains("b"));
|
|
ASSERT_TRUE(returned.Contains("c"));
|
|
ASSERT_EQ(returned.Get("a").type(), Variant::kString);
|
|
ASSERT_EQ(returned.Get("a").get_string(), "b");
|
|
ASSERT_EQ(returned.Get("c").type(), Variant::kString);
|
|
ASSERT_EQ(returned.Get("c").get_string(), "d");
|
|
|
|
c->Next();
|
|
ASSERT_TRUE(!c->Valid());
|
|
|
|
delete c;
|
|
delete db_;
|
|
}
|
|
|
|
TEST_F(SpatialDBTest, SimpleTest) {
|
|
if (!LZ4_Supported()) {
|
|
return;
|
|
}
|
|
// iter 0 -- not read only
|
|
// iter 1 -- read only
|
|
for (int iter = 0; iter < 2; ++iter) {
|
|
DestroyDB(dbname_, Options());
|
|
ASSERT_OK(SpatialDB::Create(
|
|
SpatialDBOptions(), dbname_,
|
|
{SpatialIndexOptions("index", BoundingBox<double>(0, 0, 128, 128),
|
|
3)}));
|
|
ASSERT_OK(SpatialDB::Open(SpatialDBOptions(), dbname_, &db_));
|
|
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(33, 17, 63, 79),
|
|
"one", FeatureSet(), {"index"}));
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(65, 65, 111, 111),
|
|
"two", FeatureSet(), {"index"}));
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(1, 49, 127, 63),
|
|
"three", FeatureSet(), {"index"}));
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(20, 100, 21, 101),
|
|
"four", FeatureSet(), {"index"}));
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(81, 33, 127, 63),
|
|
"five", FeatureSet(), {"index"}));
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(1, 65, 47, 95),
|
|
"six", FeatureSet(), {"index"}));
|
|
|
|
if (iter == 1) {
|
|
delete db_;
|
|
ASSERT_OK(SpatialDB::Open(SpatialDBOptions(), dbname_, &db_, true));
|
|
}
|
|
|
|
AssertCursorResults(BoundingBox<double>(33, 17, 47, 31), "index", {"one"});
|
|
AssertCursorResults(BoundingBox<double>(17, 33, 79, 63), "index",
|
|
{"one", "three"});
|
|
AssertCursorResults(BoundingBox<double>(17, 81, 63, 111), "index",
|
|
{"four", "six"});
|
|
AssertCursorResults(BoundingBox<double>(85, 86, 85, 86), "index", {"two"});
|
|
AssertCursorResults(BoundingBox<double>(33, 1, 127, 111), "index",
|
|
{"one", "two", "three", "five", "six"});
|
|
// even though the bounding box doesn't intersect, we got "four" back
|
|
// because
|
|
// it's in the same tile
|
|
AssertCursorResults(BoundingBox<double>(18, 98, 19, 99), "index", {"four"});
|
|
AssertCursorResults(BoundingBox<double>(130, 130, 131, 131), "index", {});
|
|
AssertCursorResults(BoundingBox<double>(81, 17, 127, 31), "index", {});
|
|
AssertCursorResults(BoundingBox<double>(90, 50, 91, 51), "index",
|
|
{"three", "five"});
|
|
|
|
delete db_;
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
std::string RandomStr(Random* rnd) {
|
|
std::string r;
|
|
for (int k = 0; k < 10; ++k) {
|
|
r.push_back(rnd->Uniform(26) + 'a');
|
|
}
|
|
return r;
|
|
}
|
|
|
|
BoundingBox<int> RandomBoundingBox(int limit, Random* rnd, int max_size) {
|
|
BoundingBox<int> r;
|
|
r.min_x = rnd->Uniform(limit - 1);
|
|
r.min_y = rnd->Uniform(limit - 1);
|
|
r.max_x = r.min_x + rnd->Uniform(std::min(limit - 1 - r.min_x, max_size)) + 1;
|
|
r.max_y = r.min_y + rnd->Uniform(std::min(limit - 1 - r.min_y, max_size)) + 1;
|
|
return r;
|
|
}
|
|
|
|
BoundingBox<double> ScaleBB(BoundingBox<int> b, double step) {
|
|
return BoundingBox<double>(b.min_x * step + 1, b.min_y * step + 1,
|
|
(b.max_x + 1) * step - 1,
|
|
(b.max_y + 1) * step - 1);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_F(SpatialDBTest, RandomizedTest) {
|
|
if (!LZ4_Supported()) {
|
|
return;
|
|
}
|
|
Random rnd(301);
|
|
std::vector<std::pair<std::string, BoundingBox<int>>> elements;
|
|
|
|
BoundingBox<double> spatial_index_bounds(0, 0, (1LL << 32), (1LL << 32));
|
|
ASSERT_OK(SpatialDB::Create(
|
|
SpatialDBOptions(), dbname_,
|
|
{SpatialIndexOptions("index", spatial_index_bounds, 7)}));
|
|
ASSERT_OK(SpatialDB::Open(SpatialDBOptions(), dbname_, &db_));
|
|
double step = (1LL << 32) / (1 << 7);
|
|
|
|
for (int i = 0; i < 1000; ++i) {
|
|
std::string blob = RandomStr(&rnd);
|
|
BoundingBox<int> bbox = RandomBoundingBox(128, &rnd, 10);
|
|
ASSERT_OK(db_->Insert(WriteOptions(), ScaleBB(bbox, step), blob,
|
|
FeatureSet(), {"index"}));
|
|
elements.push_back(make_pair(blob, bbox));
|
|
}
|
|
|
|
// parallel
|
|
db_->Compact(2);
|
|
// serial
|
|
db_->Compact(1);
|
|
|
|
for (int i = 0; i < 1000; ++i) {
|
|
BoundingBox<int> int_bbox = RandomBoundingBox(128, &rnd, 10);
|
|
BoundingBox<double> double_bbox = ScaleBB(int_bbox, step);
|
|
std::vector<std::string> blobs;
|
|
for (auto e : elements) {
|
|
if (e.second.Intersects(int_bbox)) {
|
|
blobs.push_back(e.first);
|
|
}
|
|
}
|
|
AssertCursorResults(double_bbox, "index", blobs);
|
|
}
|
|
|
|
delete db_;
|
|
}
|
|
|
|
} // namespace spatial
|
|
} // namespace rocksdb
|
|
|
|
int main(int argc, char** argv) {
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|