[erlang-questions] When is code_change triggered?

Geoff Cant nem@REDACTED
Fri Jun 27 10:32:59 CEST 2008


Hi all, I puzzled about this one for a while too before stumbling onto
the 'sys' module.

gen_(server|fsm|event) code_change/3 callbacks are invoked by a
corresponding call to sys:change_code/4. The small caveat being that the
process in question must be suspended (it goes into a loop where it only
processes other 'sys' messages).

So to do code upgrade of the only gen_server in a system (Pid) running
the callback module (Mod), you want something like:

Upgrade = fun (Pid, Mod) -> c:l(Mod),
                            sys:suspend(Pid),
                            sys:change_code(Pid, Mod, foo, foo),
                            sys:resume(Pid),
                            code:purge(Mod)
          end.

Extending that to all the Pids running a callback mod is pretty easy
too. The 'foo' dummy arguments are the version number we're upgrading
from and the extra information we need for the upgrade.

Hope this helps,
--Geoff

Paul Mineiro <paul-trapexit@REDACTED> writes:

> We had the same at question here in Hazzard County several months ago.
>
> Hot code loading is a low-level feature built into the runtime; there's
> space for two versions of a module and using module-prefixed calls implies
> a call into the latest version (and a local call implies continue to use
> the same module version).  Before you hot code load a module, you have to
> first nuke the oldest version of the module (and any lingering processes).
> This is the purpose of code:purge/1 and code:soft_purge/1.  You can then
> load a new module using code:load_file/1, code:load_abs/1,
> code:load_binary/3, etc.  After loading the formerly newest version of the
> code will now occupy the oldest version slot.
>
> Code change is a high-level feature which is implemented by convention in
> the OTP libraries.  The gen_X family has an inner loop which responds to
> special "system messages" which cause the process to transfer control to a
> seperate receive loop which only processes special upgrade messages, which
> ultimately cause the code_change/3 callback to be called.  In this manner
> you will not process further normal gen_X messages until the new code has
> been loaded and the code_change handler called.  This sequence is
> orchestrated by release_handler via calls like
> release_handler:install_release/1 and release_handler:upgrade_app/2.
>
> The final piece of information is that calling c(Module) in the shell is
> shorthand for invoking the compiler and then invoking the various code
> methods for loading the new version of the module.  It is *not*, however,
> shorthand for invoking the release_handler; that wouldn't make sense
> for many reasons.  (The shortest path to seeing your code_change/3 handler
> called is, imho, rather long).
>
> Hope that helps,
>
> -- p
>
> p.z. after figuring this out we wrote erlrc:
> http://code.google.com/p/erlrc/
>
> On Thu, 26 Jun 2008, tsuraan wrote:
>
>> When I started playing with gen_server a few years ago, I recalled
>> that doing a c(module) in the REPL would immediately update the code
>> of my running servers.  Now, I cannot get that to happen, so I'm
>> trying to figure out what I'm doing wrong.  My test server is minimal:
>>
>> -module(test).
>> -export([start_link/0, start/0]).
>> -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
>>          terminate/2, code_change/3]).
>>
>> start_link() ->
>>   gen_server:start_link({ local, ?MODULE }, ?MODULE, [], []).
>>
>> start() ->
>>   gen_server:start({ local, ?MODULE }, ?MODULE, [], []).
>>
>> init([]) ->
>>   process_flag(trap_exit, true),
>>   { ok, {}}.
>>
>> handle_call(Msg, From, State) ->
>>   io:format("Unexpected Call ~p From ~p~n", [Msg, From]),
>>   { reply, { error, badcall }, State }.
>>
>> handle_cast(Msg, State) ->
>>   io:format("Unexpected Cast ~p~n", [Msg]),
>>   { noreply, State }.
>>
>> handle_info(Msg, State) ->
>>   io:format("Unexpected Info ~p~n", [Msg]),
>>   { noreply, State }.
>>
>> terminate(Reason, _State) ->
>>   io:format("Terminating ~p for reason ~p~n", [ self(), Reason ]),
>>   ok.
>>
>> code_change(OldVsn, State, Extra) ->
>>   io:format("Upgrading from ~p with extra data ~p~n", [OldVsn, Extra]),
>>   { ok, State }.
>>
>> I can run this with test:start(), but subsequent c(test) never print
>> the message "Upgrading from ...".  Can anyone tell what I'm doing
>> wrong, or is my memory just bad and c(module) has never caused running
>> instances of that module to be upgraded?
>> _______________________________________________
>> erlang-questions mailing list
>> erlang-questions@REDACTED
>> http://www.erlang.org/mailman/listinfo/erlang-questions




More information about the erlang-questions mailing list