Skip to content

Commit b8f423e

Browse files
committed
Crdt
1 parent 58f44e7 commit b8f423e

3 files changed

Lines changed: 353 additions & 0 deletions

File tree

eggwalker/Readme.md

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# FugueMax CRDT Algorithm Explanation
2+
3+
Yes, I'd be happy to explain the FugueMax CRDT algorithm step-by-step!
4+
5+
FugueMax is a Conflict-free Replicated Data Type (CRDT) algorithm designed for distributed systems to handle conflicts when multiple users make changes concurrently. It's specifically focused on maintaining the maximum value across replicas while handling network partitions and message delays.
6+
7+
## Core Concepts
8+
9+
1. **CRDT (Conflict-free Replicated Data Type)**: Data structures that can be replicated across multiple computers in a network, updated independently, and eventually reconciled automatically.
10+
11+
2. **FugueMax Approach**: Uses a pair of `(value, unique_id)` where:
12+
- `value` is the numerical value to track
13+
- `unique_id` is a site-generated unique identifier (often a UUID)
14+
15+
3. **Max Merge Rule**: When comparing two pairs, choose the one with the higher value, or if values are equal, the one with the lexicographically greater unique_id.
16+
17+
## Step-by-Step Algorithm Explanation
18+
19+
### 1. Initialization
20+
- Each site initializes with a starting value (often 0) and generates a unique ID
21+
- State = (0, site_unique_id)
22+
23+
### 2. Local Update
24+
- When a site wants to update to a new value:
25+
- Create new pair (new_value, site_unique_id)
26+
- Compare with current state using max merge rule
27+
- Update local state if new pair is greater
28+
29+
### 3. Merge Operation
30+
- When receiving updates from other sites:
31+
- Compare incoming state with local state using max merge rule
32+
- Keep the state with higher value (or higher unique_id if values are equal)
33+
34+
### 4. Convergence
35+
- As sites exchange states, they all eventually converge to the same maximum value across the entire system
36+
37+
Let me provide a diagram to illustrate this:
38+
39+
```mermaid
40+
sequenceDiagram
41+
participant Site1 as Site 1 (UUID: A123)
42+
participant Site2 as Site 2 (UUID: B456)
43+
participant Site3 as Site 3 (UUID: C789)
44+
45+
Note over Site1,Site3: Initialization
46+
Site1->>Site1: State = (0, A123)
47+
Site2->>Site2: State = (0, B456)
48+
Site3->>Site3: State = (0, C789)
49+
50+
Note over Site1: Local Update
51+
Site1->>Site1: Update to (5, A123)
52+
53+
Note over Site2: Local Update
54+
Site2->>Site2: Update to (8, B456)
55+
56+
Note over Site1,Site2: Synchronization
57+
Site1->>Site2: Send (5, A123)
58+
Site2->>Site1: Send (8, B456)
59+
60+
Note over Site1: Merge
61+
Site1->>Site1: Compare (5, A123) with (8, B456)
62+
Site1->>Site1: Keep (8, B456) as 8 > 5
63+
64+
Note over Site2: Merge
65+
Site2->>Site2: Compare (8, B456) with (5, A123)
66+
Site2->>Site2: Keep (8, B456) as 8 > 5
67+
68+
Note over Site3: Local Update
69+
Site3->>Site3: Update to (8, C789)
70+
71+
Note over Site2,Site3: Synchronization
72+
Site2->>Site3: Send (8, B456)
73+
Site3->>Site2: Send (8, C789)
74+
75+
Note over Site2: Merge
76+
Site2->>Site2: Compare (8, B456) with (8, C789)
77+
Site2->>Site2: Keep (8, C789) as C789 > B456
78+
79+
Note over Site3: Merge
80+
Site3->>Site3: Compare (8, C789) with (8, B456)
81+
Site3->>Site3: Keep (8, C789) as C789 > B456
82+
83+
Note over Site1,Site3: Synchronization
84+
Site1->>Site3: Send (8, B456)
85+
Site3->>Site1: Send (8, C789)
86+
87+
Note over Site1: Merge
88+
Site1->>Site1: Compare (8, B456) with (8, C789)
89+
Site1->>Site1: Keep (8, C789) as C789 > B456
90+
91+
Note over Site1,Site3: System Convergence
92+
Note over Site1: Final State: (8, C789)
93+
Note over Site2: Final State: (8, C789)
94+
Note over Site3: Final State: (8, C789)
95+
96+
```
97+
98+
## Key Advantages of FugueMax
99+
100+
1. **Strong Eventual Consistency**: All replicas converge to the same state after receiving the same set of updates, regardless of order.
101+
102+
2. **Conflict Resolution**: The algorithm automatically resolves conflicts without requiring manual intervention.
103+
104+
3. **Decentralized**: No central authority is needed, making it ideal for distributed systems.
105+
106+
4. **Fault Tolerance**: Continues to function even when some nodes are unreachable.
107+
108+
## Common Applications
109+
110+
- Distributed counters and gauges
111+
- Distributed maximum-tracking systems
112+
- Leader election in distributed systems
113+
- Resource allocation in distributed environments
114+
115+
Would you like me to explain any particular aspect of the FugueMax algorithm in more detail?
116+
117+
```mermaid
118+
sequenceDiagram
119+
participant Site1 as Site 1 (UUID: A123)
120+
participant Site2 as Site 2 (UUID: B456)
121+
participant Site3 as Site 3 (UUID: C789)
122+
123+
Note over Site1,Site3: Initialization
124+
Site1->>Site1: State = (0, A123)
125+
Site2->>Site2: State = (0, B456)
126+
Site3->>Site3: State = (0, C789)
127+
128+
Note over Site1: Local Update
129+
Site1->>Site1: Update to (5, A123)
130+
131+
Note over Site2: Local Update
132+
Site2->>Site2: Update to (8, B456)
133+
134+
Note over Site1,Site2: Synchronization
135+
Site1->>Site2: Send (5, A123)
136+
Site2->>Site1: Send (8, B456)
137+
138+
Note over Site1: Merge
139+
Site1->>Site1: Compare (5, A123) with (8, B456)
140+
Site1->>Site1: Keep (8, B456) as 8 > 5
141+
142+
Note over Site2: Merge
143+
Site2->>Site2: Compare (8, B456) with (5, A123)
144+
Site2->>Site2: Keep (8, B456) as 8 > 5
145+
146+
Note over Site3: Local Update
147+
Site3->>Site3: Update to (8, C789)
148+
149+
Note over Site2,Site3: Synchronization
150+
Site2->>Site3: Send (8, B456)
151+
Site3->>Site2: Send (8, C789)
152+
153+
Note over Site2: Merge
154+
Site2->>Site2: Compare (8, B456) with (8, C789)
155+
Site2->>Site2: Keep (8, C789) as C789 > B456
156+
157+
Note over Site3: Merge
158+
Site3->>Site3: Compare (8, C789) with (8, B456)
159+
Site3->>Site3: Keep (8, C789) as C789 > B456
160+
161+
Note over Site1,Site3: Synchronization
162+
Site1->>Site3: Send (8, B456)
163+
Site3->>Site1: Send (8, C789)
164+
165+
Note over Site1: Merge
166+
Site1->>Site1: Compare (8, B456) with (8, C789)
167+
Site1->>Site1: Keep (8, C789) as C789 > B456
168+
169+
Note over Site1,Site3: System Convergence
170+
Note over Site1: Final State: (8, C789)
171+
Note over Site2: Final State: (8, C789)
172+
Note over Site3: Final State: (8, C789)
173+
```

eggwalker/fuguemax.ts

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/**
2+
* FugueMax CRDT Implementation
3+
*
4+
* A Conflict-free Replicated Data Type (CRDT) implementation
5+
* for maintaining maximum values across distributed systems.
6+
*/
7+
8+
/**
9+
* FugueMax type representing a value with its unique identifier
10+
*/
11+
export type FugueMaxValue<T> = {
12+
value: T;
13+
id: string;
14+
};
15+
16+
/**
17+
* FugueMax class implementation
18+
* Generic type T must be comparable (typically number or string)
19+
*/
20+
export class FugueMax<T> {
21+
private state: FugueMaxValue<T>;
22+
23+
/**
24+
* Create a new FugueMax instance
25+
* @param initialValue - The initial value
26+
* @param id - A unique identifier for this site (defaults to random UUID)
27+
*/
28+
constructor(initialValue: T, id?: string) {
29+
this.state = {
30+
value: initialValue,
31+
id: id || this.generateUUID()
32+
};
33+
}
34+
35+
/**
36+
* Generate a random UUID v4
37+
* @returns A random UUID string
38+
*/
39+
private generateUUID(): string {
40+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
41+
const r = (Math.random() * 16) | 0;
42+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
43+
return v.toString(16);
44+
});
45+
}
46+
47+
/**
48+
* Get the current value
49+
* @returns The current value (without the unique ID)
50+
*/
51+
getValue(): T {
52+
return this.state.value;
53+
}
54+
55+
/**
56+
* Get the complete FugueMax state (value and ID)
57+
* @returns The complete state
58+
*/
59+
getState(): FugueMaxValue<T> {
60+
return { ...this.state };
61+
}
62+
63+
/**
64+
* Update the value locally
65+
* @param newValue - The new value to set
66+
* @returns true if the value was updated, false otherwise
67+
*/
68+
update(newValue: T): boolean {
69+
const newState = {
70+
value: newValue,
71+
id: this.state.id
72+
};
73+
74+
// Use the merge function to ensure we keep the maximum
75+
const didChange = this.merge(newState);
76+
return didChange;
77+
}
78+
79+
/**
80+
* Merge with another FugueMax state
81+
* This is the key CRDT operation that ensures convergence
82+
*
83+
* @param otherState - The state to merge with
84+
* @returns true if our state changed as a result, false otherwise
85+
*/
86+
merge(otherState: FugueMaxValue<T>): boolean {
87+
// Compare values
88+
if (this.isGreaterThan(otherState, this.state)) {
89+
this.state = { ...otherState };
90+
return true;
91+
}
92+
return false;
93+
}
94+
95+
/**
96+
* Determine if one FugueMax state is greater than another
97+
*
98+
* @param a - First state to compare
99+
* @param b - Second state to compare
100+
* @returns true if a > b according to FugueMax rules
101+
*/
102+
private isGreaterThan(a: FugueMaxValue<T>, b: FugueMaxValue<T>): boolean {
103+
// First compare by value
104+
if (a.value > b.value) {
105+
return true;
106+
}
107+
108+
// If values are equal, compare by ID
109+
if (a.value === b.value && a.id > b.id) {
110+
return true;
111+
}
112+
113+
return false;
114+
}
115+
}
116+
117+
/**
118+
* FugueMaxNumber is a convenient type alias for the common case of using numbers
119+
*/
120+
export type FugueMaxNumber = FugueMax<number>;
121+
122+
/**
123+
* Helper function to create a FugueMax instance for numbers
124+
* @param initialValue - Initial number value (defaults to 0)
125+
* @param id - Optional unique identifier
126+
* @returns A new FugueMaxNumber instance
127+
*/
128+
export function createFugueMaxNumber(initialValue: number = 0, id?: string): FugueMaxNumber {
129+
return new FugueMax<number>(initialValue, id);
130+
}

eggwalker/fuguemax_test.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { FugueMax, createFugueMaxNumber } from './fuguemax';
2+
3+
// Example usage in a distributed system simulation
4+
5+
// Create three replicas with different IDs
6+
const site1 = createFugueMaxNumber(0, "site1");
7+
const site2 = createFugueMaxNumber(0, "site2");
8+
const site3 = createFugueMaxNumber(0, "site3");
9+
10+
console.log("Initial states:");
11+
console.log("Site 1:", site1.getState());
12+
console.log("Site 2:", site2.getState());
13+
console.log("Site 3:", site3.getState());
14+
15+
// Site 1 updates to 5
16+
console.log("\nSite 1 updates to 5");
17+
site1.update(5);
18+
console.log("Site 1:", site1.getState());
19+
20+
// Site 2 updates to 8
21+
console.log("\nSite 2 updates to 8");
22+
site2.update(8);
23+
console.log("Site 2:", site2.getState());
24+
25+
// Simulate network sync: Site 1 and Site 2 exchange states
26+
console.log("\nSite 1 and Site 2 sync");
27+
site1.merge(site2.getState());
28+
site2.merge(site1.getState());
29+
console.log("Site 1:", site1.getState());
30+
console.log("Site 2:", site2.getState());
31+
32+
// Site 3 updates to 8 independently
33+
console.log("\nSite 3 updates to 8");
34+
site3.update(8);
35+
console.log("Site 3:", site3.getState());
36+
37+
// Site 2 and 3 sync - both have value 8, but different IDs
38+
console.log("\nSite 2 and Site 3 sync (conflict resolution via ID)");
39+
site2.merge(site3.getState());
40+
site3.merge(site2.getState());
41+
console.log("Site 2:", site2.getState());
42+
console.log("Site 3:", site3.getState());
43+
44+
// Finally, all three sites sync
45+
console.log("\nAll sites sync");
46+
site1.merge(site3.getState());
47+
console.log("Site 1:", site1.getState());
48+
console.log("Site 2:", site2.getState());
49+
console.log("Site 3:", site3.getState());
50+
console.log("\nFinal convergence achieved: All sites have the same state");

0 commit comments

Comments
 (0)