commits
- Replaced Semaphore + Kcas queue with native Eio.Stream
- Removed unused try_acquire function
- Simplified implementation to ~20 lines
- Maintains thread safety and backpressure via Eio scheduler
- Add missing 'fmt' dependency
- Move test/benchmark dependencies (eio_main, qcheck, alcotest) to with-test
- Update version constraints to match environment (mirage-crypto >= 2.0, etc.)
- Remove unused eio_main from library link phase
- Add max_gossip_queue_depth to config (default 5000)
- Enforce limit in Dissemination.enqueue by dropping oldest items (ring buffer)
- Prevents unbounded memory growth when broadcast rate exceeds gossip bandwidth
- codec: avoid creating 2KB temp buffers for every piggybacked message in encode_packet
- types: replace Printf.sprintf with String.concat for User_msg encoding
- buffer_pool: remove unnecessary memset 0 on acquire (buffers are overwritten or viewed)
Add send_direct/send_to_addr API for point-to-point messaging:
- Protocol.send_direct sends to known members by node_id
- Protocol.send_to_addr sends directly to any UDP address
- Cluster.send and Cluster.send_to_addr expose the public API
Fix critical bugs discovered during benchmark testing:
- Fix infinite loop in dissemination.ml drain function
- Fix User_msg encoding losing topic/origin (encode as length-prefixed)
- Fix cluster_name mismatch causing silent message drops
Add throughput benchmarks for direct send vs gossip comparison:
- swim_throughput.ml with -direct/-gossip flags
- swim_throughput_parallel.sh for multi-node testing
- Go memberlist/serf throughput benchmarks for comparison
Results: Direct send achieves ~400 msg/s with 100% delivery vs
~2 msg/s with gossip piggybacking. Memberlist achieves ~2000 msg/s.
- Add Go benchmark harnesses for memberlist and serf
- Add OCaml benchmark harness for swim
- Add run_benchmarks.sh script with JSON output
- Change Cluster.start to use fork_daemon for clean shutdown
- Benchmarks measure convergence time, memory usage, message counts
Run with: NODES=5 DURATION=10 ./bench/run_benchmarks.sh
- Add TCP buffer pools to Protocol.t (64KB recv, 128KB decompress)
- Update LZW to work directly with Cstruct (zero-copy decompression)
- Add decompress_to_buffer and decompress_cstruct functions to LZW
- Add Cstruct-based codec functions (decode_compress_from_cstruct,
decode_push_pull_msg_cstruct)
- Update handle_tcp_connection to use buffer pools instead of per-
connection allocation
- Eliminate Cstruct.to_string conversions in hot path
Closes: swim-hrd
- Implement pure OCaml LZW decompression (LSB order, litWidth=8)
- Handle Compress_msg (type 9) in TCP connection handler
- Re-enable compression in Go memberlist (default behavior)
- Add LZW unit tests verifying Go-compatible decompression
This enables full interoperability with memberlist's default
compressed pushPull messages during Join().
- Add TCP listener creation in transport.ml and protocol.ml
- Implement pushPull message handling for TCP state sync
- Add push_pull_header and push_node_state types to Wire module
- Add encode/decode functions for pushPull messages in codec.ml
- Wire up TCP listener fiber in swim.ml Cluster.start
- Disable compression in Go interop test (memberlist uses LZ4)
This enables Go memberlist nodes to Join() to our OCaml SWIM cluster
via TCP pushPull state exchange.
- Use encryption version 1 (no PKCS7 padding) for outgoing messages
- Support decrypting both version 0 (with PKCS7) and version 1
- Add --encrypt flag to interop_test for encrypted testing
- Add test_interop_encrypted.sh for encrypted interop testing
Verified: OCaml SWIM ↔ Go memberlist encrypted ping/ack works.
- Refactor encode/decode functions to use Cstruct buffers directly
- Add *_to_cstruct and *_from_cstruct variants for all codec functions
- Fix compound message encoding bug: create fresh buffer per message
- Add backward-compatible string wrappers for tests
All tests pass including codec roundtrip property tests and Go interop.
- Add interop/main.go: Go memberlist server for testing
- Add bin/debug_*.ml: OCaml debug tools for codec/ping testing
- Add test_interop.sh: script to run interop test
- Update .gitignore for compiled binaries
- Add conditional encryption based on config.encryption_enabled
- Fix Ping message: node field now set to target (memberlist requirement)
- Add Wire submodule with memberlist-compatible msgpack types
- Update codec to use msgpck for proper msgpack encoding
- Use AES-128-GCM with 16-byte keys (memberlist compatible)
- Add interop test client for testing against Go memberlist
Verified: OCaml SWIM can send pings to Go memberlist and receive acks.
Tracked in swim-7wx (encryption format still needs work).
- test_kcas.ml: 15 tests for buffer_pool, membership, pending_acks, member transitions
- test_integration.ml: 9 cluster lifecycle tests (create, start, shutdown, stats, members, broadcast)
- Fix env type constraint to accept platform-specific Eio backends via identity cast
Total test count: 89 tests across 6 test executables
Test modules implemented:
- generators.ml: QCheck generators for all SWIM types (node_id, incarnation,
member_state, node_info, protocol_msg, packet, config, errors)
- test_codec.ml: Codec property tests (roundtrip, size accuracy) and unit tests
for encoder/decoder operations, error handling (19 tests)
- test_crypto.ml: Crypto property tests (roundtrip, overhead size) and unit tests
for key validation, tampering detection, nonce uniqueness (13 tests)
- test_pure.ml: Protocol_pure property tests (merge convergence, idempotence) and
unit tests for state transitions, invalidation, timeouts (32 tests)
All 65 tests passing.
Core library implementation with 11 modules:
- types.ml/mli: Core immutable types (node_id, incarnation, member_state, protocol_msg, packet, config, env, stats)
- codec.ml: Zero-copy binary encoding/decoding with magic bytes, version, message tags
- crypto.ml: AES-256-GCM encryption using Mirage_crypto
- buffer_pool.ml/mli: Lock-free buffer pool using Kcas_data.Queue + Eio.Semaphore
- protocol_pure.ml/mli: Pure SWIM state transitions (handle_alive/suspect/dead, suspicion_timeout, etc)
- membership.ml/mli: Kcas-based member table with Kcas_data.Hashtbl
- dissemination.ml/mli: Broadcast queue with transmit counting and message invalidation
- pending_acks.ml/mli: Ack tracking with Eio.Promise for async waiting
- transport.ml: UDP/TCP networking with Eio.Net
- protocol.ml: Main protocol loop with message handlers and probe cycles
- swim.ml: Public API with Cluster module
Design constraints followed:
- Eio only (no Lwt/Async/Mutex/Condition)
- All coordination via kcas (no locks)
- Result types for expected errors (no exceptions)
- Zero-copy buffer management
Add send_direct/send_to_addr API for point-to-point messaging:
- Protocol.send_direct sends to known members by node_id
- Protocol.send_to_addr sends directly to any UDP address
- Cluster.send and Cluster.send_to_addr expose the public API
Fix critical bugs discovered during benchmark testing:
- Fix infinite loop in dissemination.ml drain function
- Fix User_msg encoding losing topic/origin (encode as length-prefixed)
- Fix cluster_name mismatch causing silent message drops
Add throughput benchmarks for direct send vs gossip comparison:
- swim_throughput.ml with -direct/-gossip flags
- swim_throughput_parallel.sh for multi-node testing
- Go memberlist/serf throughput benchmarks for comparison
Results: Direct send achieves ~400 msg/s with 100% delivery vs
~2 msg/s with gossip piggybacking. Memberlist achieves ~2000 msg/s.
- Add Go benchmark harnesses for memberlist and serf
- Add OCaml benchmark harness for swim
- Add run_benchmarks.sh script with JSON output
- Change Cluster.start to use fork_daemon for clean shutdown
- Benchmarks measure convergence time, memory usage, message counts
Run with: NODES=5 DURATION=10 ./bench/run_benchmarks.sh
- Add TCP buffer pools to Protocol.t (64KB recv, 128KB decompress)
- Update LZW to work directly with Cstruct (zero-copy decompression)
- Add decompress_to_buffer and decompress_cstruct functions to LZW
- Add Cstruct-based codec functions (decode_compress_from_cstruct,
decode_push_pull_msg_cstruct)
- Update handle_tcp_connection to use buffer pools instead of per-
connection allocation
- Eliminate Cstruct.to_string conversions in hot path
Closes: swim-hrd
- Implement pure OCaml LZW decompression (LSB order, litWidth=8)
- Handle Compress_msg (type 9) in TCP connection handler
- Re-enable compression in Go memberlist (default behavior)
- Add LZW unit tests verifying Go-compatible decompression
This enables full interoperability with memberlist's default
compressed pushPull messages during Join().
- Add TCP listener creation in transport.ml and protocol.ml
- Implement pushPull message handling for TCP state sync
- Add push_pull_header and push_node_state types to Wire module
- Add encode/decode functions for pushPull messages in codec.ml
- Wire up TCP listener fiber in swim.ml Cluster.start
- Disable compression in Go interop test (memberlist uses LZ4)
This enables Go memberlist nodes to Join() to our OCaml SWIM cluster
via TCP pushPull state exchange.
- Use encryption version 1 (no PKCS7 padding) for outgoing messages
- Support decrypting both version 0 (with PKCS7) and version 1
- Add --encrypt flag to interop_test for encrypted testing
- Add test_interop_encrypted.sh for encrypted interop testing
Verified: OCaml SWIM ↔ Go memberlist encrypted ping/ack works.
- Refactor encode/decode functions to use Cstruct buffers directly
- Add *_to_cstruct and *_from_cstruct variants for all codec functions
- Fix compound message encoding bug: create fresh buffer per message
- Add backward-compatible string wrappers for tests
All tests pass including codec roundtrip property tests and Go interop.
- Add conditional encryption based on config.encryption_enabled
- Fix Ping message: node field now set to target (memberlist requirement)
- Add Wire submodule with memberlist-compatible msgpack types
- Update codec to use msgpck for proper msgpack encoding
- Use AES-128-GCM with 16-byte keys (memberlist compatible)
- Add interop test client for testing against Go memberlist
Verified: OCaml SWIM can send pings to Go memberlist and receive acks.
Tracked in swim-7wx (encryption format still needs work).
- test_kcas.ml: 15 tests for buffer_pool, membership, pending_acks, member transitions
- test_integration.ml: 9 cluster lifecycle tests (create, start, shutdown, stats, members, broadcast)
- Fix env type constraint to accept platform-specific Eio backends via identity cast
Total test count: 89 tests across 6 test executables
Test modules implemented:
- generators.ml: QCheck generators for all SWIM types (node_id, incarnation,
member_state, node_info, protocol_msg, packet, config, errors)
- test_codec.ml: Codec property tests (roundtrip, size accuracy) and unit tests
for encoder/decoder operations, error handling (19 tests)
- test_crypto.ml: Crypto property tests (roundtrip, overhead size) and unit tests
for key validation, tampering detection, nonce uniqueness (13 tests)
- test_pure.ml: Protocol_pure property tests (merge convergence, idempotence) and
unit tests for state transitions, invalidation, timeouts (32 tests)
All 65 tests passing.
Core library implementation with 11 modules:
- types.ml/mli: Core immutable types (node_id, incarnation, member_state, protocol_msg, packet, config, env, stats)
- codec.ml: Zero-copy binary encoding/decoding with magic bytes, version, message tags
- crypto.ml: AES-256-GCM encryption using Mirage_crypto
- buffer_pool.ml/mli: Lock-free buffer pool using Kcas_data.Queue + Eio.Semaphore
- protocol_pure.ml/mli: Pure SWIM state transitions (handle_alive/suspect/dead, suspicion_timeout, etc)
- membership.ml/mli: Kcas-based member table with Kcas_data.Hashtbl
- dissemination.ml/mli: Broadcast queue with transmit counting and message invalidation
- pending_acks.ml/mli: Ack tracking with Eio.Promise for async waiting
- transport.ml: UDP/TCP networking with Eio.Net
- protocol.ml: Main protocol loop with message handlers and probe cycles
- swim.ml: Public API with Cluster module
Design constraints followed:
- Eio only (no Lwt/Async/Mutex/Condition)
- All coordination via kcas (no locks)
- Result types for expected errors (no exceptions)
- Zero-copy buffer management