Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/db.cpp
Show First 20 Lines • Show All 332 Lines • ▼ Show 20 Lines | |||||
u_int32_t BerkeleyBatch::SafeDbt::get_size() const { | u_int32_t BerkeleyBatch::SafeDbt::get_size() const { | ||||
return m_dbt.get_size(); | return m_dbt.get_size(); | ||||
} | } | ||||
BerkeleyBatch::SafeDbt::operator Dbt *() { | BerkeleyBatch::SafeDbt::operator Dbt *() { | ||||
return &m_dbt; | return &m_dbt; | ||||
} | } | ||||
/* End of headers, beginning of key/value data */ | |||||
static const char *HEADER_END = "HEADER=END"; | |||||
/* End of key/value data */ | |||||
static const char *DATA_END = "DATA=END"; | |||||
typedef std::pair<std::vector<uint8_t>, std::vector<uint8_t>> KeyValPair; | |||||
bool BerkeleyBatch::Recover(const fs::path &file_path, void *callbackDataIn, | bool BerkeleyBatch::Recover(const fs::path &file_path, void *callbackDataIn, | ||||
bool (*recoverKVcallback)(void *callbackData, | bool (*recoverKVcallback)(void *callbackData, | ||||
CDataStream ssKey, | CDataStream ssKey, | ||||
CDataStream ssValue), | CDataStream ssValue), | ||||
std::string &newFilename) { | std::string &newFilename) { | ||||
std::string filename; | std::string filename; | ||||
std::shared_ptr<BerkeleyEnvironment> env = | std::shared_ptr<BerkeleyEnvironment> env = | ||||
GetWalletEnv(file_path, filename); | GetWalletEnv(file_path, filename); | ||||
Show All 10 Lines | int result = env->dbenv->dbrename(nullptr, filename.c_str(), nullptr, | ||||
newFilename.c_str(), DB_AUTO_COMMIT); | newFilename.c_str(), DB_AUTO_COMMIT); | ||||
if (result == 0) { | if (result == 0) { | ||||
LogPrintf("Renamed %s to %s\n", filename, newFilename); | LogPrintf("Renamed %s to %s\n", filename, newFilename); | ||||
} else { | } else { | ||||
LogPrintf("Failed to rename %s to %s\n", filename, newFilename); | LogPrintf("Failed to rename %s to %s\n", filename, newFilename); | ||||
return false; | return false; | ||||
} | } | ||||
std::vector<BerkeleyEnvironment::KeyValPair> salvagedData; | /** | ||||
bool fSuccess = env->Salvage(newFilename, salvagedData); | * Salvage data from a file. The DB_AGGRESSIVE flag is being used (see | ||||
* berkeley DB->verify() method documentation). key/value pairs are appended | |||||
* to salvagedData which are then written out to a new wallet file. NOTE: | |||||
* reads the entire database into memory, so cannot be used for huge | |||||
* databases. | |||||
*/ | |||||
std::vector<KeyValPair> salvagedData; | |||||
std::stringstream strDump; | |||||
Db db(env->dbenv.get(), 0); | |||||
result = db.verify(newFilename.c_str(), nullptr, &strDump, | |||||
DB_SALVAGE | DB_AGGRESSIVE); | |||||
if (result == DB_VERIFY_BAD) { | |||||
LogPrintf("Salvage: Database salvage found " | |||||
"errors, all data may not be recoverable.\n"); | |||||
} | |||||
if (result != 0 && result != DB_VERIFY_BAD) { | |||||
LogPrintf("Salvage: Database salvage failed with " | |||||
"result %d.\n", | |||||
result); | |||||
return false; | |||||
} | |||||
// Format of bdb dump is ascii lines: | |||||
// header lines... | |||||
// HEADER=END | |||||
// hexadecimal key | |||||
// hexadecimal value | |||||
// ... repeated | |||||
// DATA=END | |||||
std::string strLine; | |||||
while (!strDump.eof() && strLine != HEADER_END) { | |||||
// Skip past header | |||||
getline(strDump, strLine); | |||||
} | |||||
std::string keyHex, valueHex; | |||||
while (!strDump.eof() && keyHex != DATA_END) { | |||||
getline(strDump, keyHex); | |||||
if (keyHex != DATA_END) { | |||||
if (strDump.eof()) { | |||||
break; | |||||
} | |||||
getline(strDump, valueHex); | |||||
if (valueHex == DATA_END) { | |||||
LogPrintf("Salvage: WARNING: Number of " | |||||
"keys in data does not match number of values.\n"); | |||||
break; | |||||
} | |||||
salvagedData.push_back( | |||||
make_pair(ParseHex(keyHex), ParseHex(valueHex))); | |||||
} | |||||
} | |||||
bool fSuccess; | |||||
if (keyHex != DATA_END) { | |||||
LogPrintf("Salvage: WARNING: Unexpected end of " | |||||
"file while reading salvage output.\n"); | |||||
fSuccess = false; | |||||
} else { | |||||
fSuccess = (result == 0); | |||||
} | |||||
if (salvagedData.empty()) { | if (salvagedData.empty()) { | ||||
LogPrintf("Salvage(aggressive) found no records in %s.\n", newFilename); | LogPrintf("Salvage(aggressive) found no records in %s.\n", newFilename); | ||||
return false; | return false; | ||||
} | } | ||||
LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size()); | LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size()); | ||||
std::unique_ptr<Db> pdbCopy = std::make_unique<Db>(env->dbenv.get(), 0); | std::unique_ptr<Db> pdbCopy = std::make_unique<Db>(env->dbenv.get(), 0); | ||||
int ret = pdbCopy->open(nullptr, // Txn pointer | int ret = pdbCopy->open(nullptr, // Txn pointer | ||||
filename.c_str(), // Filename | filename.c_str(), // Filename | ||||
"main", // Logical db name | "main", // Logical db name | ||||
DB_BTREE, // Database type | DB_BTREE, // Database type | ||||
DB_CREATE, // Flags | DB_CREATE, // Flags | ||||
0); | 0); | ||||
if (ret > 0) { | if (ret > 0) { | ||||
LogPrintf("Cannot create database file %s\n", filename); | LogPrintf("Cannot create database file %s\n", filename); | ||||
pdbCopy->close(0); | pdbCopy->close(0); | ||||
return false; | return false; | ||||
} | } | ||||
DbTxn *ptxn = env->TxnBegin(); | DbTxn *ptxn = env->TxnBegin(); | ||||
for (BerkeleyEnvironment::KeyValPair &row : salvagedData) { | for (KeyValPair &row : salvagedData) { | ||||
if (recoverKVcallback) { | if (recoverKVcallback) { | ||||
CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION); | CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION); | ||||
CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION); | CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION); | ||||
if (!(*recoverKVcallback)(callbackDataIn, ssKey, ssValue)) { | if (!(*recoverKVcallback)(callbackDataIn, ssKey, ssValue)) { | ||||
continue; | continue; | ||||
} | } | ||||
} | } | ||||
Dbt datKey(&row.first[0], row.first.size()); | Dbt datKey(&row.first[0], row.first.size()); | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | if (fs::exists(walletDir / walletFile)) { | ||||
walletFile); | walletFile); | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
// also return true if files does not exists | // also return true if files does not exists | ||||
return true; | return true; | ||||
} | } | ||||
/* End of headers, beginning of key/value data */ | |||||
static const char *HEADER_END = "HEADER=END"; | |||||
/* End of key/value data */ | |||||
static const char *DATA_END = "DATA=END"; | |||||
bool BerkeleyEnvironment::Salvage( | |||||
const std::string &strFile, | |||||
std::vector<BerkeleyEnvironment::KeyValPair> &vResult) { | |||||
LOCK(cs_db); | |||||
assert(mapFileUseCount.count(strFile) == 0); | |||||
std::stringstream strDump; | |||||
Db db(dbenv.get(), 0); | |||||
int result = db.verify(strFile.c_str(), nullptr, &strDump, | |||||
DB_SALVAGE | DB_AGGRESSIVE); | |||||
if (result == DB_VERIFY_BAD) { | |||||
LogPrintf("BerkeleyEnvironment::Salvage: Database salvage found " | |||||
"errors, all data may not be recoverable.\n"); | |||||
} | |||||
if (result != 0 && result != DB_VERIFY_BAD) { | |||||
LogPrintf("BerkeleyEnvironment::Salvage: Database salvage failed with " | |||||
"result %d.\n", | |||||
result); | |||||
return false; | |||||
} | |||||
// Format of bdb dump is ascii lines: | |||||
// header lines... | |||||
// HEADER=END | |||||
// hexadecimal key | |||||
// hexadecimal value | |||||
// ... repeated | |||||
// DATA=END | |||||
std::string strLine; | |||||
while (!strDump.eof() && strLine != HEADER_END) { | |||||
// Skip past header | |||||
getline(strDump, strLine); | |||||
} | |||||
std::string keyHex, valueHex; | |||||
while (!strDump.eof() && keyHex != DATA_END) { | |||||
getline(strDump, keyHex); | |||||
if (keyHex != DATA_END) { | |||||
if (strDump.eof()) { | |||||
break; | |||||
} | |||||
getline(strDump, valueHex); | |||||
if (valueHex == DATA_END) { | |||||
LogPrintf("BerkeleyEnvironment::Salvage: WARNING: Number of " | |||||
"keys in data does not match number of values.\n"); | |||||
break; | |||||
} | |||||
vResult.push_back(make_pair(ParseHex(keyHex), ParseHex(valueHex))); | |||||
} | |||||
} | |||||
if (keyHex != DATA_END) { | |||||
LogPrintf("BerkeleyEnvironment::Salvage: WARNING: Unexpected end of " | |||||
"file while reading salvage output.\n"); | |||||
return false; | |||||
} | |||||
return (result == 0); | |||||
} | |||||
void BerkeleyEnvironment::CheckpointLSN(const std::string &strFile) { | void BerkeleyEnvironment::CheckpointLSN(const std::string &strFile) { | ||||
dbenv->txn_checkpoint(0, 0, 0); | dbenv->txn_checkpoint(0, 0, 0); | ||||
if (fMockDb) { | if (fMockDb) { | ||||
return; | return; | ||||
} | } | ||||
dbenv->lsn_reset(strFile.c_str(), 0); | dbenv->lsn_reset(strFile.c_str(), 0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 453 Lines • Show Last 20 Lines |