DeltaCrdt implements a key/value store using concepts from Delta CRDTs, and relies on MerkleMap
for efficient synchronization.
It implements also GCounter and PNCounter
There is a (slightly out of date) introductory blog post and the (very much up to date) official documentation on hexdocs.pm is also very good.
The following papers have been used to implement this library:
Delta State Replicated Data Types – Almeida et al. 2016
Efficient Synchronization of State-based CRDTs – Enes et al. 2018
Documentation can be found on hexdocs.pm.
Here's a short example to illustrate adding an entry to a map:
# start 2 Delta CRDTs
{:ok, crdt1} = DeltaCrdt.start_link(DeltaCrdt.Causal, DeltaCrdt.AWLWWMap)
{:ok, crdt2} = DeltaCrdt.start_link(DeltaCrdt.Causal, DeltaCrdt.AWLWWMap)
# make them aware of each other
DeltaCrdt.set_neighbours(crdt1, [crdt2])
# show the initial value
DeltaCrdt.read(crdt1)
%{}
# add a key/value in crdt1
DeltaCrdt.mutate(crdt1, :add, ["CRDT", "is magic!"])
# read it after it has been replicated to crdt2
DeltaCrdt.read(crdt2)
%{"CRDT" => "is magic!"}
#start 2 PNCounter
{:ok, crdt3} = DeltaCrdt.start_link(DeltaCrdt.NamedCrdt,DeltaCrdt.PNCounter)
{:ok, crdt4} = DeltaCrdt.start_link(DeltaCrdt.NamedCrdt,DeltaCrdt.PNCounter)
DeltaCrdt.set_neighbours(crdt3, [crdt4])
DeltaCrdt.read(crdt4)
0
DeltaCrdt.mutate(crdt3, :inc, [5])
DeltaCrdt.read(crdt4)
5
DeltaCrdt.mutate(crdt3, :dec, [3])
DeltaCrdt.read(crdt4)
2
#start 2 GCounter
{:ok, crdt5} = DeltaCrdt.start_link(DeltaCrdt.NamedCrdt,DeltaCrdt.GCounter)
{:ok, crdt6} = DeltaCrdt.start_link(DeltaCrdt.NamedCrdt,DeltaCrdt.GCounter)
DeltaCrdt.set_neighbours(crdt5, [crdt6])
DeltaCrdt.read(crdt6)
0
DeltaCrdt.mutate(crdt5, :inc, [5])
DeltaCrdt.read(crdt6)
5
DeltaCrdt publishes the metric [:delta_crdt, :sync, :done]
.
The package can be installed by adding delta_crdt
to your list of dependencies in mix.exs
:
def deps do
[
{:delta_crdt, "~> 0.5.0"}
]
end