Viewport block caches no longer scan every object per entity

A drawing with 650k entities and 21k objects stalled for 7 minutes the
first time a layout viewport was drawn (#1746): building that viewport's
block cache asked for each entity's layer viewport overrides, and the
codec found each layer's extension dictionary by scanning every object
whenever the layer had none. Codec 2646725 reads the registered link.

The XCLIP check made the same scan for every nested INSERT without an
extension dictionary; it now reads the INSERT's own link, which the
readers and ensure_extension_dictionary always set.

Cargo: codec 2646725, kernel 4e6334a, graph 2fd1d42.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Hakan SevenandClaude Opus 5.5 committed 2026-10-17 19:46:43 +03:00
1 parent 5f5b64ef70
commit 3a3d2e4a84
8 files changed
+22 -25

No files matched your search

Generated
+4 -4
View File
@@ -96,7 +96,7 @@ checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
[[package]] [[package]]
name = "acadrust" name = "acadrust"
version = "0.6.4" version = "0.6.4"
source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=cf3a040#cf3a04051240cf88440f8aaf41c4841fcb01d0d1" source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=2646725#264672522c1edcaed1b6c04e7a4ebb888fb6aee3"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bitflags 2.13.1", "bitflags 2.13.1",
@@ -4406,7 +4406,7 @@ dependencies = [
[[package]] [[package]]
name = "opencadgraph" name = "opencadgraph"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/HakanSeven12/opencadgraph.git?rev=800878a#800878aa14be9789568544e2e552a044ac727cae" source = "git+https://github.com/HakanSeven12/opencadgraph.git?rev=2fd1d42#2fd1d429115e852fc46e47df723cb84499190927"
dependencies = [ dependencies = [
"opencadkernel", "opencadkernel",
"serde_json", "serde_json",
@@ -4415,7 +4415,7 @@ dependencies = [
[[package]] [[package]]
name = "opencadkernel" name = "opencadkernel"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=2659c33#2659c339d0b57f7f858881174e3e04d5ef46af2f" source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=4e6334a#4e6334a118bd48dd1330c4ac0ce258e0be072c59"
dependencies = [ dependencies = [
"acadrust", "acadrust",
"cavalier_contours", "cavalier_contours",
@@ -4426,7 +4426,7 @@ dependencies = [
[[package]] [[package]]
name = "opencadkernel-constraints" name = "opencadkernel-constraints"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=2659c33#2659c339d0b57f7f858881174e3e04d5ef46af2f" source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=4e6334a#4e6334a118bd48dd1330c4ac0ce258e0be072c59"
dependencies = [ dependencies = [
"nalgebra", "nalgebra",
] ]
+4 -4
View File
@@ -37,10 +37,10 @@ rfd = "0.17"
clap = { version = "4", features = ["derive", "string"] } clap = { version = "4", features = ["derive", "string"] }
env_logger = "0.11" env_logger = "0.11"
log = "0.4" log = "0.4"
codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cf3a040", features = ["serde"] } codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "2646725", features = ["serde"] }
kernel = { package = "opencadkernel", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "2659c33", features = ["acis", "offset"] } kernel = { package = "opencadkernel", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "4e6334a", features = ["acis", "offset"] }
kernel-constraints = { package = "opencadkernel-constraints", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "2659c33" } kernel-constraints = { package = "opencadkernel-constraints", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "4e6334a" }
graph = { package = "opencadgraph", git = "https://github.com/HakanSeven12/opencadgraph.git", rev = "800878a" } graph = { package = "opencadgraph", git = "https://github.com/HakanSeven12/opencadgraph.git", rev = "2fd1d42" }
dwg-thumbnailer = { path = "crates/dwg-thumbnailer" } dwg-thumbnailer = { path = "crates/dwg-thumbnailer" }
# Shared SAVE serialization dispatch + web-worker wire format: one # Shared SAVE serialization dispatch + web-worker wire format: one
# implementation for the inline (fallback/native) path and the worker path. # implementation for the inline (fallback/native) path and the worker path.
+2 -2
View File
@@ -15,7 +15,7 @@ serde_json = { version = "1", optional = true }
# Pulled in only by the `host` feature, which adds the `opencadcodec`-typed # Pulled in only by the `host` feature, which adds the `opencadcodec`-typed
# `HostApi` runtime surface. The default crate stays dependency-free so engine # `HostApi` runtime surface. The default crate stays dependency-free so engine
# crates and external tooling can depend on the manifest/ribbon contract cheaply. # crates and external tooling can depend on the manifest/ribbon contract cheaply.
codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cf3a040", optional = true, features = ["serde"] } codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "2646725", optional = true, features = ["serde"] }
# Runtime IPC and serialization (host feature only). # Runtime IPC and serialization (host feature only).
interprocess = { version = "2", optional = true } interprocess = { version = "2", optional = true }
@@ -39,7 +39,7 @@ serde_json = "1"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
cargo-lock = "11" cargo-lock = "11"
# opencadcodec is scanned at build time to generate the embedded type registry. # opencadcodec is scanned at build time to generate the embedded type registry.
codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cf3a040", features = ["serde"] } codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "2646725", features = ["serde"] }
[dev-dependencies] [dev-dependencies]
serde_json = "1" serde_json = "1"
+1 -1
View File
@@ -10,6 +10,6 @@ publish = false
# exactly one implementation. No UI/app dependencies — only the codec + serde. # exactly one implementation. No UI/app dependencies — only the codec + serde.
[dependencies] [dependencies]
codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cf3a040", features = ["serde"] } codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "2646725", features = ["serde"] }
bincode = "1.3" bincode = "1.3"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
+1 -1
View File
@@ -8,7 +8,7 @@ publish = false
crate-type = ["cdylib"] crate-type = ["cdylib"]
[dependencies] [dependencies]
codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cf3a040", features = ["serde"] } codec = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "2646725", features = ["serde"] }
bincode = "1.3" bincode = "1.3"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
console_error_panic_hook = "0.1" console_error_panic_hook = "0.1"
+1 -1
View File
@@ -16,4 +16,4 @@ ocs_plugin_api = { path = "../../crates/ocs_plugin_api", features = ["host"] }
# entry): the plugin's entities and the host's re-exports are the same types # entry): the plugin's entities and the host's re-exports are the same types
# only when both resolve the same revision. The registration `rustc` / # only when both resolve the same revision. The registration `rustc` /
# `acadrust_source` gates enforce this at load time too. # `acadrust_source` gates enforce this at load time too.
acadrust = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "cf3a040" } acadrust = { package = "acadrust", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "2646725" }
+1 -1
View File
@@ -5,7 +5,7 @@ version = 4
[[package]] [[package]]
name = "acadrust" name = "acadrust"
version = "0.6.4" version = "0.6.4"
source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=cf3a040#cf3a04051240cf88440f8aaf41c4841fcb01d0d1" source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=2646725#264672522c1edcaed1b6c04e7a4ebb888fb6aee3"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bitflags", "bitflags",
+8 -11
View File
@@ -48,15 +48,12 @@ fn resolve_extension_dictionary(doc: &CadDocument, owner: Handle) -> Option<Hand
}) })
} }
/// The INSERT's extension dictionary through its own link or the document's /// The INSERT's extension dictionary through its own link. Render walks ask
/// index — both O(1). Render walks ask this for every INSERT, so it must not /// this for every INSERT, so it must not fall back to a scan of every object:
/// fall back to [`resolve_extension_dictionary`]'s scan of every object. /// [`CadDocument::extension_dictionary_handle`] scans for an entity without
fn linked_extension_dictionary(doc: &CadDocument, ins: &Insert) -> Option<Handle> { /// a linked dictionary. Readers and `ensure_extension_dictionary` set the link.
ins.common fn linked_extension_dictionary(ins: &Insert) -> Option<Handle> {
.xdictionary_handle ins.common.xdictionary_handle.filter(|h| !h.is_null())
.filter(|h| !h.is_null())
.or_else(|| doc.extension_dictionary_handle(ins.common.handle))
.filter(|h| !h.is_null())
} }
/// Resolve the enabled XCLIP spatial filter for `ins`, if any. /// Resolve the enabled XCLIP spatial filter for `ins`, if any.
@@ -66,7 +63,7 @@ fn linked_extension_dictionary(doc: &CadDocument, ins: &Insert) -> Option<Handle
/// filter, it is disabled (code 71 = 0), or it has fewer than two boundary /// filter, it is disabled (code 71 = 0), or it has fewer than two boundary
/// points. /// points.
pub fn insert_spatial_filter<'a>(doc: &'a CadDocument, ins: &Insert) -> Option<&'a SpatialFilter> { pub fn insert_spatial_filter<'a>(doc: &'a CadDocument, ins: &Insert) -> Option<&'a SpatialFilter> {
let xdict = linked_extension_dictionary(doc, ins)?; let xdict = linked_extension_dictionary(ins)?;
let acad_filter = dict_entry(doc, xdict, "ACAD_FILTER")?; let acad_filter = dict_entry(doc, xdict, "ACAD_FILTER")?;
let spatial = dict_entry(doc, acad_filter, "SPATIAL")?; let spatial = dict_entry(doc, acad_filter, "SPATIAL")?;
match doc.objects.get(&spatial)? { match doc.objects.get(&spatial)? {
@@ -84,7 +81,7 @@ pub fn filter_handle(doc: &CadDocument, insert: Handle) -> Option<Handle> {
let Some(codec::EntityType::Insert(ins)) = doc.get_entity(insert) else { let Some(codec::EntityType::Insert(ins)) = doc.get_entity(insert) else {
return None; return None;
}; };
let xdict = linked_extension_dictionary(doc, ins)?; let xdict = linked_extension_dictionary(ins)?;
let acad_filter = dict_entry(doc, xdict, "ACAD_FILTER")?; let acad_filter = dict_entry(doc, xdict, "ACAD_FILTER")?;
let spatial = dict_entry(doc, acad_filter, "SPATIAL")?; let spatial = dict_entry(doc, acad_filter, "SPATIAL")?;
matches!( matches!(