BundleUnbundle_2level_LLfree_dynamic.tla / _3level_LLfree_dynamic.tlaExtends the static LLfree spec (BundleUnbundle_2level_LLfree.tla) with runtime
child insertion (insert(online=true)) and release (release).
The tree structure is no longer fixed; it mutates dynamically each iteration.
Priority gating (CanProceed / TagAfterFail / TagAfterSuccess / PreemptTag / ClearMyTags)
is identical to 2-level LLfree — see slides_layer2_LLfree.html.
Both children start unattached (their own priority wrappers).
Phase 1 attaches via insert; Phase 2 interleaves commit + release.
| Role (CONSTANT) | Behavior |
|---|---|
InsertThreads | Run insert(online=true) — pick an uninserted child and attach to Parent |
RootThreads | Run CommitParent — snapshot Parent, increment every discovered child's payload |
LeafThreads | Run CommitChild — direct commit per child discovered in the snapshot |
ReleaseThreads | Release children (only after own commits are done) |
Dynamic discovery is key: children are not hardcoded; commit targets come from the snapshot. This covers boundary races such as "commit while a half-constructed insert is in flight" and "commit just before release."
InsertOnline(t) ==
/\ t \in InsertThreads
/\ pc[t] = "idle"
/\ \E c \in UninsertedChildren :
/\ \* ① read parent's wrapper
/\ CanProceed(t, Parent) \* ★ priority gate
/\ \* ② CAS a new wrapper that writes the child's packet into parent.sub[c]
/\ LET newSubs == [Parent.sub EXCEPT ![c] = childPacket]
newW == PriorityWrapper(MakePacket(Parent, payload, newSubs, FALSE), ser)
IN linkage' = [linkage EXCEPT ![Parent] = newW,
![c] = BundledRefWrapper(Parent, ser)]
/\ ClearMyTags(t) \* same tag release as commit success
Release(t) ==
/\ t \in ReleaseThreads
/\ \E c \in InsertedChildren :
/\ \* Set parent.sub[c] to Null and restore the child to its own priority wrapper
/\ CanProceed(t, Parent)
/\ CanProceed(t, c)
/\ ...
/\ linkage' = [linkage EXCEPT ![Parent] = parentWithNullSlot,
![c] = PriorityWrapper(originalChildPkt, ser)]
Interference between insert and bundle/commit:
If another thread runs bundle(Parent) while insert(c) fires,
the Phase 4 m_missing=false finalise triggers the Phase 4 reachability gate
→ DISTURBED retry; the bundling thread sees the newly inserted child on re-collect.
Priority gating arbitrates between the inserter and the bundler by transaction age.
| Item | Static (_LLfree.tla) | Dynamic (_LLfree_dynamic.tla) |
|---|---|---|
| Child set | Fixed from init (Child1, Child2) | Dynamically inserted / released (DynChild1, DynChild2) |
| New actions | — | InsertOnline / Release |
| Thread roles | All threads symmetric | Configured via InsertThreads / RootThreads / LeafThreads / ReleaseThreads |
| Commit targets | Hardcoded | Discovered dynamically from snapshot |
| Invariants | 5 (SnapshotConsistency etc.) | + insert/release consistency checks |
| cfg | Threads | States | Depth | Time | Result |
|---|---|---|---|---|---|
| 2-level dynamic 2-thread superfine | 2 | (~M) | — | — | ✅ Pass + liveness |
| 2-level dynamic release superfine live | 2 | 413,884,516 | 320 | 7:13 | ✅ Pass + liveness (ohtaka) |
| 3-level dynamic 2-thread coarse | 2 | (M~) | — | — | ✅ Pass + liveness |
| 3-level dynamic 3-thread release | 3 | (large) | — | — | ohtaka pending |
What the 413M-state run proves: The 2-level dynamic release superfine liveness run is one of the largest verifications in the corpus. All interleavings that include dynamic insert/release satisfy safety + liveness — proven by exhaustion. Priority gating + dynamic discovery + bounded variable domains achieve CONSTRAINT-free termination.
# 2-level dynamic release superfine (ohtaka recommended)
java -XX:+UseParallelGC -Xmx32g -cp tla2tools.jar tlc2.TLC \
-workers auto -config BundleUnbundle_2level_LLfree_dynamic_3thr_B_live_mc.cfg \
BundleUnbundle_2level_LLfree_dynamic.tla
slides_layer2_LLfree.html — Gen 3 LLfree base specslides_layer2_LLfree_3level_en.html — 3-level LLfree diffslides_hardlink_en.html — hard-link topologies (incl. the sibling-parents dynamic variant)kamestm/tests/VERIFICATION.md §3 — latest results