Branch data Line data Source code
# 1 : : // Copyright (c) 2012-2021 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 : 6909 : void Logv(const char * format, va_list ap) override {
# 22 [ + - ]: 6909 : if (!LogAcceptCategory(BCLog::LEVELDB)) {
# 23 : 6909 : return;
# 24 : 6909 : }
# 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 : 2193 : 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 : 2193 : int default_open_files = options->max_open_files;
# 91 : 2193 : #ifndef WIN32
# 92 : 2193 : if (sizeof(void*) < 8) {
# 93 : 0 : options->max_open_files = 64;
# 94 : 0 : }
# 95 : 2193 : #endif
# 96 [ - + ]: 2193 : LogPrint(BCLog::LEVELDB, "LevelDB using max_open_files=%d (default=%d)\n",
# 97 : 2193 : options->max_open_files, default_open_files);
# 98 : 2193 : }
# 99 : :
# 100 : : static leveldb::Options GetOptions(size_t nCacheSize)
# 101 : 2193 : {
# 102 : 2193 : leveldb::Options options;
# 103 : 2193 : options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
# 104 : 2193 : options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously
# 105 : 2193 : options.filter_policy = leveldb::NewBloomFilterPolicy(10);
# 106 : 2193 : options.compression = leveldb::kNoCompression;
# 107 : 2193 : options.info_log = new CBitcoinLevelDBLogger();
# 108 : 2193 : 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 : 2193 : options.paranoid_checks = true;
# 112 : 2193 : }
# 113 : 2193 : SetMaxOpenFiles(&options);
# 114 : 2193 : return options;
# 115 : 2193 : }
# 116 : :
# 117 : : CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate)
# 118 : : : m_name{fs::PathToString(path.stem())}
# 119 : 2193 : {
# 120 : 2193 : penv = nullptr;
# 121 : 2193 : readoptions.verify_checksums = true;
# 122 : 2193 : iteroptions.verify_checksums = true;
# 123 : 2193 : iteroptions.fill_cache = false;
# 124 : 2193 : syncoptions.sync = true;
# 125 : 2193 : options = GetOptions(nCacheSize);
# 126 : 2193 : options.create_if_missing = true;
# 127 [ + + ]: 2193 : if (fMemory) {
# 128 : 651 : penv = leveldb::NewMemEnv(leveldb::Env::Default());
# 129 : 651 : options.env = penv;
# 130 : 1542 : } else {
# 131 [ + + ]: 1542 : if (fWipe) {
# 132 : 29 : LogPrintf("Wiping LevelDB in %s\n", fs::PathToString(path));
# 133 : 29 : leveldb::Status result = leveldb::DestroyDB(fs::PathToString(path), options);
# 134 : 29 : dbwrapper_private::HandleError(result);
# 135 : 29 : }
# 136 : 1542 : TryCreateDirectories(path);
# 137 : 1542 : LogPrintf("Opening LevelDB in %s\n", fs::PathToString(path));
# 138 : 1542 : }
# 139 : : // PathToString() return value is safe to pass to leveldb open function,
# 140 : : // because on POSIX leveldb passes the byte string directly to ::open(), and
# 141 : : // on Windows it converts from UTF-8 to UTF-16 before calling ::CreateFileW
# 142 : : // (see env_posix.cc and env_windows.cc).
# 143 : 2193 : leveldb::Status status = leveldb::DB::Open(options, fs::PathToString(path), &pdb);
# 144 : 2193 : dbwrapper_private::HandleError(status);
# 145 : 2193 : LogPrintf("Opened LevelDB successfully\n");
# 146 : :
# 147 [ - + ]: 2193 : if (gArgs.GetBoolArg("-forcecompactdb", false)) {
# 148 : 0 : LogPrintf("Starting database compaction of %s\n", fs::PathToString(path));
# 149 : 0 : pdb->CompactRange(nullptr, nullptr);
# 150 : 0 : LogPrintf("Finished database compaction of %s\n", fs::PathToString(path));
# 151 : 0 : }
# 152 : :
# 153 : : // The base-case obfuscation key, which is a noop.
# 154 : 2193 : obfuscate_key = std::vector<unsigned char>(OBFUSCATE_KEY_NUM_BYTES, '\000');
# 155 : :
# 156 : 2193 : bool key_exists = Read(OBFUSCATE_KEY_KEY, obfuscate_key);
# 157 : :
# 158 [ + + ][ + + ]: 2193 : if (!key_exists && obfuscate && IsEmpty()) {
# [ + + ]
# 159 : : // Initialize non-degenerate obfuscation if it won't upset
# 160 : : // existing, non-obfuscated data.
# 161 : 495 : std::vector<unsigned char> new_key = CreateObfuscateKey();
# 162 : :
# 163 : : // Write `new_key` so we don't obfuscate the key with itself
# 164 : 495 : Write(OBFUSCATE_KEY_KEY, new_key);
# 165 : 495 : obfuscate_key = new_key;
# 166 : :
# 167 : 495 : LogPrintf("Wrote new obfuscate key for %s: %s\n", fs::PathToString(path), HexStr(obfuscate_key));
# 168 : 495 : }
# 169 : :
# 170 : 2193 : LogPrintf("Using obfuscation key for %s: %s\n", fs::PathToString(path), HexStr(obfuscate_key));
# 171 : 2193 : }
# 172 : :
# 173 : : CDBWrapper::~CDBWrapper()
# 174 : 2191 : {
# 175 : 2191 : delete pdb;
# 176 : 2191 : pdb = nullptr;
# 177 : 2191 : delete options.filter_policy;
# 178 : 2191 : options.filter_policy = nullptr;
# 179 : 2191 : delete options.info_log;
# 180 : 2191 : options.info_log = nullptr;
# 181 : 2191 : delete options.block_cache;
# 182 : 2191 : options.block_cache = nullptr;
# 183 : 2191 : delete penv;
# 184 : 2191 : options.env = nullptr;
# 185 : 2191 : }
# 186 : :
# 187 : : bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync)
# 188 : 13678 : {
# 189 : 13678 : const bool log_memory = LogAcceptCategory(BCLog::LEVELDB);
# 190 : 13678 : double mem_before = 0;
# 191 [ - + ]: 13678 : if (log_memory) {
# 192 : 0 : mem_before = DynamicMemoryUsage() / 1024.0 / 1024;
# 193 : 0 : }
# 194 [ + + ]: 13678 : leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch);
# 195 : 13678 : dbwrapper_private::HandleError(status);
# 196 [ - + ]: 13678 : if (log_memory) {
# 197 : 0 : double mem_after = DynamicMemoryUsage() / 1024.0 / 1024;
# 198 [ # # ]: 0 : LogPrint(BCLog::LEVELDB, "WriteBatch memory usage: db=%s, before=%.1fMiB, after=%.1fMiB\n",
# 199 : 0 : m_name, mem_before, mem_after);
# 200 : 0 : }
# 201 : 13678 : return true;
# 202 : 13678 : }
# 203 : :
# 204 : : size_t CDBWrapper::DynamicMemoryUsage() const
# 205 : 0 : {
# 206 : 0 : std::string memory;
# 207 : 0 : std::optional<size_t> parsed;
# 208 [ # # ][ # # ]: 0 : if (!pdb->GetProperty("leveldb.approximate-memory-usage", &memory) || !(parsed = ToIntegral<size_t>(memory))) {
# [ # # ]
# 209 [ # # ]: 0 : LogPrint(BCLog::LEVELDB, "Failed to get approximate-memory-usage property\n");
# 210 : 0 : return 0;
# 211 : 0 : }
# 212 : 0 : return parsed.value();
# 213 : 0 : }
# 214 : :
# 215 : : // Prefixed with null character to avoid collisions with other keys
# 216 : : //
# 217 : : // We must use a string constructor which specifies length so that we copy
# 218 : : // past the null-terminator.
# 219 : : const std::string CDBWrapper::OBFUSCATE_KEY_KEY("\000obfuscate_key", 14);
# 220 : :
# 221 : : const unsigned int CDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8;
# 222 : :
# 223 : : /**
# 224 : : * Returns a string (consisting of 8 random bytes) suitable for use as an
# 225 : : * obfuscating XOR key.
# 226 : : */
# 227 : : std::vector<unsigned char> CDBWrapper::CreateObfuscateKey() const
# 228 : 495 : {
# 229 : 495 : std::vector<uint8_t> ret(OBFUSCATE_KEY_NUM_BYTES);
# 230 : 495 : GetRandBytes(ret.data(), OBFUSCATE_KEY_NUM_BYTES);
# 231 : 495 : return ret;
# 232 : 495 : }
# 233 : :
# 234 : : bool CDBWrapper::IsEmpty()
# 235 : 499 : {
# 236 : 499 : std::unique_ptr<CDBIterator> it(NewIterator());
# 237 : 499 : it->SeekToFirst();
# 238 : 499 : return !(it->Valid());
# 239 : 499 : }
# 240 : :
# 241 : 3379 : CDBIterator::~CDBIterator() { delete piter; }
# 242 : 102224 : bool CDBIterator::Valid() const { return piter->Valid(); }
# 243 : 499 : void CDBIterator::SeekToFirst() { piter->SeekToFirst(); }
# 244 : 97919 : void CDBIterator::Next() { piter->Next(); }
# 245 : :
# 246 : : namespace dbwrapper_private {
# 247 : :
# 248 : : void HandleError(const leveldb::Status& status)
# 249 : 15900 : {
# 250 [ + + ]: 15900 : if (status.ok())
# 251 : 15898 : return;
# 252 : 2 : const std::string errmsg = "Fatal LevelDB error: " + status.ToString();
# 253 : 2 : LogPrintf("%s\n", errmsg);
# 254 : 2 : LogPrintf("You can use -debug=leveldb to get more complete diagnostic messages\n");
# 255 : 2 : throw dbwrapper_error(errmsg);
# 256 : 15900 : }
# 257 : :
# 258 : : const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w)
# 259 : 420620 : {
# 260 : 420620 : return w.obfuscate_key;
# 261 : 420620 : }
# 262 : :
# 263 : : } // namespace dbwrapper_private
|