LCOV - code coverage report
Current view: top level - src - dbwrapper.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 94 144 65.3 %
Date: 2020-09-26 01:30:44 Functions: 23 24 95.8 %

          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        6180 : 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        4071 :     void Logv(const char * format, va_list ap) override {
      22        4071 :             if (!LogAcceptCategory(BCLog::LEVELDB)) {
      23             :                 return;
      24             :             }
      25           0 :             char buffer[500];
      26           0 :             for (int iter = 0; iter < 2; iter++) {
      27           0 :                 char* base;
      28             :                 int bufsize;
      29           0 :                 if (iter == 0) {
      30             :                     bufsize = sizeof(buffer);
      31           0 :                     base = buffer;
      32           0 :                 }
      33             :                 else {
      34             :                     bufsize = 30000;
      35           0 :                     base = new char[bufsize];
      36             :                 }
      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             :                     }
      54             :                     else {
      55           0 :                         p = limit - 1;
      56             :                     }
      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             :                 }
      70           0 :                 break;
      71           0 :             }
      72        4071 :     }
      73             : };
      74             : 
      75        1236 : 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        1236 :     int default_open_files = options->max_open_files;
      91             : #ifndef WIN32
      92             :     if (sizeof(void*) < 8) {
      93             :         options->max_open_files = 64;
      94             :     }
      95             : #endif
      96        1236 :     LogPrint(BCLog::LEVELDB, "LevelDB using max_open_files=%d (default=%d)\n",
      97             :              options->max_open_files, default_open_files);
      98        1236 : }
      99             : 
     100        1236 : static leveldb::Options GetOptions(size_t nCacheSize)
     101             : {
     102        1236 :     leveldb::Options options;
     103        1236 :     options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
     104        1236 :     options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously
     105        1236 :     options.filter_policy = leveldb::NewBloomFilterPolicy(10);
     106        1236 :     options.compression = leveldb::kNoCompression;
     107        1236 :     options.info_log = new CBitcoinLevelDBLogger();
     108             :     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        1236 :         options.paranoid_checks = true;
     112             :     }
     113        1236 :     SetMaxOpenFiles(&options);
     114        1236 :     return options;
     115             : }
     116             : 
     117        1860 : CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate)
     118        1236 :     : m_name{path.stem().string()}
     119         624 : {
     120        1236 :     penv = nullptr;
     121        1236 :     readoptions.verify_checksums = true;
     122        1236 :     iteroptions.verify_checksums = true;
     123        1236 :     iteroptions.fill_cache = false;
     124        1236 :     syncoptions.sync = true;
     125        1236 :     options = GetOptions(nCacheSize);
     126        1236 :     options.create_if_missing = true;
     127        1236 :     if (fMemory) {
     128         223 :         penv = leveldb::NewMemEnv(leveldb::Env::Default());
     129         223 :         options.env = penv;
     130         223 :     } else {
     131        1013 :         if (fWipe) {
     132          21 :             LogPrintf("Wiping LevelDB in %s\n", path.string());
     133          21 :             leveldb::Status result = leveldb::DestroyDB(path.string(), options);
     134          21 :             dbwrapper_private::HandleError(result);
     135          21 :         }
     136        1013 :         TryCreateDirectories(path);
     137        1013 :         LogPrintf("Opening LevelDB in %s\n", path.string());
     138             :     }
     139        1236 :     leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb);
     140        1236 :     dbwrapper_private::HandleError(status);
     141        1236 :     LogPrintf("Opened LevelDB successfully\n");
     142             : 
     143        1236 :     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             :     }
     148             : 
     149             :     // The base-case obfuscation key, which is a noop.
     150        1236 :     obfuscate_key = std::vector<unsigned char>(OBFUSCATE_KEY_NUM_BYTES, '\000');
     151             : 
     152        1236 :     bool key_exists = Read(OBFUSCATE_KEY_KEY, obfuscate_key);
     153             : 
     154        1236 :     if (!key_exists && obfuscate && IsEmpty()) {
     155             :         // Initialize non-degenerate obfuscation if it won't upset
     156             :         // existing, non-obfuscated data.
     157         309 :         std::vector<unsigned char> new_key = CreateObfuscateKey();
     158             : 
     159             :         // Write `new_key` so we don't obfuscate the key with itself
     160         309 :         Write(OBFUSCATE_KEY_KEY, new_key);
     161         309 :         obfuscate_key = new_key;
     162             : 
     163         309 :         LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string(), HexStr(obfuscate_key));
     164         309 :     }
     165             : 
     166        1236 :     LogPrintf("Using obfuscation key for %s: %s\n", path.string(), HexStr(obfuscate_key));
     167        1860 : }
     168             : 
     169        1860 : CDBWrapper::~CDBWrapper()
     170         624 : {
     171        1236 :     delete pdb;
     172        1236 :     pdb = nullptr;
     173        1236 :     delete options.filter_policy;
     174        1236 :     options.filter_policy = nullptr;
     175        1236 :     delete options.info_log;
     176        1236 :     options.info_log = nullptr;
     177        1236 :     delete options.block_cache;
     178        1236 :     options.block_cache = nullptr;
     179        1236 :     delete penv;
     180        1236 :     options.env = nullptr;
     181        1860 : }
     182             : 
     183        8887 : bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync)
     184             : {
     185        8887 :     const bool log_memory = LogAcceptCategory(BCLog::LEVELDB);
     186        8887 :     double mem_before = 0;
     187        8887 :     if (log_memory) {
     188           0 :         mem_before = DynamicMemoryUsage() / 1024.0 / 1024;
     189           0 :     }
     190        8887 :     leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch);
     191        8887 :     dbwrapper_private::HandleError(status);
     192        8887 :     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             :                  m_name, mem_before, mem_after);
     196           0 :     }
     197             :     return true;
     198        8887 : }
     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             :     }
     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         640 : 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         309 : std::vector<unsigned char> CDBWrapper::CreateObfuscateKey() const
     222             : {
     223         309 :     unsigned char buff[OBFUSCATE_KEY_NUM_BYTES];
     224         309 :     GetRandBytes(buff, OBFUSCATE_KEY_NUM_BYTES);
     225         309 :     return std::vector<unsigned char>(&buff[0], &buff[OBFUSCATE_KEY_NUM_BYTES]);
     226             : 
     227         309 : }
     228             : 
     229         311 : bool CDBWrapper::IsEmpty()
     230             : {
     231         311 :     std::unique_ptr<CDBIterator> it(NewIterator());
     232         311 :     it->SeekToFirst();
     233         311 :     return !(it->Valid());
     234         311 : }
     235             : 
     236        3574 : CDBIterator::~CDBIterator() { delete piter; }
     237       65142 : bool CDBIterator::Valid() const { return piter->Valid(); }
     238         311 : void CDBIterator::SeekToFirst() { piter->SeekToFirst(); }
     239       62886 : void CDBIterator::Next() { piter->Next(); }
     240             : 
     241             : namespace dbwrapper_private {
     242             : 
     243       10144 : void HandleError(const leveldb::Status& status)
     244             : {
     245       10144 :     if (status.ok())
     246       10144 :         return;
     247           0 :     const std::string errmsg = "Fatal LevelDB error: " + status.ToString();
     248           0 :     LogPrintf("%s\n", errmsg);
     249           0 :     LogPrintf("You can use -debug=leveldb to get more complete diagnostic messages\n");
     250           0 :     throw dbwrapper_error(errmsg);
     251           0 : }
     252             : 
     253      257821 : const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w)
     254             : {
     255      257821 :     return w.obfuscate_key;
     256             : }
     257             : 
     258             : } // namespace dbwrapper_private

Generated by: LCOV version 1.15