Files
ChuSQL/docs/architecture.md
T

152 lines
9.7 KiB
Markdown
Raw Normal View History

# 架构与组件
2026-10-13 14:09:36 +08:00
[← 返回 README](../README.md)
**本页导航:** [组件与访问路径](#组件与访问路径) · [数据目录](#数据目录) · [会话与并发](#会话与并发) · [SQL 查询处理](#sql-查询处理) · [快照事务](#快照事务) · [WAL 与崩溃恢复](#wal-与崩溃恢复) · [页面与空间回收](#页面与空间回收) · [身份、授权与系统目录](#身份授权与系统目录) · [权限变更与会话失效](#权限变更与会话失效) · [扩展方向](#扩展方向)
ChuSQL 采用客户端 / 服务端架构。正常运行时,只有数据库服务直接访问数据文件;离线初始化与恢复由 bootstrap 完成。
## 组件与访问路径
2026-10-13 14:09:36 +08:00
```mermaid
flowchart LR
CLI[CLI / 其他客户端] -->|TCP| Server[chusql-server]
Browser[浏览器] -->|HTTP| Web[chusql-web]
Web -->|TCP| Server
Server --> Engine[Haskell SQL 引擎]
Engine --> Storage[Rust 存储层]
Storage --> Disk[(磁盘)]
```
| 组件 | 职责 |
| --- | --- |
| chusql-server | 登录、会话、鉴权、SQL 执行和事务 |
| chusql-web | Web 管理界面,通过 TCP 访问服务 |
| csql | 命令行客户端,通过 TCP 执行 SQL |
| chusql-core/engine | 解析、语义检查、优化及执行 |
| chusql-core/storage | catalog、页面、B+ 树、缓存、WAL 与持久化 |
| csql-bootstrap | 安装引导及离线系统目录修复、恢复、重置 |
2026-10-13 14:09:36 +08:00
查询 AST 的 `Select` 使用 `selectItems :: [(String, Expr)]` 保存输出名称与投影表达式;普通列使用 `Col`,别名、计算和聚合使用相同结构。便捷函数 `makeSelect` 接受列名列表并构造这些投影项。
服务默认监听 127.0.0.1:7777,Web 默认监听 127.0.0.1:7778。配置位置和平台数据目录见 [config.md](config.md)。
## 数据目录
2026-10-13 14:09:36 +08:00
`[storage] data_dir` 保存持久化数据,`log_files` 单独指定诊断日志目录。
| 位置 | 内容 |
| --- | --- |
| system/ | 身份、凭据、角色、授权和预定义类型目录 |
| databases/<数据库名>/ | 业务数据库的 catalog、数据与索引 |
| WAL 与检查点文件 | 已提交写入的恢复记录及刷盘进度 |
安装只初始化系统数据库,业务数据库由用户创建。表存在性以 catalog 为准,不能仅凭数据文件判断。
## 会话与并发
- 每条 TCP 连接拥有独立会话,当前数据库和事务互不影响。
- 读请求可并行,写请求由存储层协调。
- Web 与 CLI 共享服务端的权限和执行规则,不直接读写数据目录。
2026-10-05 22:22:23 +08:00
- Web 登录会话分别持有普通 API / SQL 连接与表格编辑连接,编辑事务按页面标识固定数据库。表格读取携带编辑标识时使用该事务快照;普通查询不进入编辑事务。
- 同一 Web Cookie 的请求串行执行。编辑提交以固定保存点重放本地编辑集,失败整体回退;成功回执按提交标识去重。SQL 控制台事务另按页面与标签标识限制连接访问。
## SQL 查询处理
2026-10-03 16:49:23 +08:00
查询依次经过解析、基于 schema 的语义检查、优化和执行。库名、表名、列名及别名在语义层解析;存储层使用精确的表名键。
2026-10-03 16:49:23 +08:00
2026-10-13 14:09:36 +08:00
绑定查询保存依赖对象编号、schema 版本、列定义和传递 DOMAIN 依赖。执行前复查,真实存储的每次读取还在相关库读锁内验证全部依赖;结构改变或对象替换明确报错。守卫不提供整条多请求查询的数据快照;旧目录的未知身份/版本保留兼容校验,旧存储未确认守卫则拒绝执行。
| 能力 | 实现与边界 |
| --- | --- |
| 派生表 | 内层独立解析,必须有别名,不能引用外层列;输出列按别名暴露 |
| WITH / CTE | 解析时展开为派生表;不支持递归或物化,多次引用分别执行 |
| ANY / ALL | 按 OR / AND 的三值逻辑求值;空集的 ANY 为假、ALL 为真 |
| 子查询复用 | Filter 和计算列按外层绑定分组;JOIN 条件按首次遇到的绑定惰性复用 |
| 成本估算 | 使用行数、不同值数和数值列的 16 桶等宽直方图 |
| 索引选择 | 优化器判断适用条件与成本,存储层管理实际索引 |
2026-10-03 20:04:33 +08:00
派生表可根据 schema 和透明算子估计行数并参与安全的连接重排;缺统计或可能报错时保守处理。输出列投影可下推,但保留所有计算项的求值,避免隐藏错误。内存存储提供实时行数和封顶去重统计。JOIN 条件的子查询在首次遇到外层绑定时求值,缓存仅限当前连接;空行对不触发求值,普通条件仍逐行计算。尚无半连接或通用物化。统计信息只影响计划选择,优化不能改变查询结果语义。
2026-10-03 20:52:02 +08:00
完整 SQL 写法及限制见 [syntax.md](syntax.md)。
2026-10-03 21:03:17 +08:00
## 快照事务
2026-10-03 21:11:23 +08:00
| 阶段 | 行为 |
| --- | --- |
| BEGIN | 将当前数据库读为会话内存快照 |
| 事务内执行 | 读取快照与自身修改,看不到其他连接后续提交 |
| SAVEPOINT | 保存当前快照;回滚可退回指定保存点 |
| COMMIT | 比对基线与现值,确认无写写冲突后原子应用差分 |
| ROLLBACK | 丢弃会话快照与保存点 |
2026-10-03 16:49:23 +08:00
有整数 id 的表按行比对并提交差分;其他表按整表替换提交。发生冲突时返回 serialization_failure 并保留事务,由调用方回滚或重试。事务内不支持 DDL 或切换数据库。
## WAL 与崩溃恢复
2026-10-03 21:18:52 +08:00
1. 一组写操作与提交标记写入 WAL,每条记录带递增 LSN。
2. 数据和 catalog 刷盘后,检查点推进到已完成提交的 LSN。
3. 按检查点截断日志前缀,保留尚未确认刷盘的记录。
4. 重启时只重放检查点之后的已提交组,丢弃未提交组,并进行幂等检查。
建表、删表、建索引、删索引和数据修改均进入 WAL。LSN 跨重启续号,SystemStatus 的 last_lsn 表示检查点 LSN。
2026-10-04 14:44:40 +08:00
若系统目录损坏导致服务无法启动,使用离线 bootstrap。repair、recover 与 reset 的范围及操作步骤见 [bootstrap.md](bootstrap.md)。
2026-10-04 14:44:40 +08:00
## 页面与空间回收
2026-10-04 14:44:40 +08:00
- 删除行先将槽位标记为墓碑。
- 死空间达到页大小的四分之一时,随删除整理页内活行。
- 整理保留槽位编号,索引中的页号与槽号仍有效。
- compact 通常逐页整理;存在 DROP COLUMN 留下的隐藏列时整表重写。
不进行跨页填洞;没有 ORDER BY 时仍保留当前扫描顺序,但应用应使用显式排序获得稳定结果。
## 身份、授权与系统目录
系统表统一使用 __system_ 前缀,身份与凭据目录对普通语句隐藏。SUPERUSER 拥有最高权限,system_catalog_manager 提供受限目录管理能力;两者不通过角色成员关系继承。
| 机制 | 行为 |
| --- | --- |
| 角色继承 | 沿成员关系取得权限并集;拒绝自继承与环 |
2026-10-05 22:22:23 +08:00
| 对象授权 | 数据库 CONNECT / CREATE,表 SELECT / INSERT / UPDATE / DELETE;ALL 按作用域展开 |
| 转授权 | WITH GRANT OPTION 允许将持有的权限授予其他身份 |
2026-10-05 22:22:23 +08:00
| 撤销 | 授予者撤销自身来源;所有者或最高权限身份管理对象授权,级联清理无合法来源的下游 |
| 稳定对象 | catalog 分配数据库及表编号,授权与所有者绑定对象和身份编号,删除后不复用 |
| 所有者 | 建表者获得表所有权;启用角色可继承所有权,数据库所有权不隐含他人表的数据权限 |
对象权限目录 __system_object_acl 对普通语句和存储请求隐藏。权限快照按字符分块,在系统库写锁内比较版本并通过同一 WAL 组替换;服务启动恢复建表前持久化的创建者声明,旧名称授权只迁移一次到现存稳定对象。
类型目录说明见 [types.md](types.md),身份字段与权限边界见 [users-and-roles.md](users-and-roles.md)。
## 权限变更与会话失效
2026-10-05 22:22:23 +08:00
账号、属性和授权变化会标记受影响的在线连接。角色变化先展开成员及转授权来源关系,确定涉及的登录身份。共享读写门允许查询并行,并将授权及对象结构变更与查询排序;事务提交再次验证权限和稳定对象编号。
TCP 连接在下一次请求时返回 unauthorized 并关闭;空闲连接不被强行中断。权限逐条查询,避免继续使用旧授权。Web 会话还通过账号版本校验,口令或身份变更使旧凭据失效。
2026-10-05 22:22:23 +08:00
2026-10-13 14:09:36 +08:00
## 扩展方向
2026-10-05 22:22:23 +08:00
2026-10-13 14:09:36 +08:00
> [!NOTE]
> 以下是规划,不能作为当前 SQL、事务或恢复能力使用。进度与验收见 `.agents/context/progress.txt`。
2026-10-05 22:22:23 +08:00
### bound IR
2026-10-13 14:09:36 +08:00
已有列槽位、类型化函数与 `BoundQuery`;后续补齐多级词法作用域、来源/列身份,以及写语句与约束的统一绑定。迁移保留同名遮蔽、NULL / DOMAIN、输出布局和错误时序,结构改写应在绑定前完成或重新绑定。
2026-10-05 22:22:23 +08:00
2026-10-13 14:09:36 +08:00
### 查询扩展
2026-10-05 22:22:23 +08:00
2026-10-13 14:09:36 +08:00
| 方向 | 前置条件与边界 |
| --- | --- |
| 通用子查询物化 | 缓存绑定对象/schema、外层值及快照,保留惰性求值和首次错误;限制内存、执行预算及取消 |
| 递归 CTE | 先实现类型一致的迭代关系,明确去重、循环终止、轮次与行数预算;不隐含支持写入型 CTE |
2026-10-05 22:22:23 +08:00
2026-10-13 14:09:36 +08:00
### 存储扩展
2026-10-05 22:22:23 +08:00
2026-10-13 14:09:36 +08:00
| 方向 | 前置条件与边界 |
| --- | --- |
| 行版本 MVCC | 稳定且不复用的 `row_id`、版本链与快照序号;提交复查写冲突和唯一键,旧索引候选随活跃快照保留 |
| 跨页 compact | MVCC 与稳定定位映射,影子文件经 WAL 原子切换;保留旧读引用和逻辑扫描顺序 |
| 并行写 | 固定对象/行/唯一键锁序及取消机制,WAL/CSN 发布保持连续已应用前缀;DDL、权限和目录变更继续排序 |
2026-10-05 22:22:23 +08:00
2026-10-13 14:09:36 +08:00
新页格式、版本化 WAL、离线升级和恢复验证是前提。升级在停服副本上保留备份并校验后发布;旧二进制不得打开不支持的格式。任何持久化应用失败须保持 `recovery_required`,不将已提交 WAL 组当作失败撤销。性能收益不能代替语义、权限和崩溃恢复验证。