Merge pull request #1198 from jgarzik/addrman
Replace BDB-managed addr.dat with bitcoin-managed peers.dat
This commit is contained in:
commit
b56843b253
8 changed files with 125 additions and 74 deletions
131
src/db.cpp
131
src/db.cpp
|
@ -164,8 +164,6 @@ void CDB::Close()
|
||||||
unsigned int nMinutes = 0;
|
unsigned int nMinutes = 0;
|
||||||
if (fReadOnly)
|
if (fReadOnly)
|
||||||
nMinutes = 1;
|
nMinutes = 1;
|
||||||
if (strFile == "addr.dat")
|
|
||||||
nMinutes = 2;
|
|
||||||
if (strFile == "blkindex.dat")
|
if (strFile == "blkindex.dat")
|
||||||
nMinutes = 2;
|
nMinutes = 2;
|
||||||
if (strFile == "blkindex.dat" && IsInitialBlockDownload())
|
if (strFile == "blkindex.dat" && IsInitialBlockDownload())
|
||||||
|
@ -310,7 +308,7 @@ void DBFlush(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" && strFile != "addr.dat") || fDetachDB) {
|
if (strFile != "blkindex.dat" || 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);
|
||||||
}
|
}
|
||||||
|
@ -737,65 +735,96 @@ bool CTxDB::LoadBlockIndex()
|
||||||
// CAddrDB
|
// 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))
|
// Generate random temporary filename
|
||||||
{
|
unsigned short randv = 0;
|
||||||
printf("Loaded %i addresses\n", addrman.size());
|
RAND_bytes((unsigned char *)&randv, sizeof(randv));
|
||||||
return true;
|
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;
|
||||||
}
|
}
|
||||||
|
catch (std::exception &e) {
|
||||||
// Read pre-0.6 addr records
|
return error("CAddrman::Write() : I/O error");
|
||||||
|
|
||||||
vector<CAddress> vAddr;
|
|
||||||
vector<vector<unsigned char> > vDelete;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// Unserialize
|
|
||||||
string strType;
|
|
||||||
ssKey >> strType;
|
|
||||||
if (strType == "addr")
|
|
||||||
{
|
|
||||||
CAddress addr;
|
|
||||||
ssValue >> addr;
|
|
||||||
vAddr.push_back(addr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pcursor->close();
|
FileCommit(fileout);
|
||||||
|
fileout.fclose();
|
||||||
|
|
||||||
addrman.Add(vAddr, CNetAddr("0.0.0.0"));
|
// replace existing peers.dat, if any, with new peers.dat.XXXX
|
||||||
printf("Loaded %i addresses\n", addrman.size());
|
if (!RenameOver(pathTmp, pathAddr))
|
||||||
|
return error("CAddrman::Write() : Rename-into-place failed");
|
||||||
// Note: old records left; we ran into hangs-on-startup
|
|
||||||
// bugs for some users who (we think) were running after
|
|
||||||
// an unclean shutdown.
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadAddresses()
|
bool CAddrDB::Read(CAddrMan& addr)
|
||||||
{
|
{
|
||||||
return CAddrDB("cr+").LoadAddresses();
|
// 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;
|
||||||
|
}
|
||||||
|
catch (std::exception &e) {
|
||||||
|
return error("CAddrman::Read() 2 : I/O error or stream data corrupted");
|
||||||
|
}
|
||||||
|
filein.fclose();
|
||||||
|
|
||||||
|
CDataStream ssPeers(vchData, SER_DISK, CLIENT_VERSION);
|
||||||
|
|
||||||
|
// verify stored checksum matches input data
|
||||||
|
uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end());
|
||||||
|
if (hashIn != hashTmp)
|
||||||
|
return error("CAddrman::Read() : checksum mismatch; data corrupted");
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally, verify the network matches ours
|
||||||
|
if (memcmp(pchMsgTmp, pchMessageStart, sizeof(pchMsgTmp)))
|
||||||
|
return error("CAddrman::Read() : invalid network magic number");
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
17
src/db.h
17
src/db.h
|
@ -296,20 +296,15 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Access to the (IP) address database (addr.dat) */
|
/** Access to the (IP) address database (peers.dat) */
|
||||||
class CAddrDB : public CDB
|
class CAddrDB
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
CAddrDB(const char* pszMode="r+") : CDB("addr.dat", pszMode) { }
|
|
||||||
private:
|
private:
|
||||||
CAddrDB(const CAddrDB&);
|
boost::filesystem::path pathAddr;
|
||||||
void operator=(const CAddrDB&);
|
|
||||||
public:
|
public:
|
||||||
bool WriteAddrman(const CAddrMan& addr);
|
CAddrDB();
|
||||||
bool LoadAddresses();
|
bool Write(const CAddrMan& addr);
|
||||||
|
bool Read(CAddrMan& addr);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool LoadAddresses();
|
|
||||||
|
|
||||||
|
|
||||||
#endif // BITCOIN_DB_H
|
#endif // BITCOIN_DB_H
|
||||||
|
|
12
src/init.cpp
12
src/init.cpp
|
@ -371,9 +371,15 @@ bool AppInit2()
|
||||||
InitMessage(_("Loading addresses..."));
|
InitMessage(_("Loading addresses..."));
|
||||||
printf("Loading addresses...\n");
|
printf("Loading addresses...\n");
|
||||||
nStart = GetTimeMillis();
|
nStart = GetTimeMillis();
|
||||||
if (!LoadAddresses())
|
|
||||||
strErrors << _("Error loading addr.dat") << "\n";
|
{
|
||||||
printf(" addresses %15"PRI64d"ms\n", GetTimeMillis() - nStart);
|
CAddrDB adb;
|
||||||
|
if (!adb.Read(addrman))
|
||||||
|
printf("Invalid or missing peers.dat; recreating\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Loaded %i addresses from peers.dat %"PRI64d"ms\n",
|
||||||
|
addrman.size(), GetTimeMillis() - nStart);
|
||||||
|
|
||||||
InitMessage(_("Loading block index..."));
|
InitMessage(_("Loading block index..."));
|
||||||
printf("Loading block index...\n");
|
printf("Loading block index...\n");
|
||||||
|
|
|
@ -956,13 +956,7 @@ public:
|
||||||
// Flush stdio buffers and commit to disk before returning
|
// Flush stdio buffers and commit to disk before returning
|
||||||
fflush(fileout);
|
fflush(fileout);
|
||||||
if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0)
|
if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0)
|
||||||
{
|
FileCommit(fileout);
|
||||||
#ifdef WIN32
|
|
||||||
_commit(_fileno(fileout));
|
|
||||||
#else
|
|
||||||
fsync(fileno(fileout));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1278,8 +1278,13 @@ unsigned int pnSeed[] =
|
||||||
|
|
||||||
void DumpAddresses()
|
void DumpAddresses()
|
||||||
{
|
{
|
||||||
|
int64 nStart = GetTimeMillis();
|
||||||
|
|
||||||
CAddrDB adb;
|
CAddrDB adb;
|
||||||
adb.WriteAddrman(addrman);
|
adb.Write(addrman);
|
||||||
|
|
||||||
|
printf("Flushed %d addresses to peers.dat %"PRI64d"ms\n",
|
||||||
|
addrman.size(), GetTimeMillis() - nStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadDumpAddress2(void* parg)
|
void ThreadDumpAddress2(void* parg)
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
#include "addrman.h"
|
#include "addrman.h"
|
||||||
|
|
||||||
class CAddrDB;
|
|
||||||
class CRequestTracker;
|
class CRequestTracker;
|
||||||
class CNode;
|
class CNode;
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
|
|
21
src/util.cpp
21
src/util.cpp
|
@ -910,6 +910,27 @@ void CreatePidFile(const boost::filesystem::path &path, pid_t pid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest)
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
return MoveFileEx(src.string().c_str(), dest.string().c_str(),
|
||||||
|
MOVEFILE_REPLACE_EXISTING);
|
||||||
|
#else
|
||||||
|
int rc = std::rename(src.string().c_str(), dest.string().c_str());
|
||||||
|
return (rc == 0);
|
||||||
|
#endif /* WIN32 */
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileCommit(FILE *fileout)
|
||||||
|
{
|
||||||
|
fflush(fileout); // harmless if redundantly called
|
||||||
|
#ifdef WIN32
|
||||||
|
_commit(_fileno(fileout));
|
||||||
|
#else
|
||||||
|
fsync(fileno(fileout));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int GetFilesize(FILE* file)
|
int GetFilesize(FILE* file)
|
||||||
{
|
{
|
||||||
int nSavePos = ftell(file);
|
int nSavePos = ftell(file);
|
||||||
|
|
|
@ -152,7 +152,9 @@ std::string EncodeBase64(const std::string& str);
|
||||||
void ParseParameters(int argc, const char*const argv[]);
|
void ParseParameters(int argc, const char*const argv[]);
|
||||||
bool WildcardMatch(const char* psz, const char* mask);
|
bool WildcardMatch(const char* psz, const char* mask);
|
||||||
bool WildcardMatch(const std::string& str, const std::string& mask);
|
bool WildcardMatch(const std::string& str, const std::string& mask);
|
||||||
|
void FileCommit(FILE *fileout);
|
||||||
int GetFilesize(FILE* file);
|
int GetFilesize(FILE* file);
|
||||||
|
bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest);
|
||||||
boost::filesystem::path GetDefaultDataDir();
|
boost::filesystem::path GetDefaultDataDir();
|
||||||
const boost::filesystem::path &GetDataDir(bool fNetSpecific = true);
|
const boost::filesystem::path &GetDataDir(bool fNetSpecific = true);
|
||||||
boost::filesystem::path GetConfigFile();
|
boost::filesystem::path GetConfigFile();
|
||||||
|
|
Loading…
Reference in a new issue