0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-08 10:31:50 -05:00

txdb: add CCoinsViewDB::ChangeCacheSize

We'll need this to dynamically update the cache size of the existing
CCoinsViewDB instance when we create a new one during snapshot activation.

This requires us to keep the CDBWrapper instance as a pointer instead of
a reference so that we're able to destruct it and create a new instance
when the cache size changes.

Also renames `db` to `m_db` since we're already modifying each usage.

Includes feedback from Russ Yanofsky.
This commit is contained in:
James O'Beirne 2019-04-17 10:07:15 -04:00 committed by James O'Beirne
parent ea3e9e0b84
commit b223111da2
2 changed files with 36 additions and 17 deletions

View file

@ -10,6 +10,7 @@
#include <shutdown.h> #include <shutdown.h>
#include <ui_interface.h> #include <ui_interface.h>
#include <uint256.h> #include <uint256.h>
#include <util/memory.h>
#include <util/system.h> #include <util/system.h>
#include <util/translation.h> #include <util/translation.h>
#include <util/vector.h> #include <util/vector.h>
@ -41,35 +42,45 @@ struct CoinEntry {
} }
CCoinsViewDB::CCoinsViewDB(fs::path ldb_path, size_t nCacheSize, bool fMemory, bool fWipe) : db(ldb_path, nCacheSize, fMemory, fWipe, true) CCoinsViewDB::CCoinsViewDB(fs::path ldb_path, size_t nCacheSize, bool fMemory, bool fWipe) :
m_db(MakeUnique<CDBWrapper>(ldb_path, nCacheSize, fMemory, fWipe, true)),
m_ldb_path(ldb_path),
m_is_memory(fMemory) { }
void CCoinsViewDB::ResizeCache(size_t new_cache_size)
{ {
// Have to do a reset first to get the original `m_db` state to release its
// filesystem lock.
m_db.reset();
m_db = MakeUnique<CDBWrapper>(
m_ldb_path, new_cache_size, m_is_memory, /*fWipe*/ false, /*obfuscate*/ true);
} }
bool CCoinsViewDB::GetCoin(const COutPoint &outpoint, Coin &coin) const { bool CCoinsViewDB::GetCoin(const COutPoint &outpoint, Coin &coin) const {
return db.Read(CoinEntry(&outpoint), coin); return m_db->Read(CoinEntry(&outpoint), coin);
} }
bool CCoinsViewDB::HaveCoin(const COutPoint &outpoint) const { bool CCoinsViewDB::HaveCoin(const COutPoint &outpoint) const {
return db.Exists(CoinEntry(&outpoint)); return m_db->Exists(CoinEntry(&outpoint));
} }
uint256 CCoinsViewDB::GetBestBlock() const { uint256 CCoinsViewDB::GetBestBlock() const {
uint256 hashBestChain; uint256 hashBestChain;
if (!db.Read(DB_BEST_BLOCK, hashBestChain)) if (!m_db->Read(DB_BEST_BLOCK, hashBestChain))
return uint256(); return uint256();
return hashBestChain; return hashBestChain;
} }
std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const { std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const {
std::vector<uint256> vhashHeadBlocks; std::vector<uint256> vhashHeadBlocks;
if (!db.Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) { if (!m_db->Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
return std::vector<uint256>(); return std::vector<uint256>();
} }
return vhashHeadBlocks; return vhashHeadBlocks;
} }
bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
CDBBatch batch(db); CDBBatch batch(*m_db);
size_t count = 0; size_t count = 0;
size_t changed = 0; size_t changed = 0;
size_t batch_size = (size_t)gArgs.GetArg("-dbbatchsize", nDefaultDbBatchSize); size_t batch_size = (size_t)gArgs.GetArg("-dbbatchsize", nDefaultDbBatchSize);
@ -107,7 +118,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
mapCoins.erase(itOld); mapCoins.erase(itOld);
if (batch.SizeEstimate() > batch_size) { if (batch.SizeEstimate() > batch_size) {
LogPrint(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0)); LogPrint(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
db.WriteBatch(batch); m_db->WriteBatch(batch);
batch.Clear(); batch.Clear();
if (crash_simulate) { if (crash_simulate) {
static FastRandomContext rng; static FastRandomContext rng;
@ -124,14 +135,14 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
batch.Write(DB_BEST_BLOCK, hashBlock); batch.Write(DB_BEST_BLOCK, hashBlock);
LogPrint(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0)); LogPrint(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
bool ret = db.WriteBatch(batch); bool ret = m_db->WriteBatch(batch);
LogPrint(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count); LogPrint(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
return ret; return ret;
} }
size_t CCoinsViewDB::EstimateSize() const size_t CCoinsViewDB::EstimateSize() const
{ {
return db.EstimateSize(DB_COIN, (char)(DB_COIN+1)); return m_db->EstimateSize(DB_COIN, (char)(DB_COIN+1));
} }
CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) { CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
@ -158,7 +169,7 @@ bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
CCoinsViewCursor *CCoinsViewDB::Cursor() const CCoinsViewCursor *CCoinsViewDB::Cursor() const
{ {
CCoinsViewDBCursor *i = new CCoinsViewDBCursor(const_cast<CDBWrapper&>(db).NewIterator(), GetBestBlock()); CCoinsViewDBCursor *i = new CCoinsViewDBCursor(const_cast<CDBWrapper&>(*m_db).NewIterator(), GetBestBlock());
/* It seems that there are no "const iterators" for LevelDB. Since we /* It seems that there are no "const iterators" for LevelDB. Since we
only need read operations on it, use a const-cast to get around only need read operations on it, use a const-cast to get around
that restriction. */ that restriction. */
@ -338,7 +349,7 @@ public:
* Currently implemented: from the per-tx utxo model (0.8..0.14.x) to per-txout. * Currently implemented: from the per-tx utxo model (0.8..0.14.x) to per-txout.
*/ */
bool CCoinsViewDB::Upgrade() { bool CCoinsViewDB::Upgrade() {
std::unique_ptr<CDBIterator> pcursor(db.NewIterator()); std::unique_ptr<CDBIterator> pcursor(m_db->NewIterator());
pcursor->Seek(std::make_pair(DB_COINS, uint256())); pcursor->Seek(std::make_pair(DB_COINS, uint256()));
if (!pcursor->Valid()) { if (!pcursor->Valid()) {
return true; return true;
@ -349,7 +360,7 @@ bool CCoinsViewDB::Upgrade() {
LogPrintf("[0%%]..."); /* Continued */ LogPrintf("[0%%]..."); /* Continued */
uiInterface.ShowProgress(_("Upgrading UTXO database").translated, 0, true); uiInterface.ShowProgress(_("Upgrading UTXO database").translated, 0, true);
size_t batch_size = 1 << 24; size_t batch_size = 1 << 24;
CDBBatch batch(db); CDBBatch batch(*m_db);
int reportDone = 0; int reportDone = 0;
std::pair<unsigned char, uint256> key; std::pair<unsigned char, uint256> key;
std::pair<unsigned char, uint256> prev_key = {DB_COINS, uint256()}; std::pair<unsigned char, uint256> prev_key = {DB_COINS, uint256()};
@ -384,9 +395,9 @@ bool CCoinsViewDB::Upgrade() {
} }
batch.Erase(key); batch.Erase(key);
if (batch.SizeEstimate() > batch_size) { if (batch.SizeEstimate() > batch_size) {
db.WriteBatch(batch); m_db->WriteBatch(batch);
batch.Clear(); batch.Clear();
db.CompactRange(prev_key, key); m_db->CompactRange(prev_key, key);
prev_key = key; prev_key = key;
} }
pcursor->Next(); pcursor->Next();
@ -394,8 +405,8 @@ bool CCoinsViewDB::Upgrade() {
break; break;
} }
} }
db.WriteBatch(batch); m_db->WriteBatch(batch);
db.CompactRange({DB_COINS, uint256()}, key); m_db->CompactRange({DB_COINS, uint256()}, key);
uiInterface.ShowProgress("", 100, false); uiInterface.ShowProgress("", 100, false);
LogPrintf("[%s].\n", ShutdownRequested() ? "CANCELLED" : "DONE"); LogPrintf("[%s].\n", ShutdownRequested() ? "CANCELLED" : "DONE");
return !ShutdownRequested(); return !ShutdownRequested();

View file

@ -39,11 +39,16 @@ static const int64_t max_filter_index_cache = 1024;
//! Max memory allocated to coin DB specific cache (MiB) //! Max memory allocated to coin DB specific cache (MiB)
static const int64_t nMaxCoinsDBCache = 8; static const int64_t nMaxCoinsDBCache = 8;
// Actually declared in validation.cpp; can't include because of circular dependency.
extern RecursiveMutex cs_main;
/** CCoinsView backed by the coin database (chainstate/) */ /** CCoinsView backed by the coin database (chainstate/) */
class CCoinsViewDB final : public CCoinsView class CCoinsViewDB final : public CCoinsView
{ {
protected: protected:
CDBWrapper db; std::unique_ptr<CDBWrapper> m_db;
fs::path m_ldb_path;
bool m_is_memory;
public: public:
/** /**
* @param[in] ldb_path Location in the filesystem where leveldb data will be stored. * @param[in] ldb_path Location in the filesystem where leveldb data will be stored.
@ -60,6 +65,9 @@ public:
//! Attempt to update from an older database format. Returns whether an error occurred. //! Attempt to update from an older database format. Returns whether an error occurred.
bool Upgrade(); bool Upgrade();
size_t EstimateSize() const override; size_t EstimateSize() const override;
//! Dynamically alter the underlying leveldb cache size.
void ResizeCache(size_t new_cache_size) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
}; };
/** Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB */ /** Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB */