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 }