Hybrid Logical Clocks

Deep dive into HLC for conflict resolution

Hybrid Logical Clocks

Talon uses Hybrid Logical Clocks (HLC) for conflict resolution. This page explains how they work.

What is HLC?

HLC combines physical time with a logical counter:

Format: {timestamp}:{count}:{node}

Example: 000001704067200000:00001:device-abc
         └─────────────────┘ └───┘ └────────┘
          Physical time      Count  Node ID

Why HLC?

ProblemSolution
Clocks out of syncUses max(local, remote) time
Same millisecondCounter distinguishes
Identical timestampsNode ID breaks ties

Components

Timestamp

Wall clock time in milliseconds since epoch.

DateTime.now().millisecondsSinceEpoch  // 1704067200000

Count

Logical counter for same-millisecond ordering.

10:00:00.000 - Event 1 → count: 0
10:00:00.000 - Event 2 → count: 1
10:00:00.000 - Event 3 → count: 2
10:00:00.001 - Event 4 → count: 0  // New millisecond, reset

Node

Device/client identifier for tie-breaking.

clientId: 'device-abc'  // Alphabetically compared

Comparison

HLCs compare in order: timestamp → count → node

// HLC A: 1704067200000:5:device-a
// HLC B: 1704067200000:3:device-b

// 1. Timestamps equal
// 2. Count A (5) > Count B (3)
// Result: A wins

Using HLC Directly

Most users don't need to interact with HLC directly, but you can:

// Parse an HLC from a string
final hlc = HLC.tryParse(message.localTimestamp);
if (hlc != null) {
  print('Timestamp: ${hlc.timestamp}');
  print('Count: ${hlc.count}');
  print('Node: ${hlc.node}');
}

// Compare two HLC strings
final result = HLC.compareTimestamps(ts1, ts2);
if (result > 0) {
  print('ts1 is newer');
} else if (result < 0) {
  print('ts2 is newer');
} else {
  print('Equal');
}

// Create an HLC
final hlc = HLC.now('my-client-id');

Clock Drift

HLC handles clock drift automatically:

  1. When receiving a future timestamp, local clock advances
  2. When sending, uses max(wall clock, current HLC)
  3. Counter prevents duplicates
// Local clock: 10:00
// Receive message with HLC at 10:05

// Local HLC advances to 10:05 (with incremented counter)
// Future local events will be > 10:05

Best Practices

  1. Use unique client IDs - Prevents HLC collisions
  2. Don't manipulate HLC - Let Talon manage it
  3. Trust the algorithm - HLC handles edge cases