Hone logo
Hone
Problems

Implementing Logical Clocks in Go

In distributed systems, coordinating events across multiple nodes without a shared global clock is a fundamental challenge. Logical clocks, such as Lamport timestamps or Vector Clocks, provide a mechanism to establish a causal ordering of events. This challenge focuses on implementing a basic logical clock mechanism to understand this ordering.

Problem Description

Your task is to implement a simplified logical clock system in Go. This system will simulate events happening on different logical "processes" or nodes. Each process will maintain its own logical clock, which increments based on internal events and reacts to events received from other processes to ensure causal consistency.

You will need to:

  1. Define a LogicalClock struct: This struct will encapsulate the state of a single logical clock. It should have a field to store the current timestamp (an integer).
  2. Implement Increment method: This method should be called when an internal event occurs on a process. It will increment the clock's timestamp by 1.
  3. Implement Receive method: This method will be called when a process receives a message from another process. The Receive method will take the sender's logical clock timestamp as an argument. The receiving clock's timestamp should be updated to the maximum of its current timestamp and the received timestamp, plus 1. This ensures that the receiver's clock reflects not only its own internal events but also acknowledges the causal dependency on the received event.
  4. Simulate a sequence of events: Create a small simulation where multiple logical clocks interact, demonstrating the Increment and Receive operations.

Expected Behavior:

  • When Increment is called, the clock's timestamp increases by 1.
  • When Receive(timestamp) is called, the clock's timestamp becomes max(current_timestamp, timestamp) + 1.
  • The simulation should show how timestamps evolve and maintain a consistent causal order.

Edge Cases:

  • Receiving a message with a timestamp smaller than the current clock's timestamp. The clock should still be updated to max(current_timestamp, received_timestamp) + 1, which in this case will be current_timestamp + 1.
  • Receiving a message with a timestamp equal to the current clock's timestamp.
  • Receiving a message with a timestamp greater than the current clock's timestamp.

Examples

Example 1:

Initial state:
Clock A: 0
Clock B: 0

Event Sequence:
1. Clock A increments.
2. Clock B increments.
3. Clock A increments.
4. Clock B receives from A (current A timestamp is 2).
5. Clock A increments.
Output:
Initial state:
Clock A: 0
Clock B: 0

After step 1:
Clock A: 1
Clock B: 0

After step 2:
Clock A: 1
Clock B: 1

After step 3:
Clock A: 2
Clock B: 1

After step 4 (B receives from A, A's timestamp was 2):
Clock A: 2
Clock B: max(1, 2) + 1 = 3

After step 5:
Clock A: 3
Clock B: 3

Example 2:

Initial state:
Clock X: 0
Clock Y: 0

Event Sequence:
1. Clock X increments.
2. Clock Y increments.
3. Clock X receives from Y (current Y timestamp is 1).
4. Clock Y increments.
5. Clock X increments.
6. Clock Y receives from X (current X timestamp is 3).
Output:
Initial state:
Clock X: 0
Clock Y: 0

After step 1:
Clock X: 1
Clock Y: 0

After step 2:
Clock X: 1
Clock Y: 1

After step 3 (X receives from Y, Y's timestamp was 1):
Clock X: max(1, 1) + 1 = 2
Clock Y: 1

After step 4:
Clock X: 2
Clock Y: 2

After step 5:
Clock X: 3
Clock Y: 2

After step 6 (Y receives from X, X's timestamp was 3):
Clock X: 3
Clock Y: max(2, 3) + 1 = 4

Constraints

  • Timestamps will be non-negative integers.
  • The number of simulated events and clocks will be small (e.g., less than 10 clocks, less than 20 events per clock).
  • Your implementation should be efficient and handle the described logic correctly.

Notes

This implementation uses a simplified Lamport timestamp. Think about how the Receive operation ensures that a process's clock is always at least as advanced as any event it has acknowledged. Consider how you might structure your Go code to represent multiple interacting clocks. You'll need to define the LogicalClock struct and its methods.

Loading editor...
go