修bug,完善功能
This commit is contained in:
1 parent
30364b1c4b
commit
6996e19694
125 files changed
+15343
-3746
No files matched your search
+194
-40
@@ -2,10 +2,35 @@
|
||||
|
||||
[← 返回 README](../README.md)
|
||||
|
||||
**本页导航:** [组件与访问路径](#组件与访问路径) · [数据目录](#数据目录) · [会话与并发](#会话与并发) · [SQL 查询处理](#sql-查询处理) · [快照事务](#快照事务) · [WAL 与崩溃恢复](#wal-与崩溃恢复) · [页面与空间回收](#页面与空间回收) · [身份、授权与系统目录](#身份授权与系统目录) · [权限变更与会话失效](#权限变更与会话失效) · [扩展方向](#扩展方向)
|
||||
本页内容:
|
||||
|
||||
- [组件与访问路径](#组件与访问路径)
|
||||
- [数据目录](#数据目录)
|
||||
- [会话与并发](#会话与并发)
|
||||
- [SQL 查询处理](#sql-查询处理)
|
||||
- [快照事务](#快照事务)
|
||||
- [WAL 与崩溃恢复](#wal-与崩溃恢复)
|
||||
- [页面与空间回收](#页面与空间回收)
|
||||
- [身份、授权与系统目录](#身份授权与系统目录)
|
||||
- [权限变更与会话失效](#权限变更与会话失效)
|
||||
- [扩展方向](#扩展方向)
|
||||
|
||||
本页面向需要理解或修改 ChuSQL 的开发者,说明组件职责、查询执行过程及存储边界。SQL 的使用方法见 [SQL 语法](syntax.md)。
|
||||
|
||||
ChuSQL 采用客户端 / 服务端架构。正常运行时,只有数据库服务直接访问数据文件;离线初始化与恢复由 bootstrap 完成。
|
||||
|
||||
阅读实现细节前,先了解本文使用的术语:
|
||||
|
||||
| 术语 | 含义 |
|
||||
| --- | --- |
|
||||
| schema(表结构) | 列名、类型和约束等定义;语义检查与优化以此为依据 |
|
||||
| catalog(系统目录) | 记录数据库对象及其结构的元数据;判断表是否存在以此为准 |
|
||||
| 绑定与槽位 | 绑定将列引用对应到输入行的位置,这个位置称为槽位 |
|
||||
| 结构守卫 | 在执行前和存储操作锁内复查依赖,拒绝使用已经失效的表结构 |
|
||||
| DOMAIN(领域类型) | 为基础类型命名,并可附加默认值和约束的自定义类型 |
|
||||
| WAL / LSN | WAL 是恢复用的预写日志,LSN 是标识日志进度的递增序号 |
|
||||
| DML / DDL | DML 包括插入、更新和删除数据;DDL 包括创建、修改和删除结构 |
|
||||
|
||||
## 组件与访问路径
|
||||
|
||||
```mermaid
|
||||
@@ -27,9 +52,15 @@ flowchart LR
|
||||
| chusql-core/storage | catalog、页面、B+ 树、缓存、WAL 与持久化 |
|
||||
| csql-bootstrap | 安装引导及离线系统目录修复、恢复、重置 |
|
||||
|
||||
查询 AST 的 `Select` 使用 `selectItems :: [(String, Expr)]` 保存输出名称与投影表达式,`selectHaving` 保存分组条件;`OrderKey` 明确区分名称、输出序号和表达式。普通列使用 `Col`,别名、计算和聚合使用相同结构。便捷函数 `makeSelect` 接受列名列表并构造这些投影项。
|
||||
服务默认监听 127.0.0.1:7777,Web 默认监听 127.0.0.1:7778。配置位置和平台数据目录见[配置选项](config.md)。
|
||||
|
||||
服务默认监听 127.0.0.1:7777,Web 默认监听 127.0.0.1:7778。配置位置和平台数据目录见 [config.md](config.md)。
|
||||
### 存储名称校验
|
||||
|
||||
存储层解析库限定名后,物理表名、声明列名和写入行顶层字段名使用同一规则:名称非空,只含 ASCII 字母、数字和下划线。SQL 标识符另遵守解析器规则。
|
||||
|
||||
单行、批量、整表替换、结构替换及事务载荷在处理请求时拒绝非法字段名,不修改数据和 WAL。校验不遍历文本内容或复合值内部的键。
|
||||
|
||||
旧数据不自动改名,原始扫描与历史 WAL 重放保留兼容;后续重写需显式提供合法字段名。
|
||||
|
||||
## 数据目录
|
||||
|
||||
@@ -46,7 +77,7 @@ flowchart LR
|
||||
## 会话与并发
|
||||
|
||||
- 每条 TCP 连接拥有独立会话,当前数据库和事务互不影响。
|
||||
- 读请求可并行,写请求由存储层协调。
|
||||
- 服务端业务请求共享全局权限门,数据写语句和提交独占目标数据库的执行门,不同数据库可并行写;权限、DDL 和管理员存储请求独占全局门。库门按名称排序获取并在取消时释放,避免跨库等待环。存储层仍维护每库读写门及表锁。
|
||||
- Web 与 CLI 共享服务端的权限和执行规则,不直接读写数据目录。
|
||||
- Web 登录会话分别持有普通 API / SQL 连接与表格编辑连接,编辑事务按页面标识固定数据库。表格读取携带编辑标识时使用该事务快照;普通查询不进入编辑事务。
|
||||
- 同一 Web Cookie 的请求串行执行。编辑提交以固定保存点重放本地编辑集,失败整体回退;成功回执按提交标识去重。SQL 控制台事务另按页面与标签标识限制连接访问。
|
||||
@@ -55,21 +86,104 @@ flowchart LR
|
||||
|
||||
查询依次经过解析、基于 schema 的语义检查、优化和执行。库名、表名、列名及别名在语义层解析;存储层使用精确的表名键。
|
||||
|
||||
绑定查询保存依赖对象编号、schema 版本、列定义和传递 DOMAIN 依赖。执行前复查,真实存储的每次读取还在相关库读锁内验证全部依赖;结构改变或对象替换明确报错。守卫不提供整条多请求查询的数据快照;旧目录的未知身份/版本保留兼容校验,旧存储未确认守卫则拒绝执行。
|
||||
### 解析后的查询表示
|
||||
|
||||
查询由 `Runtime.Query.bindQuery` 统一准备并绑定,输出按位置校验,保留重复列名。优化完成后将表达式、排序及分组键绑定到输入布局;物理列顺序不同会在存储边界整理,缺列或位置不符明确报错。`ORDER BY` 输出序号保留到计划生成,选择对应投影表达式或 DISTINCT 输出槽位,不通过别名再次查找;非排序投影仍在 LIMIT 后求值。
|
||||
解析器将 SQL 转为抽象语法树(AST)。其中 `Select` 的字段与辅助函数分工如下:
|
||||
|
||||
聚合计划合并投影、HAVING 和排序表达式中的当前层聚合,重复调用只计算一次,内部列使用 SQL 标识符无法声明的名称。HAVING 强制形成分组(无键时为整体组),过滤位于 Aggregate 之后、去重与排序截断之前。表达式排序先计算隐藏排序键并保留投影所需列,再排序、截断和投影;DISTINCT 排序映射到已有输出槽位。HAVING 和排序子查询同样参与结构依赖守卫与 SELECT 权限检查。
|
||||
| 名称 | 用途 |
|
||||
| --- | --- |
|
||||
| `selectItems :: [(String, Expr)]` | 保存输出名称与投影表达式,即查询要返回的列或计算结果 |
|
||||
| `selectHaving` | 保存分组条件 |
|
||||
| `OrderKey` | 区分按名称、输出序号和表达式排序 |
|
||||
| `Col` | 表示普通列;别名、计算和聚合使用相同的投影项结构 |
|
||||
| `makeSelect` | 接受列名列表并构造投影项 |
|
||||
|
||||
相关子查询按最近到最远的独立列作用域查找,最近层歧义不向外回退;二段限定引用只在最近声明该来源的层解析,裸列可继续向外查找。`BoundSubquery` 保存父布局中的取值表达式,缓存按槽位和值区分;重绑定保留局部和外层身份,原位置失效时只允许唯一同名列重定位。执行期外层行仍扁平化,尚无独立作用域或来源编号,结构改写须在绑定前完成。
|
||||
### 类型能力与复合值运算
|
||||
|
||||
写语句按目标 schema 绑定输入表达式和赋值目标。INSERT 拒绝重复目标列,按输入顺序求值,再按 schema 顺序补默认值、NULL 和自增值;UPDATE 的重复赋值读取前一次修改结果,全部赋值后检查 CHECK,再检查最终行集的 NOT NULL、UNIQUE 和 PRIMARY KEY。唯一性检查保留整数与整值浮点的一致语义,多个 NULL 不冲突;检查通过前不发布修改。CHECK、非空和唯一性按列槽位取值,INSERT 已有行及引擎 ALTER 输入行按原 schema 整理,缺列不跳过。
|
||||
运行时类型描述保存相等比较(Eq)、排序(Ord)和哈希(Hash)能力,复合类型按参数递归派生。语义检查按运算要求能力,DOMAIN 沿用基础类型。值排序和哈希按结构执行,不使用显示文本;嵌套浮点正负零保持相等与哈希一致。
|
||||
|
||||
INSERT、UPDATE、DELETE 和已有表的结构变更由 `Engine.bindWrite` 生成不保存数据行的 `BoundWrite`,`executeWriteM` 在执行前复查结构,允许跨数据及统计变化复用。DML 在绑定阶段固定 INSERT 输入槽位、UPDATE 目标槽位、DELETE 行布局和 CHECK / NOT NULL / UNIQUE / PRIMARY KEY 约束;复用时不重新解析或绑定这些内容,自增起点与行集约束仍取当前数据。结构变更则在执行时对变更后的 schema 绑定并检查约束。计划携带目标表、嵌套查询及传递 DOMAIN 依赖;ADD COLUMN / ALTER TYPE 还包含新声明类型的 DOMAIN。建表、建删库、DOMAIN 管理和会话命令继续走各自入口,不属于已有表写计划。
|
||||
值与类型编码保持版本 1,能力由代码中的类型描述提供,不写入已有值载荷。索引键编码是独立约束,运行时复合键不进入索引探测。SQL 行为见 [复合值的比较、排序与分组](types.md#比较排序与分组)。
|
||||
|
||||
写入前先发送只读的 `validate_write` 请求,确认存储支持写守卫并校验依赖;未确认时不发送实际修改请求。实际读取在相关库共享门内复查,实际写入在目标库独占门及其他依赖库共享门内复查,跨库按库名排序取门。对象替换或结构版本变化使旧绑定失效,包括结构改变后恢复原定义。守卫保证结构校验与单次存储操作之间不发生 DDL,不提供整条写语句的数据快照或数据冲突检测。
|
||||
### 绑定查询与结构复查
|
||||
|
||||
CHECK 定义和执行共用类型、函数及列槽位绑定入口,拒绝聚合、子查询和非布尔条件。DROP COLUMN 校验保留下来的 CHECK;RENAME COLUMN 不自动改写约束文本,引用旧名称的 CHECK 会使改名被拒绝。ALTER TYPE 依据新 schema 校验 CHECK、默认值和键能力,空表也不跳过定义校验;通过定义校验后仍检查已有行,再发布结构变更。
|
||||
绑定查询保存依赖对象编号、schema 版本、列定义和直接及间接依赖的 DOMAIN。执行前复查,真实存储的每次读取还在相关库读锁内验证全部依赖;结构改变或对象替换明确报错。守卫不提供整条多请求查询的数据快照;旧目录的未知身份/版本保留兼容校验,旧存储未确认守卫则拒绝执行。
|
||||
|
||||
查询由 `Runtime.Query.bindQuery` 统一准备并绑定,输出按位置校验,保留重复列名。优化完成后将表达式、排序及分组键绑定到输入布局;物理列顺序不同会在存储边界整理,缺列或位置不符明确报错。
|
||||
|
||||
`ORDER BY` 输出序号保留到计划生成,选择对应投影表达式或 DISTINCT 输出槽位,不通过别名再次查找。非排序投影仍在 LIMIT 后求值。
|
||||
|
||||
### 聚合与排序的求值顺序
|
||||
|
||||
聚合计划合并投影、HAVING 和排序表达式中的当前层聚合,重复调用只计算一次。内部列使用 SQL 标识符无法声明的名称。
|
||||
|
||||
HAVING 强制形成分组,无分组键时将输入作为整体组。HAVING 过滤位于聚合算子 Aggregate 之后、去重与排序截断之前。
|
||||
|
||||
表达式排序先计算隐藏排序键并保留投影所需列,再排序、截断和投影。DISTINCT 排序映射到已有输出槽位。HAVING 和排序子查询同样参与结构依赖守卫与 SELECT 权限检查。
|
||||
|
||||
### 相关子查询的列查找
|
||||
|
||||
相关子查询会引用外层查询的列,因此列查找必须区分内外层作用域。
|
||||
|
||||
相关子查询按最近到最远的独立列作用域查找,最近层歧义不向外回退;二段限定引用只在最近声明该来源的层解析,裸列可继续向外查找。
|
||||
|
||||
`BoundSubquery` 保存父布局中的取值表达式,缓存按槽位和值区分;重绑定保留局部和外层身份,原位置失效时只允许唯一同名列重定位。
|
||||
|
||||
执行期外层行仍扁平化,尚无独立作用域或来源编号,结构改写须在绑定前完成。
|
||||
|
||||
### 写入求值与约束检查
|
||||
|
||||
写语句按目标 schema 绑定输入表达式和赋值目标,求值与校验遵循以下规则:
|
||||
|
||||
- INSERT 拒绝重复目标列,按输入顺序求值,再按 schema 顺序补默认值、NULL 和自增值。
|
||||
- UPDATE 的重复赋值读取前一次修改结果。全部赋值后检查 CHECK,再检查最终行集的 NOT NULL、UNIQUE 和 PRIMARY KEY。
|
||||
- 唯一性检查保留整数与整值浮点的一致语义,多个 NULL 不冲突。检查通过前不发布修改。
|
||||
- CHECK、非空和唯一性按列槽位取值。INSERT 已有行及引擎 ALTER 输入行按原 schema 整理,缺列不跳过。
|
||||
|
||||
### 可复用的写计划
|
||||
|
||||
INSERT、UPDATE、DELETE 和已有表的结构变更由 `Engine.bindWrite` 生成不保存数据行的 `BoundWrite`,`executeWriteM` 在执行前复查结构,允许跨数据及统计变化复用。
|
||||
|
||||
DML 在绑定阶段固定 INSERT 输入槽位、UPDATE 目标槽位、DELETE 行布局和 CHECK / NOT NULL / UNIQUE / PRIMARY KEY 约束;复用时不重新解析或绑定这些内容,自增起点与行集约束仍取当前数据。
|
||||
|
||||
结构变更则在执行时对变更后的 schema 绑定并检查约束。
|
||||
|
||||
计划携带目标表、嵌套查询及传递 DOMAIN 依赖;ADD COLUMN / ALTER TYPE 还包含新声明类型的 DOMAIN。
|
||||
|
||||
建表、建删库、DOMAIN 管理和会话命令继续走各自入口,不属于已有表写计划。
|
||||
|
||||
### DOMAIN 约束的变更
|
||||
|
||||
DOMAIN 的 CHECK 在独立 VALUE 槽位绑定,继承默认值和非空限制按当前领域目录合成;表列保留原始声明。创建依赖 DOMAIN 的表或领域也通过结构守卫复查定义。
|
||||
|
||||
ALTER DOMAIN 的校验与提交按以下顺序执行:
|
||||
|
||||
1. 在存储库读锁内取得完整快照,校验直接及间接依赖和已有行。
|
||||
2. 以库身份和 WAL 检查点作为令牌,在写锁内再次比较。
|
||||
3. 令牌一致时,通过 `ReplaceSchema` 提交;期间任何普通提交都使令牌失效,并返回 `serialization_failure`。
|
||||
|
||||
约束变更复用现有目录版本、WAL 和恢复路径,不引入通用结构事务。
|
||||
|
||||
### 存储操作的结构守卫
|
||||
|
||||
写入前先发送只读的 `validate_write` 请求,确认存储支持写守卫并校验依赖;未确认时不发送实际修改请求。
|
||||
|
||||
实际读取在相关库共享门内复查,实际写入在目标库独占门及其他依赖库共享门内复查,跨库按库名排序取门。
|
||||
|
||||
对象替换或结构版本变化使旧绑定失效,包括结构改变后恢复原定义。
|
||||
|
||||
守卫保证结构校验与单次存储操作之间不发生 DDL,不提供整条写语句的数据快照或数据冲突检测。
|
||||
|
||||
### 修改表结构时的约束校验
|
||||
|
||||
CHECK 定义和执行共用类型、函数及列槽位绑定入口,拒绝聚合、子查询和非布尔条件。修改表结构时还需遵守以下规则:
|
||||
|
||||
- DROP COLUMN 校验保留下来的 CHECK。
|
||||
- RENAME COLUMN 不自动改写约束文本,引用旧名称的 CHECK 会使改名被拒绝。
|
||||
- ALTER TYPE 依据新 schema 校验 CHECK、默认值和键能力,空表也不跳过定义校验。通过定义校验后仍检查已有行,再发布结构变更。
|
||||
|
||||
### 查询优化的能力与边界
|
||||
|
||||
查询优化支持以下能力,统计信息只影响计划选择,优化不能改变查询结果语义:
|
||||
|
||||
| 能力 | 实现与边界 |
|
||||
| --- | --- |
|
||||
@@ -81,43 +195,87 @@ CHECK 定义和执行共用类型、函数及列槽位绑定入口,拒绝聚
|
||||
| 成本估算 | 使用行数、不同值数和数值列的 16 桶等宽直方图 |
|
||||
| 索引选择 | 优化器判断适用条件与成本,存储层管理实际索引 |
|
||||
|
||||
派生表可根据 schema 和透明算子估计行数并参与安全的连接重排;缺统计或可能报错时保守处理。输出列投影可下推,但保留所有计算项的求值,避免隐藏错误。内存存储提供实时行数和封顶去重统计。执行器用查询内状态保存首次使用时成功求出的子查询行;键包含已解析查询定义与具名外层绑定值,跨不同父布局复用,原始名称调用保守包含整个外层行。派生表按执行子树和外层行缓存,应用来源别名前复用,优化后子树不同则分别执行。标量、IN、EXISTS 和 ANY / ALL 各自处理共享行集,保留基数错误和三值逻辑。缓存在每次执行时清空,不跨会话或数据修改保留;既有表达式分组求值顺序保持,JOIN 空行对仍不触发子查询。尚无磁盘溢出或物化内存预算,也不提供整条查询的数据快照。统计信息只影响计划选择,优化不能改变查询结果语义。
|
||||
#### 连接重排与投影下推
|
||||
|
||||
`SemiJoin` 分别绑定两侧键,只暴露左侧布局;执行左侧为空时不求右侧,其他情况完整求右侧并构建键集合,按原左行顺序过滤,右侧重复键不会放大结果。独立 IN 保存原子查询身份,继续共享其他消费者的物化结果;NOT IN 跟踪右侧 NULL,NOT EXISTS 的空值键则视作不匹配。大整数与浮点混合比较超出安全哈希范围时退回既有逐值比较。重写只覆盖单独过滤谓词:IN 左键限普通列或简单字面量;相关 EXISTS 限单表、唯一外层等值引用和普通列/简单字面量投影。组合谓词、复杂相关条件、聚合、排序截断及可能报错的相关投影继续走原路径,避免改变错误时序和词法作用域。
|
||||
派生表可根据 schema 和透明算子估计行数并参与安全的连接重排;缺统计或可能报错时保守处理。输出列投影可下推,但保留所有计算项的求值,避免隐藏错误。内存存储提供实时行数和封顶去重统计。
|
||||
|
||||
完整 SQL 写法及限制见 [syntax.md](syntax.md)。
|
||||
#### 子查询结果的复用
|
||||
|
||||
## 快照事务
|
||||
执行器用查询内状态保存首次使用时成功求出的子查询行;键包含已解析查询定义与具名外层绑定值,跨不同父布局复用,原始名称调用保守包含整个外层行。
|
||||
|
||||
派生表按执行子树和外层行缓存,应用来源别名前复用,优化后子树不同则分别执行。标量、IN、EXISTS 和 ANY / ALL 各自处理共享行集,保留基数错误和三值逻辑。
|
||||
|
||||
缓存在每次执行时清空,不跨会话或数据修改保留;既有表达式分组求值顺序保持,JOIN 空行对仍不触发子查询。
|
||||
|
||||
尚无磁盘溢出或物化内存预算,也不提供整条查询的数据快照。
|
||||
|
||||
#### 用存在性匹配加速子查询
|
||||
|
||||
半连接与反连接根据右侧是否存在匹配行来筛选左行,只输出左侧列。`SemiJoin` 分别绑定两侧键,只暴露左侧布局;执行左侧为空时不求右侧,其他情况完整求右侧并构建键集合,按原左行顺序过滤,右侧重复键不会放大结果。
|
||||
|
||||
独立 IN 保存原子查询身份,继续共享其他消费者的物化结果;NOT IN 跟踪右侧 NULL,NOT EXISTS 的空值键则视作不匹配。
|
||||
|
||||
大整数与浮点混合比较超出安全哈希范围时退回既有逐值比较。
|
||||
|
||||
重写只覆盖单独过滤谓词:IN 左键限普通列或简单字面量;相关 EXISTS 限单表、唯一外层等值引用和普通列/简单字面量投影。
|
||||
|
||||
组合谓词、复杂相关条件、聚合、排序截断及可能报错的相关投影继续走原路径,避免改变错误时序和词法作用域。
|
||||
|
||||
完整 SQL 写法及限制见 [SQL 语法](syntax.md)。
|
||||
|
||||
## 快照事务与行锁
|
||||
|
||||
MVCC 是多版本并发控制:每条逻辑行有不复用的内部编号和版本链,事务读取开始时可见的版本及自身修改。库内提交序号使用 WAL 提交 LSN;`mvcc.json` 保存版本目录,在堆与索引同步后原子发布,再推进库检查点。旧目录首次写入或开始事务时导入版本,原页格式保留。
|
||||
|
||||
| 阶段 | 行为 |
|
||||
| --- | --- |
|
||||
| BEGIN | 将当前数据库读为会话内存快照 |
|
||||
| 事务内执行 | 读取快照与自身修改,看不到其他连接后续提交 |
|
||||
| SAVEPOINT | 保存当前快照;回滚可退回指定保存点 |
|
||||
| COMMIT | 比对基线与现值,确认无写写冲突后原子应用差分 |
|
||||
| ROLLBACK | 丢弃会话快照与保存点 |
|
||||
| BEGIN | 注册存储事务和快照引用,向引擎返回一致的结构与行集 |
|
||||
| 事务内执行 | 基于开始快照执行,修改行和唯一键在语句成功前取得锁 |
|
||||
| SAVEPOINT | 保存工作行集和读依赖;回滚同步存储计划,已有锁保留到事务结束 |
|
||||
| COMMIT | 在短提交门内合并最新版本、校验权限、对象、读写依赖及最终约束,再经 WAL 发布 |
|
||||
| ROLLBACK / 断线 | 清除计划、快照引用、锁和等待边;保存点不能跨连接恢复 |
|
||||
|
||||
有整数 id 的表按行比对并提交差分;其他表按整表替换提交。发生冲突时返回 serialization_failure 并保留事务,由调用方回滚或重试。事务内不支持 DDL 或切换数据库。
|
||||
行锁覆盖内部行编号及旧、新唯一值,NULL 不争用唯一值锁。同一库中不同行可以同时准备修改,等待行锁不占库提交门。等待图检测环并中止形成环的等待者;总等待上限为 5 秒,分别返回 `deadlock_detected` 或 `lock_timeout`。版本冲突返回 `serialization_failure`。调用方须 ROLLBACK,再从 BEGIN 重做,不能只重发 COMMIT。保存点回滚不释放此前取得的锁。
|
||||
|
||||
默认 BEGIN 提供快照隔离,复查写入行的内容版本。SERIALIZABLE 写事务另外按表复查所有读依赖,包括子查询及幻行,因此不同记录的变化也可能导致保守冲突。只读事务可完成原快照读取。事务内禁止 DDL 和切换数据库。
|
||||
|
||||
自动提交的查询与数据写语句也使用存储事务。权限和 DDL 使用全局独占门;数据准备使用共享门,同库提交校验和 WAL 发布仍按顺序完成,以保留连续的已应用提交前缀。原始管理员存储写入不取得 SQL 事务行锁,但会发布版本,旧事务随后按版本冲突规则拒绝提交。
|
||||
|
||||
SQL 工作行集仍在 Haskell 中物化;版本目录发布也会读取整库并写出版本文件。行版本支持隔离与回收,不表示已有按需取行、增量版本日志或吞吐量保证。结束事务释放内存中的旧版本,后续发布写回回收结果;旧版本及整库快照会增加内存、磁盘和 I/O 成本。
|
||||
|
||||
### 在线空间整理
|
||||
|
||||
显式 `compact` 将快照中的存活行复制到独立代次的影子堆与索引,复制期间继续接受 SQL 数据写入。切换前短暂独占库门,保留最新行集的有序前缀,删除影子中的过期行并按最新顺序追加其余行;并发变化较多时,切换窗口可能重写较长后缀。
|
||||
|
||||
影子文件同步完成后,以 WAL 的 Migrate 操作发布 catalog 中的 `file_generation`,逻辑对象编号和结构版本不变。旧快照结束后删除退役文件;重启先恢复切换日志,再清理未发布与退役代次。启动时隐藏列整理仍使用离线重写。备份须包含整个库目录及页侧文件,不能只复制 catalog 指向的新堆。
|
||||
|
||||
## WAL 与崩溃恢复
|
||||
|
||||
预写日志记录已提交的修改,检查点记录已完成刷盘的位置。写入和恢复遵循以下顺序:
|
||||
|
||||
1. 一组写操作与提交标记写入 WAL,每条记录带递增 LSN。
|
||||
2. 数据和 catalog 刷盘后,检查点推进到已完成提交的 LSN。
|
||||
3. 按检查点截断日志前缀,保留尚未确认刷盘的记录。
|
||||
4. 重启时只重放检查点之后的已提交组,丢弃未提交组,并进行幂等检查。
|
||||
2. 数据页和索引页覆盖前,完整页镜像与校验和先同步到对应 `.page-wal` 文件。
|
||||
3. 数据文件同步后,原子替换 `.pages` 中的页 LSN 和写序号,再清理镜像日志。
|
||||
4. 数据、页版本和 catalog 刷盘后,同步并原子发布行版本目录,再将库检查点推进到已完成提交的 LSN。
|
||||
5. 按检查点截断日志前缀,保留尚未确认刷盘的记录。
|
||||
6. 重启时先按有效全页镜像修复撕裂写,再重放库检查点之后的已提交组,丢弃未提交组,并进行幂等检查。
|
||||
|
||||
建表、删表、建索引、删索引和数据修改均进入 WAL。LSN 跨重启续号,SystemStatus 的 last_lsn 表示检查点 LSN。
|
||||
页镜像有独立递增写序号,允许同一事务多次刷新同一页;不能仅凭相同页 LSN 跳过后一次写入。未完整写出的尾帧丢弃,完整帧校验失败则明确报错并保留材料。镜像写入或检查点失败后,当前页句柄拒绝继续刷新,析构也不能绕过恢复。
|
||||
|
||||
若系统目录损坏导致服务无法启动,使用离线 bootstrap。repair、recover 与 reset 的范围及操作步骤见 [bootstrap.md](bootstrap.md)。
|
||||
已提交组恢复前丢弃受影响表的派生索引,再从堆数据重建,避免残缺索引根阻断逻辑重放。整表日志直接重写,不先依赖可能不完整的行集判断是否已应用。
|
||||
|
||||
建表、删表、建索引、删索引、账号和数据修改均进入带提交点的 WAL。LSN 跨重启续号,SystemStatus 的 last_lsn 表示检查点 LSN。
|
||||
|
||||
若系统目录损坏导致服务无法启动,使用离线 bootstrap。repair、recover 与 reset 的范围及操作步骤见[系统引导与恢复](bootstrap.md)。
|
||||
|
||||
## 页面与空间回收
|
||||
|
||||
- 删除行先将槽位标记为墓碑。
|
||||
- 死空间达到页大小的四分之一时,随删除整理页内活行。
|
||||
- 整理保留槽位编号,索引中的页号与槽号仍有效。
|
||||
- compact 通常逐页整理;存在 DROP COLUMN 留下的隐藏列时整表重写。
|
||||
- 显式 compact 在线复制存活行、补齐并发修改并经 WAL 切换文件代次,回收跨页空洞及隐藏列字节,同时重建索引位置。
|
||||
|
||||
不进行跨页填洞;没有 ORDER BY 时仍保留当前扫描顺序,但应用应使用显式排序获得稳定结果。
|
||||
跨页整理的复制阶段允许并发数据写入,最终追平与切换仍独占库门。旧快照引用阻止退役文件回收。整理保留切换时的逻辑行序;应用应使用 ORDER BY 获得确定结果。
|
||||
|
||||
## 身份、授权与系统目录
|
||||
|
||||
@@ -132,13 +290,15 @@ CHECK 定义和执行共用类型、函数及列槽位绑定入口,拒绝聚
|
||||
| 稳定对象 | catalog 分配数据库及表编号,授权与所有者绑定对象和身份编号,删除后不复用 |
|
||||
| 所有者 | 建表者获得表所有权;启用角色可继承所有权,数据库所有权不隐含他人表的数据权限 |
|
||||
|
||||
对象权限目录 __system_object_acl 对普通语句和存储请求隐藏。权限快照按字符分块,在系统库写锁内比较版本并通过同一 WAL 组替换;服务启动恢复建表前持久化的创建者声明,旧名称授权只迁移一次到现存稳定对象。
|
||||
对象权限目录 __system_object_acl 对普通语句和存储请求隐藏。
|
||||
|
||||
类型目录说明见 [types.md](types.md),身份字段与权限边界见 [users-and-roles.md](users-and-roles.md)。
|
||||
权限快照按字符分块,在系统库写锁内比较版本并通过同一 WAL 组替换;服务启动恢复建表前持久化的创建者声明,旧名称授权只迁移一次到现存稳定对象。
|
||||
|
||||
类型目录说明见[类型与类型目录](types.md),身份字段与权限边界见[用户、角色与属性](users-and-roles.md)。
|
||||
|
||||
## 权限变更与会话失效
|
||||
|
||||
账号、属性和授权变化会标记受影响的在线连接。角色变化先展开成员及转授权来源关系,确定涉及的登录身份。共享读写门允许查询并行,并将授权及对象结构变更与查询排序;事务提交再次验证权限和稳定对象编号。
|
||||
账号、属性和授权变化会标记受影响的在线连接。角色变化先展开成员及转授权来源关系,确定涉及的登录身份。共享读写门允许查询并行,并将数据写入、提交、授权及对象结构变更与查询排序;事务提交再次验证权限和稳定对象编号。
|
||||
|
||||
TCP 连接在下一次请求时返回 unauthorized 并关闭;空闲连接不被强行中断。权限逐条查询,避免继续使用旧授权。Web 会话还通过账号版本校验,口令或身份变更使旧凭据失效。
|
||||
|
||||
@@ -147,7 +307,7 @@ TCP 连接在下一次请求时返回 unauthorized 并关闭;空闲连接不
|
||||
> [!NOTE]
|
||||
> 以下是规划,不能作为当前 SQL、事务或恢复能力使用。进度与验收见 `.agents/context/progress.txt`。
|
||||
|
||||
### bound IR
|
||||
### 查询内部表示的后续完善
|
||||
|
||||
已有列槽位、类型化函数与 `BoundQuery`;后续补齐多级词法作用域、来源/列身份,以及写语句与约束的统一绑定。迁移保留同名遮蔽、NULL / DOMAIN、输出布局和错误时序,结构改写应在绑定前完成或重新绑定。
|
||||
|
||||
@@ -160,10 +320,4 @@ TCP 连接在下一次请求时返回 unauthorized 并关闭;空闲连接不
|
||||
|
||||
### 存储扩展
|
||||
|
||||
| 方向 | 前置条件与边界 |
|
||||
| --- | --- |
|
||||
| 行版本 MVCC | 稳定且不复用的 `row_id`、版本链与快照序号;提交复查写冲突和唯一键,旧索引候选随活跃快照保留 |
|
||||
| 跨页 compact | MVCC 与稳定定位映射,影子文件经 WAL 原子切换;保留旧读引用和逻辑扫描顺序 |
|
||||
| 并行写 | 固定对象/行/唯一键锁序及取消机制,WAL/CSN 发布保持连续已应用前缀;DDL、权限和目录变更继续排序 |
|
||||
|
||||
新页格式、版本化 WAL、离线升级和恢复验证是前提。升级在停服副本上保留备份并校验后发布;旧二进制不得打开不支持的格式。任何持久化应用失败须保持 `recovery_required`,不将已提交 WAL 组当作失败撤销。性能收益不能代替语义、权限和崩溃恢复验证。
|
||||
行版本、行锁、同库数据准备与在线整理的边界见上文。后续优化须根据测量减少整库物化、版本文件写放大和最终切换窗口;WAL 发布顺序、版本可见性与恢复约束保持一致。
|
||||
Reference in new issue
Block a user