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  }