# 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 tlusty_success_method string synspec_success_method double last_elapsed_sec } TASKS { string task_id PK string point_name string node_id 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 string failed_stage text summary_json } 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 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 completed 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` / `completed` / `failed`(7c 由 `converged` 改名,M9 迁移)。 - `attempt_count` (`INTEGER`):失败重试计数(仅观测用)。 - `tlusty_success_method` (`VARCHAR(32)`):**大气收敛归因**(P9 拆分)——TLUSTY 阶段以何策略收敛 (`cold_run` 冷启动成功 / `seed_step` 种子步进成功 / 策略名);TLUSTY 禁用(synspec-only)为 NULL。 Phase 6 起由 `tlusty_strategies[0]` 派生。整体归因由消费方派生(`tlusty ?? synspec`)。 - `synspec_success_method` (`VARCHAR(32)`):**光谱收敛归因**(Phase 5a)——synspec 阶段以何策略收敛 (如 `standard`);TLUSTY-only 成功为 NULL。解锁"光谱以 standard 等策略收敛了多少点"的统计与过滤。 - `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`):任务 ID(UUID)。 - `point_name` (`TEXT NOT NULL`):网格点权威名(源精度,非 params 重推)。 - `node_id` (`TEXT`):执行节点 ID。 - `seed_point_name` (`TEXT`):种子步进时注入的近邻种子点(`GET /api/seed/` 下载依据)。 **双义**:SYNSPEC-only(TLUSTY 关闭)时恒为 NULL(大气来源见 `atmosphere_ref`)。 - `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 估算优先用此值)。 - `failed_stage` (`TEXT`):失败阶段归因(`"tlusty"` / `"synspec"`;旧节点/旧行 NULL → 服务端兜底按 TLUSTY 归因)。 - `summary_json` (`TEXT`):完整 `ModelSummary` JSON(含 `synspec_rc`/`synspec_error`/`synspec_sec` 与各子步骤摘要); 错误路径为 `{"error": ...}`。**全量保真**(Phase 5b 起):逐次 itek 迭代诊断 (`itek_history: [{iter, max_relc, n_depths}]`)随 summary_json 落库,与 conv.json 同源。 ### 2.4 `nodes` (计算节点心跳与状态表) - `node_id` (`TEXT PRIMARY KEY`):节点唯一标识(未指定 `DCTS_NODE_ID` 时自动生成 `node-`)。 - `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`):颁发时间。 - `raw_token_pending` (`TEXT`):暂存待确认的明文 token(颁发流程过渡用,确认后清除)。 > token 失效靠重发覆盖 `token_hash`(旧 hash 不存在 → 鉴权失败),无独立吊销标记; > 历史 `revoked` 死列已由迁移 M4 清除(Phase 4)。 ### 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` / `completed` / `failed`(7c 由 `converged` 改名,M9 迁移) (`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`):任务 ID(UUID)。 - `payload` (`TEXT NOT NULL`):序列化的 [`TaskSpec`](file:///home/fmq/program/tlusty/tl208-s54/dcts/crates/common/src/models.rs) (含 point_name / params / seed_point_name / workflow_name / tlusty_config / synspec_config 等; Phase 6 起无 `task_type` 字段,执行链由 `tlusty_config.strategies[0]` 派生)。 - `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`):领用方节点 ID(claim 时写入,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。