/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
- -module(ecnty_vnode).
- -behaviour(riak_core_vnode).
- -include("ecnty.hrl").
- -include_lib("riak_core/include/riak_core_vnode.hrl").
- -compile([{parse_transform, lager_transform}]).
- -export([test_vnode/1]).
- -export([start_vnode/1,
- init/1,
- terminate/2,
- handle_command/3,
- is_empty/1,
- delete/1,
- handle_handoff_command/3,
- handoff_starting/2,
- handoff_cancelled/1,
- handoff_finished/2,
- handle_handoff_data/2,
- encode_handoff_item/2,
- handle_exit/3,
- handle_coverage/4]).
- -export([increment/4, increment_sync/3, get/3, get_sync/2, merge/4]).
- -define(MASTER, ecnty_vnode_master).
- -define(sync(PrefList, Command, Master),
- riak_core_vnode_master:sync_command(PrefList, Command, Master)).
- -record(state, {storage_module, storage_state, my_id = "" :: string(), partition}).
- test_vnode(I) ->
- riak_core_vnode:start_link(?MODULE, I, infinity).
-
- %% API
- start_vnode(I) ->
- riak_core_vnode_master:get_vnode_pid(I, ?MODULE).
- get_sync(Preflist, Key) ->
- riak_core_vnode_master:sync_command(Preflist, {get, Key}, ?MASTER).
-
- increment_sync(Preflist, Key, Value) ->
- riak_core_vnode_master:sync_command(Preflist, {increment, Key, Value}, ?MASTER).
- get(Preflist, Key, Sender) ->
- riak_core_vnode_master:command(Preflist, {get, Key}, Sender, ?MASTER).
- merge(Preflist, Key, Counters, Sender) ->
- riak_core_vnode_master:command(Preflist, {merge, Key, Counters}, Sender, ?MASTER).
- increment(Preflist, Key, Val, Sender) ->
- riak_core_vnode_master:command(Preflist, {increment, Key, Val}, Sender, ?MASTER).
- init([Partition]) ->
- Module = app_helper:get_env(ecnty, storage_module),
- Configuration = app_helper:get_env(ecnty),
-
- {ok, Vid} = vnode_id:get_vnodeid(Partition),
- {ok, StorageState} = Module:start(Partition, Configuration),
- {ok, #state { storage_module = Module, partition=Partition, my_id = <<Partition:160, Vid/binary>>, storage_state = StorageState }}.
- do_get(StatName, _Sender, #state{storage_module = StorageModule, storage_state=StorageState}=State) ->
- lager:debug("do_get ~p", [StatName]),
- case StorageModule:get(StorageState, StatName) of
- {ok, Counters} ->
- lager:debug("do_get ok ~p", [StatName]),
- {reply, {r, {ok, Counters}, State#state.partition}, State};
- {error, Reason} ->
- lager:debug("do_get error ~p ~p", [StatName, Reason]),
- {reply, {r, {error, Reason}, State#state.partition}, State}
- end.
-
- do_increment(StatName, Value, _Sender, #state{storage_module = StorageModule, my_id = MyId, storage_state=StorageState}=State) ->
- case StorageModule:get(StorageState, StatName) of
- {ok, Counters} ->
- NewCounters = partitioned_counter:update(MyId, Value, Counters),
- store_update(NewCounters, StatName, State);
- {error, not_found} ->
- NewCounters = partitioned_counter:new(MyId, Value),
- store_update(NewCounters, StatName, State);
- {error, Reason} ->
- {reply, {error, Reason}, State}
- end.
- do_merge_counters(StatName, CountersToMerge, #state{storage_module = StorageModule, storage_state=StorageState}=State) ->
- lager:debug("Do Merge Counters"),
- case StorageModule:get(StorageState, StatName) of
- {ok, Counters} ->
- NewCounters = partitioned_counter:merge([Counters, CountersToMerge]),
- store_merged_counters(NewCounters, StatName, State);
- {error, not_found} ->
- store_merged_counters(CountersToMerge, StatName, State);
- {error, Reason} ->
- {reply, {error, Reason}, State}
- end.
-
- store_merged_counters(Counters, StatName, #state{storage_module = StorageModule, storage_state=StorageState}=State) ->
- case StorageModule:put(StorageState, StatName, Counters) of
- {ok, NewStorageState} ->
- lager:debug("Counter Stored"),
- {reply, ok, State#state{storage_state=NewStorageState}};
- {error, Reason, NewStorageState} ->
- {reply, {error, Reason}, State#state{storage_state=NewStorageState}}
- end.
- store_update(Counters, StatName, #state{storage_module = StorageModule, storage_state=StorageState}=State) ->
- case StorageModule:put(StorageState, StatName, Counters) of
- {ok, NewStorageState} -> {reply, {ok, Counters}, State#state{storage_state=NewStorageState}};
- {error, Reason, NewStorageState} -> {reply, {error, Reason}, State#state{storage_state=NewStorageState}}
- end.
- % Sample command: respond to a ping
- handle_command(ping, _Sender, State) ->
- {reply, {pong, State#state.partition}, State};
- handle_command({increment, StatName, Value}, Sender, State) ->
- do_increment(StatName, Value, Sender, State);
- handle_command({merge, Key, Counters}, _Sender, State) ->
- do_merge_counters(Key, Counters, State);
- handle_command({get, StatName}, Sender, State) ->
- do_get(StatName, Sender, State);
- handle_command(Message, _Sender, State) ->
- lager:error("Unhandled Command ~p", [Message]),
- {noreply, State}.
- handle_handoff_command(?FOLD_REQ{foldfun=FoldFun, acc0=Acc0}, _Sender, #state{storage_module = StorageModule, storage_state=StorageState}=State) ->
- FoldResult = StorageModule:fold_objects(StorageState, FoldFun, Acc0),
- case FoldResult of
- {ok, Acc} ->
- {reply, Acc, State};
- {error, ERROR} ->
- {reply, ERROR, State}
- end;
- handle_handoff_command(_Req, _Sender, State) -> {forward, State}.
- handoff_starting(_TargetNode, State) ->
- {true, State}.
- handoff_cancelled(State) ->
- {ok, State}.
- handoff_finished(_TargetNode, State) ->
- {ok, State}.
- handle_handoff_data(Data, State) ->
- {CounterName, Counters} = binary_to_term(Data),
- do_merge_counters(CounterName, Counters, State).
- encode_handoff_item(CounterName, CounterValue) ->
- term_to_binary({CounterName, CounterValue}).
- is_empty(#state{storage_state=StorageState, storage_module = StorageModule}=State) ->
- {StorageModule:is_empty(StorageState), State}.
- delete(#state{storage_module = StorageModule, storage_state=StorageState, partition=Partition}=State) ->
- {ok, cleared} = vnode_id:clear_vnodeid(Partition),
- case StorageModule:drop(StorageState) of
- {ok, NewStorageState} ->
- ok;
- {error, _Reason, NewStorageState} ->
- ok
- end,
- {ok, State#state{storage_state=NewStorageState, my_id=undefined}}.
- handle_exit(_Pid, _Reason, State) ->
- {noreply, State}.
- handle_coverage(_Req, _KeySpaces, _Sender, State) ->
- {stop, not_implemented, State}.
-
- terminate(_Reason, #state{storage_module = StorageModule, storage_state=StorageState}) ->
- StorageModule:stop(StorageState),
- ok.