Skip to content

Commit

Permalink
Merge pull request #48 from initia-labs/feat/cache-with-size
Browse files Browse the repository at this point in the history
use size-based cache
  • Loading branch information
Vritra4 authored Jul 9, 2024
2 parents 549c754 + 4d5f824 commit 8808e02
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 30 deletions.
41 changes: 41 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!--
Guiding Principles:
Changelogs are for humans, not machines.
There should be an entry for every single version.
The same types of changes should be grouped.
Versions and sections should be linkable.
The latest version comes first.
The release date of each version is displayed.
Mention whether you follow Semantic Versioning.
Usage:
Change log entries are to be added to the Unreleased section under the
appropriate stanza (see below). Each entry is required to include a tag and
the Github issue reference in the following format:
* (<tag>) \#<issue-number> message
The tag should consist of where the change is being made ex. (x/staking), (store)
The issue numbers will later be link-ified during the release process so you do
not have to worry about including a link manually, but you can if you wish.
Types of changes (Stanzas):
"Features" for new features.
"Improvements" for changes in existing functionality.
"Deprecated" for soon-to-be removed features.
"Bug Fixes" for any bug fixes.
"KVIndexer Breaking" for breaking KVIndexer module.
"Submodule Breaking" for breaking submodules
Ref: https://keepachangelog.com/en/1.0.0/
-->

# Changelog

## [Unreleased]

### KVIndexer breaking

