github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/iavl/benchmarks/cosmos-exim/main.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "time" 8 9 "github.com/fibonacci-chain/fbc/libs/iavl" 10 tmdb "github.com/fibonacci-chain/fbc/libs/tm-db" 11 ) 12 13 // stores is the list of stores in the CosmosHub database 14 // FIXME would be nice to autodetect this 15 var stores = []string{ 16 "acc", 17 "distribution", 18 "evidence", 19 "god", 20 "main", 21 "mint", 22 "params", 23 "slashing", 24 "staking", 25 "supply", 26 "upgrade", 27 } 28 29 // Stats track import/export statistics 30 type Stats struct { 31 nodes uint64 32 leafNodes uint64 33 size uint64 34 duration time.Duration 35 } 36 37 func (s *Stats) Add(o Stats) { 38 s.nodes += o.nodes 39 s.leafNodes += o.leafNodes 40 s.size += o.size 41 s.duration += o.duration 42 } 43 44 func (s *Stats) AddDurationSince(started time.Time) { 45 s.duration += time.Since(started) 46 } 47 48 func (s *Stats) AddNode(node *iavl.ExportNode) { 49 s.nodes++ 50 if node.Height == 0 { 51 s.leafNodes++ 52 } 53 s.size += uint64(len(node.Key) + len(node.Value) + 8 + 1) 54 } 55 56 func (s *Stats) String() string { 57 return fmt.Sprintf("%v nodes (%v leaves) in %v with size %v MB", 58 s.nodes, s.leafNodes, s.duration.Round(time.Millisecond), s.size/1024/1024) 59 } 60 61 // main runs the main program 62 func main() { 63 if len(os.Args) != 2 { 64 fmt.Fprintf(os.Stderr, "Usage: %v <dbpath>\n", os.Args[0]) 65 os.Exit(1) 66 } 67 err := run(os.Args[1]) 68 if err != nil { 69 fmt.Fprintf(os.Stderr, "Error: %v\n", err.Error()) 70 os.Exit(1) 71 } 72 } 73 74 // run runs the command with normal error handling 75 func run(dbPath string) error { 76 version, exports, err := runExport(dbPath) 77 if err != nil { 78 return err 79 } 80 81 err = runImport(version, exports) 82 if err != nil { 83 return err 84 } 85 return nil 86 } 87 88 // runExport runs an export benchmark and returns a map of store names/export nodes 89 func runExport(dbPath string) (int64, map[string][]*iavl.ExportNode, error) { 90 ldb := tmdb.NewDB("application", tmdb.GoLevelDBBackend, dbPath) 91 tree, err := iavl.NewMutableTree(tmdb.NewPrefixDB(ldb, []byte("s/k:main/")), 0) 92 if err != nil { 93 return 0, nil, err 94 } 95 version, err := tree.LoadVersion(0) 96 if err != nil { 97 return 0, nil, err 98 } 99 fmt.Printf("Exporting cosmoshub database at version %v\n\n", version) 100 101 exports := make(map[string][]*iavl.ExportNode, len(stores)) 102 103 totalStats := Stats{} 104 for _, name := range stores { 105 db := tmdb.NewPrefixDB(ldb, []byte("s/k:"+name+"/")) 106 tree, err := iavl.NewMutableTree(db, 0) 107 if err != nil { 108 return 0, nil, err 109 } 110 111 stats := Stats{} 112 export := make([]*iavl.ExportNode, 0, 100000) 113 114 storeVersion, err := tree.LoadVersion(0) 115 if err != nil { 116 return 0, nil, err 117 } 118 if storeVersion == 0 { 119 fmt.Printf("%-13v: %v\n", name, stats.String()) 120 continue 121 } 122 123 itree, err := tree.GetImmutable(version) 124 if err != nil { 125 return 0, nil, err 126 } 127 start := time.Now().UTC() 128 exporter := itree.Export() 129 defer exporter.Close() 130 for { 131 node, err := exporter.Next() 132 if err == iavl.ExportDone { 133 break 134 } else if err != nil { 135 return 0, nil, err 136 } 137 export = append(export, node) 138 stats.AddNode(node) 139 } 140 stats.AddDurationSince(start) 141 fmt.Printf("%-13v: %v\n", name, stats.String()) 142 totalStats.Add(stats) 143 exports[name] = export 144 } 145 146 fmt.Printf("\nExported %v stores with %v\n\n", len(stores), totalStats.String()) 147 148 return version, exports, nil 149 } 150 151 // runImport runs an import benchmark with nodes exported from runExport() 152 func runImport(version int64, exports map[string][]*iavl.ExportNode) error { 153 fmt.Print("Importing into new LevelDB stores\n\n") 154 155 totalStats := Stats{} 156 157 for _, name := range stores { 158 tempdir, err := ioutil.TempDir("", name) 159 if err != nil { 160 return err 161 } 162 defer os.RemoveAll(tempdir) 163 164 start := time.Now() 165 stats := Stats{} 166 167 newDB := tmdb.NewDB(name, tmdb.GoLevelDBBackend, tempdir) 168 newTree, err := iavl.NewMutableTree(newDB, 0) 169 if err != nil { 170 return err 171 } 172 importer, err := newTree.Import(version) 173 if err != nil { 174 return err 175 } 176 defer importer.Close() 177 for _, node := range exports[name] { 178 err = importer.Add(node) 179 if err != nil { 180 return err 181 } 182 stats.AddNode(node) 183 } 184 err = importer.Commit() 185 if err != nil { 186 return err 187 } 188 stats.AddDurationSince(start) 189 fmt.Printf("%-12v: %v\n", name, stats.String()) 190 totalStats.Add(stats) 191 } 192 193 fmt.Printf("\nImported %v stores with %v\n", len(stores), totalStats.String()) 194 195 return nil 196 }