Use Erlang to handle xml stream
2009-06-03
| 張貼者:
M-OSCAR
写了一个模块,使用xmerl_scan:string函数流式的读取和处理XML流(边读边处理),很适合用于处理XMPP协议的XML流数据,每读取到一个完整的节点(message, presence, iq ....)就会做相应处理~~源码在这里~~
Posted In
erlang,
xml
|
1 意見
|
erlang 与 linked-in driver 间的通信
2009-05-31
| 張貼者:
M-OSCAR
erlang貌似没有直接向port写入整数的方法,通过port传送的全是binary数据,以下代码在erlang中通过port传送一个整数给cpp读取~~
Erlang :
send_integer(Int) ->
Size = erlang:system_info(wordsize) * 8,
Data = <<Int:Size/integer-little>>,
Port ! {self(), {command, Data}},
....
CPP :
static void output(ErlDrvData handle, char* buff, int bufflen){
int *num = (int *)buff
....
Posted In
cpp,
erlang,
port
|
0
意見
|
Erlang Linked in driver
2009-05-24
| 張貼者:
M-OSCAR
Erlang允许其他语言编写的程序以共享库的方式动态连接到Erlang运行时环境里运行,与Erlang Port的方式相似,这种方式称为linked-in driver(内部连接驱动??),是Erlang与其他语言程序交互的最高效的方式,但同时也是最危险的,因为一旦驱动内部出现致命异常,Erlang虚拟机也会崩溃,拖累其他Erlang进程一起挂掉,因此如非必要不推荐使用linked-in driver。
下面是C++编写的driver,具体代码结构解析请参见《Programming Erlang》
g++ test.cpp -I/usr/local/lib/erlang/usr/include/ -fPIC -shared -o test.so
Erlang里调用这个共享库的代码如下:
下面是C++编写的driver,具体代码结构解析请参见《Programming Erlang》
#include然后用如下命令编译成共享库:#include "erl_driver.h" using namespace std; struct data{ ErlDrvPort port; }; //PORT打开时执行 static ErlDrvData start(ErlDrvPort port, char *buff){ data* d = (data*)driver_alloc(sizeof(data)); d->port = port; return (ErlDrvData)d; } //PORT关闭时执行 static void stop(ErlDrvData handle){ driver_free((char*)handle); } //ERLANG发送来信息时执行 static void output(ErlDrvData handle, char *buff, int bufflen){ cout << buff << endl; char rs[] = "ok"; data* d = (data*)handle; driver_output(d->port, rs, 2); } ErlDrvEntry driver_entry = { NULL, //F_PTR init N/A start, //L_PTR PORT打开时执行此函数 stop, //F_PTR PORT关闭时执行此函数 output, //F_PTR ERLANG发来信息时执行 NULL, //F_PTR ready_input, called when input descriptor ready to read NULL, //F_PTR ready_output "test", //DRIVER名,OPEN_PORT函数的参数 NULL, //F_PTR finish, called when unloaded NULL, //F_PTR control, port_command callback NULL, //F_PTR timeout, reserved NULL //F_PTR outputv, reserved }; extern "C"{ DRIVER_INIT(test){ return &driver_entry; } }
g++ test.cpp -I/usr/local/lib/erlang/usr/include/ -fPIC -shared -o test.so
Erlang里调用这个共享库的代码如下:
-module(test).
-compile(export_all).
start() ->
ok = erl_ddll:load_driver(".", "test"),
Port = open_port({spawn, "test"}, [{packet, 2}]),
Port ! {self(), {command, "woo just a test"}},
receive
{Port, {data, Data}} ->
ok = io:format("[~p/~p] ~p\n", [?MODULE, self(), Data])
end,
Port ! {self(), close}.
Posted In
c++,
erlang,
port
|
0
意見
|
[ Erlang + ActionScript ] System Monitor
2009-05-12
| 張貼者:
M-OSCAR
在畢業設計裡加入了一個遠程的服務端負載監測功能,可以遠程查看服務端的當前CPU負載、內存分配等狀況,效果圖如下:
前台用Flex實現,Flex的圖表組件很好用,坐標軸能自動根據數據來調整,不過數據綁定上好像有點問題,數據源更新了圖表卻不會自動刷新~~後台由Erlang提供數據,Erlang的OS_MON模塊可以提供系統CPU負載、內存狀況、硬碟空間使用情況等系統信息~~Erlang通過Socket主動推送JSON格式的數據給客戶端~~有興趣的話可以看看源碼:
客戶端源碼 / 服務端源碼
前台用Flex實現,Flex的圖表組件很好用,坐標軸能自動根據數據來調整,不過數據綁定上好像有點問題,數據源更新了圖表卻不會自動刷新~~後台由Erlang提供數據,Erlang的OS_MON模塊可以提供系統CPU負載、內存狀況、硬碟空間使用情況等系統信息~~Erlang通過Socket主動推送JSON格式的數據給客戶端~~有興趣的話可以看看源碼:
客戶端源碼 / 服務端源碼
Posted In
actionscript,
erlang,
flex,
json
|
0
意見
|
Erlang處理JSON數據~~
2009-05-09
| 張貼者:
M-OSCAR
要用Erlang處理JSON數據,先下載這個東東:
JSON and JSON-RPC for Erlang
下載解壓編譯完之後,輸出的beam文件在ebin目錄下~~
上面下載的包裡有一個rfc4627模塊,提供了JSON數據的encode、decode等方法,還可以將JSON與Erlang Record相互轉換,十分方便快捷,下面看看用法:
JSON and JSON-RPC for Erlang
下載解壓編譯完之後,輸出的beam文件在ebin目錄下~~
上面下載的包裡有一個rfc4627模塊,提供了JSON數據的encode、decode等方法,還可以將JSON與Erlang Record相互轉換,十分方便快捷,下面看看用法:
首先試試將字符串轉換為Json Object:
1> JsonBin = <<"{
1> \"username\":\"Oscar Tong\",
1> \"password\":\"123456\",
1> \"male\":true,
1> \"age\":23
1> }">>.
<<"{\n\"username\":\"Oscar Tong\",\n\"password\":\"123456\",\n\"male\":true,\n\"age\":23\n}">>
2> {ok, {obj, JsonObj}, _Rest} = rfc4627:decode(JsonBin).
{ok,{obj,[{"username",<<"Oscar Tong">>},
{"password",<<"123456">>},
{"male",true},
{"age",23}]},
[]}
再轉換為JSON格式的字符串:
3> rfc4627:encode({obj,JsonObj}).
"{\"username\":\"Oscar Tong\",\"password\":\"123456\",\"male\":true,\"age\":23}"經測試表明,JSON數據的解析與處理速度比XML要快得多,decode和encode僅耗時約40us,比xmerl模塊處理XML需要超過200us相比實在是快多了~~
gen_tcp:controlling_process BADARG error ??
2009-05-07
| 張貼者:
M-OSCAR
今晚嘗試了一下在ERLANG裡將SOCKET鏈接的控制進程轉到另一個節點上去,結果得了一個{error,badarg}錯誤,代碼如下:
....
{ok, Sock} = gen_tcp:accept(Listener),
Pid = spawn(SomeOtherNode, Mod, Fun, Arg),
ok = gen_tcp:controlling_process(Sock, Pid),
....看來想用這種方式來將眾多SOCKET鏈接的壓力分擔到多個節點上是不行的 -____- |||
Erlang的進程信息過濾
2009-05-06
| 張貼者:
M-OSCAR
Erlang進程之間可以通過收發信息來通信,有時可能有一堆信息從各處無序的湧來,你只想處理其中部分信息,而將其他的保留在進程的收件箱裡遲點再管,那該怎麼搞呢?其實很簡單的,看下面代碼:
...
wait_for_reply() ->
receive
{reply, Reply} -> handle(Reply);
_Other -> wait_for_reply()
end.上述函數僅處理匹配{reply, Reply}格式的信息,其他信息因為唯一的匹配模式是一個被忽略的參數_Other,因此不會被處理而繼續留在收件箱裡~~
Erlang : head mismatch ??
2009-05-02
| 張貼者:
M-OSCAR
今天編譯代碼的時候出現了一個奇怪的問題,erlang老提示某個函數有head mismatch錯誤,但我看來看去沒發現什麼不對哇,函數的定義和調用都沒錯~~最後發現原來是因為函數放置了在兩個重名函數之間,即:
出錯前: myfun(params1) -> .... ; myfun(params2) -> .... . 這樣就會提示錯誤了: myfun(params1) -> .... ; new_fun_here(params) -> .... . myfun(params2) -> .... .把新函數放到其他地方就OK了~~粗心之過~~
Reload Erlang Module
2009-04-27
| 張貼者:
M-OSCAR
有时模块代码更新并编译后,需要重新载入才能生效,此时可以在erlang shell里输入如下:
输入help().还可以查看更多的erlang shell命令~~
> l(my_module).
{module, my_module)
输入help().还可以查看更多的erlang shell命令~~
在Erlang啟動時執行一系列操作
2009-04-26
| 張貼者:
M-OSCAR
可以將任意的Erlang代碼放入HOME目錄里的.erlang文件中,當Erlang啟動時,它就會自動執行該文件里的命令,例如:
啟動erlang時,可以看到如下輸出:
如果當前目錄下也有一個.erlang文件,則會優先于HOME目錄下的那個,這樣就可以在不同啟動位置定制不同的行為:
如果你不知道系統的HOME目錄的位置,可以看看Erlang認為的HOME目錄在哪里:
io:format("Erlang is running ....\n").
code:add_patha("."),
code:add_pathz("/home/m/bin").啟動erlang時,可以看到如下輸出:
$ erl
Erlang (BEAM) emulator version 5.6.5 [source] [smp:2] [async-threads:0] [hipe] [kernel-poll:false]
Erlang is running ....
Eshell V5.6.5 (abort with ^G)
1>
如果當前目錄下也有一個.erlang文件,則會優先于HOME目錄下的那個,這樣就可以在不同啟動位置定制不同的行為:
如果你不知道系統的HOME目錄的位置,可以看看Erlang認為的HOME目錄在哪里:
1> init:get_argument(home).
{ok,[["/home/m"]]}
設置Erlang裝載代碼的路徑
| 張貼者:
M-OSCAR
code:get_path() 查看當前的裝載路徑:
code:add_patha(Dir) -> true | {error, bad_directory}
添加新目錄Dir到裝載路徑列表的開頭
code:add_pathz(Dir) -> true | {error, bad_directory}
添加新目錄Dir到裝載路徑列表的尾部
如果怀疑裝載了錯誤的模塊,可以調用函數code:all_loaded()查看所有己加載的模塊列表,或者調用code:clash()
也可以在啟動Erlang的時候指定代碼載入路徑:
> erl -pa Dir1 -pa Dir2 ... -pz DirK1 -pz DirK2
其中-pa將目錄添加到搜索路徑的開頭,而-pz則把目錄加到路徑的末尾~~
code:get_path().
["ebin",".","/usr/local/lib/erlang/lib/kernel-2.12.5/ebin",
"/usr/local/lib/erlang/lib/stdlib-1.15.5/ebin",
"/usr/local/lib/erlang/lib/xmerl-1.1.10/ebin",
"/usr/local/lib/erlang/lib/webtool-0.8.3.2/ebin",
"/usr/local/lib/erlang/lib/typer-0.1.5/ebin",
"/usr/local/lib/erlang/lib/tv-2.1.4.2/ebin",
"/usr/local/lib/erlang/lib/tools-2.6.2/ebin",
"/usr/local/lib/erlang/lib/toolbar-1.3.0.1/ebin",
"/usr/local/lib/erlang/lib/test_server-3.2.4/ebin",
"/usr/local/lib/erlang/lib/syntax_tools-1.5.6/ebin",
"/usr/local/lib/erlang/lib/ssl-3.10/ebin",
"/usr/local/lib/erlang/lib/ssh-1.0.2/ebin",
[...]|...]
code:add_patha(Dir) -> true | {error, bad_directory}
添加新目錄Dir到裝載路徑列表的開頭
code:add_pathz(Dir) -> true | {error, bad_directory}
添加新目錄Dir到裝載路徑列表的尾部
如果怀疑裝載了錯誤的模塊,可以調用函數code:all_loaded()查看所有己加載的模塊列表,或者調用code:clash()
也可以在啟動Erlang的時候指定代碼載入路徑:
> erl -pa Dir1 -pa Dir2 ... -pz DirK1 -pz DirK2
其中-pa將目錄添加到搜索路徑的開頭,而-pz則把目錄加到路徑的末尾~~
Erlang的Makefile~~
| 張貼者:
M-OSCAR
Erlang有一個類似makefile的Emakefile文件,用于編譯項目,當我們在Erlang虛擬机里執行make:all()或輸入shell命令erl -make時,Erlang會搜索當前目錄下的Emakefile文件,并按其設置編譯一個或多個模塊。Emakefile內容格式如下:
Modules即需要編譯的模塊(atom),可以是模塊的文件名,如:mymod;
也可以是其他目錄中的模塊名,如:/somefolder/mymod;
也可以使用通配符來指定一組模塊名,如:my*;
還可以是上述種種的列表,如:['mymod', '/somefolder/mymod', 'my*'];
Options是編譯參數,詳細可參見compile模塊,下面几個比較常用:
debug_info
在輸出的beam文件里包含debug調試信息,諸如Debugger、Xref、Cover的工具需要使用這些信息,BUT可以從這些調試信息里重构出源代碼,用debuf_info_key選項可以加密debug信息以防止泄露源代碼;
{i, "/path/to/include"}
導入文件所在的目錄;
{outdir, "ebin"}
指定編譯輸出路徑。
{Modules, Options}Modules即需要編譯的模塊(atom),可以是模塊的文件名,如:mymod;
也可以是其他目錄中的模塊名,如:/somefolder/mymod;
也可以使用通配符來指定一組模塊名,如:my*;
還可以是上述種種的列表,如:['mymod', '/somefolder/mymod', 'my*'];
Options是編譯參數,詳細可參見compile模塊,下面几個比較常用:
debug_info
在輸出的beam文件里包含debug調試信息,諸如Debugger、Xref、Cover的工具需要使用這些信息,BUT可以從這些調試信息里重构出源代碼,用debuf_info_key選項可以加密debug信息以防止泄露源代碼;
{i, "/path/to/include"}
導入文件所在的目錄;
{outdir, "ebin"}
指定編譯輸出路徑。
[转]Erlang开发建议(杂记版)
2009-04-25
| 張貼者:
M-OSCAR
由 Oscar Tang 透過 Google 閱讀器傳送給您:
經由 Erlang Display - erlang:display(All_About_Erlang) litaocheng 著 (日期為 2009/4/24)
以下是在erlang项目开发中的一些记录,即包含很多通俗易懂的原则,也包含一些似是而非的建议,比较混乱,还没有积累到一个可以分门别类的地步,各位就将就看吧..:)
* 确保没有任何编译警告
* Erlang中String采用list实现,32位系统中,其1个字符用8个字节的空间(4个保存value, 4个保存指针)。因此string速度较慢,空间占用较大
* 在Server中,总是尽力书写尾递归(tail-recursive)的函数
* 使用'++'时,left list会被拷贝,然后添加到right list的头部,因此最好把length较短的list放在左侧
* 避免使用regexp,如果需要正则表达式,请使用re
* timer模块的大部分函数实现,依赖于一个process,如果过多使用timer,会导致这个process负载过大,影响效率。推荐使用erlang:send_after/3及erlang:start_timer/3
* 避免使用list_to_atom/1,因为erlang中atom数量最大为1048576, 且不进行GC控制。因此如果持续性的调用list_to_atom/1,可能很容易达到系统上限,从而导致emulator terminate。请使用list_to_existing_atom/1。
* list内部实现为一个列表,因此length(List), 需要遍历整个list比较耗时
* 对于不同的数据类型,使用不同的size函数:tuple_size/1, byte_size/1, bit_size/1
* 使用binary match来进行binary的分割,而不使用split_binary/2
* 如果两个list都拥有很多数据,那么请不要使用'--',而是将数据转化到ordsets,然后调用ordsets:substract/2.
* 对于binary相关操作可以进行binary优化(bin_opt_info编译选项)代码框架:
* f(<<Pattern1,...,Rest/bits>>,...) ->
... % Rest is not used here
f(Rest,...);
f(<<Pattern2,...,Rest/bits>>,...) ->
... % Rest is not used here
f(Rest,...);
...
f(<<>>, ...) ->
ReturnValue.
* 调用lists:flatten/1可以将list扁平化,这个操作代价很大,比'++'还要昂贵。下面这些时候我们可以避免:
将数据发送给port时
调用list_bo_binary/1和iolist_to_binary前
* 小的函数可以让您方便的找出错误的函数和代码
* 不要在同一行出现相同的符号
20 some_fun() ->
21 L = [{key1, v1}, {key2, [some_record#v21, v22]}],
22 ...
编译时,会提示line 21 '[' 语法错误, 因为21行有多个 '[' ,所以这个bug不能准确定位,你需要花时间去排查代码。
好的做法是:
20 some_fun() ->
21 L = [{key1, v1},
22 {key2, [some_record#v21, v22]}
23 ],
...
这样,编译其会提示你 line 22 '[' 语法错误,你很开就知道是那个地方错了。
* 使用 CTRL + \ 或 init:stop(), 可以退出Erlang, 使用CTRL + G 及 CTRL + C 弹出菜单选项,可以选择是否退出Erlang。
其中CTRL + G可以用来连接其他的shell, CTRL + C可以查看其他一些系统信息
Ctrl + C abort 是野蛮的退出方式
* use "open_port({fd,0,2}, [out])" make erlang program write standard error to unix system
* If you don't run experiments before you start designing a new system, your entire system will be an experiment!
* standard data structure desc:
Module Description
sets sets, i.e. a collection of unique elements.
gb_sets sets, but based on a general balanced data structure
gb_tree a general balanced tree
dict maps, also called associative arrays
ets hash tables and ordered sets (trees)
dets on-disk hash tables
Suggestion:
elments count: 0 - 100 | 100 - 10000 | 10000 -
our select : list | ets | gb_tree
* 通过code:clash/0 检测代码中是否有module冲突现象(sticky)
* epmd -d -d 启动 epmd 可以查看erlang node之间的通讯
* 将正常的逻辑代码和错误处理代码分离,发生错误时,尽管错误。由另一个错误处理模块进行处理
* 类似于操作系统,我们的程序也可以分为kernel 和 user 两层, 对于kernel绝对不能出现错误, 对于user可以出现错误,进行恢复
* process顶层loop涉及的代码及函数,最好在一个module中实现
* process 的register name和module名称一致, 便于寻找代码
* 每个process具有一个单一的角色,比如:supervisor 用来进行错误恢复, work 工作者,可以出现错误, trusted worker 不会出现错误
* 通过函数调用可以实现的功能,就不要使用sever实现(如gen_server, 及类似的loop 实现)
* 给消息加一个tag,在发生错误的时候,可以定位到消息,同时也有利于程序的稳健
* 在消息循环中,对于unknown的消息,请调用lib:flush_receive/0 将其清除,减轻process msg queue的长度
* server中总是书写尾递归的循环
* 尽量使用record, 而不是原始的tuple来表现数据结构, 在使用record时,使用select match:
#person{name = Name, age = Age} = Person
* 对于返回值,最好也添加一个tag,用来说明返回值类型,或者执行成功与否
* 尽可能少的使用catch和try,在erlang程序中,不推荐主动捕获异常。只有当我们的逻辑特别复杂,我们可以使用throw来返回数据,使用catch来获取返回值。
* 当然程序与外界交互,外界数据不可靠时,需要使用catch和try
* 慎重使用process dictory, 当你使用get/1, put/1时,你的应用会具有很大的slide effect。可以通过加入一个新的参数来保存原本需要存储到process dictory中数据
* 如果不想使自己糊涂,请不要使用import
* 使用export时,将功能类似的接口组合在一起,并添加合理的注视,这样你的接口更清晰,别人使用起来更方便
* 不要书写嵌套太深的代码
* 不要书写太长的module
* 不要书写太长的函数
* 每行代码不能太长
* 避免使用 "_" 匿名变量,请为每个变量选择有意义的名称,如够某个变量暂时不使用,请以下划线 "_" 开始
* {error, enfile} enfile error in socket 是以为内linux系统中 ulimit 限制, 在root下修改:ulimit -n 25000
* {error, enotconn} 表示socket已经关闭
* 在erlang开发时,慎重使用macro,因为erlang的single assign的缘故,同时调用某个marco,而macro又定义了某个变量,可能导致badmatch错误。
比如:
-define(ADDLINEINFO1(F),
(
begin
Str1 = lists:concat(["[Mod:", ?MODULE, " Line:", ?LINE, "]"]),
Str1 ++ F
end
)).
-define(WARN(Log, F, D), log4erl:warn(Log, ?ADDLINEINFO(F), D)).
如果连续使用 WARN, 会出现此错误
* erlang中可以定义很多环境变量:
ERL_MAX_ETS_TABLES 设置最大的ets数目 默认1400
ERL_MAX_PORTS erlang最大的port数目 默认1024
* .app文件中的start_phases, 选项既可以用来作为include applications之间的同步启动,也可以用来对单个application进行分布启动。
顺序如下
包含included app:
application:start(prim_app)
=> prim_app_cb:start(normal, [])
=> prim_app_cb:start_phase(init, normal, [])
=> prim_app_cb:start_phase(go, normal, [])
=> incl_app_cb:start_phase(go, normal, [])
ok
无included app:
application:start(prim_app)
=> prim_app_cb:start(normal, [])
=> prim_app_cb:start_phase(init, normal, [])
=> prim_app_cb:start_phase(go, normal, [])
ok
* 任何时候,都要重视函数的返回值,通过match确保您的预期,如果发生错误,那么就大胆的表达出来。
您可以在這裡操作的事項:
- 使用 Google 閱讀器訂閱 Erlang Display - erlang:display(All_About_Erlang)
- 開始使用 Google 閱讀器,輕鬆掌握所有您最愛網站的最新資訊
How to use Erlang SSL Socket
2009-04-15
| 張貼者:
M-OSCAR
首先要用OpenSSL生成私鑰和證書:
然后用Erlang的SSL模塊實現一個ssl socket server和client:
測試一下能否正常運行:
1> c(test).
{ok,test}
2> test:start().
{ok,<0.46.0>}
SSL server socket is ready
3> test:connect().
New ssl client connected
connected
Receive : <<"this is just a test">>
client receive : {ssl,{sslsocket,6,<0.50.0>},<<"this is just a test">>}
client closed
ok
Client {sslsocket,7,<0.49.0>} is disconnected
哈哈,一切正常~~
openssl genrsa -des3 -out privkey.pem 2048
生成一個長2048 bit的私鑰,并用密碼以DES算法加密該私鑰,最后輸出為名為privkey.pem的文件。
如果加密了該私鑰,則每次使用的時候都需要提供密碼,如果不需要密碼保謢,去掉-des3參數就可以了~~
openssl req -new -x509 -key privkey.pem -out cert.pem -days 1020
生成一個自簽的測試用證書,輸出為文件cert.pem,有效期為1020天。
然后用Erlang的SSL模塊實現一個ssl socket server和client:
-module(test).
-export([start/0, connect/0]).
%啟動SSL服務
start() ->
application:start(ssl),
ssl:seed("seed-every-time"),
{ok, spawn(fun() -> start_server() end)}.
%運行SSL SOCKET SERVER
start_server() ->
%創建socket server
{ok, ListenSocket} = ssl:listen(51020, [
binary, {active, true},
{keyfile, "privkey.pem"},
{certfile, "cert.pem"}]),
io:format("SSL socket server is ready\n", []),
%接受客戶端連接
{ok, Sock} = ssl:transport_accept(ListenSocket),
ok = ssl:ssl_accept(Sock),
io:format("New ssl client is connected\n", []),
loop_client(Sock).
%處理來自客戶端的信息
loop_client(Sock) ->
receive
{ssl, Sock, Data} ->
io:format("Receive : ~p\n", [Data]),
ssl:send(Sock, Data),
loop_client(Sock);
{ssl_closed, Sock} -> io:format("Client ~p is discionnected\n", [Sock]);
{ssl_errlr, Sock, Reason} -> io:format("ERROR : ~p\n", [Reason])
end.
%客戶端進行連接
connect() ->
{ok, Sock} = ssl:connect("localhost", 51020, [bianry]),
io:format("connected\n", []),
ssl:send(Sock, "this is just a test"),
receive
Any ->
io:format("client receive : ~p\n", [Any])
end,
ssl:close(Sock),
io:format("client closed\n", []).
測試一下能否正常運行:
1> c(test).
{ok,test}
2> test:start().
{ok,<0.46.0>}
SSL server socket is ready
3> test:connect().
New ssl client connected
connected
Receive : <<"this is just a test">>
client receive : {ssl,{sslsocket,6,<0.50.0>},<<"this is just a test">>}
client closed
ok
Client {sslsocket,7,<0.49.0>} is disconnected
哈哈,一切正常~~
Erlang Term Comparisons
2009-04-13
| 張貼者:
M-OSCAR
Erlang的比较运算符如下:
== 等于
/= 不等于
=< 小于或等于
< 小于
>= 大于或等于
> 大于
=:= 完全等于
=/= 完全不等于
Erlang list item searching
2009-04-12
| 張貼者:
M-OSCAR
使用lists:keysearch函数可以方便的对一个[{key, value}, ....]列表里的指定key进行搜索,函数定义如下:
比如说我们有这样的一个列表:
keysearch(Key, N, TupleList) -> {value, Tuple} | false
Key = term()
N = 1..tuple_size(Tuple)
TupleList = [Tuple]
Tuple = tuple()
比如说我们有这样的一个列表:
> Attributes = [{to, "jojo@verse.com"},
{from, "oscar@verse.com/school"},
{type, "chat"},
{'xml:lang', "en"}].
> lists:keysearch(from, 1, Attributes).
{value, {from, "oscar@verse.com/school"}}
若指定Key不存在则返回false
> lists:keysearch(not_exist, 2, Attributes).
false
Mnesia 事件处理
2009-04-11
| 張貼者:
M-OSCAR
Mnesia会产生两类事件:系统事件(system events)和表事件(table events),用户可创建一个进程来订阅Mnesia所产生的事件,有如下两个相关的函数:
mnesia:subscribe(EventCategory)
当有事件发生时发送一个事件的copy给调用此函数的进程。
mnesia:unsubscribe(EventCategory)
取消事件订阅,不再接收Mnesia产生的事件。
EventCategory可以是system、{table, Tab, simple}或{table, Tab, detailed}。事件会以进程间消息的形式发送给订阅了Mnesia事件的进程,系统事件的格式为{mnesia_system_event, Event},表事件的格式则为{mnesia_table_event, Event}。
System Events
系统事件有如下几种:
{mnesia_up, Node}
Mnesia在节点Node上被启动;
{mnesia_down, Node}
Mnesia在节点Node上停止了运行;
{mnesia_checkpoint_activated, Checkpoint}
一个与本节点相关的checkpoint被激活了;
{mnesia_checkpoint_deactivated, Checkpoint}
一个与本节点相关的checkpoint被激死(:P)了~~
{mnesia_overload, Details}
本节点上的Mnesia负载过重,可能因为对硬碟的读写请求超过了Mnesia的处理能力,如果不做任何处理可能会导致硬碟空间不足;也可能是Mnesia处理事务的速度跟不上事务的请求速度,事务堆栈可能会越来越大,直至耗尽内存或请求速度减缓。对存在异地备份或位于远程节点上的表发起大量的脏操作(dirty updates)时也可能会引发此事件;
{inconsistent|_database, Context, Node}
Mnesia发现数据库可能存在不一致的情况;
{mnesia_fatal, Format, Args, BinaryCore}
Mnesia发生了致命错误,即将在短时间内终止;
{mnesia_info, Format, Args}
调试系统时,Mnesia发现了一些应用程序可能感兴趣的东东;
{mnesia_error, Format, Args}
Mnesia发生了错误;
{mnesia_user, Event}
某应用程序触发了函数mnesia:report_event(Event),可用于调试Mnesia。
Table Events
表事件在数据表被更新时发生,分为simple和detailed两种,simple事件包括:
{write, NewRecord, ActivityId}
有新记录被写入;
{delete_object, OldRecord, ActivityId}
记录OldRecord可能被删除了(可能?),如果表类型为bag,则可能还存在其他与OldRecord主键相同的记录;
{delete, {Tab, Key}, ActivityId}
一个或多个记录可能被删除了(可能??),表里所有主键为Key的记录都已被删除;
detailed事件包括:
{write, Table, NewRecord, [OldRecords], ActivityId}
有新记录被写入;
{delete, Table, What, [OldRecords], ActivityId}
可能有记录被删除(又是可能....),What可能是{Table, Key}或{RecordName, Key, ....}
mnesia:subscribe(EventCategory)
当有事件发生时发送一个事件的copy给调用此函数的进程。
mnesia:unsubscribe(EventCategory)
取消事件订阅,不再接收Mnesia产生的事件。
EventCategory可以是system、{table, Tab, simple}或{table, Tab, detailed}。事件会以进程间消息的形式发送给订阅了Mnesia事件的进程,系统事件的格式为{mnesia_system_event, Event},表事件的格式则为{mnesia_table_event, Event}。
System Events
系统事件有如下几种:
{mnesia_up, Node}
Mnesia在节点Node上被启动;
{mnesia_down, Node}
Mnesia在节点Node上停止了运行;
{mnesia_checkpoint_activated, Checkpoint}
一个与本节点相关的checkpoint被激活了;
{mnesia_checkpoint_deactivated, Checkpoint}
一个与本节点相关的checkpoint被激死(:P)了~~
{mnesia_overload, Details}
本节点上的Mnesia负载过重,可能因为对硬碟的读写请求超过了Mnesia的处理能力,如果不做任何处理可能会导致硬碟空间不足;也可能是Mnesia处理事务的速度跟不上事务的请求速度,事务堆栈可能会越来越大,直至耗尽内存或请求速度减缓。对存在异地备份或位于远程节点上的表发起大量的脏操作(dirty updates)时也可能会引发此事件;
{inconsistent|_database, Context, Node}
Mnesia发现数据库可能存在不一致的情况;
{mnesia_fatal, Format, Args, BinaryCore}
Mnesia发生了致命错误,即将在短时间内终止;
{mnesia_info, Format, Args}
调试系统时,Mnesia发现了一些应用程序可能感兴趣的东东;
{mnesia_error, Format, Args}
Mnesia发生了错误;
{mnesia_user, Event}
某应用程序触发了函数mnesia:report_event(Event),可用于调试Mnesia。
Table Events
表事件在数据表被更新时发生,分为simple和detailed两种,simple事件包括:
{write, NewRecord, ActivityId}
有新记录被写入;
{delete_object, OldRecord, ActivityId}
记录OldRecord可能被删除了(可能?),如果表类型为bag,则可能还存在其他与OldRecord主键相同的记录;
{delete, {Tab, Key}, ActivityId}
一个或多个记录可能被删除了(可能??),表里所有主键为Key的记录都已被删除;
detailed事件包括:
{write, Table, NewRecord, [OldRecords], ActivityId}
有新记录被写入;
{delete, Table, What, [OldRecords], ActivityId}
可能有记录被删除(又是可能....),What可能是{Table, Key}或{RecordName, Key, ....}
Posted In
erlang,
mnesia
|
0
意見
|
用qlc进行数据排序与筛选
| 張貼者:
M-OSCAR
Erlang有一个类似SQL的数据检索机制,叫做QLC(Query Interface to Mnesia, ETS, Dets, etc),可用于对Mnesia、ETS/DETS的数据表进行数据检索,包括常见的按指定域排序(ORDER BY)、按条件筛选(WHERE...)以及限制返回的结果长度(COUNT)。看个简单的例子:
-module(test).
-export([start/0]).
-include_lib("stdlib/include/qlc.hrl").
start() ->
QH1 = qlc:q([{X, Y} || X <- [8,3,6,2], Y <- [b,a,c]]),
%以第一个值作为key进行排序
QH2 = qlc:keysort(1, QH1, [{order, ascending}]),
QC = qlc:cursor(QH2),
%获取前两条记录
qlc:next_answers(QC, 2),
%获取剩余的其他记录
qlc:next_answers(QC, all_remainning).
Posted In
erlang,
mnesia
|
0
意見
|
Supervisor也崩溃了??
| 張貼者:
M-OSCAR
今天测试程序的时候出现了一个怪问题:我用一个supervisor(sup)去监督一个gen_server(test)的工作,test崩溃后被重启了,但随即sup也跟着崩溃了,导致整棵监督树倒了...郁闷,检查错误报告(见下)发现test仅仅被重启了一次,不是因为重启次数过多而使得sup崩溃~~
可见sup系因为收到‘EXIT’信息才崩溃的,大白天谁无缘无故发个‘EXIT’信息出来?Google一番后在Google Groups里找到解答如下:
在erlshell里测试,需要unlink supervisor,这是因为在shell里运行时,进程层次状况如下:
这几个进程是link起来的,如不unlink,在出错时eval_loop会退出重启,导致sup收到{'EXIT', Pid, _}而发生退出。
OK,据此稍为修改监督者的启动函数即可:
=ERROR REPORT==== 11-Apr-2009::01:51:47 ===
** Generic server test terminating
** Last message in was error
** When Server state == []
** Reason for termination ==
** error
gen_server test is started (test重启时所输出的信息)
** exception exit: {error,{gen_server,call,[test,error]}}
in function gen_server:call/2
13>
=ERROR REPORT==== 11-Apr-2009::01:51:47 ===
** Generic server sup terminating
** Last message in was {'EXIT',<0.54.0>,
{{error,{gen_server,call,[test,error]}},
可见sup系因为收到‘EXIT’信息才崩溃的,大白天谁无缘无故发个‘EXIT’信息出来?Google一番后在Google Groups里找到解答如下:
在erlshell里测试,需要unlink supervisor,这是因为在shell里运行时,进程层次状况如下:
shell
eval_loop
sup
这几个进程是link起来的,如不unlink,在出错时eval_loop会退出重启,导致sup收到{'EXIT', Pid, _}而发生退出。
OK,据此稍为修改监督者的启动函数即可:
{ok, Pid} = supervisor:start_link({local, sup}, sup, []),
unlink(Pid).
Posted In
erlang,
otp
|
0
意見
|
动态增删Mnesia数据库节点
2009-04-10
| 張貼者:
M-OSCAR
Mnesia支持动态的增删节点以进行数据转移或备份:
OK,现在可以在新节点上添加表备份、分块等等了,如果不再需要某个节点,可以这样删除节点:
首先启动新节点上面的mnesia
> rpc:call(Node, mnesia, start, []).
添加新节点
> {ok, _} = mnesia:change_config(extra_db_nodes, [Node]).
修改新节点上的schema表的类型
> {atomic, ok} = mnesia:change_table_copy_type(schema, Node, disc_copies).
OK,现在可以在新节点上添加表备份、分块等等了,如果不再需要某个节点,可以这样删除节点:
首先关闭该节点上的mnesia
> rpc:call(Node, mnesia, stop, []).
删掉该节点上的schema表
> {atomic, ok} = mnesia:del_table_copy(schema, Node).
> ok = mnesia:delete_schema([Node]).
Posted In
erlang,
mnesia
|
0
意見
|
訂閱:
文章 (Atom)
