1 //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 
6 #pragma once
7 
8 #include "monitoring/statistics.h"
9 #include "port/port.h"
10 #include "rocksdb/statistics.h"
11 #include "rocksdb/system_clock.h"
12 #include "rocksdb/thread_status.h"
13 #include "util/stop_watch.h"
14 
15 namespace ROCKSDB_NAMESPACE {
16 class InstrumentedCondVar;
17 
18 // A wrapper class for port::Mutex that provides additional layer
19 // for collecting stats and instrumentation.
20 class InstrumentedMutex {
21  public:
22   explicit InstrumentedMutex(bool adaptive = false)
mutex_(adaptive)23       : mutex_(adaptive), stats_(nullptr), clock_(nullptr), stats_code_(0) {}
24 
25   explicit InstrumentedMutex(SystemClock* clock, bool adaptive = false)
mutex_(adaptive)26       : mutex_(adaptive), stats_(nullptr), clock_(clock), stats_code_(0) {}
27 
28   InstrumentedMutex(Statistics* stats, SystemClock* clock, int stats_code,
29                     bool adaptive = false)
mutex_(adaptive)30       : mutex_(adaptive),
31         stats_(stats),
32         clock_(clock),
33         stats_code_(stats_code) {}
34 
35   void Lock();
36 
Unlock()37   void Unlock() {
38     mutex_.Unlock();
39   }
40 
AssertHeld()41   void AssertHeld() {
42     mutex_.AssertHeld();
43   }
44 
45  private:
46   void LockInternal();
47   friend class InstrumentedCondVar;
48   port::Mutex mutex_;
49   Statistics* stats_;
50   SystemClock* clock_;
51   int stats_code_;
52 };
53 
54 // RAII wrapper for InstrumentedMutex
55 class InstrumentedMutexLock {
56  public:
InstrumentedMutexLock(InstrumentedMutex * mutex)57   explicit InstrumentedMutexLock(InstrumentedMutex* mutex) : mutex_(mutex) {
58     mutex_->Lock();
59   }
60 
~InstrumentedMutexLock()61   ~InstrumentedMutexLock() {
62     mutex_->Unlock();
63   }
64 
65  private:
66   InstrumentedMutex* const mutex_;
67   InstrumentedMutexLock(const InstrumentedMutexLock&) = delete;
68   void operator=(const InstrumentedMutexLock&) = delete;
69 };
70 
71 // RAII wrapper for temporary releasing InstrumentedMutex inside
72 // InstrumentedMutexLock
73 class InstrumentedMutexUnlock {
74  public:
InstrumentedMutexUnlock(InstrumentedMutex * mutex)75   explicit InstrumentedMutexUnlock(InstrumentedMutex* mutex) : mutex_(mutex) {
76     mutex_->Unlock();
77   }
78 
~InstrumentedMutexUnlock()79   ~InstrumentedMutexUnlock() { mutex_->Lock(); }
80 
81  private:
82   InstrumentedMutex* const mutex_;
83   InstrumentedMutexUnlock(const InstrumentedMutexUnlock&) = delete;
84   void operator=(const InstrumentedMutexUnlock&) = delete;
85 };
86 
87 class InstrumentedCondVar {
88  public:
InstrumentedCondVar(InstrumentedMutex * instrumented_mutex)89   explicit InstrumentedCondVar(InstrumentedMutex* instrumented_mutex)
90       : cond_(&(instrumented_mutex->mutex_)),
91         stats_(instrumented_mutex->stats_),
92         clock_(instrumented_mutex->clock_),
93         stats_code_(instrumented_mutex->stats_code_) {}
94 
95   void Wait();
96 
97   bool TimedWait(uint64_t abs_time_us);
98 
Signal()99   void Signal() {
100     cond_.Signal();
101   }
102 
SignalAll()103   void SignalAll() {
104     cond_.SignalAll();
105   }
106 
107  private:
108   void WaitInternal();
109   bool TimedWaitInternal(uint64_t abs_time_us);
110   port::CondVar cond_;
111   Statistics* stats_;
112   SystemClock* clock_;
113   int stats_code_;
114 };
115 
116 }  // namespace ROCKSDB_NAMESPACE
117