[NOD-873] Reuse allocated space when updating the UTXO set in database (#688)

This commit is contained in:
Ori Newman 2020-04-05 11:46:16 +03:00 committed by GitHub
parent 956b6f7d95
commit bfbc72724d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 12 additions and 71 deletions

View File

@ -10,7 +10,6 @@ import (
"encoding/json"
"fmt"
"io"
"sync"
"github.com/kaspanet/kaspad/dagconfig"
"github.com/kaspanet/kaspad/dbaccess"
@ -18,7 +17,6 @@ import (
"github.com/kaspanet/kaspad/util"
"github.com/kaspanet/kaspad/util/binaryserializer"
"github.com/kaspanet/kaspad/util/buffers"
"github.com/kaspanet/kaspad/util/daghash"
"github.com/kaspanet/kaspad/util/subnetworkid"
"github.com/kaspanet/kaspad/wire"
@ -46,14 +44,6 @@ func isNotInDAGErr(err error) bool {
return errors.As(err, &notInDAGErr)
}
// outpointKeyPool defines a concurrent safe free list of byte buffers used to
// provide temporary buffers for outpoint database keys.
var outpointKeyPool = sync.Pool{
New: func() interface{} {
return &bytes.Buffer{} // Pointer to a buffer to avoid boxing alloc.
},
}
// outpointIndexByteOrder is the byte order for serializing the outpoint index.
// It uses big endian to ensure that when outpoint is used as database key, the
// keys will be iterated in an ascending order by the outpoint index.
@ -91,42 +81,41 @@ func deserializeOutpoint(r io.Reader) (*wire.Outpoint, error) {
// updateUTXOSet updates the UTXO set in the database based on the provided
// UTXO diff.
func updateUTXOSet(dbContext dbaccess.Context, virtualUTXODiff *UTXODiff) error {
outpointBuff := bytes.NewBuffer(make([]byte, outpointSerializeSize))
for outpoint := range virtualUTXODiff.toRemove {
w := outpointKeyPool.Get().(*bytes.Buffer)
w.Reset()
err := serializeOutpoint(w, &outpoint)
outpointBuff.Reset()
err := serializeOutpoint(outpointBuff, &outpoint)
if err != nil {
return err
}
key := w.Bytes()
key := outpointBuff.Bytes()
err = dbaccess.RemoveFromUTXOSet(dbContext, key)
if err != nil {
return err
}
outpointKeyPool.Put(w)
}
// We are preallocating for P2PKH entries because they are the most common ones.
// If we have entries with a compressed script bigger than P2PKH's, the buffer will grow.
bytesToPreallocate := (p2pkhUTXOEntrySerializeSize + outpointSerializeSize) * len(virtualUTXODiff.toAdd)
buff := bytes.NewBuffer(make([]byte, bytesToPreallocate))
utxoEntryBuff := bytes.NewBuffer(make([]byte, p2pkhUTXOEntrySerializeSize))
for outpoint, entry := range virtualUTXODiff.toAdd {
utxoEntryBuff.Reset()
outpointBuff.Reset()
// Serialize and store the UTXO entry.
sBuff := buffers.NewSubBuffer(buff)
err := serializeUTXOEntry(sBuff, entry)
err := serializeUTXOEntry(utxoEntryBuff, entry)
if err != nil {
return err
}
serializedEntry := sBuff.Bytes()
serializedEntry := utxoEntryBuff.Bytes()
sBuff = buffers.NewSubBuffer(buff)
err = serializeOutpoint(sBuff, &outpoint)
err = serializeOutpoint(outpointBuff, &outpoint)
if err != nil {
return err
}
key := sBuff.Bytes()
key := outpointBuff.Bytes()
err = dbaccess.AddToUTXOSet(dbContext, key, serializedEntry)
if err != nil {
return err

View File

@ -1,48 +0,0 @@
package buffers
import (
"bytes"
"github.com/pkg/errors"
)
// SubBuffer lets you write to an existing buffer
// and let you check with the `Bytes()` method what
// has been written to the underlying buffer using
// the sub buffer.
type SubBuffer struct {
buff *bytes.Buffer
start, end int
}
// Bytes returns all the bytes that were written to the sub buffer.
func (s *SubBuffer) Bytes() []byte {
return s.buff.Bytes()[s.start:s.end]
}
// Write writes to the sub buffer's underlying buffer
// and increases s.end by the number of bytes written
// so s.Bytes() will be able to return the written bytes.
func (s *SubBuffer) Write(p []byte) (int, error) {
if s.buff.Len() > s.end || s.buff.Len() < s.start {
return 0, errors.New("a sub buffer cannot be written after another entity wrote or read from its " +
"underlying buffer")
}
n, err := s.buff.Write(p)
if err != nil {
return 0, err
}
s.end += n
return n, nil
}
// NewSubBuffer returns a new sub buffer.
func NewSubBuffer(buff *bytes.Buffer) *SubBuffer {
return &SubBuffer{
buff: buff,
start: buff.Len(),
end: buff.Len(),
}
}