mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
[NOD-873] Reuse allocated space when updating the UTXO set in database (#688)
This commit is contained in:
parent
956b6f7d95
commit
bfbc72724d
@ -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, ¬InDAGErr)
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user