瀏覽 1.1.1 文件
1.1.1

Binary DB v0:Snapshot 與內容記錄

展開 Snapshot 父級沿革、Snapshot 連結、Tree、Blob、物件包、manifest 以及可選的檔案快取佈局。

適用對象: 儲存實作者與恢復工具作者

本章定義不可變的內容身份及其物理儲存關係。有序的 parent edge 和歸一化的 Tree 區間是權威,而下文明確點名的那幾類快取則如所述保持可重建或可選。

內容 Snapshot 記錄#

程式碼 · text
CONTENT_SNAPSHOT_RECORD_SIZE = 88

ContentSnapshotRecord — snapshot.bin:
u8  snapshot_meta
u8  history_flags
u16 payload_len
u64 payload_offset
u64 snapshot_hash48
u32 parent_snapshot_index_plus1
u32 root_tree_pack_index_plus1
u32 root_entry_ordinal
u32 line_index_plus1
u8  manifest_hash[32]
u32 file_count
u64 total_bytes
u64 created_at_s

規範的公開 Snapshot ID 是 SNP- 後跟十二個大寫十六進位制字元。 snapshot_hash48 把該字尾存放在它的低 48 位;高 16 位必須為零。非標準的 Snapshot ID 在這個 layout 中無法表示,必須拒絕。

history_flags 屬於固定的 Snapshot schema,不是 payload。位 0 標記一個匯入的 remote-head 歷史邊界:源 Snapshot 至少有一個父節點,但本地匯入有意沒有物化該 head 之前的祖先。這樣的 Snapshot 不是真正的根。位 1 到位 7 保留,必須為零。

有序 Snapshot Parent 記錄#

程式碼 · text
SNAPSHOT_PARENT_EDGE_RECORD_SIZE = 12

SnapshotParentEdgeRecord — snapshot_parent_edge.bin:
u32 child_snapshot_index
u32 parent_snapshot_index
u16 parent_ordinal
u16 flags

ContentSnapshotRecord.snapshot_meta 位 4 置位時, snapshot_parent_edge.bin 中的有序行是該 Snapshot 唯一的 parent 權威。 此時固定欄位 parent_snapshot_index_plus1 只是 ordinal 零的一份經過校驗的 快取:對真正的根或匯入的 remote-head 歷史邊界,它為零,否則必須等於 ordinal 為零那條 edge 的 parent_snapshot_index + 1。Snapshot 的 payload 位元組絕不攜帶 parent 索引。

被接納的 parent 集合最多有 1,024 行。非空集合從 ordinal 零開始,使用連續且不 重複的 ordinal。ordinal 零是顯式 first-parent 遍歷所用的主 parent。子節點不得 引用自身、缺失的 Snapshot、已打墓碑的 Snapshot,也不得構成環。v0 中每個 flags 值都是零。parent 順序不可變,並參與 Snapshot 的 manifest 身份。

history_flags 位 0 置位的 Snapshot 還必須置位 parent_edges_authority、 滿足 parent_snapshot_index_plus1 = 0,且沒有 parent edge 行。parent 遍歷和 first-parent 遍歷在該 Snapshot 處停止。匯出、可達性和祖先證明必須保留這個邊界 區分,不得把本地被截斷的圖當作完整歷史來報告。在源根上、在帶有任何本地 parent 的 Snapshot 上、或者在沒有證據表明源確有 parent 的情況下設定該標誌,屬於損壞, 失敗拒絕。

位 4 未置位的記錄以原有的固定指標作為它完整的"零或一個 parent"權威,並且沒有 parent-edge 行。這個狀態只是為了接納前代 layout-1 generation 作為離線轉換輸入 而存在。新的寫入和新啟用的 generation 對每個存活的 Snapshot(包括根)都使用 edge 權威。同一個 Snapshot 上出現混合權威、payload 中的 parent 擴充套件、不連續的 ordinal、指標與 edge 不一致,或為位 4 未置位的子節點存在 edge,都屬於損壞, 失敗拒絕。

Snapshot 權威是一個 DAG 森林,不是單根樹。存活 Snapshot 數為零的權威是合法的。 每個存活的非邊界 Snapshot 都必須能到達一個被證明的真正的根,但不同的連通分量 可以到達不同的真正的根。前代位 4 未置位、且其完整固定指標為零的記錄證明了一個 真正的根;轉換寫入不帶 parent 行的 edge 權威,並保持 history_flags 為零。 記錄位置、Line 歸屬、分量大小和目前 head 狀態,都不足以允許合併分量,或把一個 真正的根轉成 remote-head 歷史邊界。

