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 55241 : explicit CDBBatch(int nVersion) : ssKey(SER_DISK, nVersion), ssValue(SER_DISK, nVersion), size_estimate(0){};
61 :
62 75 : void Clear()
63 : {
64 882 : batch.Clear();
65 882 : size_estimate = 0;
66 0 : }
67 :
68 : template <typename K, typename V>
69 1057498 : void Write(const K& key, const V& value)
70 : {
71 1057498 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
72 1057498 : ssKey << key;
73 1057498 : Write(ssKey, value);
74 1057498 : ssKey.clear();
75 1057498 : }
76 :
77 : template <typename V>
78 1066612 : void Write(const CDataStream& _ssKey, const V& value)
79 : {
80 1066612 : leveldb::Slice slKey(_ssKey.data(), _ssKey.size());
81 :
82 1066612 : ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE);
83 1066612 : ssValue << value;
84 1066612 : leveldb::Slice slValue(ssValue.data(), ssValue.size());
85 :
86 1066612 : 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 1066612 : size_estimate += 3 + (slKey.size() > 127) + slKey.size() + (slValue.size() > 127) + slValue.size();
96 1066612 : ssValue.clear();
97 1066612 : }
98 :
99 : template <typename K>
100 330403 : void Erase(const K& key)
101 : {
102 330403 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
103 330403 : ssKey << key;
104 330403 : Erase(ssKey);
105 330403 : ssKey.clear();
106 330403 : }
107 :
108 330403 : void Erase(const CDataStream& _ssKey)
109 : {
110 330403 : leveldb::Slice slKey(_ssKey.data(), _ssKey.size());
111 :
112 330403 : 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 330403 : size_estimate += 2 + (slKey.size() > 127) + slKey.size();
120 330403 : }
121 :
122 1025243 : 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 19608 : CDBIterator(leveldb::Iterator* _piter, int _nVersion) : piter(_piter), nVersion(_nVersion){};
137 : ~CDBIterator();
138 :
139 : bool Valid();
140 :
141 : void SeekToFirst();
142 :
143 9195 : template<typename K> void Seek(const K& key)
144 : {
145 9195 : CDataStream ssKey(SER_DISK, nVersion);
146 9195 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
147 9195 : ssKey << key;
148 9195 : Seek(ssKey);
149 9195 : }
150 :
151 19610 : void Seek(const CDataStream& ssKey)
152 : {
153 19610 : leveldb::Slice slKey(ssKey.data(), ssKey.size());
154 19610 : piter->Seek(slKey);
155 : }
156 :
157 : void Next();
158 :
159 6409881 : template<typename K> bool GetKey(K& key)
160 : {
161 : try {
162 6410625 : CDataStream ssKey = GetKey();
163 6409137 : ssKey >> key;
164 747 : } catch(const std::exception& e) {
165 : return false;
166 : }
167 6409137 : return true;
168 : }
169 :
170 6420155 : CDataStream GetKey()
171 : {
172 6420155 : leveldb::Slice slKey = piter->key();
173 6420155 : return CDataStream(slKey.data(), slKey.data() + slKey.size(), SER_DISK, nVersion);
174 : }
175 :
176 6404394 : template<typename V> bool GetValue(V& value)
177 : {
178 6404394 : leveldb::Slice slValue = piter->value();
179 : try {
180 6404394 : CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, nVersion);
181 6404394 : ssValue >> value;
182 0 : } catch(const std::exception& e) {
183 : return false;
184 : }
185 6404394 : 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 1721 : bool ReadDataStream(const K& key, CDataStream& ssValue) const
235 : {
236 1721 : CDataStream ssKey(SER_DISK, nVersion);
237 1721 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
238 1721 : ssKey << key;
239 1721 : return ReadDataStream(ssKey, ssValue);
240 : }
241 :
242 1702329 : bool ReadDataStream(const CDataStream& ssKey, CDataStream& ssValue) const
243 : {
244 1702329 : leveldb::Slice slKey(ssKey.data(), ssKey.size());
245 :
246 3404668 : std::string strValue;
247 3404668 : leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
248 1702329 : if (!status.ok()) {
249 969819 : if (status.IsNotFound())
250 : return false;
251 0 : LogPrintf("LevelDB read failure: %s\n", status.ToString());
252 0 : dbwrapper_private::HandleError(status);
253 : }
254 2434852 : CDataStream ssValueTmp(strValue.data(), strValue.data() + strValue.size(), SER_DISK, nVersion);
255 732515 : ssValue = std::move(ssValueTmp);
256 732515 : return true;
257 : }
258 :
259 : template <typename K, typename V>
260 1689406 : bool Read(const K& key, V& value) const
261 : {
262 1689406 : CDataStream ssKey(SER_DISK, nVersion);
263 1689406 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
264 1689406 : ssKey << key;
265 1689406 : return Read(ssKey, value);
266 : }
267 :
268 : template <typename V>
269 1700608 : bool Read(const CDataStream& ssKey, V& value) const
270 : {
271 3401226 : CDataStream ssValue(SER_DISK, nVersion);
272 1700608 : if (!ReadDataStream(ssKey, ssValue)) {
273 : return false;
274 : }
275 : try {
276 1699323 : 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 2128 : bool Write(const K& key, const V& value, bool fSync = false)
285 : {
286 4256 : CDBBatch batch(nVersion);
287 2128 : batch.Write(key, value);
288 4256 : return WriteBatch(batch, fSync);
289 : }
290 :
291 : template <typename K>
292 10753 : bool Exists(const K& key) const
293 : {
294 10753 : CDataStream ssKey(SER_DISK, nVersion);
295 10753 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
296 10753 : ssKey << key;
297 10753 : return Exists(ssKey);
298 : }
299 :
300 11252 : bool Exists(const CDataStream& key) const
301 : {
302 11252 : leveldb::Slice slKey(key.data(), key.size());
303 :
304 22504 : std::string strValue;
305 22504 : leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
306 11252 : if (!status.ok()) {
307 11242 : 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 19608 : CDBIterator* NewIterator()
339 : {
340 19608 : 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 10415 : 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 20830 : CDBTransactionIterator(CDBTransaction& _transaction, int _nVersion) : transaction(_transaction),
407 : parentKey(SER_DISK, _nVersion),
408 20830 : nVersion(_nVersion)
409 : {
410 20830 : transactionIt = transaction.writes.end();
411 20830 : parentIt = std::unique_ptr<ParentIterator>(transaction.parent.NewIterator());
412 20830 : }
413 :
414 : void SeekToFirst()
415 : {
416 : transactionIt = transaction.writes.begin();
417 : parentIt->SeekToFirst();
418 : SkipDeletedAndOverwritten();
419 : DecideCur();
420 : }
421 :
422 : template<typename K>
423 10415 : void Seek(const K& key)
424 : {
425 10415 : Seek(CDBTransaction::KeyToDataStream(key, nVersion));
426 10415 : }
427 :
428 20830 : void Seek(const CDataStream& ssKey)
429 : {
430 20830 : transactionIt = transaction.writes.lower_bound(ssKey);
431 20830 : parentIt->Seek(ssKey);
432 20830 : SkipDeletedAndOverwritten();
433 20830 : DecideCur();
434 20830 : }
435 :
436 52981 : bool Valid()
437 : {
438 133309 : return transactionIt != transaction.writes.end() || parentIt->Valid();
439 : }
440 :
441 25970 : void Next()
442 : {
443 25970 : if (transactionIt == transaction.writes.end() && !parentIt->Valid()) {
444 : return;
445 : }
446 25970 : if (curIsParent) {
447 12986 : assert(parentIt->Valid());
448 12986 : parentIt->Next();
449 12986 : SkipDeletedAndOverwritten();
450 : } else {
451 12984 : assert(transactionIt != transaction.writes.end());
452 12984 : ++transactionIt;
453 : }
454 25970 : DecideCur();
455 : }
456 :
457 : template<typename K>
458 33192 : bool GetKey(K& key)
459 : {
460 33192 : if (!Valid()) {
461 : return false;
462 : }
463 :
464 33192 : if (curIsParent) {
465 20208 : 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 12984 : CDataStream ssKey = transactionIt->first;
470 12984 : ssKey >> key;
471 0 : } catch (const std::exception&) {
472 : return false;
473 : }
474 12984 : return true;
475 : }
476 : }
477 :
478 19400 : CDataStream GetKey()
479 : {
480 19400 : if (!Valid()) {
481 0 : return CDataStream(SER_DISK, nVersion);
482 : }
483 19400 : if (curIsParent) {
484 3946 : return parentIt->GetKey();
485 : } else {
486 15454 : return transactionIt->first;
487 : }
488 : }
489 :
490 : template<typename V>
491 12985 : bool GetValue(V& value)
492 : {
493 12985 : if (!Valid()) {
494 : return false;
495 : }
496 12985 : if (curIsParent) {
497 12985 : return transaction.Read(parentKey, value);
498 : } else {
499 0 : return transaction.Read(transactionIt->first, value);
500 : }
501 : };
502 :
503 : private:
504 33816 : void SkipDeletedAndOverwritten()
505 : {
506 33816 : while (parentIt->Valid()) {
507 25730 : parentKey = parentIt->GetKey();
508 77190 : if (!transaction.deletes.count(parentKey) && !transaction.writes.count(parentKey)) {
509 : break;
510 : }
511 0 : parentIt->Next();
512 : }
513 33816 : }
514 :
515 46800 : void DecideCur()
516 : {
517 46800 : if (transactionIt != transaction.writes.end() && !parentIt->Valid()) {
518 2482 : curIsParent = false;
519 44318 : } else if (transactionIt == transaction.writes.end() && parentIt->Valid()) {
520 23346 : curIsParent = true;
521 20972 : } else if (transactionIt != transaction.writes.end() && parentIt->Valid()) {
522 12972 : if (CDBTransaction::DataStreamCmp::less(transactionIt->first, parentKey)) {
523 12972 : curIsParent = false;
524 : } else {
525 0 : curIsParent = true;
526 : }
527 : }
528 46800 : }
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 701928 : static bool less(const CDataStream& a, const CDataStream& b)
542 : {
543 701928 : return std::lexicographical_compare(
544 701928 : (const uint8_t*)a.data(), (const uint8_t*)a.data() + a.size(),
545 652173 : (const uint8_t*)b.data(), (const uint8_t*)b.data() + b.size());
546 : }
547 688956 : bool operator()(const CDataStream& a, const CDataStream& b) const { return less(a, b); }
548 : };
549 :
550 : struct ValueHolder {
551 : size_t memoryUsage;
552 102291 : 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 102291 : ValueHolderImpl(const V &_value, size_t _memoryUsage) : ValueHolder(_memoryUsage), value(_value) {}
561 :
562 59694 : 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 59694 : commitTarget.Write(ssKey, std::move(value));
567 59694 : }
568 : V value;
569 : };
570 :
571 : template <typename K>
572 131290 : static CDataStream KeyToDataStream(const K& key, int nVersion)
573 : {
574 131290 : CDataStream ssKey(SER_DISK, nVersion);
575 131290 : ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
576 131290 : ssKey << key;
577 131290 : 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 51711 : void Write(const K& key, const V& v)
592 : {
593 51711 : Write(KeyToDataStream(key, nVersion), v);
594 51711 : }
595 :
596 : template <typename V>
597 102291 : void Write(const CDataStream& ssKey, const V& v)
598 : {
599 102291 : auto valueMemoryUsage = ::GetSerializeSize(v, nVersion);
600 102291 : if (deletes.erase(ssKey)) {
601 0 : memoryUsage -= ssKey.size();
602 : }
603 102291 : auto it = writes.emplace(ssKey, nullptr).first;
604 102291 : if (it->second) {
605 42272 : memoryUsage -= ssKey.size() + it->second->memoryUsage;
606 : }
607 102291 : it->second = std::make_unique<ValueHolderImpl<V>>(v, valueMemoryUsage);
608 :
609 102291 : memoryUsage += ssKey.size() + valueMemoryUsage;
610 102291 : }
611 :
612 : template <typename K, typename V>
613 68477 : bool Read(const K& key, V& value)
614 : {
615 68477 : return Read(KeyToDataStream(key, nVersion), value);
616 : }
617 :
618 : template <typename V>
619 161931 : bool Read(const CDataStream& ssKey, V& value)
620 : {
621 161931 : if (deletes.count(ssKey)) {
622 0 : return false;
623 : }
624 :
625 161931 : auto it = writes.find(ssKey);
626 161931 : if (it != writes.end()) {
627 70260 : auto *impl = dynamic_cast<ValueHolderImpl<V> *>(it->second.get());
628 70260 : if (!impl) {
629 0 : throw std::runtime_error("Read called with V != previously written type");
630 : }
631 70260 : value = impl->value;
632 70260 : return true;
633 : }
634 :
635 91671 : return parent.Read(ssKey, value);
636 : }
637 :
638 : template <typename K>
639 687 : bool Exists(const K& key)
640 : {
641 687 : return Exists(KeyToDataStream(key, nVersion));
642 : }
643 :
644 1374 : bool Exists(const CDataStream& ssKey)
645 : {
646 1374 : if (deletes.count(ssKey)) {
647 0 : return false;
648 : }
649 :
650 1374 : if (writes.count(ssKey)) {
651 188 : return true;
652 : }
653 :
654 1186 : 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 58038 : void Clear()
676 : {
677 58038 : writes.clear();
678 58038 : deletes.clear();
679 58038 : memoryUsage = 0;
680 58038 : }
681 :
682 42704 : void Commit()
683 : {
684 42704 : for (const auto &k : deletes) {
685 0 : commitTarget.Erase(k);
686 : }
687 102398 : for (auto &p : writes) {
688 59694 : p.second->Write(p.first, commitTarget);
689 : }
690 42704 : Clear();
691 42704 : }
692 :
693 807 : bool IsClean()
694 : {
695 807 : return writes.empty() && deletes.empty();
696 : }
697 :
698 83793 : size_t GetMemoryUsage() const
699 : {
700 83793 : 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 83793 : return (size_t)memoryUsage;
710 : }
711 :
712 10415 : CDBTransactionIterator<CDBTransaction>* NewIterator()
713 : {
714 10415 : return new CDBTransactionIterator<CDBTransaction>(*this, nVersion);
715 : }
716 10415 : std::unique_ptr<CDBTransactionIterator<CDBTransaction>> NewIteratorUniquePtr()
717 : {
718 10415 : return std::make_unique<CDBTransactionIterator<CDBTransaction>>(*this, nVersion);
719 : }
720 : };
721 :
722 : #endif // PIVX_DBWRAPPER_H
|