github.com/iotexproject/iotex-core@v1.14.1-rc1/db/trie/mptrie/branchnode.go (about) 1 // Copyright (c) 2019 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package mptrie 7 8 import ( 9 "github.com/pkg/errors" 10 "google.golang.org/protobuf/proto" 11 12 "github.com/iotexproject/iotex-core/db/trie" 13 "github.com/iotexproject/iotex-core/db/trie/triepb" 14 ) 15 16 type branchNode struct { 17 cacheNode 18 children map[byte]node 19 indices *SortedList 20 isRoot bool 21 } 22 23 func newBranchNode( 24 cli client, 25 children map[byte]node, 26 indices *SortedList, 27 ) (node, error) { 28 if len(children) == 0 { 29 return nil, errors.New("branch node children cannot be empty") 30 } 31 if indices == nil { 32 indices = NewSortedList(children) 33 } 34 bnode := &branchNode{ 35 cacheNode: cacheNode{ 36 dirty: true, 37 }, 38 children: children, 39 indices: indices, 40 } 41 bnode.cacheNode.serializable = bnode 42 if len(bnode.children) != 0 { 43 if !cli.asyncMode() { 44 if err := bnode.store(cli); err != nil { 45 return nil, err 46 } 47 } 48 } 49 if err := logNode(_nodeTypeBranch, _actionTypeNew, bnode, cli); err != nil { 50 return nil, err 51 } 52 return bnode, nil 53 } 54 55 func newRootBranchNode(cli client, children map[byte]node, indices *SortedList, dirty bool) (branch, error) { 56 if indices == nil { 57 indices = NewSortedList(children) 58 } 59 bnode := &branchNode{ 60 cacheNode: cacheNode{ 61 dirty: dirty, 62 }, 63 children: children, 64 indices: indices, 65 isRoot: true, 66 } 67 bnode.cacheNode.serializable = bnode 68 if len(bnode.children) != 0 { 69 if !cli.asyncMode() { 70 if err := bnode.store(cli); err != nil { 71 return nil, err 72 } 73 } 74 } 75 if err := logNode(_nodeTypeBranch, _actionTypeNew, bnode, cli); err != nil { 76 return nil, err 77 } 78 return bnode, nil 79 } 80 81 func newBranchNodeFromProtoPb(pb *triepb.BranchPb, hashVal []byte) *branchNode { 82 bnode := &branchNode{ 83 cacheNode: cacheNode{ 84 hashVal: hashVal, 85 dirty: false, 86 }, 87 children: make(map[byte]node, len(pb.Branches)), 88 } 89 for _, n := range pb.Branches { 90 bnode.children[byte(n.Index)] = newHashNode(n.Path) 91 } 92 bnode.indices = NewSortedList(bnode.children) 93 bnode.cacheNode.serializable = bnode 94 if err := logNode(_nodeTypeBranch, _actionTypeNew, bnode, nil); err != nil { 95 panic(err) 96 } 97 return bnode 98 } 99 100 func (b *branchNode) MarkAsRoot() { 101 b.isRoot = true 102 } 103 104 func (b *branchNode) Children() []node { 105 ret := make([]node, 0, len(b.children)) 106 for _, idx := range b.indices.List() { 107 ret = append(ret, b.children[idx]) 108 } 109 return ret 110 } 111 112 func (b *branchNode) Delete(cli client, key keyType, offset uint8) (node, error) { 113 if err := logNode(_nodeTypeBranch, _actionTypeDelete, b, cli); err != nil { 114 return nil, err 115 } 116 offsetKey := key[offset] 117 child, err := b.child(offsetKey) 118 if err != nil { 119 return nil, err 120 } 121 newChild, err := child.Delete(cli, key, offset+1) 122 if err != nil { 123 return nil, err 124 } 125 if newChild != nil || b.isRoot { 126 return b.updateChild(cli, offsetKey, newChild) 127 } 128 switch len(b.children) { 129 case 1: 130 panic("branch shouldn't have 0 child after deleting") 131 case 2: 132 if err := b.delete(cli); err != nil { 133 return nil, err 134 } 135 var orphan node 136 var orphanKey byte 137 for i, n := range b.children { 138 if i != offsetKey { 139 orphanKey = i 140 orphan = n 141 break 142 } 143 } 144 if orphan == nil { 145 panic("unexpected branch status") 146 } 147 if hn, ok := orphan.(*hashNode); ok { 148 if orphan, err = hn.LoadNode(cli); err != nil { 149 return nil, err 150 } 151 } 152 switch node := orphan.(type) { 153 case *extensionNode: 154 return node.updatePath( 155 cli, 156 append([]byte{orphanKey}, node.path...), 157 ) 158 case *leafNode: 159 return node, nil 160 default: 161 return newExtensionNode(cli, []byte{orphanKey}, node) 162 } 163 default: 164 return b.updateChild(cli, offsetKey, newChild) 165 } 166 } 167 168 func (b *branchNode) Upsert(cli client, key keyType, offset uint8, value []byte) (node, error) { 169 if err := logNode(_nodeTypeBranch, _actionTypeUpsert, b, cli); err != nil { 170 return nil, err 171 } 172 var newChild node 173 offsetKey := key[offset] 174 child, err := b.child(offsetKey) 175 switch errors.Cause(err) { 176 case nil: 177 newChild, err = child.Upsert(cli, key, offset+1, value) // look for next key offset 178 case trie.ErrNotExist: 179 newChild, err = newLeafNode(cli, key, value) 180 } 181 if err != nil { 182 return nil, err 183 } 184 185 return b.updateChild(cli, offsetKey, newChild) 186 } 187 188 func (b *branchNode) Search(cli client, key keyType, offset uint8) (node, error) { 189 if err := logNode(_nodeTypeBranch, _actionTypeSearch, b, cli); err != nil { 190 return nil, err 191 } 192 child, err := b.child(key[offset]) 193 if err != nil { 194 return nil, err 195 } 196 return child.Search(cli, key, offset+1) 197 } 198 199 func (b *branchNode) proto(cli client, flush bool) (proto.Message, error) { 200 nodes := []*triepb.BranchNodePb{} 201 for _, idx := range b.indices.List() { 202 c := b.children[idx] 203 if flush { 204 if sn, ok := c.(serializable); ok { 205 if err := sn.store(cli); err != nil { 206 return nil, err 207 } 208 } 209 } 210 h, err := c.Hash(cli) 211 if err != nil { 212 return nil, err 213 } 214 nodes = append(nodes, &triepb.BranchNodePb{Index: uint32(idx), Path: h}) 215 } 216 return &triepb.NodePb{ 217 Node: &triepb.NodePb_Branch{ 218 Branch: &triepb.BranchPb{Branches: nodes}, 219 }, 220 }, nil 221 } 222 223 func (b *branchNode) child(key byte) (node, error) { 224 c, ok := b.children[key] 225 if !ok { 226 return nil, trie.ErrNotExist 227 } 228 return c, nil 229 } 230 231 func (b *branchNode) Flush(cli client) error { 232 if !b.dirty { 233 return nil 234 } 235 for _, idx := range b.indices.List() { 236 if err := b.children[idx].Flush(cli); err != nil { 237 return err 238 } 239 } 240 241 return b.store(cli) 242 } 243 244 func (b *branchNode) updateChild(cli client, key byte, child node) (node, error) { 245 if err := b.delete(cli); err != nil { 246 return nil, err 247 } 248 var indices *SortedList 249 // update branchnode with new child 250 children := make(map[byte]node, len(b.children)) 251 for k, v := range b.children { 252 children[k] = v 253 } 254 if child == nil { 255 delete(children, key) 256 if b.indices.sorted { 257 indices = b.indices.Clone() 258 indices.Delete(key) 259 } 260 } else { 261 children[key] = child 262 if b.indices.sorted { 263 indices = b.indices.Clone() 264 indices.Insert(key) 265 } 266 } 267 268 if b.isRoot { 269 bn, err := newRootBranchNode(cli, children, indices, true) 270 if err != nil { 271 return nil, err 272 } 273 return bn, nil 274 } 275 return newBranchNode(cli, children, indices) 276 } 277 278 func (b *branchNode) Clone() (branch, error) { 279 children := make(map[byte]node, len(b.children)) 280 for key, child := range b.children { 281 children[key] = child 282 } 283 hashVal := make([]byte, len(b.hashVal)) 284 copy(hashVal, b.hashVal) 285 ser := make([]byte, len(b.ser)) 286 copy(ser, b.ser) 287 clone := &branchNode{ 288 cacheNode: cacheNode{ 289 dirty: b.dirty, 290 hashVal: hashVal, 291 ser: ser, 292 }, 293 children: children, 294 indices: b.indices.Clone(), 295 isRoot: b.isRoot, 296 } 297 clone.cacheNode.serializable = clone 298 return clone, nil 299 }