Cross functional test infrastructure for RocksDB.
Summary: This Diff provides the implementation of the cross functional test infrastructure. This provides the ability to test a single feature with every existing regression test in order to identify issues with interoperability between features. Test Plan: Reference implementation of inplace update support cross functional test. Able to find interoperability issues with inplace support and ran all of db_test. Will add separate diff for those changes. Reviewers: igor, sdong Reviewed By: sdong Subscribers: dhruba, leveldb Differential Revision: https://reviews.facebook.net/D32247
This commit is contained in:
parent
868bfa4033
commit
0b8dec7172
@ -53,6 +53,7 @@
|
||||
#include "util/mock_env.h"
|
||||
#include "util/string_util.h"
|
||||
#include "util/thread_status_util.h"
|
||||
#include "util/xfunc.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
@ -115,6 +116,9 @@ class AtomicCounter {
|
||||
|
||||
struct OptionsOverride {
|
||||
std::shared_ptr<const FilterPolicy> filter_policy = nullptr;
|
||||
|
||||
// Used as a bit mask of individual enums in which to skip an XF test point
|
||||
int skip_policy = 0;
|
||||
};
|
||||
|
||||
} // namespace anon
|
||||
@ -564,6 +568,9 @@ class DBTest {
|
||||
const anon::OptionsOverride& options_override = anon::OptionsOverride()) {
|
||||
// this redudant copy is to minimize code change w/o having lint error.
|
||||
Options options = defaultOptions;
|
||||
XFUNC_TEST("", "dbtest_options", inplace_options1, GetXFTestOptions,
|
||||
reinterpret_cast<Options*>(&options),
|
||||
options_override.skip_policy);
|
||||
BlockBasedTableOptions table_options;
|
||||
bool set_block_based_table_factory = true;
|
||||
switch (option_config_) {
|
||||
@ -1631,8 +1638,10 @@ TEST(DBTest, GetFromVersions) {
|
||||
}
|
||||
|
||||
TEST(DBTest, GetSnapshot) {
|
||||
anon::OptionsOverride options_override;
|
||||
options_override.skip_policy = kSkipNoSnapshot;
|
||||
do {
|
||||
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
|
||||
CreateAndReopenWithCF({"pikachu"}, CurrentOptions(options_override));
|
||||
// Try with both a short key and a long key
|
||||
for (int i = 0; i < 2; i++) {
|
||||
std::string key = (i == 0) ? std::string("foo") : std::string(200, 'x');
|
||||
@ -2242,7 +2251,9 @@ TEST(DBTest, IterMulti) {
|
||||
// Check that we can skip over a run of user keys
|
||||
// by using reseek rather than sequential scan
|
||||
TEST(DBTest, IterReseek) {
|
||||
Options options = CurrentOptions();
|
||||
anon::OptionsOverride options_override;
|
||||
options_override.skip_policy = kSkipNoSnapshot;
|
||||
Options options = CurrentOptions(options_override);
|
||||
options.max_sequential_skip_in_iterations = 3;
|
||||
options.create_if_missing = true;
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
@ -5699,8 +5710,10 @@ TEST(DBTest, IteratorPinsRef) {
|
||||
}
|
||||
|
||||
TEST(DBTest, Snapshot) {
|
||||
anon::OptionsOverride options_override;
|
||||
options_override.skip_policy = kSkipNoSnapshot;
|
||||
do {
|
||||
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
|
||||
CreateAndReopenWithCF({"pikachu"}, CurrentOptions(options_override));
|
||||
Put(0, "foo", "0v1");
|
||||
Put(1, "foo", "1v1");
|
||||
|
||||
@ -5760,8 +5773,10 @@ TEST(DBTest, Snapshot) {
|
||||
}
|
||||
|
||||
TEST(DBTest, HiddenValuesAreRemoved) {
|
||||
anon::OptionsOverride options_override;
|
||||
options_override.skip_policy = kSkipNoSnapshot;
|
||||
do {
|
||||
Options options = CurrentOptions();
|
||||
Options options = CurrentOptions(options_override);
|
||||
options.max_background_flushes = 0;
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
Random rnd(301);
|
||||
@ -5798,8 +5813,10 @@ TEST(DBTest, HiddenValuesAreRemoved) {
|
||||
}
|
||||
|
||||
TEST(DBTest, CompactBetweenSnapshots) {
|
||||
anon::OptionsOverride options_override;
|
||||
options_override.skip_policy = kSkipNoSnapshot;
|
||||
do {
|
||||
Options options = CurrentOptions();
|
||||
Options options = CurrentOptions(options_override);
|
||||
options.disable_auto_compactions = true;
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
Random rnd(301);
|
||||
@ -6908,8 +6925,10 @@ TEST(DBTest, SnapshotFiles) {
|
||||
}
|
||||
|
||||
TEST(DBTest, CompactOnFlush) {
|
||||
anon::OptionsOverride options_override;
|
||||
options_override.skip_policy = kSkipNoSnapshot;
|
||||
do {
|
||||
Options options = CurrentOptions();
|
||||
Options options = CurrentOptions(options_override);
|
||||
options.purge_redundant_kvs_while_flush = true;
|
||||
options.disable_auto_compactions = true;
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
@ -7641,12 +7660,14 @@ static void MTThreadBody(void* arg) {
|
||||
} // namespace
|
||||
|
||||
TEST(DBTest, MultiThreaded) {
|
||||
anon::OptionsOverride options_override;
|
||||
options_override.skip_policy = kSkipNoSnapshot;
|
||||
do {
|
||||
std::vector<std::string> cfs;
|
||||
for (int i = 1; i < kColumnFamilies; ++i) {
|
||||
cfs.push_back(ToString(i));
|
||||
}
|
||||
CreateAndReopenWithCF(cfs, CurrentOptions());
|
||||
CreateAndReopenWithCF(cfs, CurrentOptions(options_override));
|
||||
// Initialize state
|
||||
MTState mt;
|
||||
mt.test = this;
|
||||
|
@ -501,7 +501,8 @@ struct ColumnFamilyOptions {
|
||||
|
||||
// Allows thread-safe inplace updates. If this is true, there is no way to
|
||||
// achieve point-in-time consistency using snapshot or iterator (assuming
|
||||
// concurrent updates).
|
||||
// concurrent updates). Hence iterator and multi-get will return results
|
||||
// which are not consistent as of any point-in-time.
|
||||
// If inplace_callback function is not set,
|
||||
// Put(key, new_value) will update inplace the existing_value iff
|
||||
// * key exists in current memtable
|
||||
|
27
util/xfunc.cc
Normal file
27
util/xfunc.cc
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2014, 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 <string>
|
||||
#include "rocksdb/options.h"
|
||||
#include "util/xfunc.h"
|
||||
|
||||
#ifdef XFUNC
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
std::string XFuncPoint::xfunc_test_;
|
||||
bool XFuncPoint::initialized_ = false;
|
||||
bool XFuncPoint::enabled_ = false;
|
||||
|
||||
void GetXFTestOptions(Options* options, int skip_policy) {
|
||||
if (XFuncPoint::Check("inplace_lock_test") &&
|
||||
(!(skip_policy & kSkipNoSnapshot))) {
|
||||
options->inplace_update_support = true;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
#endif // XFUNC
|
99
util/xfunc.h
Normal file
99
util/xfunc.h
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright (c) 2014, 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.
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
/*
|
||||
* If ROCKSDB_XFTEST_FORCE has a value of 1, XFUNC is forced to be defined.
|
||||
* If ROCKSDB_XFTEST_FORCE has a value other than 1,
|
||||
* XFUNC is forced to be undefined.
|
||||
* If ROCKSDB_XFTEST_FORCE is undefined, XFUNC is defined based on NDEBUG,
|
||||
* with XFUNC only being set for debug builds.
|
||||
*/
|
||||
#if defined(ROCKSDB_XFTEST_FORCE)
|
||||
#if (ROCKSDB_XFTEST_FORCE == 1)
|
||||
#define XFUNC
|
||||
#endif
|
||||
#elif NDEBUG
|
||||
#else
|
||||
#define XFUNC
|
||||
#endif
|
||||
|
||||
#ifndef XFUNC
|
||||
#define XFUNC_TEST(condition, location, lfname, fname, ...)
|
||||
#else
|
||||
|
||||
class Options;
|
||||
void GetXFTestOptions(Options* options, int skip_policy);
|
||||
|
||||
// This class provides the facility to run custom code to test a specific
|
||||
// feature typically with all existing unit tests.
|
||||
// A developer could specify cross functional test points in the codebase
|
||||
// via XFUNC_TEST.
|
||||
// Each xfunc test represents a position in the execution stream of a thread.
|
||||
// Whenever that particular piece of code is called, the given cross-functional
|
||||
// test point is executed.
|
||||
// eg. on DBOpen, a particular option can be set.
|
||||
// on Get, a particular option can be set, or a specific check can be invoked.
|
||||
// XFUNC_TEST(TestName, location, lfname, FunctionName, Args)
|
||||
// Turn on a specific cross functional test by setting the environment variable
|
||||
// ROCKSDB_XFUNC_TEST
|
||||
|
||||
class XFuncPoint {
|
||||
public:
|
||||
// call once at the beginning of a test to get the test name
|
||||
static void Init() {
|
||||
char* s = getenv("ROCKSDB_XFUNC_TEST");
|
||||
if (s == nullptr) {
|
||||
xfunc_test_ = "";
|
||||
enabled_ = false;
|
||||
} else {
|
||||
xfunc_test_ = s;
|
||||
enabled_ = true;
|
||||
}
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
static bool Initialized() { return initialized_; }
|
||||
|
||||
static bool Check(std::string test) {
|
||||
return (enabled_ &&
|
||||
((test.compare("") == 0) || (test.compare(xfunc_test_) == 0)));
|
||||
}
|
||||
|
||||
private:
|
||||
static std::string xfunc_test_;
|
||||
static bool initialized_;
|
||||
static bool enabled_;
|
||||
};
|
||||
|
||||
// Use XFUNC_TEST to specify cross functional test points inside the code base.
|
||||
// By setting ROCKSDB_XFUNC_TEST, all XFUNC_TEST having that
|
||||
// value in the condition field will be executed.
|
||||
// The second argument specifies a string representing the calling location
|
||||
// The third argument, lfname, is the name of the function which will be created
|
||||
// and called.
|
||||
// The fourth argument fname represents the function to be called
|
||||
// The arguments following that are the arguments to fname
|
||||
// See Options::Options in options.h for an example use case.
|
||||
// XFUNC_TEST is no op in release build.
|
||||
#define XFUNC_TEST(condition, location, lfname, fname, ...) \
|
||||
{ \
|
||||
if (!XFuncPoint::Initialized()) { \
|
||||
XFuncPoint::Init(); \
|
||||
} \
|
||||
if (XFuncPoint::Check(condition)) { \
|
||||
std::function<void()> lfname = std::bind(fname, __VA_ARGS__); \
|
||||
lfname(); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif // XFUNC
|
||||
|
||||
enum SkipPolicy { kSkipNone = 0, kSkipNoSnapshot = 1, kSkipNoPrefix = 2 };
|
||||
} // namespace rocksdb
|
Loading…
Reference in New Issue
Block a user