|
|
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
|
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
|
|
|
// Distributed under the GPLv3 software license, see the accompanying
|
|
|
|
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* Copyright © 2014-2019 The SuperNET Developers. *
|
|
|
|
* *
|
|
|
|
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
|
|
|
* the top-level directory of this distribution for the individual copyright *
|
|
|
|
* holder information and the developer policies on copyright and licensing. *
|
|
|
|
* *
|
|
|
|
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
|
|
|
* SuperNET software, including this file may be copied, modified, propagated *
|
|
|
|
* or distributed except according to the terms contained in the LICENSE file *
|
|
|
|
* *
|
|
|
|
* Removal or modification of this copyright notice is prohibited. *
|
|
|
|
* *
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
#include "db.h"
|
|
|
|
|
|
|
|
#include "addrman.h"
|
|
|
|
#include "hash.h"
|
|
|
|
#include "protocol.h"
|
|
|
|
#include "util.h"
|
Split up util.cpp/h
Split up util.cpp/h into:
- string utilities (hex, base32, base64): no internal dependencies, no dependency on boost (apart from foreach)
- money utilities (parsesmoney, formatmoney)
- time utilities (gettime*, sleep, format date):
- and the rest (logging, argument parsing, config file parsing)
The latter is basically the environment and OS handling,
and is stripped of all utility functions, so we may want to
rename it to something else than util.cpp/h for clarity (Matt suggested
osinterface).
Breaks dependency of sha256.cpp on all the things pulled in by util.
10 years ago
|
|
|
#include "utilstrencodings.h"
|
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <boost/filesystem.hpp>
|
Split up util.cpp/h
Split up util.cpp/h into:
- string utilities (hex, base32, base64): no internal dependencies, no dependency on boost (apart from foreach)
- money utilities (parsesmoney, formatmoney)
- time utilities (gettime*, sleep, format date):
- and the rest (logging, argument parsing, config file parsing)
The latter is basically the environment and OS handling,
and is stripped of all utility functions, so we may want to
rename it to something else than util.cpp/h for clarity (Matt suggested
osinterface).
Breaks dependency of sha256.cpp on all the things pulled in by util.
10 years ago
|
|
|
#include <boost/thread.hpp>
|
|
|
|
#include <boost/version.hpp>
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
|
|
unsigned int nWalletDBUpdated;
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// CDB
|
|
|
|
//
|
|
|
|
|
|
|
|
CDBEnv bitdb;
|
|
|
|
|
|
|
|
void CDBEnv::EnvShutdown()
|
|
|
|
{
|
|
|
|
if (!fDbEnvInit)
|
|
|
|
return;
|
|
|
|
|
|
|
|
fDbEnvInit = false;
|
|
|
|
int ret = dbenv->close(0);
|
|
|
|
if (ret != 0)
|
|
|
|
LogPrintf("CDBEnv::EnvShutdown: Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret));
|
|
|
|
if (!fMockDb)
|
|
|
|
DbEnv(u_int32_t{0}).remove(strPath.c_str(), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDBEnv::Reset()
|
|
|
|
{
|
|
|
|
delete dbenv;
|
|
|
|
dbenv = new DbEnv(DB_CXX_NO_EXCEPTIONS);
|
|
|
|
fDbEnvInit = false;
|
|
|
|
fMockDb = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
CDBEnv::CDBEnv() : dbenv(NULL)
|
|
|
|
{
|
|
|
|
Reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
CDBEnv::~CDBEnv()
|
|
|
|
{
|
|
|
|
EnvShutdown();
|
|
|
|
delete dbenv;
|
|
|
|
dbenv = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDBEnv::Close()
|
|
|
|
{
|
|
|
|
EnvShutdown();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CDBEnv::Open(const boost::filesystem::path& pathIn)
|
|
|
|
{
|
|
|
|
if (fDbEnvInit)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
boost::this_thread::interruption_point();
|
|
|
|
|
|
|
|
strPath = pathIn.string();
|
|
|
|
boost::filesystem::path pathLogDir = pathIn / "database";
|
|
|
|
TryCreateDirectory(pathLogDir);
|
|
|
|
boost::filesystem::path pathErrorFile = pathIn / "db.log";
|
|
|
|
LogPrintf("CDBEnv::Open: LogDir=%s ErrorFile=%s pathIn.(%s)\n", pathLogDir.string(), pathErrorFile.string(),pathIn.string());
|
|
|
|
//fprintf(stderr,"strPath.(%s)\n",strPath.c_str());
|
|
|
|
|
|
|
|
unsigned int nEnvFlags = 0;
|
|
|
|
if (GetBoolArg("-privdb", true))
|
|
|
|
nEnvFlags |= DB_PRIVATE;
|
|
|
|
|
|
|
|
dbenv->set_lg_dir(pathLogDir.string().c_str());
|
|
|
|
dbenv->set_cachesize(1, 0x100000, 1); // 1 MiB should be enough for just the wallet, Increased by 1 GB
|
|
|
|
dbenv->set_lg_bsize(0x10000);
|
|
|
|
dbenv->set_lg_max(1048576);
|
|
|
|
dbenv->set_lk_max_locks(40000);
|
|
|
|
dbenv->set_lk_max_objects(40000);
|
|
|
|
dbenv->set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug
|
|
|
|
dbenv->set_flags(DB_AUTO_COMMIT, 1);
|
|
|
|
dbenv->set_flags(DB_TXN_WRITE_NOSYNC, 1);
|
|
|
|
dbenv->log_set_config(DB_LOG_AUTO_REMOVE, 1);
|
|
|
|
int ret = dbenv->open(strPath.c_str(),
|
|
|
|
DB_CREATE |
|
|
|
|
DB_INIT_LOCK |
|
|
|
|
DB_INIT_LOG |
|
|
|
|
DB_INIT_MPOOL |
|
|
|
|
DB_INIT_TXN |
|
|
|
|
DB_THREAD |
|
|
|
|
DB_RECOVER |
|
|
|
|
nEnvFlags,
|
|
|
|
S_IRUSR | S_IWUSR);
|
|
|
|
if (ret != 0)
|
|
|
|
return error("CDBEnv::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
|
|
|
|
|
|
|
|
fDbEnvInit = true;
|
|
|
|
fMockDb = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDBEnv::MakeMock()
|
|
|
|
{
|
|
|
|
if (fDbEnvInit)
|
|
|
|
throw runtime_error("CDBEnv::MakeMock: Already initialized");
|
|
|
|
|
|
|
|
boost::this_thread::interruption_point();
|
|
|
|
|
|
|
|
LogPrint("db", "CDBEnv::MakeMock\n");
|
|
|
|
|
|
|
|
dbenv->set_cachesize(1, 0, 1);
|
|
|
|
dbenv->set_lg_bsize(10485760 * 4);
|
|
|
|
dbenv->set_lg_max(10485760);
|
|
|
|
dbenv->set_lk_max_locks(10000);
|
|
|
|
dbenv->set_lk_max_objects(10000);
|
|
|
|
dbenv->set_flags(DB_AUTO_COMMIT, 1);
|
|
|
|
dbenv->log_set_config(DB_LOG_IN_MEMORY, 1);
|
|
|
|
int ret = dbenv->open(NULL,
|
|
|
|
DB_CREATE |
|
|
|
|
DB_INIT_LOCK |
|
|
|
|
DB_INIT_LOG |
|
|
|
|
DB_INIT_MPOOL |
|
|
|
|
DB_INIT_TXN |
|
|
|
|
DB_THREAD |
|
|
|
|
DB_PRIVATE,
|
|
|
|
S_IRUSR | S_IWUSR);
|
|
|
|
if (ret > 0)
|
|
|
|
throw runtime_error(strprintf("CDBEnv::MakeMock: Error %d opening database environment.", ret));
|
|
|
|
|
|
|
|
fDbEnvInit = true;
|
|
|
|
fMockDb = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, bool (*recoverFunc)(CDBEnv& dbenv, const std::string& strFile))
|
|
|
|
{
|
|
|
|
LOCK(cs_db);
|
|
|
|
assert(mapFileUseCount.count(strFile) == 0);
|
|
|
|
|
|
|
|
Db db(dbenv, 0);
|
|
|
|
int result = db.verify(strFile.c_str(), NULL, NULL, 0);
|
|
|
|
if (result == 0)
|
|
|
|
return VERIFY_OK;
|
|
|
|
else if (recoverFunc == NULL)
|
|
|
|
return RECOVER_FAIL;
|
|
|
|
|
|
|
|
// Try to recover:
|
|
|
|
bool fRecovered = (*recoverFunc)(*this, strFile);
|
|
|
|
return (fRecovered ? RECOVER_OK : RECOVER_FAIL);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CDBEnv::Compact(const std::string& strFile)
|
|
|
|
{
|
|
|
|
LOCK(cs_db);
|
|
|
|
|
|
|
|
DB_COMPACT dbcompact;
|
|
|
|
dbcompact.compact_fillpercent = 80;
|
|
|
|
dbcompact.compact_pages = DB_MAX_PAGES;
|
|
|
|
dbcompact.compact_timeout = 0;
|
|
|
|
|
|
|
|
DB_COMPACT *pdbcompact;
|
|
|
|
pdbcompact = &dbcompact;
|
|
|
|
|
|
|
|
int result = 1;
|
|
|
|
if (mapDb[strFile] != NULL) {
|
|
|
|
Db* pdb = mapDb[strFile];
|
|
|
|
result = pdb->compact(NULL, NULL, NULL, pdbcompact, DB_FREE_SPACE, NULL);
|
|
|
|
delete pdb;
|
|
|
|
mapDb[strFile] = NULL;
|
|
|
|
|
|
|
|
switch (result)
|
|
|
|
{
|
|
|
|
case DB_LOCK_DEADLOCK:
|
|
|
|
LogPrint("db","Deadlock %i\n", result);
|
|
|
|
break;
|
|
|
|
case DB_LOCK_NOTGRANTED:
|
|
|
|
LogPrint("db","Lock Not Granted %i\n", result);
|
|
|
|
break;
|
|
|
|
case DB_REP_HANDLE_DEAD:
|
|
|
|
LogPrint("db","Handle Dead %i\n", result);
|
|
|
|
break;
|
|
|
|
case DB_REP_LOCKOUT:
|
|
|
|
LogPrint("db","Rep Lockout %i\n", result);
|
|
|
|
break;
|
|
|
|
case EACCES:
|
|
|
|
LogPrint("db","Eacces %i\n", result);
|
|
|
|
break;
|
|
|
|
case EINVAL:
|
|
|
|
LogPrint("db","Error Invalid %i\n", result);
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
LogPrint("db","Wallet Compact Sucessful\n");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LogPrint("db","Compact result int %i\n", result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (result == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<CDBEnv::KeyValPair>& vResult)
|
|
|
|
{
|
|
|
|
LOCK(cs_db);
|
|
|
|
assert(mapFileUseCount.count(strFile) == 0);
|
|
|
|
|
|
|
|
u_int32_t flags = DB_SALVAGE;
|
|
|
|
if (fAggressive)
|
|
|
|
flags |= DB_AGGRESSIVE;
|
|
|
|
|
|
|
|
stringstream strDump;
|
|
|
|
|
|
|
|
Db db(dbenv, 0);
|
|
|
|
int result = db.verify(strFile.c_str(), NULL, &strDump, flags);
|
|
|
|
if (result == DB_VERIFY_BAD) {
|
|
|
|
LogPrintf("CDBEnv::Salvage: Database salvage found errors, all data may not be recoverable.\n");
|
|
|
|
if (!fAggressive) {
|
|
|
|
LogPrintf("CDBEnv::Salvage: Rerun with aggressive mode to ignore errors and continue.\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (result != 0 && result != DB_VERIFY_BAD) {
|
|
|
|
LogPrintf("CDBEnv::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
|
|
|
|
|
|
|
|
string strLine;
|
|
|
|
while (!strDump.eof() && strLine != "HEADER=END")
|
|
|
|
getline(strDump, strLine); // Skip past header
|
|
|
|
|
|
|
|
std::string keyHex, valueHex;
|
|
|
|
while (!strDump.eof() && keyHex != "DATA=END") {
|
|
|
|
getline(strDump, keyHex);
|
|
|
|
if (keyHex != "DATA_END") {
|
|
|
|
getline(strDump, valueHex);
|
|
|
|
vResult.push_back(make_pair(ParseHex(keyHex), ParseHex(valueHex)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (result == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CDBEnv::CheckpointLSN(const std::string& strFile)
|
|
|
|
{
|
|
|
|
dbenv->txn_checkpoint(0, 0, 0);
|
|
|
|
if (fMockDb)
|
|
|
|
return;
|
|
|
|
dbenv->lsn_reset(strFile.c_str(), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnCloseIn) : pdb(NULL), activeTxn(NULL)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
|
|
|
|
fFlushOnClose = fFlushOnCloseIn;
|
|
|
|
if (strFilename.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
bool fCreate = strchr(pszMode, 'c') != NULL;
|
|
|
|
unsigned int nFlags = DB_THREAD;
|
|
|
|
if (fCreate)
|
|
|
|
nFlags |= DB_CREATE;
|
|
|
|
|
|
|
|
{
|
|
|
|
LOCK(bitdb.cs_db);
|
|
|
|
if (!bitdb.Open(GetDataDir()))
|
|
|
|
throw runtime_error("CDB: Failed to open database environment.");
|
|
|
|
|
|
|
|
strFile = strFilename;
|
|
|
|
++bitdb.mapFileUseCount[strFile];
|
|
|
|
pdb = bitdb.mapDb[strFile];
|
|
|
|
if (pdb == NULL) {
|
|
|
|
pdb = new Db(bitdb.dbenv, 0);
|
|
|
|
|
|
|
|
bool fMockDb = bitdb.IsMock();
|
|
|
|
if (fMockDb) {
|
|
|
|
DbMpoolFile* mpf = pdb->get_mpf();
|
|
|
|
ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);
|
|
|
|
if (ret != 0)
|
|
|
|
throw runtime_error(strprintf("CDB: Failed to configure for no temp file backing for database %s", strFile));
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = pdb->open(NULL, // Txn pointer
|
|
|
|
fMockDb ? NULL : strFile.c_str(), // Filename
|
|
|
|
fMockDb ? strFile.c_str() : "main", // Logical db name
|
|
|
|
DB_BTREE, // Database type
|
|
|
|
nFlags, // Flags
|
|
|
|
0);
|
|
|
|
|
|
|
|
if (ret != 0) {
|
|
|
|
delete pdb;
|
|
|
|
pdb = NULL;
|
|
|
|
--bitdb.mapFileUseCount[strFile];
|
|
|
|
strFile = "";
|
|
|
|
throw runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFile));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fCreate && !Exists(string("version"))) {
|
|
|
|
bool fTmp = fReadOnly;
|
|
|
|
fReadOnly = false;
|
|
|
|
WriteVersion(CLIENT_VERSION);
|
|
|
|
fReadOnly = fTmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
bitdb.mapDb[strFile] = pdb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDB::Flush()
|
|
|
|
{
|
|
|
|
if (activeTxn)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Flush database activity from memory pool to disk log
|
|
|
|
unsigned int nMinutes = 0;
|
|
|
|
if (fReadOnly)
|
|
|
|
nMinutes = 1;
|
|
|
|
|
|
|
|
bitdb.dbenv->txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100) * 1024 : 0, nMinutes, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDB::Close()
|
|
|
|
{
|
|
|
|
if (!pdb)
|
|
|
|
return;
|
|
|
|
if (activeTxn)
|
|
|
|
activeTxn->abort();
|
|
|
|
activeTxn = NULL;
|
|
|
|
pdb = NULL;
|
|
|
|
|
|
|
|
if (fFlushOnClose)
|
|
|
|
Flush();
|
|
|
|
|
|
|
|
{
|
|
|
|
LOCK(bitdb.cs_db);
|
|
|
|
--bitdb.mapFileUseCount[strFile];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDBEnv::CloseDb(const string& strFile)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
LOCK(cs_db);
|
|
|
|
if (mapDb[strFile] != NULL) {
|
|
|
|
// Close the database handle
|
|
|
|
Db* pdb = mapDb[strFile];
|
|
|
|
pdb->close(0);
|
|
|
|
delete pdb;
|
|
|
|
mapDb[strFile] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CDBEnv::RemoveDb(const string& strFile)
|
|
|
|
{
|
|
|
|
this->CloseDb(strFile);
|
|
|
|
|
|
|
|
LOCK(cs_db);
|
|
|
|
int rc = dbenv->dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT);
|
|
|
|
return (rc == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CDB::Rewrite(const string& strFile, const char* pszSkip)
|
|
|
|
{
|
|
|
|
while (true) {
|
|
|
|
{
|
|
|
|
LOCK(bitdb.cs_db);
|
|
|
|
if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0) {
|
|
|
|
// Flush log data to the dat file
|
|
|
|
bitdb.CloseDb(strFile);
|
|
|
|
bitdb.CheckpointLSN(strFile);
|
|
|
|
bitdb.mapFileUseCount.erase(strFile);
|
|
|
|
|
|
|
|
bool fSuccess = true;
|
|
|
|
LogPrintf("CDB::Rewrite: Rewriting %s...\n", strFile);
|
|
|
|
string strFileRes = strFile + ".rewrite";
|
|
|
|
{ // surround usage of db with extra {}
|
|
|
|
CDB db(strFile.c_str(), "r");
|
|
|
|
Db* pdbCopy = new Db(bitdb.dbenv, 0);
|
|
|
|
|
|
|
|
int ret = pdbCopy->open(NULL, // Txn pointer
|
|
|
|
strFileRes.c_str(), // Filename
|
|
|
|
"main", // Logical db name
|
|
|
|
DB_BTREE, // Database type
|
|
|
|
DB_CREATE, // Flags
|
|
|
|
0);
|
|
|
|
if (ret > 0) {
|
|
|
|
LogPrintf("CDB::Rewrite: Can't create database file %s\n", strFileRes);
|
|
|
|
fSuccess = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Dbc* pcursor = db.GetCursor();
|
|
|
|
if (pcursor)
|
|
|
|
while (fSuccess) {
|
|
|
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
|
|
|
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
|
|
|
|
int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
|
|
|
|
if (ret == DB_NOTFOUND) {
|
|
|
|
pcursor->close();
|
|
|
|
break;
|
|
|
|
} else if (ret != 0) {
|
|
|
|
pcursor->close();
|
|
|
|
fSuccess = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (pszSkip &&
|
|
|
|
strncmp(&ssKey[0], pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0)
|
|
|
|
continue;
|
|
|
|
if (strncmp(&ssKey[0], "\x07version", 8) == 0) {
|
|
|
|
// Update version:
|
|
|
|
ssValue.clear();
|
|
|
|
ssValue << CLIENT_VERSION;
|
|
|
|
}
|
|
|
|
Dbt datKey(&ssKey[0], ssKey.size());
|
|
|
|
Dbt datValue(&ssValue[0], ssValue.size());
|
|
|
|
int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE);
|
|
|
|
if (ret2 > 0)
|
|
|
|
fSuccess = false;
|
|
|
|
}
|
|
|
|
if (fSuccess) {
|
|
|
|
db.Close();
|
|
|
|
bitdb.CloseDb(strFile);
|
|
|
|
if (pdbCopy->close(0))
|
|
|
|
fSuccess = false;
|
|
|
|
delete pdbCopy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (fSuccess) {
|
|
|
|
Db dbA(bitdb.dbenv, 0);
|
|
|
|
if (dbA.remove(strFile.c_str(), NULL, 0))
|
|
|
|
fSuccess = false;
|
|
|
|
Db dbB(bitdb.dbenv, 0);
|
|
|
|
if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0))
|
|
|
|
fSuccess = false;
|
|
|
|
}
|
|
|
|
if (!fSuccess)
|
|
|
|
LogPrintf("CDB::Rewrite: Failed to rewrite database file %s\n", strFileRes);
|
|
|
|
return fSuccess;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MilliSleep(100);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CDBEnv::Flush(bool fShutdown)
|
|
|
|
{
|
|
|
|
int64_t nStart = GetTimeMillis();
|
|
|
|
// Flush log data to the actual data file on all files that are not in use
|
|
|
|
LogPrint("db", "CDBEnv::Flush: Flush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started");
|
|
|
|
if (!fDbEnvInit)
|
|
|
|
return;
|
|
|
|
{
|
|
|
|
LOCK(cs_db);
|
|
|
|
map<string, int>::iterator mi = mapFileUseCount.begin();
|
|
|
|
while (mi != mapFileUseCount.end()) {
|
|
|
|
string strFile = (*mi).first;
|
|
|
|
int nRefCount = (*mi).second;
|
|
|
|
LogPrint("db", "CDBEnv::Flush: Flushing %s (refcount = %d)...\n", strFile, nRefCount);
|
|
|
|
if (nRefCount == 0) {
|
|
|
|
// Move log data to the dat file
|
|
|
|
CloseDb(strFile);
|
|
|
|
LogPrint("db", "CDBEnv::Flush: %s checkpoint\n", strFile);
|
|
|
|
dbenv->txn_checkpoint(0, 0, 0);
|
|
|
|
LogPrint("db", "CDBEnv::Flush: %s detach\n", strFile);
|
|
|
|
if (!fMockDb)
|
|
|
|
dbenv->lsn_reset(strFile.c_str(), 0);
|
|
|
|
LogPrint("db", "CDBEnv::Flush: %s closed\n", strFile);
|
|
|
|
mapFileUseCount.erase(mi++);
|
|
|
|
} else
|
|
|
|
mi++;
|
|
|
|
}
|
|
|
|
LogPrint("db", "CDBEnv::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", GetTimeMillis() - nStart);
|
|
|
|
if (fShutdown) {
|
|
|
|
char** listp;
|
|
|
|
if (mapFileUseCount.empty()) {
|
|
|
|
dbenv->log_archive(&listp, DB_ARCH_REMOVE);
|
|
|
|
Close();
|
|
|
|
if (!fMockDb)
|
|
|
|
boost::filesystem::remove_all(boost::filesystem::path(strPath) / "database");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|