From 831a0359833416ada500628378655cb9ce411b39 Mon Sep 17 00:00:00 2001 From: Geoff Cant Date: Wed, 7 Jul 2010 15:57:21 -0700 Subject: [PATCH] Adding current snippets. --- dbg/trace_process_messages.erl | 57 ++++++++++++++++++ dbg/trace_to_file.erl | 66 +++++++++++++++++++++ dump_source.erl | 11 ++++ exec_as_gen.erl | 31 ++++++++++ fun_rpc.erl | 45 +++++++++++++++ mnesia_schema_symmetry.erl | 24 ++++++++ otp/get_status.erl | 23 ++++++++ pg2.erl | 102 +++++++++++++++++++++++++++++++++ 8 files changed, 359 insertions(+) create mode 100644 dbg/trace_process_messages.erl create mode 100644 dbg/trace_to_file.erl create mode 100644 dump_source.erl create mode 100644 exec_as_gen.erl create mode 100644 fun_rpc.erl create mode 100644 mnesia_schema_symmetry.erl create mode 100644 otp/get_status.erl create mode 100644 pg2.erl diff --git a/dbg/trace_process_messages.erl b/dbg/trace_process_messages.erl new file mode 100644 index 0000000..eb05154 --- /dev/null +++ b/dbg/trace_process_messages.erl @@ -0,0 +1,57 @@ +%% @copyright Geoff Cant 2009, 2010 +%% @author Geoff Cant +%% @version {@vsn}, {@date} {@time} +%% @doc Erlang shell code to trace the messages for one process. +%% @end + +dbg:stop_clear(). +f(GL). +GL=group_leader(). +f(TS). +TS = fun (TimeStamp = {_,_,Mics}) -> + {_,{H, M, Secs}} = calendar:now_to_local_time(TimeStamp), + Micros = Mics div 1000, + Seconds = Secs rem 60 + (Micros / 1000), + [H,M,Seconds]; + (OtherTimestamp) -> + io:format("Help, help, got weird ts: ~p~n", [OtherTimestamp]), + [0,0,0] + end, +dbg:tracer(process, + {fun (Msg, State) -> + case Msg of + {trace, Pid, 'receive', TMsg} -> + [H,M,Seconds] = TS(erlang:now()), + io:format(GL, "~n~p:~p:~p ~p < ~p~n", + [H, M, Seconds, Pid, TMsg]); + {trace, Pid, 'send', TMsg, ToPid} -> + [H,M,Seconds] = TS(erlang:now()), + io:format(GL, "~n~p:~p:~p ~p > ~p: ~p~n", + [H, M, Seconds, Pid, ToPid, TMsg]); + {trace_ts, Pid, 'receive', TMsg, Timestamp} -> + [H,M,Seconds] = TS(Timestamp), + io:format(GL, "~n~p:~p:~pt ~p < ~p~n", + [H, M, Seconds, Pid, TMsg]); + {trace_ts, Pid, 'send', TMsg, ToPid, Timestamp} -> + [H,M,Seconds] = TS(Timestamp), + io:format(GL, "~n~p:~p:~pt ~p > ~p: ~p~n", + [H, M, Seconds, Pid, ToPid, TMsg]); + _Else -> + Timestamp = case element(tuple_size(Msg), Msg) of + {Mg,S,MS} when is_integer(Mg), + is_integer(S), + is_integer(MS) -> + {Mg, S, MS}; + _Other -> erlang:now() + end, + [H,M,Seconds] = TS(Timestamp), + io:format(GL, "~n~p:~p:~p ~p~n", + [H, M, Seconds, Msg]) + + end, + State + end, + undefined}). + +f(Trace). +Trace = fun(Pid) -> dbg:p(Pid, [m]) end. diff --git a/dbg/trace_to_file.erl b/dbg/trace_to_file.erl new file mode 100644 index 0000000..2af3d92 --- /dev/null +++ b/dbg/trace_to_file.erl @@ -0,0 +1,66 @@ +%% @copyright Geoff Cant 2009, 2010 +%% @author Geoff Cant +%% @version {@vsn}, {@date} {@time} +%% @doc Erlang shell code to trace process messages to a wrap log. +%% @end + +dbg:stop_clear(). +f(GL). +GL=group_leader(). +f(TS). +TS = fun (TimeStamp = {_,_,Mics}) -> + {_,{H, M, Secs}} = calendar:now_to_local_time(TimeStamp), + Micros = Mics div 1000, + Seconds = Secs rem 60 + (Micros / 1000), + [H,M,Seconds]; + (OtherTimestamp) -> + io:format("Help, help, got weird ts: ~p~n", [OtherTimestamp]), + [0,0,0] + end. +f(Log). +{ok, Log} = disk_log:open([{name, dbg_log}, + {file, "dbg_trace_log"}, + {format, external}, + {type, wrap}, + {size, {1024*1024, 10}}, + {mode, read_write}]). +dbg:tracer(process, + {fun (Msg, State) -> + S = case Msg of + {trace, Pid, 'receive', TMsg} -> + [H,M,Seconds] = TS(erlang:now()), + io_lib:format("~n~p:~p:~p ~p < ~p~n", + [H, M, Seconds, Pid, TMsg]); + {trace, Pid, 'send', TMsg, ToPid} -> + [H,M,Seconds] = TS(erlang:now()), + io_lib:format("~n~p:~p:~p ~p > ~p: ~p~n", + [H, M, Seconds, Pid, ToPid, TMsg]); + {trace_ts, Pid, 'receive', TMsg, Timestamp} -> + [H,M,Seconds] = TS(Timestamp), + io_lib:format("~n~p:~p:~pt ~p < ~p~n", + [H, M, Seconds, Pid, TMsg]); + {trace_ts, Pid, 'send', TMsg, ToPid, Timestamp} -> + [H,M,Seconds] = TS(Timestamp), + io_lib:format("~n~p:~p:~pt ~p > ~p: ~p~n", + [H, M, Seconds, Pid, ToPid, TMsg]); + _Else -> + Timestamp = case element(tuple_size(Msg), Msg) of + {Mg,Se,MS} when is_integer(Mg), + is_integer(Se), + is_integer(MS) -> + {Mg, Se, MS}; + _Other -> erlang:now() + end, + [H,M,Seconds] = TS(Timestamp), + io_lib:format("~n~p:~p:~p ~p~n", + [H, M, Seconds, Msg]) + + end, + disk_log:balog(Log, iolist_to_binary(S)), + io:format(GL, ".", []), + State + end, + undefined}). + +f(Trace). +Trace = fun(Pid) -> dbg:p(Pid, [m]) end. diff --git a/dump_source.erl b/dump_source.erl new file mode 100644 index 0000000..851af7a --- /dev/null +++ b/dump_source.erl @@ -0,0 +1,11 @@ +%% @copyright Geoff Cant 2009 +%% @author Geoff Cant +%% @version {@vsn}, {@date} {@time} +%% @doc Reprints the source code of a module compiled with debug_info. +%% @end + +PrintSrc = fun (Module) -> + {ok,{_,[{abstract_code,{_,AC}}]}} = + beam_lib:chunks(code:which(Module),[abstract_code]), + io:put_chars(erl_prettypr:format(erl_syntax:form_list(AC))) + end. diff --git a/exec_as_gen.erl b/exec_as_gen.erl new file mode 100644 index 0000000..3008f95 --- /dev/null +++ b/exec_as_gen.erl @@ -0,0 +1,31 @@ +%% @copyright Geoff Cant 2010 +%% @author Geoff Cant +%% @doc Erlang shell code to cause a gen* process to evaluate a fun. +%% +%% @license This code was translated from an ancient tome in the +%% Arkham university library (restricted section, 4th vault). As such, +%% use of this code is restricted to only those who see it as the +%% manifestly evil. Using this code under any circumstances other than in +%% dire need while debugging revokes your right to use, view, posess +%% said code. +%% @end + +f(EvalAs). +EvalAs = fun (Pid, Fun) when is_function(Fun, 0) -> + Ref = make_ref(), + Caller = self(), + F = fun (nostate, {in, {hack, + _Invocation, + Ref}}, ProcState) -> + Caller ! {hack, <<"Ia! Ia! Cthulhu fhtagn">>, Ref, + catch Fun()}, + done + end, + sys:install(Pid, {F,nostate}), + Pid ! {hack, <<"Ph'nglui mglw'nafh " + "Cthulhu R'lyeh wgah'nagl fhtan">>, Ref}, + receive + {hack, TerrifyingResponse, Ref, Result} -> + {TerrifyingResponse, Result} + end + end. diff --git a/fun_rpc.erl b/fun_rpc.erl new file mode 100644 index 0000000..f1009e7 --- /dev/null +++ b/fun_rpc.erl @@ -0,0 +1,45 @@ +%% @copyright Geoff Cant 2009, 2010 +%% @author Geoff Cant +%% @version {@vsn}, {@date} {@time} +%% @doc Erlang shell code to use funs with the rpc module. +%% @end + +f(Multicall). +Multicall = fun (Fun) when is_function(Fun,0) -> + element(1, rpc:multicall(erlang, apply, [ Fun, [] ])) + end. + +f(Ncall). +Ncall = fun (Nodes, Fun) when is_function(Fun,0) -> + element(1, rpc:multicall(Nodes, erlang, apply, [ Fun, [] ])) + end. + +f(NodesCalled). +NodesCalled = fun (Name) -> + [N || N <- nodes(known), + lists:member(Name, string:tokens(atom_to_list(N), "@"))] + end. + +f(Call). +Call = fun (Node, Fun) when is_function(Fun,0) -> + rpc:call(Node, erlang, apply, [ Fun, [] ]) + end. + +f(NamedCall). +NamedCall = fun (Name, Fun) -> + Ncall(NodesCalled(Name), Fun) + end. + +f(ListDiff). +ListDiff = fun (L1, L2) -> + L1S = sets:from_list(L1), + L2S = sets:from_list(L2), + {sets:to_list(sets:subtract(L2S, L1S)), + sets:to_list(sets:subtract(L1S, L2S))} + end. + +f(EvalDiff). +EvalDiff = fun (Node1, Node2, F) -> + ListDiff(Call(Node1, F), + Call(Node2, F)) + end. diff --git a/mnesia_schema_symmetry.erl b/mnesia_schema_symmetry.erl new file mode 100644 index 0000000..28fd13c --- /dev/null +++ b/mnesia_schema_symmetry.erl @@ -0,0 +1,24 @@ +%% @copyright Geoff Cant 2009 +%% @author Geoff Cant +%% @version {@vsn}, {@date} {@time} +%% @doc Alter table copy types to match types on a specific node. +%% @end + +f(Rebalance). +Rebalance = fun (IdealNode, OtherNodes) -> + Tables = rpc:call(IdealNode, mnesia, system_info, [tables]), + TableTypes = [{T, rpc:call(IdealNode, mnesia, table_info, [T, storage_type])} + || T <- Tables], + [{Table, Type, [ case rpc:call(N, mnesia, table_info, [Table, storage_type]) of + Type -> N; + unknown -> + {atomic, ok} = mnesia:add_table_copy(Table, N, Type), + {added, N}; + Other -> + {atomic, ok} = mnesia:change_table_copy_type(Table, N, Type), + {fixed, N} + end + || N <- OtherNodes]} + || {Table, Type} <- TableTypes] + end. + diff --git a/otp/get_status.erl b/otp/get_status.erl new file mode 100644 index 0000000..637e7ce --- /dev/null +++ b/otp/get_status.erl @@ -0,0 +1,23 @@ +%% @copyright Geoff Cant 2009 +%% @author Geoff Cant +%% @version {@vsn}, {@date} {@time} +%% @doc Erlang shell code get the state of an OTP compliant process as +%% a proplist. +%% @end + +f(GetStatus). +GetStatus = fun (Pid) -> + {status,_, + Module, + [[{'$ancestors',Ancestors}, + {'$initial_call',MFA}], + _,_,Debug, + [_, + State, + Mod,infinity]]} = sys:get_status(Pid, timer:seconds(1)), + [{state, State}, + Module, + {ancestors, Ancestors}, + {initial_call, MFA}, + {debug_flags, Debug}] + end. diff --git a/pg2.erl b/pg2.erl new file mode 100644 index 0000000..e6afc33 --- /dev/null +++ b/pg2.erl @@ -0,0 +1,102 @@ +%% @copyright Geoff Cant 2010 +%% @author Geoff Cant +%% @version {@vsn}, {@date} {@time} +%% @doc Erlang shell code to fix pg2 tables. +%% @end + +f(Pg2Groups). +Pg2Groups = fun () -> + ets:select(pg2_table, + ets:fun2ms(fun ({{group, G}}) -> G end)) + end. +f(Pg2GroupMembers). +Pg2GroupMembers = fun (Groups) -> + [{G, lists:usort(ets:select(pg2_table, + ets:fun2ms(fun ({{pid, Pid, Gr}}) + when G =:= Gr -> + Pid + end)))} + || G <- Groups] + end. +f(Pg2Pids). +Pg2Pids = fun () -> + lists:usort(ets:select(pg2_table, + ets:fun2ms(fun ({{ref, R}, Pid}) when is_reference(R) -> Pid end))) + end. +f(Pg2PidGrps). +Pg2PidGrps = fun (Pids) -> + [{P, lists:usort(ets:select(pg2_table, + ets:fun2ms(fun ({{pid, P, Grp}}) -> Grp end)))} + || P <- Pids] + end. +f(Pg2Refs). +Pg2Refs = fun () -> + lists:usort(ets:select(pg2_table, + ets:fun2ms(fun ({{ref, R}, Pid}) when is_reference(R) -> + {Pid, R} + end))) + end. +f(Correct). +Correct = fun () -> + Groups = Pg2Groups(), + GrpMembers = Pg2GroupMembers(Groups), + Pids = Pg2Pids(), + PidGrps = Pg2PidGrps(Pids), + Refs = Pg2Refs(), + + lists:flatten([ [{{group, G}} || G <- Groups], + [{{ref, Ref}, Pid} || {Pid, Ref} <- Refs], + [{{ref, Pid}, Pid, Ref, length(proplists:get_value(Pid, PidGrps))} + || {Pid, Ref} <- Refs], + [ [{{local_member, Grp, Pid}} + || Grp <- Grps] + || {Pid, Grps} <- PidGrps, node() =:= node(Pid)], + [ [[{{member, Grp, Pid}, 1}, + {{pid, Pid, Grp}}] + || Grp <- Grps] + || {Pid, Grps} <- PidGrps] + ]) + end. + +f(Diff). +Diff = fun () -> + Pg2List = ets:tab2list(pg2_table), + Pg2 = sets:from_list(Pg2List), + RightList = Correct(), + Right = sets:from_list(RightList), + [ case lists:keysearch(element(1, I), 1, Pg2List) of + {value, Wrong} -> + Pos = tuple_size(I), + {fixup, element(1,I), {Pos, element(Pos, I)}, element(Pos, Wrong)}; + false -> + {insert, I} + end + || I <- sets:to_list(sets:subtract(Right, Pg2)) + ] + end. + + +f(Diff2). +Diff2 = fun () -> + NewData = Correct(), + Right = sets:from_list(NewData), + Wrong = sets:from_list(ets:tab2list(pg2_table)), + sets:to_list(sets:subtract(Wrong, Right)) + end. + +f(Fixup). +Fixup = fun () -> + NewData = Correct(), + Right = sets:from_list(NewData), + Wrong = sets:from_list(ets:tab2list(pg2_table)), + Deletable = sets:to_list(sets:subtract(Wrong, Right)), + ets:insert(pg2_table, NewData) + end. + +f(ListDiff). +ListDiff = fun (L1, L2) -> + L1S = sets:from_list(L1), + L2S = sets:from_list(L2), + {sets:to_list(sets:subtract(L2, L1)), + sets:to_list(sets:subtract(L1, L2))} + end.