From 59fa248292837fc6da30afc0a9aa43587f22f832 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 31 Dec 2015 18:50:52 +0800 Subject: [PATCH 1/5] use sync.Pool to decrease new compression writer --- context/acceptencoder.go | 71 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index 0a0586ac..c5fe1ba0 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -24,21 +24,79 @@ 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 encodeFunc func(io.Writer, int) (resetWriter, error) type acceptEncoder struct { - name string - encode func(io.Writer, int) (io.Writer, error) + name string + bestSpeedPool *sync.Pool + bestCompressionPool *sync.Pool +} + +func (ac acceptEncoder) encode(wr io.Writer, level int) (resetWriter, error) { + if ac.bestSpeedPool == nil || ac.bestCompressionPool == nil { + return nopResetWriter{wr}, nil + } + var rwr resetWriter + if level == flate.BestSpeed { + rwr = ac.bestSpeedPool.Get().(resetWriter) + } else { + rwr = ac.bestCompressionPool.Get().(resetWriter) + } + rwr.Reset(wr) + return rwr, nil +} + +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} + gzipCompressEncoder = acceptEncoder{"gzip", + &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", + &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 +121,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 @@ -72,6 +130,7 @@ func writeLevel(encoding string, writer io.Writer, reader io.Reader, level int) } encoding = ce.name outputWriter, err = ce.encode(writer, level) + defer ce.put(outputWriter, level) if err != nil { return false, "", err From ee2322e83b4a28a20e71849c519802e38395ea8b Mon Sep 17 00:00:00 2001 From: JessonChan Date: Sun, 3 Jan 2016 15:35:32 +0800 Subject: [PATCH 2/5] add any level compress --- context/acceptencoder.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index c5fe1ba0..7d4b2dbe 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -40,9 +40,9 @@ func (n nopResetWriter) Reset(w io.Writer) { //do nothing } -type encodeFunc func(io.Writer, int) (resetWriter, error) type acceptEncoder struct { name string + levelEncode func(int) resetWriter bestSpeedPool *sync.Pool bestCompressionPool *sync.Pool } @@ -52,10 +52,13 @@ func (ac acceptEncoder) encode(wr io.Writer, level int) (resetWriter, error) { return nopResetWriter{wr}, nil } var rwr resetWriter - if level == flate.BestSpeed { + switch level { + case flate.BestSpeed: rwr = ac.bestSpeedPool.Get().(resetWriter) - } else { + case flate.BestCompression: rwr = ac.bestCompressionPool.Get().(resetWriter) + default: + rwr = ac.levelEncode(level) } rwr.Reset(wr) return rwr, nil @@ -75,8 +78,9 @@ func (ac acceptEncoder) put(wr resetWriter, level int) { } var ( - noneCompressEncoder = acceptEncoder{"", nil, nil} + 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 }, }, @@ -90,6 +94,7 @@ var ( //The "zlib" format defined in RFC 1950 [31] in combination with //the "deflate" compression mechanism described in RFC 1951 [29]. 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 }, }, From 3ebf27515762608a3117d514721501c35012ae11 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Sun, 3 Jan 2016 15:40:44 +0800 Subject: [PATCH 3/5] fixed camel style name --- router.go | 73 +++++++++++++++++++++++++++---------------------------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/router.go b/router.go index 69464ac2..195b20e5 100644 --- a/router.go +++ b/router.go @@ -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 ) @@ -620,7 +620,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 +633,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) serverStaticRouter(context) if context.ResponseWriter.Started { - findrouter = true + findRouter = true goto Admin } @@ -662,7 +662,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) goto Admin } - if !findrouter { + if !findRouter { httpMethod := r.Method if httpMethod == "POST" && context.Input.Query("_method") == "PUT" { httpMethod = "PUT" @@ -674,10 +674,9 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) 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) } } @@ -687,12 +686,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 @@ -711,7 +710,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" @@ -729,17 +728,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() @@ -790,7 +789,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } } - // finish all runrouter. release resource + // finish all runRouter. release resource execController.Finish() } @@ -803,31 +802,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) } } @@ -869,7 +868,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 "" } From d23291ccc783f9613f9d0bc848ca6b382c65b649 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Mon, 4 Jan 2016 08:50:59 +0800 Subject: [PATCH 4/5] remove a dump err --- context/acceptencoder.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index 7d4b2dbe..07c5cb0b 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -47,9 +47,9 @@ type acceptEncoder struct { bestCompressionPool *sync.Pool } -func (ac acceptEncoder) encode(wr io.Writer, level int) (resetWriter, error) { +func (ac acceptEncoder) encode(wr io.Writer, level int) resetWriter { if ac.bestSpeedPool == nil || ac.bestCompressionPool == nil { - return nopResetWriter{wr}, nil + return nopResetWriter{wr} } var rwr resetWriter switch level { @@ -61,7 +61,7 @@ func (ac acceptEncoder) encode(wr io.Writer, level int) (resetWriter, error) { rwr = ac.levelEncode(level) } rwr.Reset(wr) - return rwr, nil + return rwr } func (ac acceptEncoder) put(wr resetWriter, level int) { @@ -134,13 +134,9 @@ func writeLevel(encoding string, writer io.Writer, reader io.Reader, level int) ce = cf } 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) if err != nil { return false, "", err From fd2ded190b351793327d9ab07d4e5bf5692ab16b Mon Sep 17 00:00:00 2001 From: JessonChan Date: Mon, 4 Jan 2016 09:27:58 +0800 Subject: [PATCH 5/5] EnableGzip bug fixed --- router.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/router.go b/router.go index 195b20e5..92ce2846 100644 --- a/router.go +++ b/router.go @@ -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) }