github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/iavl/mutable_tree_preload.go (about)

     1  package iavl
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"runtime"
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/fibonacci-chain/fbc/libs/system/trace"
    11  	"github.com/fibonacci-chain/fbc/libs/system/trace/persist"
    12  	"github.com/tendermint/go-amino"
    13  )
    14  
    15  const (
    16  	PreloadConcurrencyThreshold = 4
    17  
    18  	PreChangeOpSet    byte = 1
    19  	PreChangeOpDelete byte = 0
    20  	PreChangeNop      byte = 0xFF
    21  )
    22  
    23  type preWriteJob struct {
    24  	key      []byte
    25  	setOrDel byte
    26  }
    27  
    28  func (tree *MutableTree) PreChanges(keys []string, setOrDel []byte) {
    29  	if tree.root == nil {
    30  		return
    31  	}
    32  	tsPreChange := time.Now()
    33  
    34  	maxNums := runtime.NumCPU()
    35  	keyCount := len(keys)
    36  	if maxNums > keyCount {
    37  		maxNums = keyCount
    38  	}
    39  	if maxNums < PreloadConcurrencyThreshold {
    40  		return
    41  	}
    42  
    43  	tree.ndb.initPreWriteCache()
    44  
    45  	txJobChan := make(chan preWriteJob, keyCount)
    46  	var wg sync.WaitGroup
    47  	wg.Add(keyCount)
    48  
    49  	for index := 0; index < maxNums; index++ {
    50  		go func(ch chan preWriteJob, wg *sync.WaitGroup) {
    51  			for j := range ch {
    52  				tree.preChangeWithOutCache(tree.root, j.key, j.setOrDel)
    53  				wg.Done()
    54  			}
    55  		}(txJobChan, &wg)
    56  	}
    57  
    58  	for i, key := range keys {
    59  		setOrDelFlag := setOrDel[i]
    60  		if setOrDelFlag != PreChangeNop {
    61  			txJobChan <- preWriteJob{amino.StrToBytes(key), setOrDel[i]}
    62  		}
    63  	}
    64  	close(txJobChan)
    65  	wg.Wait()
    66  
    67  	tree.ndb.finishPreWriteCache()
    68  	persist.GetStatistics().Accumulate(trace.PreChange, tsPreChange)
    69  }
    70  
    71  func (tree *MutableTree) preChangeWithOutCache(node *Node, key []byte, setOrDel byte) (find bool) {
    72  	if node.isLeaf() {
    73  		if bytes.Equal(node.key, key) {
    74  			return true
    75  		}
    76  		return
    77  	} else {
    78  		var isSet = setOrDel == PreChangeOpSet
    79  		if bytes.Compare(key, node.key) < 0 {
    80  			node.leftNode = tree.preGetLeftNode(node)
    81  			if find = tree.preChangeWithOutCache(node.leftNode, key, setOrDel); (!find && isSet) || (find && !isSet) {
    82  				tree.preGetRightNode(node)
    83  			}
    84  		} else {
    85  			node.rightNode = tree.preGetRightNode(node)
    86  			if find = tree.preChangeWithOutCache(node.rightNode, key, setOrDel); (!find && isSet) || (find && !isSet) {
    87  				tree.preGetLeftNode(node)
    88  			}
    89  		}
    90  		return
    91  	}
    92  }
    93  
    94  func (tree *MutableTree) preGetNode(hash []byte) (n *Node) {
    95  	var fromDisk bool
    96  	n, fromDisk = tree.ImmutableTree.ndb.GetNodeWithoutUpdateCache(hash)
    97  	if fromDisk {
    98  		tree.ndb.cacheNodeToPreWriteCache(n)
    99  	}
   100  	return
   101  }
   102  
   103  func (tree *MutableTree) preGetLeftNode(node *Node) (n *Node) {
   104  	if node.leftNode != nil {
   105  		return node.leftNode
   106  	}
   107  	return tree.preGetNode(node.leftHash)
   108  }
   109  
   110  func (tree *MutableTree) preGetRightNode(node *Node) (n *Node) {
   111  	if node.rightNode != nil {
   112  		return node.rightNode
   113  	}
   114  	return tree.preGetNode(node.rightHash)
   115  }
   116  
   117  func (tree *MutableTree) makeOrphansSliceReady() []*Node {
   118  	maxOrphansNum := int(tree.Height()) + 3
   119  	if cap(tree.readableOrphansSlice) < maxOrphansNum {
   120  		tree.readableOrphansSlice = make([]*Node, 0, maxOrphansNum)
   121  	} else {
   122  		tree.readableOrphansSlice = tree.readableOrphansSlice[:0]
   123  	}
   124  	return tree.readableOrphansSlice
   125  }
   126  
   127  func (tree *MutableTree) setWithOrphansSlice(key []byte, value []byte, orphans *[]*Node) (updated bool) {
   128  	if value == nil {
   129  		panic(fmt.Sprintf("Attempt to store nil value at key '%s'", key))
   130  	}
   131  
   132  	if tree.ImmutableTree.root == nil {
   133  		tree.addUnsavedAddition(key, value, tree.version+1)
   134  		tree.ImmutableTree.root = NewNode(key, value, tree.version+1)
   135  		return updated
   136  	}
   137  
   138  	tree.ImmutableTree.root, updated = tree.recursiveSet(tree.ImmutableTree.root, key, value, orphans)
   139  	return updated
   140  }
   141  
   142  func (tree *MutableTree) removeWithOrphansSlice(key []byte, orphaned *[]*Node) (value []byte, removed bool) {
   143  	if tree.root == nil {
   144  		return nil, false
   145  	}
   146  	newRootHash, newRoot, _, value := tree.recursiveRemove(tree.root, key, orphaned)
   147  	if len(*orphaned) == 0 {
   148  		return nil, false
   149  	}
   150  	tree.addUnsavedRemoval(key)
   151  
   152  	if newRoot == nil && newRootHash != nil {
   153  		tree.root = tree.ndb.GetNode(newRootHash)
   154  	} else {
   155  		tree.root = newRoot
   156  	}
   157  	return value, true
   158  }