Safe Insert , to avoid the 2GB table limit on mnesia.
parent
0cf55ca2ec
commit
ea942d56f0
|
@ -19,7 +19,7 @@ erl_crash.dump
|
||||||
*.d
|
*.d
|
||||||
|
|
||||||
# File temporanei di Mnesia (database locale)
|
# File temporanei di Mnesia (database locale)
|
||||||
Mnesia.*
|
mnesia.*
|
||||||
|
|
||||||
# File temporanei di editor
|
# File temporanei di editor
|
||||||
*~
|
*~
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
%% db_safe_insert.hrl
|
||||||
|
|
||||||
|
-record(global_message, {id, activity, timestamp}).
|
||||||
|
-record(ap_users, {id, name, email, created_at}).
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -10,8 +10,8 @@
|
||||||
start(_Type, _Args) ->
|
start(_Type, _Args) ->
|
||||||
|
|
||||||
%% creiamo un utente di test, solo per vedere se mnesia va
|
%% creiamo un utente di test, solo per vedere se mnesia va
|
||||||
user_db:init(),
|
db_organization:setup(),
|
||||||
timeline_db:init(),
|
db_organization:init(),
|
||||||
users_local_check:check_ENV(), %% controlla le variabili d'ambiente
|
users_local_check:check_ENV(), %% controlla le variabili d'ambiente
|
||||||
|
|
||||||
%% aggiungiamo un paio di utenti di esempio.
|
%% aggiungiamo un paio di utenti di esempio.
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
-module(db_organization).
|
||||||
|
-export([setup/0, init/0]).
|
||||||
|
|
||||||
|
%% 1. Imposta la directory di Mnesia leggendo la variabile di ambiente
|
||||||
|
setup() ->
|
||||||
|
case os:getenv("AP_DB_DIR") of
|
||||||
|
false ->
|
||||||
|
io:format("Errore: la variabile di ambiente AP_DB_DIR non è settata!~n"),
|
||||||
|
erlang:halt(1);
|
||||||
|
Dir ->
|
||||||
|
ok = application:set_env(mnesia, dir, Dir),
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
|
%% 2. Crea lo schema, avvia Mnesia e crea le tabelle (solo se non esistono già)
|
||||||
|
init() ->
|
||||||
|
%% Crea lo schema solo se non esiste già
|
||||||
|
case mnesia:create_schema([node()]) of
|
||||||
|
{error, {already_exists, _}} -> ok;
|
||||||
|
_ -> ok
|
||||||
|
end,
|
||||||
|
%% Avvia Mnesia
|
||||||
|
mnesia:start(),
|
||||||
|
%% Crea tutte le tabelle
|
||||||
|
create_tables().
|
||||||
|
|
||||||
|
%% 3. Crea tutte le tabelle che servono
|
||||||
|
create_tables() ->
|
||||||
|
create_table(ap_users, [id, name, email, created_at]),
|
||||||
|
create_table(global_message, [id, activity, timestamp]).
|
||||||
|
|
||||||
|
%% Funzione helper per creare una tabella solo se non esiste già
|
||||||
|
create_table(Name, Attributes) ->
|
||||||
|
case mnesia:create_table(Name, [
|
||||||
|
{disc_only_copies, [node()]},
|
||||||
|
{attributes, Attributes}
|
||||||
|
]) of
|
||||||
|
{atomic, ok} ->
|
||||||
|
io:format("Tabella ~p creata.~n", [Name]),
|
||||||
|
ok;
|
||||||
|
{aborted, {already_exists, _}} ->
|
||||||
|
io:format("Tabella ~p già esistente.~n", [Name]),
|
||||||
|
ok;
|
||||||
|
Other ->
|
||||||
|
io:format("Errore nella creazione della tabella ~p: ~p~n", [Name, Other]),
|
||||||
|
erlang:halt(1)
|
||||||
|
end.
|
|
@ -0,0 +1,32 @@
|
||||||
|
-module(db_safe_insert).
|
||||||
|
-include_lib("include/db_safe_insert.hrl").
|
||||||
|
-export([safe_insert/2]).
|
||||||
|
|
||||||
|
safe_insert(Tab, Record) ->
|
||||||
|
case mnesia:transaction(fun() -> mnesia:write(Record) end) of
|
||||||
|
{atomic, ok} ->
|
||||||
|
ok;
|
||||||
|
{aborted, {file_size, _}} ->
|
||||||
|
cleanup_and_retry(Tab, Record);
|
||||||
|
{aborted, {no_disk_space, _}} ->
|
||||||
|
cleanup_and_retry(Tab, Record);
|
||||||
|
Other ->
|
||||||
|
Other
|
||||||
|
end.
|
||||||
|
|
||||||
|
cleanup_and_retry(Tab, Record) ->
|
||||||
|
remove_oldest(Tab, 0.2),
|
||||||
|
mnesia:transaction(fun() -> mnesia:write(Record) end).
|
||||||
|
|
||||||
|
remove_oldest(Tab, Fraction) ->
|
||||||
|
Records = mnesia:dirty_match_object(make_pattern(Tab)),
|
||||||
|
N = trunc(length(Records) * Fraction),
|
||||||
|
Sorted = lists:sort(fun(A, B) -> get_timestamp(A) =< get_timestamp(B) end, Records),
|
||||||
|
ToDelete = lists:sublist(Sorted, N),
|
||||||
|
lists:foreach(fun(Rec) -> mnesia:dirty_delete_object(Rec) end, ToDelete).
|
||||||
|
|
||||||
|
make_pattern(global_message) -> #global_message{id='_', activity='_', timestamp='_'};
|
||||||
|
make_pattern(ap_users) -> #ap_users{id='_', name='_', email='_', created_at='_'}. %% <-- PUNTO QUI DIOCANE!
|
||||||
|
|
||||||
|
get_timestamp(#global_message{timestamp=T}) -> T;
|
||||||
|
get_timestamp(#ap_users{created_at=T}) -> T. %% <-- PUNTO SOLO ALLA FINE, DIOCANE!
|
|
@ -1,24 +1,15 @@
|
||||||
%% timeline_db.erl
|
%% timeline_db.erl
|
||||||
-module(timeline_db).
|
-module(timeline_db).
|
||||||
-export([init/0, add_message/1, all_messages/0]).
|
-export([add_message/1, all_messages/0]).
|
||||||
|
|
||||||
-record(global_message, {id, activity, timestamp}).
|
-record(global_message, {id, activity, timestamp}).
|
||||||
|
|
||||||
init() ->
|
|
||||||
%% Crea la tabella Mnesia se non esiste
|
|
||||||
mnesia:create_table(global_message, [
|
|
||||||
{attributes, record_info(fields, global_message)},
|
|
||||||
{disc_copies, [node()]}
|
|
||||||
]).
|
|
||||||
|
|
||||||
add_message(Activity) ->
|
add_message(Activity) ->
|
||||||
%% Crea un ID unico e un timestamp per il messaggio
|
|
||||||
Id = erlang:unique_integer([monotonic, positive]),
|
Id = erlang:unique_integer([monotonic, positive]),
|
||||||
Timestamp = erlang:system_time(microsecond),
|
Timestamp = erlang:system_time(microsecond),
|
||||||
F = fun() ->
|
Record = #global_message{id=Id, activity=Activity, timestamp=Timestamp},
|
||||||
mnesia:write(#global_message{id=Id, activity=Activity, timestamp=Timestamp})
|
db_safe_insert:safe_insert(global_message, Record).
|
||||||
end,
|
|
||||||
mnesia:transaction(F).
|
|
||||||
|
|
||||||
all_messages() ->
|
all_messages() ->
|
||||||
F = fun() ->
|
F = fun() ->
|
||||||
|
|
|
@ -1,25 +1,16 @@
|
||||||
-module(user_db).
|
-module(user_db).
|
||||||
-export([init/0, add_user/2, get_user/1, all_users/0]).
|
-include("db_safe_insert.hrl").
|
||||||
|
-export([add_user/2, get_user/1, all_users/0]).
|
||||||
|
|
||||||
-record(user, {username, data}).
|
add_user(Name, Email) ->
|
||||||
|
Id = erlang:unique_integer([monotonic, positive]),
|
||||||
|
Timestamp = erlang:system_time(microsecond),
|
||||||
|
Record = #ap_users{id=Id, name=Name, email=Email, created_at=Timestamp},
|
||||||
|
db_safe_insert:safe_insert(ap_users, Record).
|
||||||
|
|
||||||
init() ->
|
get_user(Id) ->
|
||||||
mnesia:create_schema([node()]),
|
|
||||||
mnesia:start(),
|
|
||||||
mnesia:create_table(user, [
|
|
||||||
{attributes, record_info(fields, user)},
|
|
||||||
{disc_copies, [node()]}
|
|
||||||
]).
|
|
||||||
|
|
||||||
add_user(Username, Data) ->
|
|
||||||
F = fun() ->
|
F = fun() ->
|
||||||
mnesia:write(#user{username=Username, data=Data})
|
case mnesia:read({ap_users, Id}) of
|
||||||
end,
|
|
||||||
mnesia:transaction(F).
|
|
||||||
|
|
||||||
get_user(Username) ->
|
|
||||||
F = fun() ->
|
|
||||||
case mnesia:read({user, Username}) of
|
|
||||||
[User] -> {ok, User};
|
[User] -> {ok, User};
|
||||||
[] -> not_found
|
[] -> not_found
|
||||||
end
|
end
|
||||||
|
@ -29,7 +20,8 @@ get_user(Username) ->
|
||||||
|
|
||||||
all_users() ->
|
all_users() ->
|
||||||
F = fun() ->
|
F = fun() ->
|
||||||
mnesia:match_object(#user{username='_', data='_'})
|
mnesia:match_object(#ap_users{id='_', name='_', email='_', created_at='_'})
|
||||||
end,
|
end,
|
||||||
{atomic, Users} = mnesia:transaction(F),
|
{atomic, Users} = mnesia:transaction(F),
|
||||||
Users.
|
Users.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue