From b432ea557d9f42f235d9f045b704578de4bc92ac Mon Sep 17 00:00:00 2001 From: Developer Date: Fri, 13 Feb 2026 14:52:41 +0700 Subject: [PATCH] fix: docs directory cleaning --- docs/development_history/DEAD_NODE_REPROBE.md | 74 ----------- .../{ => bin-runner}/WASM_ACTOR.md | 0 .../{ => distribution}/DISTRIBUTION.md | 0 .../{ => distribution}/DOCKER_REALIZATION.md | 0 .../{ => distribution}/SIMULATION_TESTING.md | 0 .../{ => distribution}/distribution_plan.md | 0 docs/wasm-actor.md | 115 ------------------ 7 files changed, 189 deletions(-) delete mode 100644 docs/development_history/DEAD_NODE_REPROBE.md rename docs/development_history/{ => bin-runner}/WASM_ACTOR.md (100%) rename docs/development_history/{ => distribution}/DISTRIBUTION.md (100%) rename docs/development_history/{ => distribution}/DOCKER_REALIZATION.md (100%) rename docs/development_history/{ => distribution}/SIMULATION_TESTING.md (100%) rename docs/development_history/{ => distribution}/distribution_plan.md (100%) delete mode 100644 docs/wasm-actor.md diff --git a/docs/development_history/DEAD_NODE_REPROBE.md b/docs/development_history/DEAD_NODE_REPROBE.md deleted file mode 100644 index 76dc7c0..0000000 --- a/docs/development_history/DEAD_NODE_REPROBE.md +++ /dev/null @@ -1,74 +0,0 @@ -# Dead-Node Reprobe — Design & Rationale - -## Problem - -When a network partition heals, SWIM nodes on both sides may have declared each -other Dead. The `alive_members()` filter excludes Dead nodes from probing -targets, so neither side initiates communication — creating a **permanent split** -even after connectivity is restored. - -The existing refutation mechanism (incarnation bump on learning of own death -declaration) handles resurrection correctly, but depends on someone *telling* -the dead-declared node about its status. With no probes to dead nodes, nobody -does. - -## Solution: Independent Dead-Node Reprobe Cycle - -Added a lightweight reprobe mechanism to `SwimProbe` that periodically pings -dead nodes. The existing piggyback + refutation mechanism handles the rest: - -1. **Reprober** pings dead node with piggybacked "you are Dead(inc=N)" -2. **Target** receives piggyback, sees it's declared Dead → refutes → bumps incarnation -3. **Target** replies with Ack carrying piggybacked "I'm Alive(new_inc)" -4. **Reprober** applies piggyback → target transitions Dead→Alive - -Key insight: we re-enqueue the death declaration in the dissemination queue -before packing the reprobe ping's piggyback. Without this, the original death -declaration's transmit budget would be long exhausted, and the piggyback would -carry no useful membership info. - -## Design Decisions - -### Why inside SwimProbe (not SwimNode)? - -- SwimProbe owns the tick counter, sequence counter, and member list access -- All probe-related logic stays in one place -- The reprobe is a simple independent cycle — doesn't interfere with ProbePhase - -### Why no new wire messages? - -- `SwimAction::SendPing` works identically for normal probes and reprobes -- The ack from a reprobe targets a different sequence than the current probe - cycle, so the probe state machine ignores it — but the piggyback is applied - at the SwimNode layer before the probe state machine sees the ack - -### Configuration - -- `dead_reprobe_interval: u64` (default: 50 ticks, ~5× probe_interval) -- Set to 0 to disable completely -- Existing test configs use 0 to avoid interference with timing - -## Files Changed - -| File | Change | -|------|--------| -| `crates/distribution/src/swim/probe.rs` | `dead_reprobe_interval` in config, `maybe_reprobe_dead()` method | -| `crates/distribution/src/swim/member_list.rs` | Added `dead_members()` | -| `crates/distribution/src/swim/node.rs` | Re-enqueue death declaration in `translate_probe_actions` | -| All `SwimConfig` struct literals | Added `dead_reprobe_interval` field | - -## Edge Cases - -- **Truly dead nodes**: Reprobe ping is lost (no ack), no harm done -- **All members dead**: Reprobe cycles through them round-robin -- **Concurrent reprobe + normal probe**: Independent, different sequences -- **Dissemination budget**: Death re-enqueued fresh each reprobe, not stale - -## Alternatives Considered - -1. **Dead node grace period + resurrection timer**: More complex, adds new - state tracking alongside suspicion timers. Rejected for simplicity. -2. **Periodic re-join via seed nodes**: Requires seed node availability, - doesn't work when seed is itself dead-declared. Rejected. -3. **Direct liveness inference from Ping reception**: Would require changing - `handle_ping` to special-case pings from dead nodes. More invasive. diff --git a/docs/development_history/WASM_ACTOR.md b/docs/development_history/bin-runner/WASM_ACTOR.md similarity index 100% rename from docs/development_history/WASM_ACTOR.md rename to docs/development_history/bin-runner/WASM_ACTOR.md diff --git a/docs/development_history/DISTRIBUTION.md b/docs/development_history/distribution/DISTRIBUTION.md similarity index 100% rename from docs/development_history/DISTRIBUTION.md rename to docs/development_history/distribution/DISTRIBUTION.md diff --git a/docs/development_history/DOCKER_REALIZATION.md b/docs/development_history/distribution/DOCKER_REALIZATION.md similarity index 100% rename from docs/development_history/DOCKER_REALIZATION.md rename to docs/development_history/distribution/DOCKER_REALIZATION.md diff --git a/docs/development_history/SIMULATION_TESTING.md b/docs/development_history/distribution/SIMULATION_TESTING.md similarity index 100% rename from docs/development_history/SIMULATION_TESTING.md rename to docs/development_history/distribution/SIMULATION_TESTING.md diff --git a/docs/development_history/distribution_plan.md b/docs/development_history/distribution/distribution_plan.md similarity index 100% rename from docs/development_history/distribution_plan.md rename to docs/development_history/distribution/distribution_plan.md diff --git a/docs/wasm-actor.md b/docs/wasm-actor.md deleted file mode 100644 index 6d449ce..0000000 --- a/docs/wasm-actor.md +++ /dev/null @@ -1,115 +0,0 @@ -# Wasm Actor - -The `swactor-wasm-actor` crate runs WebAssembly guest code inside a swactor -actor. The Wasm instance is sandboxed by [wasmtime](https://wasmtime.dev/). - -## Architecture - -``` - ┌─ Runtime ──────────────────────────────────────────────────────────────┐ - │ │ - │ ┌─ WasmActor ──────────────────────────────────────────────────────┐ │ - │ │ │ │ - │ │ Store -- wasmtime store with outbox │ │ - │ │ Memory -- guest linear memory │ │ - │ │ alloc: TypedFunc -- guest allocator │ │ - │ │ handle: TypedFunc -- guest message handler │ │ - │ │ │ │ - │ │ impl ActorInterface for WasmActor │ │ - │ │ Incoming = ByteMessage │ │ - │ │ Response = () │ │ - │ │ │ │ - │ └──────────────────────────────────────────────────────────────────┘ │ - │ │ - │ ┌─ Native Actors ─────────────────────────────────────────────────┐ │ - │ │ (can exchange ByteMessage with WasmActors normally) │ │ - │ └─────────────────────────────────────────────────────────────────┘ │ - │ │ - └────────────────────────────────────────────────────────────────────────┘ -``` - -## Message Flow - -``` - Host Guest (Wasm) - ──── ──────────── - - ByteMessage arrives - │ - ├─1─ call alloc(len) ──────────► bump-allocate, return ptr - │ - ├─2─ write bytes at ptr ───────► (memory updated) - │ - ├─3─ call handle(ptr, len) ────► process message - │ │ - │ ◄── swactor.send() ────────────┤ (0..N times) - │ (buffered in HostState.outbox) │ - │ │ - ├─4─ drain outbox ◄────────────── handle returns - │ - v - ctx.send(dest, ByteMessage) for each outbox entry -``` - -## Guest Contract - -Guests are standalone `wasm32-unknown-unknown` modules. They export three -symbols and may import one: - -| Direction | Module | Symbol | Signature | -|-----------|--------|--------|-----------| -| **export** | — | `memory` | linear memory | -| **export** | — | `alloc` | `(i32) -> i32` | -| **export** | — | `handle` | `(i32, i32) -> ()` | -| **import** | `swactor` | `send` | `(i32, i32, i32) -> ()` | - -The `send` import takes `(dest_ptr, payload_ptr, payload_len)` where -`dest_ptr` points to a 32-byte `ActorAddress` in guest memory. - -## Usage - -```rust -use swactor::runtime::{Runtime, RuntimeConfig}; -use swactor_wasm_actor::{ByteMessage, SharedEngine, WasmActorBuilder}; - -// Create a shared engine (once) -let engine = SharedEngine::new().unwrap(); - -// Build an actor from .wasm bytes -let wasm_bytes = std::fs::read("my_guest.wasm").unwrap(); -let actor = WasmActorBuilder::new(engine, wasm_bytes) - .build() - .unwrap(); - -// Use it like any other actor -let rt = Runtime::new(RuntimeConfig::default()); -let addr = rt.spawn(actor).unwrap(); -rt.send_to(addr, ByteMessage(b"hello".to_vec())).unwrap(); -rt.tick(); -``` - -## Sandboxing - -The `SharedEngine` disables all optional Wasm proposals: - -- Threads — disabled -- SIMD / relaxed SIMD — disabled -- Reference types — disabled -- Multi-value — disabled -- Bulk memory — **enabled** (required by most Rust/LLVM toolchains) - -No WASI imports are linked. Guests have no access to the filesystem, network, -clock, or random number generator. The only host function available is -`swactor.send`. - -## Where Things Live - -| File | Purpose | -|------|---------| -| `crates/wasm-actor/src/lib.rs` | `ByteMessage` + re-exports | -| `crates/wasm-actor/src/engine.rs` | `SharedEngine` — sandboxed wasmtime config | -| `crates/wasm-actor/src/builder.rs` | `WasmActorBuilder` — compile, link, instantiate | -| `crates/wasm-actor/src/actor.rs` | `WasmActor` — `ActorInterface` impl | -| `crates/wasm-actor/src/error.rs` | `WasmActorError` | -| `crates/wasm-actor/tests/guests/` | Three test guest crates (echo, double, silent) | -| `crates/wasm-actor/tests/wasm_actor.rs` | 7 integration tests |