Branch data Line data Source code
1 : : // Copyright (c) 2012-present 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/byte_units.h>
13 : : #include <util/check.h>
14 : : #include <util/fs.h>
15 : :
16 : : #include <cstddef>
17 : : #include <exception>
18 : : #include <memory>
19 : : #include <optional>
20 : : #include <stdexcept>
21 : : #include <string>
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_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 : 41692 : 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 Obfuscation& GetObfuscation(const CDBWrapper&);
67 : : }; // namespace dbwrapper_private
68 : :
69 : : bool DestroyDB(const std::string& path_str);
70 : :
71 : : /** Batch of changes queued to be written to a CDBWrapper */
72 : : class CDBBatch
73 : : {
74 : : friend class CDBWrapper;
75 : :
76 : : private:
77 : : const CDBWrapper &parent;
78 : :
79 : : struct WriteBatchImpl;
80 : : const std::unique_ptr<WriteBatchImpl> m_impl_batch;
81 : :
82 : : DataStream ssKey{};
83 : : DataStream ssValue{};
84 : :
85 : : void WriteImpl(std::span<const std::byte> key, DataStream& ssValue);
86 : : void EraseImpl(std::span<const std::byte> key);
87 : :
88 : : public:
89 : : /**
90 : : * @param[in] _parent CDBWrapper that this batch is to be submitted to
91 : : */
92 : : explicit CDBBatch(const CDBWrapper& _parent);
93 : : ~CDBBatch();
94 : : void Clear();
95 : :
96 : : template <typename K, typename V>
97 : 8632357 : void Write(const K& key, const V& value)
98 : : {
99 : 8632357 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
100 : 8632357 : ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE);
101 : 8632357 : ssKey << key;
102 : 8632357 : ssValue << value;
103 [ - + ]: 8632357 : WriteImpl(ssKey, ssValue);
104 [ + - ]: 8632357 : ssKey.clear();
105 [ + - ]: 8632357 : ssValue.clear();
106 : 8632357 : }
107 : :
108 : : template <typename K>
109 : 6743653 : void Erase(const K& key)
110 : : {
111 : 6743653 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
112 : 6743653 : ssKey << key;
113 [ - + ]: 6743653 : EraseImpl(ssKey);
114 [ + - ]: 6743653 : ssKey.clear();
115 : 6743653 : }
116 : :
117 : : size_t ApproximateSize() const;
118 : : };
119 : :
120 : : class CDBIterator
121 : : {
122 : : public:
123 : : struct IteratorImpl;
124 : :
125 : : private:
126 : : const CDBWrapper &parent;
127 : : const std::unique_ptr<IteratorImpl> m_impl_iter;
128 : :
129 : : void SeekImpl(std::span<const std::byte> key);
130 : : std::span<const std::byte> GetKeyImpl() const;
131 : : std::span<const std::byte> GetValueImpl() const;
132 : :
133 : : public:
134 : :
135 : : /**
136 : : * @param[in] _parent Parent CDBWrapper instance.
137 : : * @param[in] _piter The original leveldb iterator.
138 : : */
139 : : CDBIterator(const CDBWrapper& _parent, std::unique_ptr<IteratorImpl> _piter);
140 : : ~CDBIterator();
141 : :
142 : : bool Valid() const;
143 : :
144 : : void SeekToFirst();
145 : :
146 : 101678 : template<typename K> void Seek(const K& key) {
147 [ + - ]: 101678 : DataStream ssKey{};
148 [ + - ]: 101678 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
149 [ - + ]: 101678 : ssKey << key;
150 [ + - ]: 101678 : SeekImpl(ssKey);
151 : 101678 : }
152 : :
153 : : void Next();
154 : :
155 : 4405720 : template<typename K> bool GetKey(K& key) {
156 : : try {
157 [ + - + - ]: 4405720 : DataStream ssKey{GetKeyImpl()};
158 : 4405281 : ssKey >> key;
159 [ - + ]: 439 : } catch (const std::exception&) {
160 : : return false;
161 : : }
162 : 4405281 : return true;
163 : : }
164 : :
165 : 4404466 : template<typename V> bool GetValue(V& value) {
166 : : try {
167 [ + - + - ]: 4404466 : DataStream ssValue{GetValueImpl()};
168 [ + - - + : 4404466 : dbwrapper_private::GetObfuscation(parent)(ssValue);
+ - ]
169 : 4404466 : ssValue >> value;
170 [ - - ]: 0 : } catch (const std::exception&) {
171 : : return false;
172 : : }
173 : 4404466 : return true;
174 : : }
175 : : };
176 : :
177 : : struct LevelDBContext;
178 : :
179 : : class CDBWrapper
180 : : {
181 : : friend const Obfuscation& dbwrapper_private::GetObfuscation(const CDBWrapper&);
182 : : private:
183 : : //! holds all leveldb-specific fields of this class
184 : : std::unique_ptr<LevelDBContext> m_db_context;
185 : :
186 : : //! the name of this database
187 : : std::string m_name;
188 : :
189 : : //! optional XOR-obfuscation of the database
190 : : Obfuscation m_obfuscation;
191 : :
192 : : //! obfuscation key storage key, null-prefixed to avoid collisions
193 : : inline static const std::string OBFUSCATION_KEY{"\000obfuscate_key", 14}; // explicit size to avoid truncation at leading \0
194 : :
195 : : std::optional<std::string> ReadImpl(std::span<const std::byte> key) const;
196 : : bool ExistsImpl(std::span<const std::byte> key) const;
197 : : size_t EstimateSizeImpl(std::span<const std::byte> key1, std::span<const std::byte> key2) const;
198 [ - + ]: 20951310 : auto& DBContext() const LIFETIMEBOUND { return *Assert(m_db_context); }
199 : :
200 : : public:
201 : : CDBWrapper(const DBParams& params);
202 : : ~CDBWrapper();
203 : :
204 : : CDBWrapper(const CDBWrapper&) = delete;
205 : : CDBWrapper& operator=(const CDBWrapper&) = delete;
206 : :
207 : : template <typename K, typename V>
208 : 6730660 : bool Read(const K& key, V& value) const
209 : : {
210 [ + - ]: 6730660 : DataStream ssKey{};
211 [ + - ]: 6730660 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
212 [ - + ]: 6730660 : ssKey << key;
213 [ + - ]: 6730660 : std::optional<std::string> strValue{ReadImpl(ssKey)};
214 [ + + ]: 6730660 : if (!strValue) {
215 : : return false;
216 : : }
217 : : try {
218 : 3716251 : std::span ssValue{MakeWritableByteSpan(*strValue)};
219 [ + - ]: 3716251 : m_obfuscation(ssValue);
220 [ + - ]: 10446911 : SpanReader{ssValue} >> value;
221 [ - - ]: 0 : } catch (const std::exception&) {
222 : : return false;
223 : : }
224 : : return true;
225 : 6730660 : }
226 : :
227 : : template <typename K, typename V>
228 : 5728 : void Write(const K& key, const V& value, bool fSync = false)
229 : : {
230 : 5728 : CDBBatch batch(*this);
231 [ + - ]: 5728 : batch.Write(key, value);
232 [ + - ]: 5728 : WriteBatch(batch, fSync);
233 : 5728 : }
234 : :
235 : : template <typename K>
236 : 5746 : bool Exists(const K& key) const
237 : : {
238 [ + - ]: 5746 : DataStream ssKey{};
239 [ + - ]: 5746 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
240 [ - + ]: 5746 : ssKey << key;
241 [ + - ]: 5746 : return ExistsImpl(ssKey);
242 : 5746 : }
243 : :
244 : : template <typename K>
245 : 439 : void Erase(const K& key, bool fSync = false)
246 : : {
247 : 439 : CDBBatch batch(*this);
248 [ + - ]: 439 : batch.Erase(key);
249 [ + - ]: 439 : WriteBatch(batch, fSync);
250 : 439 : }
251 : :
252 : : void WriteBatch(CDBBatch& batch, bool fSync = false);
253 : :
254 : : // Get an estimate of LevelDB memory usage (in bytes).
255 : : size_t DynamicMemoryUsage() const;
256 : :
257 : : CDBIterator* NewIterator();
258 : :
259 : : /**
260 : : * Return true if the database managed by this class contains no entries.
261 : : */
262 : : bool IsEmpty();
263 : :
264 : : template<typename K>
265 : 99320 : size_t EstimateSize(const K& key_begin, const K& key_end) const
266 : : {
267 [ + - ]: 99320 : DataStream ssKey1{}, ssKey2{};
268 [ + - ]: 99320 : ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
269 [ + - ]: 99320 : ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
270 [ + - ]: 99320 : ssKey1 << key_begin;
271 [ - + ]: 99320 : ssKey2 << key_end;
272 [ - + + - ]: 99320 : return EstimateSizeImpl(ssKey1, ssKey2);
273 : 99320 : }
274 : : };
275 : :
276 : : #endif // BITCOIN_DBWRAPPER_H
|