diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 3ddf23665..e0e7376b1 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -7,10 +7,12 @@ import ( "reflect" "strings" "sync" + "time" "github.com/gogo/protobuf/proto" sdbm "github.com/sei-protocol/sei-tm-db/backends" "github.com/spf13/cast" + leveldbutils "github.com/syndtr/goleveldb/leveldb/util" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -145,6 +147,8 @@ type BaseApp struct { //nolint: maligned ChainID string votesInfoLock sync.RWMutex + + compactionInterval uint64 } type appStore struct { @@ -246,6 +250,7 @@ func NewBaseApp( if app.ChainID == "" { panic("must pass --chain-id when calling 'seid start' or set in ~/.sei/config/client.toml") } + app.startCompactionRoutine(db) return app } @@ -433,6 +438,10 @@ func (app *BaseApp) setInterBlockCache(cache sdk.MultiStorePersistentCache) { app.interBlockCache = cache } +func (app *BaseApp) setCompactionInterval(compactionInterval uint64) { + app.compactionInterval = compactionInterval +} + func (app *BaseApp) setTrace(trace bool) { app.trace = trace } @@ -1065,3 +1074,21 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (*s func (app *BaseApp) GetAnteDepGenerator() sdk.AnteDepGenerator { return app.anteDepGenerator } + +func (app *BaseApp) startCompactionRoutine(db dbm.DB) { + if app.compactionInterval == 0 { + return + } + go func() { + if goleveldb, ok := db.(*dbm.GoLevelDB); ok { + for { + time.Sleep(time.Duration(app.compactionInterval) * time.Second) + if err := goleveldb.DB().CompactRange(leveldbutils.Range{Start: nil, Limit: nil}); err != nil { + app.Logger().Error(fmt.Sprintf("error compacting DB: %s", err)) + } + } + } else { + app.Logger().Info("exit compaction routine because underlying DB does not support compaction") + } + }() +} diff --git a/baseapp/options.go b/baseapp/options.go index 2cec751e8..2233b413f 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -47,6 +47,10 @@ func SetMinRetainBlocks(minRetainBlocks uint64) func(*BaseApp) { return func(bapp *BaseApp) { bapp.setMinRetainBlocks(minRetainBlocks) } } +func SetCompactionInterval(compactionInterval uint64) func(*BaseApp) { + return func(bapp *BaseApp) { bapp.setCompactionInterval(compactionInterval) } +} + // SetTrace will turn on or off trace flag func SetTrace(trace bool) func(*BaseApp) { return func(app *BaseApp) { app.setTrace(trace) } diff --git a/server/config/config.go b/server/config/config.go index e7dc56ae8..35e1217bd 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -75,6 +75,10 @@ type BaseConfig struct { // IAVLDisableFastNode enables or disables the fast sync node. IAVLDisableFastNode bool `mapstructure:"iavl-disable-fastnode"` + + // CompactionInterval sets (in seconds) the interval between forced levelDB + // compaction. A value of 0 means no forced levelDB + CompactionInterval uint64 `mapstructure:"compaction-interval"` } // APIConfig defines the API listener configuration. @@ -217,6 +221,7 @@ func DefaultConfig() *Config { IndexEvents: make([]string, 0), IAVLCacheSize: 781250, // 50 MB IAVLDisableFastNode: true, + CompactionInterval: 0, }, Telemetry: telemetry.Config{ Enabled: false, @@ -284,6 +289,7 @@ func GetConfig(v *viper.Viper) (Config, error) { MinRetainBlocks: v.GetUint64("min-retain-blocks"), IAVLCacheSize: v.GetUint64("iavl-cache-size"), IAVLDisableFastNode: v.GetBool("iavl-disable-fastnode"), + CompactionInterval: v.GetUint64("compaction-interval"), }, Telemetry: telemetry.Config{ ServiceName: v.GetString("telemetry.service-name"), diff --git a/server/config/toml.go b/server/config/toml.go index 4655ea6e9..695fcbeec 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -80,6 +80,11 @@ iavl-cache-size = {{ .BaseConfig.IAVLCacheSize }} # Default is true. iavl-disable-fastnode = {{ .BaseConfig.IAVLDisableFastNode }} +# CompactionInterval sets (in seconds) the interval between forced levelDB +# compaction. A value of 0 means no forced levelDB. +# Default is 0. +compaction-interval = {{ .BaseConfig.CompactionInterval }} + ############################################################################### ### Telemetry Configuration ### ############################################################################### diff --git a/server/start.go b/server/start.go index 855cc48bd..ac277f25b 100644 --- a/server/start.go +++ b/server/start.go @@ -50,17 +50,18 @@ const ( FlagInterBlockCache = "inter-block-cache" FlagUnsafeSkipUpgrades = "unsafe-skip-upgrades" FlagTrace = "trace" - FlagProfile = "profile" + FlagProfile = "profile" FlagInvCheckPeriod = "inv-check-period" - FlagPruning = "pruning" - FlagPruningKeepRecent = "pruning-keep-recent" - FlagPruningKeepEvery = "pruning-keep-every" - FlagPruningInterval = "pruning-interval" - FlagIndexEvents = "index-events" - FlagMinRetainBlocks = "min-retain-blocks" - FlagIAVLCacheSize = "iavl-cache-size" - FlagIAVLFastNode = "iavl-disable-fastnode" + FlagPruning = "pruning" + FlagPruningKeepRecent = "pruning-keep-recent" + FlagPruningKeepEvery = "pruning-keep-every" + FlagPruningInterval = "pruning-interval" + FlagIndexEvents = "index-events" + FlagMinRetainBlocks = "min-retain-blocks" + FlagIAVLCacheSize = "iavl-cache-size" + FlagIAVLFastNode = "iavl-disable-fastnode" + FlagCompactionInterval = "compaction-interval" // state sync-related flags FlagStateSyncSnapshotInterval = "state-sync.snapshot-interval" @@ -199,6 +200,7 @@ is performed. Note, when enabled, gRPC will also be automatically enabled. cmd.Flags().Uint64(FlagPruningInterval, 0, "Height interval at which pruned heights are removed from disk (ignored if pruning is not 'custom')") cmd.Flags().Uint(FlagInvCheckPeriod, 0, "Assert registered invariants every N blocks") cmd.Flags().Uint64(FlagMinRetainBlocks, 0, "Minimum block height offset during ABCI commit to prune Tendermint blocks") + cmd.Flags().Uint64(FlagCompactionInterval, 0, "Time interval in between forced levelDB compaction. 0 means no forced compaction.") cmd.Flags().Bool(flagGRPCOnly, false, "Start the node in gRPC query only mode (no Tendermint process is started)") cmd.Flags().Bool(flagGRPCEnable, true, "Define if the gRPC server should be enabled") diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index def47af1f..c68374ef6 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -297,6 +297,7 @@ func (a appCreator) newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, a baseapp.SetSnapshotKeepRecent(cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent))), baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(server.FlagIAVLCacheSize))), baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(server.FlagIAVLFastNode))), + baseapp.SetCompactionInterval(cast.ToUint64(appOpts.Get(server.FlagCompactionInterval))), ) }