Skip to main content

Registry

Struct Registry 

Source
pub struct Registry { /* private fields */ }
Expand description

Parent and child levels use this exact type. 父级和子级使用完全相同的类型。

Implementations§

Source§

impl Registry

Source

pub fn overlay( &self, plan: &GraftPlan, external: &Registry, ) -> Result<Registry, Box<RegistryError>>

Build an effective tree by overlaying external graft implementations.

Neither self nor external is moved or edited. Each cut addresses a logical path in the base tree; the selected external face occupies that slot while the target’s untouched siblings and child registry remain. 从外部 graft 实现生成有效注册树;不会移动或编辑原树、外部树。每个 cut 指向原树逻辑路径,外部实现只覆盖该槽位,兄弟和未覆盖子树继续继承。

Source

pub fn overlay_static( &self, cuts: &[StaticGraftCut], external: &Registry, ) -> Result<Registry, Box<RegistryError>>

Apply build-captured selectors directly from read-only data.

This skips GraftPlan, Vec, and selector String construction. The returned effective Registry remains a runtime object because an external implementation may be loaded after the binary was built. 直接应用构建阶段捕获的只读 selector;不会构造 GraftPlan、Vec 或 selector String。由于外部实现可能在二进制生成后才加载,返回的有效 Registry 仍属于运行时对象。

Source§

impl Registry

Source

pub fn overlay_recorded( &self, records: &[RecordedGraft], declared: &[StaticGraftCut], external: &Registry, ) -> Result<RecordedOverlay, Box<RegistryError>>

Apply graft records over the declarations that keep their slots alive. 在这些保持槽位活着的声明之上施加嫁接记录。

Precedence policy / 优先级策略:

The record is the newest, most specific artifact and the build is explicitly written never to apply it, so it wins over a string-form declaration (StaticGraftCut::cut() is CutTarget::Path) and reports RecordReport::DeclarationOverridden. A typed-form declaration (CutTarget::Id, emitted from cut(...)) is the host saying “this exact linked crate face”; the compiler resolved it and the binary linked it, so a text file must not defeat it: the declaration stays final and the record is reported with RecordReport::TypedDeclarationKept. A record whose selector the external registry cannot resolve falls back to the declaration and reports RecordReport::RecordSelectorUnresolved, so a bad record can never break a graft the declaration could satisfy. 记录是最新、最具体的产物,而构建被明确写成永不应用它,因此它胜过字符串形式 声明(StaticGraftCut::cut() 为 CutTarget::Path),并报告 RecordReport::DeclarationOverridden。类型化形式声明(CutTarget::Id, 由 cut(...) 发射)是宿主在说“就是这个已链接的 crate 注册面”;编译器解析了它、 二进制链接了它,因此文本文件不得击败它:声明保持最终,记录以 RecordReport::TypedDeclarationKept 报告。外部注册机解析不出记录选择器时回退 到声明并报告 RecordReport::RecordSelectorUnresolved,坏记录因此永远不会破坏 声明本可满足的嫁接。

Why the obvious approach is wrong / 显而易见的做法为何不对:

Two obvious readings both fail. “Let the record always win” lets an unreviewed, machine-local .nichlink/ file re-route shipped behavior and defeats a linked, compiler-resolved face. “Let the declaration always win” leaves the record’s graft with no production reader at all — the feature is wired but unobservable. Splitting by declaration form keeps the dynamic-by-name trust the string form already grants (resolution.rs::resolve_node) while refusing to defeat the typed form. 两种直觉读法都不成立。“总让记录赢”会让未经审查、机器本地的 .nichlink/ 文件 重新路由已发布行为,并击败已链接、编译器解析过的注册面;“总让声明赢”则让记录的 graft 完全没有生产读者——功能接了线却不可观测。按声明形式区分,既保留了字符串 形式本就授予的“按名字动态解析”的信任(resolution.rs::resolve_node),又拒绝 击败类型化形式。

Boundary / 边界: a record can never resurrect a pruned slot (the declared set is the arbiter), can never select a face the loaded external registry lacks, and is reported on every overlay. Hard failures from overlay_cuts (ambiguous selector, contract mismatch, duplicate cut) stay byte-identical to an ordinary overlay because this function delegates to the same private path with one GraftPlan. 边界:记录永远不能复活被剪掉的槽位(声明的集合才是仲裁者),永远不能选中已加载 外部注册机里没有的面,并且每次 overlay 都会报告。overlay_cuts 的硬失败 (选择器歧义、合同不匹配、重复切口)与普通 overlay 逐字节相同,因为本函数用同一 份 GraftPlan 委派给同一条私有路径。

Pinned by record_tests::a_string_declaration_yields_to_the_record, record_tests::a_typed_declaration_stays_final, record_tests::an_unresolved_record_selector_falls_back_to_the_declaration, record_tests::granularity_is_overridden_as_one_atomic_record, and run_method/tests/graft_record.rs::a_record_on_disk_reaches_overlay. 由 record_tests::a_string_declaration_yields_to_the_record、 record_tests::a_typed_declaration_stays_final、 record_tests::an_unresolved_record_selector_falls_back_to_the_declaration、 record_tests::granularity_is_overridden_as_one_atomic_record 与 run_method/tests/graft_record.rs::a_record_on_disk_reaches_overlay 钉住。

Source§

impl Registry

Source

pub fn resolve_record( &self, record: &RecordedGraft, ) -> Result<ResolvedRecord, Box<RegistryError>>

Reconcile one record’s stored identity and stored path against this tree. 把一条记录存储的身份与路径同本树对账。

The record is applied at the face’s current logical path (self.path_for), never at the stored target_path. 记录施加在注册面的当前逻辑路径(self.path_for)上,而绝不是存储的 target_path 上。

Why the obvious approach is wrong / 显而易见的做法为何不对:

The intuitive reading is “the record already stores target_path, so use it as the cut selector”. That text was written when the plan was created, and a GraftCut.cut is a string resolve_path must match exactly — there is no leniency for a renamed face. A record that survives one file rename would therefore miss the very slot it still names by identity, and the host would silently overlay nothing. The identity is the durable half; the path is the human half. So the path is re-derived from the identity, and the stored text is only used when the identity no longer resolves. 直觉读法是“记录本来就存了 target_path,拿它当切口选择器即可”。那段文本是 计划创建时写下的,而 GraftCut.cut 是 resolve_path 必须精确匹配的字符串, 对改过名的注册面没有任何宽容。于是记录只要经历一次文件改名,就会错过它仍以身份 命名的那个槽位,宿主便静默地什么都没覆盖。身份是耐久的一半,路径是给人看的一半。 因此路径从身份重新推导,存储的文本只在身份不再可解析时才使用。

Boundary / 边界: identity and path agreeing is clean; one missing is drift (applied, reported); both missing is Unkept (skipped, reported); each of the two silent-intent-change cases is an Err — identity and path naming different faces, and a directory selector disagreeing with the plan’s graft — because picking either candidate would silently change the author’s intent. 边界:身份与路径一致为干净;缺一个为漂移(应用并报告);两个都缺为 Unkept (跳过并报告);两种“会静默改变作者本意“的情形都是 Err——身份与路径指向不同的 面,以及目录选择器与计划里的 graft 不一致——因为任选其一都会静默改变作者的 本意。

Pinned by record_tests::identity_and_path_agree_resolves_to_the_target, record_tests::a_missing_identity_resolves_by_path_with_drift, record_tests::contradictory_identity_and_path_are_refused, record_tests::a_record_with_no_live_slot_is_skipped_not_fatal, and record_tests::a_directory_that_disagrees_with_its_plan_is_refused. 由 record_tests::identity_and_path_agree_resolves_to_the_target、 record_tests::a_missing_identity_resolves_by_path_with_drift、 record_tests::contradictory_identity_and_path_are_refused、 record_tests::a_record_with_no_live_slot_is_skipped_not_fatal 与 record_tests::a_directory_that_disagrees_with_its_plan_is_refused 钉住。

Source§

impl Registry

Source

pub fn validate_snapshot_migration( &self, current: NodeId, replacements: Vec<RegistrationSnapshot>, ) -> Result<(), Box<RegistryError>>

Validate a source-path migration by replacing one whole subtree in a staged registry. The live registry is untouched. 在暂存注册树中校验整个源码路径子树迁移,实时注册树不会被修改。

Source

pub fn validate_replacement( &self, current: NodeId, info: RegistrationInfo, ) -> Result<(), Box<RegistryError>>

Validate an authored replacement without committing it, by way of its snapshot form. 校验作者侧替换但不提交,经由其快照形式完成。

Source

pub fn validate_snapshot_replacement( &self, current: NodeId, info: RegistrationSnapshot, ) -> Result<(), Box<RegistryError>>

Validate an authored replacement without committing it. 校验 authored 替换,但不修改当前注册树。

Source

pub fn apply_snapshot_replacement( &mut self, current: NodeId, info: RegistrationSnapshot, ) -> Result<(), Box<RegistryError>>

Commit one already-authored replacement after validating it against the same structural and connector rules used by registration. 使用与注册相同的结构和连接校验,提交一个已经生成的替换快照。

Source§

impl Registry

Source

pub fn storage_stats(&self) -> RegistryStorageStats

Count how many pages and entries this registry tree occupies. 统计该注册树占用的页数与条目数。

Examples found in repository?
examples/scale_audit.rs (line 127)
93fn main() {
94    let sizes = std::env::args()
95        .skip(1)
96        .map(|value| value.parse::<usize>().expect("size must be an integer"))
97        .collect::<Vec<_>>();
98    let sizes = if sizes.is_empty() {
99        vec![10_000, 100_000]
100    } else {
101        sizes
102    };
103    println!(
104        "nodes\tregister_ms\tregister_budget_ms\tindex_ms\tindex_budget_ms\tentries\tpages\tstatic_face_bytes"
105    );
106    // 40 µs and 20 µs per node: roughly eight times the 5.2 µs and 2.6 µs measured
107    // for 100 000 nodes when this budget was added.
108    // 每节点 40 µs 与 20 µs:约等于加入本预算时 100 000 个节点实测 5.2 µs 与 2.6 µs 的八倍。
109    let register_ceiling = ceiling("NICHLINK_SCALE_REGISTER_US", 40);
110    let index_ceiling = ceiling("NICHLINK_SCALE_INDEX_US", 20);
111    for size in sizes {
112        let namespace = format!("scale-{size}");
113        let root = Registry::root_for_namespace(FrameworkId::new("nichlink.scale"), &namespace);
114        let parent = root_node_id(&namespace);
115        let submissions = (0..size)
116            .map(|index| snapshot(&namespace, index, parent))
117            .collect::<Vec<_>>();
118        let mut registry = root;
119        let register_start = Instant::now();
120        registry
121            .register_snapshot_batch(submissions)
122            .expect("generated scale batch must register");
123        let register_ms = register_start.elapsed().as_millis();
124        let index_start = Instant::now();
125        let index = registry.index();
126        let index_ms = index_start.elapsed().as_millis();
127        let stats = registry.storage_stats();
128        let register_budget_ms = register_ceiling * size as u128 / 1000;
129        let index_budget_ms = index_ceiling * size as u128 / 1000;
130        println!(
131            "{size}\t{register_ms}\t{register_budget_ms}\t{index_ms}\t{index_budget_ms}\t{}\t{}\t{}",
132            index.len(),
133            stats.pages,
134            size * std::mem::size_of::<nichlink::StaticFace>()
135        );
136        assert!(
137            register_ms <= register_budget_ms,
138            "registering {size} nodes took {register_ms} ms, over the {register_budget_ms} ms              budget ({register_ceiling} µs per node); raise NICHLINK_SCALE_REGISTER_US if this              machine is simply slower, and update docs/performance-baseline.md if the baseline moved"
139        );
140        assert!(
141            index_ms <= index_budget_ms,
142            "indexing {size} nodes took {index_ms} ms, over the {index_budget_ms} ms budget              ({index_ceiling} µs per node); raise NICHLINK_SCALE_INDEX_US if this machine is              simply slower, and update docs/performance-baseline.md if the baseline moved"
143        );
144        let extra = snapshot(&namespace, size, parent);
145        registry
146            .register_snapshot_batch([extra])
147            .expect("incremental transaction must register");
148        assert_eq!(registry.index().len(), size + 2);
149    }
150}
Source

pub fn index(&self) -> RegistryIndex

Build a flattened lookup index over this registry and every descendant. 为该注册机及其全部后代构建扁平查找索引。

Examples found in repository?
examples/scale_audit.rs (line 125)
93fn main() {
94    let sizes = std::env::args()
95        .skip(1)
96        .map(|value| value.parse::<usize>().expect("size must be an integer"))
97        .collect::<Vec<_>>();
98    let sizes = if sizes.is_empty() {
99        vec![10_000, 100_000]
100    } else {
101        sizes
102    };
103    println!(
104        "nodes\tregister_ms\tregister_budget_ms\tindex_ms\tindex_budget_ms\tentries\tpages\tstatic_face_bytes"
105    );
106    // 40 µs and 20 µs per node: roughly eight times the 5.2 µs and 2.6 µs measured
107    // for 100 000 nodes when this budget was added.
108    // 每节点 40 µs 与 20 µs:约等于加入本预算时 100 000 个节点实测 5.2 µs 与 2.6 µs 的八倍。
109    let register_ceiling = ceiling("NICHLINK_SCALE_REGISTER_US", 40);
110    let index_ceiling = ceiling("NICHLINK_SCALE_INDEX_US", 20);
111    for size in sizes {
112        let namespace = format!("scale-{size}");
113        let root = Registry::root_for_namespace(FrameworkId::new("nichlink.scale"), &namespace);
114        let parent = root_node_id(&namespace);
115        let submissions = (0..size)
116            .map(|index| snapshot(&namespace, index, parent))
117            .collect::<Vec<_>>();
118        let mut registry = root;
119        let register_start = Instant::now();
120        registry
121            .register_snapshot_batch(submissions)
122            .expect("generated scale batch must register");
123        let register_ms = register_start.elapsed().as_millis();
124        let index_start = Instant::now();
125        let index = registry.index();
126        let index_ms = index_start.elapsed().as_millis();
127        let stats = registry.storage_stats();
128        let register_budget_ms = register_ceiling * size as u128 / 1000;
129        let index_budget_ms = index_ceiling * size as u128 / 1000;
130        println!(
131            "{size}\t{register_ms}\t{register_budget_ms}\t{index_ms}\t{index_budget_ms}\t{}\t{}\t{}",
132            index.len(),
133            stats.pages,
134            size * std::mem::size_of::<nichlink::StaticFace>()
135        );
136        assert!(
137            register_ms <= register_budget_ms,
138            "registering {size} nodes took {register_ms} ms, over the {register_budget_ms} ms              budget ({register_ceiling} µs per node); raise NICHLINK_SCALE_REGISTER_US if this              machine is simply slower, and update docs/performance-baseline.md if the baseline moved"
139        );
140        assert!(
141            index_ms <= index_budget_ms,
142            "indexing {size} nodes took {index_ms} ms, over the {index_budget_ms} ms budget              ({index_ceiling} µs per node); raise NICHLINK_SCALE_INDEX_US if this machine is              simply slower, and update docs/performance-baseline.md if the baseline moved"
143        );
144        let extra = snapshot(&namespace, size, parent);
145        registry
146            .register_snapshot_batch([extra])
147            .expect("incremental transaction must register");
148        assert_eq!(registry.index().len(), size + 2);
149    }
150}
Source§

impl Registry

Source

pub fn health_check( &self, node: NodeId, value: &RuntimeValue, call_path: Vec<CallSite>, ) -> Result<(), Box<RegistryError>>

Validate one observed runtime value against the checks a registry face declares. 用注册面声明的检查校验一个观测到的运行期取值。

This is a host API: the kernel never observes a value, so the caller owns the boundary. Call it where a host-side value crosses into a plugin or consumer, with the NodeId of the face whose runtime_checks: list applies, the RuntimeValue the host built, and the current call path. 这是宿主 API:内核从不观测取值,边界由调用方拥有。请在宿主侧取值跨入插件或消费者的 那一点调用它,传入适用该取值的注册面 NodeId、宿主构造的 RuntimeValue 与当前调用路径。

call_path is CallTrace::current_path() when a trace is active; a host that does not trace passes Vec::new(). The kernel never synthesizes a call path. 有活动 trace 时传 CallTrace::current_path();不接 trace 的宿主传 Vec::new()。 内核从不合成调用路径。

An empty runtime_checks: list passes for any value. On failure the error aggregates one child per failed check, each carrying the face’s declaration source and the value’s provenance; render it with Display. Presence or absence is the host’s decision signal: the registry does not choose whether a failed check is fatal. runtime_checks: 为空的面对任何取值都通过。失败时按每条失败的检查聚合子错误,各自携带 声明源与来源链;用 Display 渲染。存在与否就是宿主的决策信号:注册机不替宿主决定是否致命。

The aggregate keeps the four essential facts readable: node(), path(), source(), and message(), plus children() with one entry per failed check, so a host that has to branch on which check failed does not parse Display. 聚合错误保留四项必要事实的可读读取器:node()、path()、source()、message(), 以及每条失败检查一项的 children();因此必须按“哪条检查失败”分支的宿主无需解析 Display。

let value = RuntimeValue::number(0.5, Provenance::default().push(node, "Slider", "measure", "0.5"));
if let Err(error) = registry.health_check(node, &value, Vec::new()) {
    // The aggregate names the face and path; each child names the failed check.
    eprintln!("{} {} {}: {}", error.node(), error.path(), error.source(), error.message());
    for failure in error.children() {
        eprintln!("{} [{}]", failure.message(), failure.source());
    }
}
Source

pub fn dump(&self) -> String

Render the registration tree as a human-readable multi-line report. 把注册树渲染成多行的人类可读报告。

Source

pub fn dump_effective( &self, cuts: &[StaticGraftCut], external: &Registry, ) -> Result<String, Box<RegistryError>>

Render the effective tree an overlay produces, without mutating either input. 渲染一次覆盖产生的有效树,不修改任一输入。

The overlay result used to have no way out of the library except the caller reading fields off the returned Registry; this is the output path for the same question Registry::dump answers about a base tree. A host that holds the real base_registry() and external_registry() calls this with the build-captured builtin_static_plan().grafts(); a command outside the host cannot, because neither registry is linked into it. 覆盖结果过去除了调用方读取返回的 Registry 字段外没有出口;这就是 Registry::dump 对基树回答的同一个问题的输出路径。持有真实 base_registry() 与 external_registry() 的宿主用它搭配构建捕获的 builtin_static_plan().grafts();宿主之外的命令做不到,因为两棵注册树都没有 链接进它。

Source§

impl Registry

Source

pub fn path(&self) -> &str

The logical path this registry occupies in the tree. 该注册机在树中占据的逻辑路径。

Source

pub fn id(&self) -> NodeId

The stable identity of this registry. 该注册机的稳定身份。

Source

pub fn len(&self) -> usize

Number of direct entries this registry holds. 该注册机持有的直接条目数。

Source

pub fn is_empty(&self) -> bool

Whether this registry holds no direct entries. 该注册机是否不持有任何直接条目。

Source

pub fn registry_count(&self) -> usize

Number of registries in this subtree, including this one. 本子树中的注册机数量,含自身。

Source

pub fn node_count(&self) -> usize

Number of faces registered below this registry. 本注册机之下注册的面数量。

Source

pub fn check_count(&self) -> usize

Total runtime checks declared below this registry. 本注册机之下声明的运行期检查总数。

Source§

impl Registry

Source

pub fn port_index(&self) -> PortIndex

Build the port surface of this tree. 构建这棵树的端口面。

The walk is the only part that needs the tree; every rule lives in PortIndex, so a caller can also assemble an index from declarations it already has (the build does) without walking anything. 只有遍历需要树;所有规则都住在 PortIndex 里,因此调用方也可以用手上已有的声明直接 组装索引(构建步骤就是这样),不必遍历。

Source§

impl Registry

Source

pub fn registry(&self, wanted: NodeId) -> Option<&Registry>

Find the registry with this identity anywhere in the subtree. 在本子树中查找具有该身份的注册机。

Source

pub fn find(&self, id: NodeId) -> Option<&RegistrationSnapshot>

Look up the registration snapshot of one face by identity. 按身份查找某个注册面的注册快照。

Source

pub fn path_for(&self, id: NodeId) -> Option<String>

Return the current logical path of a face, derived from the live tree. 返回某个注册面的当前逻辑路径,由现存树推导。

Source

pub fn node_path(&self, id: NodeId) -> Option<Vec<NodeId>>

Return the identity chain from this registry’s root down to a face. 返回从本注册机根到某个注册面的身份链。

Source

pub fn find_kind(&self, kind: &str) -> Vec<&RegistrationSnapshot>

Collect every face of one kind, in depth-first order. 按深度优先顺序收集某一 kind 的全部注册面。

Source

pub fn find_where( &self, predicate: impl Fn(&RegistrationSnapshot) -> bool, ) -> Vec<&RegistrationSnapshot>

Collect every face the predicate accepts, in depth-first order. 按深度优先顺序收集谓词接受的全部注册面。

Source

pub fn depth_first(&self) -> Vec<&RegistrationSnapshot>

Flatten the subtree into a depth-first list of registration snapshots. 把子树展平成深度优先的注册快照列表。

Source§

impl Registry

Source

pub fn register_batch<I>( &mut self, submissions: I, ) -> Result<(), Box<RegistryError>>
where I: IntoIterator<Item = RegistrationInfo>,

Submit one batch atomically. Failure leaves the receiver unchanged. 一批提交作为原子事务处理,失败时接收者完全不变。

Source

pub fn register_all( &mut self, registrations: &[RegistrationInfo], ) -> Result<(), Box<RegistryError>>

Register a borrowed slice of compiled declarations atomically. 原子注册一个借用的编译期声明切片。

Source

pub fn register_snapshot_batch<I>( &mut self, submissions: I, ) -> Result<(), Box<RegistryError>>

Atomically attach file-backed snapshots without borrowing or leaking their metadata. 原子挂载文件快照,不借用也不泄漏快照中的元数据。

Examples found in repository?
examples/scale_audit.rs (line 121)
93fn main() {
94    let sizes = std::env::args()
95        .skip(1)
96        .map(|value| value.parse::<usize>().expect("size must be an integer"))
97        .collect::<Vec<_>>();
98    let sizes = if sizes.is_empty() {
99        vec![10_000, 100_000]
100    } else {
101        sizes
102    };
103    println!(
104        "nodes\tregister_ms\tregister_budget_ms\tindex_ms\tindex_budget_ms\tentries\tpages\tstatic_face_bytes"
105    );
106    // 40 µs and 20 µs per node: roughly eight times the 5.2 µs and 2.6 µs measured
107    // for 100 000 nodes when this budget was added.
108    // 每节点 40 µs 与 20 µs:约等于加入本预算时 100 000 个节点实测 5.2 µs 与 2.6 µs 的八倍。
109    let register_ceiling = ceiling("NICHLINK_SCALE_REGISTER_US", 40);
110    let index_ceiling = ceiling("NICHLINK_SCALE_INDEX_US", 20);
111    for size in sizes {
112        let namespace = format!("scale-{size}");
113        let root = Registry::root_for_namespace(FrameworkId::new("nichlink.scale"), &namespace);
114        let parent = root_node_id(&namespace);
115        let submissions = (0..size)
116            .map(|index| snapshot(&namespace, index, parent))
117            .collect::<Vec<_>>();
118        let mut registry = root;
119        let register_start = Instant::now();
120        registry
121            .register_snapshot_batch(submissions)
122            .expect("generated scale batch must register");
123        let register_ms = register_start.elapsed().as_millis();
124        let index_start = Instant::now();
125        let index = registry.index();
126        let index_ms = index_start.elapsed().as_millis();
127        let stats = registry.storage_stats();
128        let register_budget_ms = register_ceiling * size as u128 / 1000;
129        let index_budget_ms = index_ceiling * size as u128 / 1000;
130        println!(
131            "{size}\t{register_ms}\t{register_budget_ms}\t{index_ms}\t{index_budget_ms}\t{}\t{}\t{}",
132            index.len(),
133            stats.pages,
134            size * std::mem::size_of::<nichlink::StaticFace>()
135        );
136        assert!(
137            register_ms <= register_budget_ms,
138            "registering {size} nodes took {register_ms} ms, over the {register_budget_ms} ms              budget ({register_ceiling} µs per node); raise NICHLINK_SCALE_REGISTER_US if this              machine is simply slower, and update docs/performance-baseline.md if the baseline moved"
139        );
140        assert!(
141            index_ms <= index_budget_ms,
142            "indexing {size} nodes took {index_ms} ms, over the {index_budget_ms} ms budget              ({index_ceiling} µs per node); raise NICHLINK_SCALE_INDEX_US if this machine is              simply slower, and update docs/performance-baseline.md if the baseline moved"
143        );
144        let extra = snapshot(&namespace, size, parent);
145        registry
146            .register_snapshot_batch([extra])
147            .expect("incremental transaction must register");
148        assert_eq!(registry.index().len(), size + 2);
149    }
150}
Source§

impl Registry

Source

pub fn root() -> Registry

Create the one top-level registry. 创建唯一的顶层注册机。

Source

pub fn root_for(framework: FrameworkId) -> Registry

Create a root for one framework namespace. 为一个框架命名空间创建根注册机。

Source

pub fn root_for_namespace( framework: FrameworkId, namespace: impl Into<String>, ) -> Registry

Create an isolated root for one package or application namespace.

Examples found in repository?
examples/scale_audit.rs (line 113)
93fn main() {
94    let sizes = std::env::args()
95        .skip(1)
96        .map(|value| value.parse::<usize>().expect("size must be an integer"))
97        .collect::<Vec<_>>();
98    let sizes = if sizes.is_empty() {
99        vec![10_000, 100_000]
100    } else {
101        sizes
102    };
103    println!(
104        "nodes\tregister_ms\tregister_budget_ms\tindex_ms\tindex_budget_ms\tentries\tpages\tstatic_face_bytes"
105    );
106    // 40 µs and 20 µs per node: roughly eight times the 5.2 µs and 2.6 µs measured
107    // for 100 000 nodes when this budget was added.
108    // 每节点 40 µs 与 20 µs:约等于加入本预算时 100 000 个节点实测 5.2 µs 与 2.6 µs 的八倍。
109    let register_ceiling = ceiling("NICHLINK_SCALE_REGISTER_US", 40);
110    let index_ceiling = ceiling("NICHLINK_SCALE_INDEX_US", 20);
111    for size in sizes {
112        let namespace = format!("scale-{size}");
113        let root = Registry::root_for_namespace(FrameworkId::new("nichlink.scale"), &namespace);
114        let parent = root_node_id(&namespace);
115        let submissions = (0..size)
116            .map(|index| snapshot(&namespace, index, parent))
117            .collect::<Vec<_>>();
118        let mut registry = root;
119        let register_start = Instant::now();
120        registry
121            .register_snapshot_batch(submissions)
122            .expect("generated scale batch must register");
123        let register_ms = register_start.elapsed().as_millis();
124        let index_start = Instant::now();
125        let index = registry.index();
126        let index_ms = index_start.elapsed().as_millis();
127        let stats = registry.storage_stats();
128        let register_budget_ms = register_ceiling * size as u128 / 1000;
129        let index_budget_ms = index_ceiling * size as u128 / 1000;
130        println!(
131            "{size}\t{register_ms}\t{register_budget_ms}\t{index_ms}\t{index_budget_ms}\t{}\t{}\t{}",
132            index.len(),
133            stats.pages,
134            size * std::mem::size_of::<nichlink::StaticFace>()
135        );
136        assert!(
137            register_ms <= register_budget_ms,
138            "registering {size} nodes took {register_ms} ms, over the {register_budget_ms} ms              budget ({register_ceiling} µs per node); raise NICHLINK_SCALE_REGISTER_US if this              machine is simply slower, and update docs/performance-baseline.md if the baseline moved"
139        );
140        assert!(
141            index_ms <= index_budget_ms,
142            "indexing {size} nodes took {index_ms} ms, over the {index_budget_ms} ms budget              ({index_ceiling} µs per node); raise NICHLINK_SCALE_INDEX_US if this machine is              simply slower, and update docs/performance-baseline.md if the baseline moved"
143        );
144        let extra = snapshot(&namespace, size, parent);
145        registry
146            .register_snapshot_batch([extra])
147            .expect("incremental transaction must register");
148        assert_eq!(registry.index().len(), size + 2);
149    }
150}
Source

pub fn framework(&self) -> FrameworkId

The framework this registry was created under. 该注册机创建时所用的框架。

Trait Implementations§

Source§

impl Clone for Registry

Source§

fn clone(&self) -> Registry

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Registry

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Default for Registry

Source§

fn default() -> Registry

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.