1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
//! Riak CRDT data types.
//!
//! This module ships the four primitive Riak CRDTs in their
//! state-based form:
//!
//! * [`PnCounter`] -- positive/negative counter. Per-actor pos and
//! neg counts; merge is element-wise max; value is sum(pos) -
//! sum(neg).
//! * [`OrSet`] -- observed-remove set. Per-element add and remove
//! tag sets; an element is present iff at least one add tag is
//! not shadowed by a remove tag; merge is set-union of tag sets.
//! * [`LwwRegister`] -- last-write-wins register. State is
//! (value, timestamp, actor); merge picks the higher timestamp
//! with ties broken by actor id.
//! * [`EwFlag`] -- enable-wins boolean. Same shape as [`OrSet`]
//! restricted to a singleton domain. Concurrent enable + disable
//! resolves to enabled.
//!
//! Per-key causality is tracked by [`Itc`] (Interval Tree
//! Clocks; see the [`itc`] module for the algorithm and the
//! citations). ITC supersedes the earlier dotted-version-vector
//! work; the algorithm scales with the live actor population
//! rather than every actor that has ever existed, which is the
//! property dyniak's dynamic-membership cluster model needs.
//!
//! # Actor-id mapping
//!
//! Riak's CRDTs key per-replica metadata by an Erlang `vnode_id`
//! tuple. This crate models actors as a value-typed
//! [`ActorId`] carrying the (datacenter name, peer name) pair the
//! Dynomite substrate already exposes through its
//! topology snapshots. The pair is stable across
//! gossip rounds and totally ordered, which is exactly what an
//! OR-Set tag generator and an LWW-register tiebreaker need.
//!
//! # CRDT laws
//!
//! Every type in this module satisfies the standard CRDT laws:
//!
//! * Associativity: `merge(merge(a, b), c) == merge(a, merge(b, c))`.
//! * Commutativity: `merge(a, b) == merge(b, a)`.
//! * Idempotence: `merge(a, a) == a`.
//!
//! Property tests under
//! `crates/dyniak/tests/datatypes_properties.rs` exercise all
//! three on randomly generated states.
// Map and HyperLogLog land in the second CRDT slice; appended
// below the original four-type block so parallel branches do
// not conflict.
// Pre-hash key shaping (per-bucket-property `chash_keyfun`)
// added by the bucket-property knobs slice. Re-exported below
// the prior block so parallel branches do not conflict.
// WebAssembly-backed custom keyfun routing
// ([`crate::datatypes::keyfun::KeyFun::Custom`]). Gated on the
// `wasm` feature since it pulls in the wasmtime runtime via the
// shared MapReduce module store.
use Ordering;
pub use cratePnCounter;
pub use crateEwFlag;
pub use crate;
pub use crateLwwRegister;
pub use crateOrSet;
pub use crateHyperLogLog;
pub use crate;
pub use crate;
pub use crate;
/// Identifier for a replica that produces CRDT operations.
///
/// Riak uses an Erlang `vnode_id` tuple. This crate uses the
/// (datacenter name, peer name) pair the Dynomite substrate
/// publishes through gossip. Both names are arbitrary ASCII byte
/// strings; ordering is lexicographic on the pair so OR-Set tag
/// comparisons and LWW tiebreakers are deterministic.
///
/// # Examples
///
/// ```
/// use dyniak::datatypes::ActorId;
/// let a = ActorId::new("dc1", "peer-a");
/// let b = ActorId::new("dc1", "peer-b");
/// assert!(a < b);
/// ```
/// Helper: compare two `(timestamp, actor)` pairs as Riak's LWW
/// rule does: the higher timestamp wins; on tie, the higher actor
/// id wins.
/// State-based CRDT contract.
///
/// Every CRDT in this module merges by an idempotent, commutative,
/// associative join. The `value` projection extracts the user-
/// visible state for the Riak `DtValue` response.