如何处理通过Erlang gen_server打开的文件?

时间:2013-04-19 04:06:25

标签: erlang gen-server

我创建了一个模块,它以完全不同的方式透明地处理某些文件,代替Erlang的file:open/2和它返回的IoDevice /文件描述符。在许多情况下,它只是返回Erlang file:open/2的结果,而在其他情况下,它会返回一个自定义IoDevice,它通过HTTP API进行读写(CloudFiles或AWS S3) )。

最近这是一个简单的模块,但我一直在尝试将其转换为gen_server以更好地处理异步HTTP调用(以及其他原因)。这些自定义位运行正常,但我只是从file:open/2调用gen_server:handle_call/3并返回生成的IoDevice时遇到问题。问题是在我的gen_server打开文件以便使用IoDevice进行回复后,会立即发出意外的gen_server:handle_info/2来电,并最终在gen_server上暂停。

...
handle_call({open, Path, Flags}, _From, State) ->
    Reply = case handle_external_file(Path) of
                false -> file:open(Path, Flags);
                true -> external_file:open(Path)
            end,
    %%
    %% Reply is {ok,{file_descriptor,prim_file,{#Port<0.1896>,14}}}
    %%
    {reply, Reply, State};
...
handle_info(Message, State) ->
    %%
    %% Message is {#Port<0.1896>,{data,[3,0,0,0,0,0,0,0,0]}}
    %%
    io:format("UNEXPECTED MESSAGE: ~p~n", [Message]),
    {noreply, State}
...

我认为这与文档中的以下内容有关:

  

IoDevice实际上是处理文件的进程的pid。此过程与最初打开文件的进程相关联。如果IoDevice链接到的任何进程终止,则文件将被关闭,进程本身将被终止。从此调用返回的IoDevice可用作IO函数的参数(请参阅io(3))。

有没有办法从gen_server打开文件,将其IoDevice交给另一个进程?

1 个答案:

答案 0 :(得分:1)

问题不在于文件:打开问题是在external_file中打开的端口驱动程序:open(Path)。 IoDevice可以被任何进程使用,但只有在创建过程存在时才可用。创建端口驱动程序的进程成为端口驱动程序的所有者,而只有该进程可以与端口驱动程序通信。如果返回Port ref并且任何其他进程访问它,程序可能会崩溃。

更好的方法是不返回端口。而是将数据作为消息获取,并使用相同的gen_server来读取/写入端口。