mirror of https://github.com/halo-dev/halo
![]() #### What type of PR is this? /area core /milestone 2.0 /kind improvement #### What this PR does / why we need it: 由于之前的实现方式在某些场景下遇到瓶颈,例如 permalink 含有中文或者 /{year}/{month}/{slug} 这样的 pattern 容易出现路由冲突,所以提出此 PR 以改进之前的路由方式: [Radix tree wiki](https://en.wikipedia.org/wiki/Radix_tree) 本 PR 通过变种的 RadixTree 来作为存储 permalink 的数据结构有以下原因: 1. 内容模块的 permalink 都具有大部分相同的前缀,例如分类是 以 /categories 前缀开头,文章的 /{year}/{month}/ 前缀等,使用 RadixTree 前缀树来存储将更节约内存 2. 具有分页规则例如根据分类查询文章列表的路由,/categories/fake-slug/page/{page},需要 Router 在匹配时能支持动态参数 3. 最坏时间复杂度为 O(n) 当插入以下几个路由 ``` /categories/default /categories/hello /archives/test /about /tags/halo ``` 存储结构将如下(带 * 的表示它为实际 path 节点) ``` / [indices=act, priority=6] ├── a [indices=rb, priority=3] │ ├── rchives/test [value=archives-test, priority=1]* │ └── bout [value=about, priority=1]* ├── categories/ [indices=dh, priority=2] │ ├── default [value=categories-default, priority=1]* │ └── hello [value=categories-hello, priority=1]* └── tags/halo [value=tags-halo, priority=1]* ``` 通过在 Node 添加 indices 字段来对应 children 的首字符,当查询时便可直接判断 key 的首字符选择对应下标的 children 进行深度查找(这得益于每个 node 都是与插入 key part 取最大公共字串,所以每个 node 的 indices 都不存在重复的字符。) 例如当查询 /categories/default 时 1. 首先将 `/categories/default` 与 root node 的 key `/` 取最长公共字串为 `/`,`/categories/default` 剩下的子串为 `categories/default` 首字符为 `c`, 通过获取 root node 的 `indices` 在 `indexOf('c')` 得到该进入哪个子分支 2. 如果 index 为 -1 则直接返回 null 表示不存在 3. 得到 index 为 1,则 node.getChildren(1), 得到 key 为 `categories` 的 node 4. 重复步骤1,取公共最长字串的剩余部分得到 `default`,获取该 node 的 indices 检查`default` 的首字符 是否存在:`indexOf('d')`,得到 index=0,取 node 的 children.get(0) 得到 key 为`default` 的 node,取最长公共字串没有剩余部分且当前node的 isReal(是否是一个 path) 为 true 查询结束得到结果 使用 indices 的改进 radix tree 的思路来自于 [julienschmidt/httprouter](https://github.com/julienschmidt/httprouter/blob/master/tree.go) - [ ] 带参数的 node 节点和带统配符的 node 节点有待优化查询效率,尽量做到一次查询得到结果 #### Which issue(s) this PR fixes: Fixes #2539 #2473 #### Special notes for your reviewer: how to test it? 1. 创建文章、分类、标签、自定义页面等多条数据 2. 通过反复删除和创建来测试这些资源的 permalink 是否还能被访问到 3. 该 PR 已经支持 permalink 中带有中文和特殊字符 /cc @halo-dev/sig-halo #### Does this PR introduce a user-facing change? ```release-note 使用 RadixTree 的变种数据结构改进 permalink Router ``` |
||
---|---|---|
.github | ||
config/checkstyle | ||
docs | ||
gradle/wrapper | ||
hack | ||
src | ||
.editorconfig | ||
.gitattributes | ||
.gitignore | ||
CODE_OF_CONDUCT.md | ||
CONTRIBUTING.md | ||
Dockerfile | ||
LICENSE | ||
OWNERS | ||
README.md | ||
SECURITY.md | ||
build.gradle | ||
gradle.properties | ||
gradlew | ||
gradlew.bat | ||
settings.gradle |
README.md
Halo [ˈheɪloʊ],一款现代化的开源博客/CMS系统,值得一试。
官网
文档(2.0 Alpha)
社区
Gitee
Telegram 频道
注意
当前分支为 Halo 2.0 的开发分支,目前 Halo 2.0 处于 Alpha 测试阶段,无法从 1.5 直接升级,也不建议在生产环境使用。稳定版本(Halo 1.x)请查阅以下地址:
- 1.5 分支:https://github.com/halo-dev/halo/tree/release-1.5
- 1.6 分支:https://github.com/halo-dev/halo/tree/release-1.6
- 1.5 文档:https://docs.halo.run
快速开始
Docker
docker run -it -d --name halo-next -p 8090:8090 -v ~/halo-next:/root/halo-next --restart=unless-stopped halohub/halo-dev:2.0.0-alpha.2
详细部署文档请查阅:https://docs.halo.run/2.0.0-SNAPSHOT/getting-started/install/docker
在线体验
- 环境地址:https://demo.halo.run
- 后台地址:https://demo.halo.run/console
- 用户名:
demo
- 密码:
P@ssw0rd123..
生态
可访问 awesome-halo 查看已经适用于 Halo 2.0 的主题和插件,以及适用于 Halo 1.x 的相关仓库。
许可证
Halo 使用 GPL-v3.0 协议开源,请遵守开源协议。
贡献
参考 CONTRIBUTING。