Erlang 热补丁原理及升级方案.

前言,  为了支持热补丁, Erlang有一个称为code server的东东, 这个code server基本上就是一个VM 进程维护着一个ETS 表. code server 可以同时在内存中保存单个模块的两个不同的版本,并且每个版本都允许运行.  当调用c(Module) , l(Module)之后, 新版本就自动加载进去了.  r

既然内存中同时存在新旧两个版本, 程序如何区分这两个新旧版本呢,  Erlang通过local 和external 调用来区分, 所有的local调用都进入旧版本, external 调用则调用新版本. 这里的external调用是指全名调用,  Module:Function(Args).

有一点需要注意的是,如果加载了第三个版本,并且进程还运行在第一个版本上,那么该进程就会被VM杀掉, 因为内存中只能保存两个版本,最旧的版本已经不存在了,所以不能有进程继续运行在其中。



 #方案一: 消息触发代码替换


#test_hot_swap.erl (新版本打印信息更新为"This is a upgraded version ~n")

-module(test_hot_swap).
-export([loop/0]).

loop() ->
    receive
        upgrade ->
            code:purge(?MODULE),                                 %%清除旧代码,
            compile:file(?MODULE),                                 %%重新编译
            code:load_file(?MODULE),                            %%重新加载
            ?MODULE:loop();                                             %%必须加上?MODULE才会触发调用新版本,否则仍然调用旧版本, code server维护两个版本,通过这个来区分调用
        run ->
            io:format("This is a old version ~n"),              %%新版本打印信息更新为"This is a upgraded version ~n".
            ?MODULE:loop();
        _ ->
            ?MODULE:loop()
    end.


11> c(test_hot_swap).

{ok,test_hot_swap}
12> 
12> Pid = spawn(test_hot_swap, loop, []).  
<0.84.0>
13> Pid ! run.                                                                                 
This is a old version                                                      %%旧版本打印, 代码还没升级                            
hello
14> 
14> Pid ! upgrade.                                                        %%发消息触发代码升级
upgrade                                                                   
15> Pid ! run.  
This is a upgraded version                                         %%新版本打印, 代码已经完成升级

run



 #方案二:  shell命令手工编译, 加载, 进行代码替换

Eshell V8.1  (abort with ^G)
1> 
1> c(test_hot_swap).
{ok,test_hot_swap}
3> Pid = spawn(test_hot_swap, loop, []).
<0.66.0>
4> Pid ! run.                                                      
This is a old version                                                      %%旧版本打印, 代码还没升级 
run
5> c(test_hot_swap).                    
{ok,test_hot_swap}
6> Pid ! run.
This is a old version                                                     %%旧版本打印, 新代码还没加载
run
7> l(test_hot_swap).
{module,test_hot_swap}
8> Pid ! run.       
This is a upgraded version                                          %%新版本打印, 代码已经完成升级 
run
9> 


#关于必须使用全名调用才能使用新加载的code, 下面贴出了OTP文档的描述, 具体原因还没见到解释的地方.


"To change from old code to current code, a process must make a fully
qualified function call." [0] That is, a module:function() call, rather
than just a function() call.

Also in that document:

"If a third instance of the module is loaded, the code server removes
(purges) the old code and any processes lingering in it is terminated.
Then the third instance becomes 'current' and the previously current
code becomes 'old'."

So, if you reload a module three times (I'm not sure if you have to
actually change the contents of the .beam file between each load), any
processes running that code that haven't yet made a fully qualified
function call will be killed.


#另外一个例子,拷贝自Stackoverflow


z.erl (old):

-module(z).
-version("0").

-export([start_link/0, boing/0]).

-behavior(gen_server).
-export([init/1, handle_call/3, handle_cast/2, handle_info/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值