anchor.diff:  -module(consistent_hashing).
   -author("Tomasz Lichon").
   
  --type chash() :: chash:chash() | node().
  +-record(ring, {
  +    type :: single_node | multi_node | broken,
  +    chash :: chash:chash() | node(),
  +    broken_nodes = [] :: [node()]
  +}).
  +
  +-type ring() :: #ring{}.
   
   %% API
   -export([init/1, cleanup/0, get_chash_ring/0, set_chash_ring/1,
  -    get_node/1, get_nodes/2, get_all_nodes/0]).
  -
  --define(SINGLE_NODE_CHASH(Node), Node).
  --define(IS_SINGLE_NODE_CHASH(CHash), is_atom(CHash)).
  +    set_broken_node/1, set_fixed_node/1,
  +    get_node/1, get_nodes/2, get_alive_and_broken_nodes/2, get_all_nodes/0]).
   
   %%%===================================================================
   %%% API
  
positive.code:     case get_chash_ring() of
          undefined ->
              error(chash_ring_not_initialized);
          Node when ?IS_SINGLE_NODE_CHASH(Node) ->
              Node;
          CHash ->
              Index = chash:key_of(Label),
              [{_, BestNode}] = chash:successors(Index, CHash, 1),
              BestNode
      end.
  
  %%--------------------------------------------------------------------
  
negative.code: %% Sets consistent hashing ring.
  %% @end
  %%--------------------------------------------------------------------
  -spec set_chash_ring(ring()) -> ok.
  set_chash_ring(CHash) ->
      ctool:set_env(chash, CHash).
  
  %%--------------------------------------------------------------------
  %% @doc
  %% Sets information about broken node.
  %% @end
  %%--------------------------------------------------------------------
  -spec set_broken_node(node()) -> ok.
  set_broken_node(BrokenNode) ->
      #ring{broken_nodes = BrokenNodes} = Ring = get_chash_ring(),
      Ring2 = Ring#ring{type = broken,
          broken_nodes = lists:usort([BrokenNode | BrokenNodes -- [BrokenNode]])},
      ctool:set_env(chash, Ring2).
  
  %%--------------------------------------------------------------------
  %% @doc
  %% Sets information about fixed node.
  %% @end
  %%--------------------------------------------------------------------
  -spec set_fixed_node(node()) -> ok.
  set_fixed_node(FixedNodes) ->
      #ring{broken_nodes = BrokenNodes} = Ring = get_chash_ring(),
      Ring2 = case BrokenNodes -- [FixedNodes] of
          [] -> Ring#ring{type = multi_node, broken_nodes = []};
          BrokenNodes2 -> Ring#ring{broken_nodes = BrokenNodes2}
      end,
      ctool:set_env(chash, Ring2).
  
  %%--------------------------------------------------------------------
  %% @doc
  %% Get node that is responsible for the data labeled with given term.
  %% Throws error if node is broken.
  %% @end
  %%--------------------------------------------------------------------
  -spec get_node(term()) -> node().
  