From c68eb3831a497e5bab91a0cb3998c979e50c6996 Mon Sep 17 00:00:00 2001 From: galaio Date: Mon, 25 Aug 2025 15:42:12 +0800 Subject: [PATCH 1/5] freezer: support custom freezer batch limit; --- cmd/geth/main.go | 1 + cmd/utils/flags.go | 9 +++++++++ core/rawdb/chain_freezer.go | 8 +++++++- eth/backend.go | 1 + eth/ethconfig/config.go | 17 ++++++++++------- eth/ethconfig/gen_config.go | 6 ++++++ ethdb/database.go | 1 + 7 files changed, 35 insertions(+), 8 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 239ef3a1d3..6e02626afc 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -130,6 +130,7 @@ var ( utils.CachePreimagesFlag, utils.MultiDataBaseFlag, utils.PruneAncientDataFlag, // deprecated + utils.FreezerBatchLimitFlag, utils.CacheLogSizeFlag, utils.FDLimitFlag, utils.CryptoKZGFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 07da73acd4..a61a92fe82 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -391,6 +391,12 @@ var ( Value: ethconfig.Defaults.BlockHistory, Category: flags.BlockHistoryCategory, } + FreezerBatchLimitFlag = &cli.Uint64Flag{ + Name: "freezer.batchlimit", + Usage: "The maximum number of blocks to freeze in one batch", + Value: 100, + Category: flags.BlockHistoryCategory, + } ChainHistoryFlag = &cli.StringFlag{ Name: "history.chain", Usage: `Blockchain history retention ("all" or "postmerge")`, @@ -2020,6 +2026,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { log.Warn(fmt.Sprintf("Option --%s is deprecated. Please using --%s in the future", PruneAncientDataFlag.Name, BlockHistoryFlag.Name)) cfg.PruneAncientData = ctx.Bool(PruneAncientDataFlag.Name) } + if ctx.IsSet(FreezerBatchLimitFlag.Name) { + cfg.FreezerBatchLimit = ctx.Uint64(FreezerBatchLimitFlag.Name) + } if ctx.IsSet(EraFlag.Name) { cfg.DatabaseEra = ctx.String(EraFlag.Name) } diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index c629e5a764..218756a205 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -38,12 +38,14 @@ const ( // chain progression that might permit new blocks to be frozen into immutable // storage. freezerRecheckInterval = time.Minute +) +var ( // freezerBatchLimit is the maximum number of blocks to freeze in one batch // before doing an fsync and deleting it from the key-value store. // TODO(galaio): For BSC, the 0.75 interval and freezing of 30,000 blocks will seriously affect performance. // It is temporarily adjusted to 100, and improves the freezing performance later. - freezerBatchLimit = 100 + freezerBatchLimit uint64 = 100 ) var ( @@ -596,6 +598,10 @@ func (f *chainFreezer) freezeRange(nfdb *nofreezedb, number, limit uint64) (hash } func (f *chainFreezer) SetupFreezerEnv(env *ethdb.FreezerEnv, blockHistory uint64) error { + if env.BatchLimit > freezerBatchLimit { + log.Info("Freezer batch limit is set to", "new", env.BatchLimit, "old", freezerBatchLimit) + freezerBatchLimit = env.BatchLimit + } f.freezeEnv.Store(env) f.blockHistory.Store(blockHistory) return nil diff --git a/eth/backend.go b/eth/backend.go index f91b713015..2212b47342 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -257,6 +257,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if err = freezeDb.SetupFreezerEnv(ðdb.FreezerEnv{ ChainCfg: chainConfig, BlobExtraReserve: config.BlobExtraReserve, + BatchLimit: config.FreezerBatchLimit, }, config.BlockHistory); err != nil { return nil, err } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 968241c792..c2c59f5b62 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -155,13 +155,16 @@ type Config struct { // the oldest unpruned block number. // !!Deprecated: use 'BlockHistory' instead. PruneAncientData bool - TrieCleanCache int - TrieDirtyCache int - TrieTimeout time.Duration - SnapshotCache int - TriesInMemory uint64 - TriesVerifyMode core.VerifyMode - Preimages bool + // FreezerBatchLimit is the maximum number of blocks to freeze in one batch + FreezerBatchLimit uint64 + + TrieCleanCache int + TrieDirtyCache int + TrieTimeout time.Duration + SnapshotCache int + TriesInMemory uint64 + TriesVerifyMode core.VerifyMode + Preimages bool // This is the number of blocks for which logs will be cached in the filter system. FilterLogCacheSize int diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 038fec8aec..821e357aac 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -51,6 +51,7 @@ func (c Config) MarshalTOML() (interface{}, error) { DatabaseFreezer string DatabaseEra string PruneAncientData bool + FreezerBatchLimit uint64 TrieCleanCache int TrieDirtyCache int TrieTimeout time.Duration @@ -111,6 +112,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.DatabaseFreezer = c.DatabaseFreezer enc.DatabaseEra = c.DatabaseEra enc.PruneAncientData = c.PruneAncientData + enc.FreezerBatchLimit = c.FreezerBatchLimit enc.TrieCleanCache = c.TrieCleanCache enc.TrieDirtyCache = c.TrieDirtyCache enc.TrieTimeout = c.TrieTimeout @@ -175,6 +177,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { DatabaseFreezer *string DatabaseEra *string PruneAncientData *bool + FreezerBatchLimit *uint64 TrieCleanCache *int TrieDirtyCache *int TrieTimeout *time.Duration @@ -304,6 +307,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.PruneAncientData != nil { c.PruneAncientData = *dec.PruneAncientData } + if dec.FreezerBatchLimit != nil { + c.FreezerBatchLimit = *dec.FreezerBatchLimit + } if dec.TrieCleanCache != nil { c.TrieCleanCache = *dec.TrieCleanCache } diff --git a/ethdb/database.go b/ethdb/database.go index ec70677c5b..df29044644 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -183,6 +183,7 @@ type AncientWriter interface { type FreezerEnv struct { ChainCfg *params.ChainConfig BlobExtraReserve uint64 + BatchLimit uint64 } // AncientFreezer defines the help functions for freezing ancient data From b9c4615af0fb11c709cabfd4a372963975c82175 Mon Sep 17 00:00:00 2001 From: galaio Date: Tue, 26 Aug 2025 11:32:23 +0800 Subject: [PATCH 2/5] freezer: support custom freezer batch limit; --- cmd/geth/main.go | 1 - cmd/utils/flags.go | 10 ++-------- core/rawdb/chain_freezer.go | 1 + 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 6e02626afc..239ef3a1d3 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -130,7 +130,6 @@ var ( utils.CachePreimagesFlag, utils.MultiDataBaseFlag, utils.PruneAncientDataFlag, // deprecated - utils.FreezerBatchLimitFlag, utils.CacheLogSizeFlag, utils.FDLimitFlag, utils.CryptoKZGFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index a61a92fe82..7a4f5c3f83 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -391,12 +391,6 @@ var ( Value: ethconfig.Defaults.BlockHistory, Category: flags.BlockHistoryCategory, } - FreezerBatchLimitFlag = &cli.Uint64Flag{ - Name: "freezer.batchlimit", - Usage: "The maximum number of blocks to freeze in one batch", - Value: 100, - Category: flags.BlockHistoryCategory, - } ChainHistoryFlag = &cli.StringFlag{ Name: "history.chain", Usage: `Blockchain history retention ("all" or "postmerge")`, @@ -2026,8 +2020,8 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { log.Warn(fmt.Sprintf("Option --%s is deprecated. Please using --%s in the future", PruneAncientDataFlag.Name, BlockHistoryFlag.Name)) cfg.PruneAncientData = ctx.Bool(PruneAncientDataFlag.Name) } - if ctx.IsSet(FreezerBatchLimitFlag.Name) { - cfg.FreezerBatchLimit = ctx.Uint64(FreezerBatchLimitFlag.Name) + if !ctx.Bool(MiningEnabledFlag.Name) { + cfg.FreezerBatchLimit = rawdb.MaxFreezerBatchLimit } if ctx.IsSet(EraFlag.Name) { cfg.DatabaseEra = ctx.String(EraFlag.Name) diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index 218756a205..9d424ace38 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -38,6 +38,7 @@ const ( // chain progression that might permit new blocks to be frozen into immutable // storage. freezerRecheckInterval = time.Minute + MaxFreezerBatchLimit = 30000 ) var ( From d226c1b32f1c9c7dd4a3e25324d4261fe7024a5d Mon Sep 17 00:00:00 2001 From: galaio Date: Tue, 26 Aug 2025 16:15:55 +0800 Subject: [PATCH 3/5] freezer: support custom freezer batch limit; --- cmd/utils/flags.go | 3 --- core/rawdb/chain_freezer.go | 24 ++++++++++++++++-------- eth/backend.go | 1 - eth/ethconfig/config.go | 2 -- eth/ethconfig/gen_config.go | 6 ------ ethdb/database.go | 1 - 6 files changed, 16 insertions(+), 21 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 7a4f5c3f83..07da73acd4 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2020,9 +2020,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { log.Warn(fmt.Sprintf("Option --%s is deprecated. Please using --%s in the future", PruneAncientDataFlag.Name, BlockHistoryFlag.Name)) cfg.PruneAncientData = ctx.Bool(PruneAncientDataFlag.Name) } - if !ctx.Bool(MiningEnabledFlag.Name) { - cfg.FreezerBatchLimit = rawdb.MaxFreezerBatchLimit - } if ctx.IsSet(EraFlag.Name) { cfg.DatabaseEra = ctx.String(EraFlag.Name) } diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index 9d424ace38..70a5774012 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -38,15 +38,17 @@ const ( // chain progression that might permit new blocks to be frozen into immutable // storage. freezerRecheckInterval = time.Minute - MaxFreezerBatchLimit = 30000 + + // TODO(galaio): For BSC, the 0.75 interval and freezing of 30,000 blocks will seriously affect performance. + // It is temporarily adjusted to 100, and improves the freezing performance later. + SlowFreezerBatchLimit = 100 + SlowdownFreezeWindow = 24 * time.Hour ) var ( // freezerBatchLimit is the maximum number of blocks to freeze in one batch // before doing an fsync and deleting it from the key-value store. - // TODO(galaio): For BSC, the 0.75 interval and freezing of 30,000 blocks will seriously affect performance. - // It is temporarily adjusted to 100, and improves the freezing performance later. - freezerBatchLimit uint64 = 100 + freezerBatchLimit uint64 = 30000 ) var ( @@ -271,6 +273,7 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore, continueFreeze bool) { backoff = true continue } + trySlowdownFreeze(head) first = frozen last = threshold @@ -310,6 +313,7 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore, continueFreeze bool) { backoff = true continue } + trySlowdownFreeze(head) first, _ = f.Ancients() last = *number - threshold if last-first > freezerBatchLimit { @@ -599,10 +603,6 @@ func (f *chainFreezer) freezeRange(nfdb *nofreezedb, number, limit uint64) (hash } func (f *chainFreezer) SetupFreezerEnv(env *ethdb.FreezerEnv, blockHistory uint64) error { - if env.BatchLimit > freezerBatchLimit { - log.Info("Freezer batch limit is set to", "new", env.BatchLimit, "old", freezerBatchLimit) - freezerBatchLimit = env.BatchLimit - } f.freezeEnv.Store(env) f.blockHistory.Store(blockHistory) return nil @@ -742,3 +742,11 @@ func (f *chainFreezer) ResetTable(kind string, startAt uint64, onlyEmpty bool) e func (f *chainFreezer) SyncAncient() error { return f.ancients.SyncAncient() } + +func trySlowdownFreeze(head *types.Header) { + if time.Since(time.Unix(int64(head.Time), 0)) > SlowdownFreezeWindow { + return + } + log.Info("Freezer need to slow down", "number", head.Number, "time", head.Time, "new", freezerBatchLimit) + freezerBatchLimit = SlowFreezerBatchLimit +} diff --git a/eth/backend.go b/eth/backend.go index 2212b47342..f91b713015 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -257,7 +257,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if err = freezeDb.SetupFreezerEnv(ðdb.FreezerEnv{ ChainCfg: chainConfig, BlobExtraReserve: config.BlobExtraReserve, - BatchLimit: config.FreezerBatchLimit, }, config.BlockHistory); err != nil { return nil, err } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index c2c59f5b62..a3402e32c1 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -155,8 +155,6 @@ type Config struct { // the oldest unpruned block number. // !!Deprecated: use 'BlockHistory' instead. PruneAncientData bool - // FreezerBatchLimit is the maximum number of blocks to freeze in one batch - FreezerBatchLimit uint64 TrieCleanCache int TrieDirtyCache int diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 821e357aac..038fec8aec 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -51,7 +51,6 @@ func (c Config) MarshalTOML() (interface{}, error) { DatabaseFreezer string DatabaseEra string PruneAncientData bool - FreezerBatchLimit uint64 TrieCleanCache int TrieDirtyCache int TrieTimeout time.Duration @@ -112,7 +111,6 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.DatabaseFreezer = c.DatabaseFreezer enc.DatabaseEra = c.DatabaseEra enc.PruneAncientData = c.PruneAncientData - enc.FreezerBatchLimit = c.FreezerBatchLimit enc.TrieCleanCache = c.TrieCleanCache enc.TrieDirtyCache = c.TrieDirtyCache enc.TrieTimeout = c.TrieTimeout @@ -177,7 +175,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { DatabaseFreezer *string DatabaseEra *string PruneAncientData *bool - FreezerBatchLimit *uint64 TrieCleanCache *int TrieDirtyCache *int TrieTimeout *time.Duration @@ -307,9 +304,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.PruneAncientData != nil { c.PruneAncientData = *dec.PruneAncientData } - if dec.FreezerBatchLimit != nil { - c.FreezerBatchLimit = *dec.FreezerBatchLimit - } if dec.TrieCleanCache != nil { c.TrieCleanCache = *dec.TrieCleanCache } diff --git a/ethdb/database.go b/ethdb/database.go index df29044644..ec70677c5b 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -183,7 +183,6 @@ type AncientWriter interface { type FreezerEnv struct { ChainCfg *params.ChainConfig BlobExtraReserve uint64 - BatchLimit uint64 } // AncientFreezer defines the help functions for freezing ancient data From a52d8c83b3cf6a7ef75374cc0f00618c5b8bc6af Mon Sep 17 00:00:00 2001 From: galaio Date: Tue, 26 Aug 2025 16:17:33 +0800 Subject: [PATCH 4/5] freezer: support custom freezer batch limit; --- core/rawdb/chain_freezer.go | 5 ++++- eth/ethconfig/config.go | 15 +++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index 70a5774012..047f824d46 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -747,6 +747,9 @@ func trySlowdownFreeze(head *types.Header) { if time.Since(time.Unix(int64(head.Time), 0)) > SlowdownFreezeWindow { return } - log.Info("Freezer need to slow down", "number", head.Number, "time", head.Time, "new", freezerBatchLimit) + if freezerBatchLimit == SlowFreezerBatchLimit { + return + } + log.Info("Freezer need to slow down", "number", head.Number, "time", head.Time, "new", SlowFreezerBatchLimit) freezerBatchLimit = SlowFreezerBatchLimit } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index a3402e32c1..968241c792 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -155,14 +155,13 @@ type Config struct { // the oldest unpruned block number. // !!Deprecated: use 'BlockHistory' instead. PruneAncientData bool - - TrieCleanCache int - TrieDirtyCache int - TrieTimeout time.Duration - SnapshotCache int - TriesInMemory uint64 - TriesVerifyMode core.VerifyMode - Preimages bool + TrieCleanCache int + TrieDirtyCache int + TrieTimeout time.Duration + SnapshotCache int + TriesInMemory uint64 + TriesVerifyMode core.VerifyMode + Preimages bool // This is the number of blocks for which logs will be cached in the filter system. FilterLogCacheSize int From e0c1919e0a2ee8e589c54475693217b31df40bab Mon Sep 17 00:00:00 2001 From: galaio Date: Tue, 26 Aug 2025 18:16:33 +0800 Subject: [PATCH 5/5] freezer: support custom freezer batch limit; --- core/rawdb/chain_freezer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index 047f824d46..31b8774c66 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -744,7 +744,7 @@ func (f *chainFreezer) SyncAncient() error { } func trySlowdownFreeze(head *types.Header) { - if time.Since(time.Unix(int64(head.Time), 0)) > SlowdownFreezeWindow { + if time.Since(time.UnixMilli(int64(head.MilliTimestamp()))) > SlowdownFreezeWindow { return } if freezerBatchLimit == SlowFreezerBatchLimit {