Erlang:RabbitMQ源码分析 4. file_handle_cache实现分析

本文深入解析了RabbitMQ使用file_handle_cache管理文件操作的机制,包括内存数据存储方式、基本文件操作函数实现及文件打开与关闭的逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

RabbitMQ的文件操作使用file_handle_cache,将Erlang的prim_file Module包了一层。增加了writeBuffer和对文件打开数量的控制逻辑


file_handle_cache也是一个gen_server2,但一般来说只有Open操作会send message to gen_server2, 读写操作,包括writeBuffer都在Client Process里执行和维护。


file_handle_cache里存储了几张表:

   1. Elders:    {Pid, EldestUnusedSince},  存储每个client的pid 和其最老的Handle打开时间, 没有key

   2. Clients:   #cstate,存储每个client的信息,key是pid


在file_handle_cache中可以看出,内存数据在Erlang中的存储无非于几种:

   1. ETS表,例如Elders, Clients; 适合存储一些集中的信息,不同的Process都能访问

   2. Process Dictionary,本Process的信息,例如file_handle_cache中client Process的file和handle

   3. gen_server的state,放在loop state里不断循环反复


下面我们从四个最基本的文件操作函数看一下file_handle_cache的实现:

open:

    1. file_handle_cache对于同一个文件是共享读但不共享写的,所以在client的Process Dictionary里存储了<key = {Path, fhc_file}, value = #file{ reader_count, has_writer}>,当open时如果发现has_writer = TRUE, open的model又是write,就直接返回{error, writer_exists};

    2. 新建一个closed的Handle,Handle相关的信息存储在client的Process Dictionary里 <key = {Ref, fhc_handle}, value = #handle>

    3. file_handle_cache在client的Process Dictionary里存储里一个gb_tree,用来保存这个client打开的所有Handle的打开时间。这个时间是用来调整Client Open的Handle个数。

    1-3都是在client的Process里做的

    4. gen_server:call open,  进入到file_handle_cache的Process loop里 , 当发现file_handle_cache打开的文件数不超过用户预设的文件数时,就update Clients table 和State,返回 OK。

    5. 回到client Process里,调用prim_file:open打开文件,所以打开文件的操作实际上市在Client Process里做的。

    6. 如果4中发现file_handle_cache打开的文件数超过用户预设的文件数时,

        6.1 如果这个pid已经打开了很多文件,就返回close, client接到close后就soft_close所有之前打开的Handle,所谓软关闭,就是将Handle对应文件buffer写完,sync后再关闭。软关闭所有之前打开的Handle后再重新试图open 这个Handle。

        6.2 如果这个pid没有打开任何文件,就对其他的pid下手,计算每个pid的最老时间(最早的打开的文件时间),累加算平均值。

             一般来说client在打开文件前会call register_callback 注册一个清理函数

             6.2.1 如果平均值大于两秒,说明有很多老文件还未关闭, 就对每个client call 清理函数。参数是最老时间的平均值。如果没有注册清理函数就不管。

             6.2.1 如果平均值小于两秒,说明没有很多未关闭的老文件。找到所有注册清理函数的pid, 假设有N个Open被Block,就用其中N个清理函数去清理N个已打开的Handle


close:

      1. 删掉ProcessDictionary 里的{Ref, fhc_handle}

      2. Handle的writebuffer 要prim_file:write

      3. 如果之前有write没有sync,call prim_file:sync

      4. call prim_file:close

      5. 将这个Handle的时间从gb_tree里删掉

      6. 更新Process Dictionary里的{Path, fhc_file}, read_count, write_count之类


read:  read本身没有什么特殊的,也没有用buffer

      1.  虽然已经Open过,但有可能因为打开文件过多被close,所以还是看下,如果被close了要reopen一下

      2.  Handle的writebuffer要prim_file:write

      3.  调用prim_file:read得到结果


append:

      1.  和read一样,也是有可能会reopen。

      2.  如果client在Open时没有设置WriteBuffer,就直接call prim_file:write(Hdl, Data)了事

      3.  所谓的Writebuff是针对于单个Handle的,即Open时搞一个空的List来做Buffer,append时如果BufferSize > Client Open时设置的limit,就call prim_file:write把Buffer都写到file里,如果BufferSize < limit,就只是将Data放到Buffer里即返回。




错误:软件包:rabbitmq-server-3.13.7-1.el8.noarch (rabbitmq_server) 需要:erlang >= 26.0 已安装: erlang-23.3.4.11-1.el7.x86_64 (@rabbitmq-erlang) erlang = 23.3.4.11-1.el7 可用: erlang-R16B-03.18.el7.x86_64 (epel) erlang = R16B-03.18.el7 可用: erlang-20.3.8.25-1.el7.x86_64 (rabbitmq-erlang) erlang = 20.3.8.25-1.el7 可用: erlang-20.3.8.26-1.el7.x86_64 (rabbitmq-erlang) erlang = 20.3.8.26-1.el7 可用: erlang-21.3.8.14-1.el7.x86_64 (rabbitmq-erlang) erlang = 21.3.8.14-1.el7 可用: erlang-21.3.8.15-1.el7.x86_64 (rabbitmq-erlang) erlang = 21.3.8.15-1.el7 可用: erlang-21.3.8.16-1.el7.x86_64 (rabbitmq-erlang) erlang = 21.3.8.16-1.el7 可用: erlang-21.3.8.18-1.el7.x86_64 (rabbitmq-erlang) erlang = 21.3.8.18-1.el7 可用: erlang-21.3.8.21-1.el7.x86_64 (rabbitmq-erlang) erlang = 21.3.8.21-1.el7 可用: erlang-22.2.7-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.2.7-1.el7 可用: erlang-22.2.8-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.2.8-1.el7 可用: erlang-22.3-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3-1.el7 可用: erlang-22.3.1-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.1-1.el7 可用: erlang-22.3.2-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.2-1.el7 可用: erlang-22.3.3-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.3-1.el7 可用: erlang-22.3.4-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.4-1.el7 可用: erlang-22.3.4.7-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.4.7-1.el7 可用: erlang-22.3.4.10-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.4.10-1.el7 可用: erlang-22.3.4.11-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.4.11-1.el7 可用: erlang-22.3.4.12-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.4.12-1.el7 可用: erlang-22.3.4.16-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.4.16-1.el7 可用: erlang-22.3.4.19-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.4.19-1.el7 可用: erlang-22.3.4.21-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.4.21-1.el7 可用: erlang-23.1.2-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.1.2-1.el7 可用: erlang-23.1.5-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.1.5-1.el7 可用: erlang-23.2.1-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.2.1-1.el7 可用: erlang-23.2.3-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.2.3-1.el7 可用: erlang-23.2.4-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.2.4-1.el7 可用: erlang-23.2.5-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.2.5-1.el7 可用: erlang-23.2.6-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.2.6-1.el7 可用: erlang-23.2.7-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.2.7-1.el7 可用: erlang-23.2.7-2.el7.x86_64 (rabbitmq-erlang) erlang = 23.2.7-2.el7 可用: erlang-23.3-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3-1.el7 可用: erlang-23.3-2.el7.x86_64 (rabbitmq-erlang) erlang = 23.3-2.el7 可用: erlang-23.3.1-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.1-1.el7 可用: erlang-23.3.2-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.2-1.el7 可用: erlang-23.3.3-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.3-1.el7 可用: erlang-23.3.4-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4-1.el7 可用: erlang-23.3.4.1-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4.1-1.el7 可用: erlang-23.3.4.3-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4.3-1.el7 可用: erlang-23.3.4.4-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4.4-1.el7 可用: erlang-23.3.4.5-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4.5-1.el7 可用: erlang-23.3.4.6-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4.6-1.el7 可用: erlang-23.3.4.7-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4.7-1.el7 可用: erlang-23.3.4.8-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4.8-1.el7 可用: erlang-23.3.4.10-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4.10-1.el7 您可以尝试添加 --skip-broken 选项来解决该问题 您可以尝试执行:rpm -Va --nofiles --nodigest
07-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值