docs: 总体架构 V14 — FrameDataStore 内存回放双层存储设计
This commit is contained in:
parent
6098186f34
commit
bc8b401ef6
@ -1,8 +1,9 @@
|
||||
# 反无人机仿真系统 — 总体架构设计
|
||||
|
||||
> **版本**:V13
|
||||
> **日期**:2026-06-16
|
||||
> **状态**:已实现(探测实时链路 + 3D 球冠待实现)
|
||||
> **版本**:V14
|
||||
> **日期**:2026-06-17
|
||||
> **状态**:已实现
|
||||
> **变更**:V14 新增 DataService 基础数据 CRUD + FrameDataStore 内存回放架构
|
||||
> **Unity 版本**:22.3.62
|
||||
> **.NET 版本**:.NET Standard 2.1
|
||||
> **变更**:V13 探测行为决策固化——5 项规则确认(回退 Undetected / 融合取最早-同刻取精度高 / 不影响 FireSchedule / 盲区仅可视化 / 3D 球冠);新增 14.2.1 三维球冠几何(IsInCoverage)+ 14.7 数据模型变更清单;EquipmentDeployment 表加 4 个 3D 探测字段;DetectionSource 同步扩展
|
||||
@ -1257,38 +1258,46 @@ public interface IDefensePlanner
|
||||
|
||||
### 7.1 FrameDataStore 实现
|
||||
|
||||
`FrameDataStore` 是**具体类**(非接口),采用内存缓存 + 仿真结束批量落库策略,避免每帧磁盘 IO:
|
||||
`FrameDataStore` 采用**双层存储**架构:仿真期间内存缓冲 → 仿真结束保留 LiveFrames 副本 + 批量写入 SQLite:
|
||||
|
||||
```csharp
|
||||
/// <summary>帧数据存储 — 内存缓存,仿真结束时批量写入 SQLite</summary>
|
||||
public class FrameDataStore
|
||||
{
|
||||
void BeginRecording(string taskId); // 仿真启动:清空缓冲区
|
||||
void RecordFrame(int frameIdx, float timestamp, // 每 Tick:仅写内存缓冲(零字符串分配)
|
||||
List<EntitySnapshot> snapshots);
|
||||
void Flush(); // 仿真结束:序列化 JSON + 单次事务批量入库
|
||||
void Discard(); // 丢弃未落库的缓冲
|
||||
List<SimFrameRecord> ReadFrames(string taskId, int fromFrame, int toFrame); // 回放读
|
||||
void DeleteTaskDb(string taskId);
|
||||
int CleanupExpired(); // TTL 清理(按 RetentionDays,默认 180 天)
|
||||
int BufferedFrameCount { get; } // 已缓冲帧数
|
||||
// 内存回放:Flush 后保留副本,供回放直接读取(零磁盘 IO)
|
||||
public List<SimFrameRecord> LiveFrames { get; private set; }
|
||||
|
||||
void BeginRecording(string taskId); // 清空 buffer + LiveFrames
|
||||
void RecordFrame(...); // 仅写内存 List<FrameRecord>
|
||||
void Flush(); // 序列化 → LiveFrames 副本 + SQLite 入库
|
||||
void Discard(); // 清空 buffer + LiveFrames
|
||||
List<SimFrameRecord> ReadFrames(...); // 从 SQLite 读(历史仿真回放)
|
||||
}
|
||||
```
|
||||
|
||||
> **关键设计**:`RecordFrame` 在仿真热路径上**只搬强类型标量字段**(位置/血量/云团半径等)到内存 `List<FrameRecord>`,不做任何 JSON 拼接。JSON 序列化推迟到 `Flush` 一次性完成(详见第十四章性能设计)。
|
||||
**LiveFrames 生命周期**:
|
||||
```
|
||||
仿真运行 → Flush() → LiveFrames = 当前仿真数据(同时写 SQLite)
|
||||
↓
|
||||
回放:优先取 LiveFrames(内存,快)
|
||||
↓
|
||||
新仿真开始 → BeginRecording() → LiveFrames.Clear()
|
||||
↓
|
||||
如需回放旧仿真 → 回退读 SQLite
|
||||
```
|
||||
|
||||
### 7.2 录制
|
||||
|
||||
- 仿真启动时 `BeginRecording` 清空内存缓冲区
|
||||
- 仿真启动时 `BeginRecording` 清空内存缓冲区和 LiveFrames
|
||||
- 录制帧率 = 仿真 TickRate(每想定可配置,默认 20Hz)
|
||||
- 每 Tick 调用 `RecordFrame()`,仅追加到内存 `List<FrameRecord>`,零磁盘 IO、零字符串分配
|
||||
- 仿真结束 `Flush()`:序列化为 `SimFrameRecord` + 单事务 `InsertAll` 批量写入 `frames/{taskId}.db`
|
||||
- 仿真事件 `SimEvent` 直接写入主库 `main.db`(每任务 ~30 条,轻量)
|
||||
- 仿真结束 `Flush()`:序列化为 `SimFrameRecord` → 保留 `LiveFrames` 副本 → 单事务 `InsertAll` 写入 SQLite
|
||||
- 仿真事件 `SimEvent` 直接写入主库 `main.db`
|
||||
|
||||
### 7.3 回放
|
||||
|
||||
- ReplayController 协程驱动
|
||||
- 打开 `frames/{taskId}.db`,按 FrameIndex 范围查询
|
||||
- `ReplayController.LoadReplay(taskId, frameStore)` 双路径:
|
||||
- 传入 `frameStore` 且 `LiveFrames` 非空 → 直接使用内存数据(仿真刚结束,零延迟)
|
||||
- 否则 → 从 `frames/{taskId}.db` 读取(历史仿真)
|
||||
- WHERE FrameIndex BETWEEN a AND b 命中索引,毫秒级
|
||||
- 回放帧率由前端控制(可与录制不同)
|
||||
- 支持暂停 / 快进 / 后退 / 跳转
|
||||
|
||||
Loading…
Reference in New Issue
Block a user