LCOV - code coverage report
Current view: top level - src - dbwrapper.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 100 165 60.6 %
Date: 2021-06-29 14:35:33 Functions: 14 15 93.3 %
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: 18 46 39.1 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2012-2019 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                 :            : #include <dbwrapper.h>
#       6                 :            : 
#       7                 :            : #include <memory>
#       8                 :            : #include <random.h>
#       9                 :            : 
#      10                 :            : #include <leveldb/cache.h>
#      11                 :            : #include <leveldb/env.h>
#      12                 :            : #include <leveldb/filter_policy.h>
#      13                 :            : #include <memenv.h>
#      14                 :            : #include <stdint.h>
#      15                 :            : #include <algorithm>
#      16                 :            : 
#      17                 :            : class CBitcoinLevelDBLogger : public leveldb::Logger {
#      18                 :            : public:
#      19                 :            :     // This code is adapted from posix_logger.h, which is why it is using vsprintf.
#      20                 :            :     // Please do not do this in normal code
#      21                 :       5266 :     void Logv(const char * format, va_list ap) override {
#      22         [ +  - ]:       5266 :             if (!LogAcceptCategory(BCLog::LEVELDB)) {
#      23                 :       5266 :                 return;
#      24                 :       5266 :             }
#      25                 :          0 :             char buffer[500];
#      26         [ #  # ]:          0 :             for (int iter = 0; iter < 2; iter++) {
#      27                 :          0 :                 char* base;
#      28                 :          0 :                 int bufsize;
#      29         [ #  # ]:          0 :                 if (iter == 0) {
#      30                 :          0 :                     bufsize = sizeof(buffer);
#      31                 :          0 :                     base = buffer;
#      32                 :          0 :                 }
#      33                 :          0 :                 else {
#      34                 :          0 :                     bufsize = 30000;
#      35                 :          0 :                     base = new char[bufsize];
#      36                 :          0 :                 }
#      37                 :          0 :                 char* p = base;
#      38                 :          0 :                 char* limit = base + bufsize;
#      39                 :            : 
#      40                 :            :                 // Print the message
#      41         [ #  # ]:          0 :                 if (p < limit) {
#      42                 :          0 :                     va_list backup_ap;
#      43                 :          0 :                     va_copy(backup_ap, ap);
#      44                 :            :                     // Do not use vsnprintf elsewhere in bitcoin source code, see above.
#      45                 :          0 :                     p += vsnprintf(p, limit - p, format, backup_ap);
#      46                 :          0 :                     va_end(backup_ap);
#      47                 :          0 :                 }
#      48                 :            : 
#      49                 :            :                 // Truncate to available space if necessary
#      50         [ #  # ]:          0 :                 if (p >= limit) {
#      51         [ #  # ]:          0 :                     if (iter == 0) {
#      52                 :          0 :                         continue;       // Try again with larger buffer
#      53                 :          0 :                     }
#      54                 :          0 :                     else {
#      55                 :          0 :                         p = limit - 1;
#      56                 :          0 :                     }
#      57                 :          0 :                 }
#      58                 :            : 
#      59                 :            :                 // Add newline if necessary
#      60 [ #  # ][ #  # ]:          0 :                 if (p == base || p[-1] != '\n') {
#      61                 :          0 :                     *p++ = '\n';
#      62                 :          0 :                 }
#      63                 :            : 
#      64                 :          0 :                 assert(p <= limit);
#      65                 :          0 :                 base[std::min(bufsize - 1, (int)(p - base))] = '\0';
#      66                 :          0 :                 LogPrintf("leveldb: %s", base);  /* Continued */
#      67         [ #  # ]:          0 :                 if (base != buffer) {
#      68                 :          0 :                     delete[] base;
#      69                 :          0 :                 }
#      70                 :          0 :                 break;
#      71                 :          0 :             }
#      72                 :          0 :     }
#      73                 :            : };
#      74                 :            : 
#      75                 :       1641 : static void SetMaxOpenFiles(leveldb::Options *options) {
#      76                 :            :     // On most platforms the default setting of max_open_files (which is 1000)
#      77                 :            :     // is optimal. On Windows using a large file count is OK because the handles
#      78                 :            :     // do not interfere with select() loops. On 64-bit Unix hosts this value is
#      79                 :            :     // also OK, because up to that amount LevelDB will use an mmap
#      80                 :            :     // implementation that does not use extra file descriptors (the fds are
#      81                 :            :     // closed after being mmap'ed).
#      82                 :            :     //
#      83                 :            :     // Increasing the value beyond the default is dangerous because LevelDB will
#      84                 :            :     // fall back to a non-mmap implementation when the file count is too large.
#      85                 :            :     // On 32-bit Unix host we should decrease the value because the handles use
#      86                 :            :     // up real fds, and we want to avoid fd exhaustion issues.
#      87                 :            :     //
#      88                 :            :     // See PR #12495 for further discussion.
#      89                 :            : 
#      90                 :       1641 :     int default_open_files = options->max_open_files;
#      91                 :       1641 : #ifndef WIN32
#      92                 :       1641 :     if (sizeof(void*) < 8) {
#      93                 :          0 :         options->max_open_files = 64;
#      94                 :          0 :     }
#      95                 :       1641 : #endif
#      96         [ -  + ]:       1641 :     LogPrint(BCLog::LEVELDB, "LevelDB using max_open_files=%d (default=%d)\n",
#      97                 :       1641 :              options->max_open_files, default_open_files);
#      98                 :       1641 : }
#      99                 :            : 
#     100                 :            : static leveldb::Options GetOptions(size_t nCacheSize)
#     101                 :       1641 : {
#     102                 :       1641 :     leveldb::Options options;
#     103                 :       1641 :     options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
#     104                 :       1641 :     options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously
#     105                 :       1641 :     options.filter_policy = leveldb::NewBloomFilterPolicy(10);
#     106                 :       1641 :     options.compression = leveldb::kNoCompression;
#     107                 :       1641 :     options.info_log = new CBitcoinLevelDBLogger();
#     108                 :       1641 :     if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {
#     109                 :            :         // LevelDB versions before 1.16 consider short writes to be corruption. Only trigger error
#     110                 :            :         // on corruption in later versions.
#     111                 :       1641 :         options.paranoid_checks = true;
#     112                 :       1641 :     }
#     113                 :       1641 :     SetMaxOpenFiles(&options);
#     114                 :       1641 :     return options;
#     115                 :       1641 : }
#     116                 :            : 
#     117                 :            : CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate)
#     118                 :            :     : m_name{path.stem().string()}
#     119                 :       1641 : {
#     120                 :       1641 :     penv = nullptr;
#     121                 :       1641 :     readoptions.verify_checksums = true;
#     122                 :       1641 :     iteroptions.verify_checksums = true;
#     123                 :       1641 :     iteroptions.fill_cache = false;
#     124                 :       1641 :     syncoptions.sync = true;
#     125                 :       1641 :     options = GetOptions(nCacheSize);
#     126                 :       1641 :     options.create_if_missing = true;
#     127         [ +  + ]:       1641 :     if (fMemory) {
#     128                 :        355 :         penv = leveldb::NewMemEnv(leveldb::Env::Default());
#     129                 :        355 :         options.env = penv;
#     130                 :       1286 :     } else {
#     131         [ +  + ]:       1286 :         if (fWipe) {
#     132                 :         29 :             LogPrintf("Wiping LevelDB in %s\n", path.string());
#     133                 :         29 :             leveldb::Status result = leveldb::DestroyDB(path.string(), options);
#     134                 :         29 :             dbwrapper_private::HandleError(result);
#     135                 :         29 :         }
#     136                 :       1286 :         TryCreateDirectories(path);
#     137                 :       1286 :         LogPrintf("Opening LevelDB in %s\n", path.string());
#     138                 :       1286 :     }
#     139                 :       1641 :     leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb);
#     140                 :       1641 :     dbwrapper_private::HandleError(status);
#     141                 :       1641 :     LogPrintf("Opened LevelDB successfully\n");
#     142                 :            : 
#     143         [ -  + ]:       1641 :     if (gArgs.GetBoolArg("-forcecompactdb", false)) {
#     144                 :          0 :         LogPrintf("Starting database compaction of %s\n", path.string());
#     145                 :          0 :         pdb->CompactRange(nullptr, nullptr);
#     146                 :          0 :         LogPrintf("Finished database compaction of %s\n", path.string());
#     147                 :          0 :     }
#     148                 :            : 
#     149                 :            :     // The base-case obfuscation key, which is a noop.
#     150                 :       1641 :     obfuscate_key = std::vector<unsigned char>(OBFUSCATE_KEY_NUM_BYTES, '\000');
#     151                 :            : 
#     152                 :       1641 :     bool key_exists = Read(OBFUSCATE_KEY_KEY, obfuscate_key);
#     153                 :            : 
#     154 [ +  + ][ +  + ]:       1641 :     if (!key_exists && obfuscate && IsEmpty()) {
#                 [ +  + ]
#     155                 :            :         // Initialize non-degenerate obfuscation if it won't upset
#     156                 :            :         // existing, non-obfuscated data.
#     157                 :        428 :         std::vector<unsigned char> new_key = CreateObfuscateKey();
#     158                 :            : 
#     159                 :            :         // Write `new_key` so we don't obfuscate the key with itself
#     160                 :        428 :         Write(OBFUSCATE_KEY_KEY, new_key);
#     161                 :        428 :         obfuscate_key = new_key;
#     162                 :            : 
#     163                 :        428 :         LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string(), HexStr(obfuscate_key));
#     164                 :        428 :     }
#     165                 :            : 
#     166                 :       1641 :     LogPrintf("Using obfuscation key for %s: %s\n", path.string(), HexStr(obfuscate_key));
#     167                 :       1641 : }
#     168                 :            : 
#     169                 :            : CDBWrapper::~CDBWrapper()
#     170                 :       1641 : {
#     171                 :       1641 :     delete pdb;
#     172                 :       1641 :     pdb = nullptr;
#     173                 :       1641 :     delete options.filter_policy;
#     174                 :       1641 :     options.filter_policy = nullptr;
#     175                 :       1641 :     delete options.info_log;
#     176                 :       1641 :     options.info_log = nullptr;
#     177                 :       1641 :     delete options.block_cache;
#     178                 :       1641 :     options.block_cache = nullptr;
#     179                 :       1641 :     delete penv;
#     180                 :       1641 :     options.env = nullptr;
#     181                 :       1641 : }
#     182                 :            : 
#     183                 :            : bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync)
#     184                 :      12725 : {
#     185                 :      12725 :     const bool log_memory = LogAcceptCategory(BCLog::LEVELDB);
#     186                 :      12725 :     double mem_before = 0;
#     187         [ -  + ]:      12725 :     if (log_memory) {
#     188                 :          0 :         mem_before = DynamicMemoryUsage() / 1024.0 / 1024;
#     189                 :          0 :     }
#     190         [ +  + ]:      12725 :     leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch);
#     191                 :      12725 :     dbwrapper_private::HandleError(status);
#     192         [ -  + ]:      12725 :     if (log_memory) {
#     193                 :          0 :         double mem_after = DynamicMemoryUsage() / 1024.0 / 1024;
#     194         [ #  # ]:          0 :         LogPrint(BCLog::LEVELDB, "WriteBatch memory usage: db=%s, before=%.1fMiB, after=%.1fMiB\n",
#     195                 :          0 :                  m_name, mem_before, mem_after);
#     196                 :          0 :     }
#     197                 :      12725 :     return true;
#     198                 :      12725 : }
#     199                 :            : 
#     200                 :          0 : size_t CDBWrapper::DynamicMemoryUsage() const {
#     201                 :          0 :     std::string memory;
#     202         [ #  # ]:          0 :     if (!pdb->GetProperty("leveldb.approximate-memory-usage", &memory)) {
#     203         [ #  # ]:          0 :         LogPrint(BCLog::LEVELDB, "Failed to get approximate-memory-usage property\n");
#     204                 :          0 :         return 0;
#     205                 :          0 :     }
#     206                 :          0 :     return stoul(memory);
#     207                 :          0 : }
#     208                 :            : 
#     209                 :            : // Prefixed with null character to avoid collisions with other keys
#     210                 :            : //
#     211                 :            : // We must use a string constructor which specifies length so that we copy
#     212                 :            : // past the null-terminator.
#     213                 :            : const std::string CDBWrapper::OBFUSCATE_KEY_KEY("\000obfuscate_key", 14);
#     214                 :            : 
#     215                 :            : const unsigned int CDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8;
#     216                 :            : 
#     217                 :            : /**
#     218                 :            :  * Returns a string (consisting of 8 random bytes) suitable for use as an
#     219                 :            :  * obfuscating XOR key.
#     220                 :            :  */
#     221                 :            : std::vector<unsigned char> CDBWrapper::CreateObfuscateKey() const
#     222                 :        428 : {
#     223                 :        428 :     std::vector<uint8_t> ret(OBFUSCATE_KEY_NUM_BYTES);
#     224                 :        428 :     GetRandBytes(ret.data(), OBFUSCATE_KEY_NUM_BYTES);
#     225                 :        428 :     return ret;
#     226                 :        428 : }
#     227                 :            : 
#     228                 :            : bool CDBWrapper::IsEmpty()
#     229                 :        432 : {
#     230                 :        432 :     std::unique_ptr<CDBIterator> it(NewIterator());
#     231                 :        432 :     it->SeekToFirst();
#     232                 :        432 :     return !(it->Valid());
#     233                 :        432 : }
#     234                 :            : 
#     235                 :       2902 : CDBIterator::~CDBIterator() { delete piter; }
#     236                 :      82953 : bool CDBIterator::Valid() const { return piter->Valid(); }
#     237                 :        432 : void CDBIterator::SeekToFirst() { piter->SeekToFirst(); }
#     238                 :      79122 : void CDBIterator::Next() { piter->Next(); }
#     239                 :            : 
#     240                 :            : namespace dbwrapper_private {
#     241                 :            : 
#     242                 :            : void HandleError(const leveldb::Status& status)
#     243                 :      14395 : {
#     244         [ +  - ]:      14395 :     if (status.ok())
#     245                 :      14395 :         return;
#     246                 :          0 :     const std::string errmsg = "Fatal LevelDB error: " + status.ToString();
#     247                 :          0 :     LogPrintf("%s\n", errmsg);
#     248                 :          0 :     LogPrintf("You can use -debug=leveldb to get more complete diagnostic messages\n");
#     249                 :          0 :     throw dbwrapper_error(errmsg);
#     250                 :          0 : }
#     251                 :            : 
#     252                 :            : const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w)
#     253                 :     410657 : {
#     254                 :     410657 :     return w.obfuscate_key;
#     255                 :     410657 : }
#     256                 :            : 
#     257                 :            : } // namespace dbwrapper_private

Generated by: LCOV version 1.14