commit
f5469b1a61
@ -0,0 +1,71 @@ |
||||
TMP_DIR="/tmp/rocksdb-sanity-test" |
||||
|
||||
if [ "$#" -lt 2 ]; then |
||||
echo "usage: ./auto_sanity_test.sh [new_commit] [old_commit]" |
||||
echo "Missing either [new_commit] or [old_commit], perform sanity check with the latest and 10th latest commits." |
||||
recent_commits=`git log | grep -e "^commit [a-z0-9]\+$"| head -n10 | sed -e 's/commit //g'` |
||||
commit_new=`echo "$recent_commits" | head -n1` |
||||
commit_old=`echo "$recent_commits" | tail -n1` |
||||
echo "the most recent commits are:" |
||||
echo "$recent_commits" |
||||
else |
||||
commit_new=$1 |
||||
commit_old=$2 |
||||
fi |
||||
|
||||
if [ ! -d $TMP_DIR ]; then |
||||
mkdir $TMP_DIR |
||||
fi |
||||
dir_new="${TMP_DIR}/${commit_new}" |
||||
dir_old="${TMP_DIR}/${commit_old}" |
||||
|
||||
function makestuff() { |
||||
echo "make clean" |
||||
make clean > /dev/null |
||||
echo "make db_sanity_test -j32" |
||||
make db_sanity_test -j32 > /dev/null |
||||
if [ $? -ne 0 ]; then |
||||
echo "[ERROR] Failed to perform 'make db_sanity_test'" |
||||
exit 1 |
||||
fi |
||||
} |
||||
|
||||
rm -r -f $dir_new |
||||
rm -r -f $dir_old |
||||
|
||||
echo "Running db sanity check with commits $commit_new and $commit_old." |
||||
|
||||
echo "=============================================================" |
||||
echo "Making build $commit_new" |
||||
makestuff |
||||
mv db_sanity_test new_db_sanity_test |
||||
echo "Creating db based on the new commit --- $commit_new" |
||||
./new_db_sanity_test $dir_new create |
||||
|
||||
echo "=============================================================" |
||||
echo "Making build $commit_old" |
||||
makestuff |
||||
mv db_sanity_test old_db_sanity_test |
||||
echo "Creating db based on the old commit --- $commit_old" |
||||
./old_db_sanity_test $dir_old create |
||||
|
||||
echo "=============================================================" |
||||
echo "Verifying new db $dir_new using the old commit --- $commit_old" |
||||
./old_db_sanity_test $dir_new verify |
||||
if [ $? -ne 0 ]; then |
||||
echo "[ERROR] Verification of $dir_new using commit $commit_old failed." |
||||
exit 2 |
||||
fi |
||||
|
||||
echo "=============================================================" |
||||
echo "Verifying old db $dir_old using the new commit --- $commit_new" |
||||
./new_db_sanity_test $dir_old verify |
||||
if [ $? -ne 0 ]; then |
||||
echo "[ERROR] Verification of $dir_old using commit $commit_new failed." |
||||
exit 2 |
||||
fi |
||||
|
||||
rm old_db_sanity_test |
||||
rm new_db_sanity_test |
||||
|
||||
echo "Auto sanity test passed!" |
@ -0,0 +1,62 @@ |
||||
// 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 "util/sync_point.h" |
||||
|
||||
namespace rocksdb { |
||||
|
||||
SyncPoint* SyncPoint::GetInstance() { |
||||
static SyncPoint sync_point; |
||||
return &sync_point; |
||||
} |
||||
|
||||
void SyncPoint::LoadDependency(const std::vector<Dependency>& dependencies) { |
||||
successors_.clear(); |
||||
predecessors_.clear(); |
||||
cleared_points_.clear(); |
||||
for (const auto& dependency : dependencies) { |
||||
successors_[dependency.predecessor].push_back(dependency.successor); |
||||
predecessors_[dependency.successor].push_back(dependency.predecessor); |
||||
} |
||||
} |
||||
|
||||
bool SyncPoint::PredecessorsAllCleared(const std::string& point) { |
||||
for (const auto& pred : predecessors_[point]) { |
||||
if (cleared_points_.count(pred) == 0) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
void SyncPoint::EnableProcessing() { |
||||
std::unique_lock<std::mutex> lock(mutex_); |
||||
enabled_ = true; |
||||
} |
||||
|
||||
void SyncPoint::DisableProcessing() { |
||||
std::unique_lock<std::mutex> lock(mutex_); |
||||
enabled_ = false; |
||||
} |
||||
|
||||
void SyncPoint::ClearTrace() { |
||||
std::unique_lock<std::mutex> lock(mutex_); |
||||
cleared_points_.clear(); |
||||
} |
||||
|
||||
void SyncPoint::Process(const std::string& point) { |
||||
std::unique_lock<std::mutex> lock(mutex_); |
||||
|
||||
if (!enabled_) return; |
||||
|
||||
while (!PredecessorsAllCleared(point)) { |
||||
cv_.wait(lock); |
||||
} |
||||
|
||||
cleared_points_.insert(point); |
||||
cv_.notify_all(); |
||||
} |
||||
|
||||
} // namespace rocksdb
|
@ -0,0 +1,79 @@ |
||||
// 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 <condition_variable> |
||||
#include <mutex> |
||||
#include <string> |
||||
#include <unordered_set> |
||||
#include <unordered_map> |
||||
#include <vector> |
||||
|
||||
namespace rocksdb { |
||||
|
||||
// This class provides facility to reproduce race conditions deterministically
|
||||
// in unit tests.
|
||||
// Developer could specify sync points in the codebase via TEST_SYNC_POINT.
|
||||
// Each sync point represents a position in the execution stream of a thread.
|
||||
// In the unit test, 'Happens After' relationship among sync points could be
|
||||
// setup via SyncPoint::LoadDependency, to reproduce a desired interleave of
|
||||
// threads execution.
|
||||
// Refer to (DBTest,TransactionLogIteratorRace), for an exmaple use case.
|
||||
|
||||
class SyncPoint { |
||||
public: |
||||
static SyncPoint* GetInstance(); |
||||
|
||||
struct Dependency { |
||||
std::string predecessor; |
||||
std::string successor; |
||||
}; |
||||
// call once at the beginning of a test to setup the dependency between
|
||||
// sync points
|
||||
void LoadDependency(const std::vector<Dependency>& dependencies); |
||||
|
||||
// enable sync point processing (disabled on startup)
|
||||
void EnableProcessing(); |
||||
|
||||
// disable sync point processing
|
||||
void DisableProcessing(); |
||||
|
||||
// remove the execution trace of all sync points
|
||||
void ClearTrace(); |
||||
|
||||
// triggered by TEST_SYNC_POINT, blocking execution until all predecessors
|
||||
// are executed.
|
||||
void Process(const std::string& point); |
||||
|
||||
// TODO: it might be useful to provide a function that blocks until all
|
||||
// sync points are cleared.
|
||||
|
||||
private: |
||||
bool PredecessorsAllCleared(const std::string& point); |
||||
|
||||
// successor/predecessor map loaded from LoadDependency
|
||||
std::unordered_map<std::string, std::vector<std::string>> successors_; |
||||
std::unordered_map<std::string, std::vector<std::string>> predecessors_; |
||||
|
||||
std::mutex mutex_; |
||||
std::condition_variable cv_; |
||||
// sync points that have been passed through
|
||||
std::unordered_set<std::string> cleared_points_; |
||||
bool enabled_ = false; |
||||
}; |
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
// Use TEST_SYNC_POINT to specify sync points inside code base.
|
||||
// Sync points can have happens-after depedency on other sync points,
|
||||
// configured at runtime via SyncPoint::LoadDependency. This could be
|
||||
// utilized to re-produce race conditions between threads.
|
||||
// See TransactionLogIteratorRace in db_test.cc for an example use case.
|
||||
// TEST_SYNC_POINT is no op in release build.
|
||||
#ifdef NDEBUG |
||||
#define TEST_SYNC_POINT(x) |
||||
#else |
||||
#define TEST_SYNC_POINT(x) rocksdb::SyncPoint::GetInstance()->Process(x) |
||||
#endif |
Loading…
Reference in new issue