core: move native cache from MemCachedStore to DAO
This commit is contained in:
parent
b77b412b04
commit
8d2d48f360
9 changed files with 181 additions and 170 deletions
|
@ -7,6 +7,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
iocore "io"
|
||||
"sync"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
|
@ -34,11 +35,28 @@ var (
|
|||
type Simple struct {
|
||||
Version Version
|
||||
Store *storage.MemCachedStore
|
||||
|
||||
nativeCacheLock sync.RWMutex
|
||||
nativeCache map[int32]NativeContractCache
|
||||
// nativeCachePS is the backend store that provides functionality to store
|
||||
// and retrieve multi-tier native contract cache. The lowest Simple has its
|
||||
// nativeCachePS set to nil.
|
||||
nativeCachePS *Simple
|
||||
|
||||
private bool
|
||||
keyBuf []byte
|
||||
dataBuf *io.BufBinWriter
|
||||
}
|
||||
|
||||
// NativeContractCache is an interface representing cache for a native contract.
|
||||
// Cache can be copied to create a wrapper around current DAO layer. Wrapped cache
|
||||
// can be persisted to the underlying DAO native cache.
|
||||
type NativeContractCache interface {
|
||||
// Copy returns a copy of native cache item that can safely be changed within
|
||||
// the subsequent DAO operations.
|
||||
Copy() NativeContractCache
|
||||
}
|
||||
|
||||
// NewSimple creates new simple dao using provided backend store.
|
||||
func NewSimple(backend storage.Store, stateRootInHeader bool, p2pSigExtensions bool) *Simple {
|
||||
st := storage.NewMemCachedStore(backend)
|
||||
|
@ -53,6 +71,7 @@ func newSimple(st *storage.MemCachedStore, stateRootInHeader bool, p2pSigExtensi
|
|||
P2PSigExtensions: p2pSigExtensions,
|
||||
},
|
||||
Store: st,
|
||||
nativeCache: make(map[int32]NativeContractCache),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,6 +85,7 @@ func (dao *Simple) GetBatch() *storage.MemBatch {
|
|||
func (dao *Simple) GetWrapped() *Simple {
|
||||
d := NewSimple(dao.Store, dao.Version.StateRootInHeader, dao.Version.P2PSigExtensions)
|
||||
d.Version = dao.Version
|
||||
d.nativeCachePS = dao
|
||||
return d
|
||||
}
|
||||
|
||||
|
@ -76,6 +96,13 @@ func (dao *Simple) GetPrivate() *Simple {
|
|||
*d = *dao // Inherit everything...
|
||||
d.Store = storage.NewPrivateMemCachedStore(dao.Store) // except storage, wrap another layer.
|
||||
d.private = true
|
||||
d.nativeCachePS = dao
|
||||
// Do not inherit cache from nativeCachePS; instead should create clear map:
|
||||
// GetRWCache and GetROCache will retrieve cache from the underlying
|
||||
// nativeCache if requested. The lowest underlying DAO MUST have its native
|
||||
// cache initialized before access it, otherwise GetROCache and GetRWCache
|
||||
// won't work properly.
|
||||
d.nativeCache = make(map[int32]NativeContractCache)
|
||||
return d
|
||||
}
|
||||
|
||||
|
@ -809,6 +836,17 @@ func (dao *Simple) getDataBuf() *io.BufBinWriter {
|
|||
// Persist flushes all the changes made into the (supposedly) persistent
|
||||
// underlying store. It doesn't block accesses to DAO from other threads.
|
||||
func (dao *Simple) Persist() (int, error) {
|
||||
if dao.nativeCachePS != nil {
|
||||
if !dao.private {
|
||||
dao.nativeCacheLock.Lock()
|
||||
defer dao.nativeCacheLock.Unlock()
|
||||
}
|
||||
if !dao.nativeCachePS.private {
|
||||
dao.nativeCachePS.nativeCacheLock.Lock()
|
||||
defer dao.nativeCachePS.nativeCacheLock.Unlock()
|
||||
}
|
||||
dao.persistNativeCache()
|
||||
}
|
||||
return dao.Store.Persist()
|
||||
}
|
||||
|
||||
|
@ -816,5 +854,77 @@ func (dao *Simple) Persist() (int, error) {
|
|||
// underlying store. It's a synchronous version of Persist that doesn't allow
|
||||
// other threads to work with DAO while flushing the Store.
|
||||
func (dao *Simple) PersistSync() (int, error) {
|
||||
if dao.nativeCachePS != nil {
|
||||
dao.nativeCacheLock.Lock()
|
||||
dao.nativeCachePS.nativeCacheLock.Lock()
|
||||
defer func() {
|
||||
dao.nativeCachePS.nativeCacheLock.Unlock()
|
||||
dao.nativeCacheLock.Unlock()
|
||||
}()
|
||||
dao.persistNativeCache()
|
||||
}
|
||||
return dao.Store.PersistSync()
|
||||
}
|
||||
|
||||
// persistNativeCache is internal unprotected method for native cache persisting.
|
||||
// It does NO checks for nativeCachePS is not nil.
|
||||
func (dao *Simple) persistNativeCache() {
|
||||
lower := dao.nativeCachePS
|
||||
for id, nativeCache := range dao.nativeCache {
|
||||
lower.nativeCache[id] = nativeCache
|
||||
}
|
||||
dao.nativeCache = nil
|
||||
}
|
||||
|
||||
// GetROCache returns native contact cache. The cache CAN NOT be modified by
|
||||
// the caller. It's the caller's duty to keep it unmodified.
|
||||
func (dao *Simple) GetROCache(id int32) NativeContractCache {
|
||||
if !dao.private {
|
||||
dao.nativeCacheLock.RLock()
|
||||
defer dao.nativeCacheLock.RUnlock()
|
||||
}
|
||||
|
||||
return dao.getCache(id, true)
|
||||
}
|
||||
|
||||
// GetRWCache returns native contact cache. The cache CAN BE safely modified
|
||||
// by the caller.
|
||||
func (dao *Simple) GetRWCache(id int32) NativeContractCache {
|
||||
if !dao.private {
|
||||
dao.nativeCacheLock.Lock()
|
||||
defer dao.nativeCacheLock.Unlock()
|
||||
}
|
||||
|
||||
return dao.getCache(id, false)
|
||||
}
|
||||
|
||||
// getCache is an internal unlocked representation of GetROCache and GetRWCache.
|
||||
func (dao *Simple) getCache(k int32, ro bool) NativeContractCache {
|
||||
if itm, ok := dao.nativeCache[k]; ok {
|
||||
// Don't need to create itm copy, because its value was already copied
|
||||
// the first time it was retrieved from loser ps.
|
||||
return itm
|
||||
}
|
||||
|
||||
if dao.nativeCachePS != nil {
|
||||
if ro {
|
||||
return dao.nativeCachePS.GetROCache(k)
|
||||
}
|
||||
v := dao.nativeCachePS.GetRWCache(k)
|
||||
if v != nil {
|
||||
// Create a copy here in order not to modify the existing cache.
|
||||
cp := v.Copy()
|
||||
dao.nativeCache[k] = cp
|
||||
return cp
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetCache adds native contract cache to the cache map.
|
||||
func (dao *Simple) SetCache(id int32, v NativeContractCache) {
|
||||
dao.nativeCacheLock.Lock()
|
||||
defer dao.nativeCacheLock.Unlock()
|
||||
|
||||
dao.nativeCache[id] = v
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/contract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/iterator"
|
||||
|
@ -533,7 +532,7 @@ func TestStorageFind(t *testing.T) {
|
|||
func createVM(t testing.TB) (*vm.VM, *interop.Context, *Blockchain) {
|
||||
chain := newTestChain(t)
|
||||
context := chain.newInteropContext(trigger.Application,
|
||||
dao.NewSimple(chain.dao.Store, chain.config.StateRootInHeader, chain.config.P2PSigExtensions), nil, nil)
|
||||
chain.dao.GetWrapped(), nil, nil)
|
||||
v := context.SpawnVM()
|
||||
return v, context, chain
|
||||
}
|
||||
|
|
|
@ -80,11 +80,11 @@ var (
|
|||
|
||||
var (
|
||||
_ interop.Contract = (*Designate)(nil)
|
||||
_ storage.NativeContractCache = (*DesignationCache)(nil)
|
||||
_ dao.NativeContractCache = (*DesignationCache)(nil)
|
||||
)
|
||||
|
||||
// Copy implements NativeContractCache interface.
|
||||
func (c *DesignationCache) Copy() storage.NativeContractCache {
|
||||
func (c *DesignationCache) Copy() dao.NativeContractCache {
|
||||
cp := &DesignationCache{}
|
||||
copyDesignationCache(c, cp)
|
||||
return cp
|
||||
|
@ -128,7 +128,7 @@ func newDesignate(p2pSigExtensionsEnabled bool) *Designate {
|
|||
// data in the storage.
|
||||
func (s *Designate) Initialize(ic *interop.Context) error {
|
||||
cache := &DesignationCache{}
|
||||
ic.DAO.Store.SetCache(s.ID, cache)
|
||||
ic.DAO.SetCache(s.ID, cache)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ func (s *Designate) InitializeCache(d *dao.Simple) error {
|
|||
return fmt.Errorf("failed to get nodes from storage for %d role: %w", r, err)
|
||||
}
|
||||
}
|
||||
d.Store.SetCache(s.ID, cache)
|
||||
d.SetCache(s.ID, cache)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -157,7 +157,7 @@ func (s *Designate) OnPersist(ic *interop.Context) error {
|
|||
|
||||
// PostPersist implements Contract interface.
|
||||
func (s *Designate) PostPersist(ic *interop.Context) error {
|
||||
cache := ic.DAO.Store.GetRWCache(s.ID).(*DesignationCache)
|
||||
cache := ic.DAO.GetRWCache(s.ID).(*DesignationCache)
|
||||
if !cache.rolesChangedFlag {
|
||||
return nil
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ func (s *Designate) GetLastDesignatedHash(d *dao.Simple, r noderoles.Role) (util
|
|||
if !s.isValidRole(r) {
|
||||
return util.Uint160{}, ErrInvalidRole
|
||||
}
|
||||
cache := d.Store.GetROCache(s.ID).(*DesignationCache)
|
||||
cache := d.GetROCache(s.ID).(*DesignationCache)
|
||||
if val := getCachedRoleData(cache, r); val != nil {
|
||||
return val.addr, nil
|
||||
}
|
||||
|
@ -285,7 +285,7 @@ func (s *Designate) GetDesignatedByRole(d *dao.Simple, r noderoles.Role, index u
|
|||
if !s.isValidRole(r) {
|
||||
return nil, 0, ErrInvalidRole
|
||||
}
|
||||
cache := d.Store.GetROCache(s.ID).(*DesignationCache)
|
||||
cache := d.GetROCache(s.ID).(*DesignationCache)
|
||||
if val := getCachedRoleData(cache, r); val != nil {
|
||||
if val.height <= index {
|
||||
return val.nodes.Copy(), val.height, nil
|
||||
|
@ -380,7 +380,7 @@ func (s *Designate) DesignateAsRole(ic *interop.Context, r noderoles.Role, pubs
|
|||
return err
|
||||
}
|
||||
|
||||
cache := ic.DAO.Store.GetRWCache(s.ID).(*DesignationCache)
|
||||
cache := ic.DAO.GetRWCache(s.ID).(*DesignationCache)
|
||||
err = s.updateCachedRoleData(cache, ic.DAO, r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update Designation role data cache: %w", err)
|
||||
|
|
|
@ -59,11 +59,11 @@ var (
|
|||
|
||||
var (
|
||||
_ interop.Contract = (*Management)(nil)
|
||||
_ storage.NativeContractCache = (*ManagementCache)(nil)
|
||||
_ dao.NativeContractCache = (*ManagementCache)(nil)
|
||||
)
|
||||
|
||||
// Copy implements NativeContractCache interface.
|
||||
func (c *ManagementCache) Copy() storage.NativeContractCache {
|
||||
func (c *ManagementCache) Copy() dao.NativeContractCache {
|
||||
cp := &ManagementCache{
|
||||
contracts: make(map[util.Uint160]*state.Contract),
|
||||
nep11: make(map[util.Uint160]struct{}),
|
||||
|
@ -170,7 +170,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 := d.GetROCache(m.ID).(*ManagementCache)
|
||||
cs, ok := cache.contracts[hash]
|
||||
if !ok {
|
||||
return nil, storage.ErrKeyNotFound
|
||||
|
@ -272,7 +272,7 @@ func (m *Management) deployWithData(ic *interop.Context, args []stackitem.Item)
|
|||
}
|
||||
|
||||
func (m *Management) markUpdated(d *dao.Simple, hash util.Uint160, cs *state.Contract) {
|
||||
cache := d.Store.GetRWCache(m.ID).(*ManagementCache)
|
||||
cache := d.GetRWCache(m.ID).(*ManagementCache)
|
||||
delete(cache.nep11, hash)
|
||||
delete(cache.nep17, hash)
|
||||
if cs == nil {
|
||||
|
@ -486,7 +486,7 @@ func (m *Management) OnPersist(ic *interop.Context) error {
|
|||
return err
|
||||
}
|
||||
if cache == nil {
|
||||
cache = ic.DAO.Store.GetRWCache(m.ID).(*ManagementCache)
|
||||
cache = ic.DAO.GetRWCache(m.ID).(*ManagementCache)
|
||||
}
|
||||
updateContractCache(cache, cs)
|
||||
}
|
||||
|
@ -517,7 +517,7 @@ func (m *Management) InitializeCache(d *dao.Simple) error {
|
|||
if initErr != nil {
|
||||
return initErr
|
||||
}
|
||||
d.Store.SetCache(m.ID, cache)
|
||||
d.SetCache(m.ID, cache)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -530,7 +530,7 @@ func (m *Management) PostPersist(ic *interop.Context) error {
|
|||
// is updated every PostPersist, so until PostPersist is called, the result for the previous block
|
||||
// is returned.
|
||||
func (m *Management) GetNEP11Contracts(d *dao.Simple) []util.Uint160 {
|
||||
cache := d.Store.GetROCache(m.ID).(*ManagementCache)
|
||||
cache := d.GetROCache(m.ID).(*ManagementCache)
|
||||
result := make([]util.Uint160, 0, len(cache.nep11))
|
||||
for h := range cache.nep11 {
|
||||
result = append(result, h)
|
||||
|
@ -542,7 +542,7 @@ func (m *Management) GetNEP11Contracts(d *dao.Simple) []util.Uint160 {
|
|||
// is updated every PostPersist, so until PostPersist is called, the result for the previous block
|
||||
// is returned.
|
||||
func (m *Management) GetNEP17Contracts(d *dao.Simple) []util.Uint160 {
|
||||
cache := d.Store.GetROCache(m.ID).(*ManagementCache)
|
||||
cache := d.GetROCache(m.ID).(*ManagementCache)
|
||||
result := make([]util.Uint160, 0, len(cache.nep17))
|
||||
for h := range cache.nep17 {
|
||||
result = append(result, h)
|
||||
|
@ -560,7 +560,7 @@ func (m *Management) Initialize(ic *interop.Context) error {
|
|||
nep11: make(map[util.Uint160]struct{}),
|
||||
nep17: make(map[util.Uint160]struct{}),
|
||||
}
|
||||
ic.DAO.Store.SetCache(m.ID, cache)
|
||||
ic.DAO.SetCache(m.ID, cache)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -106,11 +106,11 @@ var (
|
|||
|
||||
var (
|
||||
_ interop.Contract = (*NEO)(nil)
|
||||
_ storage.NativeContractCache = (*NeoCache)(nil)
|
||||
_ dao.NativeContractCache = (*NeoCache)(nil)
|
||||
)
|
||||
|
||||
// Copy implements NativeContractCache interface.
|
||||
func (c *NeoCache) Copy() storage.NativeContractCache {
|
||||
func (c *NeoCache) Copy() dao.NativeContractCache {
|
||||
cp := &NeoCache{}
|
||||
copyNeoCache(c, cp)
|
||||
return cp
|
||||
|
@ -245,7 +245,7 @@ func (n *NEO) Initialize(ic *interop.Context) error {
|
|||
}
|
||||
|
||||
// We need cache to be present in DAO before the subsequent call to `mint`.
|
||||
ic.DAO.Store.SetCache(n.ID, cache)
|
||||
ic.DAO.SetCache(n.ID, cache)
|
||||
|
||||
committee0 := n.standbyKeys[:n.cfg.GetCommitteeSize(ic.Block.Index)]
|
||||
cvs := toKeysWithVotes(committee0)
|
||||
|
@ -297,7 +297,7 @@ func (n *NEO) InitializeCache(bc interop.Ledger, d *dao.Simple) error {
|
|||
cache.gasPerBlock = n.getSortedGASRecordFromDAO(d)
|
||||
cache.registerPrice = getIntWithKey(n.ID, d, []byte{prefixRegisterPrice})
|
||||
|
||||
d.Store.SetCache(n.ID, cache)
|
||||
d.SetCache(n.ID, cache)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -348,7 +348,7 @@ func (n *NEO) updateCommittee(cache *NeoCache, ic *interop.Context) error {
|
|||
// OnPersist implements Contract interface.
|
||||
func (n *NEO) OnPersist(ic *interop.Context) error {
|
||||
if n.cfg.ShouldUpdateCommitteeAt(ic.Block.Index) {
|
||||
cache := ic.DAO.Store.GetRWCache(n.ID).(*NeoCache)
|
||||
cache := ic.DAO.GetRWCache(n.ID).(*NeoCache)
|
||||
oldKeys := cache.nextValidators
|
||||
oldCom := cache.committee
|
||||
if n.cfg.GetNumOfCNs(ic.Block.Index) != len(oldKeys) ||
|
||||
|
@ -365,7 +365,7 @@ func (n *NEO) OnPersist(ic *interop.Context) error {
|
|||
// PostPersist implements Contract interface.
|
||||
func (n *NEO) PostPersist(ic *interop.Context) error {
|
||||
gas := n.GetGASPerBlock(ic.DAO, ic.Block.Index)
|
||||
cache := ic.DAO.Store.GetRWCache(n.ID).(*NeoCache)
|
||||
cache := ic.DAO.GetRWCache(n.ID).(*NeoCache)
|
||||
pubs := getCommitteeMembers(cache)
|
||||
committeeSize := n.cfg.GetCommitteeSize(ic.Block.Index)
|
||||
index := int(ic.Block.Index) % committeeSize
|
||||
|
@ -532,7 +532,7 @@ func (n *NEO) getSortedGASRecordFromDAO(d *dao.Simple) gasRecord {
|
|||
|
||||
// GetGASPerBlock returns gas generated for block with provided index.
|
||||
func (n *NEO) GetGASPerBlock(d *dao.Simple, index uint32) *big.Int {
|
||||
cache := d.Store.GetROCache(n.ID).(*NeoCache)
|
||||
cache := d.GetROCache(n.ID).(*NeoCache)
|
||||
gr := cache.gasPerBlock
|
||||
for i := len(gr) - 1; i >= 0; i-- {
|
||||
if gr[i].Index <= index {
|
||||
|
@ -545,7 +545,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)
|
||||
cache := d.GetROCache(n.ID).(*NeoCache)
|
||||
return cache.committeeHash
|
||||
}
|
||||
|
||||
|
@ -575,7 +575,7 @@ func (n *NEO) SetGASPerBlock(ic *interop.Context, index uint32, gas *big.Int) er
|
|||
return errors.New("invalid committee signature")
|
||||
}
|
||||
n.putGASRecord(ic.DAO, index, gas)
|
||||
cache := ic.DAO.Store.GetRWCache(n.ID).(*NeoCache)
|
||||
cache := ic.DAO.GetRWCache(n.ID).(*NeoCache)
|
||||
cache.gasPerBlock = append(cache.gasPerBlock, gasIndexPair{
|
||||
Index: index,
|
||||
GASPerBlock: *gas,
|
||||
|
@ -588,7 +588,7 @@ 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)
|
||||
cache := d.GetROCache(n.ID).(*NeoCache)
|
||||
return cache.registerPrice
|
||||
}
|
||||
|
||||
|
@ -602,7 +602,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 := ic.DAO.GetRWCache(n.ID).(*NeoCache)
|
||||
cache.registerPrice = price.Int64()
|
||||
return stackitem.Null{}
|
||||
}
|
||||
|
@ -672,7 +672,7 @@ func (n *NEO) CalculateNEOHolderReward(d *dao.Simple, value *big.Int, start, end
|
|||
} else if value.Sign() < 0 {
|
||||
return nil, errors.New("negative value")
|
||||
}
|
||||
cache := d.Store.GetROCache(n.ID).(*NeoCache)
|
||||
cache := d.GetROCache(n.ID).(*NeoCache)
|
||||
gr := cache.gasPerBlock
|
||||
var sum, tmp big.Int
|
||||
for i := len(gr) - 1; i >= 0; i-- {
|
||||
|
@ -743,7 +743,7 @@ func (n *NEO) UnregisterCandidateInternal(ic *interop.Context, pub *keys.PublicK
|
|||
if si == nil {
|
||||
return nil
|
||||
}
|
||||
cache := ic.DAO.Store.GetRWCache(n.ID).(*NeoCache)
|
||||
cache := ic.DAO.GetRWCache(n.ID).(*NeoCache)
|
||||
cache.validators = nil
|
||||
c := new(candidate).FromBytes(si)
|
||||
c.Registered = false
|
||||
|
@ -823,7 +823,7 @@ func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pub *keys.Public
|
|||
// ModifyAccountVotes modifies votes of the specified account by value (can be negative).
|
||||
// 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 := d.GetRWCache(n.ID).(*NeoCache)
|
||||
cache.votesChanged = true
|
||||
if acc.VoteTo != nil {
|
||||
key := makeValidatorKey(acc.VoteTo)
|
||||
|
@ -934,7 +934,7 @@ func (n *NEO) getAccountState(ic *interop.Context, args []stackitem.Item) stacki
|
|||
// ComputeNextBlockValidators returns an actual list of current validators.
|
||||
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)
|
||||
cache := d.GetRWCache(n.ID).(*NeoCache)
|
||||
if vals := cache.validators; vals != nil && numOfCNs == len(vals) {
|
||||
return vals.Copy(), nil
|
||||
}
|
||||
|
@ -969,7 +969,7 @@ func (n *NEO) modifyVoterTurnout(d *dao.Simple, amount *big.Int) error {
|
|||
|
||||
// GetCommitteeMembers returns public keys of nodes in committee using cached value.
|
||||
func (n *NEO) GetCommitteeMembers(d *dao.Simple) keys.PublicKeys {
|
||||
cache := d.Store.GetROCache(n.ID).(*NeoCache)
|
||||
cache := d.GetROCache(n.ID).(*NeoCache)
|
||||
return getCommitteeMembers(cache)
|
||||
}
|
||||
|
||||
|
@ -1049,7 +1049,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)
|
||||
cache := d.GetROCache(n.ID).(*NeoCache)
|
||||
return cache.nextValidators.Copy()
|
||||
}
|
||||
|
||||
|
|
|
@ -54,11 +54,11 @@ var (
|
|||
|
||||
var (
|
||||
_ interop.Contract = (*Notary)(nil)
|
||||
_ storage.NativeContractCache = (*NotaryCache)(nil)
|
||||
_ dao.NativeContractCache = (*NotaryCache)(nil)
|
||||
)
|
||||
|
||||
// Copy implements NativeContractCache interface.
|
||||
func (c *NotaryCache) Copy() storage.NativeContractCache {
|
||||
func (c *NotaryCache) Copy() dao.NativeContractCache {
|
||||
cp := &NotaryCache{}
|
||||
copyNotaryCache(c, cp)
|
||||
return cp
|
||||
|
@ -142,7 +142,7 @@ func (n *Notary) Initialize(ic *interop.Context) error {
|
|||
maxNotValidBeforeDelta: defaultMaxNotValidBeforeDelta,
|
||||
notaryServiceFeePerKey: defaultNotaryServiceFeePerKey,
|
||||
}
|
||||
ic.DAO.Store.SetCache(n.ID, cache)
|
||||
ic.DAO.SetCache(n.ID, cache)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ func (n *Notary) InitializeCache(d *dao.Simple) error {
|
|||
notaryServiceFeePerKey: getIntWithKey(n.ID, d, notaryServiceFeeKey),
|
||||
}
|
||||
|
||||
d.Store.SetCache(n.ID, cache)
|
||||
d.SetCache(n.ID, cache)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -407,7 +407,7 @@ 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 := dao.GetROCache(n.ID).(*NotaryCache)
|
||||
return cache.maxNotValidBeforeDelta
|
||||
}
|
||||
|
||||
|
@ -423,7 +423,7 @@ func (n *Notary) setMaxNotValidBeforeDelta(ic *interop.Context, args []stackitem
|
|||
panic("invalid committee signature")
|
||||
}
|
||||
setIntWithKey(n.ID, ic.DAO, maxNotValidBeforeDeltaKey, int64(value))
|
||||
cache := ic.DAO.Store.GetRWCache(n.ID).(*NotaryCache)
|
||||
cache := ic.DAO.GetRWCache(n.ID).(*NotaryCache)
|
||||
cache.maxNotValidBeforeDelta = value
|
||||
return stackitem.Null{}
|
||||
}
|
||||
|
@ -435,7 +435,7 @@ 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 := dao.GetROCache(n.ID).(*NotaryCache)
|
||||
return cache.notaryServiceFeePerKey
|
||||
}
|
||||
|
||||
|
@ -449,7 +449,7 @@ func (n *Notary) setNotaryServiceFeePerKey(ic *interop.Context, args []stackitem
|
|||
panic("invalid committee signature")
|
||||
}
|
||||
setIntWithKey(n.ID, ic.DAO, notaryServiceFeeKey, int64(value))
|
||||
cache := ic.DAO.Store.GetRWCache(n.ID).(*NotaryCache)
|
||||
cache := ic.DAO.GetRWCache(n.ID).(*NotaryCache)
|
||||
cache.notaryServiceFeePerKey = value
|
||||
return stackitem.Null{}
|
||||
}
|
||||
|
|
|
@ -85,11 +85,11 @@ var (
|
|||
|
||||
var (
|
||||
_ interop.Contract = (*Oracle)(nil)
|
||||
_ storage.NativeContractCache = (*OracleCache)(nil)
|
||||
_ dao.NativeContractCache = (*OracleCache)(nil)
|
||||
)
|
||||
|
||||
// Copy implements NativeContractCache interface.
|
||||
func (c *OracleCache) Copy() storage.NativeContractCache {
|
||||
func (c *OracleCache) Copy() dao.NativeContractCache {
|
||||
cp := &OracleCache{}
|
||||
copyOracleCache(c, cp)
|
||||
return cp
|
||||
|
@ -235,14 +235,14 @@ func (o *Oracle) Initialize(ic *interop.Context) error {
|
|||
cache := &OracleCache{
|
||||
requestPrice: int64(DefaultOracleRequestPrice),
|
||||
}
|
||||
ic.DAO.Store.SetCache(o.ID, cache)
|
||||
ic.DAO.SetCache(o.ID, cache)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Oracle) InitializeCache(d *dao.Simple) {
|
||||
cache := &OracleCache{}
|
||||
cache.requestPrice = getIntWithKey(o.ID, d, prefixRequestPrice)
|
||||
d.Store.SetCache(o.ID, cache)
|
||||
d.SetCache(o.ID, cache)
|
||||
}
|
||||
|
||||
func getResponse(tx *transaction.Transaction) *transaction.OracleResponse {
|
||||
|
@ -459,7 +459,7 @@ 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)
|
||||
cache := d.GetROCache(o.ID).(*OracleCache)
|
||||
return cache.requestPrice
|
||||
}
|
||||
|
||||
|
@ -472,7 +472,7 @@ func (o *Oracle) setPrice(ic *interop.Context, args []stackitem.Item) stackitem.
|
|||
panic("invalid committee signature")
|
||||
}
|
||||
setIntWithKey(o.ID, ic.DAO, prefixRequestPrice, price.Int64())
|
||||
cache := ic.DAO.Store.GetRWCache(o.ID).(*OracleCache)
|
||||
cache := ic.DAO.GetRWCache(o.ID).(*OracleCache)
|
||||
cache.requestPrice = price.Int64()
|
||||
return stackitem.Null{}
|
||||
}
|
||||
|
|
|
@ -64,11 +64,11 @@ type PolicyCache struct {
|
|||
|
||||
var (
|
||||
_ interop.Contract = (*Policy)(nil)
|
||||
_ storage.NativeContractCache = (*PolicyCache)(nil)
|
||||
_ dao.NativeContractCache = (*PolicyCache)(nil)
|
||||
)
|
||||
|
||||
// Copy implements NativeContractCache interface.
|
||||
func (c *PolicyCache) Copy() storage.NativeContractCache {
|
||||
func (c *PolicyCache) Copy() dao.NativeContractCache {
|
||||
cp := &PolicyCache{}
|
||||
copyPolicyCache(c, cp)
|
||||
return cp
|
||||
|
@ -148,7 +148,7 @@ func (p *Policy) Initialize(ic *interop.Context) error {
|
|||
storagePrice: DefaultStoragePrice,
|
||||
blockedAccounts: make([]util.Uint160, 0),
|
||||
}
|
||||
ic.DAO.Store.SetCache(p.ID, cache)
|
||||
ic.DAO.SetCache(p.ID, cache)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ func (p *Policy) InitializeCache(d *dao.Simple) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Store.SetCache(p.ID, cache)
|
||||
d.SetCache(p.ID, cache)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -204,13 +204,13 @@ 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 := dao.GetROCache(p.ID).(*PolicyCache)
|
||||
return cache.feePerByte
|
||||
}
|
||||
|
||||
// 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 := dao.GetROCache(p.ID).(*PolicyCache)
|
||||
return cache.maxVerificationGas
|
||||
}
|
||||
|
||||
|
@ -220,7 +220,7 @@ 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 := d.GetROCache(p.ID).(*PolicyCache)
|
||||
return int64(cache.execFeeFactor)
|
||||
}
|
||||
|
||||
|
@ -233,7 +233,7 @@ func (p *Policy) setExecFeeFactor(ic *interop.Context, args []stackitem.Item) st
|
|||
panic("invalid committee signature")
|
||||
}
|
||||
setIntWithKey(p.ID, ic.DAO, execFeeFactorKey, int64(value))
|
||||
cache := ic.DAO.Store.GetRWCache(p.ID).(*PolicyCache)
|
||||
cache := ic.DAO.GetRWCache(p.ID).(*PolicyCache)
|
||||
cache.execFeeFactor = value
|
||||
return stackitem.Null{}
|
||||
}
|
||||
|
@ -255,7 +255,7 @@ func (p *Policy) IsBlocked(dao *dao.Simple, hash util.Uint160) bool {
|
|||
// of the blocked account in the blocked accounts list (or the position it should be
|
||||
// put at).
|
||||
func (p *Policy) isBlockedInternal(dao *dao.Simple, hash util.Uint160) (int, bool) {
|
||||
cache := dao.Store.GetROCache(p.ID).(*PolicyCache)
|
||||
cache := dao.GetROCache(p.ID).(*PolicyCache)
|
||||
length := len(cache.blockedAccounts)
|
||||
i := sort.Search(length, func(i int) bool {
|
||||
return !cache.blockedAccounts[i].Less(hash)
|
||||
|
@ -272,7 +272,7 @@ 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 := d.GetROCache(p.ID).(*PolicyCache)
|
||||
return int64(cache.storagePrice)
|
||||
}
|
||||
|
||||
|
@ -285,7 +285,7 @@ func (p *Policy) setStoragePrice(ic *interop.Context, args []stackitem.Item) sta
|
|||
panic("invalid committee signature")
|
||||
}
|
||||
setIntWithKey(p.ID, ic.DAO, storagePriceKey, int64(value))
|
||||
cache := ic.DAO.Store.GetRWCache(p.ID).(*PolicyCache)
|
||||
cache := ic.DAO.GetRWCache(p.ID).(*PolicyCache)
|
||||
cache.storagePrice = value
|
||||
return stackitem.Null{}
|
||||
}
|
||||
|
@ -300,7 +300,7 @@ func (p *Policy) setFeePerByte(ic *interop.Context, args []stackitem.Item) stack
|
|||
panic("invalid committee signature")
|
||||
}
|
||||
setIntWithKey(p.ID, ic.DAO, feePerByteKey, value)
|
||||
cache := ic.DAO.Store.GetRWCache(p.ID).(*PolicyCache)
|
||||
cache := ic.DAO.GetRWCache(p.ID).(*PolicyCache)
|
||||
cache.feePerByte = value
|
||||
return stackitem.Null{}
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ func (p *Policy) blockAccount(ic *interop.Context, args []stackitem.Item) stacki
|
|||
}
|
||||
key := append([]byte{blockedAccountPrefix}, hash.BytesBE()...)
|
||||
ic.DAO.PutStorageItem(p.ID, key, state.StorageItem{})
|
||||
cache := ic.DAO.Store.GetRWCache(p.ID).(*PolicyCache)
|
||||
cache := ic.DAO.GetRWCache(p.ID).(*PolicyCache)
|
||||
if len(cache.blockedAccounts) == i {
|
||||
cache.blockedAccounts = append(cache.blockedAccounts, hash)
|
||||
} else {
|
||||
|
@ -346,7 +346,7 @@ func (p *Policy) unblockAccount(ic *interop.Context, args []stackitem.Item) stac
|
|||
}
|
||||
key := append([]byte{blockedAccountPrefix}, hash.BytesBE()...)
|
||||
ic.DAO.DeleteStorageItem(p.ID, key)
|
||||
cache := ic.DAO.Store.GetRWCache(p.ID).(*PolicyCache)
|
||||
cache := ic.DAO.GetRWCache(p.ID).(*PolicyCache)
|
||||
cache.blockedAccounts = append(cache.blockedAccounts[:i], cache.blockedAccounts[i+1:]...)
|
||||
return stackitem.NewBool(true)
|
||||
}
|
||||
|
|
|
@ -15,9 +15,6 @@ import (
|
|||
type MemCachedStore struct {
|
||||
MemoryStore
|
||||
|
||||
nativeCacheLock sync.RWMutex
|
||||
nativeCache map[int32]NativeContractCache
|
||||
|
||||
private bool
|
||||
// plock protects Persist from double entrance.
|
||||
plock sync.Mutex
|
||||
|
@ -25,15 +22,6 @@ type MemCachedStore struct {
|
|||
ps Store
|
||||
}
|
||||
|
||||
// NativeContractCache is an interface representing cache for a native contract.
|
||||
// Cache can be copied to create a wrapper around current DAO layer. Wrapped cache
|
||||
// can be persisted to the underlying DAO native cache.
|
||||
type NativeContractCache interface {
|
||||
// Copy returns a copy of native cache item that can safely be changed within
|
||||
// the subsequent DAO operations.
|
||||
Copy() NativeContractCache
|
||||
}
|
||||
|
||||
type (
|
||||
// KeyValue represents key-value pair.
|
||||
KeyValue struct {
|
||||
|
@ -58,12 +46,8 @@ type (
|
|||
|
||||
// NewMemCachedStore creates a new MemCachedStore object.
|
||||
func NewMemCachedStore(lower Store) *MemCachedStore {
|
||||
// Do not copy cache from ps; instead should create clear map: GetRWCache and
|
||||
// GetROCache will retrieve cache from the underlying nativeCache if requested.
|
||||
cache := make(map[int32]NativeContractCache)
|
||||
return &MemCachedStore{
|
||||
MemoryStore: *NewMemoryStore(),
|
||||
nativeCache: cache,
|
||||
ps: lower,
|
||||
}
|
||||
}
|
||||
|
@ -71,14 +55,8 @@ func NewMemCachedStore(lower Store) *MemCachedStore {
|
|||
// NewPrivateMemCachedStore creates a new private (unlocked) MemCachedStore object.
|
||||
// Private cached stores are closed after Persist.
|
||||
func NewPrivateMemCachedStore(lower Store) *MemCachedStore {
|
||||
// Do not copy cache from ps; instead should create clear map: GetRWCache and
|
||||
// GetROCache will retrieve cache from the underlying nativeCache if requested.
|
||||
// The lowest underlying store MUST have its native cache initialized, otherwise
|
||||
// GetROCache and GetRWCache won't work properly.
|
||||
cache := make(map[int32]NativeContractCache)
|
||||
return &MemCachedStore{
|
||||
MemoryStore: *NewMemoryStore(),
|
||||
nativeCache: cache,
|
||||
private: true,
|
||||
ps: lower,
|
||||
}
|
||||
|
@ -363,23 +341,15 @@ func (s *MemCachedStore) persist(isSync bool) (int, error) {
|
|||
}
|
||||
s.mem = nil
|
||||
s.stor = nil
|
||||
if cached, ok := s.ps.(*MemCachedStore); ok {
|
||||
for id, nativeCache := range s.nativeCache {
|
||||
cached.nativeCache[id] = nativeCache
|
||||
}
|
||||
s.nativeCache = nil
|
||||
}
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
s.plock.Lock()
|
||||
defer s.plock.Unlock()
|
||||
s.mut.Lock()
|
||||
s.nativeCacheLock.Lock()
|
||||
|
||||
keys = len(s.mem) + len(s.stor)
|
||||
if keys == 0 {
|
||||
s.nativeCacheLock.Unlock()
|
||||
s.mut.Unlock()
|
||||
return 0, nil
|
||||
}
|
||||
|
@ -388,30 +358,17 @@ func (s *MemCachedStore) persist(isSync bool) (int, error) {
|
|||
// starts using fresh new maps. This tempstore is only known here and
|
||||
// nothing ever changes it, therefore accesses to it (reads) can go
|
||||
// unprotected while writes are handled by s proper.
|
||||
var tempstore = &MemCachedStore{MemoryStore: MemoryStore{mem: s.mem, stor: s.stor}, ps: s.ps, nativeCache: s.nativeCache}
|
||||
var tempstore = &MemCachedStore{MemoryStore: MemoryStore{mem: s.mem, stor: s.stor}, ps: s.ps}
|
||||
s.ps = tempstore
|
||||
s.mem = make(map[string][]byte, len(s.mem))
|
||||
s.stor = make(map[string][]byte, len(s.stor))
|
||||
cached, isPSCached := tempstore.ps.(*MemCachedStore)
|
||||
if isPSCached {
|
||||
s.nativeCache = make(map[int32]NativeContractCache)
|
||||
}
|
||||
if !isSync {
|
||||
s.nativeCacheLock.Unlock()
|
||||
s.mut.Unlock()
|
||||
}
|
||||
if isPSCached {
|
||||
cached.nativeCacheLock.Lock()
|
||||
for id, nativeCache := range tempstore.nativeCache {
|
||||
cached.nativeCache[id] = nativeCache
|
||||
}
|
||||
cached.nativeCacheLock.Unlock()
|
||||
}
|
||||
err = tempstore.ps.PutChangeSet(tempstore.mem, tempstore.stor)
|
||||
|
||||
if !isSync {
|
||||
s.mut.Lock()
|
||||
s.nativeCacheLock.Lock()
|
||||
}
|
||||
if err == nil {
|
||||
// tempstore.mem and tempstore.del are completely flushed now
|
||||
|
@ -427,69 +384,14 @@ func (s *MemCachedStore) persist(isSync bool) (int, error) {
|
|||
for k := range s.stor {
|
||||
put(tempstore.stor, k, s.stor[k])
|
||||
}
|
||||
if isPSCached {
|
||||
for id, nativeCache := range s.nativeCache {
|
||||
tempstore.nativeCache[id] = nativeCache
|
||||
}
|
||||
s.nativeCache = tempstore.nativeCache
|
||||
}
|
||||
s.ps = tempstore.ps
|
||||
s.mem = tempstore.mem
|
||||
s.stor = tempstore.stor
|
||||
}
|
||||
s.nativeCacheLock.Unlock()
|
||||
s.mut.Unlock()
|
||||
return keys, err
|
||||
}
|
||||
|
||||
// GetROCache returns native contact cache. The cache CAN NOT be modified by
|
||||
// the caller. It's the caller's duty to keep it unmodified.
|
||||
func (s *MemCachedStore) GetROCache(id int32) NativeContractCache {
|
||||
s.nativeCacheLock.RLock()
|
||||
defer s.nativeCacheLock.RUnlock()
|
||||
|
||||
return s.getCache(id, true)
|
||||
}
|
||||
|
||||
// GetRWCache returns native contact cache. The cache CAN BE safely modified
|
||||
// by the caller.
|
||||
func (s *MemCachedStore) GetRWCache(k int32) NativeContractCache {
|
||||
s.nativeCacheLock.Lock()
|
||||
defer s.nativeCacheLock.Unlock()
|
||||
|
||||
return s.getCache(k, false)
|
||||
}
|
||||
|
||||
func (s *MemCachedStore) getCache(k int32, ro bool) NativeContractCache {
|
||||
if itm, ok := s.nativeCache[k]; ok {
|
||||
// Don't need to create itm copy, because its value was already copied
|
||||
// the first time it was retrieved from loser ps.
|
||||
return itm
|
||||
}
|
||||
|
||||
if cached, ok := s.ps.(*MemCachedStore); ok {
|
||||
if ro {
|
||||
return cached.GetROCache(k)
|
||||
}
|
||||
v := cached.GetRWCache(k)
|
||||
if v != nil {
|
||||
// Create a copy here in order not to modify the existing cache.
|
||||
cp := v.Copy()
|
||||
s.nativeCache[k] = cp
|
||||
return cp
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *MemCachedStore) SetCache(k int32, v NativeContractCache) {
|
||||
s.nativeCacheLock.Lock()
|
||||
defer s.nativeCacheLock.Unlock()
|
||||
|
||||
s.nativeCache[k] = v
|
||||
}
|
||||
|
||||
// Close implements Store interface, clears up memory and closes the lower layer
|
||||
// Store.
|
||||
func (s *MemCachedStore) Close() error {
|
||||
|
|
Loading…
Reference in a new issue