Appearance
Consistency & Vector Clocks
When multiple nodes can read and write the same cache key, you need a way to track which value is the most recent. The framework uses vector clocks for this.
The Problem
Without coordination, concurrent writes on different nodes can produce conflicting values:
Node A writes config:theme = "dark"
Node B writes config:theme = "light" (at the same time)
Which one wins?Vector clocks solve this by tracking causality.
How Vector Clocks Work
Each node maintains a logical clock (map<node_id, counter>). When a node writes to the cache:
- It increments its own counter in the vector clock.
- The updated clock is stored alongside the value.
- When another node receives the value, it can determine if the update is newer, older, or concurrent.
cpp
// Access the vector clock
auto& clock = app.get_state()->get_clock();
// The clock is a map of node_id → uint64_t counterConflict Resolution Rules
When a node receives a cache update, it compares the incoming vector clock against the local clock for that key:
| Scenario | Resolution |
|---|---|
| One vector dominates (all counters >=) | Newer value wins |
| Vectors conflict (A > B in some, B > A in others) | Value with the later timestamp wins |
vector_clock::compare(a, b) — Manual comparison
cpp
using namespace framework::support;
int result = vector_clock::compare(clock_a, clock_b);
// result < 0: a is older than b
// result > 0: a is newer than b
// result = 0: concurrent (conflicting)
// result = 2: equalHelper methods on vector_clock:
| Method | Description |
|---|---|
increment(node_id) | Increment this node's counter. |
update(other) | Merge in another vector clock. |
is_concurrent(other) | Returns true if the clocks conflict. |
operator<=(other) | Returns true if this is dominated by other. |
get_data() | Returns the raw map<uuid, uint64_t>. |
What This Means for You
You do not need to manage vector clocks manually in most cases. The framework handles:
- Automatic clock propagation — When
state->cache_set()is called, the current clock is included. - Automatic conflict resolution — When receiving cache updates from other nodes, the framework compares clocks and applies the correct value.
- Anti-entropy sync — Background synchronization (see Anti-Entropy Sync) ensures all nodes converge.