github.com/klaytn/klaytn@v1.10.2/cmd/utils/nodecmd/migrationcmd.go (about)

     1  // Modifications Copyright 2020 The klaytn Authors
     2  // Copyright 2015 The go-ethereum Authors
     3  // This file is part of go-ethereum.
     4  //
     5  // go-ethereum is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // go-ethereum is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU General Public License
    16  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package nodecmd
    19  
    20  import (
    21  	"encoding/json"
    22  
    23  	"github.com/klaytn/klaytn/cmd/utils"
    24  	"github.com/klaytn/klaytn/storage/database"
    25  	"github.com/pkg/errors"
    26  
    27  	"gopkg.in/urfave/cli.v1"
    28  )
    29  
    30  var (
    31  	dbFlags = []cli.Flag{
    32  		// src DB
    33  		utils.DbTypeFlag,
    34  		utils.SingleDBFlag,
    35  		utils.NumStateTrieShardsFlag,
    36  		utils.DynamoDBTableNameFlag,
    37  		utils.DynamoDBRegionFlag,
    38  		utils.DynamoDBIsProvisionedFlag,
    39  		utils.DynamoDBReadCapacityFlag,
    40  		utils.DynamoDBWriteCapacityFlag,
    41  		utils.LevelDBCompressionTypeFlag,
    42  		utils.DataDirFlag,
    43  	}
    44  	dbMigrationFlags = append(dbFlags, DBMigrationFlags...)
    45  
    46  	MigrationCommand = cli.Command{
    47  		Name:     "db-migration",
    48  		Usage:    "db migration",
    49  		Flags:    []cli.Flag{},
    50  		Category: "DB MIGRATION COMMANDS",
    51  		Description: `
    52  The migration command migrates a DB to another DB.
    53  The type of DBs can be different.
    54  (e.g. LevelDB -> LevelDB, LevelDB -> BadgerDB, LevelDB -> DynamoDB)
    55  Note: This feature is only provided when srcDB is single LevelDB.
    56  Note: Do not use db migration while a node is executing.
    57  `,
    58  		Subcommands: []cli.Command{
    59  			{
    60  				Name:   "start",
    61  				Usage:  "Start db migration",
    62  				Flags:  dbMigrationFlags,
    63  				Action: utils.MigrateFlags(startMigration),
    64  				Description: `
    65  This command starts DB migration.
    66  
    67  Even if db dir names are changed in srcDB, the original db dir names are used in dstDB.
    68  (e.g. use 'statetrie' instead of 'statetrie_migrated_xxxxx')
    69  If dst db is singleDB, you should set dst.datadir or db.dst.dynamo.tablename
    70  to the original db dir name.
    71  (e.g. Data dir : 'chaindata/klay/statetrie', Dynamo table name : 'klaytn-statetrie')
    72  
    73  Note: This feature is only provided when srcDB is single LevelDB.`,
    74  			},
    75  		},
    76  	}
    77  )
    78  
    79  func startMigration(ctx *cli.Context) error {
    80  	srcDBManager, dstDBManager, err := createDBManagerForMigration(ctx)
    81  	if err != nil {
    82  		return err
    83  	}
    84  	defer srcDBManager.Close()
    85  	defer dstDBManager.Close()
    86  
    87  	return srcDBManager.StartDBMigration(dstDBManager)
    88  }
    89  
    90  func createDBManagerForMigration(ctx *cli.Context) (database.DBManager, database.DBManager, error) {
    91  	// create db config from ctx
    92  	srcDBConfig, dstDBConfig, dbManagerCreationErr := createDBConfigForMigration(ctx)
    93  	if dbManagerCreationErr != nil {
    94  		return nil, nil, dbManagerCreationErr
    95  	}
    96  
    97  	// log
    98  	s, _ := json.Marshal(srcDBConfig)
    99  	d, _ := json.Marshal(dstDBConfig)
   100  	logger.Info("dbManager created", "\nsrcDB", string(s), "\ndstDB", string(d))
   101  
   102  	// create DBManager
   103  	srcDBManager := database.NewDBManager(srcDBConfig)
   104  	dstDBManager := database.NewDBManager(dstDBConfig)
   105  
   106  	return srcDBManager, dstDBManager, nil
   107  }
   108  
   109  func createDBConfigForMigration(ctx *cli.Context) (*database.DBConfig, *database.DBConfig, error) {
   110  	// srcDB
   111  	srcDBC := &database.DBConfig{
   112  		Dir:                ctx.GlobalString(utils.DataDirFlag.Name),
   113  		DBType:             database.DBType(ctx.GlobalString(utils.DbTypeFlag.Name)).ToValid(),
   114  		SingleDB:           ctx.GlobalBool(utils.SingleDBFlag.Name),
   115  		NumStateTrieShards: ctx.GlobalUint(utils.NumStateTrieShardsFlag.Name),
   116  		OpenFilesLimit:     database.GetOpenFilesLimit(),
   117  
   118  		LevelDBCacheSize:    ctx.GlobalInt(utils.LevelDBCacheSizeFlag.Name),
   119  		LevelDBCompression:  database.LevelDBCompressionType(ctx.GlobalInt(utils.LevelDBCompressionTypeFlag.Name)),
   120  		EnableDBPerfMetrics: !ctx.IsSet(utils.DBNoPerformanceMetricsFlag.Name),
   121  
   122  		DynamoDBConfig: &database.DynamoDBConfig{
   123  			TableName:          ctx.GlobalString(utils.DynamoDBTableNameFlag.Name),
   124  			Region:             ctx.GlobalString(utils.DynamoDBRegionFlag.Name),
   125  			IsProvisioned:      ctx.GlobalBool(utils.DynamoDBIsProvisionedFlag.Name),
   126  			ReadCapacityUnits:  ctx.GlobalInt64(utils.DynamoDBReadCapacityFlag.Name),
   127  			WriteCapacityUnits: ctx.GlobalInt64(utils.DynamoDBWriteCapacityFlag.Name),
   128  			PerfCheck:          !ctx.IsSet(utils.DBNoPerformanceMetricsFlag.Name),
   129  		},
   130  	}
   131  	if len(srcDBC.DBType) == 0 { // changed to invalid type
   132  		return nil, nil, errors.New("srcDB is not specified or invalid : " + ctx.GlobalString(utils.DbTypeFlag.Name))
   133  	}
   134  
   135  	// dstDB
   136  	dstDBC := &database.DBConfig{
   137  		Dir:                ctx.GlobalString(utils.DstDataDirFlag.Name),
   138  		DBType:             database.DBType(ctx.GlobalString(utils.DstDbTypeFlag.Name)).ToValid(),
   139  		SingleDB:           ctx.GlobalBool(utils.DstSingleDBFlag.Name),
   140  		NumStateTrieShards: ctx.GlobalUint(utils.DstNumStateTrieShardsFlag.Name),
   141  		OpenFilesLimit:     database.GetOpenFilesLimit(),
   142  
   143  		LevelDBCacheSize:    ctx.GlobalInt(utils.DstLevelDBCacheSizeFlag.Name),
   144  		LevelDBCompression:  database.LevelDBCompressionType(ctx.GlobalInt(utils.DstLevelDBCompressionTypeFlag.Name)),
   145  		EnableDBPerfMetrics: !ctx.IsSet(utils.DBNoPerformanceMetricsFlag.Name),
   146  
   147  		DynamoDBConfig: &database.DynamoDBConfig{
   148  			TableName:          ctx.GlobalString(utils.DstDynamoDBTableNameFlag.Name),
   149  			Region:             ctx.GlobalString(utils.DstDynamoDBRegionFlag.Name),
   150  			IsProvisioned:      ctx.GlobalBool(utils.DstDynamoDBIsProvisionedFlag.Name),
   151  			ReadCapacityUnits:  ctx.GlobalInt64(utils.DstDynamoDBReadCapacityFlag.Name),
   152  			WriteCapacityUnits: ctx.GlobalInt64(utils.DstDynamoDBWriteCapacityFlag.Name),
   153  			PerfCheck:          !ctx.IsSet(utils.DBNoPerformanceMetricsFlag.Name),
   154  		},
   155  	}
   156  	if len(dstDBC.DBType) == 0 { // changed to invalid type
   157  		return nil, nil, errors.New("dstDB is not specified or invalid : " + ctx.GlobalString(utils.DstDbTypeFlag.Name))
   158  	}
   159  
   160  	return srcDBC, dstDBC, nil
   161  }
   162  
   163  // TODO When it is stopped, store previous db migration info.
   164  //      Continue migration on next call with the same setting.