您现在的位置:首页
--> 源码分析
riak_sysmon 是利用 BIF 函数 system_monitor 来监控 Erlang vm 产生的消息状态的项目。下面结合使用来分析一下其源码。 由于使用 system_monitor,那么 riak_sysmmon 仅能做到如下四类事件的捕获: 1. 进程的 heap 超过预设的 heap_word_limit。 2. gc 的收集时间过长超过预设的 gc_ms_limit。 3. 繁忙的文件或者套接口 port。 4. Erlang 节点之间的网络通信烦忙。
问: 我测试发现,如果cp一个文件,然后direct io读这个文件,会消耗很长时间。 我猜测dio不能用page cache,而这个文件cp以后都在cache里面,要强制刷到磁盘,才能读? 我cp这个文件很大,超过256M 由于数据文件默认是用bufferedio方式打开的,也就是说它的数据是先缓冲在pagecache里面的,写入的数据会导致大量的脏页,而且这部分数据如果内核内存不紧张的话,是一直放在内存里面的的。我们知道directio是直接旁路掉pagecache直接发起设备IO的,也就是说在发起IO之前要保证数据是先落地到介质去,所以如果文件比较大的话,这个时间会比较长。
MariaDB数据库加入了对HASH JOIN算法的支持,我对HASH JOIN不了解,借此机会学习一下,测试的数据库版本为MariaDB5.5.27。 先是配置文件,这是我为了方便跟踪源码,在windows上建的环境。
老话题了,不过经典代码分析总是能学到很多东西。
在Direct IO模式下,异步是非常有必要的(因为绕过了pagecache,直接和磁盘交互)。linux Native AIO正是基于这种场景设计的,具体的介绍见:KernelAsynchronousI/O (AIO) SupportforLinux。下面我们就来分析一下AIO编程的相关知识。
libeio的feature:提供全套异步文件操作的接口,让使用者能写出完全非阻塞的程序。阻塞意味着低效,但非阻塞一定要有很好的通知机制才能做到高效。 其实linux下的AIO(异步IO)并不是没有解决方案:在用户态,多线程同步来模拟的异步IO,如Glibc 的AIO;以及在内核态实现异步通知,如linux内核2.6.22之后实现的Kernel Native AIO。但两者都存在让使用者望而祛步的问题。 Glibc的AIO bug太多,而且IO发起者并不是最后的IO终结者(callback是在单独的线程执行的);而kernel Native AIO只支持O_DIRECT方式,无法利用Page cache。
今天一个同事问我关于write(2)在写入文件的时候问题,问题是这样的:当磁盘剩余空间不能将一次write调用希望写入的数据写完的时候,write是直接返回-1,然后设置errno为ENOSPC,还是先写入一部分数据,将剩余空间占满然后再下一次调用的时候返回错误?当时发现好像没有考虑过这样的问题,Google了一下,好像没有找到关于这个细节的说明。于是今天决定自己试试看。用dd建立一个64M大小的文件,然后弄上不同的文件系统用loop挂载,去写满试试看。
Linux 内核中使用到了字符串搜索,所以它也有 KMP 算法的实现,代码在 lib/ts_kmp.c 中。 Linux 内核中用到 KMP 算法的地方有三处:iptables string match 模块、iptables conntrack amanda 模块(不知道这个是用...
现在的linux内核中对于缓存的管理都是以page的形式进行的,也就是说在系统底层只存在各种page,这些page保存在不同的tree 中,buffer这个概念实际上已经过时了,但是为了保持对过往系统的兼容性,linux内核中还保留了这个概念,并仍然用它来代表文件系统中的一些所谓的元数据,但是由于已经没有buffer了,那么free该怎么显示buffers呢?内核巧妙的利用了一个特性,那就是文件系统在读取元数据的时候一般都是通过它所对应的块设备来进行,也就是说元数据存储的page一般都是保存在块设备对应的tree中,而一般文件的page cache则是保存在它的宿主文件的tree中。有了这个假设,我们就可以通过统计所有在块设备的tree上的page来得出系统的buffers数量。
基本类型如何使用元表 在lua里只能为表设置元表,而在c程序里面可以为基本类型进行元表操作,但上篇博文提到了普通类型的很多操作是不会走到元表,下面的例子针对数字类型,添加多种事件,只有部分事件会生效.下面的例子在c代码里对数字类型添加元表对__add,__len都设置事件.
表是如何调度到元表的呢,上篇博文的例子我们看到当键值未能被查找到之后会调用__index事件对应的函数.现在举一个”__add”事件来遍历重要环节的源码..... arith_op是个宏,会针对操作数进行类型判断,如果是数字类型就会立即进行相加,这就是为什么基本类型即便设置了加减等事件函数后还是没有效果,例如你为数字的加法设置了__add事件后数字相加不会掉用这个元表方法,后面会举一个例子.
lua metatable(以下简称元表)类似c++的operator overloads,可以对复合结构进行操作,在lua里最常见的就是对表的操作.举例来说,当两个表作加法操作的时候,Lua会检查表的元表中是否有”__add”事件是否对应一个函数(metamethod)。如果存在Lua会调用这个函数来执行一次表的加法操作. __index和__newindex是表常常要添加的事件,用于处理键值在表无法被查找到之后的处理.
上周有位网友联系我说chaos在他的环境上编译不过,并发给我了一些错误信息 查看了编译错误信息之后并没得到太多排查的入口,询问了对方的编译器版本是gcc 4.6.3,而我基本都是工作在4.1版本左右的gcc上,周末在家自己搭了个4.6.3的环境,果然也出现了同样的问题,之后发现这是因为高版本gcc(g++)对c++模板的检查更为严格所导致的,我们直接看例子
alarm函数是信号方式的延迟,这种方式不直观,这里不说了。 仅通过函数原型中时间参数类型,可以猜测sleep可以精确到秒级,usleep/select可以精确到微妙级,nanosleep和pselect可以精确到纳秒级。 而实际实现中,linux上的nanosleep和alarm相同,都是基于内核时钟机制实现,受linux内核时钟实现的影响,并不能达到纳秒级的精度,man nanosleep也可以看到这个说明,man里给出的精度是:Linux/i386上是10 ms ,Linux/Alpha上是1ms
继续上一次的sys模块升级的话题,我们再讨论一下升级基本原理,了解一下code和code_server模块。 简单升级 上文也说到过,如果升级未改动 State 里的内容,你可以这样升级。 在集群的每个节点内(当然也可以通过 rpc) 拷贝 beam 到线上的 ebin 目录。 code:purge(Module). code:load_file(Module). 让代码触发 Fully qualified function calls,走到新的 beam 代码。 如果你想省略后 2,3 步,可以利用mochiweb的 reloader 模块进行自动加载。 升级的原理 结合code_server代码来研究一下升级的原理。 erlang 可以同时允许两套代码同时加载运行在虚拟机内部运行, 一套被成为老版本代码 , 一套被成为当前版本代码,也成为最新代码。
sys模块主要有两大用途.统计跟踪目标gen进程,代码热升级,尤其后者非常重要,下面从erlang源码层面来讲述这两大工作原理. 代码热升级 代码热升级能做到gen进程不停(自然其中的socket,file都不需要关闭咯,100%的在线率多有趣的功能阿)的情况下自动载入新的代码, 这点对于其它程序语言来说是件非常难的事情,而对于erlang确只是简单几行代码就能解决问题. 演示代码 这里有演示代码,你可以自行运行. 热升级的原理和步骤 1.首先gen进程已经启动并处于正常工作状态处理业务逻辑,现在需要对代码进行升级,修改原来的内部State状态. 2.修改代码,编译出新的beam文件. compile:file(Mod). 注意不能使用c(Mod). c命令实际包含一个编译和加载和清理老代码作用,这里还不能加载哦, 老的内存状态运行在新的代码肯定报错.
深夜失眠,苦闷无处排遣,于是打开电脑读起Zen Cart的代码来了。 从index.php开始读,这个文件相当重要,注释里说index.php represents the hub of the Zen Cart MVC system,也就是说它代表了Zen Cart MVC系统的中心。
当一个网卡配置了多个IP时,那么kernel选择哪个IP作为源IP来发送数据包呢?
gen_fsm和gen_server非常的类似, 在gen进程递归调用loop函数的过程中,除有StateData还额外有一个StateName的atom, 它决定了下次执行的函数. 另外一个不同之处是, gen_server程序是由调用进程向gen进程发送消息, 一种cs模式的调用关系,而gen_fsm程序中这个发送消息的通常都是gen进程本身. init 初始化过程和gen_server很类似, 区别是init返回必须获得一个当前状态StateName, 这样才能继续接下来的事件处理.
supervisor实际上是基于gen_server的系统进程,监控子进程的退出状态并设置一定的重启机制。 init 在这个例子里Mod模块是一个sup程序,它的启动会调用supervisor:start_link,而start_link实际上调用的gen_server:start_link并存入Mod模块的名字和参数. 从前面的文章我们可以知道, spawn出来的gen进程会先调用supervisor:init函数. 接着把gen进程设置为系统进程, 这样就可以捕获子进程退出信号, 然后根据Args里的Mod模块名和参数,再次调用到Mod:init. Mod的init函数返回的是一个{ok, SupFlags, StartSpec}的元组. SupFlags是supervisor管理的进程的启动策略和可重启的范围窗口,StartSpec是一个列表,保存多个子进程的MFA等信息.
近3天十大热文
- [67] Twitter/微博客的学习摘要
- [67] IOS安全–浅谈关于IOS加固的几种方法
- [64] 如何拿下简短的域名
- [63] android 开发入门
- [63] Go Reflect 性能
- [60] find命令的一点注意事项
- [60] Oracle MTS模式下 进程地址与会话信
- [58] 流程管理与用户研究
- [57] 【社会化设计】自我(self)部分――欢迎区
- [55] 图书馆的世界纪录
赞助商广告