mpt: do not allocate new buffer when updating dirty node

Running time becomes faster under high load while staying the same in
the average case.
Memory allocation done in `Trie` goes down by about ~10% (even more,
actually).
This commit is contained in:
Evgenii Stratonikov 2020-12-24 14:19:10 +03:00
parent 9fcee12276
commit 168ba7960c
3 changed files with 15 additions and 10 deletions

View file

@ -63,7 +63,7 @@ func (b *BaseNode) updateHash(n Node) {
// updateCache updates hash and bytes fields for this BaseNode. // updateCache updates hash and bytes fields for this BaseNode.
func (b *BaseNode) updateBytes(n Node) { func (b *BaseNode) updateBytes(n Node) {
buf := io.NewBufBinWriter() buf := io.NewBufBinWriterPreAlloc(b.bytes)
encodeNodeWithType(n, buf.BinWriter) encodeNodeWithType(n, buf.BinWriter)
b.bytes = buf.Bytes() b.bytes = buf.Bytes()
b.bytesValid = true b.bytesValid = true

View file

@ -418,31 +418,29 @@ func (t *Trie) updateRefCount(h util.Uint256) int32 {
func (t *Trie) addRef(h util.Uint256, bs []byte) { func (t *Trie) addRef(h util.Uint256, bs []byte) {
node := t.refcount[h] node := t.refcount[h]
if node == nil { if node == nil {
data := make([]byte, len(bs))
copy(data, bs)
t.refcount[h] = &cachedNode{ t.refcount[h] = &cachedNode{
refcount: 1, refcount: 1,
bytes: bs, bytes: data,
} }
return return
} }
node.refcount++ node.refcount++
if node.bytes == nil {
node.bytes = bs
}
} }
func (t *Trie) removeRef(h util.Uint256, bs []byte) { func (t *Trie) removeRef(h util.Uint256, bs []byte) {
node := t.refcount[h] node := t.refcount[h]
if node == nil { if node == nil {
data := make([]byte, len(bs))
copy(data, bs)
t.refcount[h] = &cachedNode{ t.refcount[h] = &cachedNode{
refcount: -1, refcount: -1,
bytes: bs, bytes: data,
} }
return return
} }
node.refcount-- node.refcount--
if node.bytes == nil {
node.bytes = bs
}
} }
func (t *Trie) getFromStore(h util.Uint256) (Node, error) { func (t *Trie) getFromStore(h util.Uint256) (Node, error) {
@ -462,7 +460,8 @@ func (t *Trie) getFromStore(h util.Uint256) (Node, error) {
data = data[:len(data)-4] data = data[:len(data)-4]
node := t.refcount[h] node := t.refcount[h]
if node != nil { if node != nil {
node.bytes = data node.bytes = make([]byte, len(data))
copy(node.bytes, data)
node.initial = int32(r.ReadU32LE()) node.initial = int32(r.ReadU32LE())
} }
} }

View file

@ -19,6 +19,12 @@ func NewBufBinWriter() *BufBinWriter {
return &BufBinWriter{BinWriter: NewBinWriterFromIO(b), buf: b} return &BufBinWriter{BinWriter: NewBinWriterFromIO(b), buf: b}
} }
// NewBufBinWriterPreAlloc makes a BufBinWriter using preallocated buffer.
func NewBufBinWriterPreAlloc(buf []byte) *BufBinWriter {
b := bytes.NewBuffer(buf[:0])
return &BufBinWriter{BinWriter: NewBinWriterFromIO(b), buf: b}
}
// Len returns the number of bytes of the unread portion of the buffer. // Len returns the number of bytes of the unread portion of the buffer.
func (bw *BufBinWriter) Len() int { func (bw *BufBinWriter) Len() int {
return bw.buf.Len() return bw.buf.Len()