Skip to content

Commit 5ce68e6

Browse files
committed
Add runtime LevelDB pruning: batch-delete shares evicted by clean_tracker
Matches p2pool main.py:269-270 (tracker.removed.watch → ss.forget_share). Previously LevelDB was only pruned at startup, growing unbounded at runtime. Now chain.on_removed buffers hashes, flushed as atomic WriteBatch after drop-tails. Crash-safe: unflushed shares cleaned up by load_persisted_shares.
1 parent 03a865b commit 5ce68e6

6 files changed

Lines changed: 74 additions & 0 deletions

File tree

src/c2pool/storage/sharechain_storage.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,13 @@ bool SharechainStorage::remove_share(const uint256& hash)
182182
return m_leveldb_store->remove_share(hash);
183183
}
184184

185+
bool SharechainStorage::remove_shares_batch(const std::vector<uint256>& hashes)
186+
{
187+
if (!m_leveldb_store || hashes.empty())
188+
return false;
189+
return m_leveldb_store->remove_shares_batch(hashes);
190+
}
191+
185192
bool SharechainStorage::load_share(const uint256& hash, std::vector<uint8_t>& serialized_data,
186193
core::ShareMetadata& metadata)
187194
{

src/c2pool/storage/sharechain_storage.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ class SharechainStorage {
125125
*/
126126
bool remove_share(const uint256& hash);
127127

128+
/// Batch-remove multiple shares from LevelDB in one WriteBatch.
129+
bool remove_shares_batch(const std::vector<uint256>& hashes);
130+
128131
/// Batch-mark shares as verified in LevelDB metadata.
129132
bool mark_shares_verified(const std::vector<uint256>& hashes);
130133

src/core/leveldb_store.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,46 @@ bool SharechainLevelDBStore::remove_share(const uint256& hash)
678678
}
679679
}
680680

681+
bool SharechainLevelDBStore::remove_shares_batch(const std::vector<uint256>& hashes)
682+
{
683+
if (!m_store || hashes.empty())
684+
return false;
685+
686+
try {
687+
auto batch = m_store->create_batch();
688+
size_t removed = 0;
689+
690+
for (const auto& hash : hashes)
691+
{
692+
// Load metadata for height key removal
693+
ShareMetadata metadata;
694+
std::vector<uint8_t> dummy;
695+
bool had_meta = load_share(hash, dummy, metadata);
696+
697+
batch.remove(make_share_key(hash));
698+
batch.remove(make_index_key(hash));
699+
if (had_meta && metadata.height > 0)
700+
batch.remove(make_height_key(metadata.height));
701+
++removed;
702+
}
703+
704+
if (!batch.commit()) {
705+
LOG_ERROR << "[LevelDB] batch remove failed, count=" << hashes.size();
706+
return false;
707+
}
708+
709+
if (m_metadata.total_shares >= removed)
710+
m_metadata.total_shares -= removed;
711+
else
712+
m_metadata.total_shares = 0;
713+
714+
return true;
715+
} catch (const std::exception& e) {
716+
LOG_ERROR << "[LevelDB] batch remove exception: " << e.what();
717+
return false;
718+
}
719+
}
720+
681721
bool SharechainLevelDBStore::mark_shares_verified(const std::vector<uint256>& hashes)
682722
{
683723
if (!m_store || hashes.empty())

src/core/leveldb_store.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ class SharechainLevelDBStore
166166
bool has_share(const uint256& hash);
167167
bool remove_share(const uint256& hash);
168168

169+
/// Batch-remove multiple shares in a single WriteBatch (much faster than per-share remove).
170+
bool remove_shares_batch(const std::vector<uint256>& hashes);
171+
169172
/// Batch-update the is_verified flag for multiple shares without rewriting share data.
170173
bool mark_shares_verified(const std::vector<uint256>& hashes);
171174

src/impl/ltc/node.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1607,6 +1607,17 @@ void NodeImpl::clean_tracker()
16071607
// Step 4: Update best share (p2pool node.py:402)
16081608
run_think();
16091609

1610+
// Step 5: Flush pruned shares from LevelDB (p2pool main.py:269-270)
1611+
if (!m_removal_flush_buf.empty() && m_storage && m_storage->is_available())
1612+
{
1613+
auto count = m_removal_flush_buf.size();
1614+
if (m_storage->remove_shares_batch(m_removal_flush_buf))
1615+
LOG_INFO << "[clean-leveldb] removed " << count << " pruned shares from LevelDB";
1616+
else
1617+
LOG_WARNING << "[clean-leveldb] batch remove failed, count=" << count;
1618+
m_removal_flush_buf.clear();
1619+
}
1620+
16101621
// Orphan/fork diagnostics — understand chain topology
16111622
{
16121623
auto& chain = m_tracker.chain;

src/impl/ltc/node.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ class NodeImpl : public pool::BaseNode<ltc::Config, ltc::ShareChain, ltc::Peer>
6767
// Buffer of newly verified share hashes, flushed to LevelDB periodically
6868
std::vector<uint256> m_verified_flush_buf;
6969

70+
// Buffer of pruned share hashes, batch-deleted from LevelDB after clean_tracker()
71+
std::vector<uint256> m_removal_flush_buf;
72+
7073
public:
7174
NodeImpl()
7275
: m_share_getter(nullptr,
@@ -103,6 +106,13 @@ class NodeImpl : public pool::BaseNode<ltc::Config, ltc::ShareChain, ltc::Peer>
103106
if (m_verified_flush_buf.size() >= 50)
104107
flush_verified_to_leveldb();
105108
};
109+
110+
// Wire up share removal → LevelDB cleanup (p2pool main.py:269-270)
111+
// Buffer removals; clean_tracker() flushes after drop-tails.
112+
// Safe on crash: unflushed shares get pruned at next startup by load_persisted_shares().
113+
m_tracker.chain.on_removed([this](const uint256& hash) {
114+
m_removal_flush_buf.push_back(hash);
115+
});
106116
}
107117

108118
// INetwork: Pool node does not initiate disconnect — peer connections

0 commit comments

Comments
 (0)