From 607b838deddeab29501abb56167eee8bea41fe85 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Tue, 28 Jan 2020 12:24:09 +0200 Subject: [PATCH] [NOD-702] Fix netsync slowing down significantly due to excessive allocs in serializeUTXO (#605) * [NOD-702] Fix netsync slowing down significantly due to excessive allocs in serializeUTXO. * [NOD-702] Fix bad make statement. * [NOD-702] Move writeBuffer to flushToDB. --- blockdag/utxodiffstore.go | 22 +++++++++++++++++++--- blockdag/utxoio.go | 11 +++++------ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/blockdag/utxodiffstore.go b/blockdag/utxodiffstore.go index 6162a91a7..ec7c2ac87 100644 --- a/blockdag/utxodiffstore.go +++ b/blockdag/utxodiffstore.go @@ -1,6 +1,7 @@ package blockdag import ( + "bytes" "github.com/kaspanet/kaspad/database" "github.com/kaspanet/kaspad/util/daghash" "github.com/kaspanet/kaspad/util/locks" @@ -161,9 +162,13 @@ func (diffStore *utxoDiffStore) flushToDB(dbTx database.Tx) error { return nil } + // Allocate a buffer here to avoid needless allocations/grows + // while writing each entry. + buffer := &bytes.Buffer{} for hash := range diffStore.dirty { + buffer.Reset() diffData := diffStore.loaded[hash] - err := dbStoreDiffData(dbTx, &hash, diffData) + err := dbStoreDiffData(dbTx, buffer, &hash, diffData) if err != nil { return err } @@ -177,12 +182,23 @@ func (diffStore *utxoDiffStore) clearDirtyEntries() { // dbStoreDiffData stores the UTXO diff data to the database. // This overwrites the current entry if there exists one. -func dbStoreDiffData(dbTx database.Tx, hash *daghash.Hash, diffData *blockUTXODiffData) error { - serializedDiffData, err := serializeBlockUTXODiffData(diffData) +func dbStoreDiffData(dbTx database.Tx, writeBuffer *bytes.Buffer, hash *daghash.Hash, diffData *blockUTXODiffData) error { + // To avoid a ton of allocs, use the given writeBuffer + // instead of allocating one. We expect the buffer to + // already be initalized and, in most cases, to already + // be large enough to accommodate the serialized data + // without growing. + err := serializeBlockUTXODiffData(writeBuffer, diffData) if err != nil { return err } + // Bucket.Put doesn't copy on its own, so we manually + // copy here. We do so because we expect the buffer + // to be reused once we're done with it. + serializedDiffData := make([]byte, writeBuffer.Len()) + copy(serializedDiffData, writeBuffer.Bytes()) + return dbTx.Metadata().Bucket(utxoDiffsBucketName).Put(hash[:], serializedDiffData) } diff --git a/blockdag/utxoio.go b/blockdag/utxoio.go index 7e62c23e5..753f3af3f 100644 --- a/blockdag/utxoio.go +++ b/blockdag/utxoio.go @@ -19,26 +19,25 @@ import ( // hasDiffChild | Boolean | Indicates if a diff child exist // diffChild | Hash | The diffChild's hash. Empty if hasDiffChild is true. // diff | UTXODiff | The diff data's diff -func serializeBlockUTXODiffData(diffData *blockUTXODiffData) ([]byte, error) { - w := &bytes.Buffer{} +func serializeBlockUTXODiffData(w io.Writer, diffData *blockUTXODiffData) error { hasDiffChild := diffData.diffChild != nil err := wire.WriteElement(w, hasDiffChild) if err != nil { - return nil, err + return err } if hasDiffChild { err := wire.WriteElement(w, diffData.diffChild.hash) if err != nil { - return nil, err + return err } } err = serializeUTXODiff(w, diffData.diff) if err != nil { - return nil, err + return err } - return w.Bytes(), nil + return nil } // utxoEntryHeaderCode returns the calculated header code to be used when