diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-30 09:17:13 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-30 09:17:13 +0300 |
| commit | ae6b3fde6d2ef130e2bb18dd2c6ee040687b143d (patch) | |
| tree | f2b831df9f1377cf0579496e7e82a46472c81d5d /gemfeed/atom.xml | |
| parent | 39b002074e735808daafa3b7f1fe960c9ab603b2 (diff) | |
Update content for html
Diffstat (limited to 'gemfeed/atom.xml')
| -rw-r--r-- | gemfeed/atom.xml | 2174 |
1 files changed, 997 insertions, 1177 deletions
diff --git a/gemfeed/atom.xml b/gemfeed/atom.xml index 0b9d9da9..33188a8e 100644 --- a/gemfeed/atom.xml +++ b/gemfeed/atom.xml @@ -1,12 +1,1008 @@ <?xml version="1.0" encoding="utf-8"?> <feed xmlns="http://www.w3.org/2005/Atom"> - <updated>2026-03-28T00:29:48+02:00</updated> + <updated>2026-03-30T09:16:50+03:00</updated> <title>foo.zone feed</title> <subtitle>To be in the .zone!</subtitle> <link href="https://foo.zone/gemfeed/atom.xml" rel="self" /> <link href="https://foo.zone/" /> <id>https://foo.zone/</id> <entry> + <title>Distributed Systems Simulator - Part 3: Advanced Examples and Protocol API</title> + <link href="https://foo.zone/gemfeed/2026-04-02-distributed-systems-simulator-part-3.html" /> + <id>https://foo.zone/gemfeed/2026-04-02-distributed-systems-simulator-part-3.html</id> + <updated>2026-04-02T00:00:00+03:00</updated> + <author> + <name>Paul Buetow aka snonux</name> + <email>paul@dev.buetow.org</email> + </author> + <summary>This is the third and final blog post of the Distributed Systems Simulator series. This part covers advanced simulation examples, the Raft consensus protocol, and the extensible Protocol API.</summary> + <content type="xhtml"> + <div xmlns="http://www.w3.org/1999/xhtml"> + <h1 style='display: inline' id='distributed-systems-simulator---part-3-advanced-examples-and-protocol-api'>Distributed Systems Simulator - Part 3: Advanced Examples and Protocol API</h1><br /> +<br /> +<span class='quote'>Published at 2026-04-02T00:00:00+03:00</span><br /> +<br /> +<span>This is the third and final blog post of the Distributed Systems Simulator series. This part covers advanced simulation examples, the Raft consensus protocol, and the extensible Protocol API.</span><br /> +<br /> +<a class='textlink' href='https://codeberg.org/snonux/ds-sim'>ds-sim on Codeberg (modernized, English-translated version)</a><br /> +<br /> +<span>These are all the posts of this series:</span><br /> +<br /> +<a class='textlink' href='./2026-03-31-distributed-systems-simulator-part-1.html'>2026-03-31 Distributed Systems Simulator - Part 1: Introduction and GUI</a><br /> +<a class='textlink' href='./2026-04-01-distributed-systems-simulator-part-2.html'>2026-04-01 Distributed Systems Simulator - Part 2: Built-in Protocols</a><br /> +<a class='textlink' href='./2026-04-02-distributed-systems-simulator-part-3.html'>2026-04-02 Distributed Systems Simulator - Part 3: Advanced Examples and Protocol API (You are currently reading this)</a><br /> +<br /> +<a href='./distributed-systems-simulator/ds-sim-screenshot.png'><img alt='Screenshot: The Distributed Systems Simulator running a Broadcast protocol simulation with 6 processes. The visualization shows message lines between process bars, with blue indicating delivered messages and green indicating messages still in transit.' title='Screenshot: The Distributed Systems Simulator running a Broadcast protocol simulation with 6 processes. The visualization shows message lines between process bars, with blue indicating delivered messages and green indicating messages still in transit.' src='./distributed-systems-simulator/ds-sim-screenshot.png' /></a><br /> +<br /> +<h2 style='display: inline' id='table-of-contents'>Table of Contents</h2><br /> +<br /> +<ul> +<li><a href='#distributed-systems-simulator---part-3-advanced-examples-and-protocol-api'>Distributed Systems Simulator - Part 3: Advanced Examples and Protocol API</a></li> +<li>⇢ <a href='#additional-examples'>Additional Examples</a></li> +<li>⇢ ⇢ <a href='#lamport-and-vector-timestamps'>Lamport and Vector Timestamps</a></li> +<li>⇢ ⇢ <a href='#simulating-slow-connections'>Simulating Slow Connections</a></li> +<li>⇢ ⇢ <a href='#raft-consensus-failover'>Raft Consensus Failover</a></li> +<li>⇢ <a href='#protocol-api'>Protocol API</a></li> +<li>⇢ ⇢ <a href='#class-hierarchy'>Class Hierarchy</a></li> +<li>⇢ ⇢ <a href='#implementing-a-custom-protocol'>Implementing a Custom Protocol</a></li> +<li>⇢ ⇢ <a href='#available-api-methods'>Available API Methods</a></li> +<li>⇢ ⇢ <a href='#example-reliable-multicast-implementation'>Example: Reliable Multicast Implementation</a></li> +<li>⇢ <a href='#project-statistics'>Project Statistics</a></li> +</ul><br /> +<h2 style='display: inline' id='additional-examples'>Additional Examples</h2><br /> +<br /> +<h3 style='display: inline' id='lamport-and-vector-timestamps'>Lamport and Vector Timestamps</h3><br /> +<br /> +<a href='./distributed-systems-simulator/lamport-timestamps.png'><img alt='Visualization: Lamport Timestamps displayed on the Berkeley Algorithm simulation. Each event on a process bar shows its Lamport timestamp as a number in parentheses. The timestamps increase monotonically and are updated according to the Lamport clock rules when messages are sent and received between P1, P2, and P3.' title='Visualization: Lamport Timestamps displayed on the Berkeley Algorithm simulation. Each event on a process bar shows its Lamport timestamp as a number in parentheses. The timestamps increase monotonically and are updated according to the Lamport clock rules when messages are sent and received between P1, P2, and P3.' src='./distributed-systems-simulator/lamport-timestamps.png' /></a><br /> +<br /> +<span class='quote'>"For many purposes, it is sufficient that all machines agree on the same time. It is not necessary that this time also agrees with real time, like every hour announced on the radio... For a certain class of algorithms, only the internal consistency of clocks is important." - Andrew Tanenbaum</span><br /> +<br /> +<span>Clocks that provide such a time are also known as logical clocks. Two implementations are realized in the simulator: Lamport timestamps and vector timestamps.</span><br /> +<br /> +<span>After activating the Lamport time switch in expert mode, the current Lamport timestamp appears at every event of a process. Each process has its own Lamport timestamp that is incremented when a message is sent or received. Each message carries the current Lamport time t_l(i) of the sending process i. When another process j receives this message, its Lamport timestamp t_l(j) is recalculated as:</span><br /> +<br /> +<pre> +t_l(j) := 1 + max(t_l(j), t_l(i)) +</pre> +<br /> +<span>The larger Lamport time of the sender and receiver process is used and then incremented by 1. After the Berkeley simulation shown here, P1 has Lamport timestamp 16, P2 has 14, and P3 has 15.</span><br /> +<br /> +<a href='./distributed-systems-simulator/vector-timestamps.png'><img alt='Visualization: Vector Timestamps displayed on the same Berkeley Algorithm simulation. Each event shows its vector timestamp as a tuple (v1,v2,v3) representing the known state of all three processes. The tuples grow as processes communicate and merge their knowledge of each other's progress.' title='Visualization: Vector Timestamps displayed on the same Berkeley Algorithm simulation. Each event shows its vector timestamp as a tuple (v1,v2,v3) representing the known state of all three processes. The tuples grow as processes communicate and merge their knowledge of each other's progress.' src='./distributed-systems-simulator/vector-timestamps.png' /></a><br /> +<br /> +<span>With the active vector time switch, all vector timestamps are displayed. Like the Lamport timestamp, each message includes the current vector timestamp of the sending process. With n participating processes, the vector timestamp v has size n. Each participating process i has its own index, accessible via v(i). When v is the vector timestamp of the receiving process j and w is the vector timestamp of the sending process, the new local vector timestamp of process j is calculated as follows:</span><br /> +<br /> +<pre> +for (i := 0; i < n; i++) { + if (i = j) { + v(i)++; + } else if (v(i) < w(i)) { + v(i) := w(i); + } +} +</pre> +<br /> +<span>By default, the vector timestamp is only incremented when a message is sent or received. In both cases, the sender and receiver each increment their own index in the vector timestamp by 1. Upon receiving a message, the local vector timestamp is then compared with the sender's, and the larger value is taken for all indices.</span><br /> +<br /> +<span>After the simulation, P1 has vector timestamp (8,10,6), P2 has (6,10,6), and P3 has (6,10,8).</span><br /> +<br /> +<span>The simulation settings include boolean variables "Lamport times affect all events" and "Vector times affect all events" (both default to false). When set to true, all events (not just message send/receive) will update the timestamps.</span><br /> +<br /> +<h3 style='display: inline' id='simulating-slow-connections'>Simulating Slow Connections</h3><br /> +<br /> +<a href='./distributed-systems-simulator/slow-connection.png'><img alt='Visualization: Slow connection simulation comparing Internal Synchronization (P1) and Christian's Method (P3) with P2 as server. P3 has high transmission times (2000-8000ms) simulating a slow network connection. P1 synchronizes to 21446ms (error: -1446ms) while P3 only reaches 16557ms (error: -3443ms), showing how slow connections degrade synchronization quality.' title='Visualization: Slow connection simulation comparing Internal Synchronization (P1) and Christian's Method (P3) with P2 as server. P3 has high transmission times (2000-8000ms) simulating a slow network connection. P1 synchronizes to 21446ms (error: -1446ms) while P3 only reaches 16557ms (error: -3443ms), showing how slow connections degrade synchronization quality.' src='./distributed-systems-simulator/slow-connection.png' /></a><br /> +<br /> +<span>The simulator can also simulate slow connections to a specific process. This example revisits the comparison of Internal Synchronization (P1) and Christian's Method (P3), with P2 serving both. In this scenario, P3 has a poor network connection, so messages to and from P3 always require a longer transmission time.</span><br /> +<br /> +<span>P3's minimum transmission time is set to 2000ms and maximum to 8000ms, while P1 and P2 keep the defaults (500ms/2000ms). The simulation duration is 20000ms. With the "Average transmission times" setting enabled, the effective transmission time for messages involving P3 is:</span><br /> +<br /> +<pre> +1/2 * (rand(500,2000) + rand(2000,8000)) = 1/2 * rand(2500,10000) = rand(1250,5000)ms +</pre> +<br /> +<span>Because P3 starts a new request before receiving the answer to its previous one, and because it always associates server responses with its most recently sent request, its RTT calculations become incorrect on each round, and its local time is poorly synchronized. P1 synchronizes to 21446ms (error: -1446ms) while P3 only reaches 16557ms (error: -3443ms).</span><br /> +<br /> +<h3 style='display: inline' id='raft-consensus-failover'>Raft Consensus Failover</h3><br /> +<br /> +<a href='./distributed-systems-simulator/raft-consensus-failover.png'><img alt='Screenshot: A 60-second Raft simulation with three processes. P1 starts as the initial leader, crashes at 3500ms, later recovers, P2 wins the reelection and remains leader, and P3 crashes later. The blue and red message lines show the continuing heartbeat and acknowledgment traffic during and after failover.' title='Screenshot: A 60-second Raft simulation with three processes. P1 starts as the initial leader, crashes at 3500ms, later recovers, P2 wins the reelection and remains leader, and P3 crashes later. The blue and red message lines show the continuing heartbeat and acknowledgment traffic during and after failover.' src='./distributed-systems-simulator/raft-consensus-failover.png' /></a><br /> +<br /> +<span>While modernizing ds-sim, I also added a simplified Raft Consensus example. The simulation is intentionally small: three processes, one initial leader, one crash, a clean reelection, a recovery of the old leader, and then another crash later in the run. This makes it possible to see the most important Raft transitions without being overwhelmed by cluster size.</span><br /> +<br /> +<span>The event log tells a very readable story. At <span class='inlinecode'>0ms</span>, <span class='inlinecode'>P1</span> starts as the initial leader in <span class='inlinecode'>term 0</span>. It immediately sends a heartbeat and an <span class='inlinecode'>appendEntry</span> message carrying the log entry <span class='inlinecode'>cmd1</span>. <span class='inlinecode'>P2</span> joins at <span class='inlinecode'>100ms</span>, <span class='inlinecode'>P3</span> at <span class='inlinecode'>1700ms</span>, and both acknowledge the leader's traffic. At that point the cluster is healthy: one leader, two followers, successful heartbeats, and successful log replication.</span><br /> +<br /> +<span>At <span class='inlinecode'>3500ms</span>, <span class='inlinecode'>P1</span> crashes. The followers still process the last in-flight messages, but once the election timeout expires, <span class='inlinecode'>P2</span> becomes a candidate and sends a <span class='inlinecode'>voteRequest</span> for <span class='inlinecode'>term 1</span>. <span class='inlinecode'>P3</span> grants that vote, and at <span class='inlinecode'>9395ms</span> the log records the decisive line:</span><br /> +<br /> +<pre> +009395ms: PID: 2; ... Leader elected by majority vote: process 2 (term 1) +</pre> +<br /> +<span>That transition is followed immediately by new heartbeats and a new <span class='inlinecode'>appendEntry</span>, which is exactly what you want to see in a Raft simulation: leadership is not just declared, it is exercised.</span><br /> +<br /> +<span>At <span class='inlinecode'>12002ms</span>, the old leader <span class='inlinecode'>P1</span> recovers. Importantly, it does not try to reclaim control. Instead, it receives heartbeats from <span class='inlinecode'>P2</span> and answers with <span class='inlinecode'>heartbeatAck</span> messages, rejoining the cluster as a follower. That is one of the most useful teaching moments in the log, because it makes the term-based leadership model concrete: the recovered node does not become leader again just because it used to be one.</span><br /> +<br /> +<span>At <span class='inlinecode'>20000ms</span>, <span class='inlinecode'>P3</span> crashes. The cluster continues running with <span class='inlinecode'>P2</span> as leader and <span class='inlinecode'>P1</span> as follower for the rest of the 60-second simulation. The log remains dominated by periodic heartbeats from <span class='inlinecode'>P2</span> and acknowledgments from <span class='inlinecode'>P1</span>, showing that the system stays stable even after a second failure.</span><br /> +<br /> +<span>This single scenario demonstrates several core Raft properties in one replay:</span><br /> +<br /> +<ul> +<li>Stable startup leadership</li> +<li>Heartbeats and follower acknowledgments</li> +<li>Log replication</li> +<li>Leader failure detection</li> +<li>Majority-based reelection</li> +<li>Safe reintegration of a recovered former leader</li> +<li>Continued service after a later follower crash</li> +</ul><br /> +<span>It is also a good example of why a simulator is useful for distributed systems. In a real production system, reconstructing this sort of sequence would require stitching together logs from multiple nodes. Here, the message flow, the crashes, the recoveries, and the Lamport/vector timestamps are all visible in one place.</span><br /> +<br /> +<h2 style='display: inline' id='protocol-api'>Protocol API</h2><br /> +<br /> +<span>The simulator was designed from the ground up to be extensible. Users can implement their own protocols in Java by extending the <span class='inlinecode'>VSAbstractProtocol</span> base class. Each protocol has its own class in the <span class='inlinecode'>protocols.implementations</span> package.</span><br /> +<br /> +<h3 style='display: inline' id='class-hierarchy'>Class Hierarchy</h3><br /> +<br /> +<pre> +VSAbstractEvent + +-- VSAbstractProtocol (base class for all protocols) + +-- VSDummyProtocol + +-- VSPingPongProtocol + +-- VSBroadcastProtocol + +-- VSInternalTimeSyncProtocol + +-- VSExternalTimeSyncProtocol + +-- VSBerkeleyTimeProtocol + +-- VSOnePhaseCommitProtocol + +-- VSTwoPhaseCommitProtocol + +-- VSBasicMulticastProtocol + +-- VSReliableMulticastProtocol +</pre> +<br /> +<h3 style='display: inline' id='implementing-a-custom-protocol'>Implementing a Custom Protocol</h3><br /> +<br /> +<span>Each protocol class must implement the following methods:</span><br /> +<br /> +<ul> +<li>A public constructor: Must specify whether the client or the server initiates requests, using <span class='inlinecode'>VSAbstractProtocol.HAS_ON_CLIENT_START</span> or <span class='inlinecode'>VSAbstractProtocol.HAS_ON_SERVER_START</span>.</li> +<li><span class='inlinecode'>onClientInit()</span> / <span class='inlinecode'>onServerInit()</span>: Called once before the protocol is first used. Used to initialize protocol variables and attributes via the VSPrefs methods (e.g. <span class='inlinecode'>initVector</span>, <span class='inlinecode'>initLong</span>). Variables initialized this way appear in the process editor and can be configured by the user.</li> +<li><span class='inlinecode'>onClientReset()</span> / <span class='inlinecode'>onServerReset()</span>: Called each time the simulation is reset.</li> +<li><span class='inlinecode'>onClientStart()</span> / <span class='inlinecode'>onServerStart()</span>: Called when the client/server initiates a request. Typically creates and sends a <span class='inlinecode'>VSMessage</span> object.</li> +<li><span class='inlinecode'>onClientRecv(VSMessage)</span> / <span class='inlinecode'>onServerRecv(VSMessage)</span>: Called when a message arrives.</li> +<li><span class='inlinecode'>onClientSchedule()</span> / <span class='inlinecode'>onServerSchedule()</span>: Called when a scheduled alarm fires.</li> +<li><span class='inlinecode'>toString()</span>: Optional. Customizes log output for this protocol.</li> +</ul><br /> +<h3 style='display: inline' id='available-api-methods'>Available API Methods</h3><br /> +<br /> +<span>Methods inherited from <span class='inlinecode'>VSAbstractProtocol</span>:</span><br /> +<br /> +<ul> +<li><span class='inlinecode'>sendMessage(VSMessage message)</span>: Sends a protocol message (automatically updates Lamport and Vector timestamps)</li> +<li><span class='inlinecode'>hasOnServerStart()</span>: Whether the server or client initiates requests</li> +<li><span class='inlinecode'>isServer()</span> / <span class='inlinecode'>isClient()</span>: Whether the current process has the protocol activated as server/client</li> +<li><span class='inlinecode'>scheduleAt(long time)</span>: Creates an alarm that fires at the given local process time, triggering <span class='inlinecode'>onClientSchedule()</span> or <span class='inlinecode'>onServerSchedule()</span></li> +<li><span class='inlinecode'>removeSchedules()</span>: Cancels all pending alarms in the current context</li> +<li><span class='inlinecode'>getNumProcesses()</span>: Returns the total number of processes in the simulation</li> +</ul><br /> +<span>Process methods available via the inherited <span class='inlinecode'>process</span> attribute:</span><br /> +<br /> +<ul> +<li><span class='inlinecode'>getTime()</span> / <span class='inlinecode'>setTime(long)</span>: Get/set the local process time</li> +<li><span class='inlinecode'>getGlobalTime()</span>: Get the current global simulation time</li> +<li><span class='inlinecode'>getClockVariance()</span> / <span class='inlinecode'>setClockVariance(float)</span>: Get/set the clock drift</li> +<li><span class='inlinecode'>getLamportTime()</span> / <span class='inlinecode'>setLamportTime(long)</span>: Get/set the Lamport timestamp</li> +<li><span class='inlinecode'>getVectorTime()</span> / <span class='inlinecode'>updateVectorTime(VSVectorTime)</span>: Get/update the vector timestamp</li> +<li><span class='inlinecode'>getProcessID()</span>: Get the process PID</li> +<li><span class='inlinecode'>isCrashed()</span> / <span class='inlinecode'>isCrashed(boolean)</span>: Check or set crash state</li> +<li><span class='inlinecode'>getRandomPercentage()</span>: Get a random value between 0 and 100</li> +</ul><br /> +<span>Message methods (<span class='inlinecode'>VSMessage</span>):</span><br /> +<br /> +<ul> +<li><span class='inlinecode'>new VSMessage()</span>: Create a new message</li> +<li><span class='inlinecode'>getMessageID()</span>: Get the message NID</li> +<li><span class='inlinecode'>setBoolean(key, value)</span> / <span class='inlinecode'>getBoolean(key)</span>: Set/get boolean data</li> +<li><span class='inlinecode'>setInteger(key, value)</span> / <span class='inlinecode'>getInteger(key)</span>: Set/get integer data</li> +<li><span class='inlinecode'>setLong(key, value)</span> / <span class='inlinecode'>getLong(key)</span>: Set/get long data</li> +<li><span class='inlinecode'>setString(key, value)</span> / <span class='inlinecode'>getString(key)</span>: Set/get string data</li> +<li><span class='inlinecode'>getSendingProcess()</span>: Get a reference to the sending process</li> +<li><span class='inlinecode'>isServerMessage()</span>: Whether it's a server or client message</li> +</ul><br /> +<h3 style='display: inline' id='example-reliable-multicast-implementation'>Example: Reliable Multicast Implementation</h3><br /> +<br /> +<span>Here is a condensed example showing key parts of the Reliable Multicast Protocol implementation:</span><br /> +<br /> +<!-- Generator: GNU source-highlight 3.1.9 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><b><u><font color="#000000">public</font></u></b> <b><u><font color="#000000">class</font></u></b> VSReliableMulticastProtocol <b><u><font color="#000000">extends</font></u></b> VSAbstractProtocol { + <b><u><font color="#000000">public</font></u></b> VSReliableMulticastProtocol() { + <i><font color="silver">// The client initiates requests</font></i> + <b><u><font color="#000000">super</font></u></b>(VSAbstractProtocol.HAS_ON_CLIENT_START); + <b><u><font color="#000000">super</font></u></b>.setClassname(<b><u><font color="#000000">super</font></u></b>.getClass().toString()); + } + + <b><u><font color="#000000">private</font></u></b> ArrayList<Integer> pids; + + <i><font color="silver">// Initialize protocol variables (editable in the process editor)</font></i> + <b><u><font color="#000000">public</font></u></b> <b><font color="#000000">void</font></b> onClientInit() { + Vector<Integer> vec = <b><u><font color="#000000">new</font></u></b> Vector<Integer>(); + vec.add(<font color="#000000">1</font>); vec.add(<font color="#000000">3</font>); + <b><u><font color="#000000">super</font></u></b>.initVector(<font color="#808080">"pids"</font>, vec, <font color="#808080">"PIDs of participating processes"</font>); + <b><u><font color="#000000">super</font></u></b>.initLong(<font color="#808080">"timeout"</font>, <font color="#000000">2500</font>, <font color="#808080">"Time until resend"</font>, <font color="#808080">"ms"</font>); + } + + <i><font color="silver">// Send multicast to all servers that haven't ACKed yet</font></i> + <b><u><font color="#000000">public</font></u></b> <b><font color="#000000">void</font></b> onClientStart() { + <b><u><font color="#000000">if</font></u></b> (pids.size() != <font color="#000000">0</font>) { + <b><font color="#000000">long</font></b> timeout = <b><u><font color="#000000">super</font></u></b>.getLong(<font color="#808080">"timeout"</font>) + process.getTime(); + <b><u><font color="#000000">super</font></u></b>.scheduleAt(timeout); + VSMessage message = <b><u><font color="#000000">new</font></u></b> VSMessage(); + message.setBoolean(<font color="#808080">"isMulticast"</font>, <b><u><font color="#000000">true</font></u></b>); + <b><u><font color="#000000">super</font></u></b>.sendMessage(message); + } + } + + <i><font color="silver">// Handle ACK from a server</font></i> + <b><u><font color="#000000">public</font></u></b> <b><font color="#000000">void</font></b> onClientRecv(VSMessage recvMessage) { + <b><u><font color="#000000">if</font></u></b> (pids.size() != <font color="#000000">0</font> && recvMessage.getBoolean(<font color="#808080">"isAck"</font>)) { + Integer pid = recvMessage.getIntegerObj(<font color="#808080">"pid"</font>); + <b><u><font color="#000000">if</font></u></b> (pids.contains(pid)) + pids.remove(pid); + <b><u><font color="#000000">super</font></u></b>.log(<font color="#808080">"ACK from Process "</font> + pid + <font color="#808080">" received!"</font>); + <b><u><font color="#000000">if</font></u></b> (pids.size() == <font color="#000000">0</font>) { + <b><u><font color="#000000">super</font></u></b>.log(<font color="#808080">"ACKs from all processes received!"</font>); + <b><u><font color="#000000">super</font></u></b>.removeSchedules(); + } + } + } + + <i><font color="silver">// Retry on timeout</font></i> + <b><u><font color="#000000">public</font></u></b> <b><font color="#000000">void</font></b> onClientSchedule() { onClientStart(); } +} +</pre> +<br /> +<h2 style='display: inline' id='project-statistics'>Project Statistics</h2><br /> +<br /> +<span>The original VS-Sim project (August 2008) was written in Java 6 and consisted of:</span><br /> +<br /> +<ul> +<li>61 source files across 12 Java packages</li> +<li>Approximately 15,710 lines of code</li> +<li>2.2 MB of generated Javadoc documentation</li> +<li>142 KB compiled JAR file</li> +<li>10 built-in protocols</li> +<li>163 configurable settings</li> +</ul><br /> +<span>The modernized successor ds-sim (version 1.1.0) has been updated to Java 21 and translated to English:</span><br /> +<br /> +<ul> +<li>146 source files (117 main + 29 test) across 19 Java packages</li> +<li>Approximately 27,900 lines of code (22,400 main + 5,500 test)</li> +<li>12 built-in protocols</li> +<li>208 unit tests</li> +<li>269 configurable settings</li> +</ul><br /> +<a class='textlink' href='https://codeberg.org/snonux/ds-sim'>ds-sim source code on Codeberg</a><br /> +<a class='textlink' href='https://codeberg.org/snonux/vs-sim'>vs-sim source code on Codeberg (original German version, 2008)</a><br /> +<br /> +<span>Other related posts are:</span><br /> +<br /> +<a class='textlink' href='./2026-03-01-loadbars-0.13.0-released.html'>2026-03-01 Loadbars 0.13.0 released</a><br /> +<a class='textlink' href='./2022-12-24-ultrarelearning-java-my-takeaways.html'>2022-12-24 (Re)learning Java - My takeaways</a><br /> +<a class='textlink' href='./2022-03-06-the-release-of-dtail-4.0.0.html'>2022-03-06 The release of DTail 4.0.0</a><br /> +<a class='textlink' href='./2016-11-20-object-oriented-programming-with-ansi-c.html'>2016-11-20 Object oriented programming with ANSI C</a><br /> +<br /> +<span>E-Mail your comments to <span class='inlinecode'>paul@nospam.buetow.org</span></span><br /> +<br /> +<a class='textlink' href='../'>Back to the main site</a><br /> + </div> + </content> + </entry> + <entry> + <title>Distributed Systems Simulator - Part 2: Built-in Protocols</title> + <link href="https://foo.zone/gemfeed/2026-04-01-distributed-systems-simulator-part-2.html" /> + <id>https://foo.zone/gemfeed/2026-04-01-distributed-systems-simulator-part-2.html</id> + <updated>2026-04-01T00:00:00+03:00</updated> + <author> + <name>Paul Buetow aka snonux</name> + <email>paul@dev.buetow.org</email> + </author> + <summary>This is the second blog post of the Distributed Systems Simulator series. This part covers all 10 built-in protocols with examples.</summary> + <content type="xhtml"> + <div xmlns="http://www.w3.org/1999/xhtml"> + <h1 style='display: inline' id='distributed-systems-simulator---part-2-built-in-protocols'>Distributed Systems Simulator - Part 2: Built-in Protocols</h1><br /> +<br /> +<span class='quote'>Published at 2026-04-01T00:00:00+03:00</span><br /> +<br /> +<span>This is the second blog post of the Distributed Systems Simulator series. This part covers all 10 built-in protocols with examples.</span><br /> +<br /> +<a class='textlink' href='https://codeberg.org/snonux/ds-sim'>ds-sim on Codeberg (modernized, English-translated version)</a><br /> +<br /> +<span>These are all the posts of this series:</span><br /> +<br /> +<a class='textlink' href='./2026-03-31-distributed-systems-simulator-part-1.html'>2026-03-31 Distributed Systems Simulator - Part 1: Introduction and GUI</a><br /> +<a class='textlink' href='./2026-04-01-distributed-systems-simulator-part-2.html'>2026-04-01 Distributed Systems Simulator - Part 2: Built-in Protocols (You are currently reading this)</a><br /> +<a class='textlink' href='./2026-04-02-distributed-systems-simulator-part-3.html'>2026-04-02 Distributed Systems Simulator - Part 3: Advanced Examples and Protocol API</a><br /> +<br /> +<a href='./distributed-systems-simulator/ds-sim-screenshot.png'><img alt='Screenshot: The Distributed Systems Simulator running a Broadcast protocol simulation with 6 processes. The visualization shows message lines between process bars, with blue indicating delivered messages and green indicating messages still in transit.' title='Screenshot: The Distributed Systems Simulator running a Broadcast protocol simulation with 6 processes. The visualization shows message lines between process bars, with blue indicating delivered messages and green indicating messages still in transit.' src='./distributed-systems-simulator/ds-sim-screenshot.png' /></a><br /> +<br /> +<h2 style='display: inline' id='table-of-contents'>Table of Contents</h2><br /> +<br /> +<ul> +<li><a href='#distributed-systems-simulator---part-2-built-in-protocols'>Distributed Systems Simulator - Part 2: Built-in Protocols</a></li> +<li>⇢ <a href='#protocols-and-examples'>Protocols and Examples</a></li> +<li>⇢ ⇢ <a href='#dummy-protocol'>Dummy Protocol</a></li> +<li>⇢ ⇢ <a href='#ping-pong-protocol'>Ping-Pong Protocol</a></li> +<li>⇢ ⇢ <a href='#broadcast-protocol'>Broadcast Protocol</a></li> +<li>⇢ ⇢ <a href='#internal-synchronization-protocol'>Internal Synchronization Protocol</a></li> +<li>⇢ ⇢ <a href='#christian-s-method-external-synchronization'>Christian's Method (External Synchronization)</a></li> +<li>⇢ ⇢ <a href='#berkeley-algorithm'>Berkeley Algorithm</a></li> +<li>⇢ ⇢ <a href='#one-phase-commit-protocol'>One-Phase Commit Protocol</a></li> +<li>⇢ ⇢ <a href='#two-phase-commit-protocol'>Two-Phase Commit Protocol</a></li> +<li>⇢ ⇢ <a href='#basic-multicast-protocol'>Basic Multicast Protocol</a></li> +<li>⇢ ⇢ <a href='#reliable-multicast-protocol'>Reliable Multicast Protocol</a></li> +</ul><br /> +<h2 style='display: inline' id='protocols-and-examples'>Protocols and Examples</h2><br /> +<br /> +<span>The simulator comes with 10 built-in protocols. As described earlier, protocols are distinguished between server-side and client-side. Servers can respond to client messages, and clients can respond to server messages. Each process can support any number of protocols on both the client and server side. Users can also implement their own protocols using the simulator's Protocol API (see the Protocol API section).</span><br /> +<br /> +<span>The program directory contains a <span class='inlinecode'>saved-simulations</span> folder with example simulations for each protocol as serialized <span class='inlinecode'>.dat</span> files.</span><br /> +<br /> +<h3 style='display: inline' id='dummy-protocol'>Dummy Protocol</h3><br /> +<br /> +<span>The Dummy Protocol serves only as a template for creating custom protocols. When using the Dummy Protocol, only log messages are output when events occur. No further actions are performed.</span><br /> +<br /> +<h3 style='display: inline' id='ping-pong-protocol'>Ping-Pong Protocol</h3><br /> +<br /> +<a href='./distributed-systems-simulator/ping-pong.png'><img alt='Visualization: The Ping-Pong Protocol showing two processes (P1 and P2) exchanging messages in a continuous back-and-forth pattern. Blue lines represent delivered messages bouncing between the process bars over a 15-second simulation.' title='Visualization: The Ping-Pong Protocol showing two processes (P1 and P2) exchanging messages in a continuous back-and-forth pattern. Blue lines represent delivered messages bouncing between the process bars over a 15-second simulation.' src='./distributed-systems-simulator/ping-pong.png' /></a><br /> +<br /> +<span>In the Ping-Pong Protocol, two processes -- Client P1 and Server P2 -- constantly send messages back and forth. The Ping-Pong client starts the first request, to which the server responds to the client. The client then responds again, and so on. Each message includes a counter that is incremented at each station and logged in the log window.</span><br /> +<br /> +<pre> +Programmed Ping-Pong Events: + +| Time (ms) | PID | Event | +|-----------|-----|--------------------------------| +| 0 | 1 | Ping-Pong Client activate | +| 0 | 2 | Ping-Pong Server activate | +| 0 | 1 | Ping-Pong Client request start | +</pre> +<br /> +<span>It is important that Process 1 activates its Ping-Pong client before starting a Ping-Pong client request. Before a process can start a request, it must have the corresponding protocol activated. This also applies to all other protocols.</span><br /> +<br /> +<span>**Ping-Pong Storm Variant**</span><br /> +<br /> +<a href='./distributed-systems-simulator/ping-pong-storm.png'><img alt='Visualization: The Ping-Pong Storm variant with three processes. P1 is the client, P2 and P3 are both servers. The visualization shows an exponentially growing number of messages as each client message generates two server responses, creating a dense web of blue and green message lines.' title='Visualization: The Ping-Pong Storm variant with three processes. P1 is the client, P2 and P3 are both servers. The visualization shows an exponentially growing number of messages as each client message generates two server responses, creating a dense web of blue and green message lines.' src='./distributed-systems-simulator/ping-pong-storm.png' /></a><br /> +<br /> +<span>By adding a third process P3 as an additional Ping-Pong server, a Ping-Pong "Storm" can be realized. Since every client message now receives two server responses, the number of messages doubles with each round, creating an exponential message flood.</span><br /> +<br /> +<pre> +Programmed Ping-Pong Storm Events: + +| Time (ms) | PID | Event | +|-----------|-----|--------------------------------| +| 0 | 1 | Ping-Pong Client activate | +| 0 | 2 | Ping-Pong Server activate | +| 0 | 3 | Ping-Pong Server activate | +| 0 | 1 | Ping-Pong Client request start | +</pre> +<br /> +<h3 style='display: inline' id='broadcast-protocol'>Broadcast Protocol</h3><br /> +<br /> +<a href='./distributed-systems-simulator/broadcast.png'><img alt='Visualization: The Broadcast Protocol with 6 processes (P1-P6). Dense crossing message lines show how a broadcast from P1 propagates to all processes, with each process re-broadcasting to others. Blue lines indicate delivered messages, green lines indicate messages still in transit.' title='Visualization: The Broadcast Protocol with 6 processes (P1-P6). Dense crossing message lines show how a broadcast from P1 propagates to all processes, with each process re-broadcasting to others. Blue lines indicate delivered messages, green lines indicate messages still in transit.' src='./distributed-systems-simulator/broadcast.png' /></a><br /> +<br /> +<span>The Broadcast Protocol behaves similarly to the Ping-Pong Protocol. The difference is that the protocol tracks -- using a unique Broadcast ID -- which messages have already been sent. Each process re-broadcasts all received messages to others, provided it has not already sent them.</span><br /> +<br /> +<span>In this case, no distinction is made between client and server, so that the same action is performed when a message arrives at either side. This makes it possible, using multiple processes, to create a broadcast. P1 is the client and starts a request at 0ms and 2500ms. The simulation duration is exactly 5000ms. Since a client can only receive server messages and a server can only receive client messages, every process in this simulation is both server and client.</span><br /> +<br /> +<pre> +Programmed Broadcast Events: + +| Time (ms) | PID | Event | +|-----------|-----|----------------------------------| +| 0 | 1-6 | Broadcast Client activate | +| 0 | 1-6 | Broadcast Server activate | +| 0 | 1 | Broadcast Client request start | +| 2500 | 1 | Broadcast Client request start | +</pre> +<br /> +<h3 style='display: inline' id='internal-synchronization-protocol'>Internal Synchronization Protocol</h3><br /> +<br /> +<a href='./distributed-systems-simulator/int-sync.png'><img alt='Visualization: Internal Synchronization with 2 processes. P1 (client, clock drift 0.1) shows a faster-running clock reaching 15976ms by simulation end. The blue message lines show P1 periodically synchronizing with P2 (server, no drift), with the time corrections visible as slight adjustments in P1's timeline.' title='Visualization: Internal Synchronization with 2 processes. P1 (client, clock drift 0.1) shows a faster-running clock reaching 15976ms by simulation end. The blue message lines show P1 periodically synchronizing with P2 (server, no drift), with the time corrections visible as slight adjustments in P1's timeline.' src='./distributed-systems-simulator/int-sync.png' /></a><br /> +<br /> +<span>The Internal Synchronization Protocol is used for synchronizing the local process time, which can be applied when a process time is running incorrectly due to clock drift. When the client wants to synchronize its (incorrect) local process time t_c with a server, it sends a client request. The server responds with its own local process time t_s, allowing the client to calculate a new, more accurate time for itself.</span><br /> +<br /> +<span>After receiving the server response, the client P1 calculates its new local process time as:</span><br /> +<br /> +<pre> +t_c := t_s + 1/2 * (t'_min + t'_max) +</pre> +<br /> +<span>This synchronizes P1's local time with an error of less than 1/2 * (t'_max - t'_min), where t'_min and t'_max are the assumed minimum and maximum transmission times configured in the protocol settings.</span><br /> +<br /> +<span>In the example, the client process has a clock drift of 0.1 and the server has 0.0. The client starts a request at local process times 0ms, 5000ms, and 10000ms. By simulation end, P1's time is synchronized to 15976ms (an error of -976ms from the global 15000ms).</span><br /> +<br /> +<pre> +Programmed Internal Sync Events: + +| Time (ms) | PID | Event | +|-----------|-----|------------------------------------| +| 0 | 1 | Internal Sync Client activate | +| 0 | 2 | Internal Sync Server activate | +| 0 | 1 | Internal Sync Client request start | +| 5000 | 1 | Internal Sync Client request start | +| 10000 | 1 | Internal Sync Client request start | +</pre> +<br /> +<span>Protocol variables (client-side):</span><br /> +<br /> +<ul> +<li>Min. transmission time (Long: 500): The assumed t'_min in milliseconds</li> +<li>Max. transmission time (Long: 2000): The assumed t'_max in milliseconds</li> +</ul><br /> +<span>These can differ from the actual message transmission times t_min and t_max, allowing simulation of scenarios where the protocol is misconfigured and large synchronization errors occur.</span><br /> +<br /> +<h3 style='display: inline' id='christian-s-method-external-synchronization'>Christian's Method (External Synchronization)</h3><br /> +<br /> +<a href='./distributed-systems-simulator/christians.png'><img alt='Visualization: Comparison of Internal Synchronization (P1) and Christian's Method (P3) with P2 as shared server. Both P1 and P3 have clock drift 0.1. The visualization shows P1 synchronized to 14567ms (error: -433ms) while P3 synchronized to 15539ms (error: -539ms), demonstrating the different accuracy of the two methods.' title='Visualization: Comparison of Internal Synchronization (P1) and Christian's Method (P3) with P2 as shared server. Both P1 and P3 have clock drift 0.1. The visualization shows P1 synchronized to 14567ms (error: -433ms) while P3 synchronized to 15539ms (error: -539ms), demonstrating the different accuracy of the two methods.' src='./distributed-systems-simulator/christians.png' /></a><br /> +<br /> +<span>Christian's Method uses the RTT (Round Trip Time) to approximate the transmission time of individual messages. When the client wants to synchronize its local time t_c with a server, it sends a request and measures the RTT t_rtt until the server response arrives. The server response contains the local process time t_s from the moment the server sent the response. The client then calculates its new local time as:</span><br /> +<br /> +<pre> +t_c := t_s + 1/2 * t_rtt |
