LCOV - code coverage report
Current view: top level - src - dbwrapper.h (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 105 133 78.9 %
Date: 2021-06-29 14:35:33 Functions: 84 97 86.6 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 50 92 54.3 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2012-2020 The Bitcoin Core 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 BITCOIN_DBWRAPPER_H
#       6                 :            : #define BITCOIN_DBWRAPPER_H
#       7                 :            : 
#       8                 :            : #include <clientversion.h>
#       9                 :            : #include <fs.h>
#      10                 :            : #include <serialize.h>
#      11                 :            : #include <span.h>
#      12                 :            : #include <streams.h>
#      13                 :            : #include <util/strencodings.h>
#      14                 :            : #include <util/system.h>
#      15                 :            : 
#      16                 :            : #include <leveldb/db.h>
#      17                 :            : #include <leveldb/write_batch.h>
#      18                 :            : 
#      19                 :            : static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
#      20                 :            : static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
#      21                 :            : 
#      22                 :            : class dbwrapper_error : public std::runtime_error
#      23                 :            : {
#      24                 :            : public:
#      25                 :          0 :     explicit dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
#      26                 :            : };
#      27                 :            : 
#      28                 :            : class CDBWrapper;
#      29                 :            : 
#      30                 :            : /** These should be considered an implementation detail of the specific database.
#      31                 :            :  */
#      32                 :            : namespace dbwrapper_private {
#      33                 :            : 
#      34                 :            : /** Handle database error by throwing dbwrapper_error exception.
#      35                 :            :  */
#      36                 :            : void HandleError(const leveldb::Status& status);
#      37                 :            : 
#      38                 :            : /** Work around circular dependency, as well as for testing in dbwrapper_tests.
#      39                 :            :  * Database obfuscation should be considered an implementation detail of the
#      40                 :            :  * specific database.
#      41                 :            :  */
#      42                 :            : const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w);
#      43                 :            : 
#      44                 :            : };
#      45                 :            : 
#      46                 :            : /** Batch of changes queued to be written to a CDBWrapper */
#      47                 :            : class CDBBatch
#      48                 :            : {
#      49                 :            :     friend class CDBWrapper;
#      50                 :            : 
#      51                 :            : private:
#      52                 :            :     const CDBWrapper &parent;
#      53                 :            :     leveldb::WriteBatch batch;
#      54                 :            : 
#      55                 :            :     CDataStream ssKey;
#      56                 :            :     CDataStream ssValue;
#      57                 :            : 
#      58                 :            :     size_t size_estimate;
#      59                 :            : 
#      60                 :            : public:
#      61                 :            :     /**
#      62                 :            :      * @param[in] _parent   CDBWrapper that this batch is to be submitted to
#      63                 :            :      */
#      64                 :      12725 :     explicit CDBBatch(const CDBWrapper &_parent) : parent(_parent), ssKey(SER_DISK, CLIENT_VERSION), ssValue(SER_DISK, CLIENT_VERSION), size_estimate(0) { };
#      65                 :            : 
#      66                 :            :     void Clear()
#      67                 :          0 :     {
#      68                 :          0 :         batch.Clear();
#      69                 :          0 :         size_estimate = 0;
#      70                 :          0 :     }
#      71                 :            : 
#      72                 :            :     template <typename K, typename V>
#      73                 :            :     void Write(const K& key, const V& value)
#      74                 :     331523 :     {
#      75                 :     331523 :         ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
#      76                 :     331523 :         ssKey << key;
#      77                 :     331523 :         leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());
#      78                 :            : 
#      79                 :     331523 :         ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE);
#      80                 :     331523 :         ssValue << value;
#      81                 :     331523 :         ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent));
#      82                 :     331523 :         leveldb::Slice slValue((const char*)ssValue.data(), ssValue.size());
#      83                 :            : 
#      84                 :     331523 :         batch.Put(slKey, slValue);
#      85                 :            :         // LevelDB serializes writes as:
#      86                 :            :         // - byte: header
#      87                 :            :         // - varint: key length (1 byte up to 127B, 2 bytes up to 16383B, ...)
#      88                 :            :         // - byte[]: key
#      89                 :            :         // - varint: value length
#      90                 :            :         // - byte[]: value
#      91                 :            :         // The formula below assumes the key and value are both less than 16k.
#      92                 :     331523 :         size_estimate += 3 + (slKey.size() > 127) + slKey.size() + (slValue.size() > 127) + slValue.size();
#      93                 :     331523 :         ssKey.clear();
#      94                 :     331523 :         ssValue.clear();
#      95                 :     331523 :     }
#      96                 :            : 
#      97                 :            :     template <typename K>
#      98                 :            :     void Erase(const K& key)
#      99                 :      42094 :     {
#     100                 :      42094 :         ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
#     101                 :      42094 :         ssKey << key;
#     102                 :      42094 :         leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());
#     103                 :            : 
#     104                 :      42094 :         batch.Delete(slKey);
#     105                 :            :         // LevelDB serializes erases as:
#     106                 :            :         // - byte: header
#     107                 :            :         // - varint: key length
#     108                 :            :         // - byte[]: key
#     109                 :            :         // The formula below assumes the key is less than 16kB.
#     110                 :      42094 :         size_estimate += 2 + (slKey.size() > 127) + slKey.size();
#     111                 :      42094 :         ssKey.clear();
#     112                 :      42094 :     }
#     113                 :            : 
#     114                 :     399016 :     size_t SizeEstimate() const { return size_estimate; }
#     115                 :            : };
#     116                 :            : 
#     117                 :            : class CDBIterator
#     118                 :            : {
#     119                 :            : private:
#     120                 :            :     const CDBWrapper &parent;
#     121                 :            :     leveldb::Iterator *piter;
#     122                 :            : 
#     123                 :            : public:
#     124                 :            : 
#     125                 :            :     /**
#     126                 :            :      * @param[in] _parent          Parent CDBWrapper instance.
#     127                 :            :      * @param[in] _piter           The original leveldb iterator.
#     128                 :            :      */
#     129                 :            :     CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter) :
#     130                 :       2902 :         parent(_parent), piter(_piter) { };
#     131                 :            :     ~CDBIterator();
#     132                 :            : 
#     133                 :            :     bool Valid() const;
#     134                 :            : 
#     135                 :            :     void SeekToFirst();
#     136                 :            : 
#     137                 :       2474 :     template<typename K> void Seek(const K& key) {
#     138                 :       2474 :         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
#     139                 :       2474 :         ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
#     140                 :       2474 :         ssKey << key;
#     141                 :       2474 :         leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());
#     142                 :       2474 :         piter->Seek(slKey);
#     143                 :       2474 :     }
#     144                 :            : 
#     145                 :            :     void Next();
#     146                 :            : 
#     147                 :      80153 :     template<typename K> bool GetKey(K& key) {
#     148                 :      80153 :         leveldb::Slice slKey = piter->key();
#     149                 :      80153 :         try {
#     150                 :      80153 :             CDataStream ssKey(MakeUCharSpan(slKey), SER_DISK, CLIENT_VERSION);
#     151                 :      80153 :             ssKey >> key;
#     152                 :      80153 :         } catch (const std::exception&) {
#     153                 :        380 :             return false;
#     154                 :        380 :         }
#     155                 :      79773 :         return true;
#     156                 :      79773 :     }
#     157                 :            : 
#     158                 :      79122 :     template<typename V> bool GetValue(V& value) {
#     159                 :      79122 :         leveldb::Slice slValue = piter->value();
#     160                 :      79122 :         try {
#     161                 :      79122 :             CDataStream ssValue(MakeUCharSpan(slValue), SER_DISK, CLIENT_VERSION);
#     162                 :      79122 :             ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent));
#     163                 :      79122 :             ssValue >> value;
#     164                 :      79122 :         } catch (const std::exception&) {
#     165                 :          0 :             return false;
#     166                 :          0 :         }
#     167                 :      79122 :         return true;
#     168                 :      79122 :     }
#     169                 :            : 
#     170                 :          0 :     unsigned int GetValueSize() {
#     171                 :          0 :         return piter->value().size();
#     172                 :          0 :     }
#     173                 :            : 
#     174                 :            : };
#     175                 :            : 
#     176                 :            : class CDBWrapper
#     177                 :            : {
#     178                 :            :     friend const std::vector<unsigned char>& dbwrapper_private::GetObfuscateKey(const CDBWrapper &w);
#     179                 :            : private:
#     180                 :            :     //! custom environment this database is using (may be nullptr in case of default environment)
#     181                 :            :     leveldb::Env* penv;
#     182                 :            : 
#     183                 :            :     //! database options used
#     184                 :            :     leveldb::Options options;
#     185                 :            : 
#     186                 :            :     //! options used when reading from the database
#     187                 :            :     leveldb::ReadOptions readoptions;
#     188                 :            : 
#     189                 :            :     //! options used when iterating over values of the database
#     190                 :            :     leveldb::ReadOptions iteroptions;
#     191                 :            : 
#     192                 :            :     //! options used when writing to the database
#     193                 :            :     leveldb::WriteOptions writeoptions;
#     194                 :            : 
#     195                 :            :     //! options used when sync writing to the database
#     196                 :            :     leveldb::WriteOptions syncoptions;
#     197                 :            : 
#     198                 :            :     //! the database itself
#     199                 :            :     leveldb::DB* pdb;
#     200                 :            : 
#     201                 :            :     //! the name of this database
#     202                 :            :     std::string m_name;
#     203                 :            : 
#     204                 :            :     //! a key used for optional XOR-obfuscation of the database
#     205                 :            :     std::vector<unsigned char> obfuscate_key;
#     206                 :            : 
#     207                 :            :     //! the key under which the obfuscation key is stored
#     208                 :            :     static const std::string OBFUSCATE_KEY_KEY;
#     209                 :            : 
#     210                 :            :     //! the length of the obfuscate key in number of bytes
#     211                 :            :     static const unsigned int OBFUSCATE_KEY_NUM_BYTES;
#     212                 :            : 
#     213                 :            :     std::vector<unsigned char> CreateObfuscateKey() const;
#     214                 :            : 
#     215                 :            : public:
#     216                 :            :     /**
#     217                 :            :      * @param[in] path        Location in the filesystem where leveldb data will be stored.
#     218                 :            :      * @param[in] nCacheSize  Configures various leveldb cache settings.
#     219                 :            :      * @param[in] fMemory     If true, use leveldb's memory environment.
#     220                 :            :      * @param[in] fWipe       If true, remove all existing data.
#     221                 :            :      * @param[in] obfuscate   If true, store data obfuscated via simple XOR. If false, XOR
#     222                 :            :      *                        with a zero'd byte array.
#     223                 :            :      */
#     224                 :            :     CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false);
#     225                 :            :     ~CDBWrapper();
#     226                 :            : 
#     227                 :            :     CDBWrapper(const CDBWrapper&) = delete;
#     228                 :            :     CDBWrapper& operator=(const CDBWrapper&) = delete;
#     229                 :            : 
#     230                 :            :     template <typename K, typename V>
#     231                 :            :     bool Read(const K& key, V& value) const
#     232                 :    7879214 :     {
#     233                 :    7879214 :         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
#     234                 :    7879214 :         ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
#     235                 :    7879214 :         ssKey << key;
#     236                 :    7879214 :         leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());
#     237                 :            : 
#     238                 :    7879214 :         std::string strValue;
#     239                 :    7879214 :         leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
#     240 [ +  + ][ +  + ]:    7879214 :         if (!status.ok()) {
#         [ -  + ][ +  + ]
#         [ -  + ][ +  + ]
#         [ -  + ][ +  - ]
#         [ -  + ][ +  + ]
#         [ +  + ][ +  + ]
#         [ +  + ][ +  + ]
#         [ -  + ][ #  # ]
#         [ +  + ][ +  + ]
#         [ +  + ][ +  + ]
#     241 [ +  - ][ +  - ]:    7721251 :             if (status.IsNotFound())
#         [ +  - ][ +  - ]
#         [ #  # ][ #  # ]
#         [ +  - ][ +  - ]
#         [ +  - ][ +  - ]
#         [ #  # ][ +  - ]
#         [ #  # ][ +  - ]
#         [ #  # ][ +  - ]
#         [ #  # ][ +  - ]
#         [ +  - ][ +  - ]
#     242                 :    7721251 :                 return false;
#     243                 :          0 :             LogPrintf("LevelDB read failure: %s\n", status.ToString());
#     244                 :          0 :             dbwrapper_private::HandleError(status);
#     245                 :          0 :         }
#     246                 :    7879214 :         try {
#     247                 :     157963 :             CDataStream ssValue(MakeUCharSpan(strValue), SER_DISK, CLIENT_VERSION);
#     248                 :     157963 :             ssValue.Xor(obfuscate_key);
#     249                 :     157963 :             ssValue >> value;
#     250                 :     157963 :         } catch (const std::exception&) {
#     251                 :          0 :             return false;
#     252                 :          0 :         }
#     253                 :     157963 :         return true;
#     254                 :     157963 :     }
#     255                 :            : 
#     256                 :            :     template <typename K, typename V>
#     257                 :            :     bool Write(const K& key, const V& value, bool fSync = false)
#     258                 :       7654 :     {
#     259                 :       7654 :         CDBBatch batch(*this);
#     260                 :       7654 :         batch.Write(key, value);
#     261                 :       7654 :         return WriteBatch(batch, fSync);
#     262                 :       7654 :     }
#     263                 :            : 
#     264                 :            :     template <typename K>
#     265                 :            :     bool Exists(const K& key) const
#     266                 :        629 :     {
#     267                 :        629 :         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
#     268                 :        629 :         ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
#     269                 :        629 :         ssKey << key;
#     270                 :        629 :         leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());
#     271                 :            : 
#     272                 :        629 :         std::string strValue;
#     273                 :        629 :         leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
#     274 [ +  - ][ #  # ]:        629 :         if (!status.ok()) {
#                 [ +  - ]
#     275 [ +  - ][ #  # ]:        629 :             if (status.IsNotFound())
#                 [ +  - ]
#     276                 :        629 :                 return false;
#     277                 :          0 :             LogPrintf("LevelDB read failure: %s\n", status.ToString());
#     278                 :          0 :             dbwrapper_private::HandleError(status);
#     279                 :          0 :         }
#     280                 :        629 :         return true;
#     281                 :        629 :     }
#     282                 :            : 
#     283                 :            :     template <typename K>
#     284                 :            :     bool Erase(const K& key, bool fSync = false)
#     285                 :         10 :     {
#     286                 :         10 :         CDBBatch batch(*this);
#     287                 :         10 :         batch.Erase(key);
#     288                 :         10 :         return WriteBatch(batch, fSync);
#     289                 :         10 :     }
#     290                 :            : 
#     291                 :            :     bool WriteBatch(CDBBatch& batch, bool fSync = false);
#     292                 :            : 
#     293                 :            :     // Get an estimate of LevelDB memory usage (in bytes).
#     294                 :            :     size_t DynamicMemoryUsage() const;
#     295                 :            : 
#     296                 :            :     CDBIterator *NewIterator()
#     297                 :       2902 :     {
#     298                 :       2902 :         return new CDBIterator(*this, pdb->NewIterator(iteroptions));
#     299                 :       2902 :     }
#     300                 :            : 
#     301                 :            :     /**
#     302                 :            :      * Return true if the database managed by this class contains no entries.
#     303                 :            :      */
#     304                 :            :     bool IsEmpty();
#     305                 :            : 
#     306                 :            :     template<typename K>
#     307                 :            :     size_t EstimateSize(const K& key_begin, const K& key_end) const
#     308                 :         26 :     {
#     309                 :         26 :         CDataStream ssKey1(SER_DISK, CLIENT_VERSION), ssKey2(SER_DISK, CLIENT_VERSION);
#     310                 :         26 :         ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
#     311                 :         26 :         ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
#     312                 :         26 :         ssKey1 << key_begin;
#     313                 :         26 :         ssKey2 << key_end;
#     314                 :         26 :         leveldb::Slice slKey1((const char*)ssKey1.data(), ssKey1.size());
#     315                 :         26 :         leveldb::Slice slKey2((const char*)ssKey2.data(), ssKey2.size());
#     316                 :         26 :         uint64_t size = 0;
#     317                 :         26 :         leveldb::Range range(slKey1, slKey2);
#     318                 :         26 :         pdb->GetApproximateSizes(&range, 1, &size);
#     319                 :         26 :         return size;
#     320                 :         26 :     }
#     321                 :            : 
#     322                 :            :     /**
#     323                 :            :      * Compact a certain range of keys in the database.
#     324                 :            :      */
#     325                 :            :     template<typename K>
#     326                 :            :     void CompactRange(const K& key_begin, const K& key_end) const
#     327                 :          0 :     {
#     328                 :          0 :         CDataStream ssKey1(SER_DISK, CLIENT_VERSION), ssKey2(SER_DISK, CLIENT_VERSION);
#     329                 :          0 :         ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
#     330                 :          0 :         ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
#     331                 :          0 :         ssKey1 << key_begin;
#     332                 :          0 :         ssKey2 << key_end;
#     333                 :          0 :         leveldb::Slice slKey1((const char*)ssKey1.data(), ssKey1.size());
#     334                 :          0 :         leveldb::Slice slKey2((const char*)ssKey2.data(), ssKey2.size());
#     335                 :          0 :         pdb->CompactRange(&slKey1, &slKey2);
#     336                 :          0 :     }
#     337                 :            : };
#     338                 :            : 
#     339                 :            : #endif // BITCOIN_DBWRAPPER_H

Generated by: LCOV version 1.14