diff options
| author | Emile Joubert <emile@rabbitmq.com> | 2013-07-24 14:50:12 +0100 |
|---|---|---|
| committer | Emile Joubert <emile@rabbitmq.com> | 2013-07-24 14:50:12 +0100 |
| commit | de8baa212e5c47b01d131f9f06e049ab1b14e54e (patch) | |
| tree | dc1a67dbedf835472131393f6f1df1ea8455c069 | |
| parent | 9efcf2ec354e275d74ce45cba4c64125fd182405 (diff) | |
| download | rabbitmq-server-git-de8baa212e5c47b01d131f9f06e049ab1b14e54e.tar.gz | |
Write file using rename
| -rw-r--r-- | src/rabbit_file.erl | 53 |
1 files changed, 36 insertions, 17 deletions
diff --git a/src/rabbit_file.erl b/src/rabbit_file.erl index 3ceb4989c6..4412f04f98 100644 --- a/src/rabbit_file.erl +++ b/src/rabbit_file.erl @@ -24,6 +24,8 @@ -export([rename/2, delete/1, recursive_delete/1, recursive_copy/2]). -export([lock_file/1]). +-define(TMP_EXT, ".tmp"). + %%---------------------------------------------------------------------------- -ifdef(use_specs). @@ -136,26 +138,43 @@ write_term_file(File, Terms) -> write_file(Path, Data) -> write_file(Path, Data, []). -%% write_file/3 and make_binary/1 are both based on corresponding -%% functions in the kernel/file.erl module of the Erlang R14B02 -%% release, which is licensed under the EPL. That implementation of -%% write_file/3 does not do an fsync prior to closing the file, hence -%% the existence of this version. APIs are otherwise identical. write_file(Path, Data, Modes) -> Modes1 = [binary, write | (Modes -- [binary, write])], case make_binary(Data) of - Bin when is_binary(Bin) -> - with_fhc_handle( - fun () -> case prim_file:open(Path, Modes1) of - {ok, Hdl} -> try prim_file:write(Hdl, Bin) of - ok -> prim_file:sync(Hdl); - {error, _} = E -> E - after - prim_file:close(Hdl) - end; - {error, _} = E -> E - end - end); + Bin when is_binary(Bin) -> write_file1(Path, Bin, Modes1); + {error, _} = E -> E + end. + +write_file1(Path, Bin, Modes) -> + try + with_copy(Path, + fun (Copy) -> + with_sync(Copy, Modes, + fun (CopyHdl) -> + ok = prim_file:write(CopyHdl, Bin) + end) + end) + catch + error:{badmatch, Error} -> Error; + _:{error, Error} -> {error, Error} + end. + +with_copy(Path, Fun) -> + Bak = Path ++ ?TMP_EXT, + Result = Fun(Bak), + file:rename(Bak, Path), + ok = with_sync(Path, [binary], fun (_Hdl) -> ok end), + Result. + +with_sync(Path, Modes, Fun) -> + case prim_file:open(Path, Modes) of + {ok, Hdl} -> try + Result = Fun(Hdl), + ok = prim_file:sync(Hdl), + Result + after + prim_file:close(Hdl) + end; {error, _} = E -> E end. |
