aboutsummaryrefslogtreecommitdiff
path: root/src/db.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/db.cpp')
-rw-r--r--src/db.cpp150
1 files changed, 91 insertions, 59 deletions
diff --git a/src/db.cpp b/src/db.cpp
index 12647e568a..a0b9dc20f7 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "db.h"
#include "util.h"
@@ -76,6 +76,10 @@ CDB::CDB(const char *pszFile, const char* pszMode) : pdb(NULL)
if (fCreate)
nFlags |= DB_CREATE;
+ unsigned int nEnvFlags = 0;
+ if (GetBoolArg("-privdb", true))
+ nEnvFlags |= DB_PRIVATE;
+
{
LOCK(cs_db);
if (!fDbEnvInit)
@@ -96,6 +100,7 @@ CDB::CDB(const char *pszFile, const char* pszMode) : pdb(NULL)
dbenv.set_lk_max_locks(10000);
dbenv.set_lk_max_objects(10000);
dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug
+ dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1);
dbenv.set_flags(DB_AUTO_COMMIT, 1);
dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1);
ret = dbenv.open(pathDataDir.string().c_str(),
@@ -105,7 +110,8 @@ CDB::CDB(const char *pszFile, const char* pszMode) : pdb(NULL)
DB_INIT_MPOOL |
DB_INIT_TXN |
DB_THREAD |
- DB_RECOVER,
+ DB_RECOVER |
+ nEnvFlags,
S_IRUSR | S_IWUSR);
if (ret > 0)
throw runtime_error(strprintf("CDB() : error %d opening database environment", ret));
@@ -164,8 +170,6 @@ void CDB::Close()
unsigned int nMinutes = 0;
if (fReadOnly)
nMinutes = 1;
- if (strFile == "addr.dat")
- nMinutes = 2;
if (strFile == "blkindex.dat")
nMinutes = 2;
if (strFile == "blkindex.dat" && IsInitialBlockDownload())
@@ -291,6 +295,7 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip)
void DBFlush(bool fShutdown)
{
+ int64 nStart = GetTimeMillis();
// Flush log data to the actual data file
// on all files that are not in use
printf("DBFlush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started");
@@ -310,7 +315,7 @@ void DBFlush(bool fShutdown)
CloseDb(strFile);
printf("%s checkpoint\n", strFile.c_str());
dbenv.txn_checkpoint(0, 0, 0);
- if ((strFile != "blkindex.dat" && strFile != "addr.dat") || fDetachDB) {
+ if (strFile != "blkindex.dat" || fDetachDB) {
printf("%s detach\n", strFile.c_str());
dbenv.lsn_reset(strFile.c_str(), 0);
}
@@ -320,6 +325,7 @@ void DBFlush(bool fShutdown)
else
mi++;
}
+ printf("DBFlush(%s)%s ended %15"PRI64d"ms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started", GetTimeMillis() - nStart);
if (fShutdown)
{
char** listp;
@@ -463,11 +469,6 @@ bool CTxDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
return Write(make_pair(string("blockindex"), blockindex.GetBlockHash()), blockindex);
}
-bool CTxDB::EraseBlockIndex(uint256 hash)
-{
- return Erase(make_pair(string("blockindex"), hash));
-}
-
bool CTxDB::ReadHashBestChain(uint256& hashBestChain)
{
return Read(string("hashBestChain"), hashBestChain);
@@ -613,7 +614,7 @@ bool CTxDB::LoadBlockIndex()
map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos;
for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
{
- if (pindex->nHeight < nBestHeight-nCheckDepth)
+ if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth)
break;
CBlock block;
if (!block.ReadFromDisk(pindex))
@@ -715,7 +716,7 @@ bool CTxDB::LoadBlockIndex()
}
}
}
- if (pindexFork)
+ if (pindexFork && !fRequestShutdown)
{
// Reorg back to the fork
printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight);
@@ -737,65 +738,96 @@ bool CTxDB::LoadBlockIndex()
// CAddrDB
//
-bool CAddrDB::WriteAddrman(const CAddrMan& addrman)
+
+CAddrDB::CAddrDB()
{
- return Write(string("addrman"), addrman);
+ pathAddr = GetDataDir() / "peers.dat";
}
-bool CAddrDB::LoadAddresses()
+bool CAddrDB::Write(const CAddrMan& addr)
{
- if (Read(string("addrman"), addrman))
- {
- printf("Loaded %i addresses\n", addrman.size());
- return true;
+ // Generate random temporary filename
+ unsigned short randv = 0;
+ RAND_bytes((unsigned char *)&randv, sizeof(randv));
+ std::string tmpfn = strprintf("peers.dat.%04x", randv);
+
+ // serialize addresses, checksum data up to that point, then append csum
+ CDataStream ssPeers(SER_DISK, CLIENT_VERSION);
+ ssPeers << FLATDATA(pchMessageStart);
+ ssPeers << addr;
+ uint256 hash = Hash(ssPeers.begin(), ssPeers.end());
+ ssPeers << hash;
+
+ // open temp output file, and associate with CAutoFile
+ boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
+ FILE *file = fopen(pathTmp.string().c_str(), "wb");
+ CAutoFile fileout = CAutoFile(file, SER_DISK, CLIENT_VERSION);
+ if (!fileout)
+ return error("CAddrman::Write() : open failed");
+
+ // Write and commit header, data
+ try {
+ fileout << ssPeers;
}
-
- // Read pre-0.6 addr records
+ catch (std::exception &e) {
+ return error("CAddrman::Write() : I/O error");
+ }
+ FileCommit(fileout);
+ fileout.fclose();
- vector<CAddress> vAddr;
- vector<vector<unsigned char> > vDelete;
+ // replace existing peers.dat, if any, with new peers.dat.XXXX
+ if (!RenameOver(pathTmp, pathAddr))
+ return error("CAddrman::Write() : Rename-into-place failed");
- // Get cursor
- Dbc* pcursor = GetCursor();
- if (!pcursor)
- return false;
-
- loop
- {
- // Read next record
- CDataStream ssKey(SER_DISK, CLIENT_VERSION);
- CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- int ret = ReadAtCursor(pcursor, ssKey, ssValue);
- if (ret == DB_NOTFOUND)
- break;
- else if (ret != 0)
- return false;
+ return true;
+}
- // Unserialize
- string strType;
- ssKey >> strType;
- if (strType == "addr")
- {
- CAddress addr;
- ssValue >> addr;
- vAddr.push_back(addr);
- }
+bool CAddrDB::Read(CAddrMan& addr)
+{
+ // open input file, and associate with CAutoFile
+ FILE *file = fopen(pathAddr.string().c_str(), "rb");
+ CAutoFile filein = CAutoFile(file, SER_DISK, CLIENT_VERSION);
+ if (!filein)
+ return error("CAddrman::Read() : open failed");
+
+ // use file size to size memory buffer
+ int fileSize = GetFilesize(filein);
+ int dataSize = fileSize - sizeof(uint256);
+ vector<unsigned char> vchData;
+ vchData.resize(dataSize);
+ uint256 hashIn;
+
+ // read data and checksum from file
+ try {
+ filein.read((char *)&vchData[0], dataSize);
+ filein >> hashIn;
}
- pcursor->close();
+ catch (std::exception &e) {
+ return error("CAddrman::Read() 2 : I/O error or stream data corrupted");
+ }
+ filein.fclose();
- addrman.Add(vAddr, CNetAddr("0.0.0.0"));
- printf("Loaded %i addresses\n", addrman.size());
+ CDataStream ssPeers(vchData, SER_DISK, CLIENT_VERSION);
- // Note: old records left; we ran into hangs-on-startup
- // bugs for some users who (we think) were running after
- // an unclean shutdown.
+ // verify stored checksum matches input data
+ uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end());
+ if (hashIn != hashTmp)
+ return error("CAddrman::Read() : checksum mismatch; data corrupted");
- return true;
-}
+ // de-serialize address data
+ unsigned char pchMsgTmp[4];
+ try {
+ ssPeers >> FLATDATA(pchMsgTmp);
+ ssPeers >> addr;
+ }
+ catch (std::exception &e) {
+ return error("CAddrman::Read() : I/O error or stream data corrupted");
+ }
-bool LoadAddresses()
-{
- return CAddrDB("cr+").LoadAddresses();
-}
+ // finally, verify the network matches ours
+ if (memcmp(pchMsgTmp, pchMessageStart, sizeof(pchMsgTmp)))
+ return error("CAddrman::Read() : invalid network magic number");
+ return true;
+}