Skip to content

fix(net/ghttp): refactor the route tree#4712

Open
LanceAdd wants to merge 4 commits intogogf:masterfrom
LanceAdd:fix/ghttp
Open

fix(net/ghttp): refactor the route tree#4712
LanceAdd wants to merge 4 commits intogogf:masterfrom
LanceAdd:fix/ghttp

Conversation

@LanceAdd
Copy link
Member

背景

Server.serveTree 是 ghttp 路由系统的核心数据结构,承载从域名到路由处理器的整棵前缀树。每次 HTTP 请求在缓存未命中时,都必须通过 searchHandlers 遍历该树来匹配路由,是真正的热路径。

原始实现将整棵树递归地表示为 map[string]any,通过硬编码字符串键区分节点语义:

  • "*fuzz" → 模糊子节点(:param / {param} / *wildcard
  • "*list" → 当前节点的处理器列表(*glist.List

这导致 searchHandlers 每处理一个 URI 段最多产生 5 次运行时类型断言,以 /api/v1/user/123(4 段)为例,单次调用约产生 16 次断言。


变更内容

新增 routeNode 结构体

用具体结构体替换递归的 map[string]any,将三种节点语义直接表达为结构体字段:

type routeNode struct {
    children map[string]*routeNode       // 精确匹配子节点(原普通字符串键)
    fuzz     *routeNode                  // 模糊子节点(原 "*fuzz" 键)
    list     *glist.TList[*HandlerItem]  // 处理器列表(原 "*list" 键)
}

Server.serveTree 字段类型由 map[string]any 改为 map[string]*routeNode

新增 4 个封装方法

方法 用途 路径
ensureList(dst) 懒初始化 list,追加到 dst 并返回 写路径
ensureFuzz() 懒初始化 fuzz 子节点并返回 写路径
ensureChild(part) 懒初始化精确匹配子节点并返回 写路径
appendList(dst) list 非 nil 时追加到 dst 读路径(热路径)

性能收益

指标 改前 改后
searchHandlers 每段断言次数 ~5 次 0 次
list 元素迭代断言 每元素 1 次 0 次
fuzz / list 字段访问 类型断言 + map 查找 直接指针解引用
doSetHandler 核心循环行数 15 行 8 行
缓存命中时断言(serveCache 1 次 1 次(不变)
外部接口破坏

- 引入 routeNode 结构体作为路由前缀树的节点
- 使用 children 字段存储精确匹配路径段,fuzz 字段存储通配符节点,list 字段存储处理器项
- 添加 ensureList、ensureFuzz、ensureChild 等辅助方法来管理节点操作
- 修改路由注册逻辑以适应新的前缀树结构
- 更新路由查找逻辑以遍历前缀树并正确处理模糊匹配和精确匹配
- 替换原有的 map[string]any 嵌套结构为类型安全的 routeNode 指针映射
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors ghttp’s core routing structure (Server.serveTree) from a map[string]any-based recursive tree with magic keys into a typed prefix trie (routeNode) to eliminate runtime type assertions on the hot path (searchHandlers).

Changes:

  • Introduced routeNode (children/fuzz/list) and changed serveTree to map[string]*routeNode keyed by domain.
  • Added small helper methods on routeNode (ensureList/ensureFuzz/ensureChild/appendList) to simplify and speed up route registration and lookup.
  • Updated route registration (doSetHandler) and lookup (searchHandlers) to use typed navigation instead of map[string]any + type assertions.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
net/ghttp/ghttp_server_router_serve.go Switch route lookup to typed trie traversal and typed handler list iteration.
net/ghttp/ghttp_server_router.go Add routeNode helper methods and refactor registration to build the typed trie.
net/ghttp/ghttp_server.go Initialize serveTree as map[string]*routeNode.
net/ghttp/ghttp.go Update Server’s serveTree type and define the routeNode struct.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants