github.com/iotexproject/iotex-core@v1.14.1-rc1/tools/iomigrater/cmds/migrate-db.go (about) 1 package cmd 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/pkg/errors" 8 "github.com/schollz/progressbar/v2" 9 "github.com/spf13/cobra" 10 11 "github.com/iotexproject/iotex-core/blockchain/block" 12 "github.com/iotexproject/iotex-core/blockchain/filedao" 13 "github.com/iotexproject/iotex-core/config" 14 "github.com/iotexproject/iotex-core/tools/iomigrater/common" 15 ) 16 17 const ( 18 // INTMAX Max value of type int. 19 INTMAX = int(^uint(0) >> 1) 20 ) 21 22 // Multi-language support 23 var ( 24 migrateDbCmdShorts = map[string]string{ 25 "english": "Sub-Command for migration IoTeX blockchain db file.", 26 "chinese": "迁移IoTeX区块链 db 文件的子命令", 27 } 28 migrateDbCmdLongs = map[string]string{ 29 "english": "Sub-Command for migration IoTeX blockchain db file from 0 to Specified height.", 30 "chinese": "迁移IoTeX区块链 db 文件从 0 到指定的高度的子命令", 31 } 32 migrateDbCmdUse = map[string]string{ 33 "english": "migrate", 34 "chinese": "migrate", 35 } 36 migrateDbFlagOldFileUse = map[string]string{ 37 "english": "The file you want to migrate.", 38 "chinese": "您要迁移的文件。", 39 } 40 migrateDbFlagNewFileUse = map[string]string{ 41 "english": "The path you want to migrate to", 42 "chinese": "您要迁移到的路径。", 43 } 44 migrateDbFlagBlockHeightUse = map[string]string{ 45 "english": "The height you want to migrate to, Cannot be larger than the height of the migration file (the old file)", 46 "chinese": "您要迁移到的高度,不能大于迁移文件(旧文件)的高度。", 47 } 48 ) 49 50 var ( 51 // MigrateDb Used to Sub command. 52 MigrateDb = &cobra.Command{ 53 Use: common.TranslateInLang(migrateDbCmdUse), 54 Short: common.TranslateInLang(migrateDbCmdShorts), 55 Long: common.TranslateInLang(migrateDbCmdLongs), 56 RunE: func(cmd *cobra.Command, args []string) error { 57 return migrateDbFile() 58 }, 59 } 60 ) 61 62 var ( 63 oldFile = "" 64 newFile = "" 65 blockHeight = uint64(0) 66 ) 67 68 func init() { 69 MigrateDb.PersistentFlags().StringVarP(&oldFile, "old-file", "o", "", common.TranslateInLang(migrateDbFlagOldFileUse)) 70 MigrateDb.PersistentFlags().StringVarP(&newFile, "new-file", "n", "", common.TranslateInLang(migrateDbFlagNewFileUse)) 71 MigrateDb.PersistentFlags().Uint64VarP(&blockHeight, "block-height", "b", uint64(0), common.TranslateInLang(migrateDbFlagBlockHeightUse)) 72 } 73 74 func getProgressMod(num uint64) (int, int) { 75 step := 1 76 for num/2 >= uint64(INTMAX) { 77 step *= 2 78 num /= 2 79 } 80 numInt := int(num) 81 82 for numInt/10 > 100 { 83 numInt /= 10 84 step *= 10 85 } 86 87 return numInt, step 88 } 89 90 func migrateDbFile() (err error) { 91 // Check flags 92 if oldFile == "" { 93 return fmt.Errorf("--old-file is empty") 94 } 95 if newFile == "" { 96 return fmt.Errorf("--new-file is empty") 97 } 98 if oldFile == newFile { 99 return fmt.Errorf("the values of --old-file --new-file flags cannot be the same") 100 } 101 if blockHeight == 0 { 102 return fmt.Errorf("--block-height is 0") 103 } 104 105 height, err := checkDbFileHeight(oldFile) 106 if err != nil { 107 return err 108 } else if height < blockHeight { 109 return fmt.Errorf("the --block-height cannot be larger than the height of the migration file") 110 } 111 112 cfg, err := config.New([]string{}, []string{}) 113 if err != nil { 114 return fmt.Errorf("failed to new config: %v", err) 115 } 116 117 cfg.DB.DbPath = oldFile 118 deser := block.NewDeserializer(cfg.Chain.EVMNetworkID) 119 oldDAO, err := filedao.NewFileDAO(cfg.DB, deser) 120 if err != nil { 121 return errors.Wrapf(err, "failed to create dao from %s", oldFile) 122 } 123 124 cfg.DB.DbPath = newFile 125 newDAO, err := filedao.NewFileDAO(cfg.DB, deser) 126 if err != nil { 127 return errors.Wrapf(err, "failed to create dao from %s", newFile) 128 } 129 130 ctx := context.Background() 131 if err := oldDAO.Start(ctx); err != nil { 132 return fmt.Errorf("failed to start the old db file") 133 } 134 if err := newDAO.Start(ctx); err != nil { 135 return fmt.Errorf("failed to start the new db file") 136 } 137 138 defer func() { 139 err = oldDAO.Stop(ctx) 140 err = newDAO.Stop(ctx) 141 }() 142 143 // Show the progressbar 144 intHeight, step := getProgressMod(blockHeight) 145 bar := progressbar.New(intHeight) 146 147 for i := uint64(1); i <= blockHeight; i++ { 148 149 hash, err := oldDAO.GetBlockHash(i) 150 if err != nil { 151 return fmt.Errorf("failed to get block hash on height %d: %v", i, err) 152 } 153 blk, err := oldDAO.GetBlock(hash) 154 if err != nil { 155 return fmt.Errorf("failed to get block on height %d: %v", i, err) 156 } 157 if err := newDAO.PutBlock(ctx, blk); err != nil { 158 return fmt.Errorf("failed to migrate block on height %d: %v", i, err) 159 } 160 161 if i%uint64(step) == 0 { 162 if err = bar.Add(1); err != nil { 163 return fmt.Errorf("failed to add 1 on bar on height %d: %v", i, err) 164 } 165 intHeight-- 166 } 167 } 168 if intHeight > 0 { 169 if err = bar.Add(intHeight); err != nil { 170 return fmt.Errorf("failed to add %d on bar: %v", intHeight, err) 171 } 172 } 173 174 return nil 175 }