github.com/ledgerwatch/erigon-lib@v1.0.0/bptree/tree.go (about) 1 /* 2 Copyright 2022 Erigon contributors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package bptree 18 19 import ( 20 "fmt" 21 ) 22 23 type Stats struct { 24 ExposedCount uint 25 RehashedCount uint 26 CreatedCount uint 27 UpdatedCount uint 28 DeletedCount uint 29 OpeningHashes uint 30 ClosingHashes uint 31 } 32 33 type Tree23 struct { 34 root *Node23 35 } 36 37 func NewEmptyTree23() *Tree23 { 38 return &Tree23{} 39 } 40 41 func NewTree23(kvItems KeyValues) *Tree23 { 42 tree := new(Tree23).Upsert(kvItems) 43 tree.reset() 44 return tree 45 } 46 47 func (t *Tree23) String() string { 48 return fmt.Sprintf("root={keys=%v #children=%d} size=%d", deref(t.root.keys), t.root.childrenCount(), t.Size()) 49 } 50 51 func (t *Tree23) Size() int { 52 count := 0 53 t.WalkPostOrder(func(n *Node23) interface{} { count++; return nil }) 54 return count 55 } 56 57 func (t *Tree23) RootHash() []byte { 58 if t.root == nil { 59 return []byte{} 60 } 61 return t.root.hashNode() 62 } 63 64 func (t *Tree23) IsValid() (bool, error) { 65 if t.root == nil { 66 return true, nil 67 } 68 // Last leaf must have sentinel next key 69 if lastLeaf := t.root.lastLeaf(); lastLeaf.keyCount() > 0 && lastLeaf.nextKey() != nil { 70 return false, fmt.Errorf("no sentinel next key in last leaf %d", &lastLeaf) 71 } 72 return t.root.isValid() 73 } 74 75 func (t *Tree23) Graph(filename string, debug bool) { 76 graph := NewGraph(t.root) 77 graph.saveDot(filename, debug) 78 } 79 80 func (t *Tree23) GraphAndPicture(filename string) error { 81 graph := NewGraph(t.root) 82 return graph.saveDotAndPicture(filename, false) 83 } 84 85 func (t *Tree23) GraphAndPictureDebug(filename string) error { 86 graph := NewGraph(t.root) 87 return graph.saveDotAndPicture(filename, true) 88 } 89 90 func (t *Tree23) Height() int { 91 if t.root == nil { 92 return 0 93 } 94 return t.root.height() 95 } 96 97 func (t *Tree23) KeysInLevelOrder() []Felt { 98 if t.root == nil { 99 return []Felt{} 100 } 101 return t.root.keysInLevelOrder() 102 } 103 104 func (t *Tree23) WalkPostOrder(w Walker) []interface{} { 105 if t.root == nil { 106 return make([]interface{}, 0) 107 } 108 return t.root.walkPostOrder(w) 109 } 110 111 func (t *Tree23) WalkKeysPostOrder() []Felt { 112 keyPointers := make([]*Felt, 0) 113 t.WalkPostOrder(func(n *Node23) interface{} { 114 if n.isLeaf && n.keyCount() > 0 { 115 keyPointers = append(keyPointers, n.keys[:len(n.keys)-1]...) 116 } 117 return nil 118 }) 119 keys := deref(keyPointers) 120 return keys 121 } 122 123 func (t *Tree23) Upsert(kvItems KeyValues) *Tree23 { 124 return t.UpsertWithStats(kvItems, &Stats{}) 125 } 126 127 func (t *Tree23) UpsertWithStats(kvItems KeyValues, stats *Stats) *Tree23 { 128 promoted, _, intermediateKeys := upsert(t.root, kvItems, stats) 129 ensure(len(promoted) > 0, "nodes length is zero") 130 if len(promoted) == 1 { 131 t.root = promoted[0] 132 } else { 133 t.root = promote(promoted, intermediateKeys, stats) 134 } 135 stats.RehashedCount, stats.ClosingHashes = t.countUpsertRehashedNodes() 136 return t 137 } 138 139 func (t *Tree23) Delete(keyToDelete []Felt) *Tree23 { 140 return t.DeleteWithStats(keyToDelete, &Stats{}) 141 } 142 143 func (t *Tree23) DeleteWithStats(keysToDelete []Felt, stats *Stats) *Tree23 { 144 newRoot, nextKey, intermediateKeys := del(t.root, keysToDelete, stats) 145 t.root, _ = demote(newRoot, nextKey, intermediateKeys, stats) 146 stats.RehashedCount, stats.ClosingHashes = t.countDeleteRehashedNodes() 147 return t 148 } 149 150 func (t *Tree23) countUpsertRehashedNodes() (rehashedCount uint, closingHashes uint) { 151 t.WalkPostOrder(func(n *Node23) interface{} { 152 if n.exposed { 153 rehashedCount++ 154 closingHashes += n.howManyHashes() 155 } 156 return nil 157 }) 158 return rehashedCount, closingHashes 159 } 160 161 func (t *Tree23) countDeleteRehashedNodes() (rehashedCount uint, closingHashes uint) { 162 t.WalkPostOrder(func(n *Node23) interface{} { 163 if n.updated { 164 rehashedCount++ 165 closingHashes += n.howManyHashes() 166 } 167 return nil 168 }) 169 return rehashedCount, closingHashes 170 } 171 172 func (t *Tree23) reset() { 173 if t.root == nil { 174 return 175 } 176 t.root.reset() 177 }