Browse Source

Caching.

cl-refactor
Gav Wood 10 years ago
parent
commit
0a5869739b
  1. 7
      alethzero/Main.ui
  2. 8
      alethzero/MainWin.cpp
  3. 1
      alethzero/MainWin.h
  4. 124
      libethereum/BlockChain.cpp
  5. 34
      libethereum/BlockChain.h
  6. 5
      libethereum/BlockDetails.cpp
  7. 17
      libethereum/BlockDetails.h
  8. 1
      libethereum/Client.cpp

7
alethzero/Main.ui

@ -38,6 +38,13 @@
</property> </property>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_7"> <layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QLabel" name="cacheUsage">
<property name="text">
<string>0 bytes used</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QLabel" name="balance"> <widget class="QLabel" name="balance">
<property name="text"> <property name="text">

8
alethzero/MainWin.cpp

@ -141,6 +141,7 @@ Main::Main(QWidget *parent) :
ui->configDock->close(); ui->configDock->close();
on_verbosity_valueChanged(); on_verbosity_valueChanged();
statusBar()->addPermanentWidget(ui->cacheUsage);
statusBar()->addPermanentWidget(ui->balance); statusBar()->addPermanentWidget(ui->balance);
statusBar()->addPermanentWidget(ui->peerCount); statusBar()->addPermanentWidget(ui->peerCount);
statusBar()->addPermanentWidget(ui->mineStatus); statusBar()->addPermanentWidget(ui->mineStatus);
@ -1144,6 +1145,12 @@ void Main::on_refresh_triggered()
refreshAll(); refreshAll();
} }
void Main::refreshCache()
{
BlockChain::Statistics s = ethereum()->blockChain().usage();
ui->cacheUsage->setText(QString("%1 bytes used").arg(s.memTotal()));
}
void Main::timerEvent(QTimerEvent*) void Main::timerEvent(QTimerEvent*)
{ {
// 7/18, Alex: aggregating timers, prelude to better threading? // 7/18, Alex: aggregating timers, prelude to better threading?
@ -1172,6 +1179,7 @@ void Main::timerEvent(QTimerEvent*)
interval = 0; interval = 0;
refreshNetwork(); refreshNetwork();
refreshWhispers(); refreshWhispers();
refreshCache();
poll(); poll();
} }
else else

1
alethzero/MainWin.h

@ -212,6 +212,7 @@ private:
void refreshNetwork(); void refreshNetwork();
void refreshMining(); void refreshMining();
void refreshWhispers(); void refreshWhispers();
void refreshCache();
void refreshAll(); void refreshAll();
void refreshPending(); void refreshPending();

124
libethereum/BlockChain.cpp

