Grove.DottedVersionVector (Grove v0.1.1)

View Source

A Dotted Version Vector (DVV) for precise causality tracking.

DVVs combine a "dot" (a single event identifier) with a version vector (causal context). This provides more precise causality tracking than plain vector clocks, especially for OR-Set semantics.

Structure

  • dot: {actor, counter} - identifies a single event
  • context: %{actor => counter} - what events have been observed

Key Operations

  • event/2 - Record a new event, creating a dot
  • sync/2 - Merge contexts when receiving remote state
  • descends?/2 - Check if one DVV causally follows another
  • dominates?/2 - Check strict causal dominance

Example

iex> dvv = Grove.DottedVersionVector.new()
iex> {dvv, dot} = Grove.DottedVersionVector.event(dvv, :node_a)
iex> dot
{:node_a, 1}

References

Based on Riak's implementation and the Shapiro et al. papers on CRDTs.

Summary

Functions

Adds a dot to the context without making it the current dot.

Compares two DVVs for causal ordering.

Checks if a dot is included in the DVV's context.

Returns the context as a map.

Checks if dvv1 descends from (causally follows or equals) dvv2.

Checks if dvv1 strictly dominates dvv2.

Returns the current dot, if any.

Records a new event for the given actor.

Merges two DVVs, taking the maximum context and keeping the more recent dot.

Creates a new empty DVV.

Syncs two DVVs by merging their contexts.

Types

actor()

@type actor() :: term()

context()

@type context() :: %{required(actor()) => counter()}

counter()

@type counter() :: non_neg_integer()

dot()

@type dot() :: {actor(), counter()}

t()

@type t() :: %Grove.DottedVersionVector{context: context(), dot: dot() | nil}

Functions

add_to_context(dvv, arg)

@spec add_to_context(t(), dot()) :: t()

Adds a dot to the context without making it the current dot.

Used when observing a remote event.

compare(dvv1, dvv2)

@spec compare(t(), t()) :: :before | :after | :equal | :concurrent

Compares two DVVs for causal ordering.

Returns:

  • :before if dvv1 happened before dvv2
  • :after if dvv1 happened after dvv2
  • :equal if they are identical
  • :concurrent if they are causally independent

contains?(dotted_version_vector, arg)

@spec contains?(t(), dot()) :: boolean()

Checks if a dot is included in the DVV's context.

context(dotted_version_vector)

@spec context(t()) :: context()

Returns the context as a map.

descends?(dotted_version_vector1, dotted_version_vector2)

@spec descends?(t(), t()) :: boolean()

Checks if dvv1 descends from (causally follows or equals) dvv2.

Returns true if dvv1's context includes all events in dvv2's context.

dominates?(dvv1, dvv2)

@spec dominates?(t(), t()) :: boolean()

Checks if dvv1 strictly dominates dvv2.

Returns true if dvv1 descends from dvv2 AND dvv1 has additional events.

dot(dotted_version_vector)

@spec dot(t()) :: dot() | nil

Returns the current dot, if any.

event(dvv, actor)

@spec event(t(), actor()) :: {t(), dot()}

Records a new event for the given actor.

Returns the updated DVV and the new dot. The dot is added to the context, and becomes the current dot.

merge(dotted_version_vector1, dotted_version_vector2)

@spec merge(t(), t()) :: t()

Merges two DVVs, taking the maximum context and keeping the more recent dot.

new()

@spec new() :: t()

Creates a new empty DVV.

sync(dvv1, dotted_version_vector)

@spec sync(t(), t()) :: t()

Syncs two DVVs by merging their contexts.

Takes the pointwise maximum of all counters. The dot from the first DVV is preserved.