mirror of
https://github.com/Telecominfraproject/wlan-cloud-loadsim.git
synced 2026-01-08 21:11:30 +00:00
ovsdb client hadler now working for startup sequence
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
-ifdef(debug).
|
||||
-define(DBGTRC(Msg), io:format("~s:~s (~p) => ~s~n",[?MODULE,?FUNCTION_NAME,?LINE,Msg])).
|
||||
-define(DBGSTR(Msg), io_lib:format("~s:~s (~B) => ~s~n",[?MODULE,?FUNCTION_NAME,?LINE,Msg])).
|
||||
-define(DBGSTR(FMsg,Args), io_lib:format("~s:~s (~B) => " FMsg "~n",[?MODULE,?FUNCTION_NAME,?LINE] ++ [Args])).
|
||||
-define(DBGSTR(FMsg,Args), io_lib:format("~s:~s (~B) => " FMsg "~n",[?MODULE,?FUNCTION_NAME,?LINE] ++ Args)).
|
||||
-else.
|
||||
-define(DBGTRC(Msg), true).
|
||||
-define(DBGSTR(Msg), Msg).
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
|
||||
%% API
|
||||
-export([start/2]).
|
||||
-export([start_link/3]).
|
||||
-export([uuid/1]).
|
||||
|
||||
|
||||
@@ -40,14 +40,17 @@
|
||||
|
||||
%% data structures
|
||||
|
||||
-type ap_status() :: init | ready | running | paused | stopped.
|
||||
-export_type([ap_status/0]).
|
||||
|
||||
-record(ap_state, {
|
||||
sim_node :: pid(), % controlling simnode
|
||||
sim_manager :: pid(), % manager to be contacted to get configuration
|
||||
serial :: string(), % serial number of the access point
|
||||
type :: binary(), % device type e.g. EA8300
|
||||
uuid :: term(), % unique ID for this AP node
|
||||
serial = "" :: string(), % serial number of the access point
|
||||
type = <<"">> :: binary(), % device type e.g. EA8300
|
||||
uuid :: string(), % unique ID for this AP node
|
||||
timer :: owls_timers:tms(),
|
||||
status = init :: init | ready | running | stopped, % internal status
|
||||
status = init :: ap_status(), % internal status
|
||||
config = #{} :: map(),
|
||||
statistics = #{} :: map()
|
||||
}).
|
||||
@@ -60,14 +63,15 @@
|
||||
%%%============================================================================
|
||||
|
||||
|
||||
-spec start (Handler, Spec) -> {ok, Pid} | {error, Reason} when
|
||||
-spec start_link (Handler, Id, SimMan) -> {ok, Pid} | {error, Reason} when
|
||||
Handler :: pid(),
|
||||
Spec :: proplists:proplist(),
|
||||
Id :: UUID::string(),
|
||||
SimMan :: pid(),
|
||||
Pid :: pid(),
|
||||
Reason :: term().
|
||||
|
||||
start (Handler, Spec) ->
|
||||
gen_server:start(?MODULE, {Handler, Spec}, []).
|
||||
start_link (Handler, Id, SimMan) ->
|
||||
gen_server:start_link(?MODULE, {Handler, Id, SimMan}, []).
|
||||
|
||||
|
||||
|
||||
@@ -86,14 +90,15 @@ uuid (Node) ->
|
||||
%%% GEN_SERVER callbacks
|
||||
%%%============================================================================
|
||||
|
||||
-spec init ({Handler, Spec}) -> {ok, State} when
|
||||
-spec init ({Handler, Id, SimMan}) -> {ok, State} when
|
||||
Handler :: pid(),
|
||||
Spec :: proplists:proplist(),
|
||||
Id :: UUID::string(),
|
||||
SimMan :: pid(),
|
||||
State :: #ap_state{}.
|
||||
|
||||
init ({Handler,Spec}) ->
|
||||
init ({Handler,Id,SimMan}) ->
|
||||
process_flag(trap_exit, true),
|
||||
InitialState = prepare_state(Handler,Spec),
|
||||
InitialState = prepare_state(Handler,Id,SimMan),
|
||||
gen_server:cast(self(),start_up),
|
||||
{ok, InitialState}.
|
||||
|
||||
@@ -181,20 +186,19 @@ code_change (_,OldState,_) ->
|
||||
%%%============================================================================
|
||||
|
||||
|
||||
%---------prepare_state/2----------------convert Spec proplist into internal state
|
||||
%---------prepare_state/3----------------convert Spec proplist into internal state
|
||||
|
||||
-spec prepare_state (Node, Spec) -> State when
|
||||
Node :: pid(),
|
||||
Spec :: proplists:proplist(),
|
||||
-spec prepare_state (Handler, ID, SimMan) -> State when
|
||||
Handler :: pid(),
|
||||
ID :: UUID::string(),
|
||||
SimMan :: pid(),
|
||||
State :: #ap_state{}.
|
||||
|
||||
prepare_state (Node,Spec) ->
|
||||
prepare_state (Handler, ID, SimMan) ->
|
||||
#ap_state{
|
||||
sim_node = Node,
|
||||
sim_manager = proplists:get_value(manager,Spec,Node),
|
||||
serial = proplists:get_value(ap_serial,Spec,"1P000000000"),
|
||||
type = proplists:get_value(ap_type,Spec,<<"EA8300">>),
|
||||
uuid = proplists:get_value(uuid,Spec,erlang:phash2({node(),erlang:system_time()})),
|
||||
sim_node = Handler,
|
||||
sim_manager = SimMan,
|
||||
uuid = ID,
|
||||
timer = owls_timers:new(millisecond)
|
||||
}.
|
||||
|
||||
|
||||
@@ -12,7 +12,10 @@
|
||||
-behaviour(gen_server).
|
||||
-behaviour(gen_sim_client).
|
||||
|
||||
-include("../include/common.hrl").
|
||||
|
||||
-define(SERVER, ?MODULE).
|
||||
-define(MAX_STARTUP_TIME,10000).
|
||||
|
||||
%% API
|
||||
-export([start_link/0]).
|
||||
@@ -25,14 +28,22 @@
|
||||
|
||||
%% data structures
|
||||
|
||||
-type client_ref() :: {UUID::string(), available | dead | pid()}.
|
||||
-type client_states() :: #{UUID::string() := available | ovsdb_ap:ap_status()}.
|
||||
-type client_refs() :: #{pid() := UUID::string()}.
|
||||
|
||||
-record(hdl_state, {
|
||||
clients_avail = [] :: [client_ref()],
|
||||
clients_started = [] :: [client_ref()],
|
||||
clients_running = [] :: [client_ref()],
|
||||
clients_paused = [] :: [client_ref()],
|
||||
config = #{} :: #{}
|
||||
-record (command,{
|
||||
cmd :: start | stop | pause | cancel,
|
||||
refs :: [UUID::string()]
|
||||
}).
|
||||
|
||||
-type command() :: #command{}.
|
||||
|
||||
-record (hdl_state, {
|
||||
client_states = #{} :: client_states(),
|
||||
client_pids = #{} :: client_refs(),
|
||||
cmd_queue = [] :: [command()],
|
||||
config = #{} :: #{},
|
||||
timer :: owls_timers:tms()
|
||||
}).
|
||||
|
||||
|
||||
@@ -65,7 +76,7 @@ set_configuration (Cfg) ->
|
||||
Reason :: term().
|
||||
|
||||
start (What) ->
|
||||
gen_server:call(?SERVER,{start_sim, What}).
|
||||
gen_server:call(?SERVER,{cmd_start, What}).
|
||||
|
||||
|
||||
|
||||
@@ -124,7 +135,7 @@ report () ->
|
||||
|
||||
init (_) ->
|
||||
process_flag(trap_exit, true),
|
||||
{ok, #hdl_state{}}.
|
||||
{ok, #hdl_state{timer=owls_timers:new(millisecond)}}.
|
||||
|
||||
|
||||
|
||||
@@ -135,6 +146,9 @@ init (_) ->
|
||||
NewState :: #hdl_state{},
|
||||
Reason :: term().
|
||||
|
||||
handle_cast (execute, State) ->
|
||||
{noreply, execute_cmd(State)};
|
||||
|
||||
handle_cast (_,State) ->
|
||||
{noreply, State}.
|
||||
|
||||
@@ -150,16 +164,10 @@ handle_cast (_,State) ->
|
||||
NewState :: #hdl_state{}.
|
||||
|
||||
handle_call ({set_config, Cfg},_,State) ->
|
||||
NewState = apply_config(State,Cfg),
|
||||
{reply, ok, NewState};
|
||||
{reply, ok, apply_config(State,Cfg)};
|
||||
|
||||
handle_call ({start_sim, How},_,State) ->
|
||||
case start_simulation(State,How) of
|
||||
{ok, NewState} ->
|
||||
{reply, ok, NewState};
|
||||
Error ->
|
||||
{reply, Error, State}
|
||||
end;
|
||||
handle_call ({cmd_start, How},_,State) ->
|
||||
{reply, ok, cmd_startup_sim(State,How)};
|
||||
|
||||
handle_call (_, _, State) ->
|
||||
{reply, invalid, State}.
|
||||
@@ -212,24 +220,144 @@ code_change (_,OldState,_) ->
|
||||
NewState :: #hdl_state{}.
|
||||
|
||||
apply_config (State, _Cfg) ->
|
||||
State#hdl_state{clients_avail=[{"a68d41fa-dd12-4fb7-bc44-e834667280b4",available}]}.
|
||||
State#hdl_state{client_states=#{"a68d41fa-dd12-4fb7-bc44-e834667280b4" => available}}.
|
||||
|
||||
|
||||
|
||||
|
||||
%--------start_simulation/2--------------start a simulation of designated clients
|
||||
%--------get_clients_in_state/3----------filter all clients with state
|
||||
|
||||
-spec start_simulation (State, How) -> {ok, NewState} | {error, Reason} when
|
||||
-spec get_clients_in_state (State, Clients, Candidates) -> Available when
|
||||
State :: available | ovsdb_ap:ap_status(),
|
||||
Clients :: client_states(),
|
||||
Candidates :: all | [UUID::string()],
|
||||
Available :: [UUID::string()].
|
||||
|
||||
get_clients_in_state (State, Clients, all) ->
|
||||
[K || {K,V} <- maps:to_list(Clients), (V=:=State)];
|
||||
|
||||
get_clients_in_state (State, Clients, Candidates) ->
|
||||
[K || {K,V} <- maps:to_list(Clients), (V=:=State) and lists:member(K,Candidates)].
|
||||
|
||||
|
||||
|
||||
%%-----------------------------------------------------------------------------
|
||||
%% command queue handling
|
||||
|
||||
|
||||
%--------execute_cmd/1-------------------executes the first command in queue
|
||||
|
||||
-spec execute_cmd (State) -> NewState when
|
||||
State :: #hdl_state{},
|
||||
NewState :: #hdl_state{}.
|
||||
|
||||
execute_cmd (#hdl_state{cmd_queue=[]}=State) ->
|
||||
State;
|
||||
|
||||
execute_cmd (#hdl_state{cmd_queue=Q}=State) ->
|
||||
[Cmd|RemCmds] = lists:reverse(Q),
|
||||
AltState = State#hdl_state{cmd_queue=lists:reverse(RemCmds)},
|
||||
case Cmd of
|
||||
#command{cmd=start, refs=R} ->
|
||||
cmd_start_clients(R, AltState);
|
||||
|
||||
#command{cmd=Ukn} ->
|
||||
?L_E(?DBGSTR("Unknown command '~s' in queue",[Ukn])),
|
||||
AltState
|
||||
end.
|
||||
|
||||
|
||||
|
||||
|
||||
%--------cmd_startup_sim/2--------------lauches the start-up sequence of simulation clients
|
||||
|
||||
-spec cmd_startup_sim (State, How) -> NewState when
|
||||
State :: #hdl_state{},
|
||||
How :: all | [UUID::string()],
|
||||
NewState :: #hdl_state{},
|
||||
Reason :: string().
|
||||
NewState :: #hdl_state{}.
|
||||
|
||||
start_simulation (#hdl_state{clients_avail=[]}, _) ->
|
||||
{error, "no clients available"};
|
||||
cmd_startup_sim (State, How) ->
|
||||
NewState = #hdl_state{timer=owls_timers:mark("startup",State#hdl_state.timer)},
|
||||
ToLaunch = get_clients_in_state (available,State#hdl_state.client_states, How),
|
||||
ToStart = get_clients_in_state (ready,State#hdl_state.client_states, How),
|
||||
if
|
||||
length(ToLaunch) + length(ToStart) > 0 ->
|
||||
gen_server:cast(self(),execute),
|
||||
Cmds = [#command{cmd=start,refs=ToStart ++ ToLaunch} | NewState#hdl_state.cmd_queue],
|
||||
cmd_lauch(ToLaunch,NewState#hdl_state{cmd_queue=Cmds});
|
||||
true ->
|
||||
?L_E(?DBGSTR("start command issued with no clients available or ready to start")),
|
||||
NewState
|
||||
end.
|
||||
|
||||
start_simulation (#hdl_state{clients_avail=Cl} = State, all) ->
|
||||
start_simulation(State,Cl);
|
||||
|
||||
start_simulation (State, _Clients) ->
|
||||
{ok, State}.
|
||||
|
||||
|
||||
%--------cmd_launch/2--------------------lauch processes for clients (synchrounsly)
|
||||
|
||||
-spec cmd_lauch (ToLauch,State) -> NewState when
|
||||
ToLauch :: [UUID::string()],
|
||||
State :: #hdl_state{},
|
||||
NewState :: #hdl_state{}.
|
||||
|
||||
cmd_lauch (ToLauch, State) ->
|
||||
%% @TODO: pass in the real manager
|
||||
L = [ {V, ovsdb_ap:start_link(self(),V,self())} || V <- ToLauch],
|
||||
C = maps:merge(State#hdl_state.client_states,maps:from_list([{V,init} || {V, {ok, _}} <- L])),
|
||||
P = maps:from_list([{Pid,Uuid}||{Uuid,Pid}<-[{V,P} || {V, {ok, P}} <- L]]),
|
||||
T = owls_timers:mark("launched",State#hdl_state.timer),
|
||||
State#hdl_state{client_states=C,client_pids=P,timer=T}.
|
||||
|
||||
|
||||
|
||||
|
||||
%--------cmd_start_clients/2-------------starts the simulation of the cliens (in ready state)
|
||||
|
||||
-spec cmd_start_clients (Refs, State) -> NewState when
|
||||
Refs :: [UUID::string()],
|
||||
State :: #hdl_state{},
|
||||
NewState :: #hdl_state{}.
|
||||
|
||||
cmd_start_clients (Refs, #hdl_state{timer=T,cmd_queue=Q}=State) ->
|
||||
{Elapsed, T2} = get_elapsed("start_sim",T),
|
||||
if
|
||||
Elapsed > ?MAX_STARTUP_TIME * length(Refs) ->
|
||||
?L_E(?DBGSTR("Getting ~B clients ready took too long (~s)",[length(Refs),owls_timers:fmt_duration(Elapsed,T)])),
|
||||
?L_I(?DBGSTR("Cancelling simulation start request")),
|
||||
Cmds = lists:reverse([#command{cmd=cancel, refs=Refs}|lists:reverse(Q)]),
|
||||
gen_server:cast(self(),execute),
|
||||
State#hdl_state{cmd_queue=Cmds, timer=T2};
|
||||
true ->
|
||||
Ready = get_clients_in_state (ready,State#hdl_state.client_states,Refs),
|
||||
check_client_startup(Ready,Refs,State#hdl_state{timer=T2})
|
||||
end.
|
||||
|
||||
|
||||
|
||||
|
||||
-spec check_client_startup (Ready, ToStart, State) -> NewState when
|
||||
Ready :: [UUID::string()],
|
||||
ToStart :: [UUID::string()],
|
||||
State :: #hdl_state{},
|
||||
NewState :: #hdl_state{}.
|
||||
|
||||
check_client_startup (_Ready, _ToStart, State) ->
|
||||
State.
|
||||
|
||||
|
||||
|
||||
-spec get_elapsed (Mark,Timer) -> {Elapsed,NewTimer} when
|
||||
Mark :: string(),
|
||||
Timer :: owls_timers:tms(),
|
||||
Elapsed :: integer(),
|
||||
NewTimer :: owls_timers:tms().
|
||||
|
||||
get_elapsed (Mark,T) ->
|
||||
case owls_timers:delta(Mark,default,T) of
|
||||
invalid ->
|
||||
{0,owls_timers:mark("start_sim",T)};
|
||||
Stamp ->
|
||||
{Stamp,T}
|
||||
end.
|
||||
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
new (R) ->
|
||||
Ups = erlang:convert_time_unit(1, second, native),
|
||||
#tms{resolution=R,stamps=[{"start",os:system_time()}],units_per_sec=Ups}.
|
||||
#tms{resolution=R,stamps=[{"*start*",os:system_time()}],units_per_sec=Ups}.
|
||||
|
||||
|
||||
|
||||
@@ -53,28 +53,49 @@ mark (Name,Timer) ->
|
||||
|
||||
|
||||
%--------stamp/2-----------------------get the value of a specific stamp in units of resolution
|
||||
-spec stamp (Name, Timer) -> Stamp when
|
||||
-spec stamp (Name, Timer) -> invalid | Stamp when
|
||||
Name :: string(),
|
||||
Timer :: tms(),
|
||||
Stamp :: integer().
|
||||
|
||||
stamp (Name,Timer) ->
|
||||
{ok, Ts, _} = get_stamp(Name,Timer#tms.stamps),
|
||||
erlang:convert_time_unit(Ts, native, Timer#tms.resolution).
|
||||
case get_stamp(Name,Timer#tms.stamps) of
|
||||
{ok, Ts, _} ->
|
||||
erlang:convert_time_unit(Ts, native, Timer#tms.resolution);
|
||||
_ ->
|
||||
invalid
|
||||
end.
|
||||
|
||||
|
||||
|
||||
%--------delta/3-------------------------gets time difference between two stamps in units of resolution
|
||||
-spec delta (Earlier, Later, Timer) -> Delta when
|
||||
Earlier :: string(), % Earlier must have been added before Later or in other words
|
||||
Later :: string(), % Later must have occured after Earlier in the timeline
|
||||
Earlier :: default | string(), % Earlier must have been added before Later (default means start) or in other words
|
||||
Later :: default |string(), % Later must have occured after Earlier in the timeline (default means now)
|
||||
Timer :: tms(),
|
||||
Delta :: integer().
|
||||
Delta :: invalid | integer().
|
||||
|
||||
delta (default,L,T) ->
|
||||
delta("*start*",L,T);
|
||||
|
||||
delta (E,default,T) ->
|
||||
delta(E,"now",T);
|
||||
|
||||
delta (default,default,T) ->
|
||||
delta("start","now",T);
|
||||
|
||||
delta (E,L,T) ->
|
||||
{ok, T2, R} = get_stamp(L,T#tms.stamps),
|
||||
{ok, T1, _} = get_stamp(E,R),
|
||||
erlang:convert_time_unit(T2 - T1, native, T#tms.resolution).
|
||||
case get_stamp(L,T#tms.stamps) of
|
||||
{ok, T2, R} ->
|
||||
case get_stamp(E,R) of
|
||||
{ok, T1, _} ->
|
||||
erlang:convert_time_unit(T2 - T1, native, T#tms.resolution);
|
||||
_ ->
|
||||
invalid
|
||||
end;
|
||||
_ ->
|
||||
invalid
|
||||
end.
|
||||
|
||||
|
||||
|
||||
@@ -154,6 +175,9 @@ fmt_duration (Delta,Timer) ->
|
||||
get_stamp (_,[]) ->
|
||||
invalid;
|
||||
|
||||
get_stamp ("now",T) ->
|
||||
{ok, os:system_time(), T};
|
||||
|
||||
get_stamp (Stamp,[{Stamp,Value}|T]) ->
|
||||
{ok, Value, T};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user