(patch install) RE: Distributed applications
Ulf Wiger
etxuwig@REDACTED
Thu Mar 9 16:19:05 CET 2000
> From: Sean Hinde <Sean.Hinde@REDACTED>
> I must admit that I have been struggling a bit with how release handling may
> be used to load small patches into a running system without creating
> complete new release files. I for one would like to see some simplified
> routines for updating small parts of applications while maintaining the
> overall properties of the system. Is this part of your new work? What else
> will be new?
You can get pretty far by just using:
load_patch(Module, SuspendProcs) ->
[sys:suspend(P) || P <- SuspendProcs],
code:load_file(Module),
[sys:resume(P) || P <- SuspendProcs].
A slightly more involved program is attached (patch.erl).
Example:
etxuwig@REDACTED > mv tmp/sasl.beam tmp/sasl.beam.bak
etxuwig@REDACTED > erl -pa tmp/
Erlang (BEAM) emulator version 4.9.1.1
Eshell V4.9.1.1 (abort with ^G)
1>
....
=PROGRESS REPORT==== 9-Mar-2000::16:13:06 ===
application: sasl
started_at: nonode@REDACTED
1> code:which(sasl).
"/home/etxuwig/work/otp/otp-r6b_1/lib/sasl-1.8.3/ebin/sasl.beam"
2> PatchF = "tmp/sasl.beam".
"tmp/sasl.beam"
3> file:rename(PatchF++".bak", PatchF).
ok
4> patch:file(PatchF).
patch:18 - supervised procs: [<0.32.0>,<0.31.0>]
patch:41 - suspend(<0.32.0>)
patch:41 - suspend(<0.31.0>)
patch:45 - resume(<0.32.0>)
patch:45 - resume(<0.31.0>)
ok
5>
Ulf Wiger, Chief Designer AXD 301 <ulf.wiger@REDACTED>
Ericsson Telecom AB tfn: +46 8 719 81 95
Varuvägen 9, Älvsjö mob: +46 70 519 81 95
S-126 25 Stockholm, Sweden fax: +46 8 719 43 44
-------------- next part --------------
%%%
%%% The contents of this file are subject to the Erlang Public License,
%%% Version 1.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.erlang.org/license/EPL1_0.txt
%%%
%%% Software distributed under the License is distributed on an "AS IS"
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%%% the License for the specific language governing rights and limitations
%%% under the License.
%%%
%%% The Original Code is patch_utils-0.1.
%%%
%%% The Initial Developer of the Original Code is Ericsson Telecom
%%% AB. Portions created by Ericsson are Copyright (C), 1998, Ericsson
%%% Telecom AB. All Rights Reserved.
%%%
%%% Contributor(s): ______________________________________.
%%% File: patch.erl
%%% Author: Ulf Wiger <ulf.wiger@REDACTED>
%%%
%%% A small program to illustrate how to apply a patch softly.
%%% The file/1 function does not call any code_change function, but
%%% This would be trivial to add.
-module(patch).
-vsn('0.1').
-date('2000-03-09').
-author('ulf.wiger@REDACTED').
-export([file/1]).
-define(DBG(Fmt, Args), ok=io:format("~p:~p - " ++ Fmt, [?MODULE,?LINE|Args])).
file(FileName) ->
BaseName = filename:basename(FileName),
Module = list_to_atom(filename:basename(BaseName, ".beam")),
Processes = get_supervised_procs(Module),
?DBG("supervised procs: ~w~n",[Processes]),
[suspend(P) || P <- Processes],
code:purge(Module),
case code:load_file(Module) of
{module, Module} ->
[resume(P) || P <- Processes],
Which = code:which(Module),
if Which /= FileName ->
error([{module, Module},
{"code:which returns", Which}]),
{error, loaded_module_not_from_patch_dir};
true ->
ok
end;
{error, LoadReason} ->
error([{mfa, {code, load_file, [Module]}},
{error, LoadReason}]),
[resume(P) || P <- Processes],
{error, module_not_loaded}
end.
suspend(P) ->
?DBG("suspend(~w)~n", [P]),
sys:suspend(P).
resume(P) ->
?DBG("resume(~w)~n", [P]),
sys:resume(P).
error(Info) ->
error_logger:error_report(Info).
%%% ----------------------------------------------------------
%%% # get_supervised_procs
%%% Input: Module:atom()
%%% Output:
%%% Exceptions:
%%% Description: Lists all supervised processes that uses this
%%% module as callback module
%%% ----------------------------------------------------------
%%% io:format is used here to create a prettier and easier to read printout.
%%% All io:format statements should be commented when not debugging this func.
get_supervised_procs(Module) ->
%io:fwrite("~nLook for Module --> ~p~n", [Module]),
lists:foldl(
fun(Application, Procs) ->
%io:fwrite("Application= ~p~n", [Application]),
case application_controller:get_master(Application) of
Pid when pid(Pid) ->
{Root, Mod} = application_master:get_child(Pid),
%io:fwrite("Supervisor= ~p (~p)~n", [Mod, Root]),
get_procs(supervisor:which_children(Root),
Root, Module, Indent = " ") ++
case Module of
Mod ->
[Root | Procs];
Module ->
Procs
end;
_NoPid ->
%io:fwrite(" No PID~n", []),
Procs
end
end,
[],
[Appl || {Appl, _Name, _Vsn} <- application:which_applications()]).
get_procs([{Name, Pid, worker, dynamic} | T], Sup, Module, Indent)
when pid(Pid) ->
%io:fwrite("~s~p (~p); worker; Modules= dynamic~n", [Indent, Name, Pid]),
{ok, Mods} = gen:call(Pid, self(), get_modules),
%io:fwrite("~s ~p~n", [Indent, Mods]),
case lists:member(Module, Mods) of
true ->
[Pid | get_procs(T, Sup, Module, Indent)];
false ->
get_procs(T, Sup, Module, Indent)
end;
get_procs([{Name, Pid, worker, Mods} | T], Sup, Module, Indent)
when pid(Pid), list(Mods) ->
%io:fwrite("~s~p (~p); worker; Modules= ~p~n", [Indent, Name, Pid, Mods]),
case lists:member(Module, Mods) of
true ->
[Pid | get_procs(T, Sup, Module, Indent)];
false ->
get_procs(T, Sup, Module, Indent)
end;
get_procs([{Name, Pid, supervisor, Mods} | T], Sup, Module, Indent)
when pid(Pid) ->
%io:fwrite("~s~p (~p); supervisor; Modules= ~p~n",[Indent, Name, Pid, Mods]),
case lists:member(Module, Mods) of
true ->
[Pid | get_procs(T, Sup, Module, Indent)];
false ->
get_procs(T, Sup, Module, Indent)
end ++ get_procs(supervisor:which_children(Pid), Pid, Module,
Indent ++ " ");
get_procs([H|T], Sup, Module, Indent) ->
%io:fwrite("~sUnknown= ~p~n", [Indent, H]),
get_procs(T, Sup, Module, Indent);
get_procs([], _Sup, _Module, Indent) ->
[].
More information about the erlang-questions
mailing list