reverse proxy buffer pool
This commit is contained in:
parent
27033e5fcf
commit
e288c7c08c
|
@ -12,6 +12,7 @@ import (
|
|||
"git.xeserv.us/xena/route/lib/tun2"
|
||||
proto "git.xeserv.us/xena/route/proto"
|
||||
"github.com/mtneug/pkg/ulid"
|
||||
"github.com/oxtoacart/bpool"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
|
@ -139,6 +140,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
Director: s.Director,
|
||||
Transport: s.ts,
|
||||
FlushInterval: 1 * time.Second,
|
||||
BufferPool: bpool.NewBytePool(256, 4096),
|
||||
}
|
||||
|
||||
rp.ServeHTTP(w, r)
|
||||
|
|
|
@ -133,3 +133,4 @@ da118f7b8e5954f39d0d2130ab35d4bf0e3cb344 golang.org/x/net/context
|
|||
0eb507a2ca07f13baf499f89d66cc566bf644643 (dirty) google.golang.org/grpc/credentials
|
||||
737072b4e32b7a5018b4a7125da8d12de90e8045 github.com/mattn/go-runewidth
|
||||
44e365d423f4f06769182abfeeae2b91be9d529b github.com/olekukonko/tablewriter
|
||||
4e1c5567d7c2dd59fa4c7c83d34c2f3528b025d6 github.com/oxtoacart/bpool
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
/*
|
||||
Package bpool implements leaky pools of byte arrays and Buffers as bounded
|
||||
channels. It is based on the leaky buffer example from the Effective Go
|
||||
documentation: http://golang.org/doc/effective_go.html#leaky_buffer
|
||||
*/
|
||||
package bpool
|
|
@ -0,0 +1,40 @@
|
|||
package bpool
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
// BufferPool implements a pool of bytes.Buffers in the form of a bounded
|
||||
// channel.
|
||||
type BufferPool struct {
|
||||
c chan *bytes.Buffer
|
||||
}
|
||||
|
||||
// NewBufferPool creates a new BufferPool bounded to the given size.
|
||||
func NewBufferPool(size int) (bp *BufferPool) {
|
||||
return &BufferPool{
|
||||
c: make(chan *bytes.Buffer, size),
|
||||
}
|
||||
}
|
||||
|
||||
// Get gets a Buffer from the BufferPool, or creates a new one if none are
|
||||
// available in the pool.
|
||||
func (bp *BufferPool) Get() (b *bytes.Buffer) {
|
||||
select {
|
||||
case b = <-bp.c:
|
||||
// reuse existing buffer
|
||||
default:
|
||||
// create new buffer
|
||||
b = bytes.NewBuffer([]byte{})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Put returns the given Buffer to the BufferPool.
|
||||
func (bp *BufferPool) Put(b *bytes.Buffer) {
|
||||
b.Reset()
|
||||
select {
|
||||
case bp.c <- b:
|
||||
default: // Discard the buffer if the pool is full.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package bpool
|
||||
|
||||
// BytePool implements a leaky pool of []byte in the form of a bounded
|
||||
// channel.
|
||||
type BytePool struct {
|
||||
c chan []byte
|
||||
w int
|
||||
}
|
||||
|
||||
// NewBytePool creates a new BytePool bounded to the given maxSize, with new
|
||||
// byte arrays sized based on width.
|
||||
func NewBytePool(maxSize int, width int) (bp *BytePool) {
|
||||
return &BytePool{
|
||||
c: make(chan []byte, maxSize),
|
||||
w: width,
|
||||
}
|
||||
}
|
||||
|
||||
// Get gets a []byte from the BytePool, or creates a new one if none are
|
||||
// available in the pool.
|
||||
func (bp *BytePool) Get() (b []byte) {
|
||||
select {
|
||||
case b = <-bp.c:
|
||||
// reuse existing buffer
|
||||
default:
|
||||
// create new buffer
|
||||
b = make([]byte, bp.w)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Put returns the given Buffer to the BytePool.
|
||||
func (bp *BytePool) Put(b []byte) {
|
||||
select {
|
||||
case bp.c <- b:
|
||||
// buffer went back into pool
|
||||
default:
|
||||
// buffer didn't go back into pool, just discard
|
||||
}
|
||||
}
|
||||
|
||||
// Width returns the width of the byte arrays in this pool.
|
||||
func (bp *BytePool) Width() (n int) {
|
||||
return bp.w
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package bpool
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
// SizedBufferPool implements a pool of bytes.Buffers in the form of a bounded
|
||||
// channel. Buffers are pre-allocated to the requested size.
|
||||
type SizedBufferPool struct {
|
||||
c chan *bytes.Buffer
|
||||
a int
|
||||
}
|
||||
|
||||
// SizedBufferPool creates a new BufferPool bounded to the given size.
|
||||
// size defines the number of buffers to be retained in the pool and alloc sets
|
||||
// the initial capacity of new buffers to minimize calls to make().
|
||||
//
|
||||
// The value of alloc should seek to provide a buffer that is representative of
|
||||
// most data written to the the buffer (i.e. 95th percentile) without being
|
||||
// overly large (which will increase static memory consumption). You may wish to
|
||||
// track the capacity of your last N buffers (i.e. using an []int) prior to
|
||||
// returning them to the pool as input into calculating a suitable alloc value.
|
||||
func NewSizedBufferPool(size int, alloc int) (bp *SizedBufferPool) {
|
||||
return &SizedBufferPool{
|
||||
c: make(chan *bytes.Buffer, size),
|
||||
a: alloc,
|
||||
}
|
||||
}
|
||||
|
||||
// Get gets a Buffer from the SizedBufferPool, or creates a new one if none are
|
||||
// available in the pool. Buffers have a pre-allocated capacity.
|
||||
func (bp *SizedBufferPool) Get() (b *bytes.Buffer) {
|
||||
select {
|
||||
case b = <-bp.c:
|
||||
// reuse existing buffer
|
||||
default:
|
||||
// create new buffer
|
||||
b = bytes.NewBuffer(make([]byte, 0, bp.a))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Put returns the given Buffer to the SizedBufferPool.
|
||||
func (bp *SizedBufferPool) Put(b *bytes.Buffer) {
|
||||
b.Reset()
|
||||
|
||||
// Release buffers over our maximum capacity and re-create a pre-sized
|
||||
// buffer to replace it.
|
||||
// Note that the cap(b.Bytes()) provides the capacity from the read off-set
|
||||
// only, but as we've called b.Reset() the full capacity of the underlying
|
||||
// byte slice is returned.
|
||||
if cap(b.Bytes()) > bp.a {
|
||||
b = bytes.NewBuffer(make([]byte, 0, bp.a))
|
||||
}
|
||||
|
||||
select {
|
||||
case bp.c <- b:
|
||||
default: // Discard the buffer if the pool is full.
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue