Repository navigation
stack: #1037 (share edge arenas with the classification snapshot) merged with main, Send-safe - #1090
Merged
bherbruck merged 4 commits intoOct 26, 2026
Conversation
…ication snapshot curve_on_classify clones the whole B-rep (clone_sharing_surface_caches) for every curve it classifies and drops it afterwards; on a 269-face boolean this was about half of the cut, and the edge and edgeuse arenas were 72% of each copy. The snapshot now shares those two arenas through an Arc and copies one only when something writes to it (Arc::make_mut in DerefMut), so every writer sees exactly what the deep copy gave it. Plain Brep::clone stays deep.
…hare-edges-on-main
… Send The classification snapshot shares the edge and edgeuse arenas through an `Arc`, which is `Send` only when the arenas are `Sync`. Four interior caches reachable from an edge's curve were `Cell`/`RefCell`: - `CrvOnSurf::break_cache`: `RefCell` -> `Mutex` (locked only per access) - `OffsetSurface::offset_distance`: `Cell<f64>` -> `AtomicU64` of the bits - `OffsetSurface` pending extension: `Cell<Option<Box<Surface>>>` -> `Mutex` - `BSplineSurface::out_of_bounds_enabled`: `Cell<bool>` -> `AtomicBool` Same reads and writes in the same order, relaxed atomics, poisoned locks recovered (values are written whole), so no result changes. The memo test now also asserts `Curve: Sync`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011gJAwcLRBPQXYLmvXd3pWf
…hare-edges-on-main
bherbruck
approved these changes
Oct 26, 2026
bherbruck
left a comment
Collaborator
There was a problem hiding this comment.
Approved by the automated first-pass review: CI green, mergeable, no CI/build/dependency file changes, no red-flag patterns in added code (process/network/env/unsafe outside FFI/blobs/hidden unicode), 0 known-mismatch entries added. Logic is gated by CI and the difftest merge queue.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacks @ablasik's #1037 (commit
4a66dda56, unchanged) on currentmain, plus one commit that keepsBrep: Send. Closes if #1037 lands instead; credit for the sharing goes to #1037.Why #1037 stopped compiling
#992 added
curves_and_breps_stay_send(assert_send::<Brep>()). #1037 holds the edge and edgeuse arenas in anArc, andArc<T>isSendonly whenT: Send + Sync. Four interior caches that an edge's curve can reach wereCell/RefCell. These are not #992's memo, which is already anOnceLock<Arc<Mutex<…>>>:CrvOnSurf::break_cache(m_bNeedBreaks,m_vBreaks)RefCell<BreakCache>Mutex<BreakCache>, locked only for each accessOffsetSurface::offset_distanceCell<f64>F64Cell(anAtomicU64holding the bits, relaxed)OffsetSurfacepending extensionCell<Option<Box<Surface>>>Mutex<…>with the sametake/setBSplineSurface::out_of_bounds_enabledCell<bool>AtomicBool(relaxed)Design and why
I considered three options:
Rcis not an option, because it is notSend.The reads and writes stay the same and in the same order, and the bits round-trip exactly. No lock is held while geometry runs, which the existing
BreakCacheand pending-extension invariants already require. A poisoned lock is recovered, since every value is written whole. Nothing panics and there is nounsafe. Atomics andMutexcompile forwasm32-unknown-unknown, as #992's memo does. Uncontended, they cost one load or one CAS.Sharing these caches between the source and the snapshot is the same behaviour #1037 already had on its base with the
Cells. The break cache is a pure function of the curve's value. The out-of-bounds flag is set and restored within one scope. The offset distance and extension are only written through&selfby the fillet solvers, never by classification.Intent preserved
#1037:
Arc(Shared::share,clone_sharing_surface_caches->copy(true)). The commit is unchanged.DerefMutisArc::make_mut.Brep::clonestays deep (copy(false),Shared::clonedeep-copies the arena).#992:
CurveMemo, the key,memo_pure, the off switch) is untouched.curve_cache_memopasses: memo on = memo off, and second run = first.curves_and_breps_stay_sendkeeps bothSendassertions and now also assertsCurve: Sync, which the shared arena relies on. Its comment is updated.Gate
fmt, clippy
-D warnings,cargo test -p solidcoreand the wasm check all pass. Difftest ran on the 62 green/partial units that go throughcurve_on_classify, the Booleans or the changed types:boolean.*(api_brep, merge_p1–p5, topology_intersector_p1–p3),intersect.curve_class_p1–p9,topology.brep_p1–p10,query.brep,curve.crv_on_surf,nurbs.b_spline_surface_p1/p2,surface.offset_surface,surface.surface_point_solve_p1–p3,intersect.surface_intersector_p1–p5andblend.fillet_*(21 units).Every unit's total/passed/failed/deferred/rejected/vacuous counts and status are identical to main's CI reports at the merge base
f58ad1525: 0 of 62 differ.Totals: 63954 cases, 63822 passed, 0 failed, 0 deferred, 132 rejected, max_rel_err 0. Sample lines:
Timing (sharing still avoids the deep copy)
The test case is a 100x100x10 box cut by 25 cylinders in turn, then 200
clone_sharing_surface_cachesof the result. It ran in release on Linux x86_64 under load (loadavg ~33), so the totals are noisy. I compared it against the same head withcopy(true)->copy(false)(a local experiment, not committed):The snapshots are about 3x cheaper. This model's edges are only lines and circles. #1037's 269-face battery model measured about 2x for the whole cut.
🤖 Generated with Claude Code
https://claude.ai/code/session_011gJAwcLRBPQXYLmvXd3pWf