github.com/klaytn/klaytn@v1.12.1/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  	"github.com/urfave/cli/v2"
    27  )
    28  
    29  var (
    30  	dbMigrationFlags = append(utils.DBMigrationSrcFlags, utils.DBMigrationDstFlags...)
    31  
    32  	MigrationCommand = &cli.Command{
    33  		Name:     "db-migration",
    34  		Usage:    "db migration",
    35  		Flags:    []cli.Flag{},
    36  		Category: "DB MIGRATION COMMANDS",
    37  		Description: `
    38  The migration command migrates a DB to another DB.
    39  The type of DBs can be different.
    40  (e.g. LevelDB -> LevelDB, LevelDB -> BadgerDB, LevelDB -> DynamoDB)
    41  Note: This feature is only provided when srcDB is single LevelDB.
    42  Note: Do not use db migration while a node is executing.
    43  `,
    44  		Subcommands: []*cli.Command{
    45  			{
    46  				Name:   "start",
    47  				Usage:  "Start db migration",
    48  				Flags:  dbMigrationFlags,
    49  				Action: startMigration,
    50  				Description: `
    51  This command starts DB migration.
    52  
    53  Even if db dir names are changed in srcDB, the original db dir names are used in dstDB.
    54  (e.g. use 'statetrie' instead of 'statetrie_migrated_xxxxx')
    55  If dst db is singleDB, you should set dst.datadir or db.dst.dynamo.tablename
    56  to the original db dir name.
    57  (e.g. Data dir : 'chaindata/klay/statetrie', Dynamo table name : 'klaytn-statetrie')
    58  
    59  Note: This feature is only provided when srcDB is single LevelDB.`,
    60  			},
    61  		},
    62  	}
    63  )
    64  
    65  func startMigration(ctx *cli.Context) error {
    66  	srcDBManager, dstDBManager, err := createDBManagerForMigration(ctx)
    67  	if err != nil {
    68  		return err
    69  	}
    70  	defer srcDBManager.Close()
    71  	defer dstDBManager.Close()
    72  
    73  	return srcDBManager.StartDBMigration(dstDBManager)
    74  }
    75  
    76  func createDBManagerForMigration(ctx *cli.Context) (database.DBManager, database.DBManager, error) {
    77  	// create db config from ctx
    78  	srcDBConfig, dstDBConfig, dbManagerCreationErr := createDBConfigForMigration(ctx)
    79  	if dbManagerCreationErr != nil {
    80  		return nil, nil, dbManagerCreationErr
    81  	}
    82  
    83  	// log
    84  	s, _ := json.Marshal(srcDBConfig)
    85  	d, _ := json.Marshal(dstDBConfig)
    86  	logger.Info("dbManager created", "\nsrcDB", string(s), "\ndstDB", string(d))
    87  
    88  	// create DBManager
    89  	srcDBManager := database.NewDBManager(srcDBConfig)
    90  	dstDBManager := database.NewDBManager(dstDBConfig)
    91  
    92  	return srcDBManager, dstDBManager, nil
    93  }
    94  
    95  func createDBConfigForMigration(ctx *cli.Context) (*database.DBConfig, *database.DBConfig, error) {
    96  	// srcDB
    97  	srcDBC := &database.DBConfig{
    98  		Dir:                ctx.String(utils.DataDirFlag.Name),
    99  		DBType:             database.DBType(ctx.String(utils.DbTypeFlag.Name)).ToValid(),
   100  		SingleDB:           ctx.Bool(utils.SingleDBFlag.Name),
   101  		NumStateTrieShards: ctx.Uint(utils.NumStateTrieShardsFlag.Name),
   102  		OpenFilesLimit:     database.GetOpenFilesLimit(),
   103  
   104  		LevelDBCacheSize:    ctx.Int(utils.LevelDBCacheSizeFlag.Name),
   105  		LevelDBCompression:  database.LevelDBCompressionType(ctx.Int(utils.LevelDBCompressionTypeFlag.Name)),
   106  		EnableDBPerfMetrics: !ctx.Bool(utils.DBNoPerformanceMetricsFlag.Name),
   107  
   108  		DynamoDBConfig: &database.DynamoDBConfig{
   109  			TableName:          ctx.String(utils.DynamoDBTableNameFlag.Name),
   110  			Region:             ctx.String(utils.DynamoDBRegionFlag.Name),
   111  			IsProvisioned:      ctx.Bool(utils.DynamoDBIsProvisionedFlag.Name),
   112  			ReadCapacityUnits:  ctx.Int64(utils.DynamoDBReadCapacityFlag.Name),
   113  			WriteCapacityUnits: ctx.Int64(utils.DynamoDBWriteCapacityFlag.Name),
   114  			PerfCheck:          !ctx.Bool(utils.DBNoPerformanceMetricsFlag.Name),
   115  		},
   116  
   117  		RocksDBConfig: &database.RocksDBConfig{
   118  			CacheSize:                 ctx.Uint64(utils.RocksDBCacheSizeFlag.Name),
   119  			DumpMallocStat:            ctx.Bool(utils.RocksDBDumpMallocStatFlag.Name),
   120  			DisableMetrics:            ctx.Bool(utils.RocksDBDisableMetricsFlag.Name),
   121  			Secondary:                 ctx.Bool(utils.RocksDBSecondaryFlag.Name),
   122  			CompressionType:           ctx.String(utils.RocksDBCompressionTypeFlag.Name),
   123  			BottommostCompressionType: ctx.String(utils.RocksDBBottommostCompressionTypeFlag.Name),
   124  			FilterPolicy:              ctx.String(utils.RocksDBFilterPolicyFlag.Name),
   125  			MaxOpenFiles:              ctx.Int(utils.RocksDBMaxOpenFilesFlag.Name),
   126  			CacheIndexAndFilter:       ctx.Bool(utils.RocksDBCacheIndexAndFilterFlag.Name),
   127  		},
   128  	}
   129  	if len(srcDBC.DBType) == 0 { // changed to invalid type
   130  		return nil, nil, errors.New("srcDB is not specified or invalid : " + ctx.String(utils.DbTypeFlag.Name))
   131  	}
   132  
   133  	// dstDB
   134  	dstDBC := &database.DBConfig{
   135  		Dir:                ctx.String(utils.DstDataDirFlag.Name),
   136  		DBType:             database.DBType(ctx.String(utils.DstDbTypeFlag.Name)).ToValid(),
   137  		SingleDB:           ctx.Bool(utils.DstSingleDBFlag.Name),
   138  		NumStateTrieShards: ctx.Uint(utils.DstNumStateTrieShardsFlag.Name),
   139  		OpenFilesLimit:     database.GetOpenFilesLimit(),
   140  
   141  		LevelDBCacheSize:    ctx.Int(utils.DstLevelDBCacheSizeFlag.Name),
   142  		LevelDBCompression:  database.LevelDBCompressionType(ctx.Int(utils.DstLevelDBCompressionTypeFlag.Name)),
   143  		EnableDBPerfMetrics: !ctx.Bool(utils.DBNoPerformanceMetricsFlag.Name),
   144  
   145  		DynamoDBConfig: &database.DynamoDBConfig{
   146  			TableName:          ctx.String(utils.DstDynamoDBTableNameFlag.Name),
   147  			Region:             ctx.String(utils.DstDynamoDBRegionFlag.Name),
   148  			IsProvisioned:      ctx.Bool(utils.DstDynamoDBIsProvisionedFlag.Name),
   149  			ReadCapacityUnits:  ctx.Int64(utils.DstDynamoDBReadCapacityFlag.Name),
   150  			WriteCapacityUnits: ctx.Int64(utils.DstDynamoDBWriteCapacityFlag.Name),
   151  			PerfCheck:          !ctx.Bool(utils.DBNoPerformanceMetricsFlag.Name),
   152  		},
   153  
   154  		RocksDBConfig: &database.RocksDBConfig{
   155  			CacheSize:                 ctx.Uint64(utils.DstRocksDBCacheSizeFlag.Name),
   156  			DumpMallocStat:            ctx.Bool(utils.DstRocksDBDumpMallocStatFlag.Name),
   157  			DisableMetrics:            ctx.Bool(utils.DstRocksDBDisableMetricsFlag.Name),
   158  			Secondary:                 ctx.Bool(utils.DstRocksDBSecondaryFlag.Name),
   159  			CompressionType:           ctx.String(utils.DstRocksDBCompressionTypeFlag.Name),
   160  			BottommostCompressionType: ctx.String(utils.DstRocksDBBottommostCompressionTypeFlag.Name),
   161  			FilterPolicy:              ctx.String(utils.DstRocksDBFilterPolicyFlag.Name),
   162  			MaxOpenFiles:              ctx.Int(utils.DstRocksDBMaxOpenFilesFlag.Name),
   163  			CacheIndexAndFilter:       ctx.Bool(utils.DstRocksDBCacheIndexAndFilterFlag.Name),
   164  		},
   165  	}
   166  	if len(dstDBC.DBType) == 0 { // changed to invalid type
   167  		return nil, nil, errors.New("dstDB is not specified or invalid : " + ctx.String(utils.DstDbTypeFlag.Name))
   168  	}
   169  
   170  	return srcDBC, dstDBC, nil
   171  }
   172  
   173  // TODO When it is stopped, store previous db migration info.
   174  //      Continue migration on next call with the same setting.