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  }