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  }