///|
/// 某一页用途的首次归属页数;不重复计入冲突引用。
pub(all) struct PageKindCount {
kind : PageKind
pages : Int
} derive(Debug, Eq)
///|
pub extend PageKindCount with @debug.Debug::{to_repr}
///|
pub extend PageKindCount with Eq::{equal, not_equal}
///|
/// 仅统计已经认领的页,不把冲突引用重复计入另一个对象。
/// 一个对象已认领的 B-tree 与 overflow 页数;包含页内空闲空间,不是有效 payload 长度。
pub(all) struct ObjectPageCount {
root_page : Int
object_name : String?
btree_pages : Int
overflow_pages : Int
} derive(Debug, Eq)
///|
pub extend ObjectPageCount with @debug.Debug::{to_repr}
///|
pub extend ObjectPageCount with Eq::{equal, not_equal}
///|
/// 对已有报告的纯汇总;完整程度、诊断及 payload 请求总量仍以原报告为准。
/// 已有归属报告的纯汇总;不重新读取源。未完成检查的统计只代表已观察前缀,完整程度仍看原报告。
pub(all) struct InspectionSummary {
claimed_pages : Int
unclaimed_pages : Int
page_kinds : Array[PageKindCount]
objects : Array[ObjectPageCount]
} derive(Debug, Eq)
///|
pub extend InspectionSummary with @debug.Debug::{to_repr}
///|
pub extend InspectionSummary with Eq::{equal, not_equal}
///|
priv struct ObjectPageCounter {
mut btree_pages : Int
mut overflow_pages : Int
}
///|
fn page_kind_index(kind : PageKind) -> Int {
match kind {
BtreeRoot => 0
BtreeChild => 1
OverflowFirst => 2
OverflowContinuation => 3
FreelistTrunk => 4
FreelistLeaf => 5
PointerMap => 6
LockByte => 7
}
}
///|
/// 不读取数据源、不解码记录;未完成报告的统计只表示已观察到的页。
/// 对已有页归属报告作纯汇总,不重读数据源;冲突页只按首次归属计数,未完成报告只代表已观察前缀。
pub fn DatabaseInspection::summarize(
self : DatabaseInspection,
) -> InspectionSummary {
let kinds = [
BtreeRoot,
BtreeChild,
OverflowFirst,
OverflowContinuation,
FreelistTrunk,
FreelistLeaf,
PointerMap,
LockByte,
]
let counts = Array::make(8, 0)
let objects : Map[(Int, String?), ObjectPageCounter] = Map([])
for page in self.pages {
let index = page_kind_index(page.kind)
counts[index] = counts[index] + 1
let btree = page.kind == BtreeRoot || page.kind == BtreeChild
let overflow = page.kind == OverflowFirst ||
page.kind == OverflowContinuation
if (btree || overflow) && page.root_page is Some(root) {
let key = (root, page.object_name)
let counter = match objects.get(key) {
Some(counter) => counter
None => {
let counter : ObjectPageCounter = {
btree_pages: 0,
overflow_pages: 0,
}
objects[key] = counter
counter
}
}
if btree {
counter.btree_pages = counter.btree_pages + 1
}
if overflow {
counter.overflow_pages = counter.overflow_pages + 1
}
}
}
let object_counts : Array[ObjectPageCount] = []
for (root, name), counter in objects {
object_counts.push({
root_page: root,
object_name: name,
btree_pages: counter.btree_pages,
overflow_pages: counter.overflow_pages,
})
}
// 输出顺序固定,避免 Map 枚举顺序导致 CLI 与展示层反复变化。
object_counts.sort_by((left, right) => {
let root_order = left.root_page.compare(right.root_page)
if root_order != 0 {
root_order
} else {
match (left.object_name, right.object_name) {
(None, None) => 0
(None, Some(_)) => -1
(Some(_), None) => 1
(Some(left_name), Some(right_name)) => left_name.compare(right_name)
}
}
})
{
claimed_pages: self.pages.length(),
unclaimed_pages: self.unclaimed_pages.length(),
page_kinds: Array::makei(8, i => { kind: kinds[i], pages: counts[i], }),
objects: object_counts,
}
}