1
0
mirror of https://github.com/astaxie/beego.git synced 2024-11-26 10:01:28 +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" "os"
"strconv" "strconv"
"strings" "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 { type acceptEncoder struct {
name string 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 ( var (
noneCompressEncoder = acceptEncoder{"", func(wr io.Writer, level int) (io.Writer, error) { return wr, nil }} noneCompressEncoder = acceptEncoder{"", nil, nil, nil}
gzipCompressEncoder = acceptEncoder{"gzip", func(wr io.Writer, level int) (io.Writer, error) { return gzip.NewWriterLevel(wr, level) }} 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 //according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed
//deflate //deflate
//The "zlib" format defined in RFC 1950 [31] in combination with //The "zlib" format defined in RFC 1950 [31] in combination with
//the "deflate" compression mechanism described in RFC 1951 [29]. //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 ( 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 // writeLevel reads from reader,writes to writer by specific encoding and compress level
// the compress level is defined by deflate package // the compress level is defined by deflate package
func writeLevel(encoding string, writer io.Writer, reader io.Reader, level int) (bool, string, error) { 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 err error
var ce = noneCompressEncoder var ce = noneCompressEncoder
@ -71,11 +134,8 @@ func writeLevel(encoding string, writer io.Writer, reader io.Reader, level int)
ce = cf ce = cf
} }
encoding = ce.name encoding = ce.name
outputWriter, err = ce.encode(writer, level) outputWriter = ce.encode(writer, level)
defer ce.put(outputWriter, level)
if err != nil {
return false, "", err
}
_, err = io.Copy(outputWriter, reader) _, err = io.Copy(outputWriter, reader)
if err != nil { if err != nil {

View File

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