程式碼 · text
TASK_SNAPSHOT_INDEX_RECORD_SIZE = 8

TaskSnapshotIndexRecord — task_snapshot_index.bin:
u32 latest_snapshot_link_index_plus1
u16 snapshot_count
u8  next_snapshot_ordinal
u8  reserved0

CHANGE_SNAPSHOT_INDEX_RECORD_SIZE = 8

ChangeSnapshotIndexRecord — change_snapshot_index.bin:
u32 latest_snapshot_link_index_plus1
u16 snapshot_count
u16 reserved0
程式碼 · text
AUTHORITATIVE_SNAPSHOT_LINK_RECORD_SIZE = 40

LocalTaskSnapshotLinkRecord / ServerTaskSnapshotLinkRecord — snapshot_link.bin:
u8  link_meta
u8  snapshot_ordinal
u16 payload_len
u64 payload_offset
u32 task_index
u32 change_index_plus1
u32 content_snapshot_index
u32 previous_task_snapshot_link_index_plus1
u32 previous_change_snapshot_link_index_plus1
u64 created_at_s
程式碼 · text
REMOTE_MIRROR_SNAPSHOT_LINK_RECORD_SIZE = 52

RemoteMirrorTaskSnapshotLinkRecord — snapshot_link.bin:
u8  link_meta
u8  remote_meta
u16 reserved1
u8  snapshot_ordinal
u8  reserved0
u16 payload_len
u64 payload_offset
u32 task_index
u32 change_index_plus1
u32 content_snapshot_index
u32 previous_task_snapshot_link_index_plus1
u32 previous_change_snapshot_link_index_plus1
u64 created_at_s
u64 fetched_at_s

snapshot_ordinal 使用完整的 u8 範圍。值 0..255 渲染為 S-01..S-256。 寫入方必須拒絕 ordinal 255 之後的下一個 link,不得迴繞、截斷、複用,也不得 發明擴充套件的 Snapshot 控制代碼。

Tree 記錄#

程式碼 · text
TREE_PACK_RECORD_SIZE = 32

TreePackRecord — tree_pack.bin:
u8  pack_meta
u8  pack_format_kind
u16 pack_hash_hi16
u32 pack_hash_lo32
u32 first_tree_index
u32 tree_count
u64 total_bytes
u64 created_at_s
程式碼 · text
TREE_RECORD_SIZE = 20

TreeRecord — tree.bin:
u8  tree_meta
u8  reserved0
u32 pack_entry_ordinal
u32 entry_count
u8  tree_hash80[10]
程式碼 · text
TREE_ENTRY_RANGE_RECORD_SIZE = 4

TreeEntryRangeRecord — tree_entry_range.bin:
u32 first_entry_index
程式碼 · text
TREE_ENTRY_RECORD_SIZE = 16

TreeEntryRecord — tree_entry.bin:
u8  entry_meta
u8  name_len
u16 mode_bits
u64 name_offset
u32 target_index

Tree entry 的名字是單個歸一化的 UTF-8 路徑片段,不是完整路徑,且限制為 255 位元組。Blob entry 指向 blob.bin;Tree entry 指向 tree.bin

TreeRecord.pack_entry_ordinal 是提供該 Tree 原始 payload 的那個 Tree pack 歸檔內部確切的物理 entry ordinal。對於 sparse_physical_ordinals 未置位的 Tree Pack,其邏輯區間中的每個 Tree 都滿足 pack_entry_ordinal = tree_index - first_tree_index,且該 ordinal 小於 tree_count。當該位置位時,這個 ordinal 改為確切的稀疏物理歸檔定位符,不必 等於邏輯偏移,也不必小於邏輯上的 tree_count;歸檔邊界、解碼出的 Tree ID 和 解碼出的 entry 數仍然要校驗。

TreeEntryRangeRecord 屬於固定 schema,不是 payload。它的記錄 ordinal 就是 tree_index,並且在每個穩定的啟用邊界上,tree_entry_range.bin 的記錄數與 tree.bin 完全相同。結合所屬的 TreeRecord.entry_countfirst_entry_index 指明該 Tree 在 tree_entry.bin 中權威的、連續的歸一化行。對於空 Tree,規範的 first_entry_index 是目前 tree_entry.bin 的記錄數。該區間必須落在 tree_entry.bin 之內;新的寫入按 Tree 順序追加歸一化的 entry 行,絕不與已提交 Tree 的區間重疊。

