Merge branch 'contextCaching' into develop
This commit is contained in:
		
							
								
								
									
										77
									
								
								gin.go
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								gin.go
									
									
									
									
									
								
							@ -31,6 +31,11 @@ type (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ErrorMsgs []ErrorMsg
 | 
						ErrorMsgs []ErrorMsg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Config struct {
 | 
				
			||||||
 | 
							CacheSize    int
 | 
				
			||||||
 | 
							Preallocated int
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Context is the most important part of gin. It allows us to pass variables between middleware,
 | 
						// Context is the most important part of gin. It allows us to pass variables between middleware,
 | 
				
			||||||
	// manage the flow, validate the JSON of a request and render a JSON response for example.
 | 
						// manage the flow, validate the JSON of a request and render a JSON response for example.
 | 
				
			||||||
	Context struct {
 | 
						Context struct {
 | 
				
			||||||
@ -39,8 +44,8 @@ type (
 | 
				
			|||||||
		Keys     map[string]interface{}
 | 
							Keys     map[string]interface{}
 | 
				
			||||||
		Errors   ErrorMsgs
 | 
							Errors   ErrorMsgs
 | 
				
			||||||
		Params   httprouter.Params
 | 
							Params   httprouter.Params
 | 
				
			||||||
 | 
							Engine   *Engine
 | 
				
			||||||
		handlers []HandlerFunc
 | 
							handlers []HandlerFunc
 | 
				
			||||||
		engine   *Engine
 | 
					 | 
				
			||||||
		index    int8
 | 
							index    int8
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -56,9 +61,10 @@ type (
 | 
				
			|||||||
	// Represents the web framework, it wrappers the blazing fast httprouter multiplexer and a list of global middlewares.
 | 
						// Represents the web framework, it wrappers the blazing fast httprouter multiplexer and a list of global middlewares.
 | 
				
			||||||
	Engine struct {
 | 
						Engine struct {
 | 
				
			||||||
		*RouterGroup
 | 
							*RouterGroup
 | 
				
			||||||
 | 
							HTMLTemplates *template.Template
 | 
				
			||||||
 | 
							cache         chan *Context
 | 
				
			||||||
		handlers404   []HandlerFunc
 | 
							handlers404   []HandlerFunc
 | 
				
			||||||
		router        *httprouter.Router
 | 
							router        *httprouter.Router
 | 
				
			||||||
		HTMLTemplates *template.Template
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -71,16 +77,35 @@ func (a ErrorMsgs) String() string {
 | 
				
			|||||||
	return buffer.String()
 | 
						return buffer.String()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Returns a new blank Engine instance without any middleware attached.
 | 
					func NewWithConfig(config Config) *Engine {
 | 
				
			||||||
// The most basic configuration
 | 
						if config.CacheSize < 2 {
 | 
				
			||||||
func New() *Engine {
 | 
							panic("CacheSize must be at least 2")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if config.Preallocated > config.CacheSize {
 | 
				
			||||||
 | 
							panic("Preallocated must be less or equal to CacheSize")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	engine := &Engine{}
 | 
						engine := &Engine{}
 | 
				
			||||||
	engine.RouterGroup = &RouterGroup{nil, "/", nil, engine}
 | 
						engine.RouterGroup = &RouterGroup{nil, "/", nil, engine}
 | 
				
			||||||
	engine.router = httprouter.New()
 | 
						engine.router = httprouter.New()
 | 
				
			||||||
	engine.router.NotFound = engine.handle404
 | 
						engine.router.NotFound = engine.handle404
 | 
				
			||||||
 | 
						engine.cache = make(chan *Context, config.CacheSize)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Fill it with empty contexts
 | 
				
			||||||
 | 
						for i := 0; i < config.Preallocated; i++ {
 | 
				
			||||||
 | 
							engine.cache <- &Context{Engine: engine}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return engine
 | 
						return engine
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Returns a new blank Engine instance without any middleware attached.
 | 
				
			||||||
 | 
					// The most basic configuration
 | 
				
			||||||
 | 
					func New() *Engine {
 | 
				
			||||||
 | 
						return NewWithConfig(Config{
 | 
				
			||||||
 | 
							CacheSize:    1024,
 | 
				
			||||||
 | 
							Preallocated: 512,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Returns a Engine instance with the Logger and Recovery already attached.
 | 
					// Returns a Engine instance with the Logger and Recovery already attached.
 | 
				
			||||||
func Default() *Engine {
 | 
					func Default() *Engine {
 | 
				
			||||||
	engine := New()
 | 
						engine := New()
 | 
				
			||||||
@ -97,6 +122,10 @@ func (engine *Engine) NotFound404(handlers ...HandlerFunc) {
 | 
				
			|||||||
	engine.handlers404 = handlers
 | 
						engine.handlers404 = handlers
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (engine *Engine) CacheStress() float32 {
 | 
				
			||||||
 | 
						return 1.0 - float32(len(engine.cache))/float32(cap(engine.cache))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (engine *Engine) handle404(w http.ResponseWriter, req *http.Request) {
 | 
					func (engine *Engine) handle404(w http.ResponseWriter, req *http.Request) {
 | 
				
			||||||
	handlers := engine.combineHandlers(engine.handlers404)
 | 
						handlers := engine.combineHandlers(engine.handlers404)
 | 
				
			||||||
	c := engine.createContext(w, req, nil, handlers)
 | 
						c := engine.createContext(w, req, nil, handlers)
 | 
				
			||||||
@ -107,6 +136,7 @@ func (engine *Engine) handle404(w http.ResponseWriter, req *http.Request) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c.Next()
 | 
						c.Next()
 | 
				
			||||||
 | 
						engine.reuseContext(c)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ServeFiles serves files from the given file system root.
 | 
					// ServeFiles serves files from the given file system root.
 | 
				
			||||||
@ -138,14 +168,32 @@ func (engine *Engine) Run(addr string) {
 | 
				
			|||||||
/********** ROUTES GROUPING *********/
 | 
					/********** ROUTES GROUPING *********/
 | 
				
			||||||
/************************************/
 | 
					/************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (group *RouterGroup) createContext(w http.ResponseWriter, req *http.Request, params httprouter.Params, handlers []HandlerFunc) *Context {
 | 
					func (engine *Engine) createContext(w http.ResponseWriter, req *http.Request, params httprouter.Params, handlers []HandlerFunc) *Context {
 | 
				
			||||||
 | 
						select {
 | 
				
			||||||
 | 
						case c := <-engine.cache:
 | 
				
			||||||
 | 
							c.Writer = w
 | 
				
			||||||
 | 
							c.Req = req
 | 
				
			||||||
 | 
							c.Params = params
 | 
				
			||||||
 | 
							c.handlers = handlers
 | 
				
			||||||
 | 
							c.Keys = nil
 | 
				
			||||||
 | 
							c.index = -1
 | 
				
			||||||
 | 
							return c
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
		return &Context{
 | 
							return &Context{
 | 
				
			||||||
			Writer:   w,
 | 
								Writer:   w,
 | 
				
			||||||
			Req:      req,
 | 
								Req:      req,
 | 
				
			||||||
		index:    -1,
 | 
					 | 
				
			||||||
		engine:   group.engine,
 | 
					 | 
				
			||||||
			Params:   params,
 | 
								Params:   params,
 | 
				
			||||||
			handlers: handlers,
 | 
								handlers: handlers,
 | 
				
			||||||
 | 
								index:    -1,
 | 
				
			||||||
 | 
								Engine:   engine,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (engine *Engine) reuseContext(c *Context) {
 | 
				
			||||||
 | 
						select {
 | 
				
			||||||
 | 
						case engine.cache <- c:
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -180,7 +228,9 @@ func (group *RouterGroup) Handle(method, p string, handlers []HandlerFunc) {
 | 
				
			|||||||
	p = path.Join(group.prefix, p)
 | 
						p = path.Join(group.prefix, p)
 | 
				
			||||||
	handlers = group.combineHandlers(handlers)
 | 
						handlers = group.combineHandlers(handlers)
 | 
				
			||||||
	group.engine.router.Handle(method, p, func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
 | 
						group.engine.router.Handle(method, p, func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
 | 
				
			||||||
		group.createContext(w, req, params, handlers).Next()
 | 
							c := group.engine.createContext(w, req, params, handlers)
 | 
				
			||||||
 | 
							c.Next()
 | 
				
			||||||
 | 
							group.engine.reuseContext(c)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -221,6 +271,13 @@ func (group *RouterGroup) combineHandlers(handlers []HandlerFunc) []HandlerFunc
 | 
				
			|||||||
/****** FLOW AND ERROR MANAGEMENT****/
 | 
					/****** FLOW AND ERROR MANAGEMENT****/
 | 
				
			||||||
/************************************/
 | 
					/************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Context) Copy() *Context {
 | 
				
			||||||
 | 
						var cp Context = *c
 | 
				
			||||||
 | 
						cp.index = AbortIndex
 | 
				
			||||||
 | 
						cp.handlers = nil
 | 
				
			||||||
 | 
						return &cp
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Next should be used only in the middlewares.
 | 
					// Next should be used only in the middlewares.
 | 
				
			||||||
// It executes the pending handlers in the chain inside the calling handler.
 | 
					// It executes the pending handlers in the chain inside the calling handler.
 | 
				
			||||||
// See example in github.
 | 
					// See example in github.
 | 
				
			||||||
@ -358,7 +415,7 @@ func (c *Context) HTML(code int, name string, data interface{}) {
 | 
				
			|||||||
	if code >= 0 {
 | 
						if code >= 0 {
 | 
				
			||||||
		c.Writer.WriteHeader(code)
 | 
							c.Writer.WriteHeader(code)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err := c.engine.HTMLTemplates.ExecuteTemplate(c.Writer, name, data); err != nil {
 | 
						if err := c.Engine.HTMLTemplates.ExecuteTemplate(c.Writer, name, data); err != nil {
 | 
				
			||||||
		c.Error(err, map[string]interface{}{
 | 
							c.Error(err, map[string]interface{}{
 | 
				
			||||||
			"name": name,
 | 
								"name": name,
 | 
				
			||||||
			"data": data,
 | 
								"data": data,
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user