Skip to content

Commit

Permalink
Redesigning cache using atomic.Pointer + fixing tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pbukva committed Aug 10, 2023
1 parent 7aafc7d commit ee47532
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 48 deletions.
18 changes: 9 additions & 9 deletions x/bank/simulation/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import (
)

var (
testSupplyVal, _ = sdk.NewIntFromString("1000000000000000000")
AdditionalTestSupply = sdk.NewCoins(
testSupplyVal, _ = sdk.NewIntFromString("1000000000000000000")
AdditionalTestBalancePerAccount = sdk.NewCoins(
sdk.NewCoin("denom0", testSupplyVal),
sdk.NewCoin("denom1", testSupplyVal),
sdk.NewCoin("denom2", testSupplyVal),
Expand Down Expand Up @@ -51,17 +51,14 @@ func RandomGenesisBalances(simState *module.SimulationState) []types.Balance {
genesisBalances := []types.Balance{}

for _, acc := range simState.Accounts {
coins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(simState.InitialStake)))
coins.Add(AdditionalTestBalancePerAccount...)
genesisBalances = append(genesisBalances, types.Balance{
Address: acc.Address.String(),
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(simState.InitialStake))),
Coins: coins,
})
}

if len(genesisBalances) > 0 {
nb := genesisBalances[0].Coins.Add(AdditionalTestSupply...)
genesisBalances[0].Coins = nb
}

return genesisBalances
}

Expand All @@ -82,7 +79,10 @@ func RandomizedGenState(simState *module.SimulationState) {
numAccs := int64(len(simState.Accounts))
totalSupply := sdk.NewInt(simState.InitialStake * (numAccs + simState.NumBonded))

supply := AdditionalTestSupply.Add(sdk.NewCoin(sdk.DefaultBondDenom, totalSupply))
supply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, totalSupply))
for _, b := range AdditionalTestBalancePerAccount {
supply.Add(sdk.NewCoin(b.Denom, b.Amount.MulRaw(numAccs)))
}

bankGenesis := types.GenesisState{
Params: types.Params{
Expand Down
7 changes: 6 additions & 1 deletion x/bank/simulation/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ func TestRandomizedGenState(t *testing.T) {
require.Len(t, bankGenesis.Balances, 3)
require.Equal(t, "cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r", bankGenesis.Balances[2].GetAddress().String())
require.Equal(t, "1000stake", bankGenesis.Balances[2].GetCoins().String())
expectedSupply := simulation.AdditionalTestSupply.Add(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(6000)))

numAccs := int64(len(simState.Accounts))
expectedSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(6000)))
for _, b := range simulation.AdditionalTestBalancePerAccount {
expectedSupply.Add(sdk.NewCoin(b.Denom, b.Amount.MulRaw(numAccs)))
}
require.Equal(t, expectedSupply.String(), bankGenesis.Supply.String())
}

Expand Down
59 changes: 26 additions & 33 deletions x/mint/cache/municipal_inflation_cahe.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cache

import (
"sync"
"sync/atomic"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/mint/types"
Expand All @@ -12,11 +12,14 @@ type MunicipalInflationCacheItem struct {
AnnualInflation *types.MunicipalInflation
}

type MunicipalInflationCache struct {
type MunicipalInflationCacheInternal struct {
blocksPerYear uint64
original *[]*types.MunicipalInflationPair
inflations map[string]*MunicipalInflationCacheItem // {denom: inflationPerBlock}
mu sync.RWMutex
}

type MunicipalInflationCache struct {
internal atomic.Pointer[MunicipalInflationCacheInternal]

Check failure on line 22 in x/mint/cache/municipal_inflation_cahe.go

View workflow job for this annotation

GitHub Actions / golangci-lint

undefined: atomic.Pointer (typecheck)
}

// GMunicipalInflationCache Thread safety:
Expand All @@ -32,41 +35,38 @@ type MunicipalInflationCache struct {
var GMunicipalInflationCache = MunicipalInflationCache{}

func (cache *MunicipalInflationCache) Refresh(inflations *[]*types.MunicipalInflationPair, blocksPerYear uint64) {
cache.mu.Lock()
defer cache.mu.Unlock()

cache.refresh(inflations, blocksPerYear)
newCache := MunicipalInflationCacheInternal{}
newCache.refresh(inflations, blocksPerYear)
cache.internal.Store(&newCache)
}

// RefreshIfNecessary
// IMPORTANT: Assuming *NO* concurrent writes, designed with emphasis for concurrent reads. This requirement
// guaranteed, since this method is called exclusively from call contexts which are never concurrent.
// This approach will guarantee the most possible effective cache operation in heavily concurrent
// read environment with minimum possible blocking for concurrent read operations, but with slight
// limitation for write operations (there should not be concurrent write operations).
// Most of the read operations are assumed to be done from RPC (querying municipal inflation).
func (cache *MunicipalInflationCache) RefreshIfNecessary(inflations *[]*types.MunicipalInflationPair, blocksPerYear uint64) {
cache.mu.Lock()
defer cache.mu.Unlock()

cache.refreshIfNecessary(inflations, blocksPerYear)
}

func (cache *MunicipalInflationCache) IsRefreshRequired(blocksPerYear uint64) bool {
cache.mu.RLock()
defer cache.mu.RUnlock()
return cache.isRefreshRequired(blocksPerYear)
current := cache.internal.Load()
if current.isRefreshRequired(blocksPerYear) {
cache.Refresh(inflations, blocksPerYear)
}
}

func (cache *MunicipalInflationCache) GetInflation(denom string) (MunicipalInflationCacheItem, bool) {
cache.mu.RLock()
defer cache.mu.RUnlock()
infl, exists := cache.inflations[denom]
current := cache.internal.Load()
infl, exists := current.inflations[denom]
return *infl, exists
}

func (cache *MunicipalInflationCache) GetOriginal() *[]*types.MunicipalInflationPair {
cache.mu.RLock()
defer cache.mu.RUnlock()
// NOTE(pb): Mutex locking might not be necessary here since we are returning by pointer
return cache.original
current := cache.internal.Load()
return current.original
}

// NOTE(pb): *NOT* thread safe
func (cache *MunicipalInflationCache) refresh(inflations *[]*types.MunicipalInflationPair, blocksPerYear uint64) {
func (cache *MunicipalInflationCacheInternal) refresh(inflations *[]*types.MunicipalInflationPair, blocksPerYear uint64) {
if err := types.ValidateMunicipalInflations(inflations); err != nil {
panic(err)
}
Expand All @@ -89,13 +89,6 @@ func (cache *MunicipalInflationCache) refresh(inflations *[]*types.MunicipalInfl
}

// NOTE(pb): *NOT* thread safe
func (cache *MunicipalInflationCache) refreshIfNecessary(inflations *[]*types.MunicipalInflationPair, blocksPerYear uint64) {
if cache.isRefreshRequired(blocksPerYear) {
cache.refresh(inflations, blocksPerYear)
}
}

// NOTE(pb): *NOT* thread safe
func (cache *MunicipalInflationCache) isRefreshRequired(blocksPerYear uint64) bool {
func (cache *MunicipalInflationCacheInternal) isRefreshRequired(blocksPerYear uint64) bool {
return cache.blocksPerYear != blocksPerYear
}
2 changes: 2 additions & 0 deletions x/mint/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package mint

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/mint/cache"
"github.com/cosmos/cosmos-sdk/x/mint/keeper"
"github.com/cosmos/cosmos-sdk/x/mint/types"
)

// InitGenesis new mint genesis
func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, ak types.AccountKeeper, data *types.GenesisState) {
cache.GMunicipalInflationCache.Refresh(&data.Minter.MunicipalInflation, data.Params.BlocksPerYear)
keeper.SetMinter(ctx, data.Minter)
keeper.SetParams(ctx, data.Params)
ak.GetModuleAccount(ctx, types.ModuleName)
Expand Down
12 changes: 7 additions & 5 deletions x/mint/simulation/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ package simulation
import (
"encoding/json"
"fmt"
"github.com/cosmos/cosmos-sdk/x/bank/simulation"
"math/rand"

"github.com/cosmos/cosmos-sdk/x/bank/simulation"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/mint/types"
Expand All @@ -33,9 +34,9 @@ func GenInflationRate(r *rand.Rand) sdk.Dec {
func GenMunicipalInflation(simState *module.SimulationState) []*types.MunicipalInflationPair {
r := simState.Rand

coins := make([]*sdk.Coin, len(simulation.AdditionalTestSupply))
for i := 0; i < len(simulation.AdditionalTestSupply); i++ {
coins[i] = &simulation.AdditionalTestSupply[i]
coins := make([]*sdk.Coin, len(simulation.AdditionalTestBalancePerAccount))
for i := 0; i < len(simulation.AdditionalTestBalancePerAccount); i++ {
coins[i] = &simulation.AdditionalTestBalancePerAccount[i]
}

len_ := r.Intn(len(coins) + 1)
Expand All @@ -44,7 +45,8 @@ func GenMunicipalInflation(simState *module.SimulationState) []*types.MunicipalI
lenCoins := len(coins)
lastIdx := lenCoins - 1
rndIdx := r.Intn(lenCoins)
fmt.Println(">>>>>>>>>>>>>>>", coins, "rndIdx:", rndIdx)

// Swapping rndIdx element with the last element in the slice and cuttig slice without last element
c := coins[rndIdx]
coins[rndIdx] = coins[lastIdx]
coins = coins[:lastIdx]
Expand Down

0 comments on commit ee47532

Please sign in to comment.