diff --git a/g/net/ghttp/ghttp_server.go b/g/net/ghttp/ghttp_server.go index 1541ba9c2..580d81999 100644 --- a/g/net/ghttp/ghttp_server.go +++ b/g/net/ghttp/ghttp_server.go @@ -27,7 +27,6 @@ import ( "github.com/gorilla/websocket" "gitee.com/johng/gf/g/os/gtime" "time" - "container/list" ) const ( @@ -43,6 +42,8 @@ const ( gDEFAULT_COOKIE_MAX_AGE = 86400*365 // 默认cookie有效期(一年) gDEFAULT_SESSION_MAX_AGE = 600 // 默认session有效期(600秒) gDEFAULT_SESSION_ID_NAME = "gfsessionid" // 默认存放Cookie中的SessionId名称 + gSERVE_CACHE_LRU_SIZE = 100000 // 服务回调函数缓存LRU大小 + gHOOKS_CACHE_LRU_SIZE = 100000 // 事件回调函数缓存LRU大小 ) // ghttp.Server结构体 @@ -56,8 +57,9 @@ type Server struct { servedCount *gtype.Int // 已经服务的请求数(4-8字节,不考虑溢出情况),同时作为请求ID closeQueue *gqueue.Queue // 请求结束的关闭队列(存放的是需要异步关闭处理的*Request对象) // 服务注册相关 - handlerTree map[string]interface{} // 所有注册的回调函数(路由表,树型结构,哈希表+链表优先级匹配) - handlerCache *gcache.Cache // 服务注册路由内存缓存 + serveTree map[string]interface{} // 所有注册的服务回调函数(路由表,树型结构,哈希表+链表优先级匹配) + hooksTree map[string]interface{} // 所有注册的事件回调函数(路由表,树型结构,哈希表+链表优先级匹配) + serveCache *gcache.Cache // 服务注册路由内存缓存 hooksCache *gcache.Cache // 事件回调路由内存缓存 // 自定义状态码回调 hsmu sync.RWMutex // status handler互斥锁 @@ -88,7 +90,7 @@ type Router struct { Priority int // 优先级,用于链表排序,值越大优先级越高 } -// 域名、URI与回调函数的绑定记录表 +// pattern与回调函数的绑定map type handlerMap map[string]*handlerItem // http回调函数注册信息 @@ -96,19 +98,13 @@ type handlerItem struct { ctype reflect.Type // 控制器类型(反射类型) fname string // 回调方法名称 faddr HandlerFunc // 准确的执行方法内存地址(与以上两个参数二选一) -} - -// 路由注册项(这里使用了非并发安全的list.List,因为该对象的使用统一是由htmu互斥锁保证并发安全) -type handlerRegisterItem struct { - handler *handlerItem // 准确的执行方法内存地址 - hooks map[string]*list.List // 当前的事件回调注册,键名为事件名称,键值为事件执行方法链表 - router *Router // 注册时绑定的路由对象 + router *Router // 注册时绑定的路由对象 } // 根据特定URL.Path解析后的路由检索结果项 type handlerParsedItem struct { - item *handlerRegisterItem // 路由注册项 - values map[string][]string // 特定URL.Path的Router解析参数 + item *handlerItem // 路由注册项 + values map[string][]string // 特定URL.Path的Router解析参数 } // HTTP注册函数 @@ -172,8 +168,9 @@ func GetServer(name...interface{}) (*Server) { servers : make([]*gracefulServer, 0), methodsMap : make(map[string]bool), statusHandlerMap : make(map[string]HandlerFunc), - handlerTree : make(map[string]interface{}), - handlerCache : gcache.New(), + serveTree : make(map[string]interface{}), + hooksTree : make(map[string]interface{}), + serveCache : gcache.New(), hooksCache : gcache.New(), cookies : gmap.NewIntInterfaceMap(), sessions : gcache.New(), @@ -192,8 +189,8 @@ func GetServer(name...interface{}) (*Server) { s.errorLogger.SetBacktraceSkip(4) s.accessLogger.SetBacktraceSkip(4) // 设置路由解析缓存上限,使用LRU进行缓存淘汰 - s.hooksCache.SetCap(10000) - s.handlerCache.SetCap(10000) + s.serveCache.SetCap(gSERVE_CACHE_LRU_SIZE) + s.hooksCache.SetCap(gHOOKS_CACHE_LRU_SIZE) for _, v := range strings.Split(gHTTP_METHODS, ",") { s.methodsMap[v] = true } diff --git a/g/net/ghttp/ghttp_server_router.go b/g/net/ghttp/ghttp_server_router.go index ece3cc59f..a8c39d95f 100644 --- a/g/net/ghttp/ghttp_server_router.go +++ b/g/net/ghttp/ghttp_server_router.go @@ -70,7 +70,7 @@ func (s *Server)parsePattern(pattern string) (domain, method, uri string, err er func (s *Server) setHandler(pattern string, handler *handlerItem, hook ... string) error { // Web Server正字运行时无法动态注册路由方法 if s.Status() == SERVER_STATUS_RUNNING { - return errors.New("cannnot bind handler while server running") + return errors.New("cannot bind handler while server running") } var hookName string if len(hook) > 0 { @@ -82,34 +82,28 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ... strin } // 路由对象 - router := &Router { + handler.router = &Router { Uri : uri, Domain : domain, Method : method, Priority : strings.Count(uri[1:], "/"), } - router.RegRule, router.RegNames = s.patternToRegRule(uri) - - // 注册对象 - registerItem := &handlerRegisterItem { - handler : handler, - hooks : make(map[string]*list.List), - router : router, - } - if len(hookName) > 0 { - registerItem.handler = nil - registerItem.hooks[hookName] = list.New() - registerItem.hooks[hookName].PushBack(handler) - } + handler.router.RegRule, handler.router.RegNames = s.patternToRegRule(uri) // 动态注册,首先需要判断是否是动态注册,如果不是那么就没必要添加到动态注册记录变量中。 // 非叶节点为哈希表检索节点,按照URI注册的层级进行高效检索,直至到叶子链表节点; // 叶子节点是链表,按照优先级进行排序,优先级高的排前面,按照遍历检索,按照哈希表层级检索后的叶子链表数据量不会很大,所以效率比较高; - if _, ok := s.handlerTree[domain]; !ok { - s.handlerTree[domain] = make(map[string]interface{}) + tree := (map[string]interface{})(nil) + if len(hookName) == 0 { + tree = s.serveTree + } else { + tree = s.hooksTree + } + if _, ok := tree[domain]; !ok { + tree[domain] = make(map[string]interface{}) } // 用于遍历的指针 - p := s.handlerTree[domain] + p := tree[domain] // 当前节点的规则链表 lists := make([]*list.List, 0) array := ([]string)(nil) @@ -153,79 +147,29 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ... strin } // 得到的lists是该路由规则一路匹配下来相关的模糊匹配链表(注意不是这棵树所有的链表), // 从头开始遍历每个节点的模糊匹配链表,将该路由项插入进去(按照优先级高的放在前面) - item := (*handlerRegisterItem)(nil) - // 用以标记 *handlerRegisterItem 指向的对象是否已经处理过,因为多个节点可能会关联同一个该对象 - pushedItemSet := gset.NewStringSet() - if len(hookName) == 0 { - // 普通方法路由注册,追加或者覆盖 - for _, l := range lists { - pushed := false - address := "" - for e := l.Front(); e != nil; e = e.Next() { - item = e.Value.(*handlerRegisterItem) - address = fmt.Sprintf("%p", item) - if pushedItemSet.Contains(address) { - pushed = true - break - } - // 判断是否已存在相同的路由注册项 - if strings.EqualFold(router.Domain, item.router.Domain) && - strings.EqualFold(router.Method, item.router.Method) && - strings.EqualFold(router.Uri, item.router.Uri) { - item.handler = handler - pushed = true - break - } - if s.compareRouterPriority(router, item.router) { - l.InsertBefore(registerItem, e) + item := (*handlerItem)(nil) + for _, l := range lists { + pushed := false + for e := l.Front(); e != nil; e = e.Next() { + item = e.Value.(*handlerItem) + // 判断是否已存在相同的路由注册项 + if len(hookName) == 0 { + if strings.EqualFold(handler.router.Domain, item.router.Domain) && + strings.EqualFold(handler.router.Method, item.router.Method) && + strings.EqualFold(handler.router.Uri, item.router.Uri) { + e.Value = handler pushed = true break } } - if pushed { - if len(address) > 0 { - pushedItemSet.Add(address) - } - } else { - l.PushBack(registerItem) + if s.compareRouterPriority(handler.router, item.router) { + l.InsertBefore(handler, e) + pushed = true + break } } - } else { - // 回调方法路由注册,将方法追加到链表末尾 - for _, l := range lists { - pushed := false - address := "" - for e := l.Front(); e != nil; e = e.Next() { - item = e.Value.(*handlerRegisterItem) - address = fmt.Sprintf("%p", item) - if pushedItemSet.Contains(address) { - pushed = true - break - } - // 判断是否已存在相同的路由注册项 - if strings.EqualFold(router.Domain, item.router.Domain) && - strings.EqualFold(router.Method, item.router.Method) && - strings.EqualFold(router.Uri, item.router.Uri) { - if _, ok := item.hooks[hookName]; !ok { - item.hooks[hookName] = list.New() - } - item.hooks[hookName].PushBack(handler) - pushed = true - break - } - if s.compareRouterPriority(router, item.router) { - l.InsertBefore(registerItem, e) - pushed = true - break - } - } - if pushed { - if len(address) > 0 { - pushedItemSet.Add(address) - } - } else { - l.PushBack(registerItem) - } + if !pushed { + l.PushBack(handler) } } //gutil.Dump(s.handlerTree)