github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/cmd/u2u/launcher/dbcmd.go (about)

     1  package launcher
     2  
     3  import (
     4  	"fmt"
     5  	"path"
     6  
     7  	"github.com/syndtr/goleveldb/leveldb/opt"
     8  	"github.com/unicornultrafoundation/go-helios/u2udb"
     9  	"github.com/unicornultrafoundation/go-helios/u2udb/cachedproducer"
    10  	"github.com/unicornultrafoundation/go-helios/u2udb/multidb"
    11  	"github.com/unicornultrafoundation/go-u2u/cmd/utils"
    12  	"github.com/unicornultrafoundation/go-u2u/ethdb"
    13  	"github.com/unicornultrafoundation/go-u2u/log"
    14  	"gopkg.in/urfave/cli.v1"
    15  
    16  	"github.com/unicornultrafoundation/go-u2u/gossip"
    17  	"github.com/unicornultrafoundation/go-u2u/integration"
    18  	"github.com/unicornultrafoundation/go-u2u/utils/dbutil/compactdb"
    19  )
    20  
    21  var (
    22  	experimentalFlag = cli.BoolFlag{
    23  		Name:  "experimental",
    24  		Usage: "Allow experimental DB fixing",
    25  	}
    26  	dbCommand = cli.Command{
    27  		Name:        "db",
    28  		Usage:       "A set of commands related to leveldb database",
    29  		Category:    "DB COMMANDS",
    30  		Description: "",
    31  		Subcommands: []cli.Command{
    32  			{
    33  				Name:      "compact",
    34  				Usage:     "Compact all databases",
    35  				ArgsUsage: "",
    36  				Action:    utils.MigrateFlags(compact),
    37  				Category:  "DB COMMANDS",
    38  				Flags: []cli.Flag{
    39  					utils.DataDirFlag,
    40  				},
    41  				Description: `
    42  u2u db compact
    43  will compact all databases under datadir's chaindata.
    44  `,
    45  			},
    46  			{
    47  				Name:      "transform",
    48  				Usage:     "Transform DBs layout",
    49  				ArgsUsage: "",
    50  				Action:    utils.MigrateFlags(dbTransform),
    51  				Category:  "DB COMMANDS",
    52  				Flags: []cli.Flag{
    53  					utils.DataDirFlag,
    54  				},
    55  				Description: `
    56  u2u db transform
    57  will migrate tables layout according to the configuration.
    58  `,
    59  			},
    60  			{
    61  				Name:      "heal",
    62  				Usage:     "Experimental - try to heal dirty DB",
    63  				ArgsUsage: "",
    64  				Action:    utils.MigrateFlags(healDirty),
    65  				Category:  "DB COMMANDS",
    66  				Flags: []cli.Flag{
    67  					utils.DataDirFlag,
    68  					experimentalFlag,
    69  				},
    70  				Description: `
    71  u2u db heal --experimental
    72  Experimental - try to heal dirty DB.
    73  `,
    74  			},
    75  		},
    76  	}
    77  )
    78  
    79  func makeUncheckedDBsProducers(cfg *config) map[multidb.TypeName]u2udb.IterableDBProducer {
    80  	dbsList, _ := integration.SupportedDBs(path.Join(cfg.Node.DataDir, "chaindata"), cfg.DBs.RuntimeCache)
    81  	return dbsList
    82  }
    83  
    84  func makeUncheckedCachedDBsProducers(chaindataDir string) map[multidb.TypeName]u2udb.FullDBProducer {
    85  	dbTypes, _ := integration.SupportedDBs(chaindataDir, integration.DBsCacheConfig{
    86  		Table: map[string]integration.DBCacheConfig{
    87  			"": {
    88  				Cache:   1024 * opt.MiB,
    89  				Fdlimit: uint64(utils.MakeDatabaseHandles() / 2),
    90  			},
    91  		},
    92  	})
    93  	wrappedDbTypes := make(map[multidb.TypeName]u2udb.FullDBProducer)
    94  	for typ, producer := range dbTypes {
    95  		wrappedDbTypes[typ] = cachedproducer.WrapAll(&integration.DummyScopedProducer{IterableDBProducer: producer})
    96  	}
    97  	return wrappedDbTypes
    98  }
    99  
   100  func makeCheckedDBsProducers(cfg *config) map[multidb.TypeName]u2udb.IterableDBProducer {
   101  	if err := integration.CheckStateInitialized(path.Join(cfg.Node.DataDir, "chaindata"), cfg.DBs); err != nil {
   102  		utils.Fatalf(err.Error())
   103  	}
   104  	return makeUncheckedDBsProducers(cfg)
   105  }
   106  
   107  func makeDirectDBsProducerFrom(dbsList map[multidb.TypeName]u2udb.IterableDBProducer, cfg *config) u2udb.FullDBProducer {
   108  	multiRawDbs, err := integration.MakeDirectMultiProducer(dbsList, cfg.DBs.Routing)
   109  	if err != nil {
   110  		utils.Fatalf("Failed to initialize multi DB producer: %v", err)
   111  	}
   112  	return multiRawDbs
   113  }
   114  
   115  func makeDirectDBsProducer(cfg *config) u2udb.FullDBProducer {
   116  	dbsList := makeCheckedDBsProducers(cfg)
   117  	return makeDirectDBsProducerFrom(dbsList, cfg)
   118  }
   119  
   120  func makeGossipStore(producer u2udb.FlushableDBProducer, cfg *config) *gossip.Store {
   121  	return gossip.NewStore(producer, cfg.U2UStore)
   122  }
   123  
   124  func compact(ctx *cli.Context) error {
   125  
   126  	cfg := makeAllConfigs(ctx)
   127  
   128  	producers := makeCheckedDBsProducers(cfg)
   129  	for typ, p := range producers {
   130  		for _, name := range p.Names() {
   131  			if err := compactDB(typ, name, p); err != nil {
   132  				return err
   133  			}
   134  		}
   135  	}
   136  
   137  	return nil
   138  }
   139  
   140  func compactDB(typ multidb.TypeName, name string, producer u2udb.DBProducer) error {
   141  	humanName := path.Join(string(typ), name)
   142  	db, err := producer.OpenDB(name)
   143  	defer db.Close()
   144  	if err != nil {
   145  		log.Error("Cannot open db or db does not exists", "db", humanName)
   146  		return err
   147  	}
   148  
   149  	log.Info("Stats before compaction", "db", humanName)
   150  	showDbStats(db)
   151  
   152  	err = compactdb.Compact(db, humanName, 64*opt.GiB)
   153  	if err != nil {
   154  		log.Error("Database compaction failed", "err", err)
   155  		return err
   156  	}
   157  
   158  	log.Info("Stats after compaction", "db", humanName)
   159  	showDbStats(db)
   160  
   161  	return nil
   162  }
   163  
   164  func showDbStats(db ethdb.KeyValueStater) {
   165  	if stats, err := db.Stat("stats"); err != nil {
   166  		log.Warn("Failed to read database stats", "error", err)
   167  	} else {
   168  		fmt.Println(stats)
   169  	}
   170  	if ioStats, err := db.Stat("iostats"); err != nil {
   171  		log.Warn("Failed to read database iostats", "error", err)
   172  	} else {
   173  		fmt.Println(ioStats)
   174  	}
   175  }