<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>cryolite</title>
    <description></description>
    <link>http://cryolite.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>VIM深度学习之旅（zz）</title>
        <author>cryolite</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cryolite.javaeye.com">cryolite</a>&nbsp;
          链接：<a href="http://cryolite.javaeye.com/blog/200727" style="color:red;">http://cryolite.javaeye.com/blog/200727</a>&nbsp;
          发表时间: 2008年06月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          VIM深度学习之旅<br />（1）<br />http://imtx.cn/archives/122.html<br />（2）<br />http://imtx.cn/archives/124.html
          <br/>
          <span style="color:red;">
            <a href="http://cryolite.javaeye.com/blog/200727#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 06 Jun 2008 00:50:41 +0800</pubDate>
        <link>http://cryolite.javaeye.com/blog/200727</link>
        <guid>http://cryolite.javaeye.com/blog/200727</guid>
      </item>
      <item>
        <title>关于真随机数生成器</title>
        <author>cryolite</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cryolite.javaeye.com">cryolite</a>&nbsp;
          链接：<a href="http://cryolite.javaeye.com/blog/199943" style="color:red;">http://cryolite.javaeye.com/blog/199943</a>&nbsp;
          发表时间: 2008年06月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          有关如何产生随机数的理论有许多，如果要详细地讨论，需要厚厚的一本书的篇幅。<br /><br />有限状态机不能产生真正的随机数的，所以在现在的计算机中并没有一个真正的随机数生成算法，现有的随机数生成算法生产的随机数只不过因为重复的周期比较大，可以做到使产生的数字重复率很低，这样看起来好象是真正的随机数，一般称作叫伪随机数发生器。<br /><br />真正的随机数是使用物理现象产生的：比如掷钱币、骰子、转轮、使用电子元件的噪音、核裂变等等。这样的随机数发生器叫做物理性随机数发生器，它们的缺点是技术要求比较高。真随机数生产效率没有伪随机数高，还有就是"信息熵的信息量如果很有限的话，就不是一定是真的随机数了。"<br /><br />还有人质疑真正的随机数的存在，这是哲学问题，不在此涉及。<br /><br />查了下现有的真随机数生成器，比如PuTTYgen的随机数是让用户移动鼠标达到一定的长度，之后把鼠标的运动轨迹转化为种子；Intel通过电阻和振荡器来生成热噪声作为信息熵资源；Unix/Linux的dev/random和/dev/urandom采用硬件噪音生成随机数；（待补充）<br /><br />基于特定Intel芯片组中random number generator(RNG)单元的真随机数生成器.在Intel 815E芯片组的个人电脑上安装Intel Security Driver(ISD)后,可以通过编程读取寄存器获取RNG中的随机数.<br /><br />有人在BBS上提到：RSA的书上介绍过一种随机数发生器,根据的是劣质内存芯片工作在高温下，其数据是不可预测的，读取这里面的数据，就会得到难以预测的随机数。有采用这种技术制作随机数发生器板卡。<br /><br />关于Linux系统的真随机数生成器在《Linux内核设计与实现》一书的附录B中有详细介绍<br />Linux自1.3.30版就在内核提供了真随机数生成器，至少是理论上能产生真随机数，它利用机器的噪音生成随机数，噪音源包括各种硬件运行时速，用户和计算机交互时速。比如击键的间隔时间、鼠标移动速度、特定中断的时间间隔和块IO请求的响应时间等。<br /><br />此外还有提供真随机数的网站，如：<br />1。 http://random.irb.hr/ 是一个免费为学术和科研机构提供真随机数字服务的网站。全名是Quantum Random Bit Generator Service (QRBGS)，由克罗地亚的计算机科学家开发。其随机性依赖于半导体光子发散量子物理过程中内在的随机性，光子通过光电效应进行检测。这些随机检测到的光子都是相互独立的。<br />可以通过C/C++库、Web Service、Mathmatic/Matlab插件等多种方式访问。将来会提供基于SSL的安全访问。<br />它甚至还有个小小的Erlang的客户端访问程序<br />http://code.google.com/p/qrbgerl/<br /><br /><br />2. 还有http://random.org/，从1998年开始就在Internet上提供真随机数服务了，它用大气噪音生成真随机数<br /><br /><br />有人还提到<br />用Java可以使用java.security.SecureRandom 产生真随机数（待查）；<br />Linux系统有/dev/random,/dev/urandom向用户提供真随机数；<br />Windows系统有CryptGenRandom 函數生成真随机数（待查）<br /><br /><br /><br />参考：<br />http://www.cnblogs.com/hehehu/archive/2005/08/23/221125.html<br />http://bbs.chinaunix.net/viewthread.php?tid=1054170&extra=&page=1
          <br/>
          <span style="color:red;">
            <a href="http://cryolite.javaeye.com/blog/199943#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 04 Jun 2008 00:37:15 +0800</pubDate>
        <link>http://cryolite.javaeye.com/blog/199943</link>
        <guid>http://cryolite.javaeye.com/blog/199943</guid>
      </item>
      <item>
        <title>关于库的深入思考(转载)</title>
        <author>cryolite</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cryolite.javaeye.com">cryolite</a>&nbsp;
          链接：<a href="http://cryolite.javaeye.com/blog/198490" style="color:red;">http://cryolite.javaeye.com/blog/198490</a>&nbsp;
          发表时间: 2008年05月30日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          来自：http://blog.chinaunix.net/u/16651/showart_361289.html<br /><br />    经常见有人提起关于库的种种问题,今天我也终于按捺不住,根据自己的经验,实验,学习中得到的一些,来说说自己的一点看法.<br />    我们都知道库对系统的重要.没了它,系统几乎无法运转,包括LFS整个过程至少是对工具链调整来调整去的过程是以对库的倚赖为核心的.这其中又以动态库为精华.<br />    那先来说简单的静态库.它简单到只是ar打包的目标文件的集合罢了,于是,它的作用也就和目标文件没什么区别了,链接进目标文件,ok,使命完成,至于程序以后的事包括运行则和这个静态库没有关系了.其实我觉的最有说服力的就是例子了,那我们就举最简单的例子.<br /><strong>cat >say.c&lt;&lt;eof</strong><br /><pre name="code" class="java">#include "stdio.h"
