github.com/datachainlab/burrow@v0.25.0/storage/rwtree.go (about) 1 package storage 2 3 import ( 4 "fmt" 5 6 "github.com/tendermint/iavl" 7 8 dbm "github.com/tendermint/tendermint/libs/db" 9 "github.com/xlab/treeprint" 10 ) 11 12 type RWTree struct { 13 // Working tree accumulating writes 14 tree *MutableTree 15 // Read-only tree serving previous state 16 *ImmutableTree 17 // Have any writes occurred since last save 18 updated bool 19 } 20 21 // Creates a concurrency safe version of an IAVL tree whereby reads are routed to the last saved tree. 22 // Writes must be serialised (as they are within a commit for example). 23 func NewRWTree(db dbm.DB, cacheSize int) *RWTree { 24 tree := NewMutableTree(db, cacheSize) 25 return &RWTree{ 26 tree: tree, 27 ImmutableTree: &ImmutableTree{iavl.NewImmutableTree(db, cacheSize)}, 28 } 29 } 30 31 // Tries to load the execution state from DB, returns nil with no error if no state found 32 func (rwt *RWTree) Load(version int64, overwriting bool) error { 33 const errHeader = "RWTree.Load():" 34 if version <= 0 { 35 return fmt.Errorf("%s trying to load from non-positive version %d", errHeader, version) 36 } 37 err := rwt.tree.Load(version, overwriting) 38 if err != nil { 39 return fmt.Errorf("%s loading version %d: %v", errHeader, version, err) 40 } 41 // Set readTree at commit point == tree 42 rwt.ImmutableTree, err = rwt.tree.GetImmutable(version) 43 if err != nil { 44 return fmt.Errorf("%s loading version %d: %v", errHeader, version, err) 45 } 46 return nil 47 } 48 49 // Save the current write tree making writes accessible from read tree. 50 func (rwt *RWTree) Save() ([]byte, int64, error) { 51 // save state at a new version may still be orphaned before we save the version against the hash 52 hash, version, err := rwt.tree.SaveVersion() 53 if err != nil { 54 return nil, 0, fmt.Errorf("could not save RWTree: %v", err) 55 } 56 // Take an immutable reference to the tree we just saved for querying 57 rwt.ImmutableTree, err = rwt.tree.GetImmutable(version) 58 if err != nil { 59 return nil, 0, fmt.Errorf("RWTree.Save() could not obtain ImmutableTree read tree: %v", err) 60 } 61 rwt.updated = false 62 return hash, version, nil 63 } 64 65 func (rwt *RWTree) Set(key, value []byte) bool { 66 rwt.updated = true 67 return rwt.tree.Set(key, value) 68 } 69 70 func (rwt *RWTree) Delete(key []byte) ([]byte, bool) { 71 rwt.updated = true 72 return rwt.tree.Remove(key) 73 } 74 75 // Returns true if there have been any writes since last save 76 func (rwt *RWTree) Updated() bool { 77 return rwt.updated 78 } 79 80 func (rwt *RWTree) GetImmutable(version int64) (*ImmutableTree, error) { 81 return rwt.tree.GetImmutable(version) 82 } 83 84 func (rwt *RWTree) IterateWriteTree(start, end []byte, ascending bool, fn func(key []byte, value []byte) error) error { 85 return rwt.tree.IterateWriteTree(start, end, ascending, fn) 86 } 87 88 // Tree printing 89 90 func (rwt *RWTree) Dump() string { 91 tree := treeprint.New() 92 AddTreePrintTree("ReadTree", tree, rwt) 93 AddTreePrintTree("WriteTree", tree, rwt.tree) 94 return tree.String() 95 } 96 97 func AddTreePrintTree(edge string, tree treeprint.Tree, rwt KVCallbackIterableReader) { 98 tree = tree.AddBranch(fmt.Sprintf("%q", edge)) 99 rwt.Iterate(nil, nil, true, func(key []byte, value []byte) error { 100 tree.AddNode(fmt.Sprintf("%q -> %q", string(key), string(value))) 101 return nil 102 }) 103 }