/src/rocksdb/env/emulated_clock.h
Line | Count | Source (jump to first uncovered line) |
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 | | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. |
7 | | // Use of this source code is governed by a BSD-style license that can be |
8 | | // found in the LICENSE file. See the AUTHORS file for names of contributors. |
9 | | #pragma once |
10 | | |
11 | | #include <atomic> |
12 | | #include <string> |
13 | | |
14 | | #include "rocksdb/status.h" |
15 | | #include "rocksdb/system_clock.h" |
16 | | |
17 | | namespace ROCKSDB_NAMESPACE { |
18 | | // A SystemClock that can "mock" sleep and counts its operations. |
19 | | class EmulatedSystemClock : public SystemClockWrapper { |
20 | | private: |
21 | | // Something to return when mocking current time |
22 | | const int64_t maybe_starting_time_; |
23 | | std::atomic<int> sleep_counter_{0}; |
24 | | std::atomic<int> cpu_counter_{0}; |
25 | | std::atomic<int64_t> addon_microseconds_{0}; |
26 | | // Do not modify in the env of a running DB (could cause deadlock) |
27 | | std::atomic<bool> time_elapse_only_sleep_; |
28 | | bool no_slowdown_; |
29 | | |
30 | | public: |
31 | | explicit EmulatedSystemClock(const std::shared_ptr<SystemClock>& base, |
32 | | bool time_elapse_only_sleep = false); |
33 | | |
34 | 0 | static const char* kClassName() { return "TimeEmulatedSystemClock"; } |
35 | 0 | const char* Name() const override { return kClassName(); } |
36 | | |
37 | 0 | void SleepForMicroseconds(int micros) override { |
38 | 0 | sleep_counter_++; |
39 | 0 | if (no_slowdown_ || time_elapse_only_sleep_) { |
40 | 0 | addon_microseconds_.fetch_add(micros); |
41 | 0 | } |
42 | 0 | if (!no_slowdown_) { |
43 | 0 | SystemClockWrapper::SleepForMicroseconds(micros); |
44 | 0 | } |
45 | 0 | } |
46 | | |
47 | 0 | void MockSleepForMicroseconds(int64_t micros) { |
48 | 0 | sleep_counter_++; |
49 | 0 | assert(no_slowdown_); |
50 | 0 | addon_microseconds_.fetch_add(micros); |
51 | 0 | } |
52 | | |
53 | 0 | void MockSleepForSeconds(int64_t seconds) { |
54 | 0 | sleep_counter_++; |
55 | 0 | assert(no_slowdown_); |
56 | 0 | addon_microseconds_.fetch_add(seconds * 1000000); |
57 | 0 | } |
58 | | |
59 | 0 | void SetTimeElapseOnlySleep(bool enabled) { |
60 | | // We cannot set these before destroying the last DB because they might |
61 | | // cause a deadlock or similar without the appropriate options set in |
62 | | // the DB. |
63 | 0 | time_elapse_only_sleep_ = enabled; |
64 | 0 | no_slowdown_ = enabled; |
65 | 0 | } |
66 | | |
67 | 0 | bool IsTimeElapseOnlySleep() const { return time_elapse_only_sleep_.load(); } |
68 | 0 | void SetMockSleep(bool enabled = true) { no_slowdown_ = enabled; } |
69 | 0 | bool IsMockSleepEnabled() const { return no_slowdown_; } |
70 | | |
71 | 0 | int GetSleepCounter() const { return sleep_counter_.load(); } |
72 | | |
73 | 0 | Status GetCurrentTime(int64_t* unix_time) override { |
74 | 0 | Status s; |
75 | 0 | if (time_elapse_only_sleep_) { |
76 | 0 | *unix_time = maybe_starting_time_; |
77 | 0 | } else { |
78 | 0 | s = SystemClockWrapper::GetCurrentTime(unix_time); |
79 | 0 | } |
80 | 0 | if (s.ok()) { |
81 | | // mock microseconds elapsed to seconds of time |
82 | 0 | *unix_time += addon_microseconds_.load() / 1000000; |
83 | 0 | } |
84 | 0 | return s; |
85 | 0 | } |
86 | | |
87 | 0 | uint64_t CPUNanos() override { |
88 | 0 | cpu_counter_++; |
89 | 0 | return SystemClockWrapper::CPUNanos(); |
90 | 0 | } |
91 | | |
92 | 0 | uint64_t CPUMicros() override { |
93 | 0 | cpu_counter_++; |
94 | 0 | return SystemClockWrapper::CPUMicros(); |
95 | 0 | } |
96 | | |
97 | 0 | uint64_t NowNanos() override { |
98 | 0 | return (time_elapse_only_sleep_ ? 0 : SystemClockWrapper::NowNanos()) + |
99 | 0 | addon_microseconds_.load() * 1000; |
100 | 0 | } |
101 | | |
102 | 0 | uint64_t NowMicros() override { |
103 | 0 | return (time_elapse_only_sleep_ ? 0 : SystemClockWrapper::NowMicros()) + |
104 | 0 | addon_microseconds_.load(); |
105 | 0 | } |
106 | | |
107 | 0 | int GetCpuCounter() const { return cpu_counter_.load(); } |
108 | | |
109 | 0 | void ResetCounters() { |
110 | 0 | cpu_counter_.store(0); |
111 | 0 | sleep_counter_.store(0); |
112 | 0 | } |
113 | | }; |
114 | | } // namespace ROCKSDB_NAMESPACE |