@ -76,8 +76,33 @@ ldb::Slice dev::eth::toSlice(h256 _h, unsigned _sub)
#endif #endif
} }
#if ETH_DEBUG
static const chrono::system_clock::duration c_collectionDuration = chrono::seconds(15);
static const unsigned c_collectionQueueSize = 2;
static const unsigned c_maxCacheSize = 1024 * 1024 * 1;
static const unsigned c_minCacheSize = 1;
#else
/// Duration between flushes.
static const chrono::system_clock::duration c_collectionDuration = chrono::seconds(60);
/// Length of death row (total time in cache is multiple of this and collection duration).
static const unsigned c_collectionQueueSize = 20;
/// Max size, above which we start forcing cache reduction.
static const unsigned c_maxCacheSize = 1024 * 1024 * 64;
/// Min size, below which we don't bother flushing it.
static const unsigned c_minCacheSize = 1024 * 1024 * 32;
#endif
BlockChain::BlockChain(bytes const& _genesisBlock, std::string _path, bool _killExisting) BlockChain::BlockChain(bytes const& _genesisBlock, std::string _path, bool _killExisting)
{ {
// initialise deathrow.
m_cacheUsage.resize(c_collectionQueueSize);
m_lastCollection = chrono::system_clock::now();
// Initialise with the genesis as the last block on the longest chain. // Initialise with the genesis as the last block on the longest chain.
m_genesisBlock = _genesisBlock; m_genesisBlock = _genesisBlock;
m_genesisHash = sha3(RLP(m_genesisBlock)[0].data()); m_genesisHash = sha3(RLP(m_genesisBlock)[0].data());
@ -428,6 +453,103 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo
return ret; return ret;
} }
void BlockChain::noteUsed(h256 const& _h, unsigned _extra) const
{
auto id = CacheID(_h, _extra);
Guard l(x_cacheUsage);
m_cacheUsage[0].insert(id);
if (m_cacheUsage[1].count(id))
m_cacheUsage[1].erase(id);
else
m_inUse.insert(id);
}
template <class T> static unsigned getHashSize(map<h256, T> const& _map)
{
unsigned ret = 0;
for (auto const& i: _map)
ret += i.second.size + 64;
return ret;
}
void BlockChain::updateStats() const
{
{
ReadGuard l1(x_blocks);
m_lastStats.memBlocks = 0;
for (auto const& i: m_blocks)
m_lastStats.memBlocks += i.second.size() + 64;
}
{
ReadGuard l2(x_details);
m_lastStats.memDetails = getHashSize(m_details);
}
{
ReadGuard l5(x_logBlooms);
m_lastStats.memLogBlooms = getHashSize(m_logBlooms);
}
{
ReadGuard l4(x_receipts);
m_lastStats.memReceipts = getHashSize(m_receipts);
}
{
ReadGuard l3(x_blockHashes);
m_lastStats.memBlockHashes = getHashSize(m_blockHashes);
}
{
ReadGuard l6(x_transactionAddresses);
m_lastStats.memTransactionAddresses = getHashSize(m_transactionAddresses);
}
}
void BlockChain::garbageCollect(bool _force)
{
updateStats();
if (!_force && chrono::system_clock::now() < m_lastCollection + c_collectionDuration && m_lastStats.memTotal() < c_maxCacheSize)
return;
if (m_lastStats.memTotal() < c_minCacheSize)
return;
m_lastCollection = chrono::system_clock::now();
Guard l(x_cacheUsage);
WriteGuard l1(x_blocks);
WriteGuard l2(x_details);
WriteGuard l3(x_blockHashes);
WriteGuard l4(x_receipts);
WriteGuard l5(x_logBlooms);
WriteGuard l6(x_transactionAddresses);
for (CacheID const& id: m_cacheUsage.back())
{
m_inUse.erase(id);
// kill i from cache.
switch (id.second)
{
case (unsigned)-1:
m_blocks.erase(id.first);
break;
case ExtraDetails:
m_details.erase(id.first);
break;
case ExtraBlockHash:
m_blockHashes.erase(id.first);
break;
case ExtraReceipts:
m_receipts.erase(id.first);
break;
case ExtraLogBlooms:
m_logBlooms.erase(id.first);
break;
case ExtraTransactionAddress:
m_transactionAddresses.erase(id.first);
break;
}
}
m_cacheUsage.pop_back();
m_cacheUsage.push_front({});
}
void BlockChain::checkConsistency() void BlockChain::checkConsistency()
{ {
{ {
@ -511,5 +633,7 @@ bytes BlockChain::block(h256 _hash) const
m_blocks[_hash].resize(d.size()); m_blocks[_hash].resize(d.size());
memcpy(m_blocks[_hash].data(), d.data(), d.size()); memcpy(m_blocks[_hash].data(), d.data(), d.size());
noteUsed(_hash);
return m_blocks[_hash]; return m_blocks[_hash];
} }

34
libethereum/BlockChain.h

@ -26,7 +26,7 @@
#include <leveldb/db.h> #include <leveldb/db.h>
#pragma warning(pop) #pragma warning(pop)
#include <mutex> #include <chrono>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/Exceptions.h> #include <libdevcore/Exceptions.h>
#include <libethcore/Common.h> #include <libethcore/Common.h>
@ -171,18 +171,20 @@ public:
struct Statistics struct Statistics
{ {
unsigned memBlocks;
unsigned memDetails; unsigned memDetails;
unsigned memLogBlooms; unsigned memLogBlooms;
unsigned memReceipts; unsigned memReceipts;
unsigned memTransactionAddresses; unsigned memTransactionAddresses;
unsigned memCache; unsigned memBlockHashes;
unsigned memTotal() const { return memBlocks + memDetails + memLogBlooms + memReceipts + memTransactionAddresses + memBlockHashes; }
}; };
/// @returns statistics about memory usage. /// @returns statistics about memory usage.
Statistics usage() const; Statistics usage(bool _freshen = false) const { if (_freshen) updateStats(); return m_lastStats; }
/// Deallocate unused data. /// Deallocate unused data.
void garbageCollect(); void garbageCollect(bool _force = false);
private: private:
void open(std::string _path, bool _killExisting = false); void open(std::string _path, bool _killExisting = false);
@ -205,6 +207,8 @@ private:
return _n; return _n;
} }
noteUsed(_h, N);
WriteGuard l(_x); WriteGuard l(_x);
auto ret = _m.insert(std::make_pair(_h, T(RLP(s)))); auto ret = _m.insert(std::make_pair(_h, T(RLP(s))));
return ret.first->second; return ret.first->second;
@ -213,19 +217,29 @@ private:
void checkConsistency(); void checkConsistency();
/// The caches of the disk DB and their locks. /// The caches of the disk DB and their locks.
mutable boost::shared_mutex x_blocks; mutable SharedMutex x_blocks;
mutable BlocksHash m_blocks; mutable BlocksHash m_blocks;
mutable boost::shared_mutex x_details; mutable SharedMutex x_details;
mutable BlockDetailsHash m_details; mutable BlockDetailsHash m_details;
mutable boost::shared_mutex x_logBlooms; mutable SharedMutex x_logBlooms;
mutable BlockLogBloomsHash m_logBlooms; mutable BlockLogBloomsHash m_logBlooms;
mutable boost::shared_mutex x_receipts; mutable SharedMutex x_receipts;
mutable BlockReceiptsHash m_receipts; mutable BlockReceiptsHash m_receipts;
mutable boost::shared_mutex x_transactionAddresses; mutable SharedMutex x_transactionAddresses;
mutable TransactionAddressHash m_transactionAddresses; mutable TransactionAddressHash m_transactionAddresses;
mutable boost::shared_mutex x_blockHashes; mutable SharedMutex x_blockHashes;
mutable BlockHashHash m_blockHashes; mutable BlockHashHash m_blockHashes;
using CacheID = std::pair<h256, unsigned>;
mutable Mutex x_cacheUsage;
mutable std::deque<std::set<CacheID>> m_cacheUsage;
mutable std::set<CacheID> m_inUse;
void noteUsed(h256 const& _h, unsigned _extra = (unsigned)-1) const;
std::chrono::system_clock::time_point m_lastCollection;
void updateStats() const;
mutable Statistics m_lastStats;
/// The disk DBs. Thread-safe, so no need for locks. /// The disk DBs. Thread-safe, so no need for locks.
ldb::DB* m_blocksDB; ldb::DB* m_blocksDB;
ldb::DB* m_extrasDB; ldb::DB* m_extrasDB;

5
libethereum/BlockDetails.cpp

@ -32,9 +32,12 @@ BlockDetails::BlockDetails(RLP const& _r)
totalDifficulty = _r[1].toInt<u256>(); totalDifficulty = _r[1].toInt<u256>();
parent = _r[2].toHash<h256>(); parent = _r[2].toHash<h256>();
children = _r[3].toVector<h256>(); children = _r[3].toVector<h256>();
size = _r.size();
} }
bytes BlockDetails::rlp() const bytes BlockDetails::rlp() const
{ {
return rlpList(number, totalDifficulty, parent, children); auto ret = rlpList(number, totalDifficulty, parent, children);
size = ret.size();
return ret;
} }

17
libethereum/BlockDetails.h

@ -46,28 +46,32 @@ struct BlockDetails
bool isNull() const { return !totalDifficulty; } bool isNull() const { return !totalDifficulty; }
explicit operator bool() const { return !isNull(); } explicit operator bool() const { return !isNull(); }
unsigned number; // TODO: remove? unsigned number;
u256 totalDifficulty; u256 totalDifficulty;
h256 parent; h256 parent;
h256s children; h256s children;
mutable unsigned size;
}; };
struct BlockLogBlooms struct BlockLogBlooms
{ {
BlockLogBlooms() {} BlockLogBlooms() {}
BlockLogBlooms(RLP const& _r) { blooms = _r.toVector<LogBloom>(); } BlockLogBlooms(RLP const& _r) { blooms = _r.toVector<LogBloom>(); size = _r.data().size(); }
bytes rlp() const { RLPStream s; s << blooms; return s.out(); } bytes rlp() const { RLPStream s; s << blooms; size = s.out().size(); return s.out(); }
LogBlooms blooms; LogBlooms blooms;
mutable unsigned size;
}; };
struct BlockReceipts struct BlockReceipts
{ {
BlockReceipts() {} BlockReceipts() {}
BlockReceipts(RLP const& _r) { for (auto const& i: _r) receipts.emplace_back(i.data()); } BlockReceipts(RLP const& _r) { for (auto const& i: _r) receipts.emplace_back(i.data()); size = _r.data().size(); }
bytes rlp() const { RLPStream s(receipts.size()); for (TransactionReceipt const& i: receipts) i.streamRLP(s); return s.out(); } bytes rlp() const { RLPStream s(receipts.size()); for (TransactionReceipt const& i: receipts) i.streamRLP(s); size = s.out().size(); return s.out(); }
TransactionReceipts receipts; TransactionReceipts receipts;
mutable unsigned size;
}; };
struct BlockHash struct BlockHash
@ -77,6 +81,7 @@ struct BlockHash
bytes rlp() const { return dev::rlp(value); } bytes rlp() const { return dev::rlp(value); }
h256 value; h256 value;
static const unsigned size = 65;
}; };
struct TransactionAddress struct TransactionAddress
@ -89,6 +94,8 @@ struct TransactionAddress
h256 blockHash; h256 blockHash;
unsigned index = 0; unsigned index = 0;
static const unsigned size = 67;
}; };
using BlockDetailsHash = std::map<h256, BlockDetails>; using BlockDetailsHash = std::map<h256, BlockDetails>;

1
libethereum/Client.cpp

@ -635,6 +635,7 @@ void Client::doWork()
uninstallWatch(i); uninstallWatch(i);
m_lastGarbageCollection = chrono::system_clock::now(); m_lastGarbageCollection = chrono::system_clock::now();
} }
m_bc.garbageCollect();
} }
unsigned Client::numberOf(int _n) const unsigned Client::numberOf(int _n) const

Loading…
Cancel
Save