diff --git a/lnpeer/write_buffer_pool.go b/lnpeer/write_buffer_pool.go new file mode 100644 index 00000000..ec266ed9 --- /dev/null +++ b/lnpeer/write_buffer_pool.go @@ -0,0 +1,79 @@ +package lnpeer + +import ( + "time" + + "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/queue" +) + +const ( + // DefaultGCInterval is the default interval that the WriteBufferPool + // will perform a sweep to see which expired buffers can be released to + // the runtime. + DefaultGCInterval = 15 * time.Second + + // DefaultExpiryInterval is the default, minimum interval that must + // elapse before a WriteBuffer will be released. The maximum time before + // the buffer can be released is equal to the expiry interval plus the + // gc interval. + DefaultExpiryInterval = 30 * time.Second +) + +// WriteBuffer is static byte array occupying to maximum-allowed +// plaintext-message size. +type WriteBuffer [lnwire.MaxMessagePayload]byte + +// Recycle zeroes the WriteBuffer, 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 this buffer size. Inspired by: +// https://stackoverflow.com/questions/30614165/is-there-analog-of-memset-in-go +// +// This is part of the queue.Recycler interface. +func (b *WriteBuffer) Recycle() { + b[0] = 0 + for i := 1; i < lnwire.MaxMessagePayload; i *= 2 { + copy(b[i:], b[:i]) + } +} + +// newRecyclableWriteBuffer is a constructor that returns a WriteBuffer typed as +// a queue.Recycler. +func newRecyclableWriteBuffer() queue.Recycler { + return new(WriteBuffer) +} + +// A compile-time constraint to ensure that *WriteBuffer implements the +// queue.Recycler interface. +var _ queue.Recycler = (*WriteBuffer)(nil) + +// WriteBufferPool acts a global pool of WriteBuffers, that dynamically +// allocates and reclaims buffers in response to load. +type WriteBufferPool struct { + pool *queue.GCQueue +} + +// NewWriteBufferPool returns a freshly instantiated WriteBufferPool, using the +// given gcInterval and expiryIntervals. +func NewWriteBufferPool( + gcInterval, expiryInterval time.Duration) *WriteBufferPool { + + return &WriteBufferPool{ + pool: queue.NewGCQueue( + newRecyclableWriteBuffer, 100, + gcInterval, expiryInterval, + ), + } +} + +// Take returns a fresh WriteBuffer to the caller. +func (p *WriteBufferPool) Take() *WriteBuffer { + return p.pool.Take().(*WriteBuffer) +} + +// Return returns the WriteBuffer to the pool, so that it can be recycled or +// released. +func (p *WriteBufferPool) Return(buf *WriteBuffer) { + p.pool.Return(buf) +}