Conversation
4a7fc18 to
f39ef05
Compare
f39ef05 to
267785b
Compare
rust/rubydex/src/model/graph.rs
Outdated
| self.remove_definitions_for_document(&document); | ||
| let old_document = self.documents.remove(&uri_id); | ||
|
|
||
| self.invalidate(old_document.as_ref(), Some(&other)); |
There was a problem hiding this comment.
It might be worth adding a fast path for the initial indexing on boot (which can trigger no invalidation and no removal of data).
Maybe a boolean flag for skipping invalidation.
| && let Some(nesting_id) = name_ref.nesting() | ||
| && let Some(NameRef::Resolved(resolved)) = self.names.get(nesting_id) |
There was a problem hiding this comment.
Can you clarify that document change this is accounting for? I'm having a hard time understanding it.
A constant reference was changed and we're enqueuing invalidation for the reference's nesting declaration.
There was a problem hiding this comment.
This is for
class Foo
include Bar # constant reference, when added we invalidate Foo entirely for now
endI've added comments for it.
There was a problem hiding this comment.
Got it. Similar to the other, I would say it's best to unwrap the option here to avoid hiding data inconsistencies in the graph.
There was a problem hiding this comment.
We can't panic here because it's possible both the const reference and the name exists only in the local graph and haven't been extended into global graph yet.
rust/rubydex/src/model/graph.rs
Outdated
|
|
||
| self.declarations.remove(&decl_id); | ||
| } else { | ||
| // Ancestor-stale mode |
There was a problem hiding this comment.
Added more comments. Basically, it's triggered in
class Foo
include Bar # this is added/removed
endSo we simply change ancestors/descendents update in this branch.
de13a32 to
d560ba6
Compare
d560ba6 to
6862eca
Compare
|
If we adopt #654, we should carry the memoized |
e37a74a to
9ae2496
Compare
Introduces a worklist-based invalidation engine that cascades changes through the graph when documents are updated or deleted. Uses ChildName/NestedName edges from the name_dependents index to propagate invalidation with two distinct modes: - Structural cascade (UnresolveName): declaration removed or scope broken - Ancestor cascade (UnresolveReferences): ancestor chain changed Replaces the has_unresolved_dependency runtime check with explicit invalidation variants determined at queue time.
9ae2496 to
2b9316b
Compare
vinistock
left a comment
There was a problem hiding this comment.
Great work. I think we can ship and continue to iterate, to unblock this significant portion of the work.
However, let's please add these test scenarios (which I believe are missing) and ensure that they are doing the right thing.
- Switching the target of an
include,prependorextend - Removing an existing superclass
- Changing the target of an alias (e.g.: first
Foo = BarthenFoo = Baz) - Switching the order of mixin operations (which impacts the final ancestor chain order). For example:
# first
class Foo
include Bar
include Baz
end
# after modification
class Foo
include Baz
include Bar
end
rust/rubydex/src/model/graph.rs
Outdated
| // invalidate the nesting declaration. | ||
| // We can optimize this later by checking where the constant reference is used. | ||
| for cr in lg.constant_references().values() { | ||
| if let Some(name_ref) = self.names.get(cr.name_id()) |
There was a problem hiding this comment.
I would vote for doing this here
let name_ref = self.names.get(cr.name_id()).unwrap();
// if statementA constant reference that holds a name_id for a name that doesn't exist in the graph is a significant data consistency issue. It's best to crash immediately and discover those bugs early than to silently ignore.
| && let Some(nesting_id) = name_ref.nesting() | ||
| && let Some(NameRef::Resolved(resolved)) = self.names.get(nesting_id) |
There was a problem hiding this comment.
Got it. Similar to the other, I would say it's best to unwrap the option here to avoid hiding data inconsistencies in the graph.
- Rename `cr` to `const_ref` for readability - Unwrap `names.get()` in `remove_document_data` — a constant reference with a missing name is a data inconsistency - Add comment explaining why `invalidate` can't unwrap the same lookup (runs before `extend`, names not in global graph yet)
On boot, no documents or declarations exist yet, so invalidation iterates definitions/references doing hash lookups that always miss. Skip it when there's no old document and no resolved declarations. ~5.4% indexing speedup on Shopify core (12.17s → 11.52s).
Replaces the old
remove_definitions_for_document+invalidate_ancestor_chainsapproach with a targeted invalidation engine. When a file is updated or deleted, the engine traces through thename_dependentsreverse index to invalidate only the affected declarations, names, and references — instead of requiring a full graph rebuild.How it works
consume_document_changes()(renamed fromupdate()) anddelete_document()run a three-step pipeline:invalidate— read-only scan that seeds a worklist from old/new definitions and references, building apending_detachmentsside table for definitions that need to be detached from their declarationsremove_document_data— cleans up phase 1 data (definitions, references, names, strings) from mapsextend— merges new content and queues work items for the resolverThe resolver still does
clear_declarations+ full rebuild. Wiring it to drainpending_workincrementally is a follow-up.Invalidation worklist
The worklist processes three item types:
Declaration— two modes:class Foo::Barsurvives even ifFoochanges from a module to an alias).Name— structural dependency broken (name's nesting or parent scope removed). Unresolves the name and cascades to all dependents.References— ancestor context changed, but the name itself is still valid. Needed for mixin-related invalidation:Cascade differentiation
The
name_dependentsreverse index distinguishesChildName(compact syntaxFoo::Bar) fromNestedName(nested syntaxmodule Foo; class Bar; end; end):ChildNameandNestedName→NameChildName→Name(resolves through parent),NestedName→References(only references need rechecking)