%% This Source Code Form is subject to the terms of the Mozilla Public %% License, v. 2.0. If a copy of the MPL was not distributed with this %% file, You can obtain one at https://mozilla.org/MPL/2.0/. %% %% Copyright (c) 2017-2025 Broadcom. All Rights Reserved. The term Broadcom refers to Broadcom Inc. and/or its subsidiaries. %% @hidden -module(ra_log_pre_init). -behaviour(gen_server). -include("ra.hrl"). %% API functions -export([start_link/1]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -record(state, {}). -define(ETSTBL, ra_log_snapshot_state). %%%=================================================================== %%% API functions %%%=================================================================== start_link(System) when is_atom(System) -> gen_server:start_link(?MODULE, [System], []). %%%=================================================================== %%% gen_server callbacks %%%=================================================================== init([System]) -> %% ra_log:pre_init ensures that the ra_log_snapshot_state table is %% populated before WAL recovery begins to avoid writing unnecessary %% indexes to segment files. Regd = ra_directory:list_registered(System), ?INFO("ra system '~ts' running pre init for ~b registered servers", [System, length(Regd)]), _ = [begin try pre_init(System, UId) of ok -> ok catch _:Err -> ?ERROR("pre_init failed in system ~s for UId ~ts with name ~ts" " This error may need manual intervention, Error ~p", [System, UId, Name, Err]), ok end end|| {Name, UId} <- Regd], {ok, #state{} , hibernate}. handle_call(_Request, _From, State) -> Reply = ok, {reply, Reply, State}. handle_cast(_Msg, State) -> {noreply, State}. handle_info(_Info, State) -> {noreply, State}. terminate(_Reason, _State) -> ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. %%%=================================================================== %%% Internal functions %%%=================================================================== pre_init(System, UId) -> case ets:lookup(?ETSTBL, UId) of [{_, _}] -> %% already initialised ok; [] -> case ra_system:fetch(System) of undefined -> {error, system_not_started}; SysCfg -> %% check if the server dir exists, if not %% then just log and return instead of failing. Dir = ra_env:server_data_dir(System, UId), case ra_lib:is_dir(Dir) of true -> case ra_log:read_config(Dir) of {ok, #{log_init_args := Log}} -> ok = ra_log:pre_init(Log#{system_config => SysCfg}), ok; {error, Err} -> ?ERROR("pre_init failed to read config file for UId '~ts', Err ~p", [UId, Err]), ok end; false -> ?INFO("pre_init UId '~ts' is registered but no data directory was found, removing from ra directory", [UId]), _ = catch ra_directory:unregister_name(System, UId), ok end end end.