github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/iavl/export.go (about) 1 package iavl 2 3 import ( 4 "context" 5 6 "github.com/pkg/errors" 7 ) 8 9 // exportBufferSize is the number of nodes to buffer in the exporter. It improves throughput by 10 // processing multiple nodes per context switch, but take care to avoid excessive memory usage, 11 // especially since callers may export several IAVL stores in parallel (e.g. the Cosmos SDK). 12 const exportBufferSize = 32 13 14 // ExportDone is returned by Exporter.Next() when all items have been exported. 15 var ExportDone = errors.New("export is complete") // nolint:golint 16 17 // ExportNode contains exported node data. 18 type ExportNode struct { 19 Key []byte 20 Value []byte 21 Version int64 22 Height int8 23 } 24 25 // Exporter exports nodes from an ImmutableTree. It is created by ImmutableTree.Export(). 26 // 27 // Exported nodes can be imported into an empty tree with MutableTree.Import(). Nodes are exported 28 // depth-first post-order (LRN), this order must be preserved when importing in order to recreate 29 // the same tree structure. 30 type Exporter struct { 31 tree *ImmutableTree 32 ch chan *ExportNode 33 cancel context.CancelFunc 34 } 35 36 // NewExporter creates a new Exporter. Callers must call Close() when done. 37 func newExporter(tree *ImmutableTree) *Exporter { 38 ctx, cancel := context.WithCancel(context.Background()) 39 exporter := &Exporter{ 40 tree: tree, 41 ch: make(chan *ExportNode, exportBufferSize), 42 cancel: cancel, 43 } 44 45 tree.ndb.incrVersionReaders(tree.version) 46 go exporter.export(ctx) 47 48 return exporter 49 } 50 51 // export exports nodes 52 func (e *Exporter) export(ctx context.Context) { 53 e.tree.root.traversePost(e.tree, true, func(node *Node) bool { 54 exportNode := &ExportNode{ 55 Key: node.key, 56 Value: node.value, 57 Version: node.version, 58 Height: node.height, 59 } 60 61 select { 62 case e.ch <- exportNode: 63 return false 64 case <-ctx.Done(): 65 return true 66 } 67 }) 68 close(e.ch) 69 } 70 71 // Next fetches the next exported node, or returns ExportDone when done. 72 func (e *Exporter) Next() (*ExportNode, error) { 73 if exportNode, ok := <-e.ch; ok { 74 return exportNode, nil 75 } 76 return nil, ExportDone 77 } 78 79 // Close closes the exporter. It is safe to call multiple times. 80 func (e *Exporter) Close() { 81 e.cancel() 82 for range e.ch { // drain channel 83 } 84 if e.tree != nil { 85 e.tree.ndb.decrVersionReaders(e.tree.version) 86 } 87 e.tree = nil 88 }