void say() {
  printf("Say!");
}
</pre>eof<br /><span style="color: green">cat >test.c &lt;&lt;eof</span><br /><pre name="code" class="java">#include "stdio.h"
void say();
main(){
  say();
}</pre><br />eof<br /><span style="color: green"><br />gcc -c say.c<br />ar -r say.a say.o<br />gcc test.c say.a -o test<br />ldd test<br /></span><br />输出结果让我们看不到任何跟say.a这个我们自己写的静态库的关系.说明程序运行时已经不需要这个静态库了,它已经被ld链接进最终的程序了.<br />那么动态库,我们继续<br /><span style="color: green">gcc -fPIC -shared say.c -o say.so<br />gcc test.c say.so -o test<br />ldd test<br /></span><br />如果不出意外的话,会出现<span style="color: red">say.so => not found</span>.这时的./test是不能运行的.但至少说明程序运行时是需要这个库的.那为什么找不到这个库呢?那就让我们看看系统是怎样寻找这些库的吧.<br />首先是<strong>ld-linux.so.2</strong>这个不能不说,它太重要了,以至于也决定了后面的搜索方式.<br />先是程序内部决定的.<br /><span style="color: green">strings test </span><br />还好我们这个test程序不大,不用过滤输出,好,你看见什么,/lib/ld-linux.so.2,say.so,libc.so.6,对,用到的库!<br />但我们发现不同,有的有路径,有的没有,先不管没有路径的怎么寻找,有路径的肯定是能找到了,那好,我们让say.so也有了路径.<br /><span style="color: green"><br />gcc test.c ./say.so -o test2<br />strings test2<br /></span><br />我们发现原来的输出中原来的say.so已经变成了./say.so.运行一下./test2,可以运行了!好,找到库了,这里用的相对路径,无疑,我们 将say.so移动到非当前文件夹.那test就又不能运行了.这样无疑是把我们用到的库硬编码进了程序里.我不喜欢硬编码,太死板.那不硬编码系统怎么找到我们需要的文件呢.<br />    在程序没有把库地址硬编码经进去的前提下,系统会寻找LD_LIBRARY_PATH环境变量中的地址.<br /><span style="color: green">LD_LIBRARY_PATH=./ ./test2</span><br />如我们所愿,程序正常运行.<br />如果系统在这一步也没发现我们需要的库呢.<br />/etc/ld.so.cache这个由ldconfig生成的文件,记载着在/etc/ld.so.conf文件中指明的所有库路径加上/lib,/usr/lib里的所有库的信息.<br />其实以上这句话只是在大多数情况下是正确的,是否是这个文件由ld-linux.so.2决定.如过你的LFS中的第一遍工具链/tools还在的话,<br /><span style="color: green">strings /tools/lib/ld-linux.so.2|grep etc</span><br />输出很可能是/tools/etc/ld.so.cache.那么它用的哪个文件我们就清楚了吧.<br />可这个路径前面的/tools到底和什么有关呢?首先我们可能会想到与ld-linux所在的位置有关.还好我们有3套glib,感谢LFS,现在我们拿第二遍的工具链下手.假设我们的LFS在/lfsroot<br />strings /lfsroot/lib/ld-linux.so.2<br />很奇怪的是输出竟然是/etc/ld.so.cache!那这到底和什么有关呢,没错就是我们编译时候的--prefix有关.<br />现在再看这个/etc/ld.so.conf,和/lib,/usr/lib这些默认ldconfig路径.也都要加上个这个prefix了.<br /><span style="color: green">strings /tools/sbin/ldconfig|grep etc<br />strings /tools/sbin/ldconfig|grep /lib</span><br />验证一下吧.<br />那要是ld.so.cache里也没有记载这个库的地址怎么办呢.<br />最后在默认路径里找.这个路径一般是/lib,/usr/lib,但也不全是.<br /><span style="color: green">strings /tools/lib/ld-linux.so.2|grep /lib</span><br />还是要加个prefix.<br />现在我们反过来思考,不用程序中硬编码的/lib/ld-linux.so.2做动态加载器了.这也可以?!是的!虽然不一定成功.<br />LD_TRACE_LOADED_OBJECTS=y /tools/lib/ld-linux.so.2 /bin/test<br />LD_TRACE_LOADED_OBJECTS=y /lib/ld-linux.so.2 /bin/test<br />LD_TRACE_LOADED_OBJECTS=y /lfsroot/lib/ld-linux.so.2 /bin/test<br />试着比较结果吧.<br />不出意外的话第一个是在/tools/lib中搜索的库,二三个都是在/lib中的库.原因我想上面已经说清楚了.<br />下面以第二个为例说明问题:<br /><span style="color: green">LD_LIBRARY_PATH=./ /tools/lib/ld-linux.so.2 ./test<br />/tools/sbin/ldconfig ./;/tools/lib/ld-linux.so.2 ./test<br />cp ./say.so /tools/lib/;/tools/lib/ld-linux.so.2 ./test</span><br />三种方法应该都会出现我们想要的结果,这里说明/tools/lib/ld-linux.so.2在这里的含义,是用/tools/lib/ld- linux.so.2这个做动态装载器.不信把这个去掉,后两种方法一定不行.因为以./test自己硬编码进去的/lib/ld-linux.so.2 来说,是不会去管/tools/etc/ld.so.cache,和/tools/lib下的库的.<br /><br />为了说明顺序,我们做如下很危险的实验:<br />ldconfig /lfsroot/lib;<br />ldconfig -p<br />会出现很多内容,但不要试着过滤,因为这时的系统应该很多程序不能运行了.先踏下心来观察.你会发现很多库出现两次/lfsroot/lib,和/lib 而且/lfsroot/lib在前,说明ldconfig先处理参数给出的地址,最后是默认地址.但顺序也不一定,应该还和编译glibc时我们的参数- -enable-kernel有关(我根据种种表现猜测).<br />加上export LD_LIBRARY_PATH=/lib 环境变量在前面,不能运行的程序又能运行了,说明LD_LIBRARY_PATH变量的优先级优于ld.so.cache<br />unset LD_LIBRARY_PATH<br />echo >/etc/ld.so.cache<br />ldconfig -p<br />应该什么都不出现,可大部分程序能运行.说明ld-linux.so.2决定的默认路径起了作用(注意,这里的ldconfig的默认路径没有作用)<br />ldconfig<br />恢复系统正常.<br />如果你原意,可以chroot /lfsroot后,再做类似的操作看有什么不同.<br /><br />懂了原理我们就来应用一下.<br />拿./test2为例.<br />我们把它的库给换了!!!<br />cat >saa.c &lt;&lt;eof<br />#include "stdio.h"<br />say(){<br />printf("I can do something here!!!");<br />}<br />eof<br />gcc -fPIC -shared saa.c -o saa.so<br />sed "s#\./say\.so#./saa.so#" test >test3<br />./test3<br />看看结果吧!<br />很令人惊奇是么,如果是setuid程序的话...其实这个也很难,因为这种程序我们一般是无法写的(给自己搞破坏不算).这也就明白了为什么长久以来对setuid程序的权限始终如此重视----因为太危险了.<br />惊奇过后你可能会想,对于未硬编码库地址的程序,我们直接把LD_LIBRARY_PATH改了不也行么?!指向我们的地址,用我们的库,然后...根本不用改什么文件了,要什么写权限了.<br />呵呵,要真那么容易我们可爱的Linux不也太脆弱了,这恐怕就玩大了,也是你我都不原意见到的.所以,ld-linux.so.2早以作出限止,setsid程序,LD_LIBRARY_PATH变量不起作用.不过文件中的还是有作用的.<br />最后,说一下ld,和ld-linux.so.2的区别,一个编译时用,一个运行时用,ld负责在它的搜索路径里找到要求的库,并查看是否有提供了需要的 符号(如函数等),如果有,记录相关信息到程序中,由ld-linux.so.2在执行时查找到该库并,并根据相关信息进行需要符号的重定位等工作.注意 这两者的搜索库的方式是不同的.<br />LC_ALL=C ld --verbose|grep search -i<br />显示了它默认的查找地址.我们可以做个实验.一般它会有个类似i686-pc-linux-gnu/lib的路径,同时是不在ld-linux.so.2的搜索路径里的.其余的是我们编译是--with-lib-path和LIB_PATH变量指定的.<br />mv ./say.so XXXX/i686-pc-linux-gnu/lib/libsay.so<br />gcc -o test4 -lsay test.c <br />ldd ./test4<br />结果肯定是libsay.so找不到的.<br /><br />好了,写到这吧,想起什么再加,有什么不对的地方也望大家多多提出来^^<br /><br />------------------Skymoon作品,转贴请注明出处作者.
          <br/>
          <span style="color:red;">
            <a href="http://cryolite.javaeye.com/blog/198490#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 30 May 2008 00:13:56 +0800</pubDate>
        <link>http://cryolite.javaeye.com/blog/198490</link>
        <guid>http://cryolite.javaeye.com/blog/198490</guid>
      </item>
      <item>
        <title>Linux动态库搜索路径(转载)</title>
        <author>cryolite</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cryolite.javaeye.com">cryolite</a>&nbsp;
          链接：<a href="http://cryolite.javaeye.com/blog/198487" style="color:red;">http://cryolite.javaeye.com/blog/198487</a>&nbsp;
          发表时间: 2008年05月30日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          原文：http://blog.chinaunix.net/u/16651/showart.php?id=434959<br /><br />众所周知，Linux动态库的默认搜索路径是/lib和/usr/lib。动态库被创建后，一般都复制到这两个目录中。当程序执行时需要某动态库，并且该动态库还未加载到内存中，则系统会自动到这两个默认搜索路径中去查找相应的动态库文件，然后加载该文件到内存中，这样程序就可以使用该动态库中的函数，以及该动态库的其它资源了。在Linux中，动态库的搜索路径除了默认的搜索路径外，还可以通过以下三种方法来指定。 <br /><br />方法一：在配置文件/etc/ld.so.conf中指定动态库搜索路径。 <br /><br />可以通过编辑配置文件/etc/ld.so.conf来指定动态库的搜索路径，该文件中每行为一个动态库搜索路径。每次编辑完该文件后，都必须运行命令ldconfig使修改后的配置生效。我们通过例1来说明该方法。 <br /><br />例1： <br /><br />我们通过以下命令用源程序pos_conf.c（见程序1）来创建动态库 libpos.so，详细创建过程请参考文[1]。<br /><span style="color: green"><br /># gcc -c pos_conf.c<br /># gcc -shared -fPCI -o libpos.so pos_conf.o<br />#<br /></span><br /><pre name="code" class="java">
#include &lt;stdio.h>
void pos() {
    printf("/root/test/conf/lib\n");
}</pre><br />程序1: pos_conf.c<br /><br />接着通过以下命令编译main.c（见程序2）生成目标程序pos。 <br /><span style="color: green"># gcc -o pos main.c -L. -lpos</span><br /><br /><pre name="code" class="java">
void pos();
int main() {
    pos();
    return 0;
}</pre><br />程序2: main.c<br /><br />然后把库文件移动到目录/root/test/conf/lib中。 <br /><span style="color: green"># mkdir -p /root/test/conf/lib<br /># mv libpos.so /root/test/conf/lib<br /></span><br /><br />最后编辑配置文件/etc/ld.so.conf，在该文件中追加一行"/root/test/conf/lib"。 <br /><br />运行程序pos试试。 <br /><span style="color: green"># ./pos<br />./pos: error while loading shared libraries: libpos.so: cannot open shared object file: No such file or directory</span><br /><br /><br />出错了，系统未找到动态库libpos.so。找找原因，原来在编辑完配置文件/etc/ld.so.conf后，没有运行命令ldconfig，所以刚才的修改还未生效。我们运行ldconfig后再试试。<br /><span style="color: green"># ldconfig<br /># ./pos     /root/test/conf/lib <br /></span><br /><br />程序pos运行成功，并且打印出正确结果。 <br /><br /><br />方法二：通过环境变量LD_LIBRARY_PATH指定动态库搜索路径（！）。 <br /><br />通过设定环境变量LD_LIBRARY_PATH也可以指定动态库搜索路径。当通过该环境变量指定多个动态库搜索路径时，路径之间用冒号"："分隔。<br />    不过LD_LIBRARY_PATH的设定作用是全局的，过多的使用可能会影响到其他应用程序的运行，所以多用在调试。（LD_LIBRARY_PATH的缺陷和使用准则，可以参考《Why LD_LIBRARY_PATH is bad》 ）。通常情况下推荐还是使用gcc的-R或-rpath选项来在编译时就指定库的查找路径，并且该库的路径信息保存在可执行文件中，运行时它会直接到该路 径查找库，避免了使用LD_LIBRARY_PATH环境变量查找。<br /><br />下面通过例2来说明本方法。 <br /><br />例2： <br /><br />我们通过以下命令用源程序pos_env.c（见程序3）来创建动态库libpos.so。 <br /><span style="color: green"># gcc -c pos_env.c<br /># gcc -shared -fPCI -o libpos.so pos_env.o<br /></span><br /><br /><pre name="code" class="java">#include &lt;stdio.h>
void pos() {
    printf("/root/test/env/lib\n");
}</pre><br />程序3: pos_env.c<br /><br />测试用的可执行文件pos可以使用例1中的得到的目标程序pos，不需要再次编译。因为pos_conf.c中的函数pos和pos_env.c中的函数pos 函数原型一致，且动态库名相同，这就好比修改动态库pos后重新创建该库一样。这也是使用动态库的优点之一。 <br /><br />然后把动态库libpos.so移动到目录/root/test/conf/lib中。 <br /><span style="color: green"># mkdir -p /root/test/env/lib<br /># mv libpos.so /root/test/env/lib<br /></span><br /><br />我们可以使用export来设置该环境变量，在设置该环境变量后所有的命令中，该环境变量都有效。 <br /><br />例如： <br /><span style="color: green"># export LD_LIBRARY_PATH=/root/test/env/lib<br /></span><br /><br />但本文为了举例方便，使用另一种设置环境变量的方法，既在命令前加环境变量设置，该环境变量只对该命令有效，当该命令执行完成后，该环境变量就无效了。如下述命令：<br /><span style="color: green"># LD_LIBRARY_PATH=/root/test/env/lib ./pos  /root/test/env/lib</span><br /><br />程序pos运行成功，并且打印的结果是"/root/test/env/lib"，正是程序pos_env.c中的函数pos的运行结果。因此程序pos搜索到的动态库是/root/test/env/lib/libpos.so。 <br /><br /><br />方法三：在编译目标代码时指定该程序的动态库搜索路径。 <br /><br />还可以在编译目标代码时指定程序的动态库搜索路径。这是通过gcc 的参数"-Wl,-rpath,"指定（如例3所示）。当指定多个动态库搜索路径时，路径之间用冒号"："分隔。 <br /><br />例3： <br /><br />我们通过以下命令用源程序pos.c（见程序4）来创建动态库libpos.so。 <br /><span style="color: green"># gcc -c pos.c<br /># gcc -shared -fPCI -o libpos.so pos.o</span><br /><br /><pre name="code" class="java">#include &lt;stdio.h>
void pos() {
    printf("./\n");
}</pre><br />程序4: pos.c<br /><br />因为我们需要在编译目标代码时指定可执行文件的动态库搜索路径，所以需要用gcc命令重新编译源程序main.c(见程序2)来生成可执行文件pos。<br /><span style="color: green"># gcc -o pos main.c -L. -lpos -Wl,-rpath,./</span><br /><br /><br />再运行程序pos试试。<br /><span style="color: green"># ./pos   ./</span><br /><br />程序pos运行成功，输出的结果正是pos.c中的函数pos的运行结果。因此程序pos搜索到的动态库是./libpos.so。 <br /><br /><br /><br />以上介绍了三种指定动态库搜索路径的方法，加上默认的动态库搜索路径/lib和/usr/lib，共五种动态库的搜索路径，那么它们搜索的先后顺序是什么呢？ <br /><br />在 介绍上述三种方法时，分别创建了动态库./libpos.so、 /root/test/env/lib/libpos.so和/root/test/conf/lib/libpos.so。我们再用源程序 pos_lib.c（见程序5）来创建动态库/lib/libpos.so，用源程序pos_usrlib.c（见程序6）来创建动态库 /usr/lib/libpos.so。 <br /><br /><pre name="code" class="java">#include &lt;stdio.h>
void pos() {
    printf("/lib\n");
}
</pre>程序5: pos_lib.c<br /><br /><pre name="code" class="java">#include &lt;stdio.h>
void pos() {
    printf("/usr/lib\n");
}
</pre>程序6: pos_usrlib.c<br /><br />这样我们得到五个动态库libpos.so，这些动态库的名字相同，且都包含相同函数原型的公用函数pos。但存储的位置不同和公用函数pos打印的结果不同。每个动态库中的公用函数pos都输出该动态库所存放的位置。这样我们可以通过执行例3中的可执行文件pos得到的结果不同获知其搜索到了 哪个动态库，从而获得第1个动态库搜索顺序，然后删除该动态库，再执行程序pos，获得第2个动态库搜索路径，再删除第2个被搜索到的动态库，如此往复， 将可得到Linux搜索动态库的先后顺序。程序pos执行的输出结果和搜索到的动态库的对应关系如表1所示： 程序pos输出结果	使用的动态库	对应的动态库搜索路径指定方式<br />./	./libpos.so	编译目标代码时指定的动态库搜索路径<br />/root/test/env/lib	/root/test/env/lib/libpos.so	环境变量LD_LIBRARY_PATH指定的动态库搜索路径<br />/root/test/conf/lib	/root/test/conf/lib/libpos.so	配置文件/etc/ld.so.conf中指定的动态库搜索路径<br />/lib	/lib/libpos.so	默认的动态库搜索路径/lib<br />/usr/lib	/usr/lib/libpos.so	默认的动态库搜索路径/usr/lib<br /><br />表1: 程序pos输出结果和动态库的对应关系 <br /><br />创建各个动态库，并放置在相应的目录中。测试环境就准备好了。执行程序pos，并在该命令行中设置环境变量LD_LIBRARY_PATH。 <br /><br /><span style="color: green"># LD_LIBRARY_PATH=/root/test/env/lib ./pos  ./</span><br /><br /><br />根据程序pos的输出结果可知，最先搜索的是编译目标代码时指定的动态库搜索路径。然后我们把动态库./libpos.so删除了，再运行上述命令试试。<br /><br /><span style="color: green"># rm libpos.so<br />rm: remove regular file `libpos.so'? y<br /># LD_LIBRARY_PATH=/root/test/env/lib ./pos /root/test/env/lib</span><br /><br /><br />根据程序pos的输出结果可知，第2个动态库搜索的路径是环境变量LD_LIBRARY_PATH指定的。我们再把/root/test/env/lib/libpos.so删除，运行上述命令。<br /><br /><span style="color: green"># rm /root/test/env/lib/libpos.so<br />rm: remove regular file `/root/test/env/lib/libpos.so'? y<br /># LD_LIBRARY_PATH=/root/test/env/lib ./pos  /root/test/conf/lib<br /></span><br /><br />第3个动态库的搜索路径是配置文件/etc/ld.so.conf指定的路径。删除动态库/root/test/conf/lib/libpos.so后再运行上述命令。<br /><br /><span style="color: green"># rm /root/test/conf/lib/libpos.so<br />rm: remove regular file `/root/test/conf/lib/libpos.so'? y<br /># LD_LIBRARY_PATH=/root/test/env/lib ./pos  /lib<br /></span><br /><br />第4个动态库的搜索路径是默认搜索路径/lib。我们再删除动态库/lib/libpos.so，运行上述命令。<br /><br /><span style="color: green"># rm /lib/libpos.so<br />rm: remove regular file `/lib/libpos.so'? y<br /># LD_LIBRARY_PATH=/root/test/env/lib ./pos  /usr/lib<br /></span><br /><br />最后的动态库搜索路径是默认搜索路径/usr/lib。 <br /><br />综合以上结果可知，动态库的搜索路径搜索的先后顺序是： <br /><br />1.编译目标代码时指定的动态库搜索路径； <br />2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径； <br />3.配置文件/etc/ld.so.conf中指定的动态库搜索路径； <br />4.默认的动态库搜索路径/lib； <br />5.默认的动态库搜索路径/usr/lib。 <br /><br />在上述1、2、3指定动态库搜索路径时，都可指定多个动态库搜索路径，其搜索的先后顺序是按指定路径的先后顺序搜索的。对此本文不再举例说明，有兴趣的读者可以参照本文的方法验证。
          <br/>
          <span style="color:red;">
            <a href="http://cryolite.javaeye.com/blog/198487#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 30 May 2008 00:13:23 +0800</pubDate>
        <link>http://cryolite.javaeye.com/blog/198487</link>
        <guid>http://cryolite.javaeye.com/blog/198487</guid>
      </item>
      <item>
        <title>在所有连接的节点上装载指定的程序模块</title>
        <author>cryolite</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cryolite.javaeye.com">cryolite</a>&nbsp;
          链接：<a href="http://cryolite.javaeye.com/blog/197258" style="color:red;">http://cryolite.javaeye.com/blog/197258</a>&nbsp;
          发表时间: 2008年05月27日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          通过c模块中的nl函数实现，如下<br />c:nl(Module) -> void()<br />Load module on all nodes.<br /><br />通过net_adm:ping(Node)可以实现节点的连接<br /><br />使用nl可以将模块远程装载到其它的节点上，即使那些节点没有此模块的代码<br /><br />io模块中也有一个nl函数，不过该函数表示写一个new line<br />io_lib模块中也有一个nl，含义同上<br /><br />注意：c模块代表命令接口（Command Interface）的意思；该模块的文档称：该模块中的函数仅用于在Erlang shell中使用，使用时模块名前缀可以省去<br /><br />查nl源码如下：<br /><pre name="code" class="java">
nl(Mod) ->
    case code:get_object_code(Mod) of
	{_Module, Bin, Fname} ->
            rpc:eval_everywhere(code,load_binary,[Mod,Fname,Bin]);
	Other ->
	    Other
    end.
</pre><br /><br />rpc:eval_everywhere(code,load_binary,[Mod,Fname,Bin])最终执行<br />eval_everywhere([node()|nodes()], Module, Function, Args)<br />也就是说在[node()|nodes()]的节点列表中的每个节点上执行code:load_binary(Mode, Fname, Bin)<br /><br />code:get_object_code(Module) -> {Module, Binary, Filename} | error<br />此函数在code path中模块Module的二进制目标代码。Binary是包含此模块目标代码的二进制数据对象，如果要在分布式系统中远程装载代码，例如在远程节点Node中装载模块Module可以这样：<br /><pre name="code" class="java">...       
{_Module, Binary, Filename} = code:get_object_code(Module),
rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
...
</pre>
          <br/>
          <span style="color:red;">
            <a href="http://cryolite.javaeye.com/blog/197258#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 27 May 2008 00:19:31 +0800</pubDate>
        <link>http://cryolite.javaeye.com/blog/197258</link>
        <guid>http://cryolite.javaeye.com/blog/197258</guid>
      </item>
      <item>
        <title>Science, Evolution, and Creationism</title>
        <author>cryolite</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cryolite.javaeye.com">cryolite</a>&nbsp;
          链接：<a href="http://cryolite.javaeye.com/blog/194063" style="color:red;">http://cryolite.javaeye.com/blog/194063</a>&nbsp;
          发表时间: 2008年05月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <a href="http://www.nap.edu/catalog.php?record_id=11876#description" target="_blank">http://www.nap.edu/catalog.php?record_id=11876#description</a><br /><br />翻译：<br />http://xys.dxiong.com/xys/ebooks/others/science/misc/evolution1.txt<br />http://xys.dxiong.com/xys/ebooks/others/science/misc/evolution2.txt<br />http://xys.dxiong.com/xys/ebooks/others/science/misc/evolution3.txt<br />http://xys.dxiong.com/xys/ebooks/others/science/misc/evolution4.txt<br />http://xys.dxiong.com/xys/ebooks/others/science/misc/evolution5.txt
          <br/>
          <span style="color:red;">
            <a href="http://cryolite.javaeye.com/blog/194063#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 18 May 2008 13:36:54 +0800</pubDate>
        <link>http://cryolite.javaeye.com/blog/194063</link>
        <guid>http://cryolite.javaeye.com/blog/194063</guid>
      </item>
      <item>
        <title>Erlang的Makefile文件备忘</title>
        <author>cryolite</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cryolite.javaeye.com">cryolite</a>&nbsp;
          链接：<a href="http://cryolite.javaeye.com/blog/192069" style="color:red;">http://cryolite.javaeye.com/blog/192069</a>&nbsp;
          发表时间: 2008年05月12日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Erlang有个类似Makefile的文件Emakefile负责编译erl程序，说明文档在http://www.erlang.org/doc/man/make.html<br /><br />格式是<br />{Modules, Options}.<br /><br />其中Modules是一个atom，或者是一个atom的列表。<br />这些atom<br />可以是一个模块名，如file1；<br />可以是别的目录中的模块名，如../foo/file3；<br />也可以是通过通配符匹配的一系列模块名，如file*；<br />还可以是上述atom的列表，如['file*', '../foo/file3', 'File4']。<br /><br />Options是compiler命令的配置参数，具体参数可以查看文档http://www.erlang.org/doc/man/compile.html<br /><br />一个Emakefile的例子<br />{'src/*', <br />	[debug_info, <br />	{i,"include"},<br />	{outdir,"ebin"}<br />	]}.<br /><br />shell命令<br />erl -make<br />将寻找当前目录下的Emakefile文件，然后根据文件内容build，例如上述例子将当前src目录中的所有模块进行编译，程序中-include 或者 -include_dir指定的相关文件将在include目录中查找，编译好的beam文件输出到ebin目录下。<br /><br />make时将查看输出目录下有没有相关的编译文件，如果没有则进行编译；<br />如果有则检查文件时间，比较后决定是否要进一步编译；<br />如果是最新修改的源文件，则进行编译。<br /><br />ps：<br />在erl中输入命令<br /> make :all().<br />有同样的功效。
          <br/>
          <span style="color:red;">
            <a href="http://cryolite.javaeye.com/blog/192069#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 12 May 2008 00:35:51 +0800</pubDate>
        <link>http://cryolite.javaeye.com/blog/192069</link>
        <guid>http://cryolite.javaeye.com/blog/192069</guid>
      </item>
      <item>
        <title>解决MacBook上的Windows XP安装SP3失败的问题</title>
        <author>cryolite</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cryolite.javaeye.com">cryolite</a>&nbsp;
          链接：<a href="http://cryolite.javaeye.com/blog/190217" style="color:red;">http://cryolite.javaeye.com/blog/190217</a>&nbsp;
          发表时间: 2008年05月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          XP是用Mac OS X Leopard的BootCamp分区装上的<br /><br />错误提示是：<br />在驱动器C:\WINDOWS\$NtServicePackUninstall$上没有足够的空间安装 Service Pack 3 .安装程序至少需要4MB的附加空间。或者您还为卸载存档文件，安装程序需要4M的附加可用空间。请释放更多的空间再试<br /><br />解决办法：<br />打开注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup，新建字符串BootDir，值为Windows XP所在分区盘符，如“C:\”
          <br/>
          <span style="color:red;">
            <a href="http://cryolite.javaeye.com/blog/190217#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 06 May 2008 14:54:42 +0800</pubDate>
        <link>http://cryolite.javaeye.com/blog/190217</link>
        <guid>http://cryolite.javaeye.com/blog/190217</guid>
      </item>
      <item>
        <title>将消息发送到另外一个节点上的进程</title>
        <author>cryolite</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cryolite.javaeye.com">cryolite</a>&nbsp;
          链接：<a href="http://cryolite.javaeye.com/blog/190084" style="color:red;">http://cryolite.javaeye.com/blog/190084</a>&nbsp;
          发表时间: 2008年05月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          如果在节点node1中注册了一个进程<br /><pre name="code" class="java">register(test1, spawn(Fun)).</pre><br /><br />在本节点内给该进程发送消息是<br /><pre name="code" class="java">test1 ! Msg.
</pre><br /><br />在另外一个节点上给该进程发生消息是<br /><pre name="code" class="java">{test1, nodeName@node1} ! Msg.
</pre><br /><br />接着玩个小把戏。<br />在FP中，函数和atom、整数、字符串等一样都是数据，这以为着我们可以像发送atom、字符串等一样将本地函数发送到另外一个节点上，然后执行。<br />首先机器（ip地址是10.0.0.11)启动节点1，执行如下命令：<br /><pre name="code" class="java">erl -name node1@10.0.0.11 -setcookie abc
</pre><br />然后在erl中定义接收消息的函数：<br /><pre name="code" class="java">
(node1@10.0.0.11)1> F1 = fun()->  
(node1@10.0.0.11)1>   receive                                                   
(node1@10.0.0.11)1>     Fun-> io:format("I received !!!~n"), Fun()
(node1@10.0.0.11)1>   end
(node1@10.0.0.11)1> end.
</pre><br />注意该函数只接收一条消息<br /><br />创建并登记进程：<br /><pre name="code" class="java">register(test1, spawn(fun() -> F1() end)). 
</pre><br />在另外一台机器（ip地址是10.0.0.12）上启动节点2：<br /><pre name="code" class="java">erl -name node2@10.0.0.12 -setcookie abc
</pre><br />然后定义作为消息发送出去的函数：<br /><pre name="code" class="java">(node2@10.0.0.12)1> F2  = fun() -> io:format("HELLO WORLD~n") end.
</pre><br />将该函数发送到节点1上：<br /><pre name="code" class="java">(node2@10.0.0.12)2> {test1, 'node1@10.0.0.11'} ! F2.
</pre><br />可以在节点1看到收到F2并执行的结果。<br />这样任何一个函数都可以发布到任何网络中的一个节点上执行，并不一定非得在定义它的地方执行。<br /><br /><br />运行时更新代码的问题：传统的系统比较难以在运行时更新代码，一般都是停机，替换代码，重新启动完成系统的升级。Erlang号称提供热切换的特性，也就是说在系统不停机时就能更新部分代码，很神奇的样子。热切换机制也与FP函数的这种特点有关，函数与普通对象没有本质的区别，那么既然运行时修改对象不算什么问题，动态更新函数也就是理所当然的了。<br />由于Erlang变量的不可变性，但是函数可以参数的形式实现动态变化：<br />loop(Fun) -><br />  receive <br />    {execute, Arg} -><br />      Fun(Arg),<br />      loop(Fun);<br />    {update_fun, New_Fun} -><br />      loop(New_Fun)<br />  end.<br /><br />当某线程运行此段代码后，该线程就会一直接收别的线程发消息给它，如果收到{execute, Arg}消息，将执行Fun函数，完成相关业务处理；处理完后线程继续等待接收新的消息；<br />如果要不停机更新代码，就给该进程发送{update_fun, NewFun}消息，NewFun即为要更新的函数。
          <br/>
          <span style="color:red;">
            <a href="http://cryolite.javaeye.com/blog/190084#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 06 May 2008 11:32:27 +0800</pubDate>
        <link>http://cryolite.javaeye.com/blog/190084</link>
        <guid>http://cryolite.javaeye.com/blog/190084</guid>
      </item>
      <item>
        <title>Mnesia──一个用于电信应用系统的健壮的分布式DBMS</title>
        <author>cryolite</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cryolite.javaeye.com">cryolite</a>&nbsp;
          链接：<a href="http://cryolite.javaeye.com/blog/186886" style="color:red;">http://cryolite.javaeye.com/blog/186886</a>&nbsp;
          发表时间: 2008年04月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h1 id="r23e">Mnesia──一个用于电信应用系统的健壮的分布式DBMS</h1>
<p>原文：http://www.erlang.se/publications/mnesia_overview.pdf</p>
<div id="yn1t">
<h2 id="gsql">摘要</h2>
<div id="d2.0">&nbsp;&nbsp;
&nbsp;Mnesia
DBMS和拥有数据的应用系统运行在同一地址空间，然而应用系统不能销毁数据库的内容。Mnesia同时提供了快速存取的特性和很好的容错性，通常这两个
需求是相互矛盾的。Mnesia的实现是基于Erlang编程语言的特性，Mnesia也内嵌到Erlang中了。</div>
<div id="d2.0"><br id="tn-m" />
</div>
<h2 id="zful">1. 介绍</h2>
<div id="d2.0">&nbsp;&nbsp;
&nbsp;电信系统中数据的管理在许多方面（但也不是全部）与传统的商业DBMS（Database Manager
System）相同。尤其是对许多&ldquo;不停歇系统（nonstop
system）&rdquo;来说，在容错性上有非常高的要求，再加上需要有一个和应用系统运行在同一地址空间内的需求，导致我们设计了一个全新的DBMS。本文描述
了这个新的被称为Mnesia的DBMS的动机和相关设计。Mnesia由Erlang语言实现，与Erlang的关系非常紧密，Erlang为实现容错
性的电信系统提供了必要的功能。Mnesia是一个为了实现工业级电信应用系统而用Erlang编写的多用户的分布式DBMS，Erlang也是操作
Mnesia的理想语言。Mnesia试图涵盖所有的关于电信系统数据管理方面的问题，它有许多通常中传统数据库中不常见的特性。</div>
<div id="d2.0">&nbsp;&nbsp;&nbsp;&nbsp;电信应用中有许多不同于传统DBMS的特性需求。我们现在的用Erlang语言实现的应用系统需要有许多特性，这些特性是传统DBMS不能满足的，Mnesia根据如下需求设计：</div>
<div id="d2.0"><ol id="true">
<li id="wjok">快速实时的键/值查找；</li>
<li id="xawf">复杂的非实时性查询，主要是为了操作和维护；</li>
<li id="jbxj">由于分布式的应用导致的分布式的数据；</li>
<li id="wbug">高容错性；</li>
<li id="a.kb">动态重配置（Dynamic reconfiguration）；</li>
<li id="w-n:">复杂的对象。</li>
</ol>
</div>
<div id="d2.0">&nbsp;&nbsp;
&nbsp;使Mnesia不同于其它DBMS的是，它是为电信应用系统中的数据管理问题设计的。Mnesia还将传统数据库中的许多概念与电信应用中的数据管理上
的概念结合在一起，前者包括事务和查询，后者包括极快速实时操作、容错性的可配置度（指复制）configurable degree of
fault tolerance（by means of
replication）、不停机或挂机而重新配置系统的能力。Mnesia与Erlang语言的紧耦合也使它看上去很有意思，它使得Erlang语言变
成了一门数据库编程语言。这带来很多好处，最主要的是通常由于DBMS中的数据格式与编程语言中的数据格式的不同带来的阻抗不匹配问题现在不存在了。</div>
<div id="d2.0">&nbsp;&nbsp; &nbsp;当前，Mnesia在Erisson中几乎所有的基于Erlang的工程中得到应用，从小规模的原型系统到大型交换机项目。</div>
<div id="d2.0">&nbsp;&nbsp; &nbsp;本文剩下部分如下组织：第2节是DBMS的简要概述，第3节列出了典型的DMBS功能，讨论了电信方面的功能以及Mnesia是如何提供这些功能的，第4节包括一些性能方面的测量，最后第5节总结。<br id="wgfa" />
<br id="d:gq" />
</div>
<h2 id="o4vy">2. Mnesia简要概述</h2>
<div id="d2.0">&nbsp;&nbsp;
&nbsp;Mnesia即是编程语言Erlang的扩展，也是一个Erlang应用程序。DBMS的组件，例如锁管理器、事务管理器、复制管理器、日志、主存储和
二级存储（primary and secondary memory
storage）、备份系统等等，这些都是由Erlang程序所实现的。然而，查询语言则是Erlang语法的一部分。Mnesia的数据模型是一种混合
类型：数据由record表组织，record表类似关系数据库中的关系（relation），但是record的属性（包括主键key）可以是任意复杂
的组合数据结构（如树、函数、闭包、代码等等）。这样，Mnesia也可以看做是所谓的对象关系DBMS。例如，我们定义人的record：</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">-record(person, {name,&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;%% atomic，唯一性主键</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;data, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;%% 未指定的组合结构数据</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; married_to, &nbsp; &nbsp; &nbsp;%% 伴侣的名字，可以不指定（undefined）</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;children}). &nbsp; &nbsp; &nbsp;%% 孩子</span>
</div>
<div id="d2.0">有了这个定义，我们就可以用接下来的Erlang语法创建一个人的记录：</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">X = #person{name = klacke,</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;data = {male, 36, 971191},</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; married_to = eva,</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;children = [marten, maja, klara]}.</span>
</div>
<div id="d2.0">将
变量X绑定到这个人的record。data域绑定到一个tuple：{male,36,971191}。这是一个复杂对象的例子，Mnesia对属性的
复杂性没有任何限制，我们甚至可以将函数对象作为属性值。变量X只是一个Erlang 项式（term），通过如下语句可以把它插入到数据库中：</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">mnesia:write(X)</span>
</div>
<div id="d2.0">一系列Mnesia操作可以组织起来作为一个原子性的事务一起执行。为了让Mnesia执行一个事务，程序员必须首先构建一个函数对象，然后将其递交给Mnesia系统。我们通过一个例子解释，假设我们想写一个Erlang函数<span style="font-family: Courier New;">divorce(Name)</span>
，它接受一个人名，从数据库中查找这个人，将这个人和这个人的配偶的<span style="font-family: Courier New;">married_to</span>
域设为undefined值：</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">divorce(Name) -&gt;</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;F = fun() -&gt;</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;case mnesia:read(Name) of</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;[] -&gt;</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;mnesia:abort(no_such_person);</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Pers -&gt;</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Partner = mnesia:read(Pers#person.married_to),</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;mnesia:write(Pers#person{married_to = undefined}),</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;mnesia:write(Partner#person{married_to = undefined})</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;end</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;end,</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;mnesia:transaction(F).</span>
</div>
<div id="d2.0"><span style="font-family: Courier New;">divorce/1</span>
函数由两条语句组成，第一条语句是 F = ...，用于创建一个函数对象，它什么都没执行，只是构建了一个匿名函数。第二条语句将这个函数交给Mnesia系统，它负责在一个事务的上行文中执行此函数，相当于传统的事务语法。</div>
<div id="d2.0">&nbsp;&nbsp; &nbsp;实际上函数F第一次执行一个读操作，用于查找给定名字Name的人，然后它执行第二个读操作以找到前者的配偶，最后执行两个写操作，将两条修改后的新记录（<span style="font-family: Courier New;">married_to</span>
都已设为undefined）插入到数据库中，数据库中的旧值将新值被覆盖。函数<span style="font-family: Courier New;">divorce/1</span>
将事务的值作为返回值，事务的值要么是<span style="font-family: Courier New;">{aborted, Reason}</span>
，要么是<span style="font-family: Courier New;">{atomic, Value}</span>
，这取决于事务是放弃了还是成功执行了。</div>
<div id="d2.0">&nbsp;&nbsp; &nbsp;Mnesia中的查询由表理解（list comprehension）语法表达[15]。一个用于查找所有生了超过X个孩子的人的名字的查询如下所示：</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">query [P.name || P &lt; table(person),</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;length(P.children) &gt; X]</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">end</span>
</div>
<div id="d2.0">这被读作：组建一个P.name的列表，这里的P从person表中得到，而且每个P的children列表的长度超过X。将用户自定义的谓词混合中一个查询中也是可行而且自然的。例如有如下谓词</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">maturep({Sex, Age, Phone}) when Age &gt; 30 -&gt;</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;true;</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">maturep({Sex, Age, Phone}) -&gt;</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;false;</span>
</div>
<div id="d2.0">查询可以是：</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">query [P.name || P &lt;- table(person),</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;maturep(P.data),</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;length(P.children) &gt; X]</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">end</span>
</div>
<div id="d2.0">这个查询将提取出所有有超过X个小孩并且data域的第二个元素值大于30的人的名字。也可以用类似Datalog这样的嵌入式逻辑语言[16]的方式定义规则：</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">oldies(Name) -&gt;</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;P &lt;- table(person),</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;maturep(P.data),</span>
</div>
<div id="d2.0"><span class="Apple-style-span" style="font-family: 'Courier New';">&nbsp;&nbsp; &nbsp;Name = P.name.</span>
</div>
<div id="d2.0">这
个规则用作是一个虚拟表，应用程序可以存取虚拟表oldies。虚拟的oldies表包含一个实际的person表的子集。这类似于关系数据库中视图
（view）的概念，但是功能更为强大。一个优化的查询编译器负责编译查询语句，该编译器已经集成到Erlang编译器中了。</div>
<div id="d2.0">&nbsp;&nbsp;&nbsp;&nbsp;数
据库表可以被复制到多个站点（或者节点）上，节点网络可以是异构网络。复制（Replication）是我们用于构建容错性系统的机制。对数据库表的访问
是位置透明的（location transparent)，也就是说，程序不需要知道数据的分布位置。一个数据库表有一个唯一的名字和一些相关的属性：</div>
<div id="d2.0">
<ul id="true">
<li id="vsot"><span class="Apple-style-span" style="font-family: 'Courier New';">type</span>
 控制数据库表是set的还是bag的，set中key值是唯一的，而bag可以让多个对象有相同的key值；</li>
<li id="a7v:"><span class="Apple-style-span" style="font-family: 'Courier New';">ram_copies</span>
 数据库表的复制品（replicas）所在的Mnesia节点仅将表保持在内存中；</li>
<li id="fl1e"><span class="Apple-style-span" style="font-family: 'Courier New';">disc_copies</span>
&nbsp;数据库表的复制品（replicas）所在的Mnesia节点将表保持在内存中，但对表的所有更新操作都记录到磁盘中；</li>
<li id="n15_"><span class="Apple-style-span" style="font-family: 'Courier New';">disc_only_copies</span>
&nbsp;数据库表的复制品（replicas）所在的Mnesia节点仅将表保持在磁盘上。显然这些复制品要比中内存中的复制品存取速度慢；</li>
<li id="eeba"><span class="Apple-style-span" style="font-family: 'Courier New';">index</span>
 用于指定record中哪些属性需要做索引。所有的record总是自动为主键做索引；</li>
<li id="j433"><span class="Apple-style-span" style="font-family: 'Courier New';">snmp</span>
&nbsp;是否需要通过SNMP协议操作。</li>
</ul>
</div>
<div id="d2.0">所
有表的描述信息都保持中数据库schema，Mnesia提供了许多函数用于动态的操作schema。表可以创建、移动、复制、改变、销毁......此
外，所有的系统活动都在背后执行，这就允许应用系统自己正在被修改时也可用（thus allows the application to
utilize the system as usual although the system itself is being
changed)。</div>
<div id="d2.0">&nbsp;&nbsp;&nbsp;&nbsp;可以通过备份创建整个分布式系统，这些备份将作为fallback安
装。（backups can be constructed of the entire distributed system, this
backups can be installed as
fallbacks.）这意味着系统如果崩溃了，数据库可以很快的从fallback自动重建。</div>
<div id="d2.0"><br id="v.j0" />
</div>
<h2 id="tvwq">3. DBMS特性讨论</h2>
<div id="d2.0">&nbsp;&nbsp; &nbsp;不同的DBMS有着不同的特性特点。本节列出了不同的DBMS特点，并讨论了一些在我们电信系统中重要且必要的特性。</div>
<h3 id="qpwc">3.1 复杂值</h3>
<div id="d2.0">&nbsp;&nbsp;
&nbsp;在DBMS中操作复杂值（如list、set、tree等）的能力可能是电信DBMS最重要的特性了。用于处理通信量（traffic）的电信应用系统
通常被到达系统的外部刺激(stimuli)所驱动，当这样一个刺激（stimuli）以PDU（Protocol Data
Unit）的形式到达电信系统时，PDU被解码，接着进行一系列操作，当PDU被解码后，系统通常提取出一些数据对象，可能是一个subscriber记
录，该记录用于决定哪些操作应该执行以响应收到的PDU。许多电信系统中，一个最重要的数据管理系统特性就是查找必须非常高效。DBMS允许数据以某种方
式组织和存储，这种方式使得一个简单的查找操作就能访问到数据。这个要求也使得为电信系统建模更加困难，以第三范式（甚至第一范式）组织电信数据通常不太
可行。</div>
<div id="d2.0">&nbsp;&nbsp; &nbsp;这也是为什么电信领域关注面向对象数据库系统的原因之一，相对于关系数据库，面向对象数据库允许数据以更灵活的方式组织。而Mnesia允许用户在数据库中使用任意复杂的对象作为属性值（attribute value），甚至是关键值（key value）。</div>
<h3 id="wqu5">3.2 数据格式和地址空间</h3>
<div id="d2.0">&nbsp;&nbsp;
&nbsp;许多数据库使用一种内部的、语言独立的格式存储数据。由于前面提到的快速查找需求，这对于电信系统来说是非常不幸的。许多OODBMS（面向对象
DBMS）与一门程序语言（例如C++或Smalltalk）紧密耦合，这种在数据库中操作常规程序语言对象的能力使得阻抗不匹配消失了。这不仅使得
DBMS的操作更加容易，而且还提供了实现高效查找的机会，因为依靠使用的程序语言，一个查找操作能立即返回一个对象的指针。例如，如果我们想通过数据库
表实现一个路由表（routing
table），将路由数据从外部DBMS格式到我们需要的格式之间进行来回的转换是不现实的。此外，执行任何上下文切换和在另一个地址空间另一个进程中为
每个packet搜索相关数据也是不现实的（it is not realistic to perform any context
switches and search the relevant data for each packet in a process
executing in another address
sapce)。这就排除了所有不能直接链接到应用系统地址空间的DBMS，以及所有虽然链接到应用系统地址空间但是使用一种语言独立的格式存储数据的
DBMS。</div>
<div id="d2.0">&nbsp;&nbsp;
&nbsp;让应用系统与DBMS运行在同一地址空间的最大缺点是如果应用系统由于程序的错误崩溃了，DBMS可能来不及在终结之前将重要数据存储到二级存储器
（secondary
storage）中。这意味着整个DBMS必须在再次启动之前进行恢复，而这通常都是一个非常耗时的过程，而在电信系统中当机时间必须尽可能短。应用系统
以及DBMS都是由Erlang实现的DBMS能避免这个问题。一个Erlang应用系统不能以影响DBMS的方式崩溃。应用系统和DBMS运行在同一地
址空间内，但Erlang保证一个应用系统的崩溃不会影响到另一个应用系统。Erlang进程有运行在同一地址空间的优点，但是这些进程不可能显式的读写
其它进程的内存。</div>
<h3 id="l4nd">3.3 容错性</h3>
<div id="d2.0">&nbsp;&nbsp;
&nbsp;许多电信应用系统都是不可间断系统（nonstop
system），即使在发生硬件或软件错误的情况下系统仍然提供持续的访问。这个要求不仅是对DBMS的，也是对电信应用系统的。这影响到了整个应用系统
的设计，而DBMS必须为应用系统设计者提供一种能很好的设计容错系统的机制。Mnesia提供的这种机制就是将一张数据库表复制到多个节点上。一张
Mnesia表的所有复制品（replicas）都是等同的，在DBMS这一级别上没有主表和备用表的概念。如果一张表被复制了，一个事务中的所有的写操
作都会应用到所有的这些复制品（replicas）上，如果某些复制品（replicas）不可访问，写操作也能成功执行，而那些漏掉的复制品
（replicas）将在它们恢复后更新。这一机制使得设计一个不间断系统成为可能，该系统通过在不同地理区域上分布的系统之间的协作实现持续运行。许多
其它的高容错性系统（例如ClustRa[11]）也通过这种复制(replication)提供容错能力，然而它们没有和应用系统在同一地址空间内执行
的能力。</div>
<div id="d2.0">&nbsp;&nbsp;
&nbsp;Mnesia能从灾难中部分的恢复，所有写入磁盘的对象能安全的与垃圾区分开来（objects are coded in such away
that it is possible to safely disinguish data from
garbage)。这使得扫描一个损害了的或者崩溃了的磁盘或文件系统，然后从崩溃了的磁盘中重新获取数据成为可能。</div>
<h3 id="si5e">3.4 分布（distribution）与位置透明</h3>
<div id="d2.0">&nbsp;&nbsp;
&nbsp;Mnesia是一个真正的分布式DBMS，数据能被复制和远程存储，在这样的环境中，DBMS程序员无需了解数据的位置就能对其访问是非常重要的。也就
是说，数据的位置透明是非常重要的。另一方面，既然远程的数据访问非常昂贵，也需要应用系统程序员能显式的找到位置信息，这样就可以在数据所在的位置执行
程序。因此，我们需要能同时提供位置透明的能力和显式的定位数据位置的能力。不同的应用有着不同的需求。</div>
<div id="d2.0">&nbsp;&nbsp; &nbsp;Mnesia应用系统仅通过使用数据库表的名字（无需考虑表的位置）就能访问这些表。系统能明了数据都复制到了哪里。然而，它也能让Mnesia程序员通过系统查询到表的位置然后远程执行代码，可以将代码发送到远程站点上，或者那些代码已经在那里并加载了。</div>
<h3 id="fyzx">3.5 事务和ACID</h3>
<div id="d2.0">&nbsp;&nbsp;
&nbsp;DBMS都有ACID特性，原子性、一致性、隔离性和持续性。这些特性通过Mnesia中的事务、writeahead
logging和恢复（recovery）实现。许多Mnesia事务包含了一系列仅在内存中（可能是复制的）的数据库表进行的操作，这些事务根本不与磁
盘存储系统打交道，因此对这些事务来说持久性特性没有实现。在电信系统中需要事务语义的一个例子就是当需要给系统添加一个新的subscriber时：当
我们进行此操作时，系统中会分配到一些资源，一些数据对象会被写入到系统内存中，所有的这些操作作为一个原子动作执行是至关重要的。不然这个系统就会出现
不一致的情况：可能某些资源没有释放。</div>
<h3 id="sb4e">3.6 绕过事务管理器的能力</h3>
<div id="d2.0">&nbsp;&nbsp;
&nbsp;对电信通信量处理应用系统来说，事务的代价非常高，简单的通过事务系统访问数据是不可行的，因此绕过这类事务系统是很有用的。一个适合电信系统的
DBMS必须能够同时支持由一系列数据库操作组成的原子性事务，以及非常轻量级的对同一数据的锁定（very light weight
locking on the same
data）。前面的通信量处理系统由许多表组成，很多表很少写但是经常读。例如处理一个单独的呼叫（single
call）比添加一个subscriber更常见，路由一个PDU packet比修改路由表更常见。</div>
<div id="d2.0">&nbsp;&nbsp;
&nbsp;当我们执行性能要求高的临界代码（critical
code）时，我们不想被强制使用事务，这些事务中只有只读操作。相反的，当路由表正被修改时从路由表中读取路由信息，一些数据包由于这种访问冲突丢失是
可以接受的。这里需要的是非常轻量级的锁定保护，这样应用系统进程可以访问数据表，并确定每个数据对象都是可读的，不会由于当前的写操作而混淆。
Mnesia通过所谓的脏接口（dirty
interface）支持这一特性。在一个事务中没有保护的读、写和搜索Mnesia表是可能的。这些脏操作是真正的实时DBMS操作：不管数据库有多
大，这些操作都能在可预期的时间内完成。</div>
<h3 id="ur8b">3.7 查询</h3>
<div id="d2.0">&nbsp;&nbsp; &nbsp;除了通信量的处理，电信系统还包含大量操作维护(O&amp;M)代码。例如，当从一个交换机系统中删除一个subscriber时，我们需要在好几张表中搜索与subscriber相关的数据，这就需要一个查询语言。操作和维护代码有如下特点：</div>
<div id="d2.0"><ol id="true">
<li id="g9tk">它没有或者有非常低的实时性要求；</li>
<li id="ri_z">它读取、搜索和操作大量的通信量数据；</li>
<li id="k18t">在系统的代码量上这些代码占了很大的比例（it constitutes a large part of the code volumn of the system）;</li>
<li id="s2p5">它很少执行，这取决于软件的好坏和bug的多少。</li>
</ol>
</div>
<div id="d2.0">这
样，一个强有力的执行在目标系统并能访问通信量表的查询语言能通过减少O&amp;M代码、通过声明（being
declarative）以及自动适应表的变化和网络拓扑结构。（a powerful query language which executes
on the target system and has complete access to all traffic tables, can
remedy by making the O&amp;M code smaller and by being declarative and
by being able to automatically adapt to chages in table layout or
network topology.）因为一个优化的编译器用于决定查询的执行顺序，O&amp;M代码可以变得更高效。</div>
<div id="d2.0">&nbsp;&nbsp;
&nbsp;Mnesia查询语言基于表理解（list comprehension），这个想法在好几个其它的函数式DBMS（functional
DBMS），如[15]中得到过应用。表理解（list comprehension）的语法能与Erlang语言完美的结合在一起。</div>
<h3 id="zjmm">3.8 模式改建（Schema alteration）</h3>
<div id="d2.0">Erlang
语言有一个扩展的支持，它使得应用系统拥有不停止进程而修改正在执行中的代码的能力。这使得不停机而修改Erlang数据的发布和组织成为可能。也就是
说，它能在运行时修改Mnesia数据库模式（schema）而不必停掉系统。既然Mnesia是用来创建永不停机系统（nonstop
system）的，所有的系统活动如备份、修改模式（schema）、转储数据表表到二级存储器以及拷贝复制品（replicas）都可以在背后运行，而
且做这些事的同时应用系统依然能像平常一样访问和修改数据库表。</div>
<div id="d2.0"><br id="ws0b" />
</div>
<h2 id="h.g9">4&nbsp;一些实施方面的问题</h2>
<div id="d2.0">&nbsp;&nbsp; &nbsp;Mnesia完全由Erlang实现，Erlang编程环境是一个实现分布式DBMS的理想工具，整个Mnesia的完整实现还包括系统从底层存储管理到查询优化编译器的所有方面，实现的代码很小，大概有2万行Erlang代码。</div>
<div id="d2.0">&nbsp;&nbsp;
&nbsp;永久存储机制由操作系统的文件系统实现。不利的一面是这样的实现其性能取决于磁盘操作，好的一面是移植性不错。既然Mnesia主要是作为一个内存
DBMS（primary memory DBMS），我们觉得移植性更重要。主内存（primary memory）中的表和索引采用线性hash
list实现[13]，二级存储表（secondary storage tables）由具名文件（named
files）实现。每个文件被组织成一个线性hash list。（a linear hash list with a medium chain
length of the hash bucket set to a small value)。线性hash
list中查找操作上非常高效，在进行插入操作时效率也不错。文件和表的大小可以动态的伸缩。每个文件的空间管理由buddy算法实现。</div>
<div id="d2.0">&nbsp;&nbsp;
&nbsp;Mnesia锁管理使用了许多传统技术。锁定（locking）是动态的，事务在需要时会得到一个锁。常规的两阶段锁定（regular
twophase locking）也有用到，死锁的预防是通过传统的waitdie[14]。waitdie算法的时间戳通过Lamport
clock得到，后者由每个节点上的事务管理器负责维护，当一个事务重启后，它的Lamport clock处于维护中，thus making
Mnesia live lock free as well.锁管理器还实现了多粒度的锁定。当一个事务提交时，事务管理器采用了传统的两阶段提交。</div>
<div id="d2.0">&nbsp;&nbsp;
&nbsp;通过关系数据库技术的操作符可以评估简单的查询，递归的查询可以通过SLG[3]进行评估。因为Mnesia运行在分布式Erlang上，其实现非常简
单。在一个分布式应用系统中有许多彼此隔离的Erlang节点运行在不同的机器上。Eralng负责运行在不同节点上的进程间的通信。分布式Erlang
可以透明的穿越不同endianism结构的机器，这样一个Mnesia系统就可以由许多异构计算机系统组成。进程和节点很容易被其它节点上的进程启动、
监视和停止。这消除了Mnesia和应用系统中许多通信的实现困难（This makes much of communication
implementation difficulties disappear for Mnesia as well as for
applications)。</div>
<div id="d2.0"><br id="w.mn" />
</div>
<h2 id="r8jm">5 性能讨论</h2>
<div id="d2.0">我们在本节提供了一些Mnesia上的测量，图表清楚的显示了：</div>
<div id="d2.0">
<ul id="true">
<li id="igvt">相对于脏接口（dirty interface），使用事务系统的代价是相当大的。这一现象的正确解释是：脏接口快，事务系统慢；</li>
<li id="cw6:">复制的代价相当高。测试中的计算机使用的局域网是常规的10Mbit/sec；</li>
</ul>
</div>
<div id="d2.0">测试中的计算机是三台运行着Solaris 2.5的Sun UltraSparcs。所有的事务由一台167Mhz的UltraSparc负责初始化，其它两台是143Mhz。</div>
<div id="d2.0"><br id="zxxw" />
</div>
<div id="pu.s">
<table cellspacing="0" border="1" id="qtho" width="583" cellpadding="3" style="height: 135px;">
<tbody id="mgh:">
<tr id="gg_o">
<td id="hgji" width="25%">复制品数量<br id="c-ny" />
(number of replicas)</td>
<td id="a_8l" width="25%">1</td>
<td id="ckg9" width="25%">2</td>
<td id="h-.x" width="25%">3</td>
</tr>
<tr id="tr9b">
<td id="btd1" width="25%" style="font-family: Courier New;">divorce/1</td>
<td id="atuv" width="25%">1877</td>
<td id="pvf5" width="25%">5009</td>
<td id="vkh_" width="25%">13372</td>
</tr>
<tr id="l32m">
<td id="bi75" width="25%">使用wread的<span style="font-family: Courier New;">divorce/1</span>
</td>
<td id="p:80" width="25%">1225</td>
<td id="romz" width="25%">4703</td>
<td id="m.t4" width="25%">12185</td>
</tr>
<tr id="sl1g">
<td id="mu1t" width="25%">dirty <span style="font-family: Courier New;">divorce/1</span>
</td>
<td id="afcz" width="25%">181</td>
<td id="kk6g" width="25%">592</td>
<td id="lk03" width="25%">1121</td>
</tr>
</tbody>
</table>
</div>
<div id="d2.0" style="text-align: center;">表1 不同配置执行divorce/1函数的wallclock，单位：毫秒（ms）</div>
<div id="d2.0">&nbsp;&nbsp;&nbsp;
第一行的数据是来自第2节的divorce/1函数运行的结果，第二行的数据是我们用Mnesia函数wread/1取代函数中的read/1后的运行结
果，wread函数通过设置一个写锁（write lock）而不是读锁（read
lock）读取数据，如果我们预先知道接下来的操作要将同一个对象写入的话，此函数效率要高一点，这样锁就不必从读锁更新成写锁。最后一行的数据来自我们
用脏函数（dirty functions）读写这些复制表，这就使用到了轻量级锁，并绕过了事务系统。<br id="qqzu" />
<h2 id="v5.j">6 结论</h2>
现在有大量的DBMS可供选择，包括许多可用的商业系统和无数的研究系统，似乎使用商业的DBMS是比较好的选择，但是如果考虑到第3节中提到的那些因素，没有一个合适的商业DBMS可用。我们认为我们的主要贡献在于：<br id="m82y" />

