From c992d6c5187f01a75a8556ac16550049612212af Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Tue, 17 Mar 2020 12:06:46 +0300 Subject: [PATCH] core: reuse buffer in (*cacheddao).Persist() When serializing multiple accounts, cost of a buffer grow can become significant. This commit tries to amortize it by reusing the same buffer in a single `Persist()` call. --- pkg/core/cacheddao.go | 12 +++++++++--- pkg/core/dao.go | 26 +++++++++++++++++++++----- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/pkg/core/cacheddao.go b/pkg/core/cacheddao.go index 0094c31fb..121de9435 100644 --- a/pkg/core/cacheddao.go +++ b/pkg/core/cacheddao.go @@ -3,6 +3,7 @@ package core import ( "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/storage" + "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/util" ) @@ -138,23 +139,28 @@ func (cd *cachedDao) AppendNEP5Transfer(acc util.Uint160, index uint32, tr *stat // Persist flushes all the changes made into the (supposedly) persistent // underlying store. func (cd *cachedDao) Persist() (int, error) { + buf := io.NewBufBinWriter() + for sc := range cd.accounts { - err := cd.dao.PutAccountState(cd.accounts[sc]) + err := cd.dao.putAccountState(cd.accounts[sc], buf) if err != nil { return 0, err } + buf.Reset() } for hash := range cd.unspents { - err := cd.dao.PutUnspentCoinState(hash, cd.unspents[hash]) + err := cd.dao.putUnspentCoinState(hash, cd.unspents[hash], buf) if err != nil { return 0, err } + buf.Reset() } for acc, bs := range cd.balances { - err := cd.dao.PutNEP5Balances(acc, bs) + err := cd.dao.putNEP5Balances(acc, bs, buf) if err != nil { return 0, err } + buf.Reset() } for acc, ts := range cd.transfers { for ind, lg := range ts { diff --git a/pkg/core/dao.go b/pkg/core/dao.go index 7ad2a65d8..d574c049f 100644 --- a/pkg/core/dao.go +++ b/pkg/core/dao.go @@ -37,7 +37,11 @@ func (dao *dao) GetAndDecode(entity io.Serializable, key []byte) error { // Put performs put operation with serializable structures. func (dao *dao) Put(entity io.Serializable, key []byte) error { - buf := io.NewBufBinWriter() + return dao.putWithBuffer(entity, key, io.NewBufBinWriter()) +} + +// putWithBuffer performs put operation using buf as a pre-allocated buffer for serialization. +func (dao *dao) putWithBuffer(entity io.Serializable, key []byte, buf *io.BufBinWriter) error { entity.EncodeBinary(buf.BinWriter) if buf.Err != nil { return buf.Err @@ -73,8 +77,12 @@ func (dao *dao) GetAccountState(hash util.Uint160) (*state.Account, error) { } func (dao *dao) PutAccountState(as *state.Account) error { + return dao.putAccountState(as, io.NewBufBinWriter()) +} + +func (dao *dao) putAccountState(as *state.Account, buf *io.BufBinWriter) error { key := storage.AppendPrefix(storage.STAccount, as.ScriptHash.BytesBE()) - return dao.Put(as, key) + return dao.putWithBuffer(as, key, buf) } // -- end accounts. @@ -148,10 +156,14 @@ func (dao *dao) GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error) { return bs, nil } -// GetNEP5Balances saves nep5 balances from the cache. +// PutNEP5Balances saves nep5 balances from the cache. func (dao *dao) PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error { + return dao.putNEP5Balances(acc, bs, io.NewBufBinWriter()) +} + +func (dao *dao) putNEP5Balances(acc util.Uint160, bs *state.NEP5Balances, buf *io.BufBinWriter) error { key := storage.AppendPrefix(storage.STNEP5Balances, acc.BytesBE()) - return dao.Put(bs, key) + return dao.putWithBuffer(bs, key, buf) } // -- end nep5 balances. @@ -220,8 +232,12 @@ func (dao *dao) GetUnspentCoinState(hash util.Uint256) (*state.UnspentCoin, erro // PutUnspentCoinState puts given UnspentCoinState into the given store. func (dao *dao) PutUnspentCoinState(hash util.Uint256, ucs *state.UnspentCoin) error { + return dao.putUnspentCoinState(hash, ucs, io.NewBufBinWriter()) +} + +func (dao *dao) putUnspentCoinState(hash util.Uint256, ucs *state.UnspentCoin, buf *io.BufBinWriter) error { key := storage.AppendPrefix(storage.STCoin, hash.BytesLE()) - return dao.Put(ucs, key) + return dao.putWithBuffer(ucs, key, buf) } // -- end unspent coins.