* (cache) [#48](https://github.com/initia-labs/kvindexer/pull/48) Replace record-count-based lru cache with capacity-based one
16 changes: 8 additions & 8 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import (
)

const (
flagIndexerEnable = "indexer.enable"
flagIndexerBackend = "indexer.backend"
flagIndexerCacheSize = "indexer.cache-size"
flagIndexerEnable = "indexer.enable"
flagIndexerBackend = "indexer.backend"
flagIndexerCacheCapacity = "indexer.cache-capacity"
)

func NewConfig(appOpts servertypes.AppOptions) (*IndexerConfig, error) {
Expand All @@ -23,15 +23,15 @@ func NewConfig(appOpts servertypes.AppOptions) (*IndexerConfig, error) {
if !cfg.Enable {
return cfg, nil
}
cfg.CacheSize = cast.ToUint(appOpts.Get(flagIndexerCacheSize))
cfg.CacheCapacity = cast.ToInt(appOpts.Get(flagIndexerCacheCapacity))

cfg.BackendConfig = viper.New()
err := cfg.BackendConfig.MergeConfigMap(cast.ToStringMap(appOpts.Get(flagIndexerBackend)))
if err != nil {
return nil, fmt.Errorf("failed to merge backend config: %w", err)
}

cfg.CacheSize = cast.ToUint(appOpts.Get(flagIndexerCacheSize))
cfg.CacheCapacity = cast.ToInt(appOpts.Get(flagIndexerCacheCapacity))

return cfg, nil
}
Expand All @@ -41,8 +41,8 @@ func (c IndexerConfig) Validate() error {
return nil
}

if c.CacheSize == 0 {
return fmt.Errorf("cache size must be greater than 0")
if c.CacheCapacity == 0 {
return fmt.Errorf("cache capacity must be greater than 0")
}

if c.BackendConfig == nil {
Expand All @@ -59,7 +59,7 @@ func (c IndexerConfig) IsEnabled() bool {
func DefaultConfig() IndexerConfig {
return IndexerConfig{
Enable: true,
CacheSize: 100_000,
CacheCapacity: 500 * 1024 * 1024, // 500MiB
BackendConfig: store.DefaultConfig(),
}
}
6 changes: 3 additions & 3 deletions config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (

type IndexerConfig struct {
Enable bool `mapstructure:"indexer.enable"`
CacheSize uint `mapstructure:"indexer.cache-size"`
CacheCapacity int `mapstructure:"indexer.cache-capacity"`
BackendConfig *viper.Viper `mapstructure:"indexer.backend"`
}

Expand All @@ -20,8 +20,8 @@ const DefaultConfigTemplate = `
# Enable defines whether the indexer is enabled.
enable = {{ .IndexerConfig.Enable }}
# CacheSize defines the size of the cache.
cache-size = {{ .IndexerConfig.CacheSize }}
# CacheCapacity defines the size of the cache. (unit: bytes)
cache-capacity = {{ .IndexerConfig.CacheCapacity }}
# Backend defines the type of the backend store and its options.
# It should have a key-value pair named 'type', and the value should exist in store supported by cosmos-db.
Expand Down
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
cosmossdk.io/core v0.11.0
cosmossdk.io/log v1.3.1
cosmossdk.io/store v1.0.2
github.com/allegro/bigcache/v3 v3.1.0
github.com/cometbft/cometbft v0.38.5
github.com/cosmos/cosmos-db v1.0.2
github.com/cosmos/cosmos-sdk v0.50.5
Expand All @@ -24,10 +25,12 @@ require (
google.golang.org/grpc v1.62.0
)

require github.com/hashicorp/golang-lru v1.0.2 // indirect

require (
cosmossdk.io/api v0.7.3 // indirect
cosmossdk.io/depinject v1.0.0-alpha.4 // indirect
cosmossdk.io/errors v1.0.1 // indirect
cosmossdk.io/errors v1.0.1
cosmossdk.io/math v1.3.0 // indirect
cosmossdk.io/x/tx v0.13.1 // indirect
filippo.io/edwards25519 v1.0.0 // indirect
Expand Down Expand Up @@ -90,7 +93,6 @@ require (
github.com/hashicorp/go-metrics v0.5.2 // indirect
github.com/hashicorp/go-plugin v1.5.2 // indirect
github.com/hashicorp/go-uuid v1.0.2 // indirect
github.com/hashicorp/golang-lru v1.0.2
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/hdevalence/ed25519consensus v0.1.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/allegro/bigcache/v3 v3.1.0 h1:H2Vp8VOvxcrB91o86fUSVJFqeuz8kpyyB02eH3bSzwk=
github.com/allegro/bigcache/v3 v3.1.0/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
Expand Down
47 changes: 31 additions & 16 deletions store/cache_kvstore.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
package store

import (
"fmt"
"context"

"cosmossdk.io/errors"
cachekv "cosmossdk.io/store/cachekv"
"cosmossdk.io/store/types"
lru "github.com/hashicorp/golang-lru"
bigcache "github.com/allegro/bigcache/v3"
)

type CacheStore struct {
store types.CacheKVStore
cache *lru.ARCCache
cache *bigcache.BigCache
}

func NewCacheStore(store types.KVStore, size uint) *CacheStore {
cache, err := lru.NewARC(int(size))
func NewCacheStore(store types.KVStore, capacity int) *CacheStore {
// default with no eviction and custom hard max cache capacity
cacheCfg := bigcache.DefaultConfig(0)
cacheCfg.Verbose = false
cacheCfg.HardMaxCacheSize = capacity

cache, err := bigcache.New(context.Background(), cacheCfg)
if err != nil {
panic(fmt.Errorf("failed to create KVStore cache: %s", err))
panic(err)
}

return &CacheStore{
Expand All @@ -28,36 +34,45 @@ func NewCacheStore(store types.KVStore, size uint) *CacheStore {
func (c CacheStore) Get(key []byte) ([]byte, error) {
types.AssertValidKey(key)

v, ok := c.cache.Get(string(key))
if ok {
// cache hit
return v.([]byte), nil
v, err := c.cache.Get(string(key))
// cache hit
if err == nil {
return v, nil
}

// write to cache
// get from store and write to cache
value := c.store.Get(key)
c.cache.Add(string(key), value)
err = c.cache.Set(string(key), value)
if err != nil {
return nil, errors.Wrap(err, "failed to set cache")
}

return value, nil
}

func (c CacheStore) Has(key []byte) (bool, error) {
_, ok := c.cache.Get(string(key))
return ok, nil
_, err := c.cache.Get(string(key))
return err == nil, err
}

func (c CacheStore) Set(key, value []byte) error {
types.AssertValidKey(key)
types.AssertValidValue(value)

c.cache.Add(string(key), value)
err := c.cache.Set(string(key), value)
if err != nil {
return errors.Wrap(err, "failed to set cache")
}
c.store.Set(key, value)

return nil
}

func (c CacheStore) Delete(key []byte) error {
c.cache.Remove(string(key))
err := c.cache.Delete(string(key))
if err != nil && errors.IsOf(err, bigcache.ErrEntryNotFound) {
return errors.Wrap(err, "failed to delete cache")
}
c.store.Delete(key)

return nil
Expand Down
2 changes: 1 addition & 1 deletion x/kvindexer/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (k *Keeper) Seal() error {
k.db = db
k.schema = &schema

k.store = store.NewCacheStore(dbadapter.Store{DB: db}, k.config.CacheSize)
k.store = store.NewCacheStore(dbadapter.Store{DB: db}, k.config.CacheCapacity)
k.sealed = true

return nil
Expand Down

0 comments on commit 8808e02

Please sign in to comment.