anchor.diff:  -module(riak_search_op_range).
   -export([
            preplan_op/2,
  -         chain_op/4
  +         chain_op/4,
  +         get_range_preflist/3
           ]).
   
   -include("riak_search.hrl").
  
positive.code:     %% Return.
      {ok, 1}.
  
  get_range_preflist(NVal, VNodes, UpNodes) ->
      %% Create an ordered set for fast repeated checking.
      UpNodesSet = ordsets:from_list(UpNodes),
  
negative.code:     random:seed(now()),
      RotationFactor = random:uniform(NVal),
      {Pre, Post} = lists:split(RotationFactor, VNodes),
      VNodes1 = Post ++ Pre,
      Iterations = ceiling(length(VNodes1), NVal),
  
      %% Create the preflist structure and then choose the preflist based on up nodes.
      Structure = create_preflist_structure(Iterations, NVal, VNodes1 ++ VNodes1),
      lists:usort(choose_preflist(Structure, UpNodesSet)).
      
  create_preflist_structure(0, _NVal, _VNodes) -> 
      [];
  create_preflist_structure(Iterations, NVal, VNodes) -> 
      {Backup, VNodes1} = lists:split(NVal, VNodes),
      {Primary, _} = lists:split(NVal, VNodes1),
      Group = [{hd(Primary), []}] ++ create_preflist_structure_1(tl(Primary), tl(Backup)),
      [Group|create_preflist_structure(Iterations - 1, NVal, VNodes1)].
  create_preflist_structure_1([], []) -> 
      [];
  create_preflist_structure_1([H|T], Backups) ->
      [{H, Backups}|create_preflist_structure_1(T, tl(Backups))].
      
  %% Given a preflist structure, return the preflist.
  choose_preflist([Group|Rest], UpNodesSet) ->
      choose_preflist_1(Group, UpNodesSet) ++ choose_preflist(Rest, UpNodesSet);
  choose_preflist([], _) -> 
      [].
  choose_preflist_1([{Primary, Backups}|Rest], UpNodesSet) ->
      {_, PrimaryNode} = Primary,
      AvailableBackups = filter_upnodes(Backups, UpNodesSet),
      case ordsets:is_element(PrimaryNode, UpNodesSet) of 
          true when AvailableBackups == [] ->
              [Primary];
          true when AvailableBackups /= [] ->
              [Primary, riak_search_utils:choose(AvailableBackups)];
          false ->
              choose_preflist_1(Rest, UpNodesSet)
      end;
  choose_preflist_1([], _) -> 
      [].
  
  %% Given a list of VNodes, filter out any that are offline.
  filter_upnodes([{Index,Node}|VNodes], UpNodesSet) ->
      case ordsets:is_element(Node, UpNodesSet) of
          true -> 
              [{Index, Node}|filter_upnodes(VNodes, UpNodesSet)];
          false ->
              filter_upnodes(VNodes, UpNodesSet)
      end;
  filter_upnodes([], _) ->
      [].
  
  ceiling(Numerator, Denominator) ->
      case Numerator rem Denominator of
          0 -> Numerator div Denominator;
          _ -> (Numerator div Denominator) + 1
      end.
  
  gather_results(OutputPid, OutputRef, {Term, Op, Iterator}, Acc)
  