/apps/ecnty/src/ecnty_vnode.erl

https://github.com/benmmurphy/ecnty · Erlang · 184 lines · 139 code · 43 blank · 2 comment · 0 complexity · bedfca29a98d774170149f810899b504 MD5 · raw file

  1. -module(ecnty_vnode).
  2. -behaviour(riak_core_vnode).
  3. -include("ecnty.hrl").
  4. -include_lib("riak_core/include/riak_core_vnode.hrl").
  5. -compile([{parse_transform, lager_transform}]).
  6. -export([test_vnode/1]).
  7. -export([start_vnode/1,
  8. init/1,
  9. terminate/2,
  10. handle_command/3,
  11. is_empty/1,
  12. delete/1,
  13. handle_handoff_command/3,
  14. handoff_starting/2,
  15. handoff_cancelled/1,
  16. handoff_finished/2,
  17. handle_handoff_data/2,
  18. encode_handoff_item/2,
  19. handle_exit/3,
  20. handle_coverage/4]).
  21. -export([increment/4, increment_sync/3, get/3, get_sync/2, merge/4]).
  22. -define(MASTER, ecnty_vnode_master).
  23. -define(sync(PrefList, Command, Master),
  24. riak_core_vnode_master:sync_command(PrefList, Command, Master)).
  25. -record(state, {storage_module, storage_state, my_id = "" :: string(), partition}).
  26. test_vnode(I) ->
  27. riak_core_vnode:start_link(?MODULE, I, infinity).
  28. %% API
  29. start_vnode(I) ->
  30. riak_core_vnode_master:get_vnode_pid(I, ?MODULE).
  31. get_sync(Preflist, Key) ->
  32. riak_core_vnode_master:sync_command(Preflist, {get, Key}, ?MASTER).
  33. increment_sync(Preflist, Key, Value) ->
  34. riak_core_vnode_master:sync_command(Preflist, {increment, Key, Value}, ?MASTER).
  35. get(Preflist, Key, Sender) ->
  36. riak_core_vnode_master:command(Preflist, {get, Key}, Sender, ?MASTER).
  37. merge(Preflist, Key, Counters, Sender) ->
  38. riak_core_vnode_master:command(Preflist, {merge, Key, Counters}, Sender, ?MASTER).
  39. increment(Preflist, Key, Val, Sender) ->
  40. riak_core_vnode_master:command(Preflist, {increment, Key, Val}, Sender, ?MASTER).
  41. init([Partition]) ->
  42. Module = app_helper:get_env(ecnty, storage_module),
  43. Configuration = app_helper:get_env(ecnty),
  44. {ok, Vid} = vnode_id:get_vnodeid(Partition),
  45. {ok, StorageState} = Module:start(Partition, Configuration),
  46. {ok, #state { storage_module = Module, partition=Partition, my_id = <<Partition:160, Vid/binary>>, storage_state = StorageState }}.
  47. do_get(StatName, _Sender, #state{storage_module = StorageModule, storage_state=StorageState}=State) ->
  48. lager:debug("do_get ~p", [StatName]),
  49. case StorageModule:get(StorageState, StatName) of
  50. {ok, Counters} ->
  51. lager:debug("do_get ok ~p", [StatName]),
  52. {reply, {r, {ok, Counters}, State#state.partition}, State};
  53. {error, Reason} ->
  54. lager:debug("do_get error ~p ~p", [StatName, Reason]),
  55. {reply, {r, {error, Reason}, State#state.partition}, State}
  56. end.
  57. do_increment(StatName, Value, _Sender, #state{storage_module = StorageModule, my_id = MyId, storage_state=StorageState}=State) ->
  58. case StorageModule:get(StorageState, StatName) of
  59. {ok, Counters} ->
  60. NewCounters = partitioned_counter:update(MyId, Value, Counters),
  61. store_update(NewCounters, StatName, State);
  62. {error, not_found} ->
  63. NewCounters = partitioned_counter:new(MyId, Value),
  64. store_update(NewCounters, StatName, State);
  65. {error, Reason} ->
  66. {reply, {error, Reason}, State}
  67. end.
  68. do_merge_counters(StatName, CountersToMerge, #state{storage_module = StorageModule, storage_state=StorageState}=State) ->
  69. lager:debug("Do Merge Counters"),
  70. case StorageModule:get(StorageState, StatName) of
  71. {ok, Counters} ->
  72. NewCounters = partitioned_counter:merge([Counters, CountersToMerge]),
  73. store_merged_counters(NewCounters, StatName, State);
  74. {error, not_found} ->
  75. store_merged_counters(CountersToMerge, StatName, State);
  76. {error, Reason} ->
  77. {reply, {error, Reason}, State}
  78. end.
  79. store_merged_counters(Counters, StatName, #state{storage_module = StorageModule, storage_state=StorageState}=State) ->
  80. case StorageModule:put(StorageState, StatName, Counters) of
  81. {ok, NewStorageState} ->
  82. lager:debug("Counter Stored"),
  83. {reply, ok, State#state{storage_state=NewStorageState}};
  84. {error, Reason, NewStorageState} ->
  85. {reply, {error, Reason}, State#state{storage_state=NewStorageState}}
  86. end.
  87. store_update(Counters, StatName, #state{storage_module = StorageModule, storage_state=StorageState}=State) ->
  88. case StorageModule:put(StorageState, StatName, Counters) of
  89. {ok, NewStorageState} -> {reply, {ok, Counters}, State#state{storage_state=NewStorageState}};
  90. {error, Reason, NewStorageState} -> {reply, {error, Reason}, State#state{storage_state=NewStorageState}}
  91. end.
  92. % Sample command: respond to a ping
  93. handle_command(ping, _Sender, State) ->
  94. {reply, {pong, State#state.partition}, State};
  95. handle_command({increment, StatName, Value}, Sender, State) ->
  96. do_increment(StatName, Value, Sender, State);
  97. handle_command({merge, Key, Counters}, _Sender, State) ->
  98. do_merge_counters(Key, Counters, State);
  99. handle_command({get, StatName}, Sender, State) ->
  100. do_get(StatName, Sender, State);
  101. handle_command(Message, _Sender, State) ->
  102. lager:error("Unhandled Command ~p", [Message]),
  103. {noreply, State}.
  104. handle_handoff_command(?FOLD_REQ{foldfun=FoldFun, acc0=Acc0}, _Sender, #state{storage_module = StorageModule, storage_state=StorageState}=State) ->
  105. FoldResult = StorageModule:fold_objects(StorageState, FoldFun, Acc0),
  106. case FoldResult of
  107. {ok, Acc} ->
  108. {reply, Acc, State};
  109. {error, ERROR} ->
  110. {reply, ERROR, State}
  111. end;
  112. handle_handoff_command(_Req, _Sender, State) -> {forward, State}.
  113. handoff_starting(_TargetNode, State) ->
  114. {true, State}.
  115. handoff_cancelled(State) ->
  116. {ok, State}.
  117. handoff_finished(_TargetNode, State) ->
  118. {ok, State}.
  119. handle_handoff_data(Data, State) ->
  120. {CounterName, Counters} = binary_to_term(Data),
  121. do_merge_counters(CounterName, Counters, State).
  122. encode_handoff_item(CounterName, CounterValue) ->
  123. term_to_binary({CounterName, CounterValue}).
  124. is_empty(#state{storage_state=StorageState, storage_module = StorageModule}=State) ->
  125. {StorageModule:is_empty(StorageState), State}.
  126. delete(#state{storage_module = StorageModule, storage_state=StorageState, partition=Partition}=State) ->
  127. {ok, cleared} = vnode_id:clear_vnodeid(Partition),
  128. case StorageModule:drop(StorageState) of
  129. {ok, NewStorageState} ->
  130. ok;
  131. {error, _Reason, NewStorageState} ->
  132. ok
  133. end,
  134. {ok, State#state{storage_state=NewStorageState, my_id=undefined}}.
  135. handle_exit(_Pid, _Reason, State) ->
  136. {noreply, State}.
  137. handle_coverage(_Req, _KeySpaces, _Sender, State) ->
  138. {stop, not_implemented, State}.
  139. terminate(_Reason, #state{storage_module = StorageModule, storage_state=StorageState}) ->
  140. StorageModule:stop(StorageState),
  141. ok.