summaryrefslogtreecommitdiff
path: root/docs/developer-guide.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/developer-guide.md')
-rw-r--r--docs/developer-guide.md537
1 files changed, 537 insertions, 0 deletions
diff --git a/docs/developer-guide.md b/docs/developer-guide.md
new file mode 100644
index 0000000..ed0f8e1
--- /dev/null
+++ b/docs/developer-guide.md
@@ -0,0 +1,537 @@
+# DS-Sim Developer Guide
+
+This guide explains how to extend DS-Sim with new protocols, events, and features.
+
+## Table of Contents
+1. [Creating a New Protocol](#creating-a-new-protocol)
+2. [Creating Custom Events](#creating-custom-events)
+3. [Working with Time and Timestamps](#working-with-time-and-timestamps)
+4. [Message Passing](#message-passing)
+5. [Testing Your Components](#testing-your-components)
+6. [Best Practices](#best-practices)
+
+## Creating a New Protocol
+
+### Step 1: Understand the Protocol Framework
+
+All protocols extend `VSAbstractProtocol` and must implement both server and client sides, even if one side does nothing. The framework supports two initialization patterns:
+
+- **Server-initiated**: Protocol starts from server side (`HAS_ON_SERVER_START = true`)
+- **Client-initiated**: Protocol starts from client side (`HAS_ON_CLIENT_START = false`)
+
+### Step 2: Create Your Protocol Class
+
+```java
+package protocols.implementations;
+
+import core.VSMessage;
+import protocols.VSAbstractProtocol;
+
+public class VSMyProtocol extends VSAbstractProtocol {
+
+ // Protocol-specific constants
+ private static final String MSG_REQUEST = "REQUEST";
+ private static final String MSG_RESPONSE = "RESPONSE";
+
+ // State variables (separate for client/server)
+ private int serverState;
+ private int clientState;
+
+ public VSMyProtocol() {
+ // true = server starts, false = client starts
+ super(HAS_ON_SERVER_START);
+ }
+
+ // Server-side implementation
+ @Override
+ public void onServerInit() {
+ // Initialize server state
+ serverState = 0;
+ // Set any server preferences
+ setBoolean("myprotocol.server.enabled", true);
+ }
+
+ @Override
+ public void onServerStart() {
+ // Server initiates the protocol
+ VSMessage msg = new VSMessage();
+ msg.setString("type", MSG_REQUEST);
+ msg.setInteger("value", 42);
+ sendMessage(msg); // Broadcasts to all clients
+ }
+
+ @Override
+ public void onServerRecv(VSMessage message) {
+ // Handle messages from clients
+ String type = message.getString("type");
+ if (MSG_RESPONSE.equals(type)) {
+ int clientId = message.getSenderNum();
+ int value = message.getInteger("value");
+ process.log("Received response from client " + clientId + ": " + value);
+ }
+ }
+
+ @Override
+ public void onServerSchedule() {
+ // Called when a scheduled server event fires
+ // Schedule periodic actions using scheduleAt(time)
+ }
+
+ @Override
+ public void onServerReset() {
+ // Clean up server state
+ serverState = 0;
+ }
+
+ // Client-side implementation
+ @Override
+ public void onClientInit() {
+ // Initialize client state
+ clientState = 0;
+ setBoolean("myprotocol.client.autorespond", true);
+ }
+
+ @Override
+ public void onClientStart() {
+ // Only called if HAS_ON_CLIENT_START = false
+ }
+
+ @Override
+ public void onClientRecv(VSMessage message) {
+ // Handle messages from server
+ String type = message.getString("type");
+ if (MSG_REQUEST.equals(type)) {
+ int value = message.getInteger("value");
+
+ // Process the request
+ clientState = value * 2;
+
+ // Send response
+ VSMessage response = new VSMessage();
+ response.setString("type", MSG_RESPONSE);
+ response.setInteger("value", clientState);
+ sendMessage(response);
+ }
+ }
+
+ @Override
+ public void onClientSchedule() {
+ // Called when a scheduled client event fires
+ }
+
+ @Override
+ public void onClientReset() {
+ // Clean up client state
+ clientState = 0;
+ }
+}
+```
+
+### Step 3: Register Your Protocol
+
+Add your protocol to `VSRegisteredEvents.init()`:
+
+```java
+public static void init(VSPrefs prefs_) {
+ // ... existing registrations ...
+ registerEvent("protocols.implementations.VSMyProtocol");
+}
+```
+
+### Step 4: Protocol Communication Patterns
+
+#### Broadcast (Server to All Clients)
+```java
+// In server code
+VSMessage msg = new VSMessage();
+sendMessage(msg); // Automatically sent to all clients
+```
+
+#### Unicast (Client to Server)
+```java
+// In client code
+VSMessage msg = new VSMessage();
+sendMessage(msg); // Automatically sent to server only
+```
+
+#### Selective Send (Server to Specific Client)
+```java
+// In server code - requires custom handling
+VSMessage msg = new VSMessage();
+msg.setInteger("targetClient", 2); // Custom field
+sendMessage(msg); // Clients must filter
+```
+
+### Step 5: Using Scheduled Events
+
+```java
+// Schedule a task to run at local time 1000
+scheduleAt(1000);
+
+// This will trigger onServerSchedule() or onClientSchedule()
+@Override
+public void onServerSchedule() {
+ // Periodic action
+ process.log("Scheduled event triggered");
+
+ // Reschedule for next interval
+ long nextTime = process.getTime() + 500;
+ scheduleAt(nextTime);
+}
+```
+
+## Creating Custom Events
+
+### Basic Event
+
+```java
+package events.implementations;
+
+import events.VSAbstractEvent;
+
+public class VSMyEvent extends VSAbstractEvent {
+
+ private String eventData;
+
+ @Override
+ public void onInit() {
+ // Called once when event is first created
+ setClassname(getClass().getName());
+ eventData = getString("myevent.data", "default");
+ }
+
+ @Override
+ public void onStart() {
+ // Called when event executes
+ process.log("MyEvent executing with data: " + eventData);
+
+ // Optionally schedule another event
+ VSMyEvent nextEvent = new VSMyEvent();
+ VSTask task = new VSTask(
+ process.getTime() + 100, // When to execute
+ process, // Which process
+ nextEvent, // What event
+ VSTask.LOCAL // LOCAL or GLOBAL time
+ );
+ // Add task through simulator
+ }
+
+ @Override
+ protected String createShortname(String savedShortname) {
+ return "MyEvent";
+ }
+}
+```
+
+### Copyable Event
+
+```java
+public class VSCopyableMyEvent extends VSAbstractEvent implements VSCopyableEvent {
+
+ private int counter;
+
+ @Override
+ public void initCopy(VSAbstractEvent copy) {
+ if (copy instanceof VSCopyableMyEvent) {
+ VSCopyableMyEvent myCopy = (VSCopyableMyEvent) copy;
+ myCopy.counter = this.counter;
+ }
+ }
+
+ // ... rest of implementation
+}
+```
+
+### Timestamp-Triggered Event
+
+```java
+public class VSCustomTimestampEvent extends VSTimestampTriggeredEvent {
+
+ public VSCustomTimestampEvent() {
+ // Trigger when Lamport time >= 50
+ super(50, ComparisonOperator.GREATER_EQUAL);
+ }
+
+ @Override
+ protected void onTimestampReached() {
+ // This fires when condition is met
+ process.log("Lamport time reached 50!");
+
+ // Highlight process
+ if (process instanceof VSInternalProcess) {
+ ((VSInternalProcess) process).highlightOn();
+ }
+ }
+}
+```
+
+## Working with Time and Timestamps
+
+### Time Types in DS-Sim
+
+1. **Global Time**: Simulation-wide clock (milliseconds)
+2. **Local Time**: Per-process clock with drift
+3. **Lamport Time**: Logical timestamp for ordering
+4. **Vector Time**: Vector clock for causality
+
+### Accessing Time Values
+
+```java
+// In a protocol or event
+long globalTime = process.getGlobalTime();
+long localTime = process.getTime(); // Local time
+long lamportTime = process.getLamportTime();
+VSVectorTime vectorTime = process.getVectorTime();
+
+// Increase timestamps (done automatically for messages)
+process.increaseLamportTime();
+process.increaseVectorTime();
+```
+
+### Clock Drift Simulation
+
+```java
+// In VSInternalProcess configuration
+setFloat("process.clock.variance", 0.1f); // 10% drift
+```
+
+## Message Passing
+
+### Message Structure
+
+```java
+// Creating a message
+VSMessage msg = new VSMessage();
+
+// Set data - supports various types
+msg.setString("type", "REQUEST");
+msg.setInteger("sequence", 42);
+msg.setBoolean("urgent", true);
+msg.setFloat("value", 3.14f);
+msg.setLong("timestamp", System.currentTimeMillis());
+
+// Get data
+String type = msg.getString("type");
+int seq = msg.getInteger("sequence", 0); // With default
+```
+
+### Message Metadata
+
+```java
+// In receiver
+int sender = message.getSenderNum();
+int receiver = message.getReceiverNum();
+VSLamportTime msgLamport = message.getLamportTime();
+VSVectorTime msgVector = message.getVectorTime();
+```
+
+### Complex Data in Messages
+
+```java
+// For complex data, convert to string
+JSONObject data = new JSONObject();
+data.put("items", new JSONArray(items));
+msg.setString("data", data.toString());
+
+// Or implement custom serialization
+msg.setInteger("arraySize", array.length);
+for (int i = 0; i < array.length; i++) {
+ msg.setInteger("array_" + i, array[i]);
+}
+```
+
+## Testing Your Components
+
+### Unit Testing a Protocol
+
+```java
+@Test
+public void testProtocolServerInit() {
+ // Setup
+ VSPrefs prefs = new VSPrefs();
+ VSInternalProcess process = mock(VSInternalProcess.class);
+ when(process.getNum()).thenReturn(0);
+
+ // Create protocol
+ VSMyProtocol protocol = new VSMyProtocol();
+ protocol.setProcess(process);
+ protocol.setPrefs(prefs);
+ protocol.isServer(true);
+
+ // Test initialization
+ protocol.onInit();
+
+ // Verify state
+ assertTrue(prefs.getBoolean("myprotocol.server.enabled"));
+}
+
+@Test
+public void testMessageHandling() {
+ // Setup protocol and process
+ VSMyProtocol protocol = new VSMyProtocol();
+ protocol.setProcess(mockProcess);
+ protocol.isClient(true);
+ protocol.onInit();
+
+ // Create test message
+ VSMessage msg = new VSMessage();
+ msg.setString("type", "REQUEST");
+ msg.setInteger("value", 10);
+
+ // Test message handling
+ protocol.onClientRecv(msg);
+
+ // Verify response was sent
+ verify(mockProcess).sendMessage(any(VSMessage.class));
+}
+```
+
+### Integration Testing
+
+```java
+@Test
+public void testProtocolIntegration() {
+ // Create simulator components
+ VSSimulatorVisualization viz = new VSSimulatorVisualization();
+ VSTaskManager taskManager = new VSTaskManager(viz);
+
+ // Create processes
+ VSInternalProcess server = createProcess(0, viz);
+ VSInternalProcess client1 = createProcess(1, viz);
+ VSInternalProcess client2 = createProcess(2, viz);
+
+ // Setup protocol on all processes
+ setupProtocol(server, true, false); // server
+ setupProtocol(client1, false, true); // client
+ setupProtocol(client2, false, true); // client
+
+ // Run simulation steps
+ for (int i = 0; i < 10; i++) {
+ taskManager.runTasks(i * 100);
+ }
+
+ // Verify expected behavior
+ // Check logs, state changes, etc.
+}
+```
+
+## Best Practices
+
+### 1. State Management
+
+- Keep server and client state separate
+- Use preferences (VSPrefs) for configurable values
+- Reset state properly in onReset methods
+
+### 2. Error Handling
+
+```java
+@Override
+public void onServerRecv(VSMessage message) {
+ try {
+ String type = message.getString("type");
+ if (type == null) {
+ process.log("Warning: Received message without type");
+ return;
+ }
+ // Process message
+ } catch (Exception e) {
+ VSErrorHandler.handle(e, "Error processing message");
+ }
+}
+```
+
+### 3. Logging
+
+```java
+// Use process.log for important events
+process.log("Protocol started");
+
+// Add context to logs
+process.log(String.format("Received %s from process %d",
+ msgType, message.getSenderNum()));
+
+// Debug logging
+if (getBoolean("debug.verbose")) {
+ process.log("Debug: " + detailedInfo);
+}
+```
+
+### 4. Performance Considerations
+
+- Avoid scheduling too many events
+- Use appropriate time types (LOCAL vs GLOBAL)
+- Clean up completed tasks and state
+- Be mindful of message size
+
+### 5. Protocol Design
+
+- Document message types and formats
+- Handle missing or malformed messages gracefully
+- Consider network failures and timeouts
+- Test with various numbers of processes
+
+### 6. Code Organization
+
+```
+protocols/implementations/
+├── VSMyProtocol.java # Main protocol implementation
+├── messages/ # Message type constants
+│ └── MyProtocolMessages.java
+└── state/ # Complex state management
+ └── MyProtocolState.java
+```
+
+## Common Patterns
+
+### Request-Response Pattern
+
+```java
+// Server sends request with ID
+msg.setInteger("requestId", nextRequestId++);
+pendingRequests.put(requestId, new RequestInfo());
+
+// Client echoes ID in response
+response.setInteger("requestId", message.getInteger("requestId"));
+
+// Server matches response to request
+int requestId = message.getInteger("requestId");
+RequestInfo info = pendingRequests.remove(requestId);
+```
+
+### Timeout Handling
+
+```java
+// Schedule timeout when sending request
+long timeout = process.getTime() + 5000;
+scheduleAt(timeout);
+markTimeout(timeout, requestId);
+
+// In onSchedule, check for timeouts
+if (isTimeout(process.getTime())) {
+ handleTimeout();
+}
+```
+
+### State Machine Implementation
+
+```java
+enum ProtocolState {
+ INIT, WAITING, PROCESSING, DONE
+}
+
+private ProtocolState state = ProtocolState.INIT;
+
+@Override
+public void onServerRecv(VSMessage message) {
+ switch (state) {
+ case INIT:
+ handleInit(message);
+ break;
+ case WAITING:
+ handleWaiting(message);
+ break;
+ // etc.
+ }
+}
+``` \ No newline at end of file