ejabberd two functions with same name - erlang
iam new in erlang and OTP i have two questions :
iam trying to read some erlang code from ejabberd source, it's very complex and iam surprised with two start/0 functions and two start/1 functions too in ejabberd_logger.erl so
1-what's this ? which function code will be executed when calling start/1?
2-should i read and understand all ejabberd source code to modify and customize it like i want ? i see that it's a huge code but is this a must for good handling ?
-module(ejabberd_logger).
-compile({no_auto_import, [get/0]}).
%% API
-export([start/0, get/0, set/1, get_log_path/0, flush/0]).
-export([convert_loglevel/1, loglevels/0]).
-ifndef(LAGER).
-export([progress_filter/2]).
-endif.
%% Deprecated functions
-export([restart/0, reopen_log/0, rotate_log/0]).
-deprecated([{restart, 0},
{reopen_log, 0},
{rotate_log, 0}]).
-type loglevel() :: none | emergency | alert | critical |
error | warning | notice | info | debug.
-define(is_loglevel(L),
((L == none) or (L == emergency) or (L == alert)
or (L == critical) or (L == error) or (L == warning)
or (L == notice) or (L == info) or (L == debug))).
-export_type([loglevel/0]).
%%%===================================================================
%%% API
%%%===================================================================
-spec get_log_path() -> string().
get_log_path() ->
case ejabberd_config:env_binary_to_list(ejabberd, log_path) of
{ok, Path} ->
Path;
undefined ->
case os:getenv("EJABBERD_LOG_PATH") of
false ->
"ejabberd.log";
Path ->
Path
end
end.
-spec loglevels() -> [loglevel(), ...].
loglevels() ->
[none, emergency, alert, critical, error, warning, notice, info, debug].
-spec convert_loglevel(0..5) -> loglevel().
convert_loglevel(0) -> none;
convert_loglevel(1) -> critical;
convert_loglevel(2) -> error;
convert_loglevel(3) -> warning;
convert_loglevel(4) -> info;
convert_loglevel(5) -> debug.
quiet_mode() ->
case application:get_env(ejabberd, quiet) of
{ok, true} -> true;
_ -> false
end.
-spec get_integer_env(atom(), T) -> T.
get_integer_env(Name, Default) ->
case application:get_env(ejabberd, Name) of
{ok, I} when is_integer(I), I>=0 ->
I;
{ok, infinity} ->
infinity;
undefined ->
Default;
{ok, Junk} ->
error_logger:error_msg("wrong value for ~ts: ~p; "
"using ~p as a fallback~n",
[Name, Junk, Default]),
Default
end.
-ifdef(LAGER).
-spec get_string_env(atom(), T) -> T.
get_string_env(Name, Default) ->
case application:get_env(ejabberd, Name) of
{ok, L} when is_list(L) ->
L;
undefined ->
Default;
{ok, Junk} ->
error_logger:error_msg("wrong value for ~ts: ~p; "
"using ~p as a fallback~n",
[Name, Junk, Default]),
Default
end.
-spec start() -> ok.
start() ->
start(info).
start(Level) ->
StartedApps = application:which_applications(5000),
case lists:keyfind(logger, 1, StartedApps) of
%% Elixir logger is started. We assume everything is in place
%% to use lager to Elixir logger bridge.
{logger, _, _} ->
error_logger:info_msg("Ignoring ejabberd logger options, using Elixir Logger.", []),
%% Do not start lager, we rely on Elixir Logger
do_start_for_logger(Level);
_ ->
do_start(Level)
end.
do_start_for_logger(Level) ->
application:load(sasl),
application:set_env(sasl, sasl_error_logger, false),
application:load(lager),
application:set_env(lager, error_logger_redirect, false),
application:set_env(lager, error_logger_whitelist, ['Elixir.Logger.ErrorHandler']),
application:set_env(lager, crash_log, false),
application:set_env(lager, handlers, [{elixir_logger_backend, [{level, Level}]}]),
ejabberd:start_app(lager),
ok.
do_start(Level) ->
application:load(sasl),
application:set_env(sasl, sasl_error_logger, false),
application:load(lager),
ConsoleLog = get_log_path(),
Dir = filename:dirname(ConsoleLog),
ErrorLog = filename:join([Dir, "error.log"]),
CrashLog = filename:join([Dir, "crash.log"]),
LogRotateDate = get_string_env(log_rotate_date, ""),
LogRotateSize = case get_integer_env(log_rotate_size, 10*1024*1024) of
infinity -> 0;
V -> V
end,
LogRotateCount = get_integer_env(log_rotate_count, 1),
LogRateLimit = get_integer_env(log_rate_limit, 100),
ConsoleLevel0 = case quiet_mode() of
true -> critical;
_ -> Level
end,
ConsoleLevel = case get_lager_version() >= "3.6.0" of
true -> [{level, ConsoleLevel0}];
false -> ConsoleLevel0
end,
application:set_env(lager, error_logger_hwm, LogRateLimit),
application:set_env(
lager, handlers,
[{lager_console_backend, ConsoleLevel},
{lager_file_backend, [{file, ConsoleLog}, {level, Level}, {date, LogRotateDate},
{count, LogRotateCount}, {size, LogRotateSize}]},
{lager_file_backend, [{file, ErrorLog}, {level, error}, {date, LogRotateDate},
{count, LogRotateCount}, {size, LogRotateSize}]}]),
application:set_env(lager, crash_log, CrashLog),
application:set_env(lager, crash_log_date, LogRotateDate),
application:set_env(lager, crash_log_size, LogRotateSize),
application:set_env(lager, crash_log_count, LogRotateCount),
ejabberd:start_app(lager),
lists:foreach(fun(Handler) ->
lager:set_loghwm(Handler, LogRateLimit)
end, gen_event:which_handlers(lager_event)).
-spec restart() -> ok.
restart() ->
Level = ejabberd_option:loglevel(),
application:stop(lager),
start(Level).
-spec reopen_log() -> ok.
reopen_log() ->
ok.
-spec rotate_log() -> ok.
rotate_log() ->
catch lager_crash_log ! rotate,
lists:foreach(
fun({lager_file_backend, File}) ->
whereis(lager_event) ! {rotate, File};
(_) ->
ok
end, gen_event:which_handlers(lager_event)).
-spec get() -> loglevel().
get() ->
Handlers = get_lager_handlers(),
lists:foldl(fun(lager_console_backend, _Acc) ->
lager:get_loglevel(lager_console_backend);
(elixir_logger_backend, _Acc) ->
lager:get_loglevel(elixir_logger_backend);
(_, Acc) ->
Acc
end,
none, Handlers).
-spec set(0..5 | loglevel()) -> ok.
set(N) when is_integer(N), N>=0, N=<5 ->
set(convert_loglevel(N));
set(Level) when ?is_loglevel(Level) ->
case get() of
Level ->
ok;
_ ->
ConsoleLog = get_log_path(),
QuietMode = quiet_mode(),
lists:foreach(
fun({lager_file_backend, File} = H) when File == ConsoleLog ->
lager:set_loglevel(H, Level);
(lager_console_backend = H) when not QuietMode ->
lager:set_loglevel(H, Level);
(elixir_logger_backend = H) ->
lager:set_loglevel(H, Level);
(_) ->
ok
end, get_lager_handlers())
end,
case Level of
debug -> xmpp:set_config([{debug, true}]);
_ -> xmpp:set_config([{debug, false}])
end.
get_lager_handlers() ->
case catch gen_event:which_handlers(lager_event) of
{'EXIT',noproc} ->
[];
Result ->
Result
end.
-spec get_lager_version() -> string().
get_lager_version() ->
Apps = application:loaded_applications(),
case lists:keyfind(lager, 1, Apps) of
{_, _, Vsn} -> Vsn;
false -> "0.0.0"
end.
-spec flush() -> ok.
flush() ->
application:stop(lager),
application:stop(sasl).
-else.
-include_lib("kernel/include/logger.hrl").
-spec start() -> ok | {error, term()}.
start() ->
start(info).
start(Level) ->
EjabberdLog = get_log_path(),
Dir = filename:dirname(EjabberdLog),
ErrorLog = filename:join([Dir, "error.log"]),
LogRotateSize = get_integer_env(log_rotate_size, 10*1024*1024),
LogRotateCount = get_integer_env(log_rotate_count, 1),
Config = #{max_no_bytes => LogRotateSize,
max_no_files => LogRotateCount,
filesync_repeat_interval => no_repeat,
file_check => 1000,
sync_mode_qlen => 1000,
drop_mode_qlen => 1000,
flush_qlen => 5000},
FmtConfig = #{legacy_header => false,
time_designator => $ ,
max_size => 100*1024,
single_line => false},
FileFmtConfig = FmtConfig#{template => file_template()},
ConsoleFmtConfig = FmtConfig#{template => console_template()},
try
ok = logger:set_primary_config(level, Level),
DefaultHandlerId = get_default_handlerid(),
ok = logger:update_formatter_config(DefaultHandlerId, ConsoleFmtConfig),
case quiet_mode() of
true ->
ok = logger:set_handler_config(DefaultHandlerId, level, critical);
_ ->
ok
end,
case logger:add_primary_filter(progress_report,
{fun ?MODULE:progress_filter/2, stop}) of
ok -> ok;
{error, {already_exist, _}} -> ok
end,
case logger:add_handler(ejabberd_log, logger_std_h,
#{level => all,
config => Config#{file => EjabberdLog},
formatter => {logger_formatter, FileFmtConfig}}) of
ok -> ok;
{error, {already_exist, _}} -> ok
end,
case logger:add_handler(error_log, logger_std_h,
#{level => error,
config => Config#{file => ErrorLog},
formatter => {logger_formatter, FileFmtConfig}}) of
ok -> ok;
{error, {already_exist, _}} -> ok
end
catch _:{Tag, Err} when Tag == badmatch; Tag == case_clause ->
?LOG_CRITICAL("Failed to set logging: ~p", [Err]),
Err
end.
get_default_handlerid() ->
Ids = logger:get_handler_ids(),
case lists:member(default, Ids) of
true -> default;
false -> hd(Ids)
end.
-spec restart() -> ok.
restart() ->
ok.
progress_filter(#{level:=info,msg:={report,#{label:={_,progress}}}} = Event, _) ->
case get() of
debug ->
logger_filters:progress(Event#{level => debug}, log);
_ ->
stop
end;
progress_filter(Event, _) ->
Event.
console_template() ->
[time, " [", level, "] " | msg()].
file_template() ->
[time, " [", level, "] ", pid,
{mfa, ["#", mfa, {line, [":", line], []}], []}, " " | msg()].
msg() ->
[{logger_formatter, [[logger_formatter, title], ":", io_lib:nl()], []},
msg, io_lib:nl()].
-spec reopen_log() -> ok.
reopen_log() ->
ok.
-spec rotate_log() -> ok.
rotate_log() ->
ok.
-spec get() -> loglevel().
get() ->
#{level := Level} = logger:get_primary_config(),
Level.
-spec set(0..5 | loglevel()) -> ok.
set(N) when is_integer(N), N>=0, N=<5 ->
set(convert_loglevel(N));
set(Level) when ?is_loglevel(Level) ->
case get() of
Level -> ok;
PrevLevel ->
?LOG_NOTICE("Changing loglevel from '~s' to '~s'",
[PrevLevel, Level]),
logger:set_primary_config(level, Level),
case Level of
debug -> xmpp:set_config([{debug, true}]);
_ -> xmpp:set_config([{debug, false}])
end
end.
-spec flush() -> ok.
flush() ->
lists:foreach(
fun(#{id := HandlerId, module := logger_std_h}) ->
logger_std_h:filesync(HandlerId);
(#{id := HandlerId, module := logger_disk_log_h}) ->
logger_disk_log_h:filesync(HandlerId);
(_) ->
ok
end, logger:get_handler_config()).
-endif.
Here, the first version is protected by -ifdef(LAGER). and thus gets used if the macro LAGER is defined, and the second version comes after '-else.', and gets used if LAGER is not defined. (The first version uses the Lager library for logging, and the second version uses the newer built-in logger library.)
Related
How to speed up "Queue using Two Stacks" in Erlang [duplicate]
This question already has answers here: How to efficiently read thousand of lines from STDIN in Erlang? (2 answers) Closed 2 years ago. A common programming problem which I've done in Python, Java, etc. with no problem. The following in Erlang (which I'm just learning) runs very slowly (~44s user time for 10^5 operations), and I am lost as to why. As written on HackerRank, the program takes one line from stdin with an integer representing the number of operations that follow. Each subsequent line should be 1 X (enqueue X), 2 (dequeue and discard), or 3 (peek and print the next value on the queue). Am I using lists:reverse/1 incorrectly? -module(two_stacks). %% API exports -export([main/1]). enqueue(Num, F, B) -> {[Num | F], B}. dequeue(F, []) -> [_|B] = lists:reverse(F), {[], B}; dequeue(F, [_|B]) -> {F, B}. peek(F, []) -> [H|T] = lists:reverse(F), io:format(H), {[], [H|T]}; peek(F, [H|T]) -> io:format(H), {F, [H|T]}. dispatchOperation(_, {F, B}) -> [Code|Line] = io:get_line(""), case Code of 49 -> [_|Num] = Line, enqueue(Num, F, B); 50 -> dequeue(F, B); 51 -> peek(F, B) end. main(_) -> {Count, _} = string:to_integer(io:get_line("")), _ = lists:foldl(fun dispatchOperation/2, {[], []}, lists:seq(1, Count)), erlang:halt(0). https://www.hackerrank.com/challenges/queue-using-two-stacks/problem
Are you running an escript? If that's the case, you should add a -mode(compile). there, because otherwise it runs the script in interpreted mode. Also, you can compare the times against using the queue module (which is implemented using two stacks)
The issue is with the way I'm parsing input. See 46493207 for discussion. Since all the inputs are integers I was able to make use of the same technique used there. The completed code is: -module(solution). -export([main/0]). enqueue(Num, F, B) -> {[Num | F], B}. dequeue(F, []) -> [_|B] = lists:reverse(F), {[], B}; dequeue(F, [_|B]) -> {F, B}. peek(F, []) -> [H|T] = lists:reverse(F), io:format("~B~n", [H]), {[], [H|T]}; peek(F, [H|T]) -> io:format("~B~n", [H]), {F, [H|T]}. run(_, {F, B}) -> Line = io:get_line(""), [X| Y] = binary:split(Line, [<<$\s>>, <<$\n>>], [global]), Code = binary_to_integer(X), case Code of 1 -> Num = binary_to_integer(lists:nth(1, Y)), enqueue(Num, F, B); 2 -> dequeue(F, B); 3 -> peek(F, B) end. main() -> ok = io:setopts(standard_io, [binary]), {Count, _} = string:to_integer(io:get_line("")), _ = lists:foldl(fun run/2, {[], []}, lists:seq(1, Count)), erlang:halt(0).
Testing a gen_server module using Common Test
I have this (very simple) gen_server implementation: -module(rand_gen). -behaviour(gen_server). -define(BASE, 1000). %% Module Functionality -export([start/0]). -export([stop/1]). -export([uniform/1, uniform/2]). %% Callback Functions -export([code_change/3]). -export([init/1]). -export([handle_call/3]). -export([handle_cast/2]). -export([handle_info/2]). -export([terminate/2]). %%%======================================================================= %%% Export %%%======================================================================= -spec start() -> {ok, pid()} | {error, Reason :: term()}. start() -> gen_server:start(?MODULE, [], []). -spec stop(Pid) -> ok when Pid :: pid(). stop(Pid) -> gen_server:stop(Pid). -spec uniform(Pid, Max) -> number() when Pid :: pid(), Max :: non_neg_integer(). uniform(Pid, Max) -> gen_server:call(Pid, {uniform, #{max => Max}}). -spec uniform(Pid) -> number() when Pid :: pid(). uniform(Pid) -> gen_server:call(Pid, uniform). %%%======================================================================= %%% Callback Functions %%%======================================================================= code_change(_OldVsn, State, _Extra) -> {ok, State}. handle_call({uniform, Input = #{max := Max}}, _From, _State) -> {reply, rand:uniform(Max), Input}; handle_call(uniform, _From, State = #{max := Max}) -> {reply, rand:uniform(Max), State}; handle_call(Msg, From, State) -> io:format("Unexpected call [~p] from [~p]~n", [Msg, From]), {reply, {error, no_call, Msg}, State}. handle_cast(Msg, State) -> io:format("Unexpected cast [~p]~n", [Msg]), {noreply, State}. handle_info(Msg, State) -> io:format("Unexpected message ~p~n", [Msg]), {noreply, State}. init([]) -> io:format("Crypto strong seed initialized! Using [~p] as base value.~n", [?BASE]), <<I1:32/unsigned-integer, I2:32/unsigned-integer, I3:32/unsigned-integer>> = crypto:strong_rand_bytes(?BASE), _ = rand:seed(exsplus, {I1, I2, I3}), {ok, #{max => ?BASE}}. terminate(_Reason, _StateData) -> ok. %%%======================================================================= %%% Internal %%%======================================================================= Now I want to write a Common Test suite for testing it ‒ I just started learning this. -module(rand_gen_SUITE). -include_lib("common_test/include/ct.hrl"). -compile(export_all). %%%======================================================================= %%% Setup %%%======================================================================= all() -> [ {group, generate} ]. groups() -> [ {generate, %%[parallel, {repeat, 3}], [uniform] } ]. init_per_suite(Config) -> {ok, Pid} = rand_gen:start(), [{pid, Pid} | Config]. end_per_suite(_Config) -> ok. %%%======================================================================= %%% Test Cases %%%======================================================================= uniform(Config) -> Pid = ?config(pid, Config), true = is_number(rand_gen:uniform(Pid)). ...but every time I run the (super-small) suite/file I get back a weird message saying: ===> Running Common Test suites... %%% rand_gen_SUITE ==> init_per_suite: FAILED %%% rand_gen_SUITE ==> {{badmatch,<<3,217,51,126,122,17,213,209,222,82,29,106,213,128,218,98,129,12, 123,22,27,194,123,120,74,110,1,254,132,243,147,87,181,74,43,159, 163,94,58,224,18,40,46,190,134,198,43,225,57,81,109,216,64,245, 103,131,46,47,234,165,210,2,78,97,52,44,131,49,0,94,168,207,176, 214,38,69,235,105,116,240,92,37,112,17,16,47,86,0,179,4,167,61, 61,167,88,84,227,247,74,132,86,64,33,92,175,51,130,242,155,174, 167,126,142,100,123,35,77,159,198,113,105,182,43,61,130,173,169, 155,135,0,6,19,90,65,139,70,236,217,253,76,223,86,228,175,145, 198,89,40,251,158,6,193,177,66,202,199,110,39,130,232,28,37,176, 215,45,251,65,220,229,124,204,99,126,132,119,41,83,226,235,117, 152,69,179,211,10,97,194,128,147,134,26,240,175,218,188,204,82, 55,34,35,49,195,183,78,150,125,137,141,76,92,253,1,46,203,37,142, 224,236,8,252,94,129,89,108,84,133,88,213,56,127,255,48,172,26, 246,51,29,79,56,33,59,122,135,80,137,63,37,124,168,90,76,46,12, 155,241,182,16,218,147,227,16,110,9,51,213,74,216,18,51,219,12, 111,229,159,231,33,12,87,114,134,113,79,147,35,122,227,114,154, 52,164,223,95,66,162,136,231,174,47,93,10,66,62,63,76,196,232, 100,240,49,16,122,81,200,222,66,180,212,16,185,117,31,111,152, 216,10,125,212,138,203,219,31,67,94,170,181,160,225,189,182,10, 110,207,197,177,198,199,83,227,121,235,12,186,90,212,160,102,187, 99,61,127,123,255,76,36,63,190,197,175,167,175,132,230,187,162, 68,183,220,9,198,29,18,191,199,182,10,227,139,38,25,113,153,199, 80,244,13,55,62,153,250,165,218,137,211,210,129,123,35,67,226,20, 153,85,25,193,46,53,40,49,134,67,92,198,106,151,195,242,46,153, 223,187,163,100,205,108,253,191,192,220,65,101,15,32,161,41,25, 148,203,153,134,55,33,88,107,222,49,120,44,173,167,82,238,185, 213,107,164,45,64,28,180,253,34,131,92,49,112,202,188,1,36,59,81, 223,0,200,93,34,253,3,214,240,211,51,135,43,70,105,98,125,186, 131,129,85,246,147,167,238,32,176,54,92,250,200,73,63,246,72,159, 64,105,119,246,58,5,153,54,126,4,33,82,153,245,79,163,187,61,45, 172,173,30,45,148,252,230,74,80,213,132,45,52,202,101,234,98,30, 68,18,117,175,231,41,153,243,243,132,184,98,234,72,134,140,229, 239,205,136,228,223,52,189,118,250,195,178,126,33,56,142,247,242, 235,160,129,75,221,73,21,148,139,110,194,87,127,147,9,71,25,111, 218,6,206,38,3,208,154,128,236,127,96,155,223,25,164,139,80,170, 82,230,130,118,88,198,254,109,249,252,146,143,6,108,134,49,29, 152,215,67,74,96,240,109,6,97,36,145,250,234,48,145,17,144,217, 198,236,60,68,213,30,7,120,228,117,41,231,72,208,245,73,153,251, 64,195,16,201,250,12,143,23,138,23,215,74,5,180,228,133,236,61, 227,123,188,100,81,77,254,187,69,213,127,22,38,143,84,184,4,47, 47,124,245,230,221,105,105,36,220,28,52,200,195,104,7,78,155,250, 36,8,42,228,166,212,106,147,247,101,21,230,78,236,91,217,115,84, 76,125,193,18,136,103,85,104,33,102,7,235,250,197,139,238,187, 154,12,84,152,174,133,92,165,72,76,45,70,90,115,32,161,156,251, 197,103,70,141,168,220,223,251,252,14,249,172,40,122,53,69,137, 45,29,129,144,146,238,181,104,28,117,166,19,238,44,162,174,117, 250,21,62,155,39,149,221,207,48,168,19,35,209,53,188,31,122,99, 83,74,138,164,103,72,106,27,175,239,240,3,100,118,152,180,225,82, 227,60,108,66,223,165,173,183,46,166,23,85,236,141,238,166,160, 114,31,7,14,23,220,90,226,79,217,203,240,126,128,241,41,149,224, 148,130,86,130,244,12,27,237,123,234,0,68,164,165,250,235,87,243, 217,253,215,249,13,206,155,197,138,192,249,154,104,131,109,229, 126,77,216,127,254,55,170,192,100,90,49,30,78,209,249,140,184,81, 121,164,178,50,204,131,144,214,8,12,130,32,164,149,92,200,235, 145,48,162,244,238,114,47,251,31,79,242,186,111,117,207,16,178, 212,234,209,161,143,21,241,111,218,32,255,191,70,177,203,5,117, 182,148,199,231,93,118,76,72>>}, [{rand_gen,init,1, [{file,"/home/x80486/Workshop/erlang/erlang_basics/_build/test/lib/erlang_basics/src/rand_gen.erl"}, {line,74}]}, {rand_gen_SUITE,init_per_suite,1, [{file,"/home/x80486/Workshop/erlang/erlang_basics/_build/test/lib/erlang_basics/test/rand_gen_SUITE.erl"}, {line,34}]}, {test_server,ts_tc,3,[{file,"test_server.erl"},{line,1546}]}, {test_server,run_test_case_eval1,6,[{file,"test_server.erl"},{line,1147}]}, {test_server,run_test_case_eval,9,[{file,"test_server.erl"},{line,994}]}]} Any clues? Thanks in advance!
That’s because the result of crypto:strong_rand_bytes(?BASE) doesn’t match <<I1:32/unsigned-integer, I2:32/unsigned-integer, I3:32/unsigned-integer>> since it’s (as you can see in the error) longer than that. You can try changing that line in your code to something like: <<I1:32/unsigned-integer, I2:32/unsigned-integer, I3:32/unsigned-integer, _/bitstring>> = crypto:strong_rand_bytes(?BASE),
extract sub string
I develop this function in erlang : get_user_cin_by_token(Token) -> Q = qlc:q([{X#person.idcard} || X <- mnesia:table(person), X#person.token =:= Token]), case do(Q) of [H] -> {ok, H}; [] -> {error, notfound} end. this is an example of result when I execute this function : {ok,{"07049200"}} my goal is to disply just "07049200" without {} I test with this function : test3()-> case get_user_cin_by_token("93090612") of {ok, H}-> G=string:substr(H, 2, length(H)-1), io:format("~s~n",[G]); {error, notfound}->io:format("error") end. but this error is displyed : ** exception error: bad argument in function length/1 called as length({"07049200"})
{"07049200"} is not a string; it's a tuple. Hence, you can "unpack" it by pattern matching: {H} = {"07049200"} will result in H=07049200. In your original code you can do: get_user_cin_by_token(Token) -> Q = qlc:q([{X#person.idcard} || X <- mnesia:table(person), X#person.token =:= Token]), case do(Q) of [{H}] -> {ok, H}; [] -> {error, notfound} end.
Try this: test3()-> case get_user_cin_by_token("93090612") of {ok, {H}}-> io:format("\"~s\"~n",[H]); {error, notfound}->io:format("error") end.
how to backup/restore only single table from/to mnesia?
I have some big tables with disc_only_copies type. Now I need change short node name to long but cannot do it with RAM limitation... Can I use backup/restore database partly (table by table)?
-module(test). -compile(export_all). -record(tab, {first, second}). do() -> mnesia:create_schema([node()]), mnesia:start(), mnesia:create_table(tab, [{disc_copies, [node()]}, {attributes, record_info(fields, tab)}]), mnesia:dirty_write({tab, 1, 2}), mnesia:dirty_write({tab, a, b}), mnesia:stop(). change_node('extra#localhost') -> 'extra#example.com'; change_node('ejabberd#localhost') -> 'ejabberd#example.com'; change_node(Node) -> Node. handle_nodes(Nodes) -> lists:map(fun(Node) -> change_node(Node) end, Nodes -- [one#badhost, extra#badhost]). handle_cookie({TS, Node}) -> {TS, change_node(Node)}. handle_version_value([]) -> []; handle_version_value({'one#badhost', _}) -> []; handle_version_value({'extra#badhost', _}) -> []; handle_version_value({Node, TS}) -> {change_node(Node), TS}. handle_version({Key, Value}) -> {Key, handle_version_value(Value)}. handle_def(Def) -> lists:map(fun({Key, Value} = Property) -> case Key of ram_copies -> {Key, handle_nodes(Value)}; disc_copies -> {Key, handle_nodes(Value)}; disc_only_copies -> {Key, handle_nodes(Value)}; cookie -> {Key, handle_cookie(Value)}; version -> {Key, handle_version(Value)}; _ -> Property end end, Def). go() -> {ok, N} = dets:open_file(schema, [{file, "./schema.DAT"},{repair,false}, {keypos, 2}]), do2(N), dets:sync(N), dets:close(N). do2(N) -> do2(N, dets:first(N)). do2(_N, '$end_of_table') -> ok; do2(N, Key) -> io:format("process: ~p~n", [Key]), [{N, Tab, Def}] = dets:lookup(N, Key), NewDef = handle_def(Def), dets:insert(N, {N, Tab, NewDef}), % file:write_file("schema.txt", io_lib:format("~p~n", [{N, Tab, NewDef}]), [append]), do2(N, dets:next(N, Key)).
The most efficient way to read a file into a list of strings
What is the most efficient way from the time consumed to read a text file into a list of binary strings in erlang ? The obvious solution -module(test). -export([run/1]). open_file(FileName, Mode) -> {ok, Device} = file:open(FileName, [Mode, binary]), Device. close_file(Device) -> ok = file:close(Device). read_lines(Device, L) -> case io:get_line(Device, L) of eof -> lists:reverse(L); String -> read_lines(Device, [String | L]) end. run(InputFileName) -> Device = open_file(InputFileName, read), Data = read_lines(Device, []), close_file(Device), io:format("Read ~p lines~n", [length(Data)]). becomes too slow when the file contains more than 100000 lines.
{ok, Bin} = file:read_file(Filename). or if you need the contents line by line read(File) -> case file:read_line(File) of {ok, Data} -> [Data | read(File)]; eof -> [] end.
read the entire file in into a binary. Convert to a list and rip out the lines. This is far more efficient than any other method. If you don't believe me time it. file2lines(File) -> {ok, Bin} = file:read_file(File), string2lines(binary_to_list(bin), []). string2lines("\n" ++ Str, Acc) -> [reverse([$\n|Acc]) | string2lines(Str,[])]; string2lines([H|T], Acc) -> string2lines(T, [H|Acc]); string2lines([], Acc) -> [reverse(Acc)].