swactor/docs/distribution_minor_flows.svg
zacheryasc 402a106beb feat: distributed runtime (#30)
Major feature addition. For full details read `./docs/development_history/DISTRIBUTION.md`


Signed-off-by: Zachery Aaron Shores-Chmielewski <zacheryasc@gmail.com>
2026-02-12 09:13:50 +00:00

199 lines
13 KiB
XML

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1100 900" font-family="system-ui, sans-serif">
<defs>
<filter id="shadow" x="-4%" y="-4%" width="108%" height="108%">
<feDropShadow dx="1" dy="2" stdDeviation="3" flood-color="#000" flood-opacity="0.10"/>
</filter>
<marker id="arrow-gray" viewBox="0 0 10 7" refX="10" refY="3.5"
markerWidth="10" markerHeight="7" orient="auto-start-reverse" fill="#5f6368">
<polygon points="0 0, 10 3.5, 0 7"/>
</marker>
<marker id="arrow-green" viewBox="0 0 10 7" refX="10" refY="3.5"
markerWidth="10" markerHeight="7" orient="auto-start-reverse" fill="#34a853">
<polygon points="0 0, 10 3.5, 0 7"/>
</marker>
<marker id="arrow-red" viewBox="0 0 10 7" refX="10" refY="3.5"
markerWidth="10" markerHeight="7" orient="auto-start-reverse" fill="#ea4335">
<polygon points="0 0, 10 3.5, 0 7"/>
</marker>
<marker id="arrow-blue" viewBox="0 0 10 7" refX="10" refY="3.5"
markerWidth="10" markerHeight="7" orient="auto-start-reverse" fill="#4285f4">
<polygon points="0 0, 10 3.5, 0 7"/>
</marker>
</defs>
<!-- Background -->
<rect width="1100" height="900" rx="8" fill="#f8f9fb" stroke="#e0e3e8" stroke-width="1.5"/>
<!-- Title -->
<text x="550" y="38" text-anchor="middle" font-size="20" font-weight="bold" fill="#202124">Distribution — Minor Flows</text>
<text x="550" y="58" text-anchor="middle" font-size="12" fill="#5f6368">swim/node.rs · swim/dissemination.rs · node.rs · kademlia/repair.rs</text>
<!-- ============================================ -->
<!-- SECTION 1: JOIN HANDSHAKE -->
<!-- ============================================ -->
<rect x="30" y="80" width="1040" height="220" rx="6" fill="#e6f4ea" fill-opacity="0.2" stroke="#34a853" stroke-width="1" stroke-opacity="0.4"/>
<text x="50" y="102" font-size="13" font-weight="700" fill="#34a853" letter-spacing="1">JOIN HANDSHAKE</text>
<!-- New Node -->
<rect x="70" y="130" width="150" height="50" rx="12" fill="#e8f0fe" stroke="#4285f4" stroke-width="1.8" filter="url(#shadow)"/>
<text x="145" y="152" text-anchor="middle" font-size="13" font-weight="600" fill="#1a73e8">New Node</text>
<text x="145" y="168" text-anchor="middle" font-size="10" fill="#5f6368">joins cluster</text>
<!-- Arrow: New Node → SendJoinRequest -->
<line x1="220" y1="155" x2="300" y2="155" stroke="#5f6368" stroke-width="1.8" marker-end="url(#arrow-gray)"/>
<text x="260" y="148" text-anchor="middle" font-size="10" fill="#5f6368">join(seeds)</text>
<!-- SendJoinRequest -->
<rect x="310" y="130" width="180" height="50" rx="12" fill="#fef7e0" stroke="#f9ab00" stroke-width="1.8" filter="url(#shadow)"/>
<text x="400" y="152" text-anchor="middle" font-size="12" font-weight="600" fill="#e37400">SendJoinRequest</text>
<text x="400" y="168" text-anchor="middle" font-size="10" fill="#5f6368">to seed address</text>
<!-- Arrow: → Seed Node -->
<line x1="490" y1="155" x2="570" y2="155" stroke="#4285f4" stroke-width="1.8" marker-end="url(#arrow-blue)"/>
<!-- Seed Node -->
<rect x="580" y="130" width="150" height="50" rx="12" fill="#e6f4ea" stroke="#34a853" stroke-width="1.8" filter="url(#shadow)"/>
<text x="655" y="152" text-anchor="middle" font-size="13" font-weight="600" fill="#137333">Seed Node</text>
<text x="655" y="168" text-anchor="middle" font-size="10" fill="#5f6368">handle_join_request</text>
<!-- Arrow: Seed → add to members -->
<line x1="655" y1="180" x2="655" y2="215" stroke="#5f6368" stroke-width="1.5" marker-end="url(#arrow-gray)"/>
<!-- Seed actions -->
<rect x="560" y="220" width="190" height="56" rx="10" fill="#fff" stroke="#e0e3e8" stroke-width="1" filter="url(#shadow)"/>
<text x="580" y="240" font-size="10" fill="#5f6368">1. members.apply(new, Alive)</text>
<text x="580" y="254" font-size="10" fill="#5f6368">2. dissemination.enqueue()</text>
<text x="580" y="268" font-size="10" fill="#5f6368">3. MembershipChanged event</text>
<!-- Arrow: Seed → SendJoinResponse -->
<line x1="750" y1="248" x2="810" y2="248" stroke="#5f6368" stroke-width="1.5" marker-end="url(#arrow-gray)"/>
<!-- SendJoinResponse -->
<rect x="820" y="220" width="210" height="56" rx="12" fill="#e6f4ea" stroke="#34a853" stroke-width="1.8" filter="url(#shadow)"/>
<text x="925" y="242" text-anchor="middle" font-size="12" font-weight="600" fill="#137333">SendJoinResponse</text>
<text x="925" y="258" text-anchor="middle" font-size="10" fill="#5f6368">full membership snapshot</text>
<text x="925" y="270" text-anchor="middle" font-size="10" fill="#5f6368">(including self + all members)</text>
<!-- Arrow: back to New Node -->
<path d="M 820 270 Q 400 285 230 220 Q 180 200 170 185"
fill="none" stroke="#34a853" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<text x="380" y="260" font-size="10" fill="#34a853" font-weight="600">handle_join_response → populate MemberList + RoutingTable</text>
<!-- ============================================ -->
<!-- SECTION 2: DISSEMINATION PIGGYBACKING -->
<!-- ============================================ -->
<rect x="30" y="320" width="1040" height="230" rx="6" fill="#fef7e0" fill-opacity="0.2" stroke="#f9ab00" stroke-width="1" stroke-opacity="0.4"/>
<text x="50" y="342" font-size="13" font-weight="700" fill="#e37400" letter-spacing="1">DISSEMINATION PIGGYBACKING</text>
<!-- MembershipUpdate -->
<rect x="70" y="365" width="175" height="50" rx="12" fill="#fef7e0" stroke="#f9ab00" stroke-width="1.8" filter="url(#shadow)"/>
<text x="157" y="387" text-anchor="middle" font-size="12" font-weight="600" fill="#e37400">MembershipUpdate</text>
<text x="157" y="403" text-anchor="middle" font-size="10" fill="#5f6368">(id, addr, state, inc)</text>
<!-- Arrow → enqueue -->
<line x1="245" y1="390" x2="310" y2="390" stroke="#5f6368" stroke-width="1.8" marker-end="url(#arrow-gray)"/>
<!-- DisseminationQueue -->
<rect x="320" y="365" width="200" height="50" rx="12" fill="#e8f0fe" stroke="#4285f4" stroke-width="1.8" filter="url(#shadow)"/>
<text x="420" y="386" text-anchor="middle" font-size="12" font-weight="600" fill="#1a73e8">DisseminationQueue</text>
<text x="420" y="402" text-anchor="middle" font-size="10" fill="#5f6368">.enqueue(update, n)</text>
<!-- Arrow → budget -->
<line x1="420" y1="415" x2="420" y2="445" stroke="#5f6368" stroke-width="1.5" marker-end="url(#arrow-gray)"/>
<!-- Budget annotation -->
<rect x="320" y="450" width="200" height="44" rx="10" fill="#fff" stroke="#e0e3e8" stroke-width="1" filter="url(#shadow)"/>
<text x="340" y="468" font-size="11" font-weight="600" fill="#202124">budget = Λ * ceil(log₂(n))</text>
<text x="340" y="484" font-size="10" fill="#5f6368">Λ = 3 (default), n = cluster size</text>
<!-- Arrow → pack_piggyback -->
<line x1="520" y1="390" x2="590" y2="390" stroke="#5f6368" stroke-width="1.8" marker-end="url(#arrow-gray)"/>
<!-- pack_piggyback -->
<rect x="600" y="365" width="200" height="50" rx="12" fill="#e8f0fe" stroke="#4285f4" stroke-width="1.8" filter="url(#shadow)"/>
<text x="700" y="386" text-anchor="middle" font-size="12" font-weight="600" fill="#1a73e8">pack_piggyback(max)</text>
<text x="700" y="402" text-anchor="middle" font-size="10" fill="#5f6368">sort by priority, take max</text>
<!-- Priority annotation -->
<rect x="600" y="450" width="200" height="44" rx="10" fill="#fff" stroke="#e0e3e8" stroke-width="1" filter="url(#shadow)"/>
<text x="620" y="468" font-size="11" font-weight="600" fill="#202124">Priority ordering:</text>
<text x="620" y="484" font-size="10" fill="#5f6368">Dead (2) > Suspect (1) > Alive (0)</text>
<!-- Arrow → on wire -->
<line x1="800" y1="390" x2="865" y2="390" stroke="#5f6368" stroke-width="1.8" marker-end="url(#arrow-gray)"/>
<!-- On wire message -->
<rect x="875" y="355" width="170" height="70" rx="12" fill="#e6f4ea" stroke="#34a853" stroke-width="1.8" filter="url(#shadow)"/>
<text x="960" y="378" text-anchor="middle" font-size="12" font-weight="600" fill="#137333">Ping / Ack /</text>
<text x="960" y="394" text-anchor="middle" font-size="12" font-weight="600" fill="#137333">PingReq</text>
<text x="960" y="414" text-anchor="middle" font-size="10" fill="#5f6368">+ piggybacked updates</text>
<!-- Decrement annotation -->
<rect x="875" y="450" width="170" height="44" rx="10" fill="#fff" stroke="#e0e3e8" stroke-width="1" filter="url(#shadow)"/>
<text x="895" y="468" font-size="10" fill="#5f6368">remaining -= 1 per send</text>
<text x="895" y="484" font-size="10" fill="#5f6368">evict at remaining == 0</text>
<!-- Arrow from on wire → decrement -->
<line x1="960" y1="425" x2="960" y2="445" stroke="#5f6368" stroke-width="1" stroke-dasharray="4,3" marker-end="url(#arrow-gray)"/>
<!-- ============================================ -->
<!-- SECTION 3: MEMBERSHIP CHANGE CASCADE -->
<!-- ============================================ -->
<rect x="30" y="570" width="1040" height="300" rx="6" fill="#fce8e6" fill-opacity="0.15" stroke="#ea4335" stroke-width="1" stroke-opacity="0.4"/>
<text x="50" y="592" font-size="13" font-weight="700" fill="#ea4335" letter-spacing="1">MEMBERSHIP CHANGE CASCADE (on node death)</text>
<!-- SWIM detects death -->
<rect x="70" y="615" width="180" height="50" rx="12" fill="#fce8e6" stroke="#ea4335" stroke-width="1.8" filter="url(#shadow)"/>
<text x="160" y="637" text-anchor="middle" font-size="12" font-weight="600" fill="#c5221f">SWIM: DeclareDead</text>
<text x="160" y="653" text-anchor="middle" font-size="10" fill="#5f6368">suspicion timer expired</text>
<!-- Arrow → MembershipChanged -->
<line x1="250" y1="640" x2="310" y2="640" stroke="#ea4335" stroke-width="1.8" marker-end="url(#arrow-red)"/>
<!-- MembershipChanged -->
<rect x="320" y="615" width="190" height="50" rx="12" fill="#fef7e0" stroke="#f9ab00" stroke-width="1.8" filter="url(#shadow)"/>
<text x="415" y="637" text-anchor="middle" font-size="12" font-weight="600" fill="#e37400">MembershipChanged</text>
<text x="415" y="653" text-anchor="middle" font-size="10" fill="#5f6368">(Dead, node_id)</text>
<!-- Arrow down to handle_membership_change -->
<line x1="415" y1="665" x2="415" y2="700" stroke="#5f6368" stroke-width="1.8" marker-end="url(#arrow-gray)"/>
<!-- handle_membership_change branching -->
<!-- Branch 1: RoutingTable -->
<line x1="415" y1="700" x2="160" y2="740" stroke="#5f6368" stroke-width="1.5" marker-end="url(#arrow-gray)"/>
<rect x="60" y="745" width="200" height="44" rx="12" fill="#e8f0fe" stroke="#4285f4" stroke-width="1.5" filter="url(#shadow)"/>
<text x="160" y="764" text-anchor="middle" font-size="12" font-weight="600" fill="#1a73e8">routing_table.remove()</text>
<text x="160" y="780" text-anchor="middle" font-size="10" fill="#5f6368">evict dead node</text>
<!-- Branch 2: Cache -->
<line x1="415" y1="700" x2="415" y2="745" stroke="#5f6368" stroke-width="1.5" marker-end="url(#arrow-gray)"/>
<rect x="310" y="745" width="210" height="44" rx="12" fill="#e8f0fe" stroke="#4285f4" stroke-width="1.5" filter="url(#shadow)"/>
<text x="415" y="764" text-anchor="middle" font-size="12" font-weight="600" fill="#1a73e8">cache.invalidate_node()</text>
<text x="415" y="780" text-anchor="middle" font-size="10" fill="#5f6368">purge stale locations</text>
<!-- Branch 3: RepairQueue -->
<line x1="415" y1="700" x2="680" y2="740" stroke="#5f6368" stroke-width="1.5" marker-end="url(#arrow-gray)"/>
<rect x="580" y="745" width="200" height="44" rx="12" fill="#fce8e6" stroke="#ea4335" stroke-width="1.5" filter="url(#shadow)"/>
<text x="680" y="764" text-anchor="middle" font-size="12" font-weight="600" fill="#c5221f">repair.on_node_death()</text>
<text x="680" y="780" text-anchor="middle" font-size="10" fill="#5f6368">extract + queue entries</text>
<!-- Arrow: RepairQueue → re-STORE -->
<line x1="780" y1="767" x2="850" y2="767" stroke="#5f6368" stroke-width="1.5" marker-end="url(#arrow-gray)"/>
<!-- re-STORE -->
<rect x="860" y="745" width="185" height="44" rx="12" fill="#e6f4ea" stroke="#34a853" stroke-width="1.5" filter="url(#shadow)"/>
<text x="952" y="764" text-anchor="middle" font-size="12" font-weight="600" fill="#137333">re-STORE entries</text>
<text x="952" y="780" text-anchor="middle" font-size="10" fill="#5f6368">to new r-closest nodes</text>
<!-- Branch 4: Disseminate -->
<line x1="415" y1="700" x2="900" y2="660" stroke="#5f6368" stroke-width="1.5" marker-end="url(#arrow-gray)"/>
<rect x="820" y="635" width="220" height="44" rx="12" fill="#fef7e0" stroke="#f9ab00" stroke-width="1.5" filter="url(#shadow)"/>
<text x="930" y="654" text-anchor="middle" font-size="12" font-weight="600" fill="#e37400">dissemination.enqueue()</text>
<text x="930" y="670" text-anchor="middle" font-size="10" fill="#5f6368">propagate death to cluster</text>
<!-- Cascade label -->
<text x="415" y="843" text-anchor="middle" font-size="10" font-weight="600" fill="#ea4335">All four actions happen in a single tick</text>
<!-- Source ref -->
<text x="550" y="885" text-anchor="middle" font-size="10" fill="#9aa0a6">node.rs:125-285 · dissemination.rs:42-118 · repair.rs:28-51</text>
</svg>