<ul id="izxg">
<li id="l2x1">通过组合许多已有的技术，我们实现了一个完整的分布式DBMS，许多研究组织只研究DBMS的某些方面，我们实现了一个完全的分布式DBMS，很少有这样的系统存在；</li>
<li id="ymir">我们展示了Erlang不仅适合电信系统而且也非常适合实现一个DBMS系统，例如Mnesia。就我们了解，这是第一次有人用一个符号编程语言(symbolic programming language)实现了一个分布式DBMS；</li>
<li id="t.sz">我们提供了一个全面的DBMS解决方案，至少在电信系统的数据管理方面是这样子。</li>
</ul>
今天Mnesia系统早已在Ericsson中用于构建真正的软件产品，Mnesia已经不再是原型系统，它已经成熟到可以贴上产品的标签了。通过http://www.ericsson.se/erlang可以了解该系统。<br id="j47r" />
<h2 id="gm9o">参考资料</h2>
<ol id="i47g">
<li id="v-pa">Armstrong,
J. L., Williams, M. C., Wikstrom, C. and Virding, S. R., Con current
Programming in Erlang, 2:nd ed. Prentice Hall (1995)</li>
<li id="o:26">Bernstein, P.A., Hadzilacos, V., Goodman, N. Concurrency Control and recovery in Database Systems Addison Wesley, 1987.</li>
<li id="s_e-">Chen,
A.W., Warren, D.S. Query Evaluation under the WellFounded Se mantics
Proc. ACM SIGACT-SIGMOD-SIGART Symp. on Principles of Database Sys.
Whashington, 1993.</li>
<li id="zt7g">Case, K. McCloghrie, M. Rose, S.
Waldbusser. Management Information Base for Version 2 of the Simple
Network Management Protocol (SNMPv2), Jan, 1996.</li>
<li id="bgur">Copeland,
G., Maier, D. Making Smalltalk a database system Proceedings of the
1984 ACM SIGMOD International Conference on Management of Data. pp.
316325. Boston 1984.</li>
<li id="x483">Eswaran, K.P., Grey, J.N.,
Lorie, R.A. and Traiger, I.L. The Notions of Consistence and Predicate
Locks in a Database system Communications of ACM, 19(11):624633,
November 1976.</li>
<li id="zwen">Faehndrich, M., Morrisett, G.,
Nettles, S., Wing, J. Extensions to Standard ML to Support Transactions
ACM SIGPLAN Workshop on ML and its Applications, June 2021, 1992.</li>
<li id="lyvq">Goetz, G. Query Evaluation Techniques for Large Databases ACMCS 2(25):73170, June 1993.</li>
<li id="p3st">Grey,
J.N. Notes on Database operating system: An advanced course Lecture
notes in Computer Science,Springer Verlag, Berlin. 1(60):393481, 1978.</li>
<li id="pjd7">Grey,
J.N., Lorie, R.A., Putzolo, G.R. and Traiger, I.L. Granularity of Locks
and degrees of consistency in a shared database IBM, Research report
RJ1654, September 1975.</li>
<li id="s7ij">Hvasshovd, SO., Torbjornsen,
O., Bratsberg, S.E., Holager, P. The ClustRa telecom database: High
availability, high throughput, and realtime response Proceedings of the
21st International Conference on Very Large Databases, Zurich,
Switzerland, pp. 469477, September 1995.</li>
<li id="mlhf">Lamport, L.
Time, clocks and the ordering of events i a distributed system ACM
Transactions on Programming Languages and Systems, 21(1):558565, July
1878.</li>
<li id="yj9d">Larsson, PA Larsson. Dynamic Hash tables Communications of the ACM, 31(4), 1988</li>
<li id="phku">Rosenkrantz,
D.J., Stearns, R.E. and Lewis, P.M. System Level Concurrency Control
for Distributed Databases ACM Transactions on Database Systems,
3(2):178198, June 1978.</li>
<li id="i_ef">Trinder, P.W. and Wadler, P.
List comprehensions and the Relational Cal culus Proceedings of the
Glasgow 1988 Workshop on functional programming, Rothesay , August
1988, pp 115123.</li>
<li id="sryk">Ullman, J. Principles of Database and KnowledgeBase Systems, vol 2. Computer Science press, 1989.</li>
</ol>
</div>
<div id="d2.0"><br id="pxup" />
</div>
</div>
          <br/>
          <span style="color:red;">
            <a href="http://cryolite.javaeye.com/blog/186886#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 25 Apr 2008 17:27:42 +0800</pubDate>
        <link>http://cryolite.javaeye.com/blog/186886</link>
        <guid>http://cryolite.javaeye.com/blog/186886</guid>
      </item>
      <item>
        <title>gdal安装和使用</title>
        <author>cryolite</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cryolite.javaeye.com">cryolite</a>&nbsp;
          链接：<a href="http://cryolite.javaeye.com/blog/176382" style="color:red;">http://cryolite.javaeye.com/blog/176382</a>&nbsp;
          发表时间: 2008年03月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h1><span style="font-size: large;"><strong>一、linux下的安装和使用</strong>
</span>
</h1>
<h2><span style="font-size: medium;">1.安装</span>
</h2>
<p>下载<a href="http://trac.osgeo.org/gdal/wiki/DownloadSource" target="_blank">源程序包</a>
，解压，运行以下三条命令</p>
<pre name="code" class="java">./configure
make
make install</pre>
<p><br />
在/usr/local/lib目录下会出现编译好了的相关gdal库</p>
<h2><span style="font-size: medium;">2.使用</span>
</h2>
<h3>2.1 gdal库连接问题</h3>
<p>gdal成功安装后，相关的库也会拷贝到/usr/local/lib目录下，但这并不意味着系统能马上找到加载libgdal.so库的路径，还需要加载库路径的问题：让程序在运行时能找到这些库</p>
<p>运行时如果出现以下错误：</p>
<p>&nbsp;error while loading shared libraries: libgdal.so.1: cannot open shared object file: No such file or directory</p>
<p>说明系统不知道gdal共享库加载路径，运行 ldd命令 列出程序正常运行所需要的共享库</p>
<p>ldd test.o</p>
<p>[root@test]# ldd a.out<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /usr/lib/libcwait.so (0x0054f000)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="background-color: #ff0000;">libgdal.so.1 =&gt; not found</span>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libstdc++.so.6 =&gt; /usr/lib/libstdc++.so.6 (0x00b42000)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libm.so.6 =&gt; /lib/tls/libm.so.6 (0x009b5000)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libgcc_s.so.1 =&gt; /lib/libgcc_s.so.1 (0x00b03000)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libc.so.6 =&gt; /lib/tls/libc.so.6 (0x0088a000)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /lib/ld-linux.so.2 (0x00871000)<br />
解决办法如下</p>
<h4>a. 设置环境变量：</h4>
<p>设置$LD_LIBRARY_PATH=库所在目录（多个目录用:分隔），系统加载工具将顺序搜索变量指定的目录</p>
<pre name="code" class="java">LD_LIBRARY_PATH=/usr/local/lib:/usr/local/erlang/lib; export LD_LIBRARY_PATH</pre>
<h4>b.&nbsp; 以root身份把库路径加入/etc/ld.so.conf</h4>
<p>vim /etc/ld.so.conf.d/gdal.conf</p>
<p>在此文件中增加如下路径</p>
<p>/usr/local/gdal-1.5.1/.libs</p>
<p>然后运行ldconfig更新/etc/ld.so.cache<br />
 /sbin/ldconfig</p>
<h4>c. </h4>
<p>直接把gdal相关的库拷贝到/usr/lib下</p>
<p>共享库搜索顺序一般是$LDLIBRARY_PATH，/etc/ld.so.cache, /usr/lib, /lib</p>
<p>参考：<a href="http://soho-schubert.blogspot.com/2007/08/linux.html">Linux编程使用库</a>
</p>
<h3>2.2 编译使用GDAL库的C++程序</h3>
<p>运行以下命令</p>
<pre name="code" class="java">g++ test.cpp -lgdal -o test.o </pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h1>二、Mac OS X下的安装与使用</h1>
<h2>1.安装 <br />
</h2>
<p>William Kyngesburye维护了一个GDAL的<a href="http://www.kyngchaos.com/software/unixport/frameworks" target="_blank">Mac OS X framework</a>
.</p>
<p>按指示安装即可，卸载的话直接将/Library/Framework/GDAL.framework, /Library/Application Support/GDAL，~/Library/Application Support/GDAL 扔到trash里 </p>
<p>&nbsp;</p>
<h2>2.使用 <br />
</h2>
<p>编译使用GDAL库的C++程序运行以下命令 </p>
<pre name="code" class="ruby">g++ gdal_test.cpp -framework GDAL -o gdal_test.o</pre>
&nbsp;
<h3><strong>注意</strong>
</h3>
<p>1. 不要错用成gcc命令了；</p>
<p>2. C++程序中的include一律要加上GDAL/，例如&nbsp;</p>
<p>&nbsp;</p>
<pre name="code" class="cpp">#include &quot;GDAL/ogrsf_frmts.h&quot;</pre>
&nbsp;
<h1>三、跨平台编译</h1>
<p>使用预处理器的技巧区分处理平台的不同 </p>
<p>用编译器的-D传入平台相关信息，一个例子:</p>
<pre name="code" class="c">#ifdef MAC_OS_X
	#include &quot;GDAL/ogrsf_frmts.h&quot;
#else
	#include &quot;ogrsf_frmts.h&quot;
#endif</pre>
&nbsp;
<p>在Mac下编译</p>
<pre name="code" class="python">g++ -D MAC_OS_X -framework GDAL test.cpp -o test.o</pre>
&nbsp;
<p>&nbsp;</p>
<p>在linux下编译方式不变</p>
<p>&nbsp;</p>
<pre name="code" class="java">g++ test.cpp -lgdal -o test.o</pre>
<p>&nbsp;</p>
<p>也许还有更优雅的跨平台方法，我暂时还不知道</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://cryolite.javaeye.com/blog/176382#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 26 Mar 2008 16:11:09 +0800</pubDate>
        <link>http://cryolite.javaeye.com/blog/176382</link>
        <guid>http://cryolite.javaeye.com/blog/176382</guid>
      </item>
      <item>
        <title>MacOSX的terminal显示设为彩色</title>
        <author>cryolite</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cryolite.javaeye.com">cryolite</a>&nbsp;
          链接：<a href="http://cryolite.javaeye.com/blog/156336" style="color:red;">http://cryolite.javaeye.com/blog/156336</a>&nbsp;
          发表时间: 2008年01月16日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <span style="font-size: large">1.一般bash命令高亮度:</span><br />编辑~/.bash_profile(没有则创建之)或者直接修改/etc/bashrc,添加<br /><pre name="code" class="java">export CLICOLOR=1</pre><br />即可<br /><br /><span style="font-size: large">2.vim支持高亮度:</span><br />进入vim后<br /><pre name="code" class="java">e $VIMRUNTIME/vimrc_example.vim
saveas ~/.vimrc

e $VIMRUNTIME/gvimrc_example.vim
saveas ~/.gvimrc</pre>
          <br/>
          <span style="color:red;">
            <a href="http://cryolite.javaeye.com/blog/156336#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 16 Jan 2008 00:06:19 +0800</pubDate>
        <link>http://cryolite.javaeye.com/blog/156336</link>
        <guid>http://cryolite.javaeye.com/blog/156336</guid>
      </item>
      <item>
        <title>遗传算法学习笔记（1）</title>
        <author>cryolite</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cryolite.javaeye.com">cryolite</a>&nbsp;
          链接：<a href="http://cryolite.javaeye.com/blog/25428" style="color:red;">http://cryolite.javaeye.com/blog/25428</a>&nbsp;
          发表时间: 2006年10月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          学概率的时候提到有这样一个“无限猴子定律”：一个具有无限生命的猴子（它不懂人类的语言）随机的敲击打字机，总有一天它会打出一本莎士比亚的书来。<br /><br />这只猴子能打出任意的书来，有意义的无意义的，无意义的远多于有意义，猴子定律只是指出了得到这种有意义的书的可能性，不保证他的现实性，也许整个宇宙从诞生到现在的时间，这只猴子仍然打不出来，但是在接下来的时间里，总有那么一天完成这个任务。<br /><br />个人理解，这个猴子定律说的是以概率的角度看，什么可能都会发生，从无序中能得到有序。生命也是一种有序的组织，它是如何诞生的，达尔文的进化论科学的解释了这一问题。<br /><br />攻击进化论的人一个重要理由是：生命如此复杂，它的产生几乎是一个概率为零的事件。他们从概率计算认为，从宇宙诞生的时间算起，也无法自发生成一个细胞。<br /><br />计算是对的，结论是错误的，原因是他们忽略了自然选择对这一过程的干预。如果没有干预，什么都在发生，也就什么都不可能发生。<br /><br />从低级到高级，从简单到复杂，高度复杂的生命是由更为简单的生命一步一步地通过选择形成。突变是随机的，但是在自然选择的作用下，随机性大大降低。无序的没有意义的被自然剔除，剩下的进一步选择，一步一步，高级生命就这样诞生了。这样的高级生命也许不是最完美的，但确实最适合环境的<br /><br />上帝是否掷骰子？上帝当然掷骰子，但是它也提供了一个甄别的手段，就是说上帝认为某种结果是合理的，合理的结果就留下了，不合理的就忽略了，在合理的结果中继续甄别。。。。。<br /><br />上帝需要操心生命具体如何进化吗，他需要对生命的各方各面（组成物质，细胞结构，器官等等）进行设计吗？也不需要。只要提供了甄别，随生命怎么随机变异，他只负责对变异的结果进行赠别就行了，若干年后，当年简单的有机物变成了现在高度复杂的生命。<br /><br />遗传算法模拟上帝创建生命的这一过程<br /><br />计算机算法是指完成一个任务所需要的具体步骤和方法。也就是说给定初始状态或输入数据，经过计算机程序的有限次运算，能够得出所要求或期望的终止状态或输出数据。<br /><br />算法也可简单描述为：给出一定的输入，得到合理的输出。一些算法我们可以在了解它的原理下计算出来，典型的如数学计算。但许多情况下数学模型很难精确求最优解，对于这些复杂问题，能够得到次优解就很满意了<br /><br />遗传算法从代表问题可能的潜在解集合开始，模仿了自然进化模型，如选择、交叉、变异、迁移等过程。计算开始时，一定数目N个个体（即初始解集合）随机的初始化，计算每个个体的适应度（供选择的量化指标），选出适应度最高的个体，第一代就这样诞生了，然后得到的子代按一定概率变异，加入下一次选择，再变异，再选择。。。。。这一过程循环往复，直到满足求解条件为止。<br /><br />也就是说，使用遗传算法我们不需要详细了解算法原理，数学模型，我们只要给出进化手段（变异手段，选择手段等），和足够的时间，遗传算法总能给我们找到一个次优解，尽管可能不是最优解<br /><br />所以某种程度上遗传算法几乎是一个万能算法<br /><br />但是为什么不容易得到最优解？所谓最优解，只会有一个，如果有两个就不叫最优解了。<br />回头看看地球上的生物进化。总的趋势是从低级到高级，从简单到复杂。我们把进化出理性生命看做最优解，是否必然只产生像人类，而不是别的什么理性生命呢？<br /><br />注：这里提到的上帝是一个比喻，也就是常说的斯宾洛沙的上帝，即大自然，而不是圣经中那个具有人格的上帝<br /><br />参考：<br />http://www.bullog.cn/blogs/fangzhouzi/archives/17777.aspx<br />http://www.bullog.cn/blogs/fangzhouzi/archives/17776.aspx
          <br/>
          <span style="color:red;">
            <a href="http://cryolite.javaeye.com/blog/25428#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 01 Oct 2006 13:06:35 +0800</pubDate>
        <link>http://cryolite.javaeye.com/blog/25428</link>
        <guid>http://cryolite.javaeye.com/blog/25428</guid>
      </item>
  </channel>
</rss>