44
55#include < dbwrapper.h>
66
7+ #include < clientversion.h>
78#include < logging.h>
89#include < random.h>
9- #include < tinyformat.h>
10+ #include < serialize.h>
11+ #include < span.h>
12+ #include < streams.h>
1013#include < util/fs.h>
1114#include < util/fs_helpers.h>
1215#include < util/strencodings.h>
2326#include < leveldb/helpers/memenv/memenv.h>
2427#include < leveldb/iterator.h>
2528#include < leveldb/options.h>
29+ #include < leveldb/slice.h>
2630#include < leveldb/status.h>
31+ #include < leveldb/write_batch.h>
2732#include < memory>
2833#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+ }
2954
3055class CBitcoinLevelDBLogger : public leveldb ::Logger {
3156public:
@@ -127,24 +152,91 @@ static leveldb::Options GetOptions(size_t nCacheSize)
127152 return options;
128153}
129154
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+
130222CDBWrapper::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 }
132224{
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 ;
140232 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 ;
143235 } else {
144236 if (params.wipe_data ) {
145237 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);
148240 }
149241 TryCreateDirectories (params.path );
150242 LogPrintf (" Opening LevelDB in %s\n " , fs::PathToString (params.path ));
@@ -153,13 +245,13 @@ CDBWrapper::CDBWrapper(const DBParams& params)
153245 // because on POSIX leveldb passes the byte string directly to ::open(), and
154246 // on Windows it converts from UTF-8 to UTF-16 before calling ::CreateFileW
155247 // (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);
158250 LogPrintf (" Opened LevelDB successfully\n " );
159251
160252 if (params.options .force_compact ) {
161253 LogPrintf (" Starting database compaction of %s\n " , fs::PathToString (params.path ));
162- pdb->CompactRange (nullptr , nullptr );
254+ DBContext (). pdb ->CompactRange (nullptr , nullptr );
163255 LogPrintf (" Finished database compaction of %s\n " , fs::PathToString (params.path ));
164256 }
165257
@@ -185,16 +277,16 @@ CDBWrapper::CDBWrapper(const DBParams& params)
185277
186278CDBWrapper::~CDBWrapper ()
187279{
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 ;
198290}
199291
200292bool CDBWrapper::WriteBatch (CDBBatch& batch, bool fSync )
@@ -204,8 +296,8 @@ bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync)
204296 if (log_memory) {
205297 mem_before = DynamicMemoryUsage () / 1024.0 / 1024 ;
206298 }
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);
209301 if (log_memory) {
210302 double mem_after = DynamicMemoryUsage () / 1024.0 / 1024 ;
211303 LogPrint (BCLog::LEVELDB, " WriteBatch memory usage: db=%s, before=%.1fMiB, after=%.1fMiB\n " ,
@@ -218,7 +310,7 @@ size_t CDBWrapper::DynamicMemoryUsage() const
218310{
219311 std::string memory;
220312 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))) {
222314 LogPrint (BCLog::LEVELDB, " Failed to get approximate-memory-usage property\n " );
223315 return 0 ;
224316 }
@@ -244,30 +336,89 @@ std::vector<unsigned char> CDBWrapper::CreateObfuscateKey() const
244336 return ret;
245337}
246338
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+
247378bool CDBWrapper::IsEmpty ()
248379{
249380 std::unique_ptr<CDBIterator> it (NewIterator ());
250381 it->SeekToFirst ();
251382 return !(it->Valid ());
252383}
253384
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;
258387
259- namespace dbwrapper_private {
388+ explicit IteratorImpl (leveldb::Iterator* _iter) : iter{_iter} {}
389+ };
260390
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 ()
262395{
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 ))};
269397}
270398
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+
271422const std::vector<unsigned char >& GetObfuscateKey (const CDBWrapper &w)
272423{
273424 return w.obfuscate_key ;
0 commit comments