multi: add buffer.Write and pool.WriteBuffer, make GCQueue generic

This commit is contained in:
Conner Fromknecht
2019-02-15 19:31:24 -08:00
parent ca4226d429
commit 6f96d04b72
12 changed files with 414 additions and 200 deletions

44
buffer/buffer_test.go Normal file
View File

@@ -0,0 +1,44 @@
package buffer_test
import (
"bytes"
"testing"
"github.com/lightningnetwork/lnd/buffer"
)
// TestRecycleSlice asserts that RecycleSlice always zeros a byte slice.
func TestRecycleSlice(t *testing.T) {
tests := []struct {
name string
slice []byte
}{
{
name: "length zero",
},
{
name: "length one",
slice: []byte("a"),
},
{
name: "length power of two length",
slice: bytes.Repeat([]byte("b"), 16),
},
{
name: "length non power of two",
slice: bytes.Repeat([]byte("c"), 27),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
buffer.RecycleSlice(test.slice)
expSlice := make([]byte, len(test.slice))
if !bytes.Equal(expSlice, test.slice) {
t.Fatalf("slice not recycled, want: %v, got: %v",
expSlice, test.slice)
}
})
}
}

17
buffer/utils.go Normal file
View File

@@ -0,0 +1,17 @@
package buffer
// RecycleSlice zeroes byte slice, making it fresh for another use.
// Zeroing the buffer using a logarithmic number of calls to the optimized copy
// method. Benchmarking shows this to be ~30 times faster than a for loop that
// sets each index to 0 for ~65KB buffers use for wire messages. Inspired by:
// https://stackoverflow.com/questions/30614165/is-there-analog-of-memset-in-go
func RecycleSlice(b []byte) {
if len(b) == 0 {
return
}
b[0] = 0
for i := 1; i < len(b); i *= 2 {
copy(b[i:], b[:i])
}
}

19
buffer/write.go Normal file
View File

@@ -0,0 +1,19 @@
package buffer
import (
"github.com/lightningnetwork/lnd/lnwire"
)
// WriteSize represents the size of the maximum plaintext message than can be
// sent using brontide. The buffer does not include extra space for the MAC, as
// that is applied by the Noise protocol after encrypting the plaintext.
const WriteSize = lnwire.MaxMessagePayload
// Write is static byte array occupying to maximum-allowed plaintext-message
// size.
type Write [WriteSize]byte
// Recycle zeroes the Write, making it fresh for another use.
func (b *Write) Recycle() {
RecycleSlice(b[:])
}