Files
DCTS/docs/database.md
T
fmq cd370d88e7 feat(all): 任务引擎双阶段解耦、僵尸涡旋修复、动态 CPU 配额与前端详情页重构
将 TLUSTY/SYNSPEC 拆为各自独立的 enabled/policy/strategies 阶段,
以策略链自动弹栈取代单级 seed_step 布尔回退;定向修复 2026-08-02
僵尸任务涡旋事故;新增节点并发配额热调;前端详情页从 1412 行巨型
视图拆为薄控制器 + detail 子模块,并补齐工具层与单测。

引擎与调度(task_engine_decoupling_design.md)
- models.rs: 新增 StagePolicy / EngineStageConfig / TaskSpec 阶段字段、
  normalize_compat() 校正旧版在途消息策略链、failed_stage 归因
- scheduler.rs: resolve_dispatchable_chain 派发门控、
  trigger_strategy_fallback 按 failed_stage 精确弹栈;启动期
  force_recompute/skip_converged(默认)/skip_failed 三策略
- db.rs: tasks 表 +7 列持久化阶段配置;终态守卫
  (mark_grid_point_running 仅 pending/queued→running;
  record_task_report 拒绝迟到失败翻黑 converged);策略弹栈快照

僵尸涡旋修复(runbook-20260802-zombie-vortex-fix.md)
- 全链路跨库活性交叉校验:派发/claim/孤儿回收/回退统一查 MQ 队列活性,
  活则放行、死则清僵尸,结构性消除"每点重复派发"
- stop/重启卫生:清队列同步 delete_tasks_by_ids,杜绝遗留 pending 行
- report_task: 幂等吸收 + 409 区分迟到冗余结果,仅 state_changed 时回退
- MQ: NULL workflow_name 回填 __legacy__、requeue 后迟到上报被 403 竞态修复

动态 CPU 配额(dynamic_cpu_slots_design.md)
- admin.rs: POST /admin/nodes/:id/quota(Option<Option<i32>> 区分
  缺字段/显式 null);nodes 表 +admin_max_slots
- worker.rs: effective_max_slots = min(admin, physical),心跳下发原子生效

科学产物保全(tlusty_result_artifacts.md)
- runner.rs: SYNSPEC 启动前快照 fort.12/fort.14 → .bfac/.emflux 防覆盖
- 半失败点(大气收敛+光谱失败)改判 Failed 并写入 note;仅 SYNSPEC
  场景不再恒判失败;撤销归档 LRU 200 上限改为永久保留
- executor.rs: 透传 synspec_params 数值参数(此前固定 None)

前端(dashboard/)
- workflowDetail.js 1412→328 行,拆出 views/detail/{ctx,overview,
  pointsTable,parSets,pointPanel}.js,AbortController 治理监听/请求生命周期
- 删除 wfActions.js,新增 wfEnginePanel.js(双阶段三维配置编辑面板)
- 新增 utils/{errors,format,icons,polling,yamlStage}.js 纯函数模块
- 路由级动态 import 代码分割;节点配额三点菜单 + Modal 管理
- 首次引入 node:test 单测(format/polling/yamlStage/psCache,644 行)
- 系统性补齐 a11y:skip-link、ARIA、Tab 键盘漫游、toast 关闭、退出动画

文档与工具
- 新增 6 篇设计/调研:引擎解耦、动态配额、涡旋 runbook、
  光谱正确性分析、收敛判断、产物归档
- PIPELINE/design/api/database 等协同重写为分布式 C/S 架构口径
- scripts/fetch_results.sh 跨节点产物备份;import_results 按 cno 升序导入
- workflows/sdB_cno.yaml: 新增 tlusty/synspec_stage 配置块,修正 wstart 笔误
2026-08-04 23:40:52 +08:00

232 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DCTS 数据库设计 (Database Schema)
> DCTS 采用轻量级、零配置、高并发安全的 **SQLite** 双数据库架构:主状态库 `dcts.db` 存储网格结构与历史记录;队列库 `dcts_queue.db` 由 `mq` 驱动管理原子任务状态机。
---
## 1. 数据库分库架构
```mermaid
erDiagram
WORKFLOWS ||--o{ GRID_POINTS : contains
GRID_POINTS ||--o{ TASKS : logs
WORKFLOWS ||--o{ WORKFLOW_PROGRESS_SNAPSHOTS : samples
NODES ||--o{ TASK_QUEUE : executes
NODES ||--o| NODE_CREDENTIALS : authenticates
SEEDS }o--o{ GRID_POINTS : hot-starts
subgraph PrimaryDB ["主数据库 (dcts.db)"]
WORKFLOWS {
string name PK
string description
text config_yaml
string status
datetime created_at
datetime updated_at
}
GRID_POINTS {
integer id PK
string name
string workflow_name FK
double teff
double logg
double loghe
double logc
double logn
double logo
double cno_sum
integer wave
string status
integer attempt_count
string success_method
double last_elapsed_sec
}
TASKS {
string task_id PK
string point_name
string node_id
string task_type
string seed_point_name
string status
double max_relc
boolean atmosphere_has_nan
integer retry_count
datetime created_at
datetime started_at
datetime completed_at
string error_message
string workflow_name
boolean tlusty_enabled
string tlusty_policy
text tlusty_strategies
boolean synspec_enabled
string synspec_policy
text synspec_strategies
string atmosphere_ref
double elapsed_sec
}
NODES {
string node_id PK
integer max_slots
integer active_slots
string status
double cpu_usage
double memory_usage
datetime last_heartbeat
string registration_secret
integer admin_max_slots
}
NODE_CREDENTIALS {
string node_id PK
string token_hash
datetime issued_at
integer revoked
string raw_token_pending
}
SEEDS {
integer id PK
string point_name UK
double teff
double logg
double loghe
double logc
double logn
double logo
string file_path
boolean is_clean
}
WORKFLOW_PROGRESS_SNAPSHOTS {
integer id PK
string workflow_name
datetime ts
integer total
integer pending
integer queued
integer running
integer converged
integer failed
}
end
subgraph QueueDB ["队列库 (dcts_queue.db / mq)"]
TASK_QUEUE {
string task_id PK
string payload
string status
datetime created_at
datetime claimed_at
string workflow_name
string claimed_by_node_id
integer wave
}
end
```
---
## 2. 表结构定义 (Schema Specification)
### 2.1 `workflows` (工作流配置表)
存储用户定义的计算网格配置及整体状态。
- `name` (`TEXT PRIMARY KEY`):工作流唯一标志(如 `sdB_cno`)。
- `description` (`TEXT`):描述信息。
- `config_yaml` (`TEXT NOT NULL`):完整的参数网格定义与物理配置 YAML 内容。
- `status` (`TEXT NOT NULL DEFAULT 'idle'`)`idle`(就绪)→ `initializing`(原子抢占加载中)→ `running`(运行中)/ 回退 `idle``running``paused`(暂停)/ `completed`(全部网格点收敛)。
- `created_at` / `updated_at` (`DATETIME NOT NULL`):创建 / 最后更新时间。
### 2.2 `grid_points` (网格点物理参数表)
存储多维笛卡尔积展开后的每一个独立参数点。
- `id` (`INTEGER PRIMARY KEY AUTOINCREMENT`):自增主键。
- `name` (`TEXT NOT NULL`):点物理唯一名(由 6 维参数生成,如 `t35000_g5.5_he-1_c-2_n-2_o-2`)。
- `workflow_name` (`TEXT NOT NULL`):所属工作流。**多工作流分区键**——同一物理点可属于多个工作流,
`name` 共同构成复合唯一约束 `UNIQUE(workflow_name, name)`
- `teff`, `logg`, `loghe`, `logc`, `logn`, `logo` (`REAL NOT NULL`)6 维物理参数。
- `cno_sum` (`REAL NOT NULL`)CNO 丰度之和(调度排序用)。
- `wave` (`INTEGER NOT NULL DEFAULT 0`):按 cno_sum 分组的批次波次(调度优先级用)。
- `status` (`VARCHAR(32)`)`pending` / `queued` / `running` / `converged` / `failed`
- `attempt_count` (`INTEGER`):失败重试计数(仅观测用)。
- `success_method` (`VARCHAR(32)`):收敛时的成功手段 (`cold_run` 冷启动成功 / `seed_step` 种子步进成功 / `imported` 历史导入)。
- `last_elapsed_sec` (`REAL`):最近一次尝试的墙钟耗时(详情页 ETA 估算用,兼容旧数据回退)。
> **多工作流分区(per-workflow partitioning**`grid_points` 与 `task_queue` 均按 `workflow_name` 隔离。
> 调度、状态更新、stale 重投、`stop_workflow` 重置都限定在单个工作流内,互不影响。
> 历史旧库(无 `workflow_name` 列)在启动时自动迁移:表重建为复合唯一结构,旧行 `workflow_name`
> 标记为 `__legacy__`,不干扰新工作流查询。
### 2.3 `tasks` (任务尝试记录表)
每次派发/尝试生成一行,记录任务的阶段配置快照与执行结果(详情页/归因/回退弹栈的数据源)。
- `task_id` (`VARCHAR(128) PRIMARY KEY`):任务 IDUUID)。
- `point_name` (`TEXT NOT NULL`):网格点权威名(源精度,非 params 重推)。
- `node_id` (`TEXT`):执行节点 ID。
- `task_type` (`VARCHAR(32)`):兼容字段,等于 `tlusty_strategies[0]``cold_run` / `seed_step`),供旧节点识别。
- `seed_point_name` (`TEXT`):种子步进时注入的近邻种子点(`GET /api/seed/<name>` 下载依据)。
- `status` (`VARCHAR(32)`)`pending` / `claimed` / `running` / `completed` / `failed` / `timeout`
- `max_relc` (`REAL`):最终最大相对变化(收敛判据量)。
- `atmosphere_has_nan` (`BOOLEAN`):最终大气是否含 >10% NaN 行(无效化标记)。
- `retry_count` (`INTEGER`):重试计数。
- `created_at` / `started_at` / `completed_at` (`DATETIME`):创建 / 开始 / 完成时间。
- `error_message` (`TEXT`):失败原因(含 synspec 错误/超时等)。
- `workflow_name` (`TEXT`):所属工作流(多工作流分区键)。
- **阶段独立配置快照(派发时落库)**:`tlusty_enabled` (`BOOLEAN`)、`tlusty_policy` (`TEXT`)、
`tlusty_strategies` (`JSON`)、`synspec_enabled` (`BOOLEAN`)、`synspec_policy` (`TEXT`)、
`synspec_strategies` (`JSON`)、`atmosphere_ref` (`TEXT`,显式大气来源点)。
回退时弹 `*_strategies` 链首(见 `task_engine_decoupling_design.md §4.2`),policy/策略链取派发时快照。
- `elapsed_sec` (`REAL`):任务墙钟耗时(详情页 ETA 估算优先用此值)。
### 2.4 `nodes` (计算节点心跳与状态表)
- `node_id` (`TEXT PRIMARY KEY`):节点唯一标识(未指定 `DCTS_NODE_ID` 时自动生成 `node-<uuid>`)。
- `max_slots` (`INTEGER NOT NULL`):节点声明的最大并发计算槽位数(即 `DCTS_MAX_SLOTS`,领用上限)。
- `active_slots` (`INTEGER NOT NULL DEFAULT 0`):当前正在执行的任务数,随 claim 自增、report 完结自减。
- `status` (`VARCHAR(32) NOT NULL DEFAULT 'online'`)`pending_approval`(注册待审批)/ `online`(在线)/ `offline`(心跳超时离线)/ `disabled`(管理员手动停用,保持心跳但不再分发任务)/ `rejected`
- `cpu_usage` / `memory_usage` (`REAL NOT NULL DEFAULT 0.0`):心跳上报的 CPU/内存使用率(仅观测展示用,**不参与任务分发决策**)。
- `last_heartbeat` (`DATETIME NOT NULL`):最后一次心跳上报时间,后台线程据此判定 `online → offline`
- `registration_secret` (`TEXT`):节点注册时下发的一次性凭据,用于 `/node/check_status` 取走专属 token 的二次鉴权。
- `admin_max_slots` (`INTEGER`,可空):管理员强制并发槽位配额(`NULL` = 无限制,沿用物理 `max_slots`),经心跳响应下发给节点动态生效。
### 2.5 `node_credentials` (节点 L2 鉴权凭据表)
- `node_id` (`TEXT PRIMARY KEY`):关联 `nodes.node_id`
- `token_hash` (`TEXT NOT NULL`):节点专属 token 的 SHA-256 哈希(**不存明文**)。
- `issued_at` (`DATETIME NOT NULL`):颁发时间。
- `revoked` (`INTEGER NOT NULL DEFAULT 0`):吊销标记(重新颁发 token 时旧行吊销)。
- `raw_token_pending` (`TEXT`):暂存待确认的明文 token(颁发流程过渡用,确认后清除)。
### 2.6 `seeds` (种子缓存池表)
全局共享的已收敛大气 `.7` 索引(跨工作流复用,种子步进热启动数据源)。
- `id` (`INTEGER PRIMARY KEY AUTOINCREMENT`)。
- `point_name` (`TEXT UNIQUE NOT NULL`):种子点权威名(源精度,与磁盘文件名一致)。
- `teff`, `logg`, `loghe`, `logc`, `logn`, `logo` (`REAL NOT NULL`):6 维物理参数(种子匹配距离计算用)。
- `file_path` (`TEXT NOT NULL`)`.7` 大气文件在 `seeds_dir` 的路径。
- `is_clean` (`BOOLEAN NOT NULL DEFAULT 1`):大气是否干净(无 NaN)——仅干净种子可被匹配(`reload_seed_cache` 只加载 `is_clean=1`)。
> 运行期维护内存 `seed_cache` + `seed_index`exact_family 桶索引),`find_best_seed_from_db`
> 先查桶索引(O(1)~O(小)),未命中退化为全量 global 扫描(见 `seed_finder.rs` / `design.md §3`)。
### 2.7 `workflow_progress_snapshots` (工作流进度时间序列表)
后台定期(每分钟)为每个 running 工作流记录进度计数,供详情页进度曲线与 ETA 估算。
- `id` (`INTEGER PRIMARY KEY AUTOINCREMENT`)。
- `workflow_name` (`TEXT NOT NULL`)。
- `ts` (`DATETIME NOT NULL DEFAULT (datetime('now'))`):采样时间。
- `total` / `pending` / `queued` / `running` / `converged` / `failed` (`INTEGER NOT NULL`):该时刻各状态计数。
### 2.8 `task_queue` (分布式任务队列表 - `mq`)
驱动分布式抢占与超时重试的核心表,使用 SQLite `WAL` 模式确保高吞吐并发安全(详见 [`sqlite_queue.rs`](file:///home/fmq/program/tlusty/tl208-s54/dcts/crates/mq/src/sqlite_queue.rs#L65))。
- `task_id` (`VARCHAR(128) PRIMARY KEY`):任务 IDUUID)。
- `payload` (`TEXT NOT NULL`):序列化的 [`TaskSpec`](file:///home/fmq/program/tlusty/tl208-s54/dcts/crates/common/src/models.rs)(含 point_name / params / task_type / seed_point_name / workflow_name / tlusty_config / synspec_config 等)。
- `status` (`TEXT NOT NULL`)`pending`(就绪待领用)/ `claimed`(已被某 node 领用,计算中)。
- `created_at` (`DATETIME NOT NULL`):推入队列时间(同 `wave` 内 FIFO 排序键)。
- `claimed_at` (`DATETIME`):被领用的时间戳(`requeue_stale_tasks` 据此判定超时回投)。
- `workflow_name` (`TEXT`):所属工作流(多工作流分区键)。
- `claimed_by_node_id` (`TEXT`):领用方节点 IDclaim 时写入,report 阶段据此校验归属,防跨节点伪造)。
- `wave` (`INTEGER NOT NULL DEFAULT 0`):难度波次(`pop_task` 出队第一排序键,低 `wave` 优先)。
> 任务完成后由 `remove_task` 直接从本表删除(不保留 `completed`/`failed` 终态行),历史记录落在主库 `tasks` 表。超时的 `claimed` 行由 [`requeue_stale_tasks`](file:///home/fmq/program/tlusty/tl208-s54/dcts/crates/mq/src/sqlite_queue.rs#L274) 改回 `pending` 重投。
---
## 3. 并发与事务安全设计
1. **WAL (Write-Ahead Logging) 模式**SQLite 连接自动启用 `PRAGMA journal_mode=WAL;``PRAGMA busy_timeout=15000;`,解决多线程/多进程读写锁竞争。
2. **连接池机制**:借助 `r2d2` + `r2d2_sqlite` 维护异步连接池,防止高并发下数据库句柄冲突。
3. **原子 Claim 事务**:任务抢占在单个 `IMMEDIATE` 事务内完成——先 `SELECT ... WHERE status='pending' ORDER BY wave ASC, created_at ASC LIMIT 1` 取队首,再 `UPDATE SET status='claimed', claimed_by_node_id=?`,提交后返回。事务保证同一任务不会被两个 node 同时领用;遇到 `SQLITE_BUSY/LOCKED` 最多退避重试 5 次(详见 [`pop_task`](file:///home/fmq/program/tlusty/tl208-s54/dcts/crates/mq/src/sqlite_queue.rs#L145))。
4. **凭据零明文存储**`node_credentials.token_hash` 只存 SHA-256 哈希;节点注册的一次性 `registration_secret` 也仅在审批前短期有效,避免数据库泄漏直接泄露有效 token。