#pragma once
#include <assert.h>
#include <atomic>
#include <functional>
#include <string>
#include <vector>
#include "rocksdb/rocksdb_namespace.h"
#include "rocksdb/slice.h"
#ifdef NDEBUG
#define TEST_KILL_RANDOM_WITH_WEIGHT(kill_point, rocksdb_kill_odds_weight)
#define TEST_KILL_RANDOM(kill_point)
#else
namespace ROCKSDB_NAMESPACE {
#define REDUCE_ODDS 2
#define REDUCE_ODDS2 4
struct KillPoint {
public:
int rocksdb_kill_odds = 0;
std::vector<std::string> rocksdb_kill_exclude_prefixes;
void TestKillRandom(std::string kill_point, int odds,
const std::string& srcfile, int srcline);
static KillPoint* GetInstance();
};
#define TEST_KILL_RANDOM_WITH_WEIGHT(kill_point, rocksdb_kill_odds_weight) \
{ \
KillPoint::GetInstance()->TestKillRandom( \
kill_point, rocksdb_kill_odds_weight, __FILE__, __LINE__); \
}
#define TEST_KILL_RANDOM(kill_point) TEST_KILL_RANDOM_WITH_WEIGHT(kill_point, 1)
}
#endif
#ifdef NDEBUG
#define TEST_SYNC_POINT(x)
#define TEST_IDX_SYNC_POINT(x, index)
#define TEST_SYNC_POINT_CALLBACK(x, y)
#define INIT_SYNC_POINT_SINGLETONS()
#else
namespace ROCKSDB_NAMESPACE {
class SyncPoint {
public:
static SyncPoint* GetInstance();
SyncPoint(const SyncPoint&) = delete;
SyncPoint& operator=(const SyncPoint&) = delete;
~SyncPoint();
struct SyncPointPair {
std::string predecessor;
std::string successor;
};
void LoadDependency(const std::vector<SyncPointPair>& dependencies);
void LoadDependencyAndMarkers(const std::vector<SyncPointPair>& dependencies,
const std::vector<SyncPointPair>& markers);
void SetCallBack(const std::string& point,
const std::function<void(void*)>& callback);
void ClearCallBack(const std::string& point);
void ClearAllCallBacks();
void EnableProcessing();
void DisableProcessing();
void ClearTrace();
void Process(const Slice& point, void* cb_arg = nullptr);
template <size_t kLen>
void Process(const char (&point)[kLen], void* cb_arg = nullptr) {
static_assert(kLen > 0, "Must not be empty");
assert(point[kLen - 1] == '\0');
Process(Slice(point, kLen - 1), cb_arg);
}
struct Data;
private:
SyncPoint();
Data* impl_;
};
void SetupSyncPointsToMockDirectIO();
}
#define TEST_SYNC_POINT(x) \
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->Process(x)
#define TEST_IDX_SYNC_POINT(x, index) \
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->Process(x + \
std::to_string(index))
#define TEST_SYNC_POINT_CALLBACK(x, y) \
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->Process(x, y)
#define INIT_SYNC_POINT_SINGLETONS() \
(void)ROCKSDB_NAMESPACE::SyncPoint::GetInstance();
#endif
#ifdef NDEBUG
#define IGNORE_STATUS_IF_ERROR(_status_)
#else
#define IGNORE_STATUS_IF_ERROR(_status_) \
{ \
if (!_status_.ok()) { \
TEST_SYNC_POINT("FaultInjectionIgnoreError"); \
} \
}
#endif
#ifdef NDEBUG
#define testable_assert(cond)
#else
namespace ROCKSDB_NAMESPACE {
struct TestableAssertionFailure {};
extern std::atomic<int> g_throw_on_testable_assertion_failure;
} #define testable_assert(cond) \
do { \
if (ROCKSDB_NAMESPACE::g_throw_on_testable_assertion_failure.load( \
std::memory_order_relaxed) > 0) { \
if (cond) { \
} else \
throw ROCKSDB_NAMESPACE::TestableAssertionFailure(); \
} else { \
assert(cond); \
} \
} while (0)
#define ASSERT_TESTABLE_FAILURE(expr) \
do { \
ROCKSDB_NAMESPACE::g_throw_on_testable_assertion_failure.fetch_add( \
1, std::memory_order_relaxed); \
ASSERT_THROW(expr, ROCKSDB_NAMESPACE::TestableAssertionFailure); \
ROCKSDB_NAMESPACE::g_throw_on_testable_assertion_failure.fetch_sub( \
1, std::memory_order_relaxed); \
} while (0)
#endif