1 // Copyright (c) 2021-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 #ifdef GFLAGS 7 8 #pragma once 9 10 #include <stdint.h> 11 12 #include <atomic> 13 #include <memory> 14 15 #include "rocksdb/env.h" 16 #include "rocksdb/rocksdb_namespace.h" 17 18 namespace ROCKSDB_NAMESPACE { 19 20 // An `ExpectedState` provides read/write access to expected values for every 21 // key. 22 class ExpectedState { 23 public: 24 explicit ExpectedState(size_t max_key, size_t num_column_families); 25 ~ExpectedState()26 virtual ~ExpectedState() {} 27 28 // Requires external locking preventing concurrent execution with any other 29 // member function. 30 virtual Status Open(bool create) = 0; 31 32 // Requires external locking covering all keys in `cf`. 33 void ClearColumnFamily(int cf); 34 35 // @param pending True if the update may have started but is not yet 36 // guaranteed finished. This is useful for crash-recovery testing when the 37 // process may crash before updating the expected values array. 38 // 39 // Requires external locking covering `key` in `cf`. 40 void Put(int cf, int64_t key, uint32_t value_base, bool pending); 41 42 // Requires external locking covering `key` in `cf`. 43 uint32_t Get(int cf, int64_t key) const; 44 45 // @param pending See comment above Put() 46 // Returns true if the key was not yet deleted. 47 // 48 // Requires external locking covering `key` in `cf`. 49 bool Delete(int cf, int64_t key, bool pending); 50 51 // @param pending See comment above Put() 52 // Returns true if the key was not yet deleted. 53 // 54 // Requires external locking covering `key` in `cf`. 55 bool SingleDelete(int cf, int64_t key, bool pending); 56 57 // @param pending See comment above Put() 58 // Returns number of keys deleted by the call. 59 // 60 // Requires external locking covering keys in `[begin_key, end_key)` in `cf`. 61 int DeleteRange(int cf, int64_t begin_key, int64_t end_key, bool pending); 62 63 // Requires external locking covering `key` in `cf`. 64 bool Exists(int cf, int64_t key); 65 66 private: 67 // Requires external locking covering `key` in `cf`. Value(int cf,int64_t key)68 std::atomic<uint32_t>& Value(int cf, int64_t key) const { 69 return values_[cf * max_key_ + key]; 70 } 71 72 const size_t max_key_; 73 const size_t num_column_families_; 74 75 protected: GetValuesLen()76 size_t GetValuesLen() const { 77 return sizeof(std::atomic<uint32_t>) * num_column_families_ * max_key_; 78 } 79 80 // Requires external locking preventing concurrent execution with any other 81 // member function. 82 void Reset(); 83 84 std::atomic<uint32_t>* values_; 85 }; 86 87 // A `FileExpectedState` implements `ExpectedState` backed by a file. 88 class FileExpectedState : public ExpectedState { 89 public: 90 explicit FileExpectedState(std::string expected_state_file_path, 91 size_t max_key, size_t num_column_families); 92 93 // Requires external locking preventing concurrent execution with any other 94 // member function. 95 Status Open(bool create) override; 96 97 private: 98 const std::string expected_state_file_path_; 99 std::unique_ptr<MemoryMappedFileBuffer> expected_state_mmap_buffer_; 100 }; 101 102 // An `AnonExpectedState` implements `ExpectedState` backed by a memory 103 // allocation. 104 class AnonExpectedState : public ExpectedState { 105 public: 106 explicit AnonExpectedState(size_t max_key, size_t num_column_families); 107 108 // Requires external locking preventing concurrent execution with any other 109 // member function. 110 Status Open(bool create) override; 111 112 private: 113 std::unique_ptr<std::atomic<uint32_t>[]> values_allocation_; 114 }; 115 116 // An `ExpectedStateManager` manages data about the expected state of the 117 // database. It exposes operations for reading and modifying the latest 118 // expected state. 119 class ExpectedStateManager { 120 public: 121 explicit ExpectedStateManager(size_t max_key, size_t num_column_families); 122 123 virtual ~ExpectedStateManager(); 124 125 // Requires external locking preventing concurrent execution with any other 126 // member function. 127 virtual Status Open() = 0; 128 129 // Requires external locking covering all keys in `cf`. ClearColumnFamily(int cf)130 void ClearColumnFamily(int cf) { return latest_->ClearColumnFamily(cf); } 131 132 // @param pending True if the update may have started but is not yet 133 // guaranteed finished. This is useful for crash-recovery testing when the 134 // process may crash before updating the expected values array. 135 // 136 // Requires external locking covering `key` in `cf`. Put(int cf,int64_t key,uint32_t value_base,bool pending)137 void Put(int cf, int64_t key, uint32_t value_base, bool pending) { 138 return latest_->Put(cf, key, value_base, pending); 139 } 140 141 // Requires external locking covering `key` in `cf`. Get(int cf,int64_t key)142 uint32_t Get(int cf, int64_t key) const { return latest_->Get(cf, key); } 143 144 // @param pending See comment above Put() 145 // Returns true if the key was not yet deleted. 146 // 147 // Requires external locking covering `key` in `cf`. Delete(int cf,int64_t key,bool pending)148 bool Delete(int cf, int64_t key, bool pending) { 149 return latest_->Delete(cf, key, pending); 150 } 151 152 // @param pending See comment above Put() 153 // Returns true if the key was not yet deleted. 154 // 155 // Requires external locking covering `key` in `cf`. SingleDelete(int cf,int64_t key,bool pending)156 bool SingleDelete(int cf, int64_t key, bool pending) { 157 return latest_->SingleDelete(cf, key, pending); 158 } 159 160 // @param pending See comment above Put() 161 // Returns number of keys deleted by the call. 162 // 163 // Requires external locking covering keys in `[begin_key, end_key)` in `cf`. DeleteRange(int cf,int64_t begin_key,int64_t end_key,bool pending)164 int DeleteRange(int cf, int64_t begin_key, int64_t end_key, bool pending) { 165 return latest_->DeleteRange(cf, begin_key, end_key, pending); 166 } 167 168 // Requires external locking covering `key` in `cf`. Exists(int cf,int64_t key)169 bool Exists(int cf, int64_t key) { return latest_->Exists(cf, key); } 170 171 protected: 172 const size_t max_key_; 173 const size_t num_column_families_; 174 std::unique_ptr<ExpectedState> latest_; 175 }; 176 177 // A `FileExpectedStateManager` implements an `ExpectedStateManager` backed by 178 // a directory of files containing data about the expected state of the 179 // database. 180 class FileExpectedStateManager : public ExpectedStateManager { 181 public: 182 explicit FileExpectedStateManager(size_t max_key, size_t num_column_families, 183 std::string expected_state_dir_path); 184 185 // Requires external locking preventing concurrent execution with any other 186 // member function. 187 Status Open() override; 188 189 private: 190 // Requires external locking preventing concurrent execution with any other 191 // member function. 192 Status Clean(); 193 194 std::string GetTempPathForFilename(const std::string& filename); 195 std::string GetPathForFilename(const std::string& filename); 196 197 static const std::string kLatestFilename; 198 199 const std::string expected_state_dir_path_; 200 }; 201 202 // An `AnonExpectedStateManager` implements an `ExpectedStateManager` backed by 203 // a memory allocation containing data about the expected state of the database. 204 class AnonExpectedStateManager : public ExpectedStateManager { 205 public: 206 explicit AnonExpectedStateManager(size_t max_key, size_t num_column_families); 207 208 // Requires external locking preventing concurrent execution with any other 209 // member function. 210 Status Open() override; 211 }; 212 213 } // namespace ROCKSDB_NAMESPACE 214 215 #endif // GFLAGS 216