1
0
mirror of https://github.com/astaxie/beego.git synced 2024-11-22 17:40:55 +00:00

Merge pull request #1527 from JessonChan/develop

reuse compress writer
This commit is contained in:
astaxie 2016-01-04 14:36:40 +08:00
commit 73168d2f7d
2 changed files with 109 additions and 48 deletions

View File

@ -24,21 +24,84 @@ import (
"os"
"strconv"
"strings"
"sync"
)
type resetWriter interface {
io.Writer
Reset(w io.Writer)
}
type nopResetWriter struct {
io.Writer
}
func (n nopResetWriter) Reset(w io.Writer) {
//do nothing
}
type acceptEncoder struct {
name string
encode func(io.Writer, int) (io.Writer, error)
levelEncode func(int) resetWriter
bestSpeedPool *sync.Pool
bestCompressionPool *sync.Pool
}
func (ac acceptEncoder) encode(wr io.Writer, level int) resetWriter {
if ac.bestSpeedPool == nil || ac.bestCompressionPool == nil {
return nopResetWriter{wr}
}
var rwr resetWriter
switch level {
case flate.BestSpeed:
rwr = ac.bestSpeedPool.Get().(resetWriter)
case flate.BestCompression:
rwr = ac.bestCompressionPool.Get().(resetWriter)
default:
rwr = ac.levelEncode(level)
}
rwr.Reset(wr)
return rwr
}
func (ac acceptEncoder) put(wr resetWriter, level int) {
if ac.bestSpeedPool == nil || ac.bestCompressionPool == nil {
return
}
wr.Reset(nil)
switch level {
case flate.BestSpeed:
ac.bestSpeedPool.Put(wr)
case flate.BestCompression:
ac.bestCompressionPool.Put(wr)
}
}
var (
noneCompressEncoder = acceptEncoder{"", func(wr io.Writer, level int) (io.Writer, error) { return wr, nil }}
gzipCompressEncoder = acceptEncoder{"gzip", func(wr io.Writer, level int) (io.Writer, error) { return gzip.NewWriterLevel(wr, level) }}
noneCompressEncoder = acceptEncoder{"", nil, nil, nil}
gzipCompressEncoder = acceptEncoder{"gzip",
func(level int) resetWriter { wr, _ := gzip.NewWriterLevel(nil, level); return wr },
&sync.Pool{
New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestSpeed); return wr },
},
&sync.Pool{
New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestCompression); return wr },
},
}
//according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed
//deflate
//The "zlib" format defined in RFC 1950 [31] in combination with
//the "deflate" compression mechanism described in RFC 1951 [29].
deflateCompressEncoder = acceptEncoder{"deflate", func(wr io.Writer, level int) (io.Writer, error) { return zlib.NewWriterLevel(wr, level) }}
deflateCompressEncoder = acceptEncoder{"deflate",
func(level int) resetWriter { wr, _ := zlib.NewWriterLevel(nil, level); return wr },
&sync.Pool{
New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, flate.BestSpeed); return wr },
},
&sync.Pool{
New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, flate.BestCompression); return wr },
},
}
)
var (
@ -63,7 +126,7 @@ func WriteBody(encoding string, writer io.Writer, content []byte) (bool, string,
// writeLevel reads from reader,writes to writer by specific encoding and compress level
// the compress level is defined by deflate package
func writeLevel(encoding string, writer io.Writer, reader io.Reader, level int) (bool, string, error) {
var outputWriter io.Writer
var outputWriter resetWriter
var err error
var ce = noneCompressEncoder
@ -71,11 +134,8 @@ func writeLevel(encoding string, writer io.Writer, reader io.Reader, level int)
ce = cf
}
encoding = ce.name
outputWriter, err = ce.encode(writer, level)
if err != nil {
return false, "", err
}
outputWriter = ce.encode(writer, level)
defer ce.put(outputWriter, level)
_, err = io.Copy(outputWriter, reader)
if err != nil {

View File

@ -391,14 +391,14 @@ func (p *ControllerRegister) AddAutoPrefix(prefix string, c ControllerInterface)
route.controllerType = ct
pattern := path.Join(prefix, strings.ToLower(controllerName), strings.ToLower(rt.Method(i).Name), "*")
patternInit := path.Join(prefix, controllerName, rt.Method(i).Name, "*")
patternfix := path.Join(prefix, strings.ToLower(controllerName), strings.ToLower(rt.Method(i).Name))
patternfixInit := path.Join(prefix, controllerName, rt.Method(i).Name)
patternFix := path.Join(prefix, strings.ToLower(controllerName), strings.ToLower(rt.Method(i).Name))
patternFixInit := path.Join(prefix, controllerName, rt.Method(i).Name)
route.pattern = pattern
for _, m := range HTTPMETHOD {
p.addToRouter(m, pattern, route)
p.addToRouter(m, patternInit, route)
p.addToRouter(m, patternfix, route)
p.addToRouter(m, patternfixInit, route)
p.addToRouter(m, patternFix, route)
p.addToRouter(m, patternFixInit, route)
}
}
}
@ -504,12 +504,12 @@ func (p *ControllerRegister) geturl(t *Tree, url, controllName, methodName strin
if find {
if l.regexps == nil {
if len(l.wildcards) == 0 {
return true, strings.Replace(url, "/"+urlPlaceholder, "", 1) + tourl(params)
return true, strings.Replace(url, "/"+urlPlaceholder, "", 1) + toUrl(params)
}
if len(l.wildcards) == 1 {
if v, ok := params[l.wildcards[0]]; ok {
delete(params, l.wildcards[0])
return true, strings.Replace(url, urlPlaceholder, v, 1) + tourl(params)
return true, strings.Replace(url, urlPlaceholder, v, 1) + toUrl(params)
}
return false, ""
}
@ -518,7 +518,7 @@ func (p *ControllerRegister) geturl(t *Tree, url, controllName, methodName strin
if e, isok := params[":ext"]; isok {
delete(params, ":path")
delete(params, ":ext")
return true, strings.Replace(url, urlPlaceholder, p+"."+e, -1) + tourl(params)
return true, strings.Replace(url, urlPlaceholder, p+"."+e, -1) + toUrl(params)
}
}
}
@ -539,7 +539,7 @@ func (p *ControllerRegister) geturl(t *Tree, url, controllName, methodName strin
return false, ""
}
}
return true, url + tourl(params)
return true, url + toUrl(params)
}
var i int
var startreg bool
@ -566,7 +566,7 @@ func (p *ControllerRegister) geturl(t *Tree, url, controllName, methodName strin
for _, p := range ps {
url = strings.Replace(url, urlPlaceholder, p, 1)
}
return true, url + tourl(params)
return true, url + toUrl(params)
}
}
}
@ -597,10 +597,10 @@ func (p *ControllerRegister) execFilter(context *beecontext.Context, pos int, ur
// Implement http.Handler interface.
func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
starttime := time.Now()
startTime := time.Now()
var (
runrouter reflect.Type
findrouter bool
runRouter reflect.Type
findRouter bool
runMethod string
routerInfo *controllerInfo
)
@ -609,6 +609,8 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
defer p.pool.Put(context)
defer p.recoverPanic(context)
context.Output.EnableGzip=BConfig.EnableGzip
if BConfig.RunMode == DEV {
context.Output.Header("Server", BConfig.ServerName)
}
@ -620,7 +622,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
urlPath = r.URL.Path
}
// filter wrong httpmethod
// filter wrong http method
if _, ok := HTTPMETHOD[r.Method]; !ok {
http.Error(rw, "Method Not Allowed", 405)
goto Admin
@ -633,7 +635,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
serverStaticRouter(context)
if context.ResponseWriter.Started {
findrouter = true
findRouter = true
goto Admin
}
@ -662,16 +664,15 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
goto Admin
}
if !findrouter {
if !findRouter {
httpMethod := r.Method
if t, ok := p.routers[httpMethod]; ok {
runObject := t.Match(urlPath, context)
if r, ok := runObject.(*controllerInfo); ok {
routerInfo = r
findrouter = true
findRouter = true
if splat := context.Input.Param(":splat"); splat != "" {
splatlist := strings.Split(splat, "/")
for k, v := range splatlist {
for k, v := range strings.Split(splat, "/") {
context.Input.SetParam(strconv.Itoa(k), v)
}
}
@ -681,12 +682,12 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
}
//if no matches to url, throw a not found exception
if !findrouter {
if !findRouter {
exception("404", context)
goto Admin
}
if findrouter {
if findRouter {
//execute middleware filters
if p.execFilter(context, BeforeExec, urlPath) {
goto Admin
@ -705,7 +706,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
isRunnable = true
routerInfo.handler.ServeHTTP(rw, r)
} else {
runrouter = routerInfo.controllerType
runRouter = routerInfo.controllerType
method := r.Method
if r.Method == "POST" && context.Input.Query("_method") == "PUT" {
method = "PUT"
@ -723,17 +724,17 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
}
}
// also defined runrouter & runMethod from filter
// also defined runRouter & runMethod from filter
if !isRunnable {
//Invoke the request handler
vc := reflect.New(runrouter)
vc := reflect.New(runRouter)
execController, ok := vc.Interface().(ControllerInterface)
if !ok {
panic("controller is not ControllerInterface")
}
//call the controller init function
execController.Init(context, runrouter.Name(), runMethod, vc.Interface())
execController.Init(context, runRouter.Name(), runMethod, vc.Interface())
//call prepare function
execController.Prepare()
@ -784,7 +785,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
}
}
// finish all runrouter. release resource
// finish all runRouter. release resource
execController.Finish()
}
@ -797,31 +798,31 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
p.execFilter(context, FinishRouter, urlPath)
Admin:
timeend := time.Since(starttime)
timeDur := time.Since(startTime)
//admin module record QPS
if BConfig.Listen.AdminEnable {
if FilterMonitorFunc(r.Method, r.URL.Path, timeend) {
if runrouter != nil {
go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, runrouter.Name(), timeend)
if FilterMonitorFunc(r.Method, r.URL.Path, timeDur) {
if runRouter != nil {
go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, runRouter.Name(), timeDur)
} else {
go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, "", timeend)
go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, "", timeDur)
}
}
}
if BConfig.RunMode == DEV || BConfig.Log.AccessLogs {
var devinfo string
if findrouter {
var devInfo string
if findRouter {
if routerInfo != nil {
devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s | % -40s |", r.Method, r.URL.Path, timeend.String(), "match", routerInfo.pattern)
devInfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s | % -40s |", r.Method, r.URL.Path, timeDur.String(), "match", routerInfo.pattern)
} else {
devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeend.String(), "match")
devInfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeDur.String(), "match")
}
} else {
devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeend.String(), "notmatch")
devInfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeDur.String(), "notmatch")
}
if DefaultAccessLogFilter == nil || !DefaultAccessLogFilter.Filter(context) {
Debug(devinfo)
Debug(devInfo)
}
}
@ -863,7 +864,7 @@ func (p *ControllerRegister) recoverPanic(context *beecontext.Context) {
}
}
func tourl(params map[string]string) string {
func toUrl(params map[string]string) string {
if len(params) == 0 {
return ""
}