This commit is contained in:
LIm1tZz7 committed 2026-09-27 22:21:45 +08:00
1 parent 7600f0f9ed
commit 687c012841
8 files changed
+2 -194

No files matched your search

-3
View File
@@ -99,6 +99,3 @@ chusql-web/static/
Thumbs.db
ehthumbs.db
desktop.ini
# Isolated UI verification build (the live server may lock the default executable)
.stack-work-ui/
+1 -1
View File
@@ -35,7 +35,7 @@
4. **等价改造不许改结果**。典型:等值连接换哈希表,输出顺序必须和嵌套循环一致(左表序为主、右表序为辅,同键下右行保序);认不出等值键或某侧空表时退回嵌套循环(决策 9)。
5. **存储接口分 `schema` 与 `snapshot`**:语义检查与优化只走 `schema`,不许再拉全库行(决策 10)。
6. **测试的位置约定**:Haskell 引擎测试全部在 `chusql-engine/test/Spec.hs`;Web 在 `chusql-web/test/Spec.hs`(web 是独立包,不能反向依赖 engine 的测试);Rust 在 `chusql-storage/tests/*_test.rs`,另有 `src/log.rs` 里 3 条单元测试。新增测试放同一处,不另起目录。
7. **只留根目录一个 README**:性能基准的跑法/结果/踩坑都写进 `README.md`;设计长文写 `docs/ENGINE_INTRO.md`、`docs/STORAGE_INTRO.md`,P3 的规格写 `docs/WEB_SPEC.md`。
7. **只留根目录一个 README**:性能基准的跑法/结果/踩坑都写进 `README.md`;设计长文写 `docs/ENGINE_INTRO.md`、`docs/STORAGE_INTRO.md`,CLI 与接口说明写 `docs/COMMANDS.md`。
8. 改任何**决策**或**已知问题**,同一轮内更新 `projectplan.txt`。
---
-18
View File
@@ -10,7 +10,6 @@
| `chusql-storage/` | Rust | 存储引擎:磁盘IO、B+树、缓冲池、WAL、崩溃恢复、并发控制 |
| `chusql-web/` | Haskell + React/TypeScript | Web 管理端:Scotty REST API + VS Code Dark+ 风格数据库 Web IDE |
| `script/` | PowerShell | `chusql.ps1` / `chusql.cmd`:一键启动 / 子命令 / 设置管理 |
| `docs/` | Markdown | 设计长文:ENGINE_INTRO / STORAGE_INTRO / WEB_SPEC |
# 架构分层
@@ -37,23 +36,6 @@
- 事务日志和崩溃恢复
- 并发控制
# 配置
服务端与前端各有一份配置文件,互不影响:
| 文件 | 归属 | 内容 | 读写方式 |
| ------------------------------- | ------------------ | ------------------------------------------------------------------------ | ---------------------------------------- |
| `script/chusql.settings.json` | chusql-web 服务端 | 端口、监听地址、会话、限流、分页上限、账号、存储进程参数 | `chusql.ps1 config set`、`/api/settings` |
| `script/chusql.ui.settings.json`| 前端 IDE(浏览器) | 字体链、字号、行高、Tab 宽度、分页大小、NULL 文本、自动补全、Minimap 等 | `GET` / `PUT /api/ui-settings` |
服务端配置的优先级是 `命令行 > 设置文件 > 环境变量 > 内置默认`;前端配置只有设置文件与内置默认两层。
前端配置由 chusql-web 负责落盘,**不经过 Rust 存储进程**,也不写进 `chusql-storage.toml`。前端在本地
`localStorage` 留一份缓存,后端不可用时(例如开发用的 MockAdapter)自动回退到本地,行为与没有这份配置时一致。
两份文件都是本机专用、不入库(见 `.gitignore`)。`chusql-web/static/` 是 vite 构建产物,同样不入库,
需要时在 `chusql-web/frontend` 下跑 `npm run build` 生成;缺失时依赖它的构建产物契约测试会记为 pending。
# 性能基准
| 指标 | 200 × 200 | 500 × 500 | 1000 × 1000 |
-67
View File
@@ -1,67 +0,0 @@
全链路基准:Haskell 引擎 ←命名管道→ Rust 存储进程
存储进程:../../chusql-storage/target\release\server.exe
管道:chusql-fullchain-145262202226
数据目录:C:\Users\32402\AppData\Local\Temp\chusql-fullchain-145262202226
数据规模:users = 1000 行,orders = 1000 行
计时:墙上时钟(单调);每条语句都走完整链路
[启动] 存储进程就绪,用时 0.05 s
[建表]
CREATE TABLE users 2.3 ms 0 行
CREATE TABLE orders 1.6 ms 0 行
[写入:每条 INSERT 都是一次完整落盘]
1000 条 INSERT INTO users 2949.8 ms 2.950 ms/条
1000 条 INSERT INTO orders 3244.4 ms 3.244 ms/条
[分解:同一条 INSERT 拆成两半,都用原始 IPC,不经过引擎]
CREATE TABLE raw_users 1.9 ms 0 行
list_catalog(取结构) 23.3 ms 0.116 ms/次
原始 IPC insert × 1000 2992.4 ms 2.992 ms/条
[读取与查询:整条语句,含引擎侧的解析与语义检查]
SELECT * FROM users 1.9 ms 1000 行
SELECT name FROM users WHERE age > 90 2.5 ms 90 行
[读取与查询:连接]
JOIN + WHERE(哈希连接) 5.4 ms 90 行
[点查]
lookup_by_index(原始 IPC,按 id) 7.7 ms 0.077 ms/次(命中 100/100)
SELECT ... WHERE id = k(走 Lookup) 0.4 ms 1 行
[批量插入:一条语句带多行,N 行只落一次盘]
CREATE TABLE batch_t 3.0 ms 0 行
多行 INSERT 58.8 ms 0.059 ms/行(100 行/条 × 10 条语句)
[行级删除:代价和删几行无关,只和扫描 + 一次落盘有关]
DELETE FROM users WHERE id = k(1 行) 4.8 ms 0 行
DELETE FROM users(全部) 20.2 ms 0 行
[二级索引:没有索引回退扫描,建完索引走索引]
CREATE TABLE items 2.1 ms 0 行
(先把 1000 行灌进 items:53.2 ms)
SELECT ... WHERE code = k(无索引) 1.8 ms 1 行
CREATE INDEX ON items (code) 9.8 ms 0 行
SELECT ... WHERE code = k(走索引) 0.2 ms 1 行
[数据字典统计]
batch_t 1000 行 索引=id
统计=age:100 id:1000 name:1000
items 1000 行 索引=id code
统计=code:1000 id:1000
orders 1000 行 索引=id
统计=id:1000 product:50 user_id:1000
raw_users 1000 行 索引=id
统计=age:100 id:1000 name:1000
users 0 行 索引=id
统计=age:0 id:0 name:0
[校验]
age > 90 命中 90(按数据分布应为 90 行)
JOIN 命中 90(每个用户恰好 1 张订单,应与上一行相同 = 90)
多行 INSERT 灌进去 1000 行(应为 1000)
二级索引那一行:code = 3501 应该查到 id = 500
[收尾] 停存储进程、清理数据目录
-102
View File
@@ -1,102 +0,0 @@
-- ============================================================================
-- ChuSQL DROP TABLE + 统计信息 手测脚本
-- 用法:
-- 1. 另开终端起 Rust server:cd chusql-storage && cargo run --bin chusql-storage
-- 2. GHCi 里执行::script ghci-scripts/drop-table-test.ghci
-- ============================================================================
:set -XOverloadedStrings
import ChuSQL.Storage
import ChuSQL.Storage.IPC
import ChuSQL.Model
import ChuSQL.Engine
import ChuSQL.Syntax.AST
import ChuSQL.Syntax.Parser
-- 辅助:把一条 SQL 字符串跑到底
let runSql sql = case parseQuery sql of { Left e -> putStrLn ("parse error: " ++ e); Right q -> runIPCStorage (runQueryM q) >>= print }
-- ============================================================================
-- 2. 清场:如果 demo3 存在就删掉
-- ============================================================================
putStrLn ">>> [2] cleanup"
runSql "DROP TABLE demo3"
-- ============================================================================
-- 3. 建表
-- ============================================================================
putStrLn ">>> [3] CREATE TABLE"
runSql "CREATE TABLE demo3 (id INT, name TEXT)"
-- ============================================================================
-- 4. describe:列应为 id/name,行数应为 0
-- ============================================================================
putStrLn ">>> [4] describe (row_count should be 0)"
doDescribeTable "demo3"
-- ============================================================================
-- 5. 空表能扫
-- ============================================================================
putStrLn ">>> [5] scan empty table"
runIPCStorage (scan "demo3")
-- ============================================================================
-- 6. 插 3 行
-- ============================================================================
putStrLn ">>> [6] INSERT 3 rows"
runSql "INSERT INTO demo3 (id, name) VALUES (1, 'Alice')"
runSql "INSERT INTO demo3 (id, name) VALUES (2, 'Bob')"
runSql "INSERT INTO demo3 (id, name) VALUES (3, 'Carol')"
-- ============================================================================
-- 7. describe:行数应为 3
-- ============================================================================
putStrLn ">>> [7] describe (row_count should be 3)"
doDescribeTable "demo3"
-- ============================================================================
-- 8. 扫回三行
-- ============================================================================
putStrLn ">>> [8] scan 3 rows"
runIPCStorage (scan "demo3")
-- ============================================================================
-- 9. SQL SELECT,走索引
-- ============================================================================
putStrLn ">>> [9] SELECT WHERE id = 2"
runSql "SELECT name FROM demo3 WHERE id = 2"
-- ============================================================================
-- 10. 重复建表应报错
-- ============================================================================
putStrLn ">>> [10] CREATE TABLE again (should fail)"
runSql "CREATE TABLE demo3 (x INT)"
-- ============================================================================
-- 11. 删表
-- ============================================================================
putStrLn ">>> [11] DROP TABLE"
runSql "DROP TABLE demo3"
-- ============================================================================
-- 12. 删后再查,应报 unknown table
-- ============================================================================
putStrLn ">>> [12a] scan after drop (should fail)"
runIPCStorage (scan "demo3")
putStrLn ">>> [12b] describe after drop (should fail)"
doDescribeTable "demo3"
-- ============================================================================
-- 13. 删不存在的表应报错
-- ============================================================================
putStrLn ">>> [13] DROP TABLE nope (should fail)"
runSql "DROP TABLE nope"
-- ============================================================================
-- 14. 列出所有表,不应含 demo3
-- ============================================================================
putStrLn ">>> [14] list_tables"
doListTables
putStrLn ">>> done. check chusql-storage/data/ for disk state"
@@ -35,7 +35,6 @@ describe('uiSettings', () => {
sqlLineNumbers: false,
autocomplete: 'yes',
minimap: true,
confirmBeforeCommit: 1,
unknownKey: 5,
}), { status: 200 }));
vi.stubGlobal('fetch', request);
-1
View File
@@ -80,7 +80,6 @@ validateUiSettings (A.Object o) = Map.fromList <$> mapM checkField (KM.toList o)
"sqlLineNumbers" -> pair key <$> boolValue key value
"autocomplete" -> pair key <$> boolValue key value
"minimap" -> pair key <$> boolValue key value
"confirmBeforeCommit" -> pair key <$> boolValue key value
_ -> Left ("unknown setting: " ++ T.unpack key)
pair key value = (key, value)
+1 -1
View File
@@ -1403,7 +1403,7 @@ settingsSpec staticDir = do
-- | 一份完整的合法 IDE 设置请求体
uiSettingsBody :: BL.ByteString
uiSettingsBody = "{\"uiFonts\":[\"JetBrains Mono\",\"Consolas\"],\"gridFonts\":[\"Consolas\"],\"sqlFonts\":[\"Mono\"],\"uiFontSize\":13,\"gridFontSize\":12,\"gridRowHeight\":24,\"sqlFontSize\":13,\"sqlLineHeight\":20,\"sqlTabSize\":2,\"pageSize\":200,\"nullText\":\"NULL\",\"sqlLineNumbers\":true,\"autocomplete\":true,\"minimap\":false,\"confirmBeforeCommit\":true}"
uiSettingsBody = "{\"uiFonts\":[\"JetBrains Mono\",\"Consolas\"],\"gridFonts\":[\"Consolas\"],\"sqlFonts\":[\"Mono\"],\"uiFontSize\":13,\"gridFontSize\":12,\"gridRowHeight\":24,\"sqlFontSize\":13,\"sqlLineHeight\":20,\"sqlTabSize\":2,\"pageSize\":200,\"nullText\":\"NULL\",\"sqlLineNumbers\":true,\"autocomplete\":true,\"minimap\":false}"
-- | 上面那份设置解出来的值
fullUiSettings :: A.Value