Go to file
guqing 6b2aea9301
refactor: content permalink routing using radix tree (#2547)
#### 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
```
2022-10-20 08:12:15 +00:00
.github Add Pull Request template for default branch (#2513) 2022-10-06 11:00:25 +00:00
config/checkstyle chore: add checkstyle rule (#2091) 2022-05-17 06:46:11 +00:00
docs Refine logic of form login and logout (#2528) 2022-10-11 08:04:14 +00:00
gradle/wrapper Create basic project structure for halo 2.0 (#1699) 2022-03-04 15:04:11 +08:00
hack chore: add cherry_pick_pull.sh for cherry-picking pull request (#1554) 2021-12-03 10:21:24 +08:00
src refactor: content permalink routing using radix tree (#2547) 2022-10-20 08:12:15 +00:00
.editorconfig refactor: next line config (#1844) 2022-04-14 07:49:17 +00:00
.gitattributes Refactor .gitignore 2019-04-03 11:37:59 +08:00
.gitignore Fix the problem of generating permalink due to special filename (#2462) 2022-09-24 04:50:15 +00:00
CODE_OF_CONDUCT.md docs: add CODE_OF_CONDUCT.md (#2150) 2022-06-12 08:10:12 +00:00
CONTRIBUTING.md chore: add cherry_pick_pull.sh for cherry-picking pull request (#1554) 2021-12-03 10:21:24 +08:00
Dockerfile Refactor CICD for Halo next (#2236) 2022-07-12 11:01:00 +08:00
LICENSE Create LICENSE 2018-03-21 21:39:46 +08:00
OWNERS feat: add OWNERS file for prow (#1840) 2022-04-13 17:06:22 +08:00
README.md Update README.md due to 2.0.0-alpha.2 released (#2546) 2022-10-12 09:10:16 +00:00
SECURITY.md Update SECURITY.md 2021-09-29 20:43:15 +08:00
build.gradle Bump version of SpringDoc to 2.0.0-M7 (#2593) 2022-10-18 10:12:11 +00:00
gradle.properties Create basic project structure for halo 2.0 (#1699) 2022-03-04 15:04:11 +08:00
gradlew Create basic project structure for halo 2.0 (#1699) 2022-03-04 15:04:11 +08:00
gradlew.bat Create basic project structure for halo 2.0 (#1699) 2022-03-04 15:04:11 +08:00
settings.gradle Create basic project structure for halo 2.0 (#1699) 2022-03-04 15:04:11 +08:00

README.md

Halo logo

Halo [ˈheɪloʊ],一款现代化的开源博客/CMS系统值得一试。

GitHub release GitHub All Releases Docker pulls GitHub last commit GitHub Workflow Status
官网 文档2.0 Alpha 社区 Gitee Telegram 频道


注意

当前分支为 Halo 2.0 的开发分支,目前 Halo 2.0 处于 Alpha 测试阶段,无法从 1.5 直接升级也不建议在生产环境使用。稳定版本Halo 1.x请查阅以下地址

快速开始

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

在线体验

生态

可访问 awesome-halo 查看已经适用于 Halo 2.0 的主题和插件,以及适用于 Halo 1.x 的相关仓库。

许可证

license

Halo 使用 GPL-v3.0 协议开源,请遵守开源协议。

贡献

参考 CONTRIBUTING

状态

Repobeats analytics