4
4
5
5
#include < dbwrapper.h>
6
6
7
+ #include < clientversion.h>
7
8
#include < logging.h>
8
9
#include < random.h>
9
- #include < tinyformat.h>
10
+ #include < serialize.h>
11
+ #include < span.h>
12
+ #include < streams.h>
10
13
#include < util/fs.h>
11
14
#include < util/fs_helpers.h>
12
15
#include < util/strencodings.h>
23
26
#include < leveldb/helpers/memenv/memenv.h>
24
27
#include < leveldb/iterator.h>
25
28
#include < leveldb/options.h>
29
+ #include < leveldb/slice.h>
26
30
#include < leveldb/status.h>
31
+ #include < leveldb/write_batch.h>
27
32
#include < memory>
28
33
#include < optional>
34
+ #include < utility>
35
+
36
+ static auto CharCast (const std::byte* data) { return reinterpret_cast <const char *>(data); }
37
+
38
+ bool DestroyDB (const std::string& path_str)
39
+ {
40
+ return leveldb::DestroyDB (path_str, {}).ok ();
41
+ }
42
+
43
+ /* * Handle database error by throwing dbwrapper_error exception.
44
+ */
45
+ static void HandleError (const leveldb::Status& status)
46
+ {
47
+ if (status.ok ())
48
+ return ;
49
+ const std::string errmsg = " Fatal LevelDB error: " + status.ToString ();
50
+ LogPrintf (" %s\n " , errmsg);
51
+ LogPrintf (" You can use -debug=leveldb to get more complete diagnostic messages\n " );
52
+ throw dbwrapper_error (errmsg);
53
+ }
29
54
30
55
class CBitcoinLevelDBLogger : public leveldb ::Logger {
31
56
public:
@@ -127,24 +152,91 @@ static leveldb::Options GetOptions(size_t nCacheSize)
127
152
return options;
128
153
}
129
154
155
+ struct CDBBatch ::WriteBatchImpl {
156
+ leveldb::WriteBatch batch;
157
+ };
158
+
159
+ CDBBatch::CDBBatch (const CDBWrapper& _parent) : parent(_parent),
160
+ m_impl_batch{std::make_unique<CDBBatch::WriteBatchImpl>()},
161
+ ssValue (SER_DISK, CLIENT_VERSION){};
162
+
163
+ CDBBatch::~CDBBatch () = default ;
164
+
165
+ void CDBBatch::Clear ()
166
+ {
167
+ m_impl_batch->batch .Clear ();
168
+ size_estimate = 0 ;
169
+ }
170
+
171
+ void CDBBatch::WriteImpl (Span<const std::byte> key, CDataStream& ssValue)
172
+ {
173
+ leveldb::Slice slKey (CharCast (key.data ()), key.size ());
174
+ ssValue.Xor (dbwrapper_private::GetObfuscateKey (parent));
175
+ leveldb::Slice slValue (CharCast (ssValue.data ()), ssValue.size ());
176
+ m_impl_batch->batch .Put (slKey, slValue);
177
+ // LevelDB serializes writes as:
178
+ // - byte: header
179
+ // - varint: key length (1 byte up to 127B, 2 bytes up to 16383B, ...)
180
+ // - byte[]: key
181
+ // - varint: value length
182
+ // - byte[]: value
183
+ // The formula below assumes the key and value are both less than 16k.
184
+ size_estimate += 3 + (slKey.size () > 127 ) + slKey.size () + (slValue.size () > 127 ) + slValue.size ();
185
+ }
186
+
187
+ void CDBBatch::EraseImpl (Span<const std::byte> key)
188
+ {
189
+ leveldb::Slice slKey (CharCast (key.data ()), key.size ());
190
+ m_impl_batch->batch .Delete (slKey);
191
+ // LevelDB serializes erases as:
192
+ // - byte: header
193
+ // - varint: key length
194
+ // - byte[]: key
195
+ // The formula below assumes the key is less than 16kB.
196
+ size_estimate += 2 + (slKey.size () > 127 ) + slKey.size ();
197
+ }
198
+
199
+ struct LevelDBContext {
200
+ // ! custom environment this database is using (may be nullptr in case of default environment)
201
+ leveldb::Env* penv;
202
+
203
+ // ! database options used
204
+ leveldb::Options options;
205
+
206
+ // ! options used when reading from the database
207
+ leveldb::ReadOptions readoptions;
208
+
209
+ // ! options used when iterating over values of the database
210
+ leveldb::ReadOptions iteroptions;
211
+
212
+ // ! options used when writing to the database
213
+ leveldb::WriteOptions writeoptions;
214
+
215
+ // ! options used when sync writing to the database
216
+ leveldb::WriteOptions syncoptions;
217
+
218
+ // ! the database itself
219
+ leveldb::DB* pdb;
220
+ };
221
+
130
222
CDBWrapper::CDBWrapper (const DBParams& params)
131
- : m_name{fs::PathToString (params.path .stem ())}, m_path{params.path }, m_is_memory{params.memory_only }
223
+ : m_db_context{std::make_unique<LevelDBContext>()}, m_name{fs::PathToString (params.path .stem ())}, m_path{params.path }, m_is_memory{params.memory_only }
132
224
{
133
- penv = nullptr ;
134
- readoptions.verify_checksums = true ;
135
- iteroptions.verify_checksums = true ;
136
- iteroptions.fill_cache = false ;
137
- syncoptions.sync = true ;
138
- options = GetOptions (params.cache_bytes );
139
- options.create_if_missing = true ;
225
+ DBContext (). penv = nullptr ;
226
+ DBContext (). readoptions .verify_checksums = true ;
227
+ DBContext (). iteroptions .verify_checksums = true ;
228
+ DBContext (). iteroptions .fill_cache = false ;
229
+ DBContext (). syncoptions .sync = true ;
230
+ DBContext (). options = GetOptions (params.cache_bytes );
231
+ DBContext (). options .create_if_missing = true ;
140
232
if (params.memory_only ) {
141
- penv = leveldb::NewMemEnv (leveldb::Env::Default ());
142
- options.env = penv;
233
+ DBContext (). penv = leveldb::NewMemEnv (leveldb::Env::Default ());
234
+ DBContext (). options .env = DBContext (). penv ;
143
235
} else {
144
236
if (params.wipe_data ) {
145
237
LogPrintf (" Wiping LevelDB in %s\n " , fs::PathToString (params.path ));
146
- leveldb::Status result = leveldb::DestroyDB (fs::PathToString (params.path ), options);
147
- dbwrapper_private:: HandleError (result);
238
+ leveldb::Status result = leveldb::DestroyDB (fs::PathToString (params.path ), DBContext (). options );
239
+ HandleError (result);
148
240
}
149
241
TryCreateDirectories (params.path );
150
242
LogPrintf (" Opening LevelDB in %s\n " , fs::PathToString (params.path ));
@@ -153,13 +245,13 @@ CDBWrapper::CDBWrapper(const DBParams& params)
153
245
// because on POSIX leveldb passes the byte string directly to ::open(), and
154
246
// on Windows it converts from UTF-8 to UTF-16 before calling ::CreateFileW
155
247
// (see env_posix.cc and env_windows.cc).
156
- leveldb::Status status = leveldb::DB::Open (options, fs::PathToString (params.path ), &pdb);
157
- dbwrapper_private:: HandleError (status);
248
+ leveldb::Status status = leveldb::DB::Open (DBContext (). options , fs::PathToString (params.path ), &DBContext (). pdb );
249
+ HandleError (status);
158
250
LogPrintf (" Opened LevelDB successfully\n " );
159
251
160
252
if (params.options .force_compact ) {
161
253
LogPrintf (" Starting database compaction of %s\n " , fs::PathToString (params.path ));
162
- pdb->CompactRange (nullptr , nullptr );
254
+ DBContext (). pdb ->CompactRange (nullptr , nullptr );
163
255
LogPrintf (" Finished database compaction of %s\n " , fs::PathToString (params.path ));
164
256
}
165
257
@@ -185,16 +277,16 @@ CDBWrapper::CDBWrapper(const DBParams& params)
185
277
186
278
CDBWrapper::~CDBWrapper ()
187
279
{
188
- delete pdb;
189
- pdb = nullptr ;
190
- delete options.filter_policy ;
191
- options.filter_policy = nullptr ;
192
- delete options.info_log ;
193
- options.info_log = nullptr ;
194
- delete options.block_cache ;
195
- options.block_cache = nullptr ;
196
- delete penv;
197
- options.env = nullptr ;
280
+ delete DBContext (). pdb ;
281
+ DBContext (). pdb = nullptr ;
282
+ delete DBContext (). options .filter_policy ;
283
+ DBContext (). options .filter_policy = nullptr ;
284
+ delete DBContext (). options .info_log ;
285
+ DBContext (). options .info_log = nullptr ;
286
+ delete DBContext (). options .block_cache ;
287
+ DBContext (). options .block_cache = nullptr ;
288
+ delete DBContext (). penv ;
289
+ DBContext (). options .env = nullptr ;
198
290
}
199
291
200
292
bool CDBWrapper::WriteBatch (CDBBatch& batch, bool fSync )
@@ -204,8 +296,8 @@ bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync)
204
296
if (log_memory) {
205
297
mem_before = DynamicMemoryUsage () / 1024.0 / 1024 ;
206
298
}
207
- leveldb::Status status = pdb->Write (fSync ? syncoptions : writeoptions, &batch.batch );
208
- dbwrapper_private:: HandleError (status);
299
+ leveldb::Status status = DBContext (). pdb ->Write (fSync ? DBContext (). syncoptions : DBContext (). writeoptions , &batch.m_impl_batch -> batch );
300
+ HandleError (status);
209
301
if (log_memory) {
210
302
double mem_after = DynamicMemoryUsage () / 1024.0 / 1024 ;
211
303
LogPrint (BCLog::LEVELDB, " WriteBatch memory usage: db=%s, before=%.1fMiB, after=%.1fMiB\n " ,
@@ -218,7 +310,7 @@ size_t CDBWrapper::DynamicMemoryUsage() const
218
310
{
219
311
std::string memory;
220
312
std::optional<size_t > parsed;
221
- if (!pdb->GetProperty (" leveldb.approximate-memory-usage" , &memory) || !(parsed = ToIntegral<size_t >(memory))) {
313
+ if (!DBContext (). pdb ->GetProperty (" leveldb.approximate-memory-usage" , &memory) || !(parsed = ToIntegral<size_t >(memory))) {
222
314
LogPrint (BCLog::LEVELDB, " Failed to get approximate-memory-usage property\n " );
223
315
return 0 ;
224
316
}
@@ -244,30 +336,89 @@ std::vector<unsigned char> CDBWrapper::CreateObfuscateKey() const
244
336
return ret;
245
337
}
246
338
339
+ std::optional<std::string> CDBWrapper::ReadImpl (Span<const std::byte> key) const
340
+ {
341
+ leveldb::Slice slKey (CharCast (key.data ()), key.size ());
342
+ std::string strValue;
343
+ leveldb::Status status = DBContext ().pdb ->Get (DBContext ().readoptions , slKey, &strValue);
344
+ if (!status.ok ()) {
345
+ if (status.IsNotFound ())
346
+ return std::nullopt;
347
+ LogPrintf (" LevelDB read failure: %s\n " , status.ToString ());
348
+ HandleError (status);
349
+ }
350
+ return strValue;
351
+ }
352
+
353
+ bool CDBWrapper::ExistsImpl (Span<const std::byte> key) const
354
+ {
355
+ leveldb::Slice slKey (CharCast (key.data ()), key.size ());
356
+
357
+ std::string strValue;
358
+ leveldb::Status status = DBContext ().pdb ->Get (DBContext ().readoptions , slKey, &strValue);
359
+ if (!status.ok ()) {
360
+ if (status.IsNotFound ())
361
+ return false ;
362
+ LogPrintf (" LevelDB read failure: %s\n " , status.ToString ());
363
+ HandleError (status);
364
+ }
365
+ return true ;
366
+ }
367
+
368
+ size_t CDBWrapper::EstimateSizeImpl (Span<const std::byte> key1, Span<const std::byte> key2) const
369
+ {
370
+ leveldb::Slice slKey1 (CharCast (key1.data ()), key1.size ());
371
+ leveldb::Slice slKey2 (CharCast (key2.data ()), key2.size ());
372
+ uint64_t size = 0 ;
373
+ leveldb::Range range (slKey1, slKey2);
374
+ DBContext ().pdb ->GetApproximateSizes (&range, 1 , &size);
375
+ return size;
376
+ }
377
+
247
378
bool CDBWrapper::IsEmpty ()
248
379
{
249
380
std::unique_ptr<CDBIterator> it (NewIterator ());
250
381
it->SeekToFirst ();
251
382
return !(it->Valid ());
252
383
}
253
384
254
- CDBIterator::~CDBIterator () { delete piter; }
255
- bool CDBIterator::Valid () const { return piter->Valid (); }
256
- void CDBIterator::SeekToFirst () { piter->SeekToFirst (); }
257
- void CDBIterator::Next () { piter->Next (); }
385
+ struct CDBIterator ::IteratorImpl {
386
+ const std::unique_ptr<leveldb::Iterator> iter;
258
387
259
- namespace dbwrapper_private {
388
+ explicit IteratorImpl (leveldb::Iterator* _iter) : iter{_iter} {}
389
+ };
260
390
261
- void HandleError (const leveldb::Status& status)
391
+ CDBIterator::CDBIterator (const CDBWrapper& _parent, std::unique_ptr<IteratorImpl> _piter) : parent(_parent),
392
+ m_impl_iter(std::move(_piter)) {}
393
+
394
+ CDBIterator* CDBWrapper::NewIterator ()
262
395
{
263
- if (status.ok ())
264
- return ;
265
- const std::string errmsg = " Fatal LevelDB error: " + status.ToString ();
266
- LogPrintf (" %s\n " , errmsg);
267
- LogPrintf (" You can use -debug=leveldb to get more complete diagnostic messages\n " );
268
- throw dbwrapper_error (errmsg);
396
+ return new CDBIterator{*this , std::make_unique<CDBIterator::IteratorImpl>(DBContext ().pdb ->NewIterator (DBContext ().iteroptions ))};
269
397
}
270
398
399
+ void CDBIterator::SeekImpl (Span<const std::byte> key)
400
+ {
401
+ leveldb::Slice slKey (CharCast (key.data ()), key.size ());
402
+ m_impl_iter->iter ->Seek (slKey);
403
+ }
404
+
405
+ Span<const std::byte> CDBIterator::GetKeyImpl () const
406
+ {
407
+ return MakeByteSpan (m_impl_iter->iter ->key ());
408
+ }
409
+
410
+ Span<const std::byte> CDBIterator::GetValueImpl () const
411
+ {
412
+ return MakeByteSpan (m_impl_iter->iter ->value ());
413
+ }
414
+
415
+ CDBIterator::~CDBIterator () = default ;
416
+ bool CDBIterator::Valid () const { return m_impl_iter->iter ->Valid (); }
417
+ void CDBIterator::SeekToFirst () { m_impl_iter->iter ->SeekToFirst (); }
418
+ void CDBIterator::Next () { m_impl_iter->iter ->Next (); }
419
+
420
+ namespace dbwrapper_private {
421
+
271
422
const std::vector<unsigned char >& GetObfuscateKey (const CDBWrapper &w)
272
423
{
273
424
return w.obfuscate_key ;
0 commit comments