v1.1.0 has improved buffer poolingtags/v1.15.0-rc1
@@ -122,7 +122,7 @@ require ( | |||
github.com/unknwon/com v1.0.1 | |||
github.com/unknwon/i18n v0.0.0-20210321134014-0ebbf2df1c44 | |||
github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae | |||
github.com/unrolled/render v1.0.3 | |||
github.com/unrolled/render v1.1.0 | |||
github.com/urfave/cli v1.22.5 | |||
github.com/willf/bitset v1.1.11 // indirect | |||
github.com/xanzy/go-gitlab v0.44.0 |
@@ -1115,6 +1115,8 @@ github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae h1:ihaXiJkaca54I | |||
github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae/go.mod h1:1fdkY6xxl6ExVs2QFv7R0F5IRZHKA8RahhB9fMC9RvM= | |||
github.com/unrolled/render v1.0.3 h1:baO+NG1bZSF2WR4zwh+0bMWauWky7DVrTOfvE2w+aFo= | |||
github.com/unrolled/render v1.0.3/go.mod h1:gN9T0NhL4Bfbwu8ann7Ry/TGHYfosul+J0obPf6NBdM= | |||
github.com/unrolled/render v1.1.0 h1:gvpR9hHxTt6DcGqRYuVVFcfd8rtK+nyEPUJN06KB57Q= | |||
github.com/unrolled/render v1.1.0/go.mod h1:gN9T0NhL4Bfbwu8ann7Ry/TGHYfosul+J0obPf6NBdM= | |||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= | |||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= | |||
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= |
@@ -1,15 +0,0 @@ | |||
language: go | |||
go: | |||
- 1.11.x | |||
- 1.12.x | |||
- tip | |||
env: | |||
- GO111MODULE=on | |||
install: | |||
- go mod download | |||
script: | |||
- go test -v -race -tags=integration |
@@ -1,4 +1,5 @@ | |||
# Render [![GoDoc](http://godoc.org/github.com/unrolled/render?status.svg)](http://godoc.org/github.com/unrolled/render) [![Build Status](https://travis-ci.org/unrolled/render.svg)](https://travis-ci.org/unrolled/render) | |||
# Render [![GoDoc](http://godoc.org/github.com/unrolled/render?status.svg)](http://godoc.org/github.com/unrolled/render) [![Test](https://github.com/unrolled/render/workflows/Test/badge.svg?branch=v1)](https://github.com/unrolled/render/actions) | |||
Render is a package that provides functionality for easily rendering JSON, XML, text, binary data, and HTML templates. This package is based on the [Martini](https://github.com/go-martini/martini) [render](https://github.com/martini-contrib/render) work. | |||
@@ -2,9 +2,6 @@ package render | |||
import "bytes" | |||
// bufPool represents a reusable buffer pool for executing templates into. | |||
var bufPool *BufferPool | |||
// BufferPool implements a pool of bytes.Buffers in the form of a bounded channel. | |||
// Pulled from the github.com/oxtoacart/bpool package (Apache licensed). | |||
type BufferPool struct { | |||
@@ -39,8 +36,3 @@ func (bp *BufferPool) Put(b *bytes.Buffer) { | |||
default: // Discard the buffer if the pool is full. | |||
} | |||
} | |||
// Initialize buffer pool for writing templates into. | |||
func init() { | |||
bufPool = NewBufferPool(64) | |||
} |
@@ -30,6 +30,8 @@ type HTML struct { | |||
Head | |||
Name string | |||
Templates *template.Template | |||
bp GenericBufferPool | |||
} | |||
// JSON built-in renderer. | |||
@@ -82,9 +84,14 @@ func (d Data) Render(w io.Writer, v interface{}) error { | |||
// Render a HTML response. | |||
func (h HTML) Render(w io.Writer, binding interface{}) error { | |||
// Retrieve a buffer from the pool to write to. | |||
out := bufPool.Get() | |||
err := h.Templates.ExecuteTemplate(out, h.Name, binding) | |||
var buf *bytes.Buffer | |||
if h.bp != nil { | |||
// If we have a bufferpool, allocate from it | |||
buf = h.bp.Get() | |||
defer h.bp.Put(buf) | |||
} | |||
err := h.Templates.ExecuteTemplate(buf, h.Name, binding) | |||
if err != nil { | |||
return err | |||
} | |||
@@ -92,10 +99,8 @@ func (h HTML) Render(w io.Writer, binding interface{}) error { | |||
if hw, ok := w.(http.ResponseWriter); ok { | |||
h.Head.Write(hw) | |||
} | |||
out.WriteTo(w) | |||
buf.WriteTo(w) | |||
// Return the buffer to the pool. | |||
bufPool.Put(out) | |||
return nil | |||
} | |||
@@ -0,0 +1,9 @@ | |||
package render | |||
import "bytes" | |||
// GenericBufferPool abstracts buffer pool implementations | |||
type GenericBufferPool interface { | |||
Get() *bytes.Buffer | |||
Put(*bytes.Buffer) | |||
} |
@@ -103,6 +103,10 @@ type Options struct { | |||
// Enables using partials without the current filename suffix which allows use of the same template in multiple files. e.g {{ partial "carosuel" }} inside the home template will match carosel-home or carosel. | |||
// ***NOTE*** - This option should be named RenderPartialsWithoutSuffix as that is what it does. "Prefix" is a typo. Maintaining the existing name for backwards compatibility. | |||
RenderPartialsWithoutPrefix bool | |||
// BufferPool to use when rendering HTML templates. If none is supplied | |||
// defaults to SizedBufferPool of size 32 with 512KiB buffers. | |||
BufferPool GenericBufferPool | |||
} | |||
// HTMLOptions is a struct for overriding some rendering Options for specific HTML call. | |||
@@ -176,6 +180,10 @@ func (r *Render) prepareOptions() { | |||
if len(r.opt.XMLContentType) == 0 { | |||
r.opt.XMLContentType = ContentXML | |||
} | |||
if r.opt.BufferPool == nil { | |||
// 32 buffers of size 512KiB each | |||
r.opt.BufferPool = NewSizedBufferPool(32, 1<<19) | |||
} | |||
} | |||
func (r *Render) compileTemplates() { | |||
@@ -410,6 +418,7 @@ func (r *Render) HTML(w io.Writer, status int, name string, binding interface{}, | |||
Head: head, | |||
Name: name, | |||
Templates: r.templates, | |||
bp: r.opt.BufferPool, | |||
} | |||
return r.Render(w, h, binding) |
@@ -0,0 +1,62 @@ | |||
package render | |||
import ( | |||
"bytes" | |||
) | |||
// Pulled from the github.com/oxtoacart/bpool package (Apache licensed). | |||
// 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 | |||
} | |||
// NewSizedBufferPool 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. | |||
} | |||
} |
@@ -777,7 +777,7 @@ github.com/unknwon/i18n | |||
# github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae | |||
## explicit | |||
github.com/unknwon/paginater | |||
# github.com/unrolled/render v1.0.3 | |||
# github.com/unrolled/render v1.1.0 | |||
## explicit | |||
github.com/unrolled/render | |||
# github.com/urfave/cli v1.22.5 |