remove mnesia

This commit is contained in:
anlicheng 2025-08-13 17:13:09 +08:00
parent cab9bb538c
commit f51756e4b5
10 changed files with 208 additions and 327 deletions

View File

@ -8,7 +8,6 @@
sync,
jiffy,
%gpb,
mnesia,
parse_trans,
lager,
crypto,

View File

@ -11,44 +11,9 @@
start(_StartType, _StartArgs) ->
io:setopts([{encoding, unicode}]),
%% mnesia数据库
start_mnesia(),
%%
erlang:system_flag(fullsweep_after, 16),
efka_sup:start_link().
stop(_State) ->
ok.
%% internal functions
%%
start_mnesia() ->
%%
ensure_mnesia_schema(),
ok = mnesia:start(),
Tables = mnesia:system_info(tables),
lager:debug("[efka_app] tables: ~p", [Tables]),
%%
not lists:member(id_generator, Tables) andalso id_generator_model:create_table(),
not lists:member(service, Tables) andalso service_model:create_table(),
not lists:member(cache, Tables) andalso cache_model:create_table(),
not lists:member(task_log, Tables) andalso task_log_model:create_table(),
ok.
-spec ensure_mnesia_schema() -> any().
ensure_mnesia_schema() ->
case mnesia:system_info(use_dir) of
true ->
lager:debug("[efka_app] mnesia schema exists"),
ok;
false ->
mnesia:stop(),
case mnesia:create_schema([node()]) of
ok -> ok;
{error, {_, {already_exists, _}}} -> ok;
Error ->
lager:debug("[iot_app] create mnesia schema failed with error: ~p", [Error]),
throw({init_schema, Error})
end
end.
ok.

View File

@ -0,0 +1,75 @@
%%%-------------------------------------------------------------------
%%% @author anlicheng
%%% @copyright (C) 2025, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 18. 4 2025 16:42
%%%-------------------------------------------------------------------
-module(efka_model_sup).
-author("anlicheng").
-include("efka_tables.hrl").
-behaviour(supervisor).
%% API
-export([start_link/0]).
-export([start_service/1, stop_service/1]).
%% Supervisor callbacks
-export([init/1]).
-define(SERVER, ?MODULE).
%%%===================================================================
%%% API functions
%%%===================================================================
%% @doc Starts the supervisor
-spec(start_link() -> {ok, Pid :: pid()} | ignore | {error, Reason :: term()}).
start_link() ->
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
%%%===================================================================
%%% Supervisor callbacks
%%%===================================================================
%% @private
%% @doc Whenever a supervisor is started using supervisor:start_link/[2,3],
%% this function is called by the new process to find out about
%% restart strategy, maximum restart frequency and child
%% specifications.
init([]) ->
SupFlags = #{strategy => one_for_one, intensity => 1000, period => 3600},
Specs = [
#{
id => cache_model,
start => {cache_model, start_link, []},
restart => permanent,
shutdown => 5000,
type => worker,
modules => ['cache_model']
},
#{
id => service_model,
start => {service_model, start_link, []},
restart => permanent,
shutdown => 5000,
type => worker,
modules => ['service_model']
},
#{
id => task_log_model,
start => {task_log_model, start_link, []},
restart => permanent,
shutdown => 5000,
type => worker,
modules => ['task_log_model']
}
],
{ok, {SupFlags, Specs}}.
%%%===================================================================
%%% Internal functions
%%%===================================================================

View File

@ -28,6 +28,15 @@ start_link() ->
init([]) ->
SupFlags = #{strategy => one_for_one, intensity => 1000, period => 3600},
ChildSpecs = [
#{
id => 'efka_model_sup',
start => {'efka_model_sup', start_link, []},
restart => permanent,
shutdown => 2000,
type => supervisor,
modules => ['efka_model_sup']
},
#{
id => 'efka_inetd_task_log',
start => {'efka_inetd_task_log', start_link, []},

View File

@ -1,74 +0,0 @@
%%%-------------------------------------------------------------------
%%% @author aresei
%%% @copyright (C) 2023, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 04. 7 2023 12:31
%%%-------------------------------------------------------------------
-module(cache_model).
-author("aresei").
-include("efka_tables.hrl").
-include_lib("stdlib/include/qlc.hrl").
-define(TAB, cache).
%% API
-export([create_table/0]).
-export([insert/2, get_all_cache/0, fetch_next/0, delete/1, next_id/0]).
-export([first_key/0]).
create_table() ->
%% id生成器
{atomic, ok} = mnesia:create_table(cache, [
{attributes, record_info(fields, cache)},
{record_name, cache},
{disc_copies, [node()]},
{type, ordered_set}
]).
next_id() ->
id_generator_model:next_id(?TAB).
-spec insert(Method :: integer(), Data :: binary()) -> ok | {error, Reason :: any()}.
insert(Method, Data) when is_integer(Method), is_binary(Data) ->
Cache = #cache{id = next_id(), method = Method, data = Data},
case mnesia:transaction(fun() -> mnesia:write(?TAB, Cache, write) end) of
{'atomic', ok} ->
ok;
{'aborted', Reason} ->
{error, Reason}
end.
fetch_next() ->
case mnesia:dirty_first(?TAB) of
'$end_of_table' ->
error;
Id ->
[Entry] = mnesia:dirty_read(?TAB, Id),
{ok, Entry}
end.
delete(Id) when is_integer(Id) ->
case mnesia:transaction(fun() -> mnesia:delete(?TAB, Id, write) end) of
{'atomic', ok} ->
ok;
{'aborted', Reason} ->
{error, Reason}
end.
-spec get_all_cache() -> [#cache{}].
get_all_cache() ->
Fun = fun() ->
Q = qlc:q([E || E <- mnesia:table(?TAB)]),
qlc:e(Q)
end,
case mnesia:transaction(Fun) of
{'atomic', Res} ->
Res;
{'aborted', _} ->
[]
end.
first_key() ->
mnesia:dirty_first(?TAB).

View File

@ -1,26 +0,0 @@
%%%-------------------------------------------------------------------
%%% @author anlicheng
%%% @copyright (C) 2025, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 06. 5 2025 10:32
%%%-------------------------------------------------------------------
-module(id_generator_model).
-author("anlicheng").
-include("efka_tables.hrl").
%% API
-export([create_table/0, next_id/1]).
create_table() ->
%% id生成器
{atomic, ok} = mnesia:create_table(id_generator, [
{attributes, record_info(fields, id_generator)},
{record_name, id_generator},
{disc_copies, [node()]},
{type, ordered_set}
]).
next_id(Tab) when is_atom(Tab) ->
mnesia:dirty_update_counter(id_generator, Tab, 1).

View File

@ -1,140 +0,0 @@
%%%-------------------------------------------------------------------
%%% @author aresei
%%% @copyright (C) 2023, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 04. 7 2023 12:31
%%%-------------------------------------------------------------------
-module(service_model).
-author("aresei").
-include("efka_tables.hrl").
-include_lib("stdlib/include/qlc.hrl").
-define(TAB, service).
%% API
-export([create_table/0]).
-export([insert/1, get_all_services/0, get_all_service_ids/0, get_running_services/0]).
-export([get_config_json/1, set_config/2, get_service/1, get_status/1, change_status/2]).
-export([display_services/0]).
create_table() ->
%% id生成器
{atomic, ok} = mnesia:create_table(service, [
{attributes, record_info(fields, service)},
{record_name, service},
{disc_copies, [node()]},
{type, ordered_set}
]).
insert(Service = #service{}) ->
case mnesia:transaction(fun() -> mnesia:write(?TAB, Service, write) end) of
{'atomic', Res} ->
Res;
{'aborted', Reason} ->
{error, Reason}
end.
change_status(ServiceId, NewStatus) when is_binary(ServiceId), is_integer(NewStatus) ->
Fun = fun() ->
case mnesia:read(?TAB, ServiceId, write) of
[] ->
mnesia:abort(<<"service not found">>);
[Service] ->
mnesia:write(?TAB, Service#service{status = NewStatus}, write)
end
end,
case mnesia:transaction(Fun) of
{'atomic', ok} ->
ok;
{'aborted', Reason} ->
{error, Reason}
end.
-spec set_config(ServiceId :: binary(), ConfigJson :: binary()) -> ok | {error, Reason :: any()}.
set_config(ServiceId, ConfigJson) when is_binary(ServiceId), is_binary(ConfigJson) ->
Fun = fun() ->
case mnesia:read(?TAB, ServiceId, write) of
[] ->
mnesia:abort(<<"service not found">>);
[S] ->
mnesia:write(?TAB, S#service{config_json = ConfigJson}, write)
end
end,
case mnesia:transaction(Fun) of
{'atomic', ok} ->
ok;
{'aborted', Reason} ->
{error, Reason}
end.
-spec get_config_json(ServiceId :: binary()) -> error | {ok, ConfigJson :: binary()}.
get_config_json(ServiceId) when is_binary(ServiceId) ->
case mnesia:dirty_read(?TAB, ServiceId) of
[] ->
error;
[#service{config_json = ConfigJson}] ->
{ok, ConfigJson}
end.
-spec get_status(ServiceId :: binary()) -> Status :: integer().
get_status(ServiceId) when is_binary(ServiceId) ->
case mnesia:dirty_read(?TAB, ServiceId) of
[] ->
0;
[#service{status = Status}] ->
Status
end.
-spec get_service(ServiceId :: binary()) -> error | {ok, Service :: #service{}}.
get_service(ServiceId) when is_binary(ServiceId) ->
case mnesia:dirty_read(?TAB, ServiceId) of
[] ->
error;
[Service] ->
{ok, Service}
end.
-spec get_all_services() -> [#service{}].
get_all_services() ->
Fun = fun() ->
Q = qlc:q([E || E <- mnesia:table(?TAB)]),
qlc:e(Q)
end,
case mnesia:transaction(Fun) of
{'atomic', Res} ->
Res;
{'aborted', _} ->
[]
end.
-spec get_all_service_ids() -> [ServiceId :: binary()].
get_all_service_ids() ->
mnesia:dirty_all_keys(?TAB).
-spec get_running_services() -> {ok, [#service{}]} | {error, Reason :: term()}.
get_running_services() ->
F = fun() ->
Q = qlc:q([E || E <- mnesia:table(?TAB), E#service.status == 1]),
qlc:e(Q)
end,
case mnesia:transaction(F) of
{atomic, Services} ->
{ok, Services};
{aborted, Error} ->
{error, Error}
end.
display_services() ->
F = fun() ->
Q = qlc:q([E || E <- mnesia:table(?TAB)]),
qlc:e(Q)
end,
case mnesia:transaction(F) of
{atomic, Services} ->
{ok, Services};
{aborted, Error} ->
{error, Error}
end.

View File

@ -1,46 +0,0 @@
%%%-------------------------------------------------------------------
%%% @author aresei
%%% @copyright (C) 2023, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 04. 7 2023 12:31
%%%-------------------------------------------------------------------
-module(task_log_model).
-author("aresei").
-include("efka_tables.hrl").
-include_lib("stdlib/include/qlc.hrl").
-define(TAB, task_log).
%% API
-export([create_table/0]).
-export([insert/2, get_logs/1]).
create_table() ->
%% id生成器
{atomic, ok} = mnesia:create_table(task_log, [
{attributes, record_info(fields, task_log)},
{record_name, task_log},
{disc_copies, [node()]},
{type, ordered_set}
]).
-spec insert(TaskId :: integer(), Logs :: [binary()]) -> ok | {error, Reason :: term()}.
insert(TaskId, Logs) when is_integer(TaskId), is_list(Logs) ->
TaskLog = #task_log{task_id = TaskId, logs = Logs},
case mnesia:transaction(fun() -> mnesia:write(?TAB, TaskLog, write) end) of
{'atomic', Res} ->
Res;
{'aborted', Reason} ->
{error, Reason}
end.
-spec get_logs(TaskId :: integer()) -> Logs :: [binary()].
get_logs(TaskId) when is_integer(TaskId) ->
case mnesia:dirty_read(?TAB, TaskId) of
[] ->
[];
[#task_log{logs = Logs}] ->
Logs
end.

View File

@ -14,6 +14,7 @@
%% API
-export([start_link/0]).
-export([insert/1, change_status/2, set_config/2, get_config_json/1, get_status/1, get_service/1, get_all_services/0, get_running_services/0]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
@ -55,10 +56,6 @@ get_service(ServiceId) when is_binary(ServiceId) ->
get_all_services() ->
gen_server:call(?SERVER, get_all_services).
-spec get_all_service_ids() -> [ServiceId :: binary()].
get_all_service_ids() ->
gen_server:call(?SERVER, get_all_service_ids).
-spec get_running_services() -> {ok, [#service{}]} | {error, Reason :: term()}.
get_running_services() ->
gen_server:call(?SERVER, get_running_services).

View File

@ -0,0 +1,122 @@
%%%-------------------------------------------------------------------
%%% @author anlicheng
%%% @copyright (C) 2025, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 13. 8 2025 17:01
%%%-------------------------------------------------------------------
-module(task_log_model).
-author("anlicheng").
-include("efka_tables.hrl").
-behaviour(gen_server).
%% API
-export([start_link/0]).
-export([insert/2, get_logs/1]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-define(SERVER, ?MODULE).
-define(TAB, task_log).
-record(state, {
}).
%%%===================================================================
%%% API
%%%===================================================================
-spec insert(TaskId :: integer(), Logs :: [binary()]) -> ok | {error, Reason :: term()}.
insert(TaskId, Logs) when is_integer(TaskId), is_list(Logs) ->
TaskLog = #task_log{task_id = TaskId, logs = Logs},
gen_server:call(?SERVER, {insert, TaskLog}).
-spec get_logs(TaskId :: integer()) -> Logs :: [binary()].
get_logs(TaskId) when is_integer(TaskId) ->
gen_server:call(?SERVER, {get_logs, TaskId}).
%% @doc Spawns the server and registers the local name (unique)
-spec(start_link() ->
{ok, Pid :: pid()} | ignore | {error, Reason :: term()}).
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
%% @private
%% @doc Initializes the server
-spec(init(Args :: term()) ->
{ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} |
{stop, Reason :: term()} | ignore).
init([]) ->
{ok, DetsDir} = application:get_env(efka, dets_dir),
File = DetsDir ++ "task_log.dets",
{ok, ?TAB} = dets:open_file(?TAB, [{file, File}, {type, set}, {keypos, 2}]),
{ok, #state{}}.
%% @private
%% @doc Handling call messages
-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()},
State :: #state{}) ->
{reply, Reply :: term(), NewState :: #state{}} |
{reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} |
{noreply, NewState :: #state{}} |
{noreply, NewState :: #state{}, timeout() | hibernate} |
{stop, Reason :: term(), Reply :: term(), NewState :: #state{}} |
{stop, Reason :: term(), NewState :: #state{}}).
handle_call({insert, TaskLog}, _From, State = #state{}) ->
ok = dets:insert(?TAB, TaskLog),
{reply, ok, State};
handle_call({get_logs, TaskId}, _From, State = #state{}) ->
Reply = case dets:lookup(?TAB, TaskId) of
[] ->
[];
[#task_log{logs = Logs}|_] ->
Logs
end,
{reply, Reply, State}.
%% @private
%% @doc Handling cast messages
-spec(handle_cast(Request :: term(), State :: #state{}) ->
{noreply, NewState :: #state{}} |
{noreply, NewState :: #state{}, timeout() | hibernate} |
{stop, Reason :: term(), NewState :: #state{}}).
handle_cast(_Request, State = #state{}) ->
{noreply, State}.
%% @private
%% @doc Handling all non call/cast messages
-spec(handle_info(Info :: timeout() | term(), State :: #state{}) ->
{noreply, NewState :: #state{}} |
{noreply, NewState :: #state{}, timeout() | hibernate} |
{stop, Reason :: term(), NewState :: #state{}}).
handle_info(_Info, State = #state{}) ->
{noreply, State}.
%% @private
%% @doc This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any
%% necessary cleaning up. When it returns, the gen_server terminates
%% with Reason. The return value is ignored.
-spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()),
State :: #state{}) -> term()).
terminate(_Reason, _State = #state{}) ->
ok.
%% @private
%% @doc Convert process state when code is changed
-spec(code_change(OldVsn :: term() | {down, term()}, State :: #state{},
Extra :: term()) ->
{ok, NewState :: #state{}} | {error, Reason :: term()}).
code_change(_OldVsn, State = #state{}, _Extra) ->
{ok, State}.
%%%===================================================================
%%% Internal functions
%%%===================================================================