本文件將說明元件檢查檔案格式 (檢查格式)。
採用「檢查格式」設定的檔案稱為「檢查檔案」。
這類檔案的副檔名通常為 .inspect
。
關於如何變更格式的資訊。請參閱 擴充檢查檔案格式
總覽
元件檢查提供各種元件, 並在執行階段公開各個狀態的結構化資訊。
元件會使用「檢查」功能代管對應的虛擬記憶體物件 (VMO) 請採用此格式,公開包含此內部狀態的檢查階層。
檢查階層由包含類型 Properties 的巢狀 Nodes 組成。
目標
本文件所述的檢查格式目標如下:
對資料的低負擔變動
檢查檔案格式可就地變更資料。舉例來說: 整數遞增的負擔為約 2 個原子遞增量。
支援非靜態階層
儲存在檢查檔案中的階層可在以下位置修改: 執行階段。您可以在階層架構中新增或移除子項 讓應用程式從可以最快做出回應的位置 回應使用者要求透過這種方式,階層可以密切反映 新增多個物件
單一寫入者、多個讀取器並行,沒有明確同步
與寫入者同時作業的讀取器對應 VMO,並嘗試 拍攝資料的快照寫作者表示自己位於重要部分 但不需要明確同步處理的產生計數器 才能獲得更棒的參與讀取器會使用生成計數器, VMO 的快照一致,且可在安全的情況下讀取
元件終止後,資料可能還會繼續提供
讀取器可能維持包含檢查資料的 VMO 控制代碼 停止。
術語
本節定義本文件中使用的常見術語。
- 檢查檔案 - 使用本文件所描述格式的限定位元組序列。
- 檢查 VMO - 儲存在虛擬記憶體物件 (VMO) 中的檢查檔案。
- 封鎖 - 檢查檔案的大小部分。區塊會有索引和訂單。
- 索引 - 特定區塊的專屬識別碼。
byte_offset = index * 16
- 順序 - 給定的區塊大小,與下限之間進行位元偏移
大小
size_in_bytes = 16 << order
。將區塊分為 類別。 - 節點 - 階層中的具名值,其他值可能包含 多層次是巢狀結構只有節點可以是階層中的父項。
- 屬性 - 包含輸入資料的已命名值 (例如「字串」、「 整數)。
- 階層 - 節點的樹狀結構,從單一「根」依遞減順序排列節點, 都含有 Properties 物件檢查檔案內含 單一階層
本文件使用 RFC 2119 中定義的「必須」、「應/建議」和「可能」關鍵字
所有位元欄位的圖表皆按小端排列順序儲存。
版本
目前版本:2
- 版本 2 可將值名稱設為 NAME 或 STRING_REFERENCE。
阻攻次數
檢查檔案會分割成多個 Blocks
,大小必須為
的 2 次方。
區塊大小下限必須為 16 個位元組 (MIN_BLOCK_SIZE
),且
區塊大小上限須為 16 位元組的倍數。實作者是
建議指定小於網頁大小的區塊大小上限
(通常是 4096 個位元組)。在我們的參考實作中
區塊大小為 2048 個位元組 (MAX_BLOCK_SIZE
)。
所有區塊都必須對齊 16 位元組的邊界,且不得在
VMO 會依據索引計算,並指定 16 位元組偏移 (offset =
index * 16
)。
我們使用 24 位元建立索引,因此檢查檔案的大小最多為 256 MiB。
block_header
包含 16 個位元組,如下所示:
.---------------------------------------------------------------.
| |1|1|1|1|1|2|2|2|2|2|3|3|3|3|3|4|4|4|4|4|5|5|5|5|5|6|6|
|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|
|---+---+-------+-----------------------------------------------|
| O | R | Type | |
|---------------------------------------------------------------|
| |
'---------------------------------------------------------------'
O = Order
R = Reserved, must be 0
The rest (left blank) depends on the payload
每個區塊都有 order
,並指定其大小。
如果區塊大小上限為 2048 個位元組,則會有 8 個可能的區塊
訂單 (NUM_ORDERS
),編號 0...7,與大小區塊對應
16、32、64、128、256、512、1024 和 2048 個位元組。
每個區塊也都有類型,可用於決定 系統會解讀區塊中的位元組。
夥伴分配
這種區塊版面配置允許使用夥伴版面配置,有效率地分配區塊 分配。建議使用 Buddy 分配 但這不是使用檢查格式的必要條件
類型
所有支援的類型都已定義於 //zircon/system/ulib/inspect/include/lib/inspect/cpp/vmo/block.h 可分為以下類別:
列舉 | value | 類型名稱 | 類別 |
---|---|---|---|
kFree |
0 | FREE |
內部 |
kReserved |
1 | RESERVED |
內部 |
kHeader |
2 | HEADER |
標頭 |
kNodeValue |
3 | NODE_VALUE |
值 |
kIntValue |
4 | INT_VALUE |
值 |
kUintValue |
5 | UINT_VALUE |
值 |
kDoubleValue |
6 | DOUBLE_VALUE |
值 |
kBufferValue |
7 | BUFFER_VALUE |
值 |
kExtent |
8 | EXTENT |
範圍 |
kName |
9 | NAME |
名稱 |
kTombstone |
10 | TOMBSTONE |
值 |
kArrayValue |
11 | ARRAY_VALUE |
值 |
kLinkValue |
12 | LINK_VALUE |
值 |
kBoolValue |
13 | BOOL_VALUE |
值 |
kStringReference |
14 | STRING_REFERENCE |
參考資料 |
內部 - 這些類型是用來導入封鎖分配功能。 讀者必須略過這些內容
標頭:這個類型可讓讀者偵測「檢查檔案」和原因 像是快照一致性這個區塊必須存在於索引 0。
值 - 這些類型會直接顯示在階層中。值必須具有「Name」(名稱) 以及父項 (必須是
NODE_VALUE
)。Extent:這個類型會儲存可能無法在單一區塊中的長二進位資料。
名稱 - 這個類型會儲存單一區塊內的二進位資料。 通常用於儲存值的名稱
參照:這個類型會保留其他區塊可參照的單一標準值。
每種型別會以不同方式解讀酬載,如下所示:
- 免費
- 已預訂
- 標頭
- 常用值欄位
- NODE_VALUE
- INT_VALUE
- UINT_VALUE
- DOUBLE_VALUE
- BUFFER_VALUE
- 接近
- 名稱
- 選單
- ARRAY_VALUE
- 連結
- BOOL_VALUE
- STRING_REFERENCE
免費
.---------------------------------------------------------------.
| |1|1|1|1|1|2|2|2|2|2|3|3|3|3|3|4|4|4|4|4|5|5|5|5|5|6|6|
|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|
|---+---+-------+-----------------------+-----------------------|
| O | R | Type | Next free block | |
|---------------------------------------------------------------|
| |
'---------------------------------------------------------------'
O = Order
R = Reserved, must be 0
Type = 0
Next free block = index (optional)
可供分配的 FREE
區塊。值得注意的是
區塊 (16 位元組 \0
) 會解讀為順序 0 的 FREE
區塊。
因此緩衝區只需歸零,即可釋放所有區塊。
寫入器實作時可能會使用 FREE
8..63 中未使用的位元
並基於任何目的加以封鎖寫入器實作時,必須設定所有其他未使用的項目
介於 0 至 0 之間。
建議撰寫者使用上述指定位置來儲存
相同訂單下一個免費區塊的索引。只要使用這個欄位
免費區塊可建立相互連結且各大小的免費區塊清單
以便快速分配當 NextFreeBlock 時可到達清單結尾
指向的地點不是「FREE
」或非相同訂單
(通常是索引 0 的「標頭」區塊)。
已預約
.---------------------------------------------------------------.
| |1|1|1|1|1|2|2|2|2|2|3|3|3|3|3|4|4|4|4|4|5|5|5|5|5|6|6|
|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|
|---+---+-------+-----------------------------------------------|
| O | R | Type | |
|---------------------------------------------------------------|
| |
'---------------------------------------------------------------'
O = Order
R = Reserved, must be 0
Type = 1
RESERVED
模塊可以輕鬆變更為不同的
類型。這是一種選擇的轉場狀態,也就是
封鎖及設定其型別,這有助於檢查
(確保即將使用的區塊)
未視為免費)。
標頭
.---------------------------------------------------------------.
| |1|1|1|1|1|2|2|2|2|2|3|3|3|3|3|4|4|4|4|4|5|5|5|5|5|6|6|
|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|
|---+---+-------+---------------+-------------------------------|
| O | R | Type | Version | Magic number |
|---------------------------------------------------------------|
| Generation count |
|-------------------------------+-------------------------------|
| Size in bytes | Unused |
|---------------------------------------------------------------|
| |
'---------------------------------------------------------------'
O = Order
R = Reserved, must be 0
Type = 2
Version = 2
Magic number = "INSP"
檔案開頭必須有一個 HEADER
區塊,流程
魔術數值 (以下簡稱「INSP」) 的「版本」 (目前為 2),
並行控制和 VMO 部分大小的產生次數
以位元組為單位分配資料標頭的第一個位元組必須是有效
ASCII 字元。
請參閱下一節,瞭解並行控制必須如何 以產生計算結果
NODE_VALUE 和 TOMBSTONE
.---------------------------------------------------------------.
| |1|1|1|1|1|2|2|2|2|2|3|3|3|3|3|4|4|4|4|4|5|5|5|5|5|6|6|
|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|
|---+---+-------+-----------------------+-----------------------|
| O | R | Type | Parent index | Name index |
|---------------------------------------------------------------|
| Reference count (optional) |
'---------------------------------------------------------------'
O = Order
R = Reserved, must be 0
Type = {3,10}
節點是進一步巢狀的錨點,以及 ParentID
欄位
的值只能參照 NODE_VALUE
類型的區塊。
NODE_VALUE
區塊支援選用的參照計數和爆炸式
允許有效率的實作方式,如下所示:
Refcount
欄位可能包含參照指定的值的數量
NODE_VALUE
做為其家長。刪除時,NODE_VALUE
會成為新的
特殊類型 TOMBSTONE
只有當TOMBSTONE
的設定檔出現時,系統才會刪除
Refcount
為 0。
這可讓不需要明確地編寫程式碼的編寫工具進行實作 持續追蹤節點的子項,並防止下列情況發生:
// "b" has a parent "a"
Index | Value
0 | HEADER
1 | NODE "a", parent 0
2 | NODE "b", parent 1
/* delete "a", allocate "c" as a child of "b" which reuses index 1 */
// "b"'s parent is now suddenly "c", introducing a cycle!
Index | Value
0 | HEADER
1 | NODE "c", parent 2
2 | NODE "b", parent 1
{INT,UINT,DOUBLE,BOOL}_VALUE
.---------------------------------------------------------------.
| |1|1|1|1|1|2|2|2|2|2|3|3|3|3|3|4|4|4|4|4|5|5|5|5|5|6|6|
|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|
|---+---+-------+-----------------------+-----------------------|
| O | R | Type | Parent index | Name index |
|---------------------------------------------------------------|
| Inlined numeric value |
'---------------------------------------------------------------'
O = Order
R = Reserved, must be 0
Type = {4,5,6,13}
數字 VALUE
區塊全都包含 64 位元數值類型,內嵌在
第二個 8 個位元組的區塊
BUFFER_VALUE
.---------------------------------------------------------------.
| |1|1|1|1|1|2|2|2|2|2|3|3|3|3|3|4|4|4|4|4|5|5|5|5|5|6|6|
|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|
|---+---+-------+-----------------------+-----------------------|
| O | R | Type | Parent index | Name index |
|---------------------------------------------------------------|
| Total length | Extent index | F |
'---------------------------------------------------------------'
O = Order
R = Reserved, must be 0
Type = 7
Total length = size of the buffer
Extent index = index of the first extent containing bytes for the buffer
F = Display format {0,1}
一般 BUFFER_VALUE
區塊會參照
一或多個已連結的 EXTENT
區塊
BUFFER_VALUE
區塊包含第一個保存 EXTENT
區塊的索引
二進位資料,且包含資料總長度 (以位元組為單位)
和規模
格式旗標會指定應如何解譯位元組資料, 如下所示:
Enum | 值 | 意義 |
---|---|---|
kUtf8 | 0 | 位元組資料可能會被解讀為 UTF-8 字串。 |
kBinary | 1 | 位元組資料是任意二進位資料,可能無法列印。 |
興奮
.---------------------------------------------------------------.
| |1|1|1|1|1|2|2|2|2|2|3|3|3|3|3|4|4|4|4|4|5|5|5|5|5|6|6|
|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|
|---+---+-------+-----------------------+-----------------------|
| O | R | Type | Next extent index | R |
|---------------------------------------------------------------|
| Payload |
'---------------------------------------------------------------'
O = Order
R = Reserved, must be 0
Type = 8
Next extent index = index of next extent in the chain
Extent index = index of the extent containing bytes for the string
Payload = byte data payload up to at most the end of the block. Size
depends on the order
EXTENT
區塊包含任意位元組資料酬載和
鏈結中的下一個 EXTENT
。擷取 buffer_value 的位元組資料
讀取每個 EXTENT
,直到讀取「Total Length」位元組為止。
名稱
.---------------------------------------------------------------.
| |1|1|1|1|1|2|2|2|2|2|3|3|3|3|3|4|4|4|4|4|5|5|5|5|5|6|6|
|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|
|---+---+-------+-----------------------------------------------|
| O | R | Type | Length | Reserved |
|---------------------------------------------------------------|
| Payload |
'---------------------------------------------------------------'
O = Order
R = Reserved, must be 0
Type = 9
Payload = contents of the name. Size depends on the order
NAME
區塊為物件和值提供使用者可理解的 ID。他們
包含完全符合指定區塊的 UTF-8 酬載。
STRING_REFERENCE
.---------------------------------------------------------------.
| |1|1|1|1|1|2|2|2|2|2|3|3|3|3|3|4|4|4|4|4|5|5|5|5|5|6|6|
|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|
|---+---+-------+-----------------------+-----------------------|
| O | R | Type | Next Extent Index | Reference Count |
|---------------------------------------------------------------|
| Total length | Payload |
'---------------------------------------------------------------'
O = Order
R = Reserved
Type = 14
Next Extent Index = index of the first overflow EXTENT, or 0 if Payload does not overflow
Reference Count = number of references to this STRING_REFERENCE
Total length = size of the Payload in bytes. Payload overflows into Next Extent if
Total length > ((16 << Order) - 12)
Payload = the canonical instance of a string. The size of the Payload field depends on the
Order. If the size of the Payload + 12 is greater than 16 << Order, then the Payload
is too large to fit in one block and will overflow into Next Extent
STRING_REFERENCE
區塊可用來在 VMO 中實作具有參考語意的字串。
這些是連結 EXTENT
清單的開頭,表示值不受大小限制。
在預期 NAME
的範圍內可使用 STRING_REFERENCE
區塊。
ARRAY_VALUE
.---------------------------------------------------------------.
| |1|1|1|1|1|2|2|2|2|2|3|3|3|3|3|4|4|4|4|4|5|5|5|5|5|6|6|
|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|
|---+---+-------+-----------------------+-----------------------|
| O | R | Type | Parent index | Name index |
|---------------------------------------------------------------|
| T | F | Count | Reserved |
|---------------------------------------------------------------|
| Payload |
'---------------------------------------------------------------'
O = Order
R = Reserved, must be 0
Type = 11
T = Type of the stored values {4,5,6,14}
F = Display format {0,1,2}
Count = Count of stored values
Payload = array of size |count|
ARRAY_VALUE
區塊 Payload
的格式取決於儲存的值類型 T
。
與「Type」欄位完全相同。其中 T ∊ {4, 5, 6}
的 Payload
應為 64 位元
數值。其中 T ∊ {14}
,Payload
應由以下何者組成:
32 位元值,代表 T
類型區塊的 24 位元索引,與位元組一起封裝
界定範圍在這種情況下,只允許使用扁平陣列的 F = 0
。
當 F = 0
時,ARRAY_VALUE
應預設為例項化。如果是數字化,這個值應為
相關的零值。在字串中,這應為空字串,以特殊
值 0
。
表示指定的儲存值類型 (或這些項目的索引) 的「數量」項目精確出現在 並將偏移量 16 的位元組傳入區塊中
「顯示格式」欄位的用途是影響陣列的編寫方式 ,解讀結果如下:
Enum | 值 | 說明 |
---|---|---|
kFlat | 0 | 顯示為已排序的無格式陣列。 |
kLinearHistogram | 1 | 將前兩個項目解讀為線性直方圖的 floor 和 step_size 參數,如下所示。 |
kExponentialHistogram | 2 | 將前三個項目解讀為 floor 、initial_step 和 step_multiplier 的指數直方圖,定義如下。 |
線性直方圖
陣列是線性直方圖,會以內嵌方式儲存參數 同時包含溢位和反向溢位值區
前兩個元素分別是 floor
和 step_size
參數
(定義列於下方)。
值區數量 (N) 默示為 Count - 4
。
其餘元素為值區:
2: (-inf, floor),
3: [floor, floor+step_size),
i+3: [floor + step_size*i, floor + step_size*(i+1)),
...
N+3: [floor+step_size*N, +inf)
指數直方圖
陣列是指數直方圖,可將參數內嵌於內嵌位置 且包含溢位和反向溢位值區
前三個元素是 floor
、initial_step
和
step_multiplier
(定義如下)。
值區數量 (N) 隱含計數 - 5。
其餘則是值區:
3: (-inf, floor),
4: [floor, floor+initial_step),
i+4: [floor + initial_step * step_multiplier^i, floor + initial_step * step_multiplier^(i+1))
N+4: [floor + initial_step * step_multiplier^N, +inf)
LINK_VALUE
.---------------------------------------------------------------.
| |1|1|1|1|1|2|2|2|2|2|3|3|3|3|3|4|4|4|4|4|5|5|5|5|5|6|6|
|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|4|6|8|0|2|
|---+---+-------+-----------------------------------------------|
| O | R | Type | Parent index | Name index |
|---------------------------------------------------------------|
| Content index | | F |
'---------------------------------------------------------------'
O = Order
R = Reserved, must be 0
Type = 12
Parent index = Index of the parent block
Name index = Index of the name of this value
Content index = Index of the content of this link (as a NAME node)
F = Disposition flags {0,1}
LINK_VALUE
區塊可讓節點支援目前存在的子項
。
內容索引指定另一個含有內容的 NAME
區塊
是參照另一個檢查檔案的專屬 ID。讀者
預期會取得 (Identifier, File)
組合組合 (透過
讀取目錄或其他介面),並且可能會嘗試追蹤
使用儲存的 ID 將樹狀圖拼湊起來,進而產生連結。
Disposition Flags 會指示讀者如何拼接樹木,如下所示:
Enum | 值 | 說明 |
---|---|---|
kChildDisposition | 0 | 儲存在連結檔案中的階層應為 LINK_VALUE 父項的子項。 |
kInlineDisposition | 1 | 儲存在連結檔案中的根層級子項和屬性應新增至 LINK_VALUE 的父項。 |
例如:
// root.inspect
root:
int_value = 10
child = LINK("other.inspect")
// other.inspect
root:
test = "Hello World"
next:
value = 0
// kChildDisposition produces:
root:
int_value = 10
child:
test = "Hello World"
next:
value = 0
// kInlineDisposition produces:
root:
int_value = 10
test = "Hello World"
next:
value = 0
如果節點和值之間發生子項名稱衝突 所新增的內嵌子系連結,而優先順序是由讀取器定義。大多數 但會將連結的值 因此可能會覆寫原始值。
並行控制
寫入者必須使用全域版本計數器,讓讀者能夠 不使用讀取或檢查之間的傳輸修改和修改作業 與作者溝通這項功能支援單一寫入者多重讀取器 並行。
本策略適用於編寫者增加全域產生計數器 讀取及結束寫入作業
這是一項簡單的策略,有很大的好處 寫入寫入者起始和結束的版本號碼 緩衝區上任意數量的作業,皆不考慮 資料更新。
主要缺點是讀取作業可能會因為 讀者經常更新作者,但讀者可以因應緩解措施 實際運作情形
讀者演算法
讀取器會使用以下演算法來取得符合自身情況的 檢查 VMO:
- 持續鎖定直到版本號碼為偶數 (無並行寫入) 為止。
- 複製整個 VMO 緩衝區,並且
- 檢查緩衝區的版本號碼等於版本 步驟 1 中的數字。
只要版本號碼相符,用戶端就能讀取 以建構共用狀態 如果版本號碼不相符,用戶端可能會重試整個 上傳資料集之後,您可以運用 AutoML 自動完成部分資料準備工作
寫入器鎖定演算法
寫入者會按照下列步驟鎖定檢查 VMO 以進行修改:
atomically_increment(generation_counter, acquire_ordering);
這項作業會將產生值設為 奇數。取得順序可確保載入結果不會在之前重新排序 這項變更。
寫入者解鎖演算法
在修改後,寫入器可解鎖檢查 VMO 包括:
atomically_increment(generation_counter, release_ordering);
將產生版本設為 新的偶數。發布順序可確保檔案寫入作業處於 在產生計數更新之前,就能看到這個狀態。