package pool import ( "bytes" "time" "github.com/lightningnetwork/lnd/buffer" ) // Write is a worker pool specifically designed for sharing access to // buffer.Write objects amongst a set of worker goroutines. This enables an // application to limit the total number of buffer.Write objects allocated at // any given time. type Write struct { workerPool *Worker bufferPool *WriteBuffer } // NewWrite creates a Write pool, using an underlying Writebuffer pool to // recycle buffer.Write objects across the lifetime of the Write pool's // workers. func NewWrite(writeBufferPool *WriteBuffer, numWorkers int, workerTimeout time.Duration) *Write { w := &Write{ bufferPool: writeBufferPool, } w.workerPool = NewWorker(&WorkerConfig{ NewWorkerState: w.newWorkerState, NumWorkers: numWorkers, WorkerTimeout: workerTimeout, }) return w } // Start safely spins up the Write pool. func (w *Write) Start() error { return w.workerPool.Start() } // Stop safely shuts down the Write pool. func (w *Write) Stop() error { return w.workerPool.Stop() } // Submit accepts a function closure that provides access to a fresh // bytes.Buffer backed by a buffer.Write object. The function's execution will // be allocated to one of the underlying Worker pool's goroutines. func (w *Write) Submit(inner func(*bytes.Buffer) error) error { return w.workerPool.Submit(func(s WorkerState) error { state := s.(*writeWorkerState) return inner(state.buf) }) } // writeWorkerState is the per-goroutine state maintained by a Write pool's // goroutines. type writeWorkerState struct { // bufferPool is the pool to which the writeBuf will be returned when // the goroutine exits. bufferPool *WriteBuffer // writeBuf is the buffer taken from the bufferPool on initialization, // which will be used to back the buf object provided to any tasks that // the goroutine processes before exiting. writeBuf *buffer.Write // buf is a buffer backed by writeBuf, that can be written to by tasks // submitted to the Write pool. The buf will be reset between each task // processed by a goroutine before exiting, and allows the task // submitters to interact with the writeBuf as if it were an io.Writer. buf *bytes.Buffer } // newWorkerState initializes a new writeWorkerState, which will be called // whenever a new goroutine is allocated to begin processing write tasks. func (w *Write) newWorkerState() WorkerState { writeBuf := w.bufferPool.Take() return &writeWorkerState{ bufferPool: w.bufferPool, writeBuf: writeBuf, buf: bytes.NewBuffer(writeBuf[0:0:len(writeBuf)]), } } // Cleanup returns the writeBuf to the underlying buffer pool, and removes the // goroutine's reference to the writeBuf and encapsulating buf. func (w *writeWorkerState) Cleanup() { w.bufferPool.Return(w.writeBuf) w.writeBuf = nil w.buf = nil } // Reset resets the bytes.Buffer so that it is zero-length and has the capacity // of the underlying buffer.Write.k func (w *writeWorkerState) Reset() { w.buf.Reset() }