LCOV - code coverage report
Current view: top level - src - dbwrapper.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 233 267 87.3 %
Date: 2025-02-23 09:33:43 Functions: 214 236 90.7 %

          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

Generated by: LCOV version 1.14