架構
本頁說明 ToriiDB 如何路由指令、儲存 entry、協調並行存取及持久化資料。
系統概覽
graph TB
A[REPL 用戶端] --> B[Store 或 Session]
B --> C[Exec 路由器]
C --> D[鍵值指令]
C --> E[JSON 欄位指令]
C --> F[查詢指令]
C --> G[向量指令]
D --> H[目前資料庫 0-15]
E --> H
F --> H
G --> H
H --> I[記憶體 Entry Map]
I --> J[AOF]
I --> K[逐鍵 JSON 檔案]
G --> L[OpenAI Embedder]
L --> M[內部向量快取]
M --> H
元件
| 元件 | 原始碼 | 職責 |
|---|---|---|
| REPL | cmd/test/main.go |
讀取指令、顯示目前資料庫,並把輸入轉交給 Exec |
| Store 生命週期 | core/store/store.go |
建立 16 個資料庫、session、清理計時器與關閉壓縮流程 |
| 指令路由器 | core/store/exec.go |
解析指令 token,分派鍵值、欄位、TTL、查詢與向量操作 |
| Entry 引擎 | core/store/set.go |
偵測值型別,並同步原始值、解析後 JSON、中繼資料與向量 |
| 持久化 | core/store/aof.go |
追加 AOF 記錄、啟動時重播狀態,以及壓縮日誌 |
| 查詢引擎 | core/store/find.go, query.go, filter/ |
掃描基本值並計算 JSON 篩選表達式 |
| 向量引擎 | core/store/vector.go, vcache.go, vsearch.go, vsim.go |
編碼與快取 embedding,並執行餘弦相似度搜尋 |
Store 與資料庫生命週期
store.New() 會建立一個 Store,其中包含資料庫 0 到 15 的槽位。每個資料庫都有獨立的 sync.RWMutex、map[string]*Entry、目錄、AOF handle 與延遲載入 guard。資料庫檔案要等到首次存取或寫入時才會開啟。
Session 共用同一組資料庫陣列、embedder 與背景工作 wait group,但保有自己的目前資料庫索引。Select 只會改變該 session 的索引。
清理計時器每分鐘執行一次,從已載入資料庫移除過期 entry。Close 會等待向量附加工作完成、取消清理程序,並行壓縮所有已載入資料庫。
指令資料流
- REPL 將輸入字串傳給
Exec。 Exec使用strings.Fields切分輸入並選擇指令 handler。- 適用時,點記法鍵值會拆成頂層鍵與巢狀 JSON 路徑。
- Handler 載入目前資料庫並取得讀鎖或寫鎖。
- 寫入 handler 更新記憶體 entry、逐鍵 JSON 檔及 AOF。
Exec將 handler 結果轉成命令列回應格式。
函式庫呼叫端也可略過 Exec,直接呼叫提升到 Store 或 Session 的方法。
儲存模型
| 層級 | 表示方式 | 行為 |
|---|---|---|
| 記憶體 | 每個資料庫一份 map[string]*Entry |
由資料庫 mutex 保護的主要執行期狀態 |
| AOF | <root>/db_N/record.aof |
資料庫載入時重播的逐行 JSON 記錄 |
| Entry 檔案 | <root>/db_N/xx/yy/zz/<md5>.json |
透過暫存檔與 rename 原子寫入的完整序列化 entry |
| 向量快取 | __torii:embed:<sha256> entry |
依 model、dimension 與 text 儲存具決定性的 embedding |
預設根目錄為 ./temp;呼叫端可將其他根目錄傳給 store.New(path)。三層 entry 檔路徑由鍵值的 MD5 雜湊推導。
AOF 重播與壓縮
AOF 記錄包含 timestamp、command、key、選用的 value、選用的 expiration,以及選用的 base64 編碼 vector。重播會重建記憶體 entry、還原過期設定與向量,並為 JSON 值預熱 parsed cache。
當日誌大小達到「載入後 baseline 與 1 MiB 較大者」的兩倍時會觸發壓縮。壓縮會為每個仍有效的 entry 寫入一筆目前的 SET 記錄,並丟棄過期或已被取代的歷史。關閉時也會壓縮各個已載入資料庫。
並行與快取不變量
- 資料庫 map、entry 修改與 parsed JSON object 都由各資料庫 mutex 保護。
parseAndCache會修改 parsed cache,只能在寫鎖下或單執行緒重播期間使用。cached為純讀取,使用期間會持續持有讀鎖。- JSON 寫入路徑呼叫
setParsed,讓原始值與解析後 object 保持同步。 - Entry 檔案使用
Entry.JSON()序列化,確保包含未匯出的原始值。 - Embedding HTTP 請求不持有資料庫鎖;之後才在寫鎖下附加,而且只在 entry value 仍與嵌入文字相符時寫入。
過期與內部鍵值
點查詢會把過期 entry 視為不存在,並可能延遲移除。掃描操作會略過過期 entry,不將其回傳。週期性清理程序會移除已載入資料庫中的過期檔案。
以 __torii: 開頭的鍵值保留給內部 embedding cache entry。KEYS、FIND、QUERY 與 VSEARCH 等掃描型指令會隱藏它們,但點操作仍可用於除錯。