diff --git a/Makefile b/Makefile index 102224e1f..0b507b591 100644 --- a/Makefile +++ b/Makefile @@ -190,6 +190,16 @@ ifeq ($(USE_LTO), 1) LDFLAGS += -flto -fuse-linker-plugin endif +# `COERCE_CONTEXT_SWITCH=1` will inject spurious wakeup and +# random length of sleep or context switch at critical +# points (e.g, before acquring db mutex) in RocksDB. +# In this way, it coerces as many excution orders as possible in the hope of +# exposing the problematic excution order +COERCE_CONTEXT_SWITCH ?= 0 +ifeq ($(COERCE_CONTEXT_SWITCH), 1) +OPT += -DCOERCE_CONTEXT_SWITCH +endif + #----------------------------------------------- include src.mk diff --git a/db/db_impl/db_impl.cc b/db/db_impl/db_impl.cc index 6ec257836..3da370da7 100644 --- a/db/db_impl/db_impl.cc +++ b/db/db_impl/db_impl.cc @@ -165,8 +165,13 @@ DBImpl::DBImpl(const DBOptions& options, const std::string& dbname, fs_(immutable_db_options_.fs, io_tracer_), mutable_db_options_(initial_db_options_), stats_(immutable_db_options_.stats), +#ifdef COERCE_CONTEXT_SWITCH + mutex_(stats_, immutable_db_options_.clock, DB_MUTEX_WAIT_MICROS, &bg_cv_, + immutable_db_options_.use_adaptive_mutex), +#else // COERCE_CONTEXT_SWITCH mutex_(stats_, immutable_db_options_.clock, DB_MUTEX_WAIT_MICROS, immutable_db_options_.use_adaptive_mutex), +#endif // COERCE_CONTEXT_SWITCH default_cf_handle_(nullptr), error_handler_(this, immutable_db_options_, &mutex_), event_logger_(immutable_db_options_.info_log.get()), diff --git a/monitoring/instrumented_mutex.cc b/monitoring/instrumented_mutex.cc index adca63f26..699495a34 100644 --- a/monitoring/instrumented_mutex.cc +++ b/monitoring/instrumented_mutex.cc @@ -34,6 +34,23 @@ void InstrumentedMutex::Lock() { void InstrumentedMutex::LockInternal() { #ifndef NDEBUG ThreadStatusUtil::TEST_StateDelay(ThreadStatus::STATE_MUTEX_WAIT); +#endif +#ifdef COERCE_CONTEXT_SWITCH + if (stats_code_ == DB_MUTEX_WAIT_MICROS) { + thread_local Random rnd(301); + if (rnd.OneIn(2)) { + if (bg_cv_) { + bg_cv_->SignalAll(); + } + sched_yield(); + } else { + uint32_t sleep_us = rnd.Uniform(11) * 1000; + if (bg_cv_) { + bg_cv_->SignalAll(); + } + SystemClock::Default()->SleepForMicroseconds(sleep_us); + } + } #endif mutex_.Lock(); } diff --git a/monitoring/instrumented_mutex.h b/monitoring/instrumented_mutex.h index ea29bb452..f2b0564bb 100644 --- a/monitoring/instrumented_mutex.h +++ b/monitoring/instrumented_mutex.h @@ -32,11 +32,19 @@ class InstrumentedMutex { clock_(clock), stats_code_(stats_code) {} +#ifdef COERCE_CONTEXT_SWITCH + InstrumentedMutex(Statistics* stats, SystemClock* clock, int stats_code, + InstrumentedCondVar* bg_cv, bool adaptive = false) + : mutex_(adaptive), + stats_(stats), + clock_(clock), + stats_code_(stats_code), + bg_cv_(bg_cv) {} +#endif + void Lock(); - void Unlock() { - mutex_.Unlock(); - } + void Unlock() { mutex_.Unlock(); } void AssertHeld() { mutex_.AssertHeld(); @@ -49,6 +57,9 @@ class InstrumentedMutex { Statistics* stats_; SystemClock* clock_; int stats_code_; +#ifdef COERCE_CONTEXT_SWITCH + InstrumentedCondVar* bg_cv_ = nullptr; +#endif }; class ALIGN_AS(CACHE_LINE_SIZE) CacheAlignedInstrumentedMutex