Line data Source code
1 : // Copyright (c) 2012-2014 The Bitcoin 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 PIVX_DBWRAPPER_H
6 : #define PIVX_DBWRAPPER_H
7 :
8 : #include "clientversion.h"
9 : #include "fs.h"
10 : #include "serialize.h"
11 : #include "streams.h"
12 : #include "util/system.h"
13 : #include "version.h"
14 :
15 : #include <typeindex>
16 :
17 : #include <leveldb/db.h>
18 : #include <leveldb/write_batch.h>
19 :
20 :
21 : static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
22 : static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
23 :
24 :
25 : class dbwrapper_error : public std::runtime_error
26 : {
27 : public:
28 0 : explicit dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
29 : };
30 :
31 : class CDBWrapper;
32 :
33 : /** These should be considered an implementation detail of the specific database.
34 : */
35 : namespace dbwrapper_private {
36 :
37 : /** Handle database error by throwing dbwrapper_error exception.
38 : */
39 : void HandleError(const leveldb::Status& status);
40 :
41 : };
42 :
43 :
44 : /** Batch of changes queued to be written to a CDBWrapper */
45 : class CDBBatch
46 : {
47 : friend class CDBWrapper;
48 :
49 : private:
50 : leveldb::WriteBatch batch;
51 :
52 : CDataStream ssKey;
53 : CDataStream ssValue;
54 : size_t size_estimate;
55 :
56 : public:
57 : /**
58 : * @param[in] _nVersion The version used to serialize data.
59 : */
60 52925 : explicit CDBBatch(int nVersion) : ssKey(SER_DISK, nVersion), ssValue(SER_DISK, nVersion), size_estimate(0){};
61 :
62 27 : void Clear()
63 : {
64 829 : batch.Clear();
65 829 : size_estimate = 0;
66 0 : }
67 :
68 : template <typename K, typename V>
69 789215 : void Write(const K& key, const V& value)
70 : {
71 789215 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
72 789215 : ssKey << key;
73 789215 : Write(ssKey, value);
74 789215 : ssKey.clear();
75 789215 : }
76 :
77 : template <typename V>
78 798926 : void Write(const CDataStream& _ssKey, const V& value)
79 : {
80 798926 : leveldb::Slice slKey(_ssKey.data(), _ssKey.size());
81 :
82 798926 : ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE);
83 798926 : ssValue << value;
84 798926 : leveldb::Slice slValue(ssValue.data(), ssValue.size());
85 :
86 798926 : batch.Put(slKey, slValue);
87 :
88 : // LevelDB serializes writes as:
89 : // - byte: header
90 : // - varint: key length (1 byte up to 127B, 2 bytes up to 16383B, ...)
91 : // - byte[]: key
92 : // - varint: value length
93 : // - byte[]: value
94 : // The formula below assumes the key and value are both less than 16k.
95 798926 : size_estimate += 3 + (slKey.size() > 127) + slKey.size() + (slValue.size() > 127) + slValue.size();
96 798926 : ssValue.clear();
97 798926 : }
98 :
99 : template <typename K>
100 261491 : void Erase(const K& key)
101 : {
102 261491 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
103 261491 : ssKey << key;
104 261491 : Erase(ssKey);
105 261491 : ssKey.clear();
106 261491 : }
107 :
108 261491 : void Erase(const CDataStream& _ssKey)
109 : {
110 261491 : leveldb::Slice slKey(_ssKey.data(), _ssKey.size());
111 :
112 261491 : batch.Delete(slKey);
113 :
114 : // LevelDB serializes erases as:
115 : // - byte: header
116 : // - varint: key length
117 : // - byte[]: key
118 : // The formula below assumes the key is less than 16kB.
119 261491 : size_estimate += 2 + (slKey.size() > 127) + slKey.size();
120 261491 : }
121 :
122 735436 : size_t SizeEstimate() const { return size_estimate; }
123 : };
124 :
125 : class CDBIterator
126 : {
127 : private:
128 : leveldb::Iterator *piter;
129 : int nVersion;
130 :
131 : public:
132 : /**
133 : * @param[in] _piter The original leveldb iterator.
134 : * @param[in] _nVersion The version used to serialize data.
135 : */
136 16343 : CDBIterator(leveldb::Iterator* _piter, int _nVersion) : piter(_piter), nVersion(_nVersion){};
137 : ~CDBIterator();
138 :
139 : bool Valid();
140 :
141 : void SeekToFirst();
142 :
143 7883 : template<typename K> void Seek(const K& key)
144 : {
145 7883 : CDataStream ssKey(SER_DISK, nVersion);
146 7883 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
147 7883 : ssKey << key;
148 7883 : Seek(ssKey);
149 7883 : }
150 :
151 16345 : void Seek(const CDataStream& ssKey)
152 : {
153 16345 : leveldb::Slice slKey(ssKey.data(), ssKey.size());
154 16345 : piter->Seek(slKey);
155 : }
156 :
157 : void Next();
158 :
159 3273395 : template<typename K> bool GetKey(K& key)
160 : {
161 : try {
162 3274149 : CDataStream ssKey = GetKey();
163 3272641 : ssKey >> key;
164 753 : } catch(const std::exception& e) {
165 : return false;
166 : }
167 3272641 : return true;
168 : }
169 :
170 3280863 : CDataStream GetKey()
171 : {
172 3280863 : leveldb::Slice slKey = piter->key();
173 3280863 : return CDataStream(slKey.data(), slKey.data() + slKey.size(), SER_DISK, nVersion);
174 : }
175 :
176 3269109 : template<typename V> bool GetValue(V& value)
177 : {
178 3269109 : leveldb::Slice slValue = piter->value();
179 : try {
180 3269109 : CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, nVersion);
181 3269109 : ssValue >> value;
182 0 : } catch(const std::exception& e) {
183 : return false;
184 : }
185 3269109 : return true;
186 : }
187 :
188 0 : unsigned int GetValueSize()
189 : {
190 0 : return piter->value().size();
191 : }
192 :
193 : };
194 :
195 : class CDBWrapper
196 : {
197 : private:
198 : //! custom environment this database is using (may be nullptr in case of default environment)
199 : leveldb::Env* penv;
200 :
201 : //! database options used
202 : leveldb::Options options;
203 :
204 : //! options used when reading from the database
205 : leveldb::ReadOptions readoptions;
206 :
207 : //! options used when iterating over values of the database
208 : leveldb::ReadOptions iteroptions;
209 :
210 : //! options used when writing to the database
211 : leveldb::WriteOptions writeoptions;
212 :
213 : //! options used when sync writing to the database
214 : leveldb::WriteOptions syncoptions;
215 :
216 : //! the database itself
217 : leveldb::DB* pdb;
218 :
219 : //! the version used to serialize data
220 : int nVersion;
221 :
222 : public:
223 : /**
224 : * @param[in] path Location in the filesystem where leveldb data will be stored.
225 : * @param[in] nCacheSize Configures various leveldb cache settings.
226 : * @param[in] fMemory If true, use leveldb's memory environment.
227 : * @param[in] fWipe If true, remove all existing data.
228 : * @param[in] nVersion The version used to serialize data.
229 : */
230 : CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, int nVersion = CLIENT_VERSION);
231 : ~CDBWrapper();
232 :
233 : template <typename K>
234 879 : bool ReadDataStream(const K& key, CDataStream& ssValue) const
235 : {
236 879 : CDataStream ssKey(SER_DISK, nVersion);
237 879 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
238 879 : ssKey << key;
239 879 : return ReadDataStream(ssKey, ssValue);
240 : }
241 :
242 1574345 : bool ReadDataStream(const CDataStream& ssKey, CDataStream& ssValue) const
243 : {
244 1574345 : leveldb::Slice slKey(ssKey.data(), ssKey.size());
245 :
246 3148690 : std::string strValue;
247 3148690 : leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
248 1574345 : if (!status.ok()) {
249 1039622 : if (status.IsNotFound())
250 : return false;
251 0 : LogPrintf("LevelDB read failure: %s\n", status.ToString());
252 0 : dbwrapper_private::HandleError(status);
253 : }
254 2109068 : CDataStream ssValueTmp(strValue.data(), strValue.data() + strValue.size(), SER_DISK, nVersion);
255 534721 : ssValue = std::move(ssValueTmp);
256 534721 : return true;
257 : }
258 :
259 : template <typename K, typename V>
260 1561806 : bool Read(const K& key, V& value) const
261 : {
262 1561806 : CDataStream ssKey(SER_DISK, nVersion);
263 1561806 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
264 1561806 : ssKey << key;
265 1561806 : return Read(ssKey, value);
266 : }
267 :
268 : template <typename V>
269 1573470 : bool Read(const CDataStream& ssKey, V& value) const
270 : {
271 3146930 : CDataStream ssValue(SER_DISK, nVersion);
272 1573470 : if (!ReadDataStream(ssKey, ssValue)) {
273 : return false;
274 : }
275 : try {
276 1572163 : ssValue >> value;
277 0 : } catch (const std::exception&) {
278 : return false;
279 : }
280 487 : return true;
281 : }
282 :
283 : template <typename K, typename V>
284 2190 : bool Write(const K& key, const V& value, bool fSync = false)
285 : {
286 4380 : CDBBatch batch(nVersion);
287 2190 : batch.Write(key, value);
288 4380 : return WriteBatch(batch, fSync);
289 : }
290 :
291 : template <typename K>
292 7449 : bool Exists(const K& key) const
293 : {
294 7449 : CDataStream ssKey(SER_DISK, nVersion);
295 7449 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
296 7449 : ssKey << key;
297 7449 : return Exists(ssKey);
298 : }
299 :
300 7978 : bool Exists(const CDataStream& key) const
301 : {
302 7978 : leveldb::Slice slKey(key.data(), key.size());
303 :
304 15956 : std::string strValue;
305 15956 : leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
306 7978 : if (!status.ok()) {
307 7968 : if (status.IsNotFound())
308 : return false;
309 0 : LogPrintf("LevelDB read failure: %s\n", status.ToString());
310 0 : dbwrapper_private::HandleError(status);
311 : }
312 : return true;
313 : }
314 :
315 : template <typename K>
316 165 : bool Erase(const K& key, bool fSync = false)
317 : {
318 330 : CDBBatch batch(nVersion);
319 165 : batch.Erase(key);
320 330 : return WriteBatch(batch, fSync);
321 : }
322 :
323 : bool WriteBatch(CDBBatch& batch, bool fSync = false);
324 :
325 : // not available for LevelDB; provide for compatibility with BDB
326 : bool Flush()
327 : {
328 : return true;
329 : }
330 :
331 : bool Sync()
332 : {
333 : CDBBatch batch(nVersion);
334 : return WriteBatch(batch, true);
335 : }
336 :
337 : // not exactly clean encapsulation, but it's easiest for now
338 16343 : CDBIterator* NewIterator()
339 : {
340 16343 : return new CDBIterator(pdb->NewIterator(iteroptions), nVersion);
341 : }
342 :
343 : /**
344 : * Return true if the database managed by this class contains no entries.
345 : */
346 : bool IsEmpty();
347 :
348 : template<typename K>
349 49 : size_t EstimateSize(const K& key_begin, const K& key_end) const
350 : {
351 98 : CDataStream ssKey1(SER_DISK, nVersion), ssKey2(SER_DISK, nVersion);
352 49 : ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
353 49 : ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
354 49 : ssKey1 << key_begin;
355 49 : ssKey2 << key_end;
356 49 : leveldb::Slice slKey1(&ssKey1[0], ssKey1.size());
357 49 : leveldb::Slice slKey2(&ssKey2[0], ssKey2.size());
358 49 : uint64_t size = 0;
359 49 : leveldb::Range range(slKey1, slKey2);
360 49 : pdb->GetApproximateSizes(&range, 1, &size);
361 98 : return size;
362 : }
363 :
364 : /**
365 : * Compact a certain range of keys in the database.
366 : */
367 : template<typename K>
368 : void CompactRange(const K& key_begin, const K& key_end) const
369 : {
370 : CDataStream ssKey1(SER_DISK, nVersion), ssKey2(SER_DISK, nVersion);
371 : ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
372 : ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
373 : ssKey1 << key_begin;
374 : ssKey2 << key_end;
375 : leveldb::Slice slKey1(ssKey1.data(), ssKey1.size());
376 : leveldb::Slice slKey2(ssKey2.data(), ssKey2.size());
377 : pdb->CompactRange(&slKey1, &slKey2);
378 : }
379 :
380 : void CompactFull() const
381 : {
382 : pdb->CompactRange(nullptr, nullptr);
383 : }
384 :
385 : };
386 :
387 : template<typename CDBTransaction>
388 8462 : class CDBTransactionIterator
389 : {
390 : private:
391 : CDBTransaction& transaction;
392 :
393 : typedef typename std::remove_pointer<decltype(transaction.parent.NewIterator())>::type ParentIterator;
394 :
395 : // We maintain 2 iterators, one for the transaction and one for the parent
396 : // At all times, only one of both provides the current value. The decision is made by comparing the current keys
397 : // of both iterators, so that always the smaller key is the current one. On Next(), the previously chosen iterator
398 : // is advanced.
399 : typename CDBTransaction::WritesMap::iterator transactionIt;
400 : std::unique_ptr<ParentIterator> parentIt;
401 : CDataStream parentKey;
402 : int nVersion;
403 : bool curIsParent{false};
404 :
405 : public:
406 16924 : CDBTransactionIterator(CDBTransaction& _transaction, int _nVersion) : transaction(_transaction),
407 : parentKey(SER_DISK, _nVersion),
408 16924 : nVersion(_nVersion)
409 : {
410 16924 : transactionIt = transaction.writes.end();
411 16924 : parentIt = std::unique_ptr<ParentIterator>(transaction.parent.NewIterator());
412 16924 : }
413 :
414 : void SeekToFirst()
415 : {
416 : transactionIt = transaction.writes.begin();
417 : parentIt->SeekToFirst();
418 : SkipDeletedAndOverwritten();
419 : DecideCur();
420 : }
421 :
422 : template<typename K>
423 8462 : void Seek(const K& key)
424 : {
425 8462 : Seek(CDBTransaction::KeyToDataStream(key, nVersion));
426 8462 : }
427 :
428 16924 : void Seek(const CDataStream& ssKey)
429 : {
430 16924 : transactionIt = transaction.writes.lower_bound(ssKey);
431 16924 : parentIt->Seek(ssKey);
432 16924 : SkipDeletedAndOverwritten();
433 16924 : DecideCur();
434 16924 : }
435 :
436 47695 : bool Valid()
437 : {
438 118771 : return transactionIt != transaction.writes.end() || parentIt->Valid();
439 : }
440 :
441 24596 : void Next()
442 : {
443 24596 : if (transactionIt == transaction.writes.end() && !parentIt->Valid()) {
444 : return;
445 : }
446 24596 : if (curIsParent) {
447 12299 : assert(parentIt->Valid());
448 12299 : parentIt->Next();
449 12299 : SkipDeletedAndOverwritten();
450 : } else {
451 12297 : assert(transactionIt != transaction.writes.end());
452 12297 : ++transactionIt;
453 : }
454 24596 : DecideCur();
455 : }
456 :
457 : template<typename K>
458 29274 : bool GetKey(K& key)
459 : {
460 29274 : if (!Valid()) {
461 : return false;
462 : }
463 :
464 29274 : if (curIsParent) {
465 16977 : return parentIt->GetKey(key);
466 : } else {
467 : try {
468 : // TODO try to avoid this copy (we need a stream that allows reading from external buffers)
469 12297 : CDataStream ssKey = transactionIt->first;
470 12297 : ssKey >> key;
471 0 : } catch (const std::exception&) {
472 : return false;
473 : }
474 12297 : return true;
475 : }
476 : }
477 :
478 17606 : CDataStream GetKey()
479 : {
480 17606 : if (!Valid()) {
481 0 : return CDataStream(SER_DISK, nVersion);
482 : }
483 17606 : if (curIsParent) {
484 2620 : return parentIt->GetKey();
485 : } else {
486 14986 : return transactionIt->first;
487 : }
488 : }
489 :
490 : template<typename V>
491 12298 : bool GetValue(V& value)
492 : {
493 12298 : if (!Valid()) {
494 : return false;
495 : }
496 12298 : if (curIsParent) {
497 12298 : return transaction.Read(parentKey, value);
498 : } else {
499 0 : return transaction.Read(transactionIt->first, value);
500 : }
501 : };
502 :
503 : private:
504 29223 : void SkipDeletedAndOverwritten()
505 : {
506 29223 : while (parentIt->Valid()) {
507 22452 : parentKey = parentIt->GetKey();
508 67356 : if (!transaction.deletes.count(parentKey) && !transaction.writes.count(parentKey)) {
509 : break;
510 : }
511 0 : parentIt->Next();
512 : }
513 29223 : }
514 :
515 41520 : void DecideCur()
516 : {
517 41520 : if (transactionIt != transaction.writes.end() && !parentIt->Valid()) {
518 3380 : curIsParent = false;
519 38140 : } else if (transactionIt == transaction.writes.end() && parentIt->Valid()) {
520 20226 : curIsParent = true;
521 17914 : } else if (transactionIt != transaction.writes.end() && parentIt->Valid()) {
522 11606 : if (CDBTransaction::DataStreamCmp::less(transactionIt->first, parentKey)) {
523 11606 : curIsParent = false;
524 : } else {
525 0 : curIsParent = true;
526 : }
527 : }
528 41520 : }
529 : };
530 :
531 : template<typename Parent, typename CommitTarget>
532 : class CDBTransaction {
533 : friend class CDBTransactionIterator<CDBTransaction>;
534 :
535 : protected:
536 : Parent &parent;
537 : CommitTarget &commitTarget;
538 : ssize_t memoryUsage{0}; // signed, just in case we made an error in the calculations so that we don't get an overflow
539 :
540 : struct DataStreamCmp {
541 690526 : static bool less(const CDataStream& a, const CDataStream& b)
542 : {
543 690526 : return std::lexicographical_compare(
544 690526 : (const uint8_t*)a.data(), (const uint8_t*)a.data() + a.size(),
545 651600 : (const uint8_t*)b.data(), (const uint8_t*)b.data() + b.size());
546 : }
547 678920 : bool operator()(const CDataStream& a, const CDataStream& b) const { return less(a, b); }
548 : };
549 :
550 : struct ValueHolder {
551 : size_t memoryUsage;
552 104598 : ValueHolder(size_t _memoryUsage) : memoryUsage(_memoryUsage) {}
553 : virtual ~ValueHolder() = default;
554 : virtual void Write(const CDataStream& ssKey, CommitTarget &parent) = 0;
555 : };
556 : typedef std::unique_ptr<ValueHolder> ValueHolderPtr;
557 :
558 : template <typename V>
559 : struct ValueHolderImpl : ValueHolder {
560 104598 : ValueHolderImpl(const V &_value, size_t _memoryUsage) : ValueHolder(_memoryUsage), value(_value) {}
561 :
562 61436 : virtual void Write(const CDataStream& ssKey, CommitTarget &commitTarget)
563 : {
564 : // we're moving the value instead of copying it. This means that Write() can only be called once per
565 : // ValueHolderImpl instance. Commit() clears the write maps, so this ok.
566 61436 : commitTarget.Write(ssKey, std::move(value));
567 61436 : }
568 : V value;
569 : };
570 :
571 : template <typename K>
572 131720 : static CDataStream KeyToDataStream(const K& key, int nVersion)
573 : {
574 131720 : CDataStream ssKey(SER_DISK, nVersion);
575 131720 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
576 131720 : ssKey << key;
577 131720 : return ssKey;
578 : }
579 :
580 : typedef std::map<CDataStream, ValueHolderPtr, DataStreamCmp> WritesMap;
581 : typedef std::set<CDataStream, DataStreamCmp> DeletesSet;
582 :
583 : WritesMap writes;
584 : DeletesSet deletes;
585 : int nVersion;
586 :
587 : public:
588 772 : CDBTransaction(Parent& _parent, CommitTarget& _commitTarget, int _nVersion) : parent(_parent), commitTarget(_commitTarget), nVersion(_nVersion) {}
589 :
590 : template <typename K, typename V>
591 52873 : void Write(const K& key, const V& v)
592 : {
593 52873 : Write(KeyToDataStream(key, nVersion), v);
594 52873 : }
595 :
596 : template <typename V>
597 104598 : void Write(const CDataStream& ssKey, const V& v)
598 : {
599 104598 : auto valueMemoryUsage = ::GetSerializeSize(v, nVersion);
600 104598 : if (deletes.erase(ssKey)) {
601 0 : memoryUsage -= ssKey.size();
602 : }
603 104598 : auto it = writes.emplace(ssKey, nullptr).first;
604 104598 : if (it->second) {
605 42836 : memoryUsage -= ssKey.size() + it->second->memoryUsage;
606 : }
607 104598 : it->second = std::make_unique<ValueHolderImpl<V>>(v, valueMemoryUsage);
608 :
609 104598 : memoryUsage += ssKey.size() + valueMemoryUsage;
610 104598 : }
611 :
612 : template <typename K, typename V>
613 69634 : bool Read(const K& key, V& value)
614 : {
615 69634 : return Read(KeyToDataStream(key, nVersion), value);
616 : }
617 :
618 : template <typename V>
619 162855 : bool Read(const CDataStream& ssKey, V& value)
620 : {
621 162855 : if (deletes.count(ssKey)) {
622 0 : return false;
623 : }
624 :
625 162855 : auto it = writes.find(ssKey);
626 162855 : if (it != writes.end()) {
627 70268 : auto *impl = dynamic_cast<ValueHolderImpl<V> *>(it->second.get());
628 70268 : if (!impl) {
629 0 : throw std::runtime_error("Read called with V != previously written type");
630 : }
631 70268 : value = impl->value;
632 70268 : return true;
633 : }
634 :
635 92587 : return parent.Read(ssKey, value);
636 : }
637 :
638 : template <typename K>
639 751 : bool Exists(const K& key)
640 : {
641 751 : return Exists(KeyToDataStream(key, nVersion));
642 : }
643 :
644 1502 : bool Exists(const CDataStream& ssKey)
645 : {
646 1502 : if (deletes.count(ssKey)) {
647 0 : return false;
648 : }
649 :
650 1502 : if (writes.count(ssKey)) {
651 222 : return true;
652 : }
653 :
654 1280 : return parent.Exists(ssKey);
655 : }
656 :
657 : template <typename K>
658 0 : void Erase(const K& key)
659 : {
660 0 : return Erase(KeyToDataStream(key, nVersion));
661 : }
662 :
663 0 : void Erase(const CDataStream& ssKey)
664 : {
665 0 : auto it = writes.find(ssKey);
666 0 : if (it != writes.end()) {
667 0 : memoryUsage -= ssKey.size() + it->second->memoryUsage;
668 0 : writes.erase(it);
669 : }
670 0 : if (deletes.emplace(ssKey).second) {
671 0 : memoryUsage += ssKey.size();
672 : }
673 0 : }
674 :
675 58581 : void Clear()
676 : {
677 58581 : writes.clear();
678 58581 : deletes.clear();
679 58581 : memoryUsage = 0;
680 58581 : }
681 :
682 43244 : void Commit()
683 : {
684 43244 : for (const auto &k : deletes) {
685 0 : commitTarget.Erase(k);
686 : }
687 104680 : for (auto &p : writes) {
688 61436 : p.second->Write(p.first, commitTarget);
689 : }
690 43244 : Clear();
691 43244 : }
692 :
693 802 : bool IsClean()
694 : {
695 802 : return writes.empty() && deletes.empty();
696 : }
697 :
698 84883 : size_t GetMemoryUsage() const
699 : {
700 84883 : if (memoryUsage < 0) {
701 : // something went wrong when we accounted/calculated used memory...
702 : static volatile bool didPrint = false;
703 0 : if (!didPrint) {
704 0 : LogPrintf("CDBTransaction::%s -- negative memoryUsage (%d)", __func__, memoryUsage);
705 0 : didPrint = true;
706 : }
707 0 : return 0;
708 : }
709 84883 : return (size_t)memoryUsage;
710 : }
711 :
712 8462 : CDBTransactionIterator<CDBTransaction>* NewIterator()
713 : {
714 8462 : return new CDBTransactionIterator<CDBTransaction>(*this, nVersion);
715 : }
716 8462 : std::unique_ptr<CDBTransactionIterator<CDBTransaction>> NewIteratorUniquePtr()
717 : {
718 8462 : return std::make_unique<CDBTransactionIterator<CDBTransaction>>(*this, nVersion);
719 : }
720 : };
721 :
722 : #endif // PIVX_DBWRAPPER_H
|