您的位置:首页 > 编程语言

riak ensemble代码中的文件检验

2016-05-27 00:00 162 查看
最近在看paxos协议,感觉很复杂,一步步来吧,学习的过程就是这样。

Mike Burrows, inventor of the Chubby service at Google, says that “there is only one consensus protocol, and that’s Paxos” – all other approaches are just broken versions of Paxos.

摘自:Consensus Protocols: Two-Phase Commit

相对来说,raft使用状态机来简化paxos协议,然后riak_ensemble实现的是Multi-Paxos协议。理论上说,Multi-Paxos比raft协议要并发强。

今天看到riak_ensemble中的文件检验,其中使用了CRC32检验。

[code=language-xml]%% 在riak_ensemble_save.erl文件中

write(File, Data) ->
CRC = erlang:crc32(Data),
Size = byte_size(Data),
Meta = <<CRC:32/integer, Size:32/integer>>,
Out = [Meta, Data,  %% copy 1
Data, Meta], %% copy 2
ok = filelib:ensure_dir(File),
try
_ = Out,
ok = riak_ensemble_util:replace_file(File, Out),
ok = riak_ensemble_util:replace_file(File ++ ".backup", Out),
ok
catch
_:Err ->
{error, Err}
end.

%% 在riak_ensemble_util.erl文件中
replace_file(FN, Data) ->
TmpFN = FN ++ ".tmp",
{ok, FH} = file:open(TmpFN, [write, raw]),
try
ok = file:write(FH, Data),
ok = file:sync(FH),
ok = file:close(FH),
ok = file:rename(TmpFN, FN),
{ok, Contents} = read_file(FN),
true = (Contents == iolist_to_binary(Data)),
ok
catch _:Err ->
{error, Err}
end.

read_file(FName) ->
case file:open(FName, [read, raw, binary]) of
{ok, FD} ->
Result = read_file(FD, []),
ok = file:close(FD),
case Result of
{ok, IOList} ->
{ok, iolist_to_binary(IOList)};
{error, _}=Err ->
Err
end;
{error,_}=Err ->
Err
end.

read_file(FD, Acc) ->
case file:read(FD, 4096) of
{ok, Data} ->
read_file(FD, [Data|Acc]);
eof ->
{ok, lists:reverse(Acc)};
{error, _}=Err ->
Err
end.

可以看到,写文件前,先检验文件内容的crc32值以及长度,然后同时写入文件和文件备份,写入后,再以4k对齐方式读入文件内容,确保文件写入没有问题。使用try catch 确保文件写入、同步、检验是在一个事务里面。然后在写入文件和文件备份时,使用try catch确保文件和文件备份是同时完成的。

然后是文件读入,这时也要检验:

[code=language-xml]%% 在riak_ensemble_save.erl 文件中
do_read(File) ->
case riak_ensemble_util:read_file(File) of
{ok, Binary} ->
safe_read(Binary);
{error, _} ->
not_found
end.

safe_read(<<CRC:32/integer, Size:32/integer, Data:Size/binary, Rest/binary>>) ->
case erlang:crc32(Data) of
CRC ->
{ok, Data};
_ ->
safe_read_backup(Rest)
end;
safe_read(Binary) ->
safe_read_backup(Binary).

safe_read_backup(Binary) when byte_size(Binary) =< 8 ->
not_found;
safe_read_backup(Binary) ->
BinSize = byte_size(Binary),
Skip = BinSize - 8,
<<_:Skip/binary, CRC:32/integer, Size:32/integer>> = Binary,
Skip2 = Skip - Size,
case Binary of
<<_:Skip2/binary, Data:Size/binary, _:8/binary>> ->
case erlang:crc32(Data) of
CRC ->
{ok, Data};
_ ->
not_found
end;
_ ->
not_found
end.

可以看到,读入文件时,会按照上面写入的规则通过crc32值来检验一下文件内容。如果检验失败,则尝试去掉内容头部,然后对内容按照规格检验。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: