cmd, core, eth, graphql, trie: no persisted clean trie cache file (#27525)
The clean trie cache is persisted periodically, therefore Geth can quickly warmup the cache in next restart. However it will reduce the robustness of system. The assumption is held in Geth that if the parent trie node is present, then the entire sub-trie associated with the parent are all prensent. Imagine the scenario that Geth rewinds itself to a past block and restart, but Geth finds the root node of "future state" in clean cache then regard this state is present in disk, while is not in fact. Another example is offline pruning tool. Whenever an offline pruning is performed, the clean cache file has to be removed to aviod hitting the root node of "deleted states" in clean cache. All in all, compare with the minor performance gain, system robustness is something we care more.
This commit is contained in:
parent
6ca3ef9a7b
commit
59f7b289c3
@ -109,15 +109,13 @@ func setupGeth(stack *node.Node) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
backend, err := eth.New(stack, ðconfig.Config{
|
backend, err := eth.New(stack, ðconfig.Config{
|
||||||
Genesis: &chain.genesis,
|
Genesis: &chain.genesis,
|
||||||
NetworkId: chain.genesis.Config.ChainID.Uint64(), // 19763
|
NetworkId: chain.genesis.Config.ChainID.Uint64(), // 19763
|
||||||
DatabaseCache: 10,
|
DatabaseCache: 10,
|
||||||
TrieCleanCache: 10,
|
TrieCleanCache: 10,
|
||||||
TrieCleanCacheJournal: "",
|
TrieDirtyCache: 16,
|
||||||
TrieCleanCacheRejournal: 60 * time.Minute,
|
TrieTimeout: 60 * time.Minute,
|
||||||
TrieDirtyCache: 16,
|
SnapshotCache: 10,
|
||||||
TrieTimeout: 60 * time.Minute,
|
|
||||||
SnapshotCache: 10,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -276,6 +276,10 @@ func deprecated(field string) bool {
|
|||||||
return true
|
return true
|
||||||
case "ethconfig.Config.EWASMInterpreter":
|
case "ethconfig.Config.EWASMInterpreter":
|
||||||
return true
|
return true
|
||||||
|
case "ethconfig.Config.TrieCleanCacheJournal":
|
||||||
|
return true
|
||||||
|
case "ethconfig.Config.TrieCleanCacheRejournal":
|
||||||
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,6 @@ var (
|
|||||||
ArgsUsage: "<root>",
|
ArgsUsage: "<root>",
|
||||||
Action: pruneState,
|
Action: pruneState,
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.CacheTrieJournalFlag,
|
|
||||||
utils.BloomFilterSizeFlag,
|
utils.BloomFilterSizeFlag,
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
||||||
Description: `
|
Description: `
|
||||||
@ -160,7 +159,7 @@ block is used.
|
|||||||
// Deprecation: this command should be deprecated once the hash-based
|
// Deprecation: this command should be deprecated once the hash-based
|
||||||
// scheme is deprecated.
|
// scheme is deprecated.
|
||||||
func pruneState(ctx *cli.Context) error {
|
func pruneState(ctx *cli.Context) error {
|
||||||
stack, config := makeConfigNode(ctx)
|
stack, _ := makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
chaindb := utils.MakeChainDatabase(ctx, stack, false)
|
chaindb := utils.MakeChainDatabase(ctx, stack, false)
|
||||||
@ -168,7 +167,6 @@ func pruneState(ctx *cli.Context) error {
|
|||||||
|
|
||||||
prunerconfig := pruner.Config{
|
prunerconfig := pruner.Config{
|
||||||
Datadir: stack.ResolvePath(""),
|
Datadir: stack.ResolvePath(""),
|
||||||
Cachedir: stack.ResolvePath(config.Eth.TrieCleanCacheJournal),
|
|
||||||
BloomSize: ctx.Uint64(utils.BloomFilterSizeFlag.Name),
|
BloomSize: ctx.Uint64(utils.BloomFilterSizeFlag.Name),
|
||||||
}
|
}
|
||||||
pruner, err := pruner.NewPruner(chaindb, prunerconfig)
|
pruner, err := pruner.NewPruner(chaindb, prunerconfig)
|
||||||
|
@ -410,18 +410,6 @@ var (
|
|||||||
Value: 15,
|
Value: 15,
|
||||||
Category: flags.PerfCategory,
|
Category: flags.PerfCategory,
|
||||||
}
|
}
|
||||||
CacheTrieJournalFlag = &cli.StringFlag{
|
|
||||||
Name: "cache.trie.journal",
|
|
||||||
Usage: "Disk journal directory for trie cache to survive node restarts",
|
|
||||||
Value: ethconfig.Defaults.TrieCleanCacheJournal,
|
|
||||||
Category: flags.PerfCategory,
|
|
||||||
}
|
|
||||||
CacheTrieRejournalFlag = &cli.DurationFlag{
|
|
||||||
Name: "cache.trie.rejournal",
|
|
||||||
Usage: "Time interval to regenerate the trie cache journal",
|
|
||||||
Value: ethconfig.Defaults.TrieCleanCacheRejournal,
|
|
||||||
Category: flags.PerfCategory,
|
|
||||||
}
|
|
||||||
CacheGCFlag = &cli.IntFlag{
|
CacheGCFlag = &cli.IntFlag{
|
||||||
Name: "cache.gc",
|
Name: "cache.gc",
|
||||||
Usage: "Percentage of cache memory allowance to use for trie pruning (default = 25% full mode, 0% archive mode)",
|
Usage: "Percentage of cache memory allowance to use for trie pruning (default = 25% full mode, 0% archive mode)",
|
||||||
@ -1710,12 +1698,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
|||||||
if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheTrieFlag.Name) {
|
if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheTrieFlag.Name) {
|
||||||
cfg.TrieCleanCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheTrieFlag.Name) / 100
|
cfg.TrieCleanCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheTrieFlag.Name) / 100
|
||||||
}
|
}
|
||||||
if ctx.IsSet(CacheTrieJournalFlag.Name) {
|
|
||||||
cfg.TrieCleanCacheJournal = ctx.String(CacheTrieJournalFlag.Name)
|
|
||||||
}
|
|
||||||
if ctx.IsSet(CacheTrieRejournalFlag.Name) {
|
|
||||||
cfg.TrieCleanCacheRejournal = ctx.Duration(CacheTrieRejournalFlag.Name)
|
|
||||||
}
|
|
||||||
if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheGCFlag.Name) {
|
if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheGCFlag.Name) {
|
||||||
cfg.TrieDirtyCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100
|
cfg.TrieDirtyCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,8 @@ var ShowDeprecated = &cli.Command{
|
|||||||
|
|
||||||
var DeprecatedFlags = []cli.Flag{
|
var DeprecatedFlags = []cli.Flag{
|
||||||
NoUSBFlag,
|
NoUSBFlag,
|
||||||
|
CacheTrieJournalFlag,
|
||||||
|
CacheTrieRejournalFlag,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -42,6 +44,17 @@ var (
|
|||||||
Usage: "Disables monitoring for and managing USB hardware wallets (deprecated)",
|
Usage: "Disables monitoring for and managing USB hardware wallets (deprecated)",
|
||||||
Category: flags.DeprecatedCategory,
|
Category: flags.DeprecatedCategory,
|
||||||
}
|
}
|
||||||
|
// (Deprecated June 2023, shown in aliased flags section)
|
||||||
|
CacheTrieJournalFlag = &cli.StringFlag{
|
||||||
|
Name: "cache.trie.journal",
|
||||||
|
Usage: "Disk journal directory for trie cache to survive node restarts",
|
||||||
|
Category: flags.PerfCategory,
|
||||||
|
}
|
||||||
|
CacheTrieRejournalFlag = &cli.DurationFlag{
|
||||||
|
Name: "cache.trie.rejournal",
|
||||||
|
Usage: "Time interval to regenerate the trie cache journal",
|
||||||
|
Category: flags.PerfCategory,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// showDeprecated displays deprecated flags that will be soon removed from the codebase.
|
// showDeprecated displays deprecated flags that will be soon removed from the codebase.
|
||||||
|
@ -130,8 +130,6 @@ const (
|
|||||||
// that's resident in a blockchain.
|
// that's resident in a blockchain.
|
||||||
type CacheConfig struct {
|
type CacheConfig struct {
|
||||||
TrieCleanLimit int // Memory allowance (MB) to use for caching trie nodes in memory
|
TrieCleanLimit int // Memory allowance (MB) to use for caching trie nodes in memory
|
||||||
TrieCleanJournal string // Disk journal for saving clean cache entries.
|
|
||||||
TrieCleanRejournal time.Duration // Time interval to dump clean cache to disk periodically
|
|
||||||
TrieCleanNoPrefetch bool // Whether to disable heuristic state prefetching for followup blocks
|
TrieCleanNoPrefetch bool // Whether to disable heuristic state prefetching for followup blocks
|
||||||
TrieDirtyLimit int // Memory limit (MB) at which to start flushing dirty trie nodes to disk
|
TrieDirtyLimit int // Memory limit (MB) at which to start flushing dirty trie nodes to disk
|
||||||
TrieDirtyDisabled bool // Whether to disable trie write caching and GC altogether (archive node)
|
TrieDirtyDisabled bool // Whether to disable trie write caching and GC altogether (archive node)
|
||||||
@ -238,7 +236,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
|||||||
// Open trie database with provided config
|
// Open trie database with provided config
|
||||||
triedb := trie.NewDatabaseWithConfig(db, &trie.Config{
|
triedb := trie.NewDatabaseWithConfig(db, &trie.Config{
|
||||||
Cache: cacheConfig.TrieCleanLimit,
|
Cache: cacheConfig.TrieCleanLimit,
|
||||||
Journal: cacheConfig.TrieCleanJournal,
|
|
||||||
Preimages: cacheConfig.Preimages,
|
Preimages: cacheConfig.Preimages,
|
||||||
})
|
})
|
||||||
// Setup the genesis block, commit the provided genesis specification
|
// Setup the genesis block, commit the provided genesis specification
|
||||||
@ -411,18 +408,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
|||||||
bc.wg.Add(1)
|
bc.wg.Add(1)
|
||||||
go bc.updateFutureBlocks()
|
go bc.updateFutureBlocks()
|
||||||
|
|
||||||
// If periodic cache journal is required, spin it up.
|
|
||||||
if bc.cacheConfig.TrieCleanRejournal > 0 {
|
|
||||||
if bc.cacheConfig.TrieCleanRejournal < time.Minute {
|
|
||||||
log.Warn("Sanitizing invalid trie cache journal time", "provided", bc.cacheConfig.TrieCleanRejournal, "updated", time.Minute)
|
|
||||||
bc.cacheConfig.TrieCleanRejournal = time.Minute
|
|
||||||
}
|
|
||||||
bc.wg.Add(1)
|
|
||||||
go func() {
|
|
||||||
defer bc.wg.Done()
|
|
||||||
bc.triedb.SaveCachePeriodically(bc.cacheConfig.TrieCleanJournal, bc.cacheConfig.TrieCleanRejournal, bc.quit)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
// Rewind the chain in case of an incompatible config upgrade.
|
// Rewind the chain in case of an incompatible config upgrade.
|
||||||
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
|
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
|
||||||
log.Warn("Rewinding chain to upgrade configuration", "err", compat)
|
log.Warn("Rewinding chain to upgrade configuration", "err", compat)
|
||||||
@ -987,11 +972,6 @@ func (bc *BlockChain) Stop() {
|
|||||||
if err := bc.stateCache.TrieDB().Close(); err != nil {
|
if err := bc.stateCache.TrieDB().Close(); err != nil {
|
||||||
log.Error("Failed to close trie db", "err", err)
|
log.Error("Failed to close trie db", "err", err)
|
||||||
}
|
}
|
||||||
// Ensure all live cached entries be saved into disk, so that we can skip
|
|
||||||
// cache warmup when node restarts.
|
|
||||||
if bc.cacheConfig.TrieCleanJournal != "" {
|
|
||||||
bc.triedb.SaveCache(bc.cacheConfig.TrieCleanJournal)
|
|
||||||
}
|
|
||||||
log.Info("Blockchain stopped")
|
log.Info("Blockchain stopped")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,6 @@ const (
|
|||||||
// Config includes all the configurations for pruning.
|
// Config includes all the configurations for pruning.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Datadir string // The directory of the state database
|
Datadir string // The directory of the state database
|
||||||
Cachedir string // The directory of state clean cache
|
|
||||||
BloomSize uint64 // The Megabytes of memory allocated to bloom-filter
|
BloomSize uint64 // The Megabytes of memory allocated to bloom-filter
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +240,7 @@ func (p *Pruner) Prune(root common.Hash) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if stateBloomRoot != (common.Hash{}) {
|
if stateBloomRoot != (common.Hash{}) {
|
||||||
return RecoverPruning(p.config.Datadir, p.db, p.config.Cachedir)
|
return RecoverPruning(p.config.Datadir, p.db)
|
||||||
}
|
}
|
||||||
// If the target state root is not specified, use the HEAD-127 as the
|
// If the target state root is not specified, use the HEAD-127 as the
|
||||||
// target. The reason for picking it is:
|
// target. The reason for picking it is:
|
||||||
@ -299,12 +298,6 @@ func (p *Pruner) Prune(root common.Hash) error {
|
|||||||
log.Info("Selecting user-specified state as the pruning target", "root", root)
|
log.Info("Selecting user-specified state as the pruning target", "root", root)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Before start the pruning, delete the clean trie cache first.
|
|
||||||
// It's necessary otherwise in the next restart we will hit the
|
|
||||||
// deleted state root in the "clean cache" so that the incomplete
|
|
||||||
// state is picked for usage.
|
|
||||||
deleteCleanTrieCache(p.config.Cachedir)
|
|
||||||
|
|
||||||
// All the state roots of the middle layer should be forcibly pruned,
|
// All the state roots of the middle layer should be forcibly pruned,
|
||||||
// otherwise the dangling state will be left.
|
// otherwise the dangling state will be left.
|
||||||
middleRoots := make(map[common.Hash]struct{})
|
middleRoots := make(map[common.Hash]struct{})
|
||||||
@ -342,7 +335,7 @@ func (p *Pruner) Prune(root common.Hash) error {
|
|||||||
// pruning can be resumed. What's more if the bloom filter is constructed, the
|
// pruning can be resumed. What's more if the bloom filter is constructed, the
|
||||||
// pruning **has to be resumed**. Otherwise a lot of dangling nodes may be left
|
// pruning **has to be resumed**. Otherwise a lot of dangling nodes may be left
|
||||||
// in the disk.
|
// in the disk.
|
||||||
func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string) error {
|
func RecoverPruning(datadir string, db ethdb.Database) error {
|
||||||
stateBloomPath, stateBloomRoot, err := findBloomFilter(datadir)
|
stateBloomPath, stateBloomRoot, err := findBloomFilter(datadir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -378,12 +371,6 @@ func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string) err
|
|||||||
}
|
}
|
||||||
log.Info("Loaded state bloom filter", "path", stateBloomPath)
|
log.Info("Loaded state bloom filter", "path", stateBloomPath)
|
||||||
|
|
||||||
// Before start the pruning, delete the clean trie cache first.
|
|
||||||
// It's necessary otherwise in the next restart we will hit the
|
|
||||||
// deleted state root in the "clean cache" so that the incomplete
|
|
||||||
// state is picked for usage.
|
|
||||||
deleteCleanTrieCache(trieCachePath)
|
|
||||||
|
|
||||||
// All the state roots of the middle layers should be forcibly pruned,
|
// All the state roots of the middle layers should be forcibly pruned,
|
||||||
// otherwise the dangling state will be left.
|
// otherwise the dangling state will be left.
|
||||||
var (
|
var (
|
||||||
@ -497,23 +484,3 @@ func findBloomFilter(datadir string) (string, common.Hash, error) {
|
|||||||
}
|
}
|
||||||
return stateBloomPath, stateBloomRoot, nil
|
return stateBloomPath, stateBloomRoot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const warningLog = `
|
|
||||||
|
|
||||||
WARNING!
|
|
||||||
|
|
||||||
The clean trie cache is not found. Please delete it by yourself after the
|
|
||||||
pruning. Remember don't start the Geth without deleting the clean trie cache
|
|
||||||
otherwise the entire database may be damaged!
|
|
||||||
|
|
||||||
Check the command description "geth snapshot prune-state --help" for more details.
|
|
||||||
`
|
|
||||||
|
|
||||||
func deleteCleanTrieCache(path string) {
|
|
||||||
if !common.FileExist(path) {
|
|
||||||
log.Warn(warningLog)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
os.RemoveAll(path)
|
|
||||||
log.Info("Deleted trie clean cache", "path", path)
|
|
||||||
}
|
|
||||||
|
@ -132,7 +132,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb, stack.ResolvePath(config.TrieCleanCacheJournal)); err != nil {
|
if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb); err != nil {
|
||||||
log.Error("Failed to recover state", "error", err)
|
log.Error("Failed to recover state", "error", err)
|
||||||
}
|
}
|
||||||
// Transfer mining-related config to the ethash config.
|
// Transfer mining-related config to the ethash config.
|
||||||
@ -184,8 +184,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||||||
}
|
}
|
||||||
cacheConfig = &core.CacheConfig{
|
cacheConfig = &core.CacheConfig{
|
||||||
TrieCleanLimit: config.TrieCleanCache,
|
TrieCleanLimit: config.TrieCleanCache,
|
||||||
TrieCleanJournal: stack.ResolvePath(config.TrieCleanCacheJournal),
|
|
||||||
TrieCleanRejournal: config.TrieCleanCacheRejournal,
|
|
||||||
TrieCleanNoPrefetch: config.NoPrefetch,
|
TrieCleanNoPrefetch: config.NoPrefetch,
|
||||||
TrieDirtyLimit: config.TrieDirtyCache,
|
TrieDirtyLimit: config.TrieDirtyCache,
|
||||||
TrieDirtyDisabled: config.NoPruning,
|
TrieDirtyDisabled: config.NoPruning,
|
||||||
|
@ -57,25 +57,23 @@ var LightClientGPO = gasprice.Config{
|
|||||||
|
|
||||||
// Defaults contains default settings for use on the Ethereum main net.
|
// Defaults contains default settings for use on the Ethereum main net.
|
||||||
var Defaults = Config{
|
var Defaults = Config{
|
||||||
SyncMode: downloader.SnapSync,
|
SyncMode: downloader.SnapSync,
|
||||||
NetworkId: 1,
|
NetworkId: 1,
|
||||||
TxLookupLimit: 2350000,
|
TxLookupLimit: 2350000,
|
||||||
LightPeers: 100,
|
LightPeers: 100,
|
||||||
UltraLightFraction: 75,
|
UltraLightFraction: 75,
|
||||||
DatabaseCache: 512,
|
DatabaseCache: 512,
|
||||||
TrieCleanCache: 154,
|
TrieCleanCache: 154,
|
||||||
TrieCleanCacheJournal: "triecache",
|
TrieDirtyCache: 256,
|
||||||
TrieCleanCacheRejournal: 60 * time.Minute,
|
TrieTimeout: 60 * time.Minute,
|
||||||
TrieDirtyCache: 256,
|
SnapshotCache: 102,
|
||||||
TrieTimeout: 60 * time.Minute,
|
FilterLogCacheSize: 32,
|
||||||
SnapshotCache: 102,
|
Miner: miner.DefaultConfig,
|
||||||
FilterLogCacheSize: 32,
|
TxPool: legacypool.DefaultConfig,
|
||||||
Miner: miner.DefaultConfig,
|
RPCGasCap: 50000000,
|
||||||
TxPool: legacypool.DefaultConfig,
|
RPCEVMTimeout: 5 * time.Second,
|
||||||
RPCGasCap: 50000000,
|
GPO: FullNodeGPO,
|
||||||
RPCEVMTimeout: 5 * time.Second,
|
RPCTxFeeCap: 1, // 1 ether
|
||||||
GPO: FullNodeGPO,
|
|
||||||
RPCTxFeeCap: 1, // 1 ether
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:generate go run github.com/fjl/gencodec -type Config -formats toml -out gen_config.go
|
//go:generate go run github.com/fjl/gencodec -type Config -formats toml -out gen_config.go
|
||||||
@ -124,13 +122,11 @@ type Config struct {
|
|||||||
DatabaseCache int
|
DatabaseCache int
|
||||||
DatabaseFreezer string
|
DatabaseFreezer string
|
||||||
|
|
||||||
TrieCleanCache int
|
TrieCleanCache int
|
||||||
TrieCleanCacheJournal string `toml:",omitempty"` // Disk journal directory for trie cache to survive node restarts
|
TrieDirtyCache int
|
||||||
TrieCleanCacheRejournal time.Duration `toml:",omitempty"` // Time interval to regenerate the journal for clean cache
|
TrieTimeout time.Duration
|
||||||
TrieDirtyCache int
|
SnapshotCache int
|
||||||
TrieTimeout time.Duration
|
Preimages bool
|
||||||
SnapshotCache int
|
|
||||||
Preimages bool
|
|
||||||
|
|
||||||
// This is the number of blocks for which logs will be cached in the filter system.
|
// This is the number of blocks for which logs will be cached in the filter system.
|
||||||
FilterLogCacheSize int
|
FilterLogCacheSize int
|
||||||
|
@ -39,8 +39,6 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
|||||||
DatabaseCache int
|
DatabaseCache int
|
||||||
DatabaseFreezer string
|
DatabaseFreezer string
|
||||||
TrieCleanCache int
|
TrieCleanCache int
|
||||||
TrieCleanCacheJournal string `toml:",omitempty"`
|
|
||||||
TrieCleanCacheRejournal time.Duration `toml:",omitempty"`
|
|
||||||
TrieDirtyCache int
|
TrieDirtyCache int
|
||||||
TrieTimeout time.Duration
|
TrieTimeout time.Duration
|
||||||
SnapshotCache int
|
SnapshotCache int
|
||||||
@ -81,8 +79,6 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
|||||||
enc.DatabaseCache = c.DatabaseCache
|
enc.DatabaseCache = c.DatabaseCache
|
||||||
enc.DatabaseFreezer = c.DatabaseFreezer
|
enc.DatabaseFreezer = c.DatabaseFreezer
|
||||||
enc.TrieCleanCache = c.TrieCleanCache
|
enc.TrieCleanCache = c.TrieCleanCache
|
||||||
enc.TrieCleanCacheJournal = c.TrieCleanCacheJournal
|
|
||||||
enc.TrieCleanCacheRejournal = c.TrieCleanCacheRejournal
|
|
||||||
enc.TrieDirtyCache = c.TrieDirtyCache
|
enc.TrieDirtyCache = c.TrieDirtyCache
|
||||||
enc.TrieTimeout = c.TrieTimeout
|
enc.TrieTimeout = c.TrieTimeout
|
||||||
enc.SnapshotCache = c.SnapshotCache
|
enc.SnapshotCache = c.SnapshotCache
|
||||||
@ -127,8 +123,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||||||
DatabaseCache *int
|
DatabaseCache *int
|
||||||
DatabaseFreezer *string
|
DatabaseFreezer *string
|
||||||
TrieCleanCache *int
|
TrieCleanCache *int
|
||||||
TrieCleanCacheJournal *string `toml:",omitempty"`
|
|
||||||
TrieCleanCacheRejournal *time.Duration `toml:",omitempty"`
|
|
||||||
TrieDirtyCache *int
|
TrieDirtyCache *int
|
||||||
TrieTimeout *time.Duration
|
TrieTimeout *time.Duration
|
||||||
SnapshotCache *int
|
SnapshotCache *int
|
||||||
@ -218,12 +212,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||||||
if dec.TrieCleanCache != nil {
|
if dec.TrieCleanCache != nil {
|
||||||
c.TrieCleanCache = *dec.TrieCleanCache
|
c.TrieCleanCache = *dec.TrieCleanCache
|
||||||
}
|
}
|
||||||
if dec.TrieCleanCacheJournal != nil {
|
|
||||||
c.TrieCleanCacheJournal = *dec.TrieCleanCacheJournal
|
|
||||||
}
|
|
||||||
if dec.TrieCleanCacheRejournal != nil {
|
|
||||||
c.TrieCleanCacheRejournal = *dec.TrieCleanCacheRejournal
|
|
||||||
}
|
|
||||||
if dec.TrieDirtyCache != nil {
|
if dec.TrieDirtyCache != nil {
|
||||||
c.TrieDirtyCache = *dec.TrieDirtyCache
|
c.TrieDirtyCache = *dec.TrieDirtyCache
|
||||||
}
|
}
|
||||||
|
@ -438,14 +438,12 @@ func createNode(t *testing.T) *node.Node {
|
|||||||
|
|
||||||
func newGQLService(t *testing.T, stack *node.Node, shanghai bool, gspec *core.Genesis, genBlocks int, genfunc func(i int, gen *core.BlockGen)) (*handler, []*types.Block) {
|
func newGQLService(t *testing.T, stack *node.Node, shanghai bool, gspec *core.Genesis, genBlocks int, genfunc func(i int, gen *core.BlockGen)) (*handler, []*types.Block) {
|
||||||
ethConf := ðconfig.Config{
|
ethConf := ðconfig.Config{
|
||||||
Genesis: gspec,
|
Genesis: gspec,
|
||||||
NetworkId: 1337,
|
NetworkId: 1337,
|
||||||
TrieCleanCache: 5,
|
TrieCleanCache: 5,
|
||||||
TrieCleanCacheJournal: "triecache",
|
TrieDirtyCache: 5,
|
||||||
TrieCleanCacheRejournal: 60 * time.Minute,
|
TrieTimeout: 60 * time.Minute,
|
||||||
TrieDirtyCache: 5,
|
SnapshotCache: 5,
|
||||||
TrieTimeout: 60 * time.Minute,
|
|
||||||
SnapshotCache: 5,
|
|
||||||
}
|
}
|
||||||
ethBackend, err := eth.New(stack, ethConf)
|
ethBackend, err := eth.New(stack, ethConf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -71,7 +71,6 @@ func getChain() *core.BlockChain {
|
|||||||
TrieDirtyLimit: 0,
|
TrieDirtyLimit: 0,
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
TrieCleanNoPrefetch: true,
|
TrieCleanNoPrefetch: true,
|
||||||
TrieCleanRejournal: 0,
|
|
||||||
SnapshotLimit: 100,
|
SnapshotLimit: 100,
|
||||||
SnapshotWait: true,
|
SnapshotWait: true,
|
||||||
}
|
}
|
||||||
|
@ -18,22 +18,18 @@ package trie
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"runtime"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/VictoriaMetrics/fastcache"
|
"github.com/VictoriaMetrics/fastcache"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
|
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
|
||||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config defines all necessary options for database.
|
// Config defines all necessary options for database.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Cache int // Memory allowance (MB) to use for caching trie nodes in memory
|
Cache int // Memory allowance (MB) to use for caching trie nodes in memory
|
||||||
Journal string // Journal of clean cache to survive node restarts
|
Preimages bool // Flag whether the preimage of trie key is recorded
|
||||||
Preimages bool // Flag whether the preimage of trie key is recorded
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// backend defines the methods needed to access/update trie nodes in different
|
// backend defines the methods needed to access/update trie nodes in different
|
||||||
@ -79,11 +75,7 @@ type Database struct {
|
|||||||
func prepare(diskdb ethdb.Database, config *Config) *Database {
|
func prepare(diskdb ethdb.Database, config *Config) *Database {
|
||||||
var cleans *fastcache.Cache
|
var cleans *fastcache.Cache
|
||||||
if config != nil && config.Cache > 0 {
|
if config != nil && config.Cache > 0 {
|
||||||
if config.Journal == "" {
|
cleans = fastcache.New(config.Cache * 1024 * 1024)
|
||||||
cleans = fastcache.New(config.Cache * 1024 * 1024)
|
|
||||||
} else {
|
|
||||||
cleans = fastcache.LoadFromFileOrNew(config.Journal, config.Cache*1024*1024)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var preimages *preimageStore
|
var preimages *preimageStore
|
||||||
if config != nil && config.Preimages {
|
if config != nil && config.Preimages {
|
||||||
@ -179,46 +171,6 @@ func (db *Database) WritePreimages() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// saveCache saves clean state cache to given directory path
|
|
||||||
// using specified CPU cores.
|
|
||||||
func (db *Database) saveCache(dir string, threads int) error {
|
|
||||||
if db.cleans == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
log.Info("Writing clean trie cache to disk", "path", dir, "threads", threads)
|
|
||||||
|
|
||||||
start := time.Now()
|
|
||||||
err := db.cleans.SaveToFileConcurrent(dir, threads)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Failed to persist clean trie cache", "error", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Info("Persisted the clean trie cache", "path", dir, "elapsed", common.PrettyDuration(time.Since(start)))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveCache atomically saves fast cache data to the given dir using all
|
|
||||||
// available CPU cores.
|
|
||||||
func (db *Database) SaveCache(dir string) error {
|
|
||||||
return db.saveCache(dir, runtime.GOMAXPROCS(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveCachePeriodically atomically saves fast cache data to the given dir with
|
|
||||||
// the specified interval. All dump operation will only use a single CPU core.
|
|
||||||
func (db *Database) SaveCachePeriodically(dir string, interval time.Duration, stopCh <-chan struct{}) {
|
|
||||||
ticker := time.NewTicker(interval)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ticker.C:
|
|
||||||
db.saveCache(dir, 1)
|
|
||||||
case <-stopCh:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cap iteratively flushes old but still referenced trie nodes until the total
|
// Cap iteratively flushes old but still referenced trie nodes until the total
|
||||||
// memory usage goes below the given threshold. The held pre-images accumulated
|
// memory usage goes below the given threshold. The held pre-images accumulated
|
||||||
// up to this point will be flushed in case the size exceeds the threshold.
|
// up to this point will be flushed in case the size exceeds the threshold.
|
Loading…
Reference in New Issue
Block a user