Skip to content

Commit 9c8ad62

Browse files
committed
DB Sanity Test
Summary: @kailiu mentioned on meeting yesterday that we sometimes have trouble opening DB created by old version with the new version. This will be very important to test for column families, since I'm changing disk format for the MANIFEST. I added a tool that can help us test that. Usage: ./db_sanity_test <path> create will create a bunch of DBs under <path> <change RocksDB version> ./db_sanity_test <path> verify will verify consistency of DBs created under <path> Test Plan: ran the db_sanity_test Reviewers: kailiu, dhruba, haobo Reviewed By: kailiu CC: leveldb, kailiu, xjin Differential Revision: https://reviews.facebook.net/D16605
1 parent abeee9f commit 9c8ad62

File tree

2 files changed

+204
-0
lines changed

2 files changed

+204
-0
lines changed

Makefile

+3
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,9 @@ block_hash_index_test: table/block_hash_index_test.o $(LIBOBJECTS) $(TESTHARNESS
234234
db_stress: tools/db_stress.o $(LIBOBJECTS) $(TESTUTIL)
235235
$(CXX) tools/db_stress.o $(LIBOBJECTS) $(TESTUTIL) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS)
236236

237+
db_sanity_test: tools/db_sanity_test.o $(LIBOBJECTS) $(TESTUTIL)
238+
$(CXX) tools/db_sanity_test.o $(LIBOBJECTS) $(TESTUTIL) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS)
239+
237240
db_repl_stress: tools/db_repl_stress.o $(LIBOBJECTS) $(TESTUTIL)
238241
$(CXX) tools/db_repl_stress.o $(LIBOBJECTS) $(TESTUTIL) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS)
239242

tools/db_sanity_test.cc

+201
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
// Copyright (c) 2013, Facebook, Inc. All rights reserved.
2+
// This source code is licensed under the BSD-style license found in the
3+
// LICENSE file in the root directory of this source tree. An additional grant
4+
// of patent rights can be found in the PATENTS file in the same directory.
5+
6+
#include <cstdio>
7+
#include <vector>
8+
#include <memory>
9+
10+
#include "include/rocksdb/db.h"
11+
#include "include/rocksdb/options.h"
12+
#include "include/rocksdb/env.h"
13+
#include "include/rocksdb/slice.h"
14+
#include "include/rocksdb/status.h"
15+
#include "include/rocksdb/comparator.h"
16+
#include "include/rocksdb/table.h"
17+
#include "include/rocksdb/slice_transform.h"
18+
19+
namespace rocksdb {
20+
21+
class SanityTest {
22+
public:
23+
explicit SanityTest(const std::string& path)
24+
: env_(Env::Default()), path_(path) {
25+
env_->CreateDirIfMissing(path);
26+
}
27+
virtual ~SanityTest() {}
28+
29+
virtual std::string Name() const = 0;
30+
virtual Options GetOptions() const = 0;
31+
32+
Status Create() {
33+
Options options = GetOptions();
34+
options.create_if_missing = true;
35+
std::string dbname = path_ + Name();
36+
DestroyDB(dbname, options);
37+
DB* db;
38+
Status s = DB::Open(options, dbname, &db);
39+
std::unique_ptr<DB> db_guard(db);
40+
if (!s.ok()) {
41+
return s;
42+
}
43+
for (int i = 0; i < 1000000; ++i) {
44+
std::string k = "key" + std::to_string(i);
45+
std::string v = "value" + std::to_string(i);
46+
s = db->Put(WriteOptions(), Slice(k), Slice(v));
47+
if (!s.ok()) {
48+
return s;
49+
}
50+
}
51+
return Status::OK();
52+
}
53+
Status Verify() {
54+
DB* db;
55+
std::string dbname = path_ + Name();
56+
Status s = DB::Open(GetOptions(), dbname, &db);
57+
std::unique_ptr<DB> db_guard(db);
58+
if (!s.ok()) {
59+
return s;
60+
}
61+
for (int i = 0; i < 1000000; ++i) {
62+
std::string k = "key" + std::to_string(i);
63+
std::string v = "value" + std::to_string(i);
64+
std::string result;
65+
s = db->Get(ReadOptions(), Slice(k), &result);
66+
if (!s.ok()) {
67+
return s;
68+
}
69+
if (result != v) {
70+
return Status::Corruption("Unexpected value for key " + k);
71+
}
72+
}
73+
return Status::OK();
74+
}
75+
76+
private:
77+
Env* env_;
78+
std::string const path_;
79+
};
80+
81+
class SanityTestBasic : public SanityTest {
82+
public:
83+
explicit SanityTestBasic(const std::string& path) : SanityTest(path) {}
84+
virtual Options GetOptions() const {
85+
Options options;
86+
options.create_if_missing = true;
87+
return options;
88+
}
89+
virtual std::string Name() const { return "Basic"; }
90+
};
91+
92+
class SanityTestSpecialComparator : public SanityTest {
93+
public:
94+
explicit SanityTestSpecialComparator(const std::string& path)
95+
: SanityTest(path) {
96+
options_.comparator = new NewComparator();
97+
}
98+
~SanityTestSpecialComparator() { delete options_.comparator; }
99+
virtual Options GetOptions() const { return options_; }
100+
virtual std::string Name() const { return "SpecialComparator"; }
101+
102+
private:
103+
class NewComparator : public Comparator {
104+
public:
105+
virtual const char* Name() const { return "rocksdb.NewComparator"; }
106+
virtual int Compare(const Slice& a, const Slice& b) const {
107+
return BytewiseComparator()->Compare(a, b);
108+
}
109+
virtual void FindShortestSeparator(std::string* s, const Slice& l) const {
110+
BytewiseComparator()->FindShortestSeparator(s, l);
111+
}
112+
virtual void FindShortSuccessor(std::string* key) const {
113+
BytewiseComparator()->FindShortSuccessor(key);
114+
}
115+
};
116+
Options options_;
117+
};
118+
119+
class SanityTestZlibCompression : public SanityTest {
120+
public:
121+
explicit SanityTestZlibCompression(const std::string& path)
122+
: SanityTest(path) {
123+
options_.compression = kZlibCompression;
124+
}
125+
virtual Options GetOptions() const { return options_; }
126+
virtual std::string Name() const { return "ZlibCompression"; }
127+
128+
private:
129+
Options options_;
130+
};
131+
132+
class SanityTestPlainTableFactory : public SanityTest {
133+
public:
134+
explicit SanityTestPlainTableFactory(const std::string& path)
135+
: SanityTest(path) {
136+
options_.table_factory.reset(NewPlainTableFactory());
137+
options_.prefix_extractor = NewFixedPrefixTransform(2);
138+
options_.allow_mmap_reads = true;
139+
}
140+
~SanityTestPlainTableFactory() { delete options_.prefix_extractor; }
141+
virtual Options GetOptions() const { return options_; }
142+
virtual std::string Name() const { return "PlainTable"; }
143+
144+
private:
145+
Options options_;
146+
};
147+
148+
bool RunSanityTests(const std::string& command, const std::string& path) {
149+
std::vector<SanityTest*> sanity_tests = {
150+
new SanityTestBasic(path),
151+
new SanityTestSpecialComparator(path),
152+
new SanityTestZlibCompression(path),
153+
new SanityTestPlainTableFactory(path)};
154+
155+
if (command == "create") {
156+
fprintf(stderr, "Creating...\n");
157+
} else {
158+
fprintf(stderr, "Verifying...\n");
159+
}
160+
for (auto sanity_test : sanity_tests) {
161+
Status s;
162+
fprintf(stderr, "%s -- ", sanity_test->Name().c_str());
163+
if (command == "create") {
164+
s = sanity_test->Create();
165+
} else {
166+
assert(command == "verify");
167+
s = sanity_test->Verify();
168+
}
169+
fprintf(stderr, "%s\n", s.ToString().c_str());
170+
if (!s.ok()) {
171+
fprintf(stderr, "FAIL\n");
172+
return false;
173+
}
174+
175+
delete sanity_test;
176+
}
177+
return true;
178+
}
179+
180+
} // namespace rocksdb
181+
182+
int main(int argc, char** argv) {
183+
std::string path, command;
184+
bool ok = (argc == 3);
185+
if (ok) {
186+
path = std::string(argv[1]);
187+
command = std::string(argv[2]);
188+
ok = (command == "create" || command == "verify");
189+
}
190+
if (!ok) {
191+
fprintf(stderr, "Usage: %s <path> [create|verify] \n", argv[0]);
192+
exit(1);
193+
}
194+
if (path.back() != '/') {
195+
path += "/";
196+
}
197+
198+
bool sanity_ok = rocksdb::RunSanityTests(command, path);
199+
200+
return sanity_ok ? 0 : 1;
201+
}

0 commit comments

Comments
 (0)