core: remove mutexes and atomic values from native cache

Native cache is always wrapped into independant layers, so concurrent
RW access is no-op.
This commit is contained in:
Anna Shaleva 2022-04-19 12:26:46 +03:00
parent 7b632c8ee8
commit 8ec8511d9d
6 changed files with 101 additions and 196 deletions

View file

@ -48,11 +48,11 @@ type roleData struct {
}
type DesignationCache struct {
rolesChangedFlag atomic.Value
oracles atomic.Value
stateVals atomic.Value
neofsAlphabet atomic.Value
notaries atomic.Value
rolesChangedFlag bool
oracles roleData
stateVals roleData
neofsAlphabet roleData
notaries roleData
}
const (
@ -101,24 +101,7 @@ func (c *DesignationCache) Persist(ps storage.NativeContractCache) (storage.Nati
}
func copyDesignationCache(src, dst *DesignationCache) {
dst.rolesChangedFlag.Store(src.rolesChangedFlag.Load())
for _, r := range []noderoles.Role{noderoles.StateValidator, noderoles.Oracle, noderoles.NeoFSAlphabet, noderoles.P2PNotary} {
data := getCachedRoleData(src, r)
if data != nil {
var v = &roleData{}
*v = *data
switch r {
case noderoles.StateValidator:
dst.stateVals.Store(v)
case noderoles.Oracle:
dst.oracles.Store(v)
case noderoles.NeoFSAlphabet:
dst.neofsAlphabet.Store(v)
case noderoles.P2PNotary:
dst.notaries.Store(v)
}
}
}
*dst = *src
}
func (s *Designate) isValidRole(r noderoles.Role) bool {
@ -153,7 +136,7 @@ func newDesignate(p2pSigExtensionsEnabled bool) *Designate {
// Initialize initializes Oracle contract.
func (s *Designate) Initialize(ic *interop.Context) error {
cache := &DesignationCache{}
cache.rolesChangedFlag.Store(true)
cache.rolesChangedFlag = true
ic.DAO.Store.SetCache(s.ID, cache)
return nil
}
@ -185,7 +168,7 @@ func (s *Designate) PostPersist(ic *interop.Context) error {
}
}
cache.rolesChangedFlag.Store(false)
cache.rolesChangedFlag = false
return nil
}
@ -215,8 +198,7 @@ func (s *Designate) getDesignatedByRole(ic *interop.Context, args []stackitem.It
}
func rolesChanged(cache *DesignationCache) bool {
rc := cache.rolesChangedFlag.Load()
return rc == nil || rc.(bool)
return cache.rolesChangedFlag
}
func (s *Designate) hashFromNodes(r noderoles.Role, nodes keys.PublicKeys) util.Uint160 {
@ -233,16 +215,14 @@ func (s *Designate) hashFromNodes(r noderoles.Role, nodes keys.PublicKeys) util.
return hash.Hash160(script)
}
func (s *Designate) updateCachedRoleData(v *atomic.Value, d *dao.Simple, r noderoles.Role) error {
func (s *Designate) updateCachedRoleData(v *roleData, d *dao.Simple, r noderoles.Role) error {
nodeKeys, height, err := s.GetDesignatedByRole(d, r, math.MaxUint32)
if err != nil {
return err
}
v.Store(&roleData{
nodes: nodeKeys,
addr: s.hashFromNodes(r, nodeKeys),
height: height,
})
v.nodes = nodeKeys
v.addr = s.hashFromNodes(r, nodeKeys)
v.height = height
switch r {
case noderoles.Oracle:
if orc, _ := s.OracleService.Load().(services.Oracle); orc != nil {
@ -261,19 +241,15 @@ func (s *Designate) updateCachedRoleData(v *atomic.Value, d *dao.Simple, r noder
}
func getCachedRoleData(cache *DesignationCache, r noderoles.Role) *roleData {
var val interface{}
switch r {
case noderoles.Oracle:
val = cache.oracles.Load()
return &cache.oracles
case noderoles.StateValidator:
val = cache.stateVals.Load()
return &cache.stateVals
case noderoles.NeoFSAlphabet:
val = cache.neofsAlphabet.Load()
return &cache.neofsAlphabet
case noderoles.P2PNotary:
val = cache.notaries.Load()
}
if val != nil {
return val.(*roleData)
return &cache.notaries
}
return nil
}
@ -381,7 +357,7 @@ func (s *Designate) DesignateAsRole(ic *interop.Context, r noderoles.Role, pubs
}
sort.Sort(pubs)
nl := NodeList(pubs)
ic.DAO.Store.GetRWCache(s.ID).(*DesignationCache).rolesChangedFlag.Store(true)
ic.DAO.Store.GetRWCache(s.ID).(*DesignationCache).rolesChangedFlag = true
err := putConvertibleToDAO(s.ID, ic.DAO, key, &nl)
if err != nil {
return err
@ -413,6 +389,6 @@ func (s *Designate) getRole(item stackitem.Item) (noderoles.Role, bool) {
// InitializeCache invalidates native Designate cache.
func (s *Designate) InitializeCache(d *dao.Simple) {
cache := &DesignationCache{}
cache.rolesChangedFlag.Store(true)
cache.rolesChangedFlag = true
d.Store.SetCache(s.ID, cache)
}

View file

@ -6,7 +6,6 @@ import (
"fmt"
"math"
"math/big"
"sync"
"unicode/utf8"
"github.com/nspcc-dev/neo-go/pkg/core/dao"
@ -33,7 +32,6 @@ type Management struct {
}
type ManagementCache struct {
mtx sync.RWMutex
contracts map[util.Uint160]*state.Contract
// nep11 is a map of NEP11-compliant contracts which is updated with every PostPersist.
nep11 map[util.Uint160]struct{}
@ -188,9 +186,7 @@ func (m *Management) getContract(ic *interop.Context, args []stackitem.Item) sta
// GetContract returns contract with given hash from given DAO.
func (m *Management) GetContract(d *dao.Simple, hash util.Uint160) (*state.Contract, error) {
cache := d.Store.GetROCache(m.ID).(*ManagementCache)
cache.mtx.RLock()
cs, ok := cache.contracts[hash]
cache.mtx.RUnlock()
if !ok {
return nil, storage.ErrKeyNotFound
} else if cs != nil {
@ -304,10 +300,8 @@ func (m *Management) deployWithData(ic *interop.Context, args []stackitem.Item)
func (m *Management) markUpdated(d *dao.Simple, h util.Uint160) {
cache := d.Store.GetRWCache(m.ID).(*ManagementCache)
cache.mtx.Lock()
// Just set it to nil, to refresh cache in `PostPersist`.
cache.contracts[h] = nil
cache.mtx.Unlock()
}
// Deploy creates contract's hash/ID and saves new contract into the given DAO.
@ -520,9 +514,7 @@ func (m *Management) OnPersist(ic *interop.Context) error {
if cache == nil {
cache = ic.DAO.Store.GetRWCache(m.ID).(*ManagementCache)
}
cache.mtx.Lock()
updateContractCache(cache, cs)
cache.mtx.Unlock()
}
return nil
@ -558,8 +550,6 @@ func (m *Management) InitializeCache(d *dao.Simple) error {
// PostPersist implements Contract interface.
func (m *Management) PostPersist(ic *interop.Context) error {
cache := ic.DAO.Store.GetRWCache(m.ID).(*ManagementCache)
cache.mtx.Lock()
defer cache.mtx.Unlock()
for h, cs := range cache.contracts {
if cs != nil {
continue
@ -582,12 +572,10 @@ func (m *Management) PostPersist(ic *interop.Context) error {
// is returned.
func (m *Management) GetNEP11Contracts(d *dao.Simple) []util.Uint160 {
cache := d.Store.GetROCache(m.ID).(*ManagementCache)
cache.mtx.RLock()
result := make([]util.Uint160, 0, len(cache.nep11))
for h := range cache.nep11 {
result = append(result, h)
}
cache.mtx.RUnlock()
return result
}
@ -596,12 +584,10 @@ func (m *Management) GetNEP11Contracts(d *dao.Simple) []util.Uint160 {
// is returned.
func (m *Management) GetNEP17Contracts(d *dao.Simple) []util.Uint160 {
cache := d.Store.GetROCache(m.ID).(*ManagementCache)
cache.mtx.RLock()
result := make([]util.Uint160, 0, len(cache.nep17))
for h := range cache.nep17 {
result = append(result, h)
}
cache.mtx.RUnlock()
return result
}

View file

@ -8,7 +8,6 @@ import (
"math/big"
"sort"
"strings"
"sync/atomic"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/core/dao"
@ -44,22 +43,22 @@ type NEO struct {
type NeoCache struct {
// gasPerBlock represents current value of generated gas per block.
// It is append-only and doesn't need to be copied when used.
gasPerBlock atomic.Value
gasPerBlockChanged atomic.Value
gasPerBlock gasRecord
gasPerBlockChanged bool
registerPrice atomic.Value
registerPriceChanged atomic.Value
registerPrice int64
registerPriceChanged bool
votesChanged atomic.Value
nextValidators atomic.Value
validators atomic.Value
votesChanged bool
nextValidators keys.PublicKeys
validators keys.PublicKeys
// committee contains cached committee members and their votes.
// It is updated once in a while depending on committee size
// (every 28 blocks for mainnet). It's value
// is always equal to value stored by `prefixCommittee`.
committee atomic.Value
committee keysWithVotes
// committeeHash contains script hash of the committee.
committeeHash atomic.Value
committeeHash util.Uint160
// gasPerVoteCache contains last updated value of GAS per vote reward for candidates.
// It is set in state-modifying methods only and read in `PostPersist` thus is not protected
@ -134,27 +133,21 @@ func (c *NeoCache) Persist(ps storage.NativeContractCache) (storage.NativeContra
}
func copyNeoCache(src, dst *NeoCache) {
dst.votesChanged.Store(src.votesChanged.Load())
dst.nextValidators.Store(src.nextValidators.Load().(keys.PublicKeys).Copy())
dst.validators.Store(src.validators.Load().(keys.PublicKeys).Copy())
committeeSrc := src.committee.Load().(keysWithVotes)
committeeDst := make(keysWithVotes, len(committeeSrc))
copy(committeeDst, committeeSrc)
dst.committee.Store(committeeDst)
dst.committeeHash.Store(src.committeeHash.Load())
regPriceChanged := src.registerPriceChanged.Load().(bool)
dst.registerPriceChanged.Store(regPriceChanged)
if !regPriceChanged {
dst.registerPrice.Store(src.registerPrice.Load())
}
gasPerBlockChanged := src.gasPerBlockChanged.Load().(bool)
dst.gasPerBlockChanged.Store(gasPerBlockChanged)
if !gasPerBlockChanged {
recordsSrc := src.gasPerBlock.Load().(gasRecord)
recordsDst := make(gasRecord, len(recordsSrc))
copy(recordsDst, recordsSrc)
dst.gasPerBlock.Store(recordsDst)
}
dst.votesChanged = src.votesChanged
dst.nextValidators = src.nextValidators.Copy()
dst.validators = src.validators.Copy()
dst.committee = make(keysWithVotes, len(src.committee))
copy(dst.committee, src.committee)
dst.committeeHash = src.committeeHash
dst.registerPriceChanged = src.registerPriceChanged
dst.registerPrice = src.registerPrice
dst.gasPerBlockChanged = src.gasPerBlockChanged
dst.gasPerBlock = make(gasRecord, len(src.gasPerBlock))
copy(dst.gasPerBlock, src.gasPerBlock)
dst.gasPerVoteCache = make(map[string]big.Int)
for k, v := range src.gasPerVoteCache {
dst.gasPerVoteCache[k] = v
@ -263,13 +256,9 @@ func (n *NEO) Initialize(ic *interop.Context) error {
cache := &NeoCache{
gasPerVoteCache: make(map[string]big.Int),
votesChanged: true,
registerPriceChanged: true,
}
cache.votesChanged.Store(true)
cache.nextValidators.Store(keys.PublicKeys(nil))
cache.validators.Store(keys.PublicKeys(nil))
cache.committee.Store(keysWithVotes(nil))
cache.committeeHash.Store(util.Uint160{})
cache.registerPriceChanged.Store(true)
// We need cache to be present in DAO before the subsequent call to `mint`.
ic.DAO.Store.SetCache(n.ID, cache)
@ -294,13 +283,13 @@ func (n *NEO) Initialize(ic *interop.Context) error {
n.putGASRecord(ic.DAO, index, value)
gr := &gasRecord{{Index: index, GASPerBlock: *value}}
cache.gasPerBlock.Store(*gr)
cache.gasPerBlockChanged.Store(false)
cache.gasPerBlock = *gr
cache.gasPerBlockChanged = false
ic.DAO.PutStorageItem(n.ID, []byte{prefixVotersCount}, state.StorageItem{})
setIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice}, DefaultRegisterPrice)
cache.registerPrice.Store(int64(DefaultRegisterPrice))
cache.registerPriceChanged.Store(false)
cache.registerPrice = int64(DefaultRegisterPrice)
cache.registerPriceChanged = false
return nil
}
@ -311,15 +300,10 @@ func (n *NEO) Initialize(ic *interop.Context) error {
func (n *NEO) InitializeCache(bc interop.Ledger, d *dao.Simple) error {
cache := &NeoCache{
gasPerVoteCache: make(map[string]big.Int),
votesChanged: true,
registerPriceChanged: true,
}
cache.votesChanged.Store(true)
cache.nextValidators.Store(keys.PublicKeys(nil))
cache.validators.Store(keys.PublicKeys(nil))
cache.committee.Store(keysWithVotes(nil))
cache.committeeHash.Store(util.Uint160{})
cache.registerPriceChanged.Store(true)
var committee = keysWithVotes{}
si := d.GetStorageItem(n.ID, prefixCommittee)
if err := committee.DecodeBytes(si); err != nil {
@ -329,8 +313,8 @@ func (n *NEO) InitializeCache(bc interop.Ledger, d *dao.Simple) error {
return fmt.Errorf("failed to update cache: %w", err)
}
cache.gasPerBlock.Store(n.getSortedGASRecordFromDAO(d))
cache.gasPerBlockChanged.Store(false)
cache.gasPerBlock = n.getSortedGASRecordFromDAO(d)
cache.gasPerBlockChanged = false
d.Store.SetCache(n.ID, cache)
return nil
@ -345,28 +329,26 @@ func (n *NEO) initConfigCache(cfg config.ProtocolConfiguration) error {
}
func (n *NEO) updateCache(cache *NeoCache, cvs keysWithVotes, bc interop.Ledger) error {
cache.committee.Store(cvs)
cache.committee = cvs
var committee = getCommitteeMembers(cache)
script, err := smartcontract.CreateMajorityMultiSigRedeemScript(committee.Copy())
if err != nil {
return err
}
cache.committeeHash.Store(hash.Hash160(script))
cache.committeeHash = hash.Hash160(script)
// TODO: use block height from interop context for proper historical calls handling.
nextVals := committee[:n.cfg.GetNumOfCNs(bc.BlockHeight()+1)].Copy()
sort.Sort(nextVals)
cache.nextValidators.Store(nextVals)
cache.nextValidators = nextVals
return nil
}
func (n *NEO) updateCommittee(cache *NeoCache, ic *interop.Context) error {
votesChanged := cache.votesChanged.Load().(bool)
if !votesChanged {
if !cache.votesChanged {
// We need to put in storage anyway, as it affects dumps
committee := cache.committee.Load().(keysWithVotes)
ic.DAO.PutStorageItem(n.ID, prefixCommittee, committee.Bytes())
ic.DAO.PutStorageItem(n.ID, prefixCommittee, cache.committee.Bytes())
return nil
}
@ -377,7 +359,7 @@ func (n *NEO) updateCommittee(cache *NeoCache, ic *interop.Context) error {
if err := n.updateCache(cache, cvs, ic.Chain); err != nil {
return err
}
cache.votesChanged.Store(false)
cache.votesChanged = false
ic.DAO.PutStorageItem(n.ID, prefixCommittee, cvs.Bytes())
return nil
}
@ -386,11 +368,11 @@ func (n *NEO) updateCommittee(cache *NeoCache, ic *interop.Context) error {
func (n *NEO) OnPersist(ic *interop.Context) error {
if n.cfg.ShouldUpdateCommitteeAt(ic.Block.Index) {
cache := ic.DAO.Store.GetRWCache(n.ID).(*NeoCache)
oldKeys := cache.nextValidators.Load().(keys.PublicKeys)
oldCom := cache.committee.Load().(keysWithVotes)
oldKeys := cache.nextValidators
oldCom := cache.committee
if n.cfg.GetNumOfCNs(ic.Block.Index) != len(oldKeys) ||
n.cfg.GetCommitteeSize(ic.Block.Index) != len(oldCom) {
cache.votesChanged.Store(true)
cache.votesChanged = true
}
if err := n.updateCommittee(cache, ic); err != nil {
return err
@ -417,7 +399,7 @@ func (n *NEO) PostPersist(ic *interop.Context) error {
voterReward.Div(voterReward, big.NewInt(int64(committeeSize+validatorsCount)))
voterReward.Div(voterReward, big100)
var cs = cache.committee.Load().(keysWithVotes)
var cs = cache.committee
var key = make([]byte, 38)
for i := range cs {
if cs[i].Votes.Sign() > 0 {
@ -448,15 +430,15 @@ func (n *NEO) PostPersist(ic *interop.Context) error {
}
}
}
if cache.gasPerBlockChanged.Load().(bool) {
cache.gasPerBlock.Store(n.getSortedGASRecordFromDAO(ic.DAO))
cache.gasPerBlockChanged.Store(false)
if cache.gasPerBlockChanged {
cache.gasPerBlock = n.getSortedGASRecordFromDAO(ic.DAO)
cache.gasPerBlockChanged = false
}
if cache.registerPriceChanged.Load().(bool) {
if cache.registerPriceChanged {
p := getIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice})
cache.registerPrice.Store(p)
cache.registerPriceChanged.Store(false)
cache.registerPrice = p
cache.registerPriceChanged = false
}
return nil
}
@ -581,10 +563,10 @@ func (n *NEO) getSortedGASRecordFromDAO(d *dao.Simple) gasRecord {
func (n *NEO) GetGASPerBlock(d *dao.Simple, index uint32) *big.Int {
cache := d.Store.GetROCache(n.ID).(*NeoCache)
var gr gasRecord
if cache.gasPerBlockChanged.Load().(bool) {
if cache.gasPerBlockChanged {
gr = n.getSortedGASRecordFromDAO(d)
} else {
gr = cache.gasPerBlock.Load().(gasRecord)
gr = cache.gasPerBlock
}
for i := len(gr) - 1; i >= 0; i-- {
if gr[i].Index <= index {
@ -598,7 +580,7 @@ func (n *NEO) GetGASPerBlock(d *dao.Simple, index uint32) *big.Int {
// GetCommitteeAddress returns address of the committee.
func (n *NEO) GetCommitteeAddress(d *dao.Simple) util.Uint160 {
cache := d.Store.GetROCache(n.ID).(*NeoCache)
return cache.committeeHash.Load().(util.Uint160)
return cache.committeeHash
}
func (n *NEO) checkCommittee(ic *interop.Context) bool {
@ -627,7 +609,7 @@ func (n *NEO) SetGASPerBlock(ic *interop.Context, index uint32, gas *big.Int) er
return errors.New("invalid committee signature")
}
cache := ic.DAO.Store.GetRWCache(n.ID).(*NeoCache)
cache.gasPerBlockChanged.Store(true)
cache.gasPerBlockChanged = true
n.putGASRecord(ic.DAO, index, gas)
return nil
}
@ -638,8 +620,8 @@ func (n *NEO) getRegisterPrice(ic *interop.Context, _ []stackitem.Item) stackite
func (n *NEO) getRegisterPriceInternal(d *dao.Simple) int64 {
cache := d.Store.GetROCache(n.ID).(*NeoCache)
if !cache.registerPriceChanged.Load().(bool) {
return cache.registerPrice.Load().(int64)
if !cache.registerPriceChanged {
return cache.registerPrice
}
return getIntWithKey(n.ID, d, []byte{prefixRegisterPrice})
}
@ -655,7 +637,7 @@ func (n *NEO) setRegisterPrice(ic *interop.Context, args []stackitem.Item) stack
setIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice}, price.Int64())
cache := ic.DAO.Store.GetRWCache(n.ID).(*NeoCache)
cache.registerPriceChanged.Store(true)
cache.registerPriceChanged = true
return stackitem.Null{}
}
@ -726,8 +708,8 @@ func (n *NEO) CalculateNEOHolderReward(d *dao.Simple, value *big.Int, start, end
}
var gr gasRecord
cache := d.Store.GetROCache(n.ID).(*NeoCache)
if !cache.gasPerBlockChanged.Load().(bool) {
gr = cache.gasPerBlock.Load().(gasRecord)
if !cache.gasPerBlockChanged {
gr = cache.gasPerBlock
} else {
gr = n.getSortedGASRecordFromDAO(d)
}
@ -801,7 +783,7 @@ func (n *NEO) UnregisterCandidateInternal(ic *interop.Context, pub *keys.PublicK
return nil
}
cache := ic.DAO.Store.GetRWCache(n.ID).(*NeoCache)
cache.validators.Store(keys.PublicKeys(nil))
cache.validators = nil
c := new(candidate).FromBytes(si)
c.Registered = false
ok, err := n.dropCandidateIfZero(ic.DAO, cache, pub, c)
@ -881,7 +863,7 @@ func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pub *keys.Public
// typ specifies if this modify is occurring during transfer or vote (with old or new validator).
func (n *NEO) ModifyAccountVotes(acc *state.NEOBalance, d *dao.Simple, value *big.Int, isNewVote bool) error {
cache := d.Store.GetRWCache(n.ID).(*NeoCache)
cache.votesChanged.Store(true)
cache.votesChanged = true
if acc.VoteTo != nil {
key := makeValidatorKey(acc.VoteTo)
si := d.GetStorageItem(n.ID, key)
@ -896,7 +878,7 @@ func (n *NEO) ModifyAccountVotes(acc *state.NEOBalance, d *dao.Simple, value *bi
return err
}
}
cache.validators.Store(keys.PublicKeys(nil))
cache.validators = nil
return putConvertibleToDAO(n.ID, d, key, cd)
}
return nil
@ -992,7 +974,7 @@ func (n *NEO) getAccountState(ic *interop.Context, args []stackitem.Item) stacki
func (n *NEO) ComputeNextBlockValidators(bc interop.Ledger, d *dao.Simple) (keys.PublicKeys, error) {
numOfCNs := n.cfg.GetNumOfCNs(bc.BlockHeight() + 1)
cache := d.Store.GetRWCache(n.ID).(*NeoCache)
if vals := cache.validators.Load().(keys.PublicKeys); vals != nil && numOfCNs == len(vals) {
if vals := cache.validators; vals != nil && numOfCNs == len(vals) {
return vals.Copy(), nil
}
result, _, err := n.computeCommitteeMembers(bc, d)
@ -1001,7 +983,7 @@ func (n *NEO) ComputeNextBlockValidators(bc interop.Ledger, d *dao.Simple) (keys
}
result = result[:numOfCNs]
sort.Sort(result)
cache.validators.Store(result)
cache.validators = result
return result, nil
}
@ -1031,7 +1013,7 @@ func (n *NEO) GetCommitteeMembers(d *dao.Simple) keys.PublicKeys {
}
func getCommitteeMembers(cache *NeoCache) keys.PublicKeys {
var cvs = cache.committee.Load().(keysWithVotes)
var cvs = cache.committee
var committee = make(keys.PublicKeys, len(cvs))
var err error
for i := range committee {
@ -1107,7 +1089,7 @@ func (n *NEO) getNextBlockValidators(ic *interop.Context, _ []stackitem.Item) st
// GetNextBlockValidatorsInternal returns next block validators.
func (n *NEO) GetNextBlockValidatorsInternal(d *dao.Simple) keys.PublicKeys {
cache := d.Store.GetROCache(n.ID).(*NeoCache)
return cache.nextValidators.Load().(keys.PublicKeys).Copy()
return cache.nextValidators.Copy()
}
// BalanceOf returns native NEO token balance for the acc.

View file

@ -5,7 +5,6 @@ import (
"fmt"
"math"
"math/big"
"sync"
"github.com/nspcc-dev/neo-go/pkg/core/dao"
"github.com/nspcc-dev/neo-go/pkg/core/interop"
@ -35,7 +34,6 @@ type Notary struct {
}
type NotaryCache struct {
lock sync.RWMutex
// isValid defies whether cached values were changed during the current
// consensus iteration. If false, these values will be updated after
// blockchain DAO persisting. If true, we can safely use cached values.
@ -84,9 +82,7 @@ func (c *NotaryCache) Persist(ps storage.NativeContractCache) (storage.NativeCon
}
func copyNotaryCache(src, dst *NotaryCache) {
dst.isValid = src.isValid
dst.maxNotValidBeforeDelta = src.maxNotValidBeforeDelta
dst.notaryServiceFeePerKey = src.notaryServiceFeePerKey
*dst = *src
}
// newNotary returns Notary native contract.
@ -224,8 +220,6 @@ func (n *Notary) OnPersist(ic *interop.Context) error {
// PostPersist implements Contract interface.
func (n *Notary) PostPersist(ic *interop.Context) error {
cache := ic.DAO.Store.GetRWCache(n.ID).(*NotaryCache)
cache.lock.Lock()
defer cache.lock.Unlock()
if cache.isValid {
return nil
}
@ -440,8 +434,6 @@ func (n *Notary) getMaxNotValidBeforeDelta(ic *interop.Context, _ []stackitem.It
// GetMaxNotValidBeforeDelta is an internal representation of Notary getMaxNotValidBeforeDelta method.
func (n *Notary) GetMaxNotValidBeforeDelta(dao *dao.Simple) uint32 {
cache := dao.Store.GetROCache(n.ID).(*NotaryCache)
cache.lock.RLock()
defer cache.lock.RUnlock()
if cache.isValid {
return cache.maxNotValidBeforeDelta
}
@ -460,8 +452,6 @@ func (n *Notary) setMaxNotValidBeforeDelta(ic *interop.Context, args []stackitem
panic("invalid committee signature")
}
cache := ic.DAO.Store.GetRWCache(n.ID).(*NotaryCache)
cache.lock.Lock()
defer cache.lock.Unlock()
setIntWithKey(n.ID, ic.DAO, maxNotValidBeforeDeltaKey, int64(value))
cache.isValid = false
return stackitem.Null{}
@ -475,8 +465,6 @@ func (n *Notary) getNotaryServiceFeePerKey(ic *interop.Context, _ []stackitem.It
// GetNotaryServiceFeePerKey is an internal representation of Notary getNotaryServiceFeePerKey method.
func (n *Notary) GetNotaryServiceFeePerKey(dao *dao.Simple) int64 {
cache := dao.Store.GetROCache(n.ID).(*NotaryCache)
cache.lock.RLock()
defer cache.lock.RUnlock()
if cache.isValid {
return cache.notaryServiceFeePerKey
}
@ -493,8 +481,6 @@ func (n *Notary) setNotaryServiceFeePerKey(ic *interop.Context, args []stackitem
panic("invalid committee signature")
}
cache := ic.DAO.Store.GetRWCache(n.ID).(*NotaryCache)
cache.lock.Lock()
defer cache.lock.Unlock()
setIntWithKey(n.ID, ic.DAO, notaryServiceFeeKey, int64(value))
cache.isValid = false
return stackitem.Null{}

View file

@ -47,8 +47,8 @@ type Oracle struct {
}
type OracleCache struct {
requestPrice atomic.Value
requestPriceChanged atomic.Value
requestPrice int64
requestPriceChanged bool
}
const (
@ -110,8 +110,7 @@ func (c *OracleCache) Persist(ps storage.NativeContractCache) (storage.NativeCon
}
func copyOracleCache(src, dst *OracleCache) {
dst.requestPrice.Store(src.requestPrice.Load())
dst.requestPriceChanged.Store(src.requestPriceChanged.Load())
*dst = *src
}
func newOracle() *Oracle {
@ -174,9 +173,9 @@ func (o *Oracle) OnPersist(ic *interop.Context) error {
func (o *Oracle) PostPersist(ic *interop.Context) error {
p := o.getPriceInternal(ic.DAO)
cache := ic.DAO.Store.GetRWCache(o.ID).(*OracleCache)
if cache.requestPriceChanged.Load().(bool) {
cache.requestPrice.Store(p)
cache.requestPriceChanged.Store(false)
if cache.requestPriceChanged {
cache.requestPrice = p
cache.requestPriceChanged = false
}
var nodes keys.PublicKeys
@ -253,16 +252,16 @@ func (o *Oracle) Initialize(ic *interop.Context) error {
setIntWithKey(o.ID, ic.DAO, prefixRequestPrice, DefaultOracleRequestPrice)
cache := &OracleCache{}
cache.requestPrice.Store(int64(DefaultOracleRequestPrice))
cache.requestPriceChanged.Store(false)
cache.requestPrice = int64(DefaultOracleRequestPrice)
cache.requestPriceChanged = false
ic.DAO.Store.SetCache(o.ID, cache)
return nil
}
func (o *Oracle) InitializeCache(d *dao.Simple) {
cache := &OracleCache{}
cache.requestPrice.Store(getIntWithKey(o.ID, d, prefixRequestPrice))
cache.requestPriceChanged.Store(false)
cache.requestPrice = getIntWithKey(o.ID, d, prefixRequestPrice)
cache.requestPriceChanged = false
d.Store.SetCache(o.ID, cache)
}
@ -481,8 +480,8 @@ func (o *Oracle) getPrice(ic *interop.Context, _ []stackitem.Item) stackitem.Ite
func (o *Oracle) getPriceInternal(d *dao.Simple) int64 {
cache := d.Store.GetROCache(o.ID).(*OracleCache)
if !cache.requestPriceChanged.Load().(bool) {
return cache.requestPrice.Load().(int64)
if !cache.requestPriceChanged {
return cache.requestPrice
}
return getIntWithKey(o.ID, d, prefixRequestPrice)
}
@ -497,7 +496,7 @@ func (o *Oracle) setPrice(ic *interop.Context, args []stackitem.Item) stackitem.
}
setIntWithKey(o.ID, ic.DAO, prefixRequestPrice, price.Int64())
cache := ic.DAO.Store.GetRWCache(o.ID).(*OracleCache)
cache.requestPriceChanged.Store(true)
cache.requestPriceChanged = true
return stackitem.Null{}
}

View file

@ -5,7 +5,6 @@ import (
"fmt"
"math/big"
"sort"
"sync"
"github.com/nspcc-dev/neo-go/pkg/core/dao"
"github.com/nspcc-dev/neo-go/pkg/core/interop"
@ -57,7 +56,6 @@ type Policy struct {
}
type PolicyCache struct {
lock sync.RWMutex
// isValid defies whether cached values were changed during the current
// consensus iteration. If false, these values will be updated after
// blockchain DAO persisting. If true, we can safely use cached values.
@ -215,8 +213,6 @@ func (p *Policy) OnPersist(ic *interop.Context) error {
// PostPersist implements Contract interface.
func (p *Policy) PostPersist(ic *interop.Context) error {
cache := ic.DAO.Store.GetRWCache(p.ID).(*PolicyCache)
cache.lock.Lock()
defer cache.lock.Unlock()
if cache.isValid {
return nil
}
@ -233,8 +229,6 @@ func (p *Policy) getFeePerByte(ic *interop.Context, _ []stackitem.Item) stackite
// GetFeePerByteInternal returns required transaction's fee per byte.
func (p *Policy) GetFeePerByteInternal(dao *dao.Simple) int64 {
cache := dao.Store.GetROCache(p.ID).(*PolicyCache)
cache.lock.RLock()
defer cache.lock.RUnlock()
if cache.isValid {
return cache.feePerByte
}
@ -244,8 +238,6 @@ func (p *Policy) GetFeePerByteInternal(dao *dao.Simple) int64 {
// GetMaxVerificationGas returns maximum gas allowed to be burned during verificaion.
func (p *Policy) GetMaxVerificationGas(dao *dao.Simple) int64 {
cache := dao.Store.GetROCache(p.ID).(*PolicyCache)
cache.lock.RLock()
defer cache.lock.RUnlock()
if cache.isValid {
return cache.maxVerificationGas
}
@ -259,8 +251,6 @@ func (p *Policy) getExecFeeFactor(ic *interop.Context, _ []stackitem.Item) stack
// GetExecFeeFactorInternal returns current execution fee factor.
func (p *Policy) GetExecFeeFactorInternal(d *dao.Simple) int64 {
cache := d.Store.GetROCache(p.ID).(*PolicyCache)
cache.lock.RLock()
defer cache.lock.RUnlock()
if cache.isValid {
return int64(cache.execFeeFactor)
}
@ -276,8 +266,6 @@ func (p *Policy) setExecFeeFactor(ic *interop.Context, args []stackitem.Item) st
panic("invalid committee signature")
}
cache := ic.DAO.Store.GetRWCache(p.ID).(*PolicyCache)
cache.lock.Lock()
defer cache.lock.Unlock()
setIntWithKey(p.ID, ic.DAO, execFeeFactorKey, int64(value))
cache.isValid = false
return stackitem.Null{}
@ -292,8 +280,6 @@ func (p *Policy) isBlocked(ic *interop.Context, args []stackitem.Item) stackitem
// IsBlockedInternal checks whether provided account is blocked.
func (p *Policy) IsBlockedInternal(dao *dao.Simple, hash util.Uint160) bool {
cache := dao.Store.GetROCache(p.ID).(*PolicyCache)
cache.lock.RLock()
defer cache.lock.RUnlock()
if cache.isValid {
length := len(cache.blockedAccounts)
i := sort.Search(length, func(i int) bool {
@ -315,8 +301,6 @@ func (p *Policy) getStoragePrice(ic *interop.Context, _ []stackitem.Item) stacki
// GetStoragePriceInternal returns current execution fee factor.
func (p *Policy) GetStoragePriceInternal(d *dao.Simple) int64 {
cache := d.Store.GetROCache(p.ID).(*PolicyCache)
cache.lock.RLock()
defer cache.lock.RUnlock()
if cache.isValid {
return int64(cache.storagePrice)
}
@ -332,8 +316,6 @@ func (p *Policy) setStoragePrice(ic *interop.Context, args []stackitem.Item) sta
panic("invalid committee signature")
}
cache := ic.DAO.Store.GetRWCache(p.ID).(*PolicyCache)
cache.lock.Lock()
defer cache.lock.Unlock()
setIntWithKey(p.ID, ic.DAO, storagePriceKey, int64(value))
cache.isValid = false
return stackitem.Null{}
@ -349,8 +331,6 @@ func (p *Policy) setFeePerByte(ic *interop.Context, args []stackitem.Item) stack
panic("invalid committee signature")
}
cache := ic.DAO.Store.GetRWCache(p.ID).(*PolicyCache)
cache.lock.Lock()
defer cache.lock.Unlock()
setIntWithKey(p.ID, ic.DAO, feePerByteKey, value)
cache.isValid = false
return stackitem.Null{}
@ -373,8 +353,6 @@ func (p *Policy) blockAccount(ic *interop.Context, args []stackitem.Item) stacki
}
key := append([]byte{blockedAccountPrefix}, hash.BytesBE()...)
cache := ic.DAO.Store.GetRWCache(p.ID).(*PolicyCache)
cache.lock.Lock()
defer cache.lock.Unlock()
ic.DAO.PutStorageItem(p.ID, key, state.StorageItem{})
cache.isValid = false
return stackitem.NewBool(true)
@ -392,8 +370,6 @@ func (p *Policy) unblockAccount(ic *interop.Context, args []stackitem.Item) stac
}
key := append([]byte{blockedAccountPrefix}, hash.BytesBE()...)
cache := ic.DAO.Store.GetRWCache(p.ID).(*PolicyCache)
cache.lock.Lock()
defer cache.lock.Unlock()
ic.DAO.DeleteStorageItem(p.ID, key)
cache.isValid = false
return stackitem.NewBool(true)