mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
instantsend: optimize db and cache usage (#3986)
* instantsend: keep islocks cache when removing confirmed islocks from db unordered_lru_cache should truncate it automagically * instantsend: Batched write/erase for connected/disconnected blocks
This commit is contained in:
parent
821210a2ca
commit
0b591043a0
@ -65,10 +65,10 @@ void CInstantSendDb::WriteNewInstantSendLock(const uint256& hash, const CInstant
|
||||
}
|
||||
}
|
||||
|
||||
void CInstantSendDb::RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, CInstantSendLockPtr islock)
|
||||
void CInstantSendDb::RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, CInstantSendLockPtr islock, bool keep_cache)
|
||||
{
|
||||
if (!islock) {
|
||||
islock = GetInstantSendLockByHash(hash);
|
||||
islock = GetInstantSendLockByHash(hash, false);
|
||||
if (!islock) {
|
||||
return;
|
||||
}
|
||||
@ -80,10 +80,12 @@ void CInstantSendDb::RemoveInstantSendLock(CDBBatch& batch, const uint256& hash,
|
||||
batch.Erase(std::make_tuple(std::string(DB_HASH_BY_OUTPOINT), in));
|
||||
}
|
||||
|
||||
islockCache.erase(hash);
|
||||
txidCache.erase(islock->txid);
|
||||
for (auto& in : islock->inputs) {
|
||||
outpointCache.erase(in);
|
||||
if (!keep_cache) {
|
||||
islockCache.erase(hash);
|
||||
txidCache.erase(islock->txid);
|
||||
for (auto& in : islock->inputs) {
|
||||
outpointCache.erase(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,12 +96,19 @@ static std::tuple<std::string, uint32_t, uint256> BuildInversedISLockKey(const s
|
||||
|
||||
void CInstantSendDb::WriteInstantSendLockMined(const uint256& hash, int nHeight)
|
||||
{
|
||||
db.Write(BuildInversedISLockKey(DB_MINED_BY_HEIGHT_AND_HASH, nHeight, hash), true);
|
||||
CDBBatch batch(db);
|
||||
WriteInstantSendLockMined(batch, hash, nHeight);
|
||||
db.WriteBatch(batch);
|
||||
}
|
||||
|
||||
void CInstantSendDb::RemoveInstantSendLockMined(const uint256& hash, int nHeight)
|
||||
void CInstantSendDb::WriteInstantSendLockMined(CDBBatch& batch, const uint256& hash, int nHeight)
|
||||
{
|
||||
db.Erase(BuildInversedISLockKey(DB_MINED_BY_HEIGHT_AND_HASH, nHeight, hash));
|
||||
batch.Write(BuildInversedISLockKey(DB_MINED_BY_HEIGHT_AND_HASH, nHeight, hash), true);
|
||||
}
|
||||
|
||||
void CInstantSendDb::RemoveInstantSendLockMined(CDBBatch& batch, const uint256& hash, int nHeight)
|
||||
{
|
||||
batch.Erase(BuildInversedISLockKey(DB_MINED_BY_HEIGHT_AND_HASH, nHeight, hash));
|
||||
}
|
||||
|
||||
void CInstantSendDb::WriteInstantSendLockArchived(CDBBatch& batch, const uint256& hash, int nHeight)
|
||||
@ -133,7 +142,7 @@ std::unordered_map<uint256, CInstantSendLockPtr> CInstantSendDb::RemoveConfirmed
|
||||
}
|
||||
|
||||
auto& islockHash = std::get<2>(curKey);
|
||||
auto islock = GetInstantSendLockByHash(islockHash);
|
||||
auto islock = GetInstantSendLockByHash(islockHash, false);
|
||||
if (islock) {
|
||||
RemoveInstantSendLock(batch, islockHash, islock);
|
||||
ret.emplace(islockHash, islock);
|
||||
@ -185,6 +194,39 @@ void CInstantSendDb::RemoveArchivedInstantSendLocks(int nUntilHeight)
|
||||
db.WriteBatch(batch);
|
||||
}
|
||||
|
||||
void CInstantSendDb::WriteBlockInstantSendLocks(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected)
|
||||
{
|
||||
CDBBatch batch(db);
|
||||
for (const auto& tx : pblock->vtx) {
|
||||
if (tx->IsCoinBase() || tx->vin.empty()) {
|
||||
// coinbase and TXs with no inputs can't be locked
|
||||
continue;
|
||||
}
|
||||
uint256 islockHash = GetInstantSendLockHashByTxid(tx->GetHash());
|
||||
// update DB about when an IS lock was mined
|
||||
if (!islockHash.IsNull()) {
|
||||
WriteInstantSendLockMined(batch, islockHash, pindexConnected->nHeight);
|
||||
}
|
||||
}
|
||||
db.WriteBatch(batch);
|
||||
}
|
||||
|
||||
void CInstantSendDb::RemoveBlockInstantSendLocks(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexDisconnected)
|
||||
{
|
||||
CDBBatch batch(db);
|
||||
for (const auto& tx : pblock->vtx) {
|
||||
if (tx->IsCoinBase() || tx->vin.empty()) {
|
||||
// coinbase and TXs with no inputs can't be locked
|
||||
continue;
|
||||
}
|
||||
uint256 islockHash = GetInstantSendLockHashByTxid(tx->GetHash());
|
||||
if (!islockHash.IsNull()) {
|
||||
RemoveInstantSendLockMined(batch, islockHash, pindexDisconnected->nHeight);
|
||||
}
|
||||
}
|
||||
db.WriteBatch(batch);
|
||||
}
|
||||
|
||||
bool CInstantSendDb::KnownInstantSendLock(const uint256& islockHash) const
|
||||
{
|
||||
return GetInstantSendLockByHash(islockHash) != nullptr || db.Exists(std::make_tuple(std::string(DB_ARCHIVED_BY_HASH), islockHash));
|
||||
@ -212,14 +254,14 @@ size_t CInstantSendDb::GetInstantSendLockCount() const
|
||||
return cnt;
|
||||
}
|
||||
|
||||
CInstantSendLockPtr CInstantSendDb::GetInstantSendLockByHash(const uint256& hash) const
|
||||
CInstantSendLockPtr CInstantSendDb::GetInstantSendLockByHash(const uint256& hash, bool use_cache) const
|
||||
{
|
||||
if (hash.IsNull()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CInstantSendLockPtr ret;
|
||||
if (islockCache.get(hash, ret)) {
|
||||
if (use_cache && islockCache.get(hash, ret)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -300,12 +342,12 @@ std::vector<uint256> CInstantSendDb::RemoveChainedInstantSendLocks(const uint256
|
||||
stack.pop_back();
|
||||
|
||||
for (auto& childIslockHash : children) {
|
||||
auto childIsLock = GetInstantSendLockByHash(childIslockHash);
|
||||
auto childIsLock = GetInstantSendLockByHash(childIslockHash, false);
|
||||
if (!childIsLock) {
|
||||
continue;
|
||||
}
|
||||
|
||||
RemoveInstantSendLock(batch, childIslockHash, childIsLock);
|
||||
RemoveInstantSendLock(batch, childIslockHash, childIsLock, false);
|
||||
WriteInstantSendLockArchived(batch, childIslockHash, nHeight);
|
||||
result.emplace_back(childIslockHash);
|
||||
|
||||
@ -315,7 +357,7 @@ std::vector<uint256> CInstantSendDb::RemoveChainedInstantSendLocks(const uint256
|
||||
}
|
||||
}
|
||||
|
||||
RemoveInstantSendLock(batch, islockHash, nullptr);
|
||||
RemoveInstantSendLock(batch, islockHash, nullptr, false);
|
||||
WriteInstantSendLockArchived(batch, islockHash, nHeight);
|
||||
result.emplace_back(islockHash);
|
||||
|
||||
@ -995,49 +1037,34 @@ void CInstantSendManager::BlockConnected(const std::shared_ptr<const CBlock>& pb
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& tx : pblock->vtx) {
|
||||
if (tx->IsCoinBase() || tx->vin.empty()) {
|
||||
// coinbase and TXs with no inputs can't be locked
|
||||
continue;
|
||||
}
|
||||
if (masternodeSync.IsBlockchainSynced()) {
|
||||
for (const auto& tx : pblock->vtx) {
|
||||
if (tx->IsCoinBase() || tx->vin.empty()) {
|
||||
// coinbase and TXs with no inputs can't be locked
|
||||
continue;
|
||||
}
|
||||
|
||||
uint256 islockHash;
|
||||
{
|
||||
LOCK(cs);
|
||||
islockHash = db.GetInstantSendLockHashByTxid(tx->GetHash());
|
||||
|
||||
// update DB about when an IS lock was mined
|
||||
if (!islockHash.IsNull()) {
|
||||
db.WriteInstantSendLockMined(islockHash, pindex->nHeight);
|
||||
if (!IsLocked(tx->GetHash()) && !chainLocksHandler->HasChainLock(pindex->nHeight, pindex->GetBlockHash())) {
|
||||
ProcessTx(*tx, true, Params().GetConsensus());
|
||||
// TX is not locked, so make sure it is tracked
|
||||
LOCK(cs);
|
||||
AddNonLockedTx(tx, pindex);
|
||||
} else {
|
||||
// TX is locked, so make sure we don't track it anymore
|
||||
LOCK(cs);
|
||||
RemoveNonLockedTx(tx->GetHash(), true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!masternodeSync.IsBlockchainSynced()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (islockHash.IsNull() && !chainLocksHandler->HasChainLock(pindex->nHeight, pindex->GetBlockHash())) {
|
||||
ProcessTx(*tx, true, Params().GetConsensus());
|
||||
// TX is not locked, so make sure it is tracked
|
||||
LOCK(cs);
|
||||
AddNonLockedTx(tx, pindex);
|
||||
} else {
|
||||
// TX is locked, so make sure we don't track it anymore
|
||||
LOCK(cs);
|
||||
RemoveNonLockedTx(tx->GetHash(), true);
|
||||
}
|
||||
}
|
||||
|
||||
LOCK(cs);
|
||||
db.WriteBlockInstantSendLocks(pblock, pindex);
|
||||
}
|
||||
|
||||
void CInstantSendManager::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexDisconnected)
|
||||
{
|
||||
LOCK(cs);
|
||||
for (auto& tx : pblock->vtx) {
|
||||
auto islockHash = db.GetInstantSendLockHashByTxid(tx->GetHash());
|
||||
if (!islockHash.IsNull()) {
|
||||
db.RemoveInstantSendLockMined(islockHash, pindexDisconnected->nHeight);
|
||||
}
|
||||
}
|
||||
db.RemoveBlockInstantSendLocks(pblock, pindexDisconnected);
|
||||
}
|
||||
|
||||
void CInstantSendManager::AddNonLockedTx(const CTransactionRef& tx, const CBlockIndex* pindexMined)
|
||||
|
@ -49,21 +49,25 @@ private:
|
||||
mutable unordered_lru_cache<uint256, uint256, StaticSaltedHasher, 10000> txidCache;
|
||||
mutable unordered_lru_cache<COutPoint, uint256, SaltedOutpointHasher, 10000> outpointCache;
|
||||
|
||||
void WriteInstantSendLockMined(CDBBatch& batch, const uint256& hash, int nHeight);
|
||||
void RemoveInstantSendLockMined(CDBBatch& batch, const uint256& hash, int nHeight);
|
||||
|
||||
public:
|
||||
explicit CInstantSendDb(CDBWrapper& _db) : db(_db) {}
|
||||
|
||||
void WriteNewInstantSendLock(const uint256& hash, const CInstantSendLock& islock);
|
||||
void RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, CInstantSendLockPtr islock);
|
||||
void RemoveInstantSendLock(CDBBatch& batch, const uint256& hash, CInstantSendLockPtr islock, bool keep_cache = true);
|
||||
|
||||
void WriteInstantSendLockMined(const uint256& hash, int nHeight);
|
||||
void RemoveInstantSendLockMined(const uint256& hash, int nHeight);
|
||||
static void WriteInstantSendLockArchived(CDBBatch& batch, const uint256& hash, int nHeight);
|
||||
std::unordered_map<uint256, CInstantSendLockPtr> RemoveConfirmedInstantSendLocks(int nUntilHeight);
|
||||
void RemoveArchivedInstantSendLocks(int nUntilHeight);
|
||||
void WriteBlockInstantSendLocks(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected);
|
||||
void RemoveBlockInstantSendLocks(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexDisconnected);
|
||||
bool KnownInstantSendLock(const uint256& islockHash) const;
|
||||
size_t GetInstantSendLockCount() const;
|
||||
|
||||
CInstantSendLockPtr GetInstantSendLockByHash(const uint256& hash) const;
|
||||
CInstantSendLockPtr GetInstantSendLockByHash(const uint256& hash, bool use_cache = true) const;
|
||||
uint256 GetInstantSendLockHashByTxid(const uint256& txid) const;
|
||||
CInstantSendLockPtr GetInstantSendLockByTxid(const uint256& txid) const;
|
||||
CInstantSendLockPtr GetInstantSendLockByInput(const COutPoint& outpoint) const;
|
||||
|
Loading…
Reference in New Issue
Block a user