|
|
@ -170,6 +170,14 @@ CDB::CDB(const char *pszFile, const char* pszMode) : |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static bool IsChainFile(std::string strFile) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (strFile == "blkindex.dat") |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void CDB::Close() |
|
|
|
void CDB::Close() |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (!pdb) |
|
|
|
if (!pdb) |
|
|
@ -183,9 +191,9 @@ void CDB::Close() |
|
|
|
unsigned int nMinutes = 0; |
|
|
|
unsigned int nMinutes = 0; |
|
|
|
if (fReadOnly) |
|
|
|
if (fReadOnly) |
|
|
|
nMinutes = 1; |
|
|
|
nMinutes = 1; |
|
|
|
if (strFile == "blkindex.dat") |
|
|
|
if (IsChainFile(strFile)) |
|
|
|
nMinutes = 2; |
|
|
|
nMinutes = 2; |
|
|
|
if (strFile == "blkindex.dat" && IsInitialBlockDownload()) |
|
|
|
if (IsChainFile(strFile) && IsInitialBlockDownload()) |
|
|
|
nMinutes = 5; |
|
|
|
nMinutes = 5; |
|
|
|
|
|
|
|
|
|
|
|
bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0); |
|
|
|
bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0); |
|
|
@ -327,7 +335,7 @@ void CDBEnv::Flush(bool fShutdown) |
|
|
|
CloseDb(strFile); |
|
|
|
CloseDb(strFile); |
|
|
|
printf("%s checkpoint\n", strFile.c_str()); |
|
|
|
printf("%s checkpoint\n", strFile.c_str()); |
|
|
|
dbenv.txn_checkpoint(0, 0, 0); |
|
|
|
dbenv.txn_checkpoint(0, 0, 0); |
|
|
|
if (strFile != "blkindex.dat" || fDetachDB) { |
|
|
|
if (!IsChainFile(strFile) || fDetachDB) { |
|
|
|
printf("%s detach\n", strFile.c_str()); |
|
|
|
printf("%s detach\n", strFile.c_str()); |
|
|
|
dbenv.lsn_reset(strFile.c_str(), 0); |
|
|
|
dbenv.lsn_reset(strFile.c_str(), 0); |
|
|
|
} |
|
|
|
} |
|
|
@ -529,68 +537,9 @@ CBlockIndex static * InsertBlockIndex(uint256 hash) |
|
|
|
|
|
|
|
|
|
|
|
bool CTxDB::LoadBlockIndex() |
|
|
|
bool CTxDB::LoadBlockIndex() |
|
|
|
{ |
|
|
|
{ |
|
|
|
// Get database cursor
|
|
|
|
if (!LoadBlockIndexGuts()) |
|
|
|
Dbc* pcursor = GetCursor(); |
|
|
|
|
|
|
|
if (!pcursor) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Load mapBlockIndex
|
|
|
|
|
|
|
|
unsigned int fFlags = DB_SET_RANGE; |
|
|
|
|
|
|
|
loop |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// Read next record
|
|
|
|
|
|
|
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION); |
|
|
|
|
|
|
|
if (fFlags == DB_SET_RANGE) |
|
|
|
|
|
|
|
ssKey << make_pair(string("blockindex"), uint256(0)); |
|
|
|
|
|
|
|
CDataStream ssValue(SER_DISK, CLIENT_VERSION); |
|
|
|
|
|
|
|
int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); |
|
|
|
|
|
|
|
fFlags = DB_NEXT; |
|
|
|
|
|
|
|
if (ret == DB_NOTFOUND) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
else if (ret != 0) |
|
|
|
|
|
|
|
return false; |
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
// Unserialize
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
string strType; |
|
|
|
|
|
|
|
ssKey >> strType; |
|
|
|
|
|
|
|
if (strType == "blockindex" && !fRequestShutdown) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
CDiskBlockIndex diskindex; |
|
|
|
|
|
|
|
ssValue >> diskindex; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Construct block index object
|
|
|
|
|
|
|
|
CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); |
|
|
|
|
|
|
|
pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); |
|
|
|
|
|
|
|
pindexNew->pnext = InsertBlockIndex(diskindex.hashNext); |
|
|
|
|
|
|
|
pindexNew->nFile = diskindex.nFile; |
|
|
|
|
|
|
|
pindexNew->nBlockPos = diskindex.nBlockPos; |
|
|
|
|
|
|
|
pindexNew->nHeight = diskindex.nHeight; |
|
|
|
|
|
|
|
pindexNew->nVersion = diskindex.nVersion; |
|
|
|
|
|
|
|
pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; |
|
|
|
|
|
|
|
pindexNew->nTime = diskindex.nTime; |
|
|
|
|
|
|
|
pindexNew->nBits = diskindex.nBits; |
|
|
|
|
|
|
|
pindexNew->nNonce = diskindex.nNonce; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Watch for genesis block
|
|
|
|
|
|
|
|
if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock) |
|
|
|
|
|
|
|
pindexGenesisBlock = pindexNew; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!pindexNew->CheckIndex()) |
|
|
|
|
|
|
|
return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
break; // if shutdown requested or finished loading block index
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} // try
|
|
|
|
|
|
|
|
catch (std::exception &e) { |
|
|
|
|
|
|
|
return error("%s() : deserialize error", __PRETTY_FUNCTION__); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
pcursor->close(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (fRequestShutdown) |
|
|
|
if (fRequestShutdown) |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
|
|
|
|
|
|
|
@ -756,6 +705,75 @@ bool CTxDB::LoadBlockIndex() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CTxDB::LoadBlockIndexGuts() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// Get database cursor
|
|
|
|
|
|
|
|
Dbc* pcursor = GetCursor(); |
|
|
|
|
|
|
|
if (!pcursor) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Load mapBlockIndex
|
|
|
|
|
|
|
|
unsigned int fFlags = DB_SET_RANGE; |
|
|
|
|
|
|
|
loop |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// Read next record
|
|
|
|
|
|
|
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION); |
|
|
|
|
|
|
|
if (fFlags == DB_SET_RANGE) |
|
|
|
|
|
|
|
ssKey << make_pair(string("blockindex"), uint256(0)); |
|
|
|
|
|
|
|
CDataStream ssValue(SER_DISK, CLIENT_VERSION); |
|
|
|
|
|
|
|
int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); |
|
|
|
|
|
|
|
fFlags = DB_NEXT; |
|
|
|
|
|
|
|
if (ret == DB_NOTFOUND) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
else if (ret != 0) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Unserialize
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
string strType; |
|
|
|
|
|
|
|
ssKey >> strType; |
|
|
|
|
|
|
|
if (strType == "blockindex" && !fRequestShutdown) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
CDiskBlockIndex diskindex; |
|
|
|
|
|
|
|
ssValue >> diskindex; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Construct block index object
|
|
|
|
|
|
|
|
CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); |
|
|
|
|
|
|
|
pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); |
|
|
|
|
|
|
|
pindexNew->pnext = InsertBlockIndex(diskindex.hashNext); |
|
|
|
|
|
|
|
pindexNew->nFile = diskindex.nFile; |
|
|
|
|
|
|
|
pindexNew->nBlockPos = diskindex.nBlockPos; |
|
|
|
|
|
|
|
pindexNew->nHeight = diskindex.nHeight; |
|
|
|
|
|
|
|
pindexNew->nVersion = diskindex.nVersion; |
|
|
|
|
|
|
|
pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; |
|
|
|
|
|
|
|
pindexNew->nTime = diskindex.nTime; |
|
|
|
|
|
|
|
pindexNew->nBits = diskindex.nBits; |
|
|
|
|
|
|
|
pindexNew->nNonce = diskindex.nNonce; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Watch for genesis block
|
|
|
|
|
|
|
|
if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock) |
|
|
|
|
|
|
|
pindexGenesisBlock = pindexNew; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!pindexNew->CheckIndex()) |
|
|
|
|
|
|
|
return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
break; // if shutdown requested or finished loading block index
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} // try
|
|
|
|
|
|
|
|
catch (std::exception &e) { |
|
|
|
|
|
|
|
return error("%s() : deserialize error", __PRETTY_FUNCTION__); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
pcursor->close(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|