Branch data Line data Source code
1 : : // Copyright (c) 2012-2022 The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #ifndef BITCOIN_DBWRAPPER_H
6 : : #define BITCOIN_DBWRAPPER_H
7 : :
8 : : #include <attributes.h>
9 : : #include <serialize.h>
10 : : #include <span.h>
11 : : #include <streams.h>
12 : : #include <util/check.h>
13 : : #include <util/fs.h>
14 : :
15 : : #include <cstddef>
16 : : #include <exception>
17 : : #include <memory>
18 : : #include <optional>
19 : : #include <stdexcept>
20 : : #include <string>
21 : : #include <vector>
22 : :
23 : : static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
24 : : static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
25 : : static const size_t DBWRAPPER_MAX_FILE_SIZE = 32 << 20; // 32 MiB
26 : :
27 : : //! User-controlled performance and debug options.
28 : : struct DBOptions {
29 : : //! Compact database on startup.
30 : : bool force_compact = false;
31 : : };
32 : :
33 : : //! Application-specific storage settings.
34 [ + - ]: 25790 : struct DBParams {
35 : : //! Location in the filesystem where leveldb data will be stored.
36 : : fs::path path;
37 : : //! Configures various leveldb cache settings.
38 : : size_t cache_bytes;
39 : : //! If true, use leveldb's memory environment.
40 : : bool memory_only = false;
41 : : //! If true, remove all existing data.
42 : : bool wipe_data = false;
43 : : //! If true, store data obfuscated via simple XOR. If false, XOR with a
44 : : //! zero'd byte array.
45 : : bool obfuscate = false;
46 : : //! Passed-through options.
47 : : DBOptions options{};
48 : : };
49 : :
50 : : class dbwrapper_error : public std::runtime_error
51 : : {
52 : : public:
53 [ # # ]: 0 : explicit dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
54 : : };
55 : :
56 : : class CDBWrapper;
57 : :
58 : : /** These should be considered an implementation detail of the specific database.
59 : : */
60 : : namespace dbwrapper_private {
61 : :
62 : : /** Work around circular dependency, as well as for testing in dbwrapper_tests.
63 : : * Database obfuscation should be considered an implementation detail of the
64 : : * specific database.
65 : : */
66 : : const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w);
67 : :
68 : : }; // namespace dbwrapper_private
69 : :
70 : : bool DestroyDB(const std::string& path_str);
71 : :
72 : : /** Batch of changes queued to be written to a CDBWrapper */
73 : : class CDBBatch
74 : : {
75 : : friend class CDBWrapper;
76 : :
77 : : private:
78 : : const CDBWrapper &parent;
79 : :
80 : : struct WriteBatchImpl;
81 : : const std::unique_ptr<WriteBatchImpl> m_impl_batch;
82 : :
83 : : DataStream ssKey{};
84 : : DataStream ssValue{};
85 : :
86 : : size_t size_estimate{0};
87 : :
88 : : void WriteImpl(Span<const std::byte> key, DataStream& ssValue);
89 : : void EraseImpl(Span<const std::byte> key);
90 : :
91 : : public:
92 : : /**
93 : : * @param[in] _parent CDBWrapper that this batch is to be submitted to
94 : : */
95 : : explicit CDBBatch(const CDBWrapper& _parent);
96 : : ~CDBBatch();
97 : : void Clear();
98 : :
99 : : template <typename K, typename V>
100 : 1911566 : void Write(const K& key, const V& value)
101 : : {
102 : 1911566 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
103 : 1911566 : ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE);
104 : 1911566 : ssKey << key;
105 : 1911566 : ssValue << value;
106 : 1911566 : WriteImpl(ssKey, ssValue);
107 [ + - ]: 1911566 : ssKey.clear();
108 [ + - ]: 1911566 : ssValue.clear();
109 : 1911566 : }
110 : :
111 : : template <typename K>
112 : 221605 : void Erase(const K& key)
113 : : {
114 : 221605 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
115 : 221605 : ssKey << key;
116 : 221605 : EraseImpl(ssKey);
117 [ + - ]: 221605 : ssKey.clear();
118 : 221605 : }
119 : :
120 [ - + - - : 209465 : size_t SizeEstimate() const { return size_estimate; }
+ - ]
121 : : };
122 : :
123 : : class CDBIterator
124 : : {
125 : : public:
126 : : struct IteratorImpl;
127 : :
128 : : private:
129 : : const CDBWrapper &parent;
130 : : const std::unique_ptr<IteratorImpl> m_impl_iter;
131 : :
132 : : void SeekImpl(Span<const std::byte> key);
133 : : Span<const std::byte> GetKeyImpl() const;
134 : : Span<const std::byte> GetValueImpl() const;
135 : :
136 : : public:
137 : :
138 : : /**
139 : : * @param[in] _parent Parent CDBWrapper instance.
140 : : * @param[in] _piter The original leveldb iterator.
141 : : */
142 : : CDBIterator(const CDBWrapper& _parent, std::unique_ptr<IteratorImpl> _piter);
143 : : ~CDBIterator();
144 : :
145 : : bool Valid() const;
146 : :
147 : : void SeekToFirst();
148 : :
149 : 112811 : template<typename K> void Seek(const K& key) {
150 [ + - ]: 112811 : DataStream ssKey{};
151 [ + - ]: 112811 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
152 [ + - ]: 112811 : ssKey << key;
153 [ + - ]: 112811 : SeekImpl(ssKey);
154 : 112811 : }
155 : :
156 : : void Next();
157 : :
158 : 5848065 : template<typename K> bool GetKey(K& key) {
159 : : try {
160 [ + - + - ]: 5848065 : DataStream ssKey{GetKeyImpl()};
161 : 5847585 : ssKey >> key;
162 [ - + ]: 480 : } catch (const std::exception&) {
163 : : return false;
164 : : }
165 : 5847585 : return true;
166 : : }
167 : :
168 : 5847585 : template<typename V> bool GetValue(V& value) {
169 : : try {
170 [ + - + - ]: 5847585 : DataStream ssValue{GetValueImpl()};
171 [ + - + - ]: 5847585 : ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent));
172 : 5847585 : ssValue >> value;
173 [ - - ]: 0 : } catch (const std::exception&) {
174 : : return false;
175 : : }
176 : 5847585 : return true;
177 : : }
178 : : };
179 : :
180 : : struct LevelDBContext;
181 : :
182 : : class CDBWrapper
183 : : {
184 : : friend const std::vector<unsigned char>& dbwrapper_private::GetObfuscateKey(const CDBWrapper &w);
185 : : private:
186 : : //! holds all leveldb-specific fields of this class
187 : : std::unique_ptr<LevelDBContext> m_db_context;
188 : :
189 : : //! the name of this database
190 : : std::string m_name;
191 : :
192 : : //! a key used for optional XOR-obfuscation of the database
193 : : std::vector<unsigned char> obfuscate_key;
194 : :
195 : : //! the key under which the obfuscation key is stored
196 : : static const std::string OBFUSCATE_KEY_KEY;
197 : :
198 : : //! the length of the obfuscate key in number of bytes
199 : : static const unsigned int OBFUSCATE_KEY_NUM_BYTES;
200 : :
201 : : std::vector<unsigned char> CreateObfuscateKey() const;
202 : :
203 : : //! path to filesystem storage
204 : : const fs::path m_path;
205 : :
206 : : //! whether or not the database resides in memory
207 : : bool m_is_memory;
208 : :
209 : : std::optional<std::string> ReadImpl(Span<const std::byte> key) const;
210 : : bool ExistsImpl(Span<const std::byte> key) const;
211 : : size_t EstimateSizeImpl(Span<const std::byte> key1, Span<const std::byte> key2) const;
212 : 3841122 : auto& DBContext() const LIFETIMEBOUND { return *Assert(m_db_context); }
213 : :
214 : : public:
215 : : CDBWrapper(const DBParams& params);
216 : : ~CDBWrapper();
217 : :
218 : : CDBWrapper(const CDBWrapper&) = delete;
219 : : CDBWrapper& operator=(const CDBWrapper&) = delete;
220 : :
221 : : template <typename K, typename V>
222 : 1446086 : bool Read(const K& key, V& value) const
223 : : {
224 [ + - ]: 1446086 : DataStream ssKey{};
225 [ + - ]: 1446086 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
226 [ + - ]: 1446086 : ssKey << key;
227 [ + - ]: 1446086 : std::optional<std::string> strValue{ReadImpl(ssKey)};
228 [ + + ]: 1446086 : if (!strValue) {
229 : : return false;
230 : : }
231 : : try {
232 [ + - ]: 357694 : DataStream ssValue{MakeByteSpan(*strValue)};
233 [ + - ]: 357694 : ssValue.Xor(obfuscate_key);
234 : 357694 : ssValue >> value;
235 [ - - ]: 0 : } catch (const std::exception&) {
236 : : return false;
237 : : }
238 : 357694 : return true;
239 : 1446086 : }
240 : :
241 : : template <typename K, typename V>
242 : 4435 : bool Write(const K& key, const V& value, bool fSync = false)
243 : : {
244 : 4435 : CDBBatch batch(*this);
245 [ + - ]: 4435 : batch.Write(key, value);
246 [ + - ]: 8870 : return WriteBatch(batch, fSync);
247 : 4435 : }
248 : :
249 : : //! @returns filesystem path to the on-disk data.
250 : 0 : std::optional<fs::path> StoragePath() {
251 [ # # # # ]: 0 : if (m_is_memory) {
[ # # # # ]
252 : 0 : return {};
253 : : }
254 : 0 : return m_path;
255 : : }
256 : :
257 : : template <typename K>
258 : 2658 : bool Exists(const K& key) const
259 : : {
260 [ + - ]: 2658 : DataStream ssKey{};
261 [ + - ]: 2658 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
262 [ + - ]: 2658 : ssKey << key;
263 [ + - ]: 2658 : return ExistsImpl(ssKey);
264 : 2658 : }
265 : :
266 : : template <typename K>
267 : 480 : bool Erase(const K& key, bool fSync = false)
268 : : {
269 : 480 : CDBBatch batch(*this);
270 [ + - ]: 480 : batch.Erase(key);
271 [ + - ]: 960 : return WriteBatch(batch, fSync);
272 : 480 : }
273 : :
274 : : bool WriteBatch(CDBBatch& batch, bool fSync = false);
275 : :
276 : : // Get an estimate of LevelDB memory usage (in bytes).
277 : : size_t DynamicMemoryUsage() const;
278 : :
279 : : CDBIterator* NewIterator();
280 : :
281 : : /**
282 : : * Return true if the database managed by this class contains no entries.
283 : : */
284 : : bool IsEmpty();
285 : :
286 : : template<typename K>
287 : 108932 : size_t EstimateSize(const K& key_begin, const K& key_end) const
288 : : {
289 [ + - ]: 108932 : DataStream ssKey1{}, ssKey2{};
290 [ + - ]: 108932 : ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
291 [ + - ]: 108932 : ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
292 [ + - ]: 108932 : ssKey1 << key_begin;
293 [ + - ]: 108932 : ssKey2 << key_end;
294 [ + - ]: 108932 : return EstimateSizeImpl(ssKey1, ssKey2);
295 : 108932 : }
296 : : };
297 : :
298 : : #endif // BITCOIN_DBWRAPPER_H
|