歸一化區間對後設資料遍歷具有權威性。物理 pack 定位符對定位和校驗已歸檔的原始 Tree payload 具有權威性。名字、mode、目標種類、目標、Tree ID 和 entry_count 在歸一化區間與解碼出的 pack entry 之間必須一致;不一致屬於損壞,失敗拒絕。

建立 Tree 時先追加並 fsync 它的歸一化 entry 行和 range 依賴,然後才追加 Tree 的提交記錄。恢復流程忽略或截斷孤立的 entry/range 依賴,拒絕已提交 Tree 缺失 range 的情況,並校驗每一個已提交的 range 和物理 pack 定位符。

沒有 tree_entry_range.bin 的前代 layout-1 generation 只能作為離線轉換輸入。 轉換保留已有的 pack_entry_ordinal,從 pack payload 重建並校驗每一個歸一化 區間,並在啟用之前物化出完整的旁路檔案。

Blob 與 object-pack 記錄#

程式碼 · text
OBJECT_PACK_RECORD_SIZE = 32

ObjectPackRecord — object_pack.bin:
u8  pack_meta
u8  pack_format_kind
u16 pack_hash_hi16
u32 pack_hash_lo32
u32 first_member_index
u32 member_count
u64 total_bytes
u64 created_at_s
程式碼 · text
OBJECT_PACK_MEMBER_RECORD_SIZE = 16

ObjectPackMemberRecord — object_pack_member.bin:
u8  member_meta
u8  delta_chain_depth
u16 reserved0
u32 pack_index
u32 blob_index
u32 base_blob_index_plus1
程式碼 · text
BLOB_RECORD_SIZE = 64

BlobRecord — blob.bin:
u8  blob_meta
u8  hash_kind
u16 reserved0
u64 size_bytes
u32 pack_member_index_plus1
u64 created_at_s
u64 pruned_at_s
u8  sha256[32]

Blob 的 SHA-256 以 32 個原始位元組儲存。公開的 BLB-* 身份由前 80 位渲染而來。 object pack 和 Tree pack 記錄以 (pack_hash_hi16, pack_hash_lo32) 存放它們 48 位的公開 ID 字尾。

在被接納的遺留轉換中,完整 32 位元組 SHA-256 相同的多條源 Blob 行,只有在 blob_meta、歸一化後的 hash_kindreserved0size_bytespruned_at_s 都一致時,才會合併成一條目標 Blob。不同的 pack-member 指標是同一內容的物理 副本,每一處 member、base-Blob、Tree-entry 和重建索引的引用都會被稠密重對映。 目標的 created_at_s 取源建立時間中最小的合法非零值。時間為零、後設資料不一致、 大小不一致、prune 不一致、雜湊字首相同但完整 SHA-256 位元組不同的碰撞,或者 位元組與雜湊不匹配,都失敗拒絕。這項歸一化不會新增任何 Blob 別名行或對映檔案。

可選的 manifest 與 file 快取#

這些記錄是可丟棄的本地加速手段,從不具有權威性:

程式碼 · text
SNAPSHOT_FILE_INDEX_RECORD_SIZE = 4

SnapshotFileIndexRecord — snapshot_file_index.bin:
u32 first_file_index_plus1
程式碼 · text
SNAPSHOT_FILE_RECORD_SIZE = 24

SnapshotFileRecord — snapshot_file.bin:
u64 path_hash64
u64 path_offset
u32 tree_entry_index
u16 path_len
u16 reserved0

權威路徑仍然是 snapshot.bin -> tree_pack.bin/tree.bin/ tree_entry.bin -> blob.bin。當所有可選的 manifest/file 快取都不存在時,讀取方 必須仍然正確。

版本權威

對照 1.1.1 原始碼逐條核對

這一頁是公開文件,不是第二份產品契約。要確認發布權威,請以確切的原始碼和分發契約為準。

所屬元件 Snapshot
  • ait-coreSNP-ED7593DBF982
  • ait-serverSNP-0CCD7DD2A077
  • ait-runnerSNP-35C9C133D2EE
  • ait-pythonSNP-756C731A4CC0
  • ait-nodeSNP-55E90D0A81F1