%% @hidden -module(ra_log_snapshot_writer). -behaviour(gen_server). -include("ra.hrl"). %% API functions -export([start_link/0, write_snapshot/3, write_snapshot_call/2 ]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -record(state, {}). %%%=================================================================== %%% API functions %%%=================================================================== -spec write_snapshot(pid(), file:filename_all(), ra_log:snapshot()) -> ok. write_snapshot(From, Dir, Snapshot) -> gen_server:cast(?MODULE, {write_snapshot, From, Dir, Snapshot}). -spec write_snapshot_call(file:filename(), ra_log:snapshot()) -> {ok, File :: file:filename(), Old :: [file:filename()]}. write_snapshot_call(Dir, Snapshot) -> gen_server:call(?MODULE, {write_snapshot, Dir, Snapshot}). start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). %%%=================================================================== %%% gen_server callbacks %%%=================================================================== init([]) -> {ok, #state{}}. handle_call({write_snapshot, Dir, Snapshot}, _From, State) -> Reply = write_snapshot(Dir, Snapshot), {reply, Reply, State}. handle_cast({write_snapshot, From, Dir, Snapshot}, State) -> ok = handle_write_snapshot(From, Dir, Snapshot), {noreply, State}. handle_info(_Info, State) -> {noreply, State}. terminate(_Reason, _State) -> ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. %%%=================================================================== %%% Internal functions %%%=================================================================== handle_write_snapshot(From, Dir, {Index, Term, _, _} = Snapshot) -> {ok, File, Old} = write_snapshot(Dir, Snapshot), From ! {ra_log_event, {snapshot_written, {Index, Term}, File, Old}}, ok. write_snapshot(Dir, Snapshot) -> case lists:sort(filelib:wildcard(filename:join(Dir, "*.snapshot"))) of [] -> % no snapshots - initialise snapshot counter File = filename:join(Dir, ra_lib:zpad_filename("", "snapshot", 1)), ok = write(File, Snapshot), {ok, File, []}; [LastFile | _] = Old -> File = ra_lib:zpad_filename_incr(LastFile), ok = write(File, Snapshot), {ok, File, Old} end. write(File, Snapshot) -> % TODO: snapshots should be checksummed ?INFO("snapshot_writer: Writing file ~p", [File]), ra_log_snapshot:write(File, Snapshot).