mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-22 00:51:04 +00:00
ifcparse: unregister a deleted instance's inverse records via its attributes (#9467)
process_deletion_inverse() called inverse_index::remove_source(), which
walked every record in the file's inverse index to find the ones whose
source is the deleted instance: O(R) per deletion, the dominant cost of
file.remove() on large files now that the lookup side no longer re-sorts.
The records a deleted instance contributed are exactly the entity
references in its own attributes, so walk those with the same visitor
build_inverses_() uses for registration and remove each record with a
targeted binary search instead. remove_source() has no callers left and
is deleted.
Also use the ordered view of batch_deletion_ids_ (a boost multi_index
that already had one) for the is-this-referencer-also-being-deleted
check in process_deletion_(), which was a linear std::find over the
sequenced view: O(b) per referencing instance made batch deletion of b
instances quadratic.
file.remove on 300 IfcPropertySet of a 155 MB IFC4 model (201k IfcRoot)
drops from 3.15 ms to 0.17 ms per call, batched removal of 2000 from
3.34 ms to 0.17 ms per call, root.remove_product on 100 walls from
332 ms to 131 ms per call.
Claude-Session: https://claude.ai/code/session_01HNrXDmR88wKPCYwGE21SyH
(cherry picked from commit 938442303f)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -444,27 +444,6 @@ namespace ifcopenshell {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Nothing indexes records by source, so this walks the whole index.
|
||||
void remove_source(uint32_t source_id) {
|
||||
sort();
|
||||
for (auto& record : base_) {
|
||||
if (!is_dead(record) && record.source_id == source_id) {
|
||||
kill(record);
|
||||
}
|
||||
}
|
||||
for (auto it = delta_.begin(); it != delta_.end();) {
|
||||
auto& records = it->second;
|
||||
auto removed = std::remove_if(records.begin(), records.end(), [source_id](const inverse_record& record) {
|
||||
return record.source_id == source_id;
|
||||
});
|
||||
delta_size_ -= (size_t)std::distance(removed, records.end());
|
||||
records.erase(removed, records.end());
|
||||
it = records.empty() ? delta_.erase(it) : std::next(it);
|
||||
}
|
||||
compact_if_tombstones_dominate();
|
||||
invalidate_materialized();
|
||||
}
|
||||
|
||||
// Finalizes bulk loading. Subsequent add() calls go to the delta.
|
||||
void sort() const {
|
||||
if (!sorted_) {
|
||||
|
||||
Reference in New Issue
Block a user