From 208c02853ffd4e223c6eca3071d873503faca5fd Mon Sep 17 00:00:00 2001 From: Shunichi Shinohara Date: Wed, 14 Oct 2015 17:37:04 +0900 Subject: [PATCH] Add cluster_info to deps and small callback module For debuging from shell, some functions in machi_cinfo are exported: - public_projection/1 - private_projection/1 - fitness/1 - chain_manager/1 - flu1/1 --- rebar.config | 3 +- src/machi.app.src | 2 +- src/machi_app.erl | 8 +-- src/machi_chain_manager1.erl | 7 ++- src/machi_cinfo.erl | 104 +++++++++++++++++++++++++++++++++++ src/machi_fitness.erl | 7 ++- src/machi_flu1.erl | 18 ++++++ test/machi_cinfo_test.erl | 67 ++++++++++++++++++++++ 8 files changed, 206 insertions(+), 10 deletions(-) create mode 100644 src/machi_cinfo.erl create mode 100644 test/machi_cinfo_test.erl diff --git a/rebar.config b/rebar.config index 782fa10..661991a 100644 --- a/rebar.config +++ b/rebar.config @@ -9,7 +9,8 @@ {protobuffs, "0.8.*", {git, "git://github.com/basho/erlang_protobuffs.git", {tag, "0.8.1p4"}}}, {riak_dt, ".*", {git, "git://github.com/basho/riak_dt.git", {branch, "develop"}}}, {node_package, ".*", {git, "git://github.com/basho/node_package.git", {branch, "develop"}}}, - {eper, ".*", {git, "git://github.com/basho/eper.git", {tag, "0.78"}}} + {eper, ".*", {git, "git://github.com/basho/eper.git", {branch, "develop"}}}, + {cluster_info, ".*", {git, "git://github.com/basho/cluster_info", {branch, "develop"}}} ]}. {sub_dirs, ["rel", "apps/machi"]}. diff --git a/src/machi.app.src b/src/machi.app.src index e12605a..a15b20c 100644 --- a/src/machi.app.src +++ b/src/machi.app.src @@ -1,7 +1,7 @@ {application, machi, [ {description, "A village of write-once files."}, {vsn, "0.0.0"}, - {applications, [kernel, stdlib, crypto]}, + {applications, [kernel, stdlib, crypto, cluster_info]}, {mod,{machi_app,[]}}, {registered, []}, {env, [ diff --git a/src/machi_app.erl b/src/machi_app.erl index 649a7db..18b1e6d 100644 --- a/src/machi_app.erl +++ b/src/machi_app.erl @@ -36,12 +36,8 @@ -export([start/2, stop/1]). start(_StartType, _StartArgs) -> - case machi_sup:start_link() of - {ok, Pid} -> - {ok, Pid}; - Error -> - Error - end. + machi_cinfo:register(), + machi_sup:start_link(). stop(_State) -> ok. diff --git a/src/machi_chain_manager1.erl b/src/machi_chain_manager1.erl index 0e8d95a..0718aa4 100644 --- a/src/machi_chain_manager1.erl +++ b/src/machi_chain_manager1.erl @@ -111,7 +111,7 @@ set_chain_members/2, set_chain_members/3, set_active/2, trigger_react_to_env/1]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). + terminate/2, format_status/2, code_change/3]). -export([make_chmgr_regname/1, projection_transitions_are_sane/2, simple_chain_state_transition_is_sane/3, @@ -400,6 +400,11 @@ handle_info(Msg, #ch_mgr{name=MyName}=S) -> terminate(_Reason, _S) -> ok. +format_status(_Opt, [_PDict, Status]) -> + Fields = record_info(fields, ch_mgr), + [_Name | Values] = tuple_to_list(Status), + lists:zip(Fields, Values). + code_change(_OldVsn, S, _Extra) -> {ok, S}. diff --git a/src/machi_cinfo.erl b/src/machi_cinfo.erl new file mode 100644 index 0000000..1036c82 --- /dev/null +++ b/src/machi_cinfo.erl @@ -0,0 +1,104 @@ +%% ------------------------------------------------------------------- +%% +%% 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. +%% +%% ------------------------------------------------------------------- + +%% @doc cluster_info callback module for machi specific information +%% gathering. + +-module(machi_cinfo). + +%% cluster_info callbacks +-export([register/0, cluster_info_init/0, cluster_info_generator_funs/0]). + +%% for debug in interactive shell +-export([dump/0, + public_projection/1, private_projection/1, + chain_manager/1, fitness/1, flu1/1]). + +-include("machi_projection.hrl"). + +-spec register() -> ok. +register() -> + ok = cluster_info:register_app(?MODULE). + +-spec cluster_info_init() -> ok. +cluster_info_init() -> + ok. + +-spec cluster_info_generator_funs() -> [{string(), fun((pid()) -> ok)}]. +cluster_info_generator_funs() -> + FluNames = [Name || {Name, _, _, _} <- supervisor:which_children(machi_flu_sup)], + lists:flatten([generator_funs_package(Name) || Name <- FluNames]). + +generator_funs_package(FluName) -> + [{"Public projection of FLU " ++ atom_to_list(FluName), + cinfo_wrapper(fun public_projection/1, FluName)}, + {"Private projection of FLU " ++ atom_to_list(FluName), + cinfo_wrapper(fun private_projection/1, FluName)}, + {"Chain manager status of FLU " ++ atom_to_list(FluName), + cinfo_wrapper(fun chain_manager/1, FluName)}, + {"Fitness server status of FLU " ++ atom_to_list(FluName), + cinfo_wrapper(fun fitness/1, FluName)}, + {"FLU1 status of FLU " ++ atom_to_list(FluName), + cinfo_wrapper(fun flu1/1, FluName)}]. + +dump() -> + {{Y,M,D},{HH,MM,SS}} = calendar:local_time(), + Filename = lists:flatten(io_lib:format( + "machi-ci-~4..0B~2..0B~2..0B-~2..0B~2..0B~2..0B.html", + [Y,M,D,HH,MM,SS])), + cluster_info:dump_local_node(Filename). + +-spec public_projection(atom()) -> ok. +public_projection(FluName) -> + projection(FluName, public). + +-spec private_projection(atom()) -> ok. +private_projection(FluName) -> + projection(FluName, private). + +-spec chain_manager(atom()) -> ok. +chain_manager(FluName) -> + Mgr = machi_flu_psup:make_mgr_supname(FluName), + sys:get_status(Mgr). + +-spec fitness(atom()) -> ok. +fitness(FluName) -> + Fitness = machi_flu_psup:make_fitness_regname(FluName), + sys:get_status(Fitness). + +-spec flu1(atom()) -> ok. +flu1(FluName) -> + State = machi_flu1:current_state(FluName), + machi_flu1:format_state(State). + +%% Internal functions + +projection(FluName, Kind) -> + ProjStore = machi_flu1:make_projection_server_regname(FluName), + {ok, Projection} = machi_projection_store:read_latest_projection( + whereis(ProjStore), Kind), + Fields = record_info(fields, projection_v1), + [_Name | Values] = tuple_to_list(Projection), + lists:zip(Fields, Values). + +cinfo_wrapper(Fun, FluName) -> + fun(C) -> + cluster_info:format(C, "~p", [Fun(FluName)]) + end. diff --git a/src/machi_fitness.erl b/src/machi_fitness.erl index c5dc3bb..993eecc 100644 --- a/src/machi_fitness.erl +++ b/src/machi_fitness.erl @@ -43,7 +43,7 @@ %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). + terminate/2, code_change/3, format_status/2]). -record(state, { my_flu_name :: atom() | binary(), @@ -193,6 +193,11 @@ handle_info(_Info, S) -> terminate(_Reason, _S) -> ok. +format_status(_Opt, [_PDict, Status]) -> + Fields = record_info(fields, state), + [_Name | Values] = tuple_to_list(Status), + lists:zip(Fields, Values). + code_change(_OldVsn, S, _Extra) -> {ok, S}. diff --git a/src/machi_flu1.erl b/src/machi_flu1.erl index 24a19a0..0a7ca50 100644 --- a/src/machi_flu1.erl +++ b/src/machi_flu1.erl @@ -61,6 +61,8 @@ -export([start_link/1, stop/1, update_wedge_state/3, wedge_myself/2]). -export([make_listener_regname/1, make_projection_server_regname/1]). +%% TODO: remove or replace in OTP way after gen_*'ified +-export([current_state/1, format_state/1]). -record(state, { flu_name :: atom(), @@ -98,6 +100,20 @@ wedge_myself(PidSpec, EpochId) when is_tuple(EpochId) -> PidSpec ! {wedge_myself, EpochId}. +current_state(PidSpec) -> + PidSpec ! {current_state, self()}, + %% TODO: Not so rubust f(^^;) + receive + Res -> Res + after + 60*1000 -> {error, timeout} + end. + +format_state(State) -> + Fields = record_info(fields, state), + [_Name | Values] = tuple_to_list(State), + lists:zip(Fields, Values). + %%%%%%%%%%%%%%%%%%%%%%%%%%%% ets_table_name(FluName) when is_atom(FluName) -> @@ -262,6 +278,8 @@ append_server_loop(FluPid, #state{wedged=Wedged_p, #state{wedged=Wedged_p, epoch_id=EpochId} = S, FromPid ! {wedge_status_reply, Wedged_p, EpochId}, append_server_loop(FluPid, S); + {current_state, FromPid} -> + FromPid ! S; Else -> io:format(user, "append_server_loop: WHA? ~p\n", [Else]), append_server_loop(FluPid, S) diff --git a/test/machi_cinfo_test.erl b/test/machi_cinfo_test.erl new file mode 100644 index 0000000..dcb611e --- /dev/null +++ b/test/machi_cinfo_test.erl @@ -0,0 +1,67 @@ +%% ------------------------------------------------------------------- +%% +%% 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_cinfo_test). + +-ifdef(TEST). +-ifndef(PULSE). + +-include_lib("eunit/include/eunit.hrl"). + +-include("machi_projection.hrl"). + +%% smoke_test() will try just dump cluster_info and call each functions + +smoke_test_() -> + {setup, + fun setup/0, + fun cleanup/1, + [ + fun() -> machi_cinfo:public_projection(a) end, + fun() -> machi_cinfo:private_projection(a) end, + fun() -> machi_cinfo:fitness(a) end, + fun() -> machi_cinfo:chain_manager(a) end, + fun() -> machi_cinfo:dump() end + ]}. + +setup() -> + machi_cinfo:register(), + Ps = [{a,#p_srvr{name=a, address="localhost", port=5555, props="./data.a"}}, + {b,#p_srvr{name=b, address="localhost", port=5556, props="./data.b"}}, + {c,#p_srvr{name=c, address="localhost", port=5557, props="./data.c"}} + ], + [os:cmd("rm -rf " ++ P#p_srvr.props) || {_,P} <- Ps], + {ok, SupPid} = machi_flu_sup:start_link(), + %% Only run a, don't run b & c so we have 100% failures talking to them + [begin + #p_srvr{name=Name, port=Port, props=Dir} = P, + {ok, _} = machi_flu_psup:start_flu_package(Name, Port, Dir, []) + end || {_,P} <- [hd(Ps)]], + machi_chain_manager1:set_chain_members(a_chmgr, orddict:from_list(Ps)), + {SupPid, Ps}. + +cleanup({SupPid, Ps}) -> + exit(SupPid, normal), + [os:cmd("rm -rf " ++ P#p_srvr.props) || {_,P} <- Ps], + machi_util:wait_for_death(SupPid, 100), + ok. + +-endif. % !PULSE +-endif. % TEST