Merge #12062: Increment MIT Licence copyright header year on files modified in 2017
[bitcoinplatinum.git] / src / dbwrapper.cpp
blob4e1e403f6989515a293706c2348249354a36f06f
1 // Copyright (c) 2012-2017 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.
5 #include <dbwrapper.h>
7 #include <random.h>
9 #include <leveldb/cache.h>
10 #include <leveldb/env.h>
11 #include <leveldb/filter_policy.h>
12 #include <memenv.h>
13 #include <stdint.h>
14 #include <algorithm>
16 class CBitcoinLevelDBLogger : public leveldb::Logger {
17 public:
18 // This code is adapted from posix_logger.h, which is why it is using vsprintf.
19 // Please do not do this in normal code
20 void Logv(const char * format, va_list ap) override {
21 if (!LogAcceptCategory(BCLog::LEVELDB)) {
22 return;
24 char buffer[500];
25 for (int iter = 0; iter < 2; iter++) {
26 char* base;
27 int bufsize;
28 if (iter == 0) {
29 bufsize = sizeof(buffer);
30 base = buffer;
32 else {
33 bufsize = 30000;
34 base = new char[bufsize];
36 char* p = base;
37 char* limit = base + bufsize;
39 // Print the message
40 if (p < limit) {
41 va_list backup_ap;
42 va_copy(backup_ap, ap);
43 // Do not use vsnprintf elsewhere in bitcoin source code, see above.
44 p += vsnprintf(p, limit - p, format, backup_ap);
45 va_end(backup_ap);
48 // Truncate to available space if necessary
49 if (p >= limit) {
50 if (iter == 0) {
51 continue; // Try again with larger buffer
53 else {
54 p = limit - 1;
58 // Add newline if necessary
59 if (p == base || p[-1] != '\n') {
60 *p++ = '\n';
63 assert(p <= limit);
64 base[std::min(bufsize - 1, (int)(p - base))] = '\0';
65 LogPrintf("leveldb: %s", base);
66 if (base != buffer) {
67 delete[] base;
69 break;
74 static leveldb::Options GetOptions(size_t nCacheSize)
76 leveldb::Options options;
77 options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
78 options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously
79 options.filter_policy = leveldb::NewBloomFilterPolicy(10);
80 options.compression = leveldb::kNoCompression;
81 options.max_open_files = 64;
82 options.info_log = new CBitcoinLevelDBLogger();
83 if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {
84 // LevelDB versions before 1.16 consider short writes to be corruption. Only trigger error
85 // on corruption in later versions.
86 options.paranoid_checks = true;
88 return options;
91 CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate)
93 penv = nullptr;
94 readoptions.verify_checksums = true;
95 iteroptions.verify_checksums = true;
96 iteroptions.fill_cache = false;
97 syncoptions.sync = true;
98 options = GetOptions(nCacheSize);
99 options.create_if_missing = true;
100 if (fMemory) {
101 penv = leveldb::NewMemEnv(leveldb::Env::Default());
102 options.env = penv;
103 } else {
104 if (fWipe) {
105 LogPrintf("Wiping LevelDB in %s\n", path.string());
106 leveldb::Status result = leveldb::DestroyDB(path.string(), options);
107 dbwrapper_private::HandleError(result);
109 TryCreateDirectories(path);
110 LogPrintf("Opening LevelDB in %s\n", path.string());
112 leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb);
113 dbwrapper_private::HandleError(status);
114 LogPrintf("Opened LevelDB successfully\n");
116 if (gArgs.GetBoolArg("-forcecompactdb", false)) {
117 LogPrintf("Starting database compaction of %s\n", path.string());
118 pdb->CompactRange(nullptr, nullptr);
119 LogPrintf("Finished database compaction of %s\n", path.string());
122 // The base-case obfuscation key, which is a noop.
123 obfuscate_key = std::vector<unsigned char>(OBFUSCATE_KEY_NUM_BYTES, '\000');
125 bool key_exists = Read(OBFUSCATE_KEY_KEY, obfuscate_key);
127 if (!key_exists && obfuscate && IsEmpty()) {
128 // Initialize non-degenerate obfuscation if it won't upset
129 // existing, non-obfuscated data.
130 std::vector<unsigned char> new_key = CreateObfuscateKey();
132 // Write `new_key` so we don't obfuscate the key with itself
133 Write(OBFUSCATE_KEY_KEY, new_key);
134 obfuscate_key = new_key;
136 LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string(), HexStr(obfuscate_key));
139 LogPrintf("Using obfuscation key for %s: %s\n", path.string(), HexStr(obfuscate_key));
142 CDBWrapper::~CDBWrapper()
144 delete pdb;
145 pdb = nullptr;
146 delete options.filter_policy;
147 options.filter_policy = nullptr;
148 delete options.info_log;
149 options.info_log = nullptr;
150 delete options.block_cache;
151 options.block_cache = nullptr;
152 delete penv;
153 options.env = nullptr;
156 bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync)
158 leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch);
159 dbwrapper_private::HandleError(status);
160 return true;
163 // Prefixed with null character to avoid collisions with other keys
165 // We must use a string constructor which specifies length so that we copy
166 // past the null-terminator.
167 const std::string CDBWrapper::OBFUSCATE_KEY_KEY("\000obfuscate_key", 14);
169 const unsigned int CDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8;
172 * Returns a string (consisting of 8 random bytes) suitable for use as an
173 * obfuscating XOR key.
175 std::vector<unsigned char> CDBWrapper::CreateObfuscateKey() const
177 unsigned char buff[OBFUSCATE_KEY_NUM_BYTES];
178 GetRandBytes(buff, OBFUSCATE_KEY_NUM_BYTES);
179 return std::vector<unsigned char>(&buff[0], &buff[OBFUSCATE_KEY_NUM_BYTES]);
183 bool CDBWrapper::IsEmpty()
185 std::unique_ptr<CDBIterator> it(NewIterator());
186 it->SeekToFirst();
187 return !(it->Valid());
190 CDBIterator::~CDBIterator() { delete piter; }
191 bool CDBIterator::Valid() const { return piter->Valid(); }
192 void CDBIterator::SeekToFirst() { piter->SeekToFirst(); }
193 void CDBIterator::Next() { piter->Next(); }
195 namespace dbwrapper_private {
197 void HandleError(const leveldb::Status& status)
199 if (status.ok())
200 return;
201 LogPrintf("%s\n", status.ToString());
202 if (status.IsCorruption())
203 throw dbwrapper_error("Database corrupted");
204 if (status.IsIOError())
205 throw dbwrapper_error("Database I/O error");
206 if (status.IsNotFound())
207 throw dbwrapper_error("Database entry missing");
208 throw dbwrapper_error("Unknown database error");
211 const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w)
213 return w.obfuscate_key;
216 } // namespace dbwrapper_private