2015-09-08 07:11:54 +00:00
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
%%
|
|
|
|
%% Copyright (c) 2007-2015 Basho Technologies, Inc. All Rights Reserved.
|
|
|
|
%%
|
|
|
|
%% This file is provided to you under the Apache License,
|
|
|
|
%% Version 2.0 (the "License"); you may not use this file
|
|
|
|
%% except in compliance with the License. You may obtain
|
|
|
|
%% a copy of the License at
|
|
|
|
%%
|
|
|
|
%% http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
%%
|
|
|
|
%% Unless required by applicable law or agreed to in writing,
|
|
|
|
%% software distributed under the License is distributed on an
|
|
|
|
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
|
|
%% KIND, either express or implied. See the License for the
|
|
|
|
%% specific language governing permissions and limitations
|
|
|
|
%% under the License.
|
|
|
|
%%
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
|
|
|
-module(machi_fitness).
|
|
|
|
|
|
|
|
-behaviour(gen_server).
|
|
|
|
|
2015-09-08 10:13:03 +00:00
|
|
|
-ifdef(TEST).
|
|
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
|
|
-endif. % TEST
|
|
|
|
|
|
|
|
-define(LWWREG, riak_dt_lwwreg).
|
|
|
|
-define(MAP, riak_dt_map).
|
|
|
|
|
2015-09-08 07:11:54 +00:00
|
|
|
%% API
|
|
|
|
-export([start_link/1,
|
|
|
|
get_unfit_list/1, update_local_down_list/2]).
|
|
|
|
|
|
|
|
%% gen_server callbacks
|
|
|
|
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
|
|
|
terminate/2, code_change/3]).
|
|
|
|
|
|
|
|
-record(state, {
|
2015-09-08 10:13:03 +00:00
|
|
|
name :: atom() | binary(),
|
|
|
|
local_down=[] :: list(),
|
|
|
|
active_map=?MAP:new() :: ?MAP:riak_dt_map(),
|
|
|
|
pending_map=?MAP:new() :: ?MAP:riak_dt_map()
|
2015-09-08 07:11:54 +00:00
|
|
|
}).
|
|
|
|
|
|
|
|
start_link(Args) ->
|
|
|
|
gen_server:start_link(?MODULE, Args, []).
|
|
|
|
|
|
|
|
get_unfit_list(PidSpec) ->
|
|
|
|
gen_server:call(PidSpec, {get_unfit_list}, infinity).
|
|
|
|
|
|
|
|
update_local_down_list(PidSpec, Down) ->
|
|
|
|
gen_server:call(PidSpec, {update_local_down_list, Down}, infinity).
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
|
|
init([{FluName}|_Args]) ->
|
|
|
|
RegName = machi_flu_psup:make_fitness_regname(FluName),
|
|
|
|
register(RegName, self()),
|
2015-09-08 10:13:03 +00:00
|
|
|
{ok, #state{name=RegName}}.
|
2015-09-08 07:11:54 +00:00
|
|
|
|
|
|
|
handle_call({get_unfit_list}, _From, S) ->
|
2015-09-08 10:13:03 +00:00
|
|
|
Unfit = make_unfit_list(S),
|
|
|
|
io:format(user, "LINE ~p val ~p\n", [?LINE, Unfit]),
|
|
|
|
{reply, Unfit, S};
|
|
|
|
handle_call({update_local_down_list, Down}, _From,
|
|
|
|
#state{name=Name, active_map=OldMap, local_down=OldDown}=S) ->
|
|
|
|
NewMap = store_in_map(OldMap, Name, erlang:now(), Down, [props_yo]),
|
|
|
|
if Down == OldDown ->
|
|
|
|
ok;
|
|
|
|
true ->
|
|
|
|
io:format(user, "fitness: ~w: ~w -> ~w\n", [Name, OldDown, Down]),
|
|
|
|
io:format(user, "TODO: spam\n", []),
|
|
|
|
io:format(user, "TODO: sched ticks, others...?\n", [])
|
|
|
|
end,
|
|
|
|
{reply, ok, S#state{local_down=Down, pending_map=NewMap}};
|
2015-09-08 07:11:54 +00:00
|
|
|
handle_call(_Request, _From, S) ->
|
|
|
|
Reply = whhhhhhhhhhhhhhaaaaaaaaaaaaaaa,
|
|
|
|
{reply, Reply, S}.
|
|
|
|
|
|
|
|
handle_cast(_Msg, S) ->
|
|
|
|
{noreply, S}.
|
|
|
|
|
|
|
|
handle_info(_Info, S) ->
|
|
|
|
{noreply, S}.
|
|
|
|
|
|
|
|
terminate(_Reason, _S) ->
|
|
|
|
ok.
|
|
|
|
|
|
|
|
code_change(_OldVsn, S, _Extra) ->
|
|
|
|
{ok, S}.
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
2015-09-08 10:13:03 +00:00
|
|
|
|
|
|
|
make_unfit_list(S) ->
|
|
|
|
Now = erlang:now(),
|
|
|
|
F = fun({Server, {UpdateTime, DownList, _Props}}, Acc) ->
|
|
|
|
case timer:now_diff(Now, UpdateTime) div (1000*1000) of
|
|
|
|
N when N > 900 ->
|
|
|
|
Acc;
|
|
|
|
_ ->
|
|
|
|
Probs = [{Server,problem_with,D} || D <- DownList],
|
|
|
|
[Probs|Acc]
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
QQ1 = (catch map_fold(F, [], S#state.active_map)),
|
|
|
|
QQ2 = (catch map_fold(F, [], S#state.pending_map)),
|
|
|
|
io:format(user, "QQ1 ~p\n", [QQ1]),
|
|
|
|
io:format(user, "QQ2 ~p\n", [QQ2]),
|
|
|
|
S#state.local_down.
|
|
|
|
|
|
|
|
store_in_map(Map, Name, Now, Down, Props) ->
|
|
|
|
Val = {Now, Down, Props},
|
|
|
|
map_set(Name, Map, Name, Val).
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
|
|
map_set(Actor, Map, Key, ValTerm) ->
|
|
|
|
Field = {Key, ?LWWREG},
|
|
|
|
Val = term_to_binary(ValTerm),
|
|
|
|
{ok, Map2} = ?MAP:update({update, [{update, Field, {assign, Val}}]},
|
|
|
|
Actor, Map),
|
|
|
|
Map2.
|
|
|
|
|
|
|
|
map_get(Map, Key) ->
|
|
|
|
Field = {Key, ?LWWREG},
|
|
|
|
case lists:keyfind(Field, 1, ?MAP:value(Map)) of
|
|
|
|
false ->
|
|
|
|
error;
|
|
|
|
{Field, ValBin} ->
|
|
|
|
{ok, binary_to_term(ValBin)}
|
|
|
|
end.
|
|
|
|
|
|
|
|
map_fold(Fun, Acc, Map) ->
|
|
|
|
Vs = [{K, binary_to_term(V)} || {{K, _Type}, V} <- ?MAP:value(Map)],
|
|
|
|
lists:foldl(Fun, Acc, lists:sort(Vs)).
|
|
|
|
|
|
|
|
-ifdef(TEST).
|
|
|
|
|
|
|
|
|
|
|
|
dt_understanding_test() ->
|
|
|
|
F1 = {'X', riak_dt_lwwreg},
|
|
|
|
F2 = {'Y', riak_dt_lwwreg},
|
|
|
|
{ok, Map1} = ?MAP:update({update, [{update, F1, {assign, <<"A">>}}]}, a, ?MAP:new()),
|
|
|
|
{ok, Map2} = ?MAP:update({update, [{update, F2, {assign, <<"B2">>}}]}, b, ?MAP:new()),
|
|
|
|
|
|
|
|
%% io:format(user, "\n", []),
|
|
|
|
%% io:format(user, "Merge comparison: ~p\n", [?MAP:merge(Map1, Map2) == ?MAP:merge(Map2, Map1)]),
|
|
|
|
%% io:format(user, "M12 Val: ~p\n", [?MAP:value(?MAP:merge(Map1, Map2))]),
|
|
|
|
%% io:format(user, "M21 Val: ~p\n", [?MAP:value(?MAP:merge(Map2, Map1))]),
|
|
|
|
?MAP:merge(Map1, Map2) == ?MAP:merge(Map2, Map1).
|
|
|
|
|
|
|
|
smoke_test() ->
|
|
|
|
{ok, Map1} = map_set(a, ?MAP:new(), k1, val1),
|
|
|
|
{ok, Map2} = map_set(a, Map1, k2, val2),
|
|
|
|
{ok, val1} = map_get(Map2, k1),
|
|
|
|
{ok, val2} = map_get(Map2, k2),
|
|
|
|
error = map_get(Map2, does_not_exist),
|
|
|
|
{ok, Map3} = map_set(a, Map2, k3, val3),
|
|
|
|
|
|
|
|
[{k3,1},{k2,1},{k1,1}] = map_fold(fun({K,_}, Acc) -> [{K,1}|Acc] end,
|
|
|
|
[], Map3),
|
|
|
|
ok.
|
|
|
|
|
|
|
|
-endif. % TEST
|