mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 12:32: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) {
|
if (!islock) {
|
||||||
islock = GetInstantSendLockByHash(hash);
|
islock = GetInstantSendLockByHash(hash, false);
|
||||||
if (!islock) {
|
if (!islock) {
|
||||||
return;
|
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));
|
batch.Erase(std::make_tuple(std::string(DB_HASH_BY_OUTPOINT), in));
|
||||||
}
|
}
|
||||||
|
|
||||||
islockCache.erase(hash);
|
if (!keep_cache) {
|
||||||
txidCache.erase(islock->txid);
|
islockCache.erase(hash);
|
||||||
for (auto& in : islock->inputs) {
|
txidCache.erase(islock->txid);
|
||||||
outpointCache.erase(in);
|
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)
|
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)
|
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& islockHash = std::get<2>(curKey);
|
||||||
auto islock = GetInstantSendLockByHash(islockHash);
|
auto islock = GetInstantSendLockByHash(islockHash, false);
|
||||||
if (islock) {
|
if (islock) {
|
||||||
RemoveInstantSendLock(batch, islockHash, islock);
|
RemoveInstantSendLock(batch, islockHash, islock);
|
||||||
ret.emplace(islockHash, islock);
|
ret.emplace(islockHash, islock);
|
||||||
@ -185,6 +194,39 @@ void CInstantSendDb::RemoveArchivedInstantSendLocks(int nUntilHeight)
|
|||||||
db.WriteBatch(batch);
|
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
|
bool CInstantSendDb::KnownInstantSendLock(const uint256& islockHash) const
|
||||||
{
|
{
|
||||||
return GetInstantSendLockByHash(islockHash) != nullptr || db.Exists(std::make_tuple(std::string(DB_ARCHIVED_BY_HASH), islockHash));
|
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;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
CInstantSendLockPtr CInstantSendDb::GetInstantSendLockByHash(const uint256& hash) const
|
CInstantSendLockPtr CInstantSendDb::GetInstantSendLockByHash(const uint256& hash, bool use_cache) const
|
||||||
{
|
{
|
||||||
if (hash.IsNull()) {
|
if (hash.IsNull()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CInstantSendLockPtr ret;
|
CInstantSendLockPtr ret;
|
||||||
if (islockCache.get(hash, ret)) {
|
if (use_cache && islockCache.get(hash, ret)) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,12 +342,12 @@ std::vector<uint256> CInstantSendDb::RemoveChainedInstantSendLocks(const uint256
|
|||||||
stack.pop_back();
|
stack.pop_back();
|
||||||
|
|
||||||
for (auto& childIslockHash : children) {
|
for (auto& childIslockHash : children) {
|
||||||
auto childIsLock = GetInstantSendLockByHash(childIslockHash);
|
auto childIsLock = GetInstantSendLockByHash(childIslockHash, false);
|
||||||
if (!childIsLock) {
|
if (!childIsLock) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoveInstantSendLock(batch, childIslockHash, childIsLock);
|
RemoveInstantSendLock(batch, childIslockHash, childIsLock, false);
|
||||||
WriteInstantSendLockArchived(batch, childIslockHash, nHeight);
|
WriteInstantSendLockArchived(batch, childIslockHash, nHeight);
|
||||||
result.emplace_back(childIslockHash);
|
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);
|
WriteInstantSendLockArchived(batch, islockHash, nHeight);
|
||||||
result.emplace_back(islockHash);
|
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 (masternodeSync.IsBlockchainSynced()) {
|
||||||
if (tx->IsCoinBase() || tx->vin.empty()) {
|
for (const auto& tx : pblock->vtx) {
|
||||||
// coinbase and TXs with no inputs can't be locked
|
if (tx->IsCoinBase() || tx->vin.empty()) {
|
||||||
continue;
|
// coinbase and TXs with no inputs can't be locked
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
uint256 islockHash;
|
if (!IsLocked(tx->GetHash()) && !chainLocksHandler->HasChainLock(pindex->nHeight, pindex->GetBlockHash())) {
|
||||||
{
|
ProcessTx(*tx, true, Params().GetConsensus());
|
||||||
LOCK(cs);
|
// TX is not locked, so make sure it is tracked
|
||||||
islockHash = db.GetInstantSendLockHashByTxid(tx->GetHash());
|
LOCK(cs);
|
||||||
|
AddNonLockedTx(tx, pindex);
|
||||||
// update DB about when an IS lock was mined
|
} else {
|
||||||
if (!islockHash.IsNull()) {
|
// TX is locked, so make sure we don't track it anymore
|
||||||
db.WriteInstantSendLockMined(islockHash, pindex->nHeight);
|
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)
|
void CInstantSendManager::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexDisconnected)
|
||||||
{
|
{
|
||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
for (auto& tx : pblock->vtx) {
|
db.RemoveBlockInstantSendLocks(pblock, pindexDisconnected);
|
||||||
auto islockHash = db.GetInstantSendLockHashByTxid(tx->GetHash());
|
|
||||||
if (!islockHash.IsNull()) {
|
|
||||||
db.RemoveInstantSendLockMined(islockHash, pindexDisconnected->nHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CInstantSendManager::AddNonLockedTx(const CTransactionRef& tx, const CBlockIndex* pindexMined)
|
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<uint256, uint256, StaticSaltedHasher, 10000> txidCache;
|
||||||
mutable unordered_lru_cache<COutPoint, uint256, SaltedOutpointHasher, 10000> outpointCache;
|
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:
|
public:
|
||||||
explicit CInstantSendDb(CDBWrapper& _db) : db(_db) {}
|
explicit CInstantSendDb(CDBWrapper& _db) : db(_db) {}
|
||||||
|
|
||||||
void WriteNewInstantSendLock(const uint256& hash, const CInstantSendLock& islock);
|
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 WriteInstantSendLockMined(const uint256& hash, int nHeight);
|
||||||
void RemoveInstantSendLockMined(const uint256& hash, int nHeight);
|
|
||||||
static void WriteInstantSendLockArchived(CDBBatch& batch, const uint256& hash, int nHeight);
|
static void WriteInstantSendLockArchived(CDBBatch& batch, const uint256& hash, int nHeight);
|
||||||
std::unordered_map<uint256, CInstantSendLockPtr> RemoveConfirmedInstantSendLocks(int nUntilHeight);
|
std::unordered_map<uint256, CInstantSendLockPtr> RemoveConfirmedInstantSendLocks(int nUntilHeight);
|
||||||
void RemoveArchivedInstantSendLocks(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;
|
bool KnownInstantSendLock(const uint256& islockHash) const;
|
||||||
size_t GetInstantSendLockCount() 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;
|
uint256 GetInstantSendLockHashByTxid(const uint256& txid) const;
|
||||||
CInstantSendLockPtr GetInstantSendLockByTxid(const uint256& txid) const;
|
CInstantSendLockPtr GetInstantSendLockByTxid(const uint256& txid) const;
|
||||||
CInstantSendLockPtr GetInstantSendLockByInput(const COutPoint& outpoint) const;
|
CInstantSendLockPtr GetInstantSendLockByInput(const COutPoint& outpoint) const;
|
||||||
|
Loading…
Reference in New Issue
Block a user