From 76dde985364729222a53df33ffe14a0f60d46b7a Mon Sep 17 00:00:00 2001 From: Marko Date: Sat, 20 Nov 2021 10:32:30 +0100 Subject: [PATCH] feat: add configurable iavl cache size (#10561) ## Description Closes: #1714 Bump default cache size to 50mb from 10kb. Allow node operators to set cache size. --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable) --- CHANGELOG.md | 1 + baseapp/options.go | 13 +++++++++---- server/config/config.go | 3 +++ server/config/toml.go | 4 ++++ server/mock/store.go | 3 +++ store/iavl/store.go | 10 +++++----- store/iavl/store_test.go | 6 +++--- store/rootmulti/proof_test.go | 2 +- store/rootmulti/store.go | 26 ++++++++++++++++---------- store/types/iterator_test.go | 2 +- store/types/store.go | 3 +++ 11 files changed, 49 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e3e0868081a..e2f8d66961e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#10348](https://github.com/cosmos/cosmos-sdk/pull/10348) Add `fee.{payer,granter}` and `tip` fields to StdSignDoc for signing tipped transactions. * [\#10208](https://github.com/cosmos/cosmos-sdk/pull/10208) Add `TipsTxMiddleware` for transferring tips. * [\#10379](https://github.com/cosmos/cosmos-sdk/pull/10379) Add validation to `x/upgrade` CLI `software-upgrade` command `--plan-info` value. +* [\#10561](https://github.com/cosmos/cosmos-sdk/pull/10561) Add configurable IAVL cache size to app.toml ### Improvements diff --git a/baseapp/options.go b/baseapp/options.go index 1d74d1229c3f..1d92698d7fa9 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -18,7 +18,7 @@ import ( // SetPruning sets a pruning option on the multistore associated with the app func SetPruning(opts sdk.PruningOptions) func(*BaseApp) { - return func(bap *BaseApp) { bap.cms.SetPruning(opts) } + return func(bapp *BaseApp) { bapp.cms.SetPruning(opts) } } // SetMinGasPrices returns an option that sets the minimum gas prices on the app. @@ -28,17 +28,17 @@ func SetMinGasPrices(gasPricesStr string) func(*BaseApp) { panic(fmt.Sprintf("invalid minimum gas prices: %v", err)) } - return func(bap *BaseApp) { bap.setMinGasPrices(gasPrices) } + return func(bapp *BaseApp) { bapp.setMinGasPrices(gasPrices) } } // SetHaltHeight returns a BaseApp option function that sets the halt block height. func SetHaltHeight(blockHeight uint64) func(*BaseApp) { - return func(bap *BaseApp) { bap.setHaltHeight(blockHeight) } + return func(bapp *BaseApp) { bapp.setHaltHeight(blockHeight) } } // SetHaltTime returns a BaseApp option function that sets the halt block time. func SetHaltTime(haltTime uint64) func(*BaseApp) { - return func(bap *BaseApp) { bap.setHaltTime(haltTime) } + return func(bapp *BaseApp) { bapp.setHaltTime(haltTime) } } // SetMinRetainBlocks returns a BaseApp option function that sets the minimum @@ -58,6 +58,11 @@ func SetIndexEvents(ie []string) func(*BaseApp) { return func(app *BaseApp) { app.setIndexEvents(ie) } } +// SetIAVLCacheSize provides a BaseApp option function that sets the size of IAVL cache. +func SetIAVLCacheSize(size int) func(*BaseApp) { + return func(bapp *BaseApp) { bapp.cms.SetIAVLCacheSize(size) } +} + // SetInterBlockCache provides a BaseApp option function that sets the // inter-block cache. func SetInterBlockCache(cache sdk.MultiStorePersistentCache) func(*BaseApp) { diff --git a/server/config/config.go b/server/config/config.go index b3d8a99cf6fe..f5a395dce8e0 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -69,6 +69,8 @@ type BaseConfig struct { // IndexEvents defines the set of events in the form {eventType}.{attributeKey}, // which informs Tendermint what to index. If empty, all events will be indexed. IndexEvents []string `mapstructure:"index-events"` + // IavlCacheSize set the size of the iavl tree cache. + IAVLCacheSize uint64 `mapstructure:"iavl-cache-size"` } // APIConfig defines the API listener configuration. @@ -209,6 +211,7 @@ func DefaultConfig() *Config { PruningInterval: "0", MinRetainBlocks: 0, IndexEvents: make([]string, 0), + IAVLCacheSize: 781250, // 50 MB }, Telemetry: telemetry.Config{ Enabled: false, diff --git a/server/config/toml.go b/server/config/toml.go index 785eac72effd..1fe85947049c 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -72,6 +72,10 @@ inter-block-cache = {{ .BaseConfig.InterBlockCache }} # ["message.sender", "message.recipient"] index-events = [{{ range .BaseConfig.IndexEvents }}{{ printf "%q, " . }}{{end}}] +# IavlCacheSize set the size of the iavl tree cache. +# Default cache size is 50mb. +iavl-cache-size = {{ .BaseConfig.IAVLCacheSize }} + ############################################################################### ### Telemetry Configuration ### ############################################################################### diff --git a/server/mock/store.go b/server/mock/store.go index 91596337f964..cf67e088fe77 100644 --- a/server/mock/store.go +++ b/server/mock/store.go @@ -114,6 +114,9 @@ func (ms multiStore) GetStoreType() storetypes.StoreType { func (ms multiStore) SetInterBlockCache(_ sdk.MultiStorePersistentCache) { panic("not implemented") } +func (ms multiStore) SetIAVLCacheSize(size int) { + panic("not implemented") +} func (ms multiStore) SetInitialVersion(version int64) error { panic("not implemented") diff --git a/store/iavl/store.go b/store/iavl/store.go index 79960d8b9866..50702da585c8 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -22,7 +22,7 @@ import ( ) const ( - defaultIAVLCacheSize = 10000 + DefaultIAVLCacheSize = 500000 ) var ( @@ -41,16 +41,16 @@ type Store struct { // LoadStore returns an IAVL Store as a CommitKVStore. Internally, it will load the // store's version (id) from the provided DB. An error is returned if the version // fails to load, or if called with a positive version on an empty tree. -func LoadStore(db dbm.DB, id types.CommitID, lazyLoading bool) (types.CommitKVStore, error) { - return LoadStoreWithInitialVersion(db, id, lazyLoading, 0) +func LoadStore(db dbm.DB, id types.CommitID, lazyLoading bool, cacheSize int) (types.CommitKVStore, error) { + return LoadStoreWithInitialVersion(db, id, lazyLoading, 0, cacheSize) } // LoadStoreWithInitialVersion returns an IAVL Store as a CommitKVStore setting its initialVersion // to the one given. Internally, it will load the store's version (id) from the // provided DB. An error is returned if the version fails to load, or if called with a positive // version on an empty tree. -func LoadStoreWithInitialVersion(db dbm.DB, id types.CommitID, lazyLoading bool, initialVersion uint64) (types.CommitKVStore, error) { - tree, err := iavl.NewMutableTreeWithOpts(db, defaultIAVLCacheSize, &iavl.Options{InitialVersion: initialVersion}) +func LoadStoreWithInitialVersion(db dbm.DB, id types.CommitID, lazyLoading bool, initialVersion uint64, cacheSize int) (types.CommitKVStore, error) { + tree, err := iavl.NewMutableTreeWithOpts(db, cacheSize, &iavl.Options{InitialVersion: initialVersion}) if err != nil { return nil, err } diff --git a/store/iavl/store_test.go b/store/iavl/store_test.go index 26cf27db8bf0..b9c9e25ad43d 100644 --- a/store/iavl/store_test.go +++ b/store/iavl/store_test.go @@ -93,17 +93,17 @@ func TestLoadStore(t *testing.T) { require.Equal(t, string(hcStore.Get([]byte("hello"))), "ciao") // Querying a new store at some previous non-pruned height H - newHStore, err := LoadStore(db, cIDH, false) + newHStore, err := LoadStore(db, cIDH, false, DefaultIAVLCacheSize) require.NoError(t, err) require.Equal(t, string(newHStore.Get([]byte("hello"))), "hallo") // Querying a new store at some previous pruned height Hp - newHpStore, err := LoadStore(db, cIDHp, false) + newHpStore, err := LoadStore(db, cIDHp, false, DefaultIAVLCacheSize) require.NoError(t, err) require.Equal(t, string(newHpStore.Get([]byte("hello"))), "hola") // Querying a new store at current height H - newHcStore, err := LoadStore(db, cIDHc, false) + newHcStore, err := LoadStore(db, cIDHc, false, DefaultIAVLCacheSize) require.NoError(t, err) require.Equal(t, string(newHcStore.Get([]byte("hello"))), "ciao") } diff --git a/store/rootmulti/proof_test.go b/store/rootmulti/proof_test.go index f0bd29063ad1..10f8397e7284 100644 --- a/store/rootmulti/proof_test.go +++ b/store/rootmulti/proof_test.go @@ -14,7 +14,7 @@ import ( func TestVerifyIAVLStoreQueryProof(t *testing.T) { // Create main tree for testing. db := dbm.NewMemDB() - iStore, err := iavl.LoadStore(db, types.CommitID{}, false) + iStore, err := iavl.LoadStore(db, types.CommitID{}, false, iavl.DefaultIAVLCacheSize) store := iStore.(*iavl.Store) require.Nil(t, err) store.Set([]byte("MYKEY"), []byte("MYVALUE")) diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index a8b4b770c032..fd4bc84ac2aa 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -48,6 +48,7 @@ type Store struct { db dbm.DB lastCommitInfo *types.CommitInfo pruningOpts types.PruningOptions + iavlCacheSize int storesParams map[types.StoreKey]storeParams stores map[types.StoreKey]types.CommitKVStore keysByName map[string]types.StoreKey @@ -75,14 +76,15 @@ var ( // LoadVersion must be called. func NewStore(db dbm.DB) *Store { return &Store{ - db: db, - pruningOpts: types.PruneNothing, - storesParams: make(map[types.StoreKey]storeParams), - stores: make(map[types.StoreKey]types.CommitKVStore), - keysByName: make(map[string]types.StoreKey), - pruneHeights: make([]int64, 0), - listeners: make(map[types.StoreKey][]types.WriteListener), - removalMap: make(map[types.StoreKey]bool), + db: db, + pruningOpts: types.PruneNothing, + iavlCacheSize: iavl.DefaultIAVLCacheSize, + storesParams: make(map[types.StoreKey]storeParams), + stores: make(map[types.StoreKey]types.CommitKVStore), + keysByName: make(map[string]types.StoreKey), + pruneHeights: make([]int64, 0), + listeners: make(map[types.StoreKey][]types.WriteListener), + removalMap: make(map[types.StoreKey]bool), } } @@ -98,6 +100,10 @@ func (rs *Store) SetPruning(pruningOpts types.PruningOptions) { rs.pruningOpts = pruningOpts } +func (rs *Store) SetIAVLCacheSize(cacheSize int) { + rs.iavlCacheSize = cacheSize +} + // SetLazyLoading sets if the iavl store should be loaded lazily or not func (rs *Store) SetLazyLoading(lazyLoading bool) { rs.lazyLoading = lazyLoading @@ -895,9 +901,9 @@ func (rs *Store) loadCommitStoreFromParams(key types.StoreKey, id types.CommitID var err error if params.initialVersion == 0 { - store, err = iavl.LoadStore(db, id, rs.lazyLoading) + store, err = iavl.LoadStore(db, id, rs.lazyLoading, rs.iavlCacheSize) } else { - store, err = iavl.LoadStoreWithInitialVersion(db, id, rs.lazyLoading, params.initialVersion) + store, err = iavl.LoadStoreWithInitialVersion(db, id, rs.lazyLoading, params.initialVersion, rs.iavlCacheSize) } if err != nil { diff --git a/store/types/iterator_test.go b/store/types/iterator_test.go index 3086917b605b..686aa1123708 100644 --- a/store/types/iterator_test.go +++ b/store/types/iterator_test.go @@ -12,7 +12,7 @@ import ( func newMemTestKVStore(t *testing.T) types.KVStore { db := dbm.NewMemDB() - store, err := iavl.LoadStore(db, types.CommitID{}, false) + store, err := iavl.LoadStore(db, types.CommitID{}, false, iavl.DefaultIAVLCacheSize) require.NoError(t, err) return store } diff --git a/store/types/store.go b/store/types/store.go index aa04a2447579..7af13914bc89 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -181,6 +181,9 @@ type CommitMultiStore interface { // SetInitialVersion sets the initial version of the IAVL tree. It is used when // starting a new chain at an arbitrary height. SetInitialVersion(version int64) error + + // SetIAVLCacheSize sets the cache size of the IAVL tree. + SetIAVLCacheSize(size int) } //---------subsp-------------------------------