Comme je l'ai déjà mentionné, la manière normale de mettre à niveau est de créer les fichiers .appup et .relup appropriés, et de laisser à release_handler le soin de faire ce qui doit être fait. Cependant, vous pouvez exécuter manuellement les étapes concernées, comme décrit ici. Désolé pour la longue réponse.
Le serveur factice suivant gen_server implémente un compteur. L'ancienne version ("0") stocke simplement un entier comme état, tandis que la nouvelle version ("1") stocke {tschak, Int} comme état. Comme je l'ai dit, c'est un exemple factice.
z.erl (ancien):
-module(z).
-version("0").
-export([start_link/0, boing/0]).
-behavior(gen_server).
-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, [], [{debug, [trace]}]).
boing() -> gen_server:call(?MODULE, boom).
init([]) -> {ok, 0}.
handle_call(boom, _From, Num) -> {reply, Num, Num+1};
handle_call(_Call, _From, State) -> {noreply, State}.
handle_cast(_Cast, State) -> {noreply, State}.
handle_info(_Info, State) -> {noreply, State}.
terminate(_Reason, _State) -> ok.
code_change(_OldVsn, State, _Extra) -> {ok, State}.
z.erl (nouveau):
-module(z).
-version("1").
-export([start_link/0, boing/0]).
-behavior(gen_server).
-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, [], [{debug, [trace]}]).
boing() -> gen_server:call(?MODULE, boom).
init([]) -> {ok, {tschak, 0}}.
handle_call(boom, _From, {tschak, Num}) -> {reply, Num, {tschak, Num+1}};
handle_call(_Call, _From, State) -> {noreply, State}.
handle_cast(_Cast, State) -> {noreply, State}.
handle_info(_Info, State) -> {noreply, State}.
terminate(_Reason, _State) -> ok.
code_change("0", Num, _Extra) -> {ok, {tschak, Num}}.
Démarrez le shell et compiler l'ancien code. Notez que gen_server est démarré avec la trace de débogage.
1> c(z).
{ok,z}
2> z:start_link().
{ok,<0.38.0>}
3> z:boing().
*DBG* z got call boom from <0.31.0>
*DBG* z sent 0 to <0.31.0>, new state 1
0
4> z:boing().
*DBG* z got call boom from <0.31.0>
*DBG* z sent 1 to <0.31.0>, new state 2
1
Fonctionne comme prévu: renvoie l'Int et le nouvel état est Int + 1.
Remplacez maintenant z.erl par le nouveau et exécutez les étapes suivantes.
5> compile:file(z).
{ok,z}
6> sys:suspend(z).
ok
7> code:purge(z).
false
8> code:load_file(z).
{module,z}
9> sys:change_code(z,z,"0",[]).
ok
10> sys:resume(z).
ok
Ce que vous venez de faire 5: compilé le nouveau code. 6: suspendu le serveur. 7: purgé du code plus ancien (juste au cas où). 8: chargé le nouveau code. 9: changement de code invoqué dans le processus 'z' pour le module 'z' à partir de la version "0" avec [] passé comme "Extra" à code_change. 10: a repris le serveur.
Maintenant, si vous exécutez d'autres tests, vous pouvez voir, que le serveur travaille avec le nouveau format d'état:
11> z:boing().
*DBG* z got call boom from <0.31.0>
*DBG* z sent 2 to <0.31.0>, new state {tschak,3}
2
12> z:boing().
*DBG* z got call boom from <0.31.0>
*DBG* z sent 3 to <0.31.0>, new state {tschak,4}
3
Dans la version 1 de z.erl, init devrait renvoyer {ok, {tschak, 0}} comme état initial – jmah
Wow, merci, corrigé – Zed
Pourquoi s'embêter avec les comportements OTP? appeler 'code: purge' si la machine virtuelle utilise la nouvelle version une fois qu'elle est chargée? – spockwang