Packages
ra
0.9.2
3.1.9
3.1.8
3.1.7
3.1.6
3.1.5
3.1.4
3.1.3
3.1.2
3.1.1
3.1.0
3.0.2
3.0.1
3.0.0
3.0.0-beta.1
2.17.3
2.17.2
2.17.1
2.17.0
2.16.13
2.16.12
2.16.11
2.16.10
2.16.9
2.16.8
2.16.7
2.16.6
2.16.5
2.16.4
2.16.3
2.16.2
2.16.1
2.16.0
2.16.0-pre.12
2.16.0-pre.11
2.16.0-pre.10
2.16.0-pre.9
2.16.0-pre.8
2.16.0-pre.7
2.16.0-pre.6
2.16.0-pre.5
2.16.0-pre.4
2.16.0-pre.3
2.16.0-pre.2
2.16.0-pre.1
2.15.4
2.15.3
2.15.2
2.15.1
2.15.0
2.14.0
2.13.6
2.13.5
2.13.4
2.13.3
2.13.2
2.13.1
2.13.0
2.13.0-pre.1
2.12.0
2.11.0
2.11.0-pre.1
2.10.2-pre.2
2.10.2-pre.1
2.10.1
2.10.0
2.10.0-pre.3
2.10.0-pre.2
2.10.0-pre.1
2.9.10-pre.1
2.9.1
2.9.1-pre.2
2.9.1-pre.1
2.9.0
2.8.0
retired
2.7.3
2.7.2
2.7.1
2.7.0
2.7.0-pre.3
2.7.0-pre.2
2.7.0-pre.1
2.6.3
2.6.2
2.6.1
2.6.0-pre.1
2.5.1
2.5.1-pre.1
2.5.0
2.4.9
2.4.8
2.4.7
2.4.6
2.4.5
2.4.4
2.4.3
2.4.2
retired
2.4.1
2.4.0
2.3.0
2.2.0
2.1.0
2.0.13
2.0.12
2.0.11
2.0.10
2.0.9
2.0.8
2.0.7
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.9.6
0.9.5
0.9.4
0.9.2
0.3.3
retired
0.3.2
retired
0.3.1
retired
Raft library
Current section
Files
Jump to
Current section
Files
src/ra_log_snapshot.erl
%% @hidden
-module(ra_log_snapshot).
-export([
write/2,
read/1,
read_indexterm/1
]).
-include("ra.hrl").
-define(MAGIC, "RASN").
-define(VERSION, 1).
-type file_err() :: file:posix() | badarg | terminated | system_limit.
-type state() :: {ra_index(), ra_term(), ra_cluster_servers(), term()}.
-export_type([state/0]).
%% @doc
%% Snapshot file format:
%% "RASN"
%% Version (byte)
%% Checksum (unsigned 32)
%% Index (unsigned 64)
%% Term (unsigned 64)
%% Num cluster servers (byte)
%% [DataLen (byte), Data (binary)]
%% Snapshot Data (binary)
%% @end
-spec write(file:filename(), state()) ->
ok | {error, file_err()}.
write(File, {Idx, Term, ClusterServers, MacState}) ->
Bin = term_to_binary(MacState),
Data = [<<Idx:64/unsigned,
Term:64/unsigned,
(length(ClusterServers)):8/unsigned>>,
[begin
B = term_to_binary(N),
<<(byte_size(B)):8/unsigned,
B/binary>>
end || N <- ClusterServers],
Bin],
Checksum = erlang:crc32(Data),
file:write_file(File, [<<?MAGIC,
1:8/unsigned,
Checksum:32/integer>>,
Data]).
-spec read(file:filename()) ->
{ok, state()} | {error, invalid_format |
{invalid_version, integer()} |
checksum_error |
file_err()}.
read(File) ->
case file:read_file(File) of
{ok, <<?MAGIC, ?VERSION:8/unsigned, Crc:32/integer, Data/binary>>} ->
validate(Crc, Data);
{ok, <<?MAGIC, Version:8/unsigned, _:32/integer, _/binary>>} ->
{error, {invalid_version, Version}};
{ok, _} ->
{error, invalid_format};
{error, _} = Err ->
Err
end.
%% @doc reads the index and term from the snapshot file without reading the
%% entire binary body. NB: this does not do checksum validation.
-spec read_indexterm(file:filename()) ->
{ok, ra_idxterm()} | {error, invalid_format |
{invalid_version, integer()} |
checksum_error |
file_err()}.
read_indexterm(File) ->
case file:open(File, [read, binary, raw]) of
{ok, Fd} ->
case file:read(Fd, 9 + 16) of
{ok, <<?MAGIC, ?VERSION:8/unsigned, _:32/integer,
Idx:64/unsigned,
Term:64/unsigned>>} ->
{ok, {Idx, Term}};
{ok, <<?MAGIC, Version:8/unsigned, _:32/integer, _/binary>>} ->
{error, {invalid_version, Version}};
{ok, _} ->
{error, invalid_format};
Err ->
Err
end;
{error, _} = Err ->
Err
end.
%% Internal
validate(Crc, Data) ->
case erlang:crc32(Data) of
Crc ->
{ok, parse_snapshot(Data)};
_ ->
{error, checksum_error}
end.
parse_snapshot(<<Idx:64/unsigned, Term:64/unsigned,
NumServers:8/unsigned, Rest0/binary>>) ->
{Servers, Rest} = parse_servers(NumServers, [], Rest0),
{Idx, Term, Servers, binary_to_term(Rest)}.
parse_servers(0, Servers, Data) ->
{lists:reverse(Servers), Data};
parse_servers(Num, Servers, <<Len:8/unsigned, ServerData:Len/binary, Rem/binary>>) ->
parse_servers(Num - 1, [binary_to_term(ServerData) | Servers], Rem).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.