diff options
Diffstat (limited to 'docs/developer-guide.md')
| -rw-r--r-- | docs/developer-guide.md | 537 |
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 |
