mirror of
https://github.com/FlipsideCrypto/dcrd.git
synced 2026-02-06 10:56:47 +00:00
chain: Remove memory block node pruning.
This removes the memory block node (header) pruning. It should be noted that this does not apply to stake node pruning. This is being done for two primary reasons: - The goal is to ultimately have all block nodes in memory in the same way the upstream code has done since it provides significant optimization and code simplification opportunities - Upcoming code that deals with calculating sequence locks on inputs far in the past requires the ability to quickly calculate the median time for arbitrarily old nodes and consequently pruning the memory block nodes could lead to significant performance implications under those conditions
This commit is contained in:
parent
1955bb1bf1
commit
3f366fbc17
@ -256,13 +256,10 @@ func (b *BlockChain) maybeAcceptBlock(block *dcrutil.Block, flags BehaviorFlags)
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Prune stake nodes and block nodes which are no longer needed before
|
||||
// creating a new node.
|
||||
// Prune stake nodes which are no longer needed before creating a new
|
||||
// node.
|
||||
if !dryRun {
|
||||
err := b.pruner.pruneChainIfNeeded()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
b.pruner.pruneChainIfNeeded()
|
||||
}
|
||||
|
||||
// Create a new block node for the block and add it to the in-memory
|
||||
|
||||
@ -890,94 +890,6 @@ func (b *BlockChain) GetTopBlock() (*dcrutil.Block, error) {
|
||||
return block, err
|
||||
}
|
||||
|
||||
// removeBlockNode removes the passed block node from the memory chain by
|
||||
// unlinking all of its children and removing it from the the node and
|
||||
// dependency indices.
|
||||
//
|
||||
// This function MUST be called with the chain state lock held (for writes).
|
||||
func (b *BlockChain) removeBlockNode(node *blockNode) error {
|
||||
if node.parent != nil {
|
||||
return AssertError(fmt.Sprintf("removeBlockNode must be "+
|
||||
"called with a node at the front of the chain - node %v",
|
||||
node.hash))
|
||||
}
|
||||
|
||||
// Remove the node from the node index.
|
||||
delete(b.index, node.hash)
|
||||
|
||||
// Unlink all of the node's children.
|
||||
for _, child := range node.children {
|
||||
child.parent = nil
|
||||
}
|
||||
node.children = nil
|
||||
|
||||
// Remove the reference from the dependency index.
|
||||
prevHash := &node.header.PrevBlock
|
||||
if children, ok := b.depNodes[*prevHash]; ok {
|
||||
// Find the node amongst the children of the
|
||||
// dependencies for the parent hash and remove it.
|
||||
b.depNodes[*prevHash] = removeChildNode(children, node)
|
||||
|
||||
// Remove the map entry altogether if there are no
|
||||
// longer any nodes which depend on the parent hash.
|
||||
if len(b.depNodes[*prevHash]) == 0 {
|
||||
delete(b.depNodes, *prevHash)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// pruneBlockNodes removes references to old block nodes which are no longer
|
||||
// needed so they may be garbage collected. In order to validate block rules
|
||||
// and choose the best chain, only a portion of the nodes which form the block
|
||||
// chain are needed in memory. This function walks the chain backwards from the
|
||||
// current best chain to find any nodes before the first needed block node.
|
||||
//
|
||||
// This function MUST be called with the chain state lock held (for writes).
|
||||
func (b *BlockChain) pruneBlockNodes() error {
|
||||
// Walk the chain backwards to find what should be the new root node.
|
||||
// Intentionally use node.parent instead of getPrevNodeFromNode since
|
||||
// the latter loads the node and the goal is to find nodes still in
|
||||
// memory that can be pruned.
|
||||
newRootNode := b.bestNode
|
||||
for i := int64(0); i < minMemoryNodes-1 && newRootNode != nil; i++ {
|
||||
newRootNode = newRootNode.parent
|
||||
}
|
||||
|
||||
// Nothing to do if there are not enough nodes.
|
||||
if newRootNode == nil || newRootNode.parent == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Push the nodes to delete on a list in reverse order since it's easier
|
||||
// to prune them going forwards than it is backwards. This will
|
||||
// typically end up being a single node since pruning is currently done
|
||||
// just before each new node is created. However, that might be tuned
|
||||
// later to only prune at intervals, so the code needs to account for
|
||||
// the possibility of multiple nodes.
|
||||
deleteNodes := list.New()
|
||||
for node := newRootNode.parent; node != nil; node = node.parent {
|
||||
deleteNodes.PushFront(node)
|
||||
}
|
||||
|
||||
// Loop through each node to prune, unlink its children, remove it from
|
||||
// the dependency index, and remove it from the node index.
|
||||
for e := deleteNodes.Front(); e != nil; e = e.Next() {
|
||||
node := e.Value.(*blockNode)
|
||||
// Do not attempt to prune if the node should already have been pruned,
|
||||
// for example if you're adding an old side chain block.
|
||||
if node.height > b.bestNode.height-minMemoryNodes {
|
||||
err := b.removeBlockNode(node)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// pruneStakeNodes removes references to old stake nodes which should no
|
||||
// longer be held in memory so as to keep the maximum memory usage down.
|
||||
// It proceeds from the bestNode back to the determined minimum height node,
|
||||
@ -1024,19 +936,6 @@ func (b *BlockChain) pruneStakeNodes() {
|
||||
}
|
||||
}
|
||||
|
||||
// pruneNodes tranverses the blockchain and prunes nodes and stake data from
|
||||
// memory so that the memory can be recovered by the garbage collector. This
|
||||
// allows the caller of the blockchain to manually handle GC related to the
|
||||
// blockchain.
|
||||
//
|
||||
// This function is NOT safe for concurrent access and must be called with
|
||||
// the chain lock held for writes.
|
||||
func (b *BlockChain) pruneNodes() error {
|
||||
b.pruneStakeNodes()
|
||||
|
||||
return b.pruneBlockNodes()
|
||||
}
|
||||
|
||||
// BestPrevHash returns the hash of the previous block of the block at HEAD.
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
|
||||
@ -27,14 +27,13 @@ func newChainPruner(chain *BlockChain) *chainPruner {
|
||||
// If the blockchain hasn't been pruned in this time, it initiates a new pruning.
|
||||
//
|
||||
// pruneChainIfNeeded must be called with the chainLock held for writes.
|
||||
func (c *chainPruner) pruneChainIfNeeded() error {
|
||||
func (c *chainPruner) pruneChainIfNeeded() {
|
||||
now := time.Now()
|
||||
duration := now.Sub(c.lastNodeInsertTime)
|
||||
if duration < time.Minute*pruningIntervalInMinutes {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
c.lastNodeInsertTime = now
|
||||
|
||||
return c.chain.pruneNodes()
|
||||
c.chain.pruneStakeNodes()
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user