Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1559191
  • 博文数量: 217
  • 博客积分: 4362
  • 博客等级: 上校
  • 技术积分: 4180
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-20 09:31
文章分类

全部博文(217)

文章存档

2017年(1)

2015年(2)

2014年(2)

2013年(6)

2012年(42)

2011年(119)

2010年(28)

2009年(17)

分类: Python/Ruby

2011-10-22 21:21:58

之前写过“从5900到65535之间随机分配一个数字——erlang实现”,
具体的地址是:http://blog.chinaunix.net/space.php?uid=22566367&do=blog&id=2974384 
不过当时用到了数据库,如果使用数据库的话,这么一来,分配的效率就大打折扣。为此,我进行了改进,使用的gen_fsm模型,结合linux内核的pid位图算法,进行了设计。
有关gen_fsm模型,简单的说就是:
State(S) + Event(E) -> Actions(A),State(S')
表示的就是在S状态时如果有事件E发生,那么执行动作A后把状态调整到S’。

背景介绍:
vnc是一款开源的远程控制软件,它能完整的将窗口界面,通过网络传输到另外一台计算机的屏幕上。在linux下,vnc包括四个命令:vncserver,vncviewer,vncpasswd,vncconnect。在连接一台计算机的时候,需要知道对方计算机的IP和端口号,在我们的项目中,虚拟机的端口号是由master分配的,因此,master就要实现vncport的分配了,vncport的分配范围一般在5900到65535之间。

我们的目标是使用elang实现这个vncport的分配,具体要求如下:
1、每次从5900~65535之间分配一个数字,而且这每次分配的数字不能重复。
2、可以对使用完毕的数字进行回收。
3、如果没有可供分配的数字,那么退出。

咋一看,觉得这个不是很难,但是,如果是这这么大的数据量之间的话,这个不是很易的。
这个分配的思想和进程的pid分配有些相似(可以说是一样的),因此,我们可以借用pid的位图算法进行erlang的算法设计。
这里的最大问题在于,在erlang中,没有我们在c语言中方便使用的那些变量,而在每次分配一个vncport之后,我们是需要记录这个位图的呀,这可怎么办呀?
于是我想到了gen_fsm模型。这里对pid位图不作详细解释了,具体可以参考我的博客:
http://blog.chinaunix.net/space.php?uid=22566367&do=blog&id=2845765

下面开始我们的gen_fsm进行相应的vncport分配。
分析:使用一个数据记录0~65535之间每一个数字的分配情况,如果分配的话就置为1,没有分配的话就是0。这样的话把这个记录转化为二进制的话会是65536个bit,这个数字是很大的,占用8KB的空间,所以如果在涉及到erlang函数传递的话,使用尾部递归比较好。

好了,大体的思想其实就这么简单,关键就是看如何实现了。
我们可以把0~65535看作一个数字仓库,这个仓库是存放这65536个数字的。这个仓库只有一个状态——使用(没有设置结束状态,原因是如果到结束状态的话,直接退出这个程序)。
接下来,就是按照gen_fsm的模型要求,我们进行相应的回调模块的编写。


%% vncport.erl
-module(vncport).
-behaviour(gen_fsm).
-author(sunny).
-export([start/0, get_one/0, free_one/1]).

%% gen_fsm callbacks
-export([init/1,
alloc_ing/2,
handle_event/3,
handle_sync_event/4,
handle_info/3,
terminate/3,
code_change/4]).

%%
%% API functions
%%
start() ->
gen_fsm:start_link({local, ?MODULE}, ?MODULE, [], []).
get_one() ->
gen_fsm:send_event(?MODULE, {alloc}).
free_one(N) ->
gen_fsm:send_event(?MODULE, {free, N}).

%%
%% gen_fsm callbacks
%%
init(_Data) ->
Last = -1,
VncMap = set_bit(set, {0, 5900, 0}),
{ok, alloc_ing, {Last, VncMap}}.

alloc_ing({alloc}, {Last, VncMap}) ->
io:format("alloc_ing + alloc -> alloc_ing + Action1.~n"),
P = alloc_vnc(Last, VncMap, 0),
case P of
{Next, NewMap} ->
{next_state, alloc_ing, {Next, NewMap}};
_ ->
io:format("stop gen_fsm~n"),
{stop, normal, {alloc_over}}
end;
alloc_ing({free, N}, {Last, VncMap}) ->
io:format("alloc_ing + free -> alloc_ing + Action2.~n"),
NewMap = (bnot (1 bsl N)) band VncMap,
{next_state, alloc_ing, {Last, NewMap}}.

handle_event(_A, _B, _C) ->
{next_state, ok, ok}.

handle_sync_event(_A, _B, _C, _D) ->
{reply, ok, ok, ok}.

handle_info(_A, _B, _C) ->
{next_state, ok, ok}.

code_change(_A, _B, _C, _D) ->
{ok, ok, ok}.

terminate(Reason, LastState, StateData) ->
io:format("alloc over,Reason:~p, Last State:~p, State Data:~p~n", [Reason, LastState, StateData]),
ok.

%%
%%  Local functions
%%

%% alloc_vnc(Last, VncMap, 0) | alloc_vnc(Last, VncMap, 1)
%% 0:the vncmap is not allocated over
%% 1:the vncmap is allocated over
alloc_vnc(Last, VncMap, 0) ->
if
Last+1 =:= 65536 ->
Flag = 1,
Current = 0;
true ->
Flag = 0,
Current = Last+1
end,
Temp = (1 bsl Current) band VncMap,
case Temp of
0 ->
io:format("Alloc result is:~p~n", [Current]),
NewMap = (1 bsl Current) bor VncMap,
{Current, NewMap};
_ ->
alloc_vnc(Current, VncMap, Flag)
end;
alloc_vnc(_Last, _VncMap, 1) ->
{vnc_alloc_over}.

%% set_bit(not_set, {InitMap}) | set_bit(set, {From, To, InitMap})
set_bit(not_set, {VncMap}) ->
VncMap;
set_bit(set, {From, From, VncMap}) ->
NewMap = (1 bsl From) bor VncMap,
NewMap;
set_bit(set, {From, To, VncMap}) ->
NewMap = (1 bsl From) bor VncMap,
set_bit(set, {From+1, To, NewMap}).



一个测试结果:

1> c(vncport).
{ok,vncport}
2> vncport:start().
{ok,<0.42.0>}
3> vncport:get_one().
alloc_ing + alloc -> alloc_ing + Action1.
ok
Alloc result is:5901
4> vncport:get_one().
alloc_ing + alloc -> alloc_ing + Action1.
ok
Alloc result is:5902
5> vncport:get_one().
alloc_ing + alloc -> alloc_ing + Action1.
ok
Alloc result is:5903
6> vncport:get_one().
alloc_ing + alloc -> alloc_ing + Action1.
ok
Alloc result is:5904
7>
阅读(1738) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~