ExHashRing.Ring (ex_hash_ring v6.0.1) View Source

A pure Elixir consistent hash ring.

Ring data is stored in an ETS table owned by the ExHashRing.Ring GenServer. This module provides functions for managing and querying a consistent hash ring quickly and efficiently.

Link to this section Summary

Types

Rings maintain a history, the history is limited to depth number of generations to retain.

Generations act as a grouping mechanism to associate many records together as one logical and atomic group.

Any hashable key can be looked up in the ring to find the nodes that own that key.

Rings are named with a unique atom.

Union type that represents all valid options

Option that controls the number of generations to retain for lookup.

Option that controls the name to register this process under, Rings that are registered can use their name in place of their pid.

Option that controls the initial nodes for the Ring.

Option that controls the initial overrides for the Ring.

Option that controls the number of replicas to use for nodes that do not define replicas.

List of options that can be provided when starting a Ring, see the option/0 type and its associated types for more information.

Overrides allow the Ring to always resolve a given key to a set list of nodes.

Several functions accept either a name for a named Ring or a pid for an anonymous Ring

Ring size is a memoized count of the number of logical nodes in a ring

t()

Functions

Adds a node to the existing set of nodes in the ring.

Adds multiple nodes to the existing set of nodes in the ring.

Returns a specification to start this module under a supervisor.

Finds the specified number of nodes responsible for the given key in the specified ring's history, going back back number of generations.

Finds the node responsible for the given key in the specified ring.

Finds the specified number of nodes responsible for the given key in the specified ring's current generation.

Finds the specificed number of nodes responsible for the given key by looking at each generation in the ring's configured depth. See find_stable_nodes/4 for more information.

Finds the specified number of nodes responsible for the given key in the specified ring's current generation and in the history of the ring. This means that this function returns up to back * num; where num = number of nodes requested, and back = the number of generations to consider.

Forces a garbage collection of any generations that are pending garbage collection. Returns the generations that were collected.

Forces a garbage collection of a specific generation, the generation must be pending or else {:error, :not_pending} is returned.

Get the current ring generation

Retrieves the current set of node names from the ring.

Retrieves the current set of nodes as tuples of {name, replicas} from the ring.

Retrieves the current set of overrides from the ring.

Retrieves a list of pending gc generations.

Callback implementation for GenServer.init/1.

Removes a node from the ring by its name.

Atomically remove multiple nodes from the ring by name

Replaces the nodes in the ring with a new set of nodes.

Replaces the overrides in the ring with new overrides.

Start and link a Ring with the given name.

Stops the GenServer holding the Ring.

Link to this section Types

Specs

depth() :: pos_integer()

Rings maintain a history, the history is limited to depth number of generations to retain.

Specs

generation() :: integer()

Generations act as a grouping mechanism to associate many records together as one logical and atomic group.

Specs

Any hashable key can be looked up in the ring to find the nodes that own that key.

Specs

name() :: atom()

Rings are named with a unique atom.

Specs

Union type that represents all valid options

Specs

option_depth() :: {:depth, depth()}

Option that controls the number of generations to retain for lookup.

Defaults to 1

Specs

option_name() :: {:name, name()}

Option that controls the name to register this process under, Rings that are registered can use their name in place of their pid.

Defaults behavior is to not register the Ring process.

Specs

option_nodes() :: {:nodes, [ExHashRing.Node.definition()]}

Option that controls the initial nodes for the Ring.

Defaults to []

Specs

option_overrides() :: {:overrides, overrides()}

Option that controls the initial overrides for the Ring.

Defaults to %{}

Specs

option_replicas() :: {:replicas, ExHashRing.Node.replicas()}

Option that controls the number of replicas to use for nodes that do not define replicas.

Defaults to 512

Specs

options() :: [option()]

List of options that can be provided when starting a Ring, see the option/0 type and its associated types for more information.

Specs

overrides() :: %{optional(key()) => [ExHashRing.Node.name()]}

Overrides allow the Ring to always resolve a given key to a set list of nodes.

Specs

ring() :: name() | pid()

Several functions accept either a name for a named Ring or a pid for an anonymous Ring

Specs

size() :: non_neg_integer()

Ring size is a memoized count of the number of logical nodes in a ring

Specs

t() :: %ExHashRing.Ring{
  depth: depth(),
  generation: generation(),
  nodes: [ExHashRing.Node.t()],
  overrides: overrides(),
  pending_gcs: %{optional(generation()) => reference()},
  replicas: ExHashRing.Node.replicas(),
  sizes: [size()],
  table: :ets.tid()
}

Link to this section Functions

Link to this function

add_node(ring, node_name, num_replicas \\ nil)

View Source

Specs

add_node(ring(), ExHashRing.Node.name(), ExHashRing.Node.replicas() | nil) ::
  {:ok, [ExHashRing.Node.t()]} | {:error, :node_exists}

Adds a node to the existing set of nodes in the ring.

Specs

add_nodes(ring(), nodes :: [ExHashRing.Node.definition()]) ::
  {:ok, [ExHashRing.Node.t()]} | {:error, :node_exists}

Adds multiple nodes to the existing set of nodes in the ring.

Returns a specification to start this module under a supervisor.

See Supervisor.

Link to this function

do_find_stable_nodes(key, hash, num, back, info)

View Source

Specs

do_find_stable_nodes(
  key(),
  hash :: ExHashRing.Hash.t(),
  num :: non_neg_integer(),
  back :: non_neg_integer(),
  info :: ExHashRing.Info.entry()
) :: {:ok, [ExHashRing.Node.name()]} | {:error, atom()}
Link to this function

find_historical_node(ring, key, back)

View Source

Specs

find_historical_node(ring(), key(), back :: non_neg_integer()) ::
  {:ok, ExHashRing.Node.name()} | {:error, atom()}
Link to this function

find_historical_nodes(ring, key, num, back)

View Source

Specs

find_historical_nodes(
  ring(),
  key(),
  num :: non_neg_integer(),
  back :: non_neg_integer()
) :: {:ok, [ExHashRing.Node.name()]} | {:error, atom()}

Finds the specified number of nodes responsible for the given key in the specified ring's history, going back back number of generations.

Specs

find_node(ring(), key()) :: {:ok, ExHashRing.Node.name()} | {:error, atom()}

Finds the node responsible for the given key in the specified ring.

Link to this function

find_nodes(ring, key, num)

View Source

Specs

find_nodes(ring(), key(), num :: non_neg_integer()) ::
  {:ok, [ExHashRing.Node.name()]} | {:error, reason :: atom()}

Finds the specified number of nodes responsible for the given key in the specified ring's current generation.

Link to this function

find_stable_nodes(ring, key, num)

View Source

Specs

find_stable_nodes(ring(), key(), num :: non_neg_integer()) ::
  {:ok, [ExHashRing.Node.name()]} | {:error, atom()}

Finds the specificed number of nodes responsible for the given key by looking at each generation in the ring's configured depth. See find_stable_nodes/4 for more information.

Link to this function

find_stable_nodes(ring, key, num, back)

View Source

Specs

find_stable_nodes(
  ring(),
  key(),
  num :: non_neg_integer(),
  back :: pos_integer()
) :: {:ok, [ExHashRing.Node.name()]} | {:error, atom()}

Finds the specified number of nodes responsible for the given key in the specified ring's current generation and in the history of the ring. This means that this function returns up to back * num; where num = number of nodes requested, and back = the number of generations to consider.

Specs

force_gc(ring()) :: {:ok, [generation()]}

Forces a garbage collection of any generations that are pending garbage collection. Returns the generations that were collected.

Link to this function

force_gc(ring, generation)

View Source

Specs

force_gc(ring(), generation()) :: :ok | {:error, :not_pending}

Forces a garbage collection of a specific generation, the generation must be pending or else {:error, :not_pending} is returned.

Specs

get_generation(ring()) :: {:ok, generation()} | :error

Get the current ring generation

Specs

get_nodes(ring()) :: {:ok, [ExHashRing.Node.name()]}

Retrieves the current set of node names from the ring.

Link to this function

get_nodes_with_replicas(ring)

View Source

Specs

get_nodes_with_replicas(ring()) :: {:ok, [ExHashRing.Node.t()]}

Retrieves the current set of nodes as tuples of {name, replicas} from the ring.

Specs

get_overrides(ring()) :: {:ok, overrides()}

Retrieves the current set of overrides from the ring.

Specs

get_pending_gcs(ring()) :: {:ok, [generation()]}

Retrieves a list of pending gc generations.

Specs

init(options()) :: {:ok, t()}

Callback implementation for GenServer.init/1.

Specs

remove_node(ring(), name :: ExHashRing.Node.name()) ::
  {:ok, [ExHashRing.Node.t()]} | {:error, :node_not_exists}

Removes a node from the ring by its name.

Link to this function

remove_nodes(ring, names)

View Source

Specs

remove_nodes(ring(), names :: [ExHashRing.Node.name()]) ::
  {:ok, [ExHashRing.Node.t()]} | {:error, :node_not_exists}

Atomically remove multiple nodes from the ring by name

Specs

set_nodes(ring(), nodes :: [ExHashRing.Node.definition()]) ::
  {:ok, [ExHashRing.Node.t()]}

Replaces the nodes in the ring with a new set of nodes.

Link to this function

set_overrides(ring, overrides)

View Source

Specs

set_overrides(ring(), overrides()) :: {:ok, overrides()}

Replaces the overrides in the ring with new overrides.

Link to this function

start_link(options \\ [])

View Source

Specs

start_link(options()) :: GenServer.on_start()

Start and link a Ring with the given name.

Ring supports various options see options/0 for more information.

Specs

stop(ring()) :: :ok

Stops the GenServer holding the Ring.