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