Version: 0.3.0
Authors: Nyiro, Gergo (gergo.nyiro@gmail.com).
References
Interval tree clock (itc) is a good candidate for a logical clock in a distributed system where the members join and leave the cluster very often.
Itc offers the following actions:1> Tic0 = itc:seed(). {1,0}Create clock for a new cluster member:
2> [Tic1, Toc1] = itc:fork(Tic0). [{{1,0},0},{{0,1},0}]The forked clock cannot be compared to the original clock:
3> itc:leq(TicA0, TicA1). true 4> itc:leq(TicA1, TicA0). trueOnly the tic of the next event can be compared to the original clock:
5> Tic2 = itc:event(Tic1). {{1,0},{0,1,0}} 6> Toc2 = itc:event(Toc1). {{0,1},{0,0,1}}So the clocks can be ordered:
7> itc:leq(Tic0, Tic2). true 8> itc:leq(Tic2, Tic0). falseIf the cluster nodes are synchronized then the clocks can be joined
9> TicC3 = itc:join(TicA2, TicB2). {1,1} 10> itc:leq(TicA2, TicC3). trueand the new clock can be used in the syncronized nodes.
events
module
is an example for such a usage.
The event store can be initialized with the events:init/0
function:
1> EventsA0 = events:init(). [{{1,0},init}]New action can be added to the store with
events:append/2
function. (The action
can be any term in our example.)
2> EventsA1 = events:append(EventsA0, {action, 1}). [{{1,1},{action,1}},{{1,0},init}] 3> EventsA2 = events:append(EventsA0, {action, 2}). [{{1,2},{action,2}},{{1,1},{action,1}},{{1,0},init}]A new event store can be forked with the
events:fork/1
function:
4> [EventsA3, EventsB3] = events:fork(EventsA2). [[{{{1,0},2},fork}, {{1,2},{action,2}}, {{1,1},{action,1}}, {{1,0},init}], [{{{0,1},2},fork}, {{1,2},{action,2}}, {{1,1},{action,1}}, {{1,0},init}]]The event store may got separated events, but the last common time stamp can be found with the
events:get_last_seen_event_tic/2
. (Where the second
parameter is the last time stamp of the compared event store.)
5> EventsA4 = events:append(EventsA3, {action, 4}). [{{{1,0},{2,1,0}},{action,4}}, {{{1,0},2},fork}, {{1,2},{action,2}}, {{1,1},{action,1}}, {{1,0},init}] 6> EventsA5 = events:append(EventsA4, {action, 5}). [{{{1,0},{2,2,0}},{action,5}}, {{{1,0},{2,1,0}},{action,4}}, {{{1,0},2},fork}, {{1,2},{action,2}}, {{1,1},{action,1}}, {{1,0},init}] 7> EventsB4 = events:append(EventsB3, {action, 14}). [{{{0,1},{2,0,1}},{action,14}}, {{{0,1},2},fork}, {{1,2},{action,2}}, {{1,1},{action,1}}, {{1,0},init}] 8> LastTic = events:get_last_tic(EventsA5). {{1,0},{2,2,0 9> SyncFrom = events:get_last_seen_event_tic(EventsB3, LastTic). {{0,1},2}The unseen events can be selected with the
events:list_unseen_events/2
function,
where the second parameter is the last common time stamp from the
events:get_last_seen_event_tic
function. And the unseen events can be merged
into the event store with the events:merge/2
function.
10> UnseenEventsA = events:list_unseen_events(EventsA5, SyncFrom). [{{{1,0},{2,2,0}},{action,5}},{{{1,0},{2,1,0}},{action,4}}] 11> events:merge(EventsB3, UnseenEventsA). [{{1,4},merge}, {{{1,0},{2,2,0}},{action,5}}, {{{1,0},{2,1,0}},{action,4}}, {{{0,1},2},fork}, {{1,2},{action,2}}, {{1,1},{action,1}}, {{1,0},init}]As you can see the time stamp of the merge event is normalized, because the two branch of the itc is merged too.
event_server
module.
1> event_server:start_link(a). {ok, <0.N.0>} 2> event_server:add(a, 1). ok 3> event_server:add(a, 2). ok 4> event_server:list(a). [2,1] 5> event_server:start_link(b). {ok, <0.N.0>} 6> event_server:join(b, a). ok 7> event_server:list(b). [2,1] 8> event_server:add(b, 3). 9> event_server:list(a). [3,2,1] 10> event_server:start_link(c). {ok, <0.N.0>} 11> event_server:join(c, b). ok 12> event_server:add(c, 4). ok 13> event_server:add(a, 5). ok 14> event_server:list(a). [5,4,3,2,1] 15> event_server:list(b). [5,4,3,2,1] 16> event_server:list(c). [5,4,3,2,1]
Generated by EDoc