Makefile View File
| 62 | @echo "Cleaning old data..."
|
| 63 | @rm -rf Mnesia.*
|
| 64 | @echo "Starting server..."
|
| 103 | @rm -rf logs/test/ct/ct_run.*
|
| 104 | @rm -rf data/Mnesia.ct data/Mnesia.ct.* data/mnesia_ct Mnesia.eventhub_api_test@* 2>/dev/null || true
|
| 105 | @bash scripts/fix-rebar-unit-symlink.sh
|
| 323 | @docker exec $$(docker ps -qf "name=eventhub_eventhub" | head -n 1) /app/bin/eventhub eval 'nodes().'
|
| 324 | @echo "Список узлов Mnesia:"
|
| 325 | @docker exec $$(docker ps -qf "name=eventhub_eventhub" | head -n 1) /app/bin/eventhub eval 'mnesia:table_info(user, disc_copies).'
|
docker/docker-compose.swarm.yml View File
docker/grafana/dashboards/eventhub-erlang.json View File
| 604 | "panels": [],
|
| 605 | "title": "Mnesia",
|
| 606 | "type": "row"
|
| 708 | {
|
| 709 | "expr": "rate(erlang_mnesia_committed_transactions{instance=~\"$instance\"}[1m])",
|
| 710 | "legendFormat": "Committed Tx Rate - {{instance}}",
|
| 713 | {
|
| 714 | "expr": "rate(erlang_mnesia_failed_transactions{instance=~\"$instance\"}[1m])",
|
| 715 | "legendFormat": "Failed Tx Rate - {{instance}}",
|
| 791 | {
|
| 792 | "expr": "erlang_mnesia_held_locks{instance=~\"$instance\"}",
|
| 793 | "legendFormat": "Held Locks - {{instance}}",
|
| 796 | {
|
| 797 | "expr": "erlang_mnesia_lock_queue{instance=~\"$instance\"}",
|
| 798 | "legendFormat": "Lock Queue - {{instance}}",
|
| 801 | {
|
| 802 | "expr": "erlang_mnesia_transaction_participants{instance=~\"$instance\"}",
|
| 803 | "legendFormat": "Participants - {{instance}}",
|
| 806 | {
|
| 807 | "expr": "erlang_mnesia_transaction_coordinators{instance=~\"$instance\"}",
|
| 808 | "legendFormat": "Coordinators - {{instance}}", |
include/records.hrl View File
src/archive/archive_controller.erl View File
| 10 | try
|
| 11 | rpc:call(ArchiveNode, mnesia, create_schema, [[ArchiveNode]]),
|
| 12 | rpc:call(ArchiveNode, mnesia, start, []),
|
| 13 | rpc:call(ArchiveNode, code, ensure_loaded, [archive_fetcher]),
|
| 65 | end,
|
| 66 | rpc:call(Node, mnesia, create_table, [Tab, Opts]).
|
| 67 |
|
| 71 | Records = fetch_records(Tab, Day),
|
| 72 | rpc:call(ArchiveNode, mnesia, transaction, [
|
| 73 | fun() -> [mnesia:write(Rec) || Rec <- Records] end
|
| 74 | ]),
|
| 75 | mnesia:transaction(fun() ->
|
| 76 | [mnesia:delete({Tab, element(2, Rec)}) || Rec <- Records]
|
| 77 | end)
|
| 82 | End = list_to_binary(Day ++ " 23:59:59"),
|
| 83 | mnesia:dirty_select(event, [{#event{start_time = '$1', _ = '_'},
|
| 84 | [{'>=','$1', Start},{'=<','$1', End}],
|
| 86 | fetch_records(booking, Day) ->
|
| 87 | mnesia:dirty_select(booking, [{#booking{created_at = '$1', _ = '_'},
|
| 88 | [{'>=','$1', Day},{'=<','$1', Day ++ " 23:59:59"}],
|
| 90 | fetch_records(review, Day) ->
|
| 91 | mnesia:dirty_select(review, [{#review{created_at = '$1', _ = '_'},
|
| 92 | [{'>=','$1', Day},{'=<','$1', Day ++ " 23:59:59"}],
|
| 94 | fetch_records(report, Day) ->
|
| 95 | mnesia:dirty_select(report, [{#report{created_at = '$1', _ = '_'},
|
| 96 | [{'>=','$1', Day},{'=<','$1', Day ++ " 23:59:59"}], |
src/archive/archive_fetcher.erl View File
src/archive/archive_manager.erl View File
src/config/sys.config View File
src/core/core_admin.erl View File
| 49 | },
|
| 50 | mnesia:dirty_write(Admin),
|
| 51 | {ok, Admin}
|
| 63 | F = fun() ->
|
| 64 | case mnesia:read(admin, AdminId) of
|
| 65 | [] ->
|
| 68 | UpdatedAdmin = apply_updates(Admin, Updates),
|
| 69 | mnesia:write(UpdatedAdmin),
|
| 70 | {ok, UpdatedAdmin}
|
| 72 | end,
|
| 73 | case mnesia:transaction(F) of
|
| 74 | {atomic, Result} -> Result;
|
| 84 | Match = #admin{email = Email, _ = '_'},
|
| 85 | case mnesia:dirty_match_object(Match) of
|
| 86 | [Admin] -> {ok, Admin};
|
| 95 | get_by_id(Id) ->
|
| 96 | case mnesia:dirty_read({admin, Id}) of
|
| 97 | [Admin] -> {ok, Admin};
|
| 106 | list_all() ->
|
| 107 | mnesia:dirty_match_object(#admin{_ = '_'}).
|
| 108 |
|
| 118 | Updated = Admin#admin{role = NewRole, updated_at = calendar:universal_time()},
|
| 119 | mnesia:dirty_write(Updated),
|
| 120 | {ok, Updated};
|
| 133 | Updated = Admin#admin{last_login = calendar:universal_time()},
|
| 134 | mnesia:dirty_write(Updated),
|
| 135 | {ok, Updated};
|
| 164 | Updated = Admin#admin{status = Status, updated_at = calendar:universal_time()},
|
| 165 | mnesia:dirty_write(Updated),
|
| 166 | {ok, Updated};
|
| 177 | {ok, _Admin} ->
|
| 178 | mnesia:dirty_delete(admin, AdminId),
|
| 179 | {ok, deleted}; |
src/core/core_admin_audit.erl View File
src/core/core_admin_session.erl View File
| 27 | },
|
| 28 | mnesia:dirty_write(Session),
|
| 29 | core_counters:inc(admin_active_sessions),
|
| 41 | validate(Token) ->
|
| 42 | case mnesia:dirty_read({admin_session, Token}) of
|
| 43 | [Session] ->
|
| 46 | false ->
|
| 47 | mnesia:dirty_delete({admin_session, Token}),
|
| 48 | core_counters:dec(admin_active_sessions),
|
| 59 | delete(Token) ->
|
| 60 | mnesia:dirty_delete({admin_session, Token}),
|
| 61 | core_counters:dec(admin_active_sessions), |
src/core/core_auth_session.erl View File
| 1 | %%%-------------------------------------------------------------------
|
| 2 | %%% @doc Единая модель сессий (refresh JWT) в Mnesia.
|
| 3 | %%% Таблица `auth_session` реплицируется через disc_copies — безопасна в кластере.
|
| 34 | },
|
| 35 | mnesia:dirty_write(Session),
|
| 36 | inc_counter(SubjectType),
|
| 44 | get(SessionId) ->
|
| 45 | case mnesia:dirty_read({auth_session, SessionId}) of
|
| 46 | [Session] -> {ok, Session};
|
| 58 | rotate(SessionId, PresentedJti) ->
|
| 59 | case mnesia:dirty_read({auth_session, SessionId}) of
|
| 60 | [Session] ->
|
| 71 | revoke(SessionId) ->
|
| 72 | case mnesia:dirty_read({auth_session, SessionId}) of
|
| 73 | [Session] when Session#auth_session.revoked =:= true ->
|
| 76 | Now = calendar:universal_time(),
|
| 77 | mnesia:dirty_write(Session#auth_session{revoked = true, updated_at = Now}),
|
| 78 | dec_counter(Session#auth_session.subject_type),
|
| 89 | revoke_family(FamilyId) ->
|
| 90 | Sessions = mnesia:dirty_index_read(auth_session, FamilyId, #auth_session.family_id),
|
| 91 | Now = calendar:universal_time(),
|
| 95 | false ->
|
| 96 | mnesia:dirty_write(Session#auth_session{revoked = true, updated_at = Now}),
|
| 97 | dec_counter(Session#auth_session.subject_type)
|
| 122 | },
|
| 123 | mnesia:dirty_write(Updated),
|
| 124 | {ok, NewJti, Updated}; |
src/core/core_automod_hit.erl View File
| 11 | create(EntityType, EntityId, Trigger, MatchedWords, ActionTaken) ->
|
| 12 | case lists:member(automod_hit, mnesia:system_info(tables)) of
|
| 13 | false ->
|
| 39 | },
|
| 40 | mnesia:dirty_write(Hit),
|
| 41 | {ok, Hit}
|
| 45 | get_by_id(Id) ->
|
| 46 | case mnesia:dirty_read(automod_hit, Id) of
|
| 47 | [Hit] -> {ok, Hit};
|
| 52 | list() ->
|
| 53 | mnesia:dirty_match_object(#automod_hit{_ = '_'}).
|
| 54 |
|
| 68 | },
|
| 69 | mnesia:dirty_write(Updated),
|
| 70 | {ok, Updated}; |
src/core/core_automod_settings.erl View File
| 12 | get() ->
|
| 13 | case catch mnesia:dirty_read(automod_settings, ?ID) of
|
| 14 | [S] -> S;
|
| 17 | ok ->
|
| 18 | case catch mnesia:dirty_read(automod_settings, ?ID) of
|
| 19 | [S2] -> S2;
|
| 32 | ensure_defaults() ->
|
| 33 | case lists:member(automod_settings, mnesia:system_info(tables)) of
|
| 34 | false ->
|
| 36 | true ->
|
| 37 | case mnesia:dirty_read(automod_settings, ?ID) of
|
| 38 | [_] -> ok;
|
| 39 | [] ->
|
| 40 | mnesia:dirty_write(default_record(<<>>)),
|
| 41 | ok
|
| 57 | },
|
| 58 | mnesia:dirty_write(Next),
|
| 59 | {ok, Next} |
src/core/core_banned_words.erl View File
| 11 | list_banned_words() ->
|
| 12 | mnesia:dirty_match_object(#banned_word{_ = '_'}).
|
| 13 |
|
| 34 | },
|
| 35 | mnesia:dirty_write(BannedWord),
|
| 36 | {ok, BannedWord}
|
| 47 | Match = #banned_word{word = Word, _ = '_'},
|
| 48 | [Record] = mnesia:dirty_match_object(Match),
|
| 49 | mnesia:dirty_delete({banned_word, Record#banned_word.id}),
|
| 50 | {ok, deleted};
|
| 61 | Match = #banned_word{word = Word, _ = '_'},
|
| 62 | case mnesia:dirty_match_object(Match) of
|
| 63 | [] -> false;
|
| 81 | Match = #banned_word{word = OldWord, _ = '_'},
|
| 82 | [Record] = mnesia:dirty_match_object(Match),
|
| 83 | Updated = Record#banned_word{word = NewWord},
|
| 84 | mnesia:dirty_write(Updated),
|
| 85 | {ok, Updated} |
src/core/core_booking.erl View File
| 33 | },
|
| 34 | F = fun() -> mnesia:write(Booking), {ok, Booking} end,
|
| 35 | case mnesia:transaction(F) of
|
| 36 | {atomic, Result} -> Result;
|
| 45 | get_by_id(Id) ->
|
| 46 | case mnesia:dirty_read(booking, Id) of
|
| 47 | [] -> {error, not_found};
|
| 57 | Match = #booking{event_id = EventId, _ = '_'},
|
| 58 | Bookings = mnesia:dirty_match_object(Match),
|
| 59 | {ok, Bookings}.
|
| 67 | Match = #booking{user_id = UserId, _ = '_'},
|
| 68 | Bookings = mnesia:dirty_match_object(Match),
|
| 69 | {ok, Bookings}.
|
| 76 | list_all() ->
|
| 77 | mnesia:dirty_match_object(#booking{_ = '_'}).
|
| 78 |
|
| 86 | F = fun() ->
|
| 87 | case mnesia:read(booking, Id) of
|
| 88 | [] -> {error, not_found};
|
| 90 | UpdatedBooking = apply_updates(Booking, Updates),
|
| 91 | mnesia:write(UpdatedBooking),
|
| 92 | {ok, UpdatedBooking}
|
| 94 | end,
|
| 95 | case mnesia:transaction(F) of
|
| 96 | {atomic, Result} -> Result;
|
| 105 | delete(Id) ->
|
| 106 | case mnesia:dirty_read(booking, Id) of
|
| 107 | [] -> {error, not_found};
|
| 108 | [_] -> mnesia:dirty_delete(booking, Id), ok
|
| 109 | end.
|
| 116 | count_bookings() ->
|
| 117 | mnesia:table_info(booking, size).
|
| 118 |
|
| 126 | Match = #booking{event_id = EventId, user_id = UserId, _ = '_'},
|
| 127 | case mnesia:dirty_match_object(Match) of
|
| 128 | [] -> {error, not_found}; |
src/core/core_calendar.erl View File
| 63 | },
|
| 64 | F = fun() -> mnesia:write(Calendar), {ok, Calendar} end,
|
| 65 | case mnesia:transaction(F) of
|
| 66 | {atomic, Result} -> Result;
|
| 75 | get_by_id(Id) ->
|
| 76 | case mnesia:dirty_read(calendar, Id) of
|
| 77 | [] -> {error, not_found};
|
| 87 | Match = #calendar{owner_id = OwnerId, status = active, _ = '_'},
|
| 88 | Calendars = mnesia:dirty_match_object(Match),
|
| 89 | {ok, Calendars}.
|
| 100 | F = fun() ->
|
| 101 | case mnesia:read(calendar, Id) of
|
| 102 | [] -> {error, not_found};
|
| 104 | UpdatedCalendar = apply_updates(Calendar, Updates),
|
| 105 | mnesia:write(UpdatedCalendar),
|
| 106 | {ok, UpdatedCalendar}
|
| 108 | end,
|
| 109 | case mnesia:transaction(F) of
|
| 110 | {atomic, Result} -> Result;
|
| 127 | count_calendars() ->
|
| 128 | mnesia:table_info(calendar, size).
|
| 129 |
|
| 135 | list_all() ->
|
| 136 | {atomic, Calendars} = mnesia:transaction(fun() ->
|
| 137 | mnesia:foldl(fun(C, Acc) -> [C | Acc] end, [], calendar)
|
| 138 | end),
|
| 166 | core_stats:with_daily(calendars_created, From, To, fun() ->
|
| 167 | All = mnesia:dirty_match_object(#calendar{_ = '_'}),
|
| 168 | Filtered = lists:filter(fun(C) -> C#calendar.created_at >= From andalso
|
| 188 | core_stats:with_dim(calendar, type, fun() ->
|
| 189 | Calendars = mnesia:dirty_match_object(#calendar{_ = '_'}),
|
| 190 | lists:foldl(fun(#calendar{type = Type}, Acc) ->
|
| 204 | core_stats:with_dim(calendar, status, fun() ->
|
| 205 | Calendars = mnesia:dirty_match_object(#calendar{_ = '_'}),
|
| 206 | lists:foldl(fun(#calendar{status = Status}, Acc) ->
|
| 222 | {error, _} ->
|
| 223 | Calendars = mnesia:dirty_match_object(#calendar{_ = '_'}),
|
| 224 | Sorted = lists:reverse(lists:sort(
|
| 256 | {error, _} ->
|
| 257 | Calendars = mnesia:dirty_match_object(#calendar{_ = '_'}),
|
| 258 | Sorted = lists:reverse(lists:sort(
|
| 265 | top_by_review_filter(N, FilterFun) ->
|
| 266 | Reviews = mnesia:dirty_match_object(#review{target_type = calendar, _ = '_'}),
|
| 267 | Filtered = lists:filter(FilterFun, Reviews), |