Mercurial > hg > bitcoin
changeset 2578:038e24060817 draft
CAddrDB: Replace BDB-managed addr.dat with internally managed peers.dat
author | Jeff Garzik <jgarzik@exmulti.com> |
---|---|
date | Wed, 16 May 2012 22:11:19 -0400 |
parents | 28158429c82e |
children | fca703503589 |
files | src/db.cpp src/db.h src/init.cpp src/net.cpp src/net.h |
diffstat | 5 files changed, 99 insertions(+), 65 deletions(-) [+] |
line wrap: on
line diff
--- a/src/db.cpp +++ b/src/db.cpp @@ -164,8 +164,6 @@ 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()) @@ -310,7 +308,7 @@ 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); } @@ -737,65 +735,96 @@ // 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; - } - - // Read pre-0.6 addr records + // Generate random temporary filename + unsigned short randv = 0; + RAND_bytes((unsigned char *)&randv, sizeof(randv)); + std::string tmpfn = strprintf("peers.dat.%04x", randv); - vector<CAddress> vAddr; - vector<vector<unsigned char> > vDelete; - - // Get cursor - Dbc* pcursor = GetCursor(); - if (!pcursor) - return false; + // 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; - 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; + // 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"); - // Unserialize - string strType; - ssKey >> strType; - if (strType == "addr") - { - CAddress addr; - ssValue >> addr; - vAddr.push_back(addr); - } + // Write and commit header, data + try { + fileout << ssPeers; + } + catch (std::exception &e) { + return error("CAddrman::Write() : I/O error"); } - pcursor->close(); + FileCommit(fileout); + fileout.fclose(); - addrman.Add(vAddr, CNetAddr("0.0.0.0")); - printf("Loaded %i addresses\n", addrman.size()); - - // Note: old records left; we ran into hangs-on-startup - // bugs for some users who (we think) were running after - // an unclean shutdown. + // replace existing peers.dat, if any, with new peers.dat.XXXX + if (!RenameOver(pathTmp, pathAddr)) + return error("CAddrman::Write() : Rename-into-place failed"); 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; } -
--- a/src/db.h +++ b/src/db.h @@ -296,20 +296,15 @@ -/** Access to the (IP) address database (addr.dat) */ -class CAddrDB : public CDB +/** Access to the (IP) address database (peers.dat) */ +class CAddrDB { -public: - CAddrDB(const char* pszMode="r+") : CDB("addr.dat", pszMode) { } private: - CAddrDB(const CAddrDB&); - void operator=(const CAddrDB&); + boost::filesystem::path pathAddr; public: - bool WriteAddrman(const CAddrMan& addr); - bool LoadAddresses(); + CAddrDB(); + bool Write(const CAddrMan& addr); + bool Read(CAddrMan& addr); }; -bool LoadAddresses(); - - #endif // BITCOIN_DB_H
--- a/src/init.cpp +++ b/src/init.cpp @@ -371,9 +371,15 @@ InitMessage(_("Loading addresses...")); printf("Loading addresses...\n"); 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...")); printf("Loading block index...\n");
--- a/src/net.cpp +++ b/src/net.cpp @@ -1278,8 +1278,13 @@ void DumpAddresses() { + int64 nStart = GetTimeMillis(); + 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)