Appendix B: Activity Access Callback Interface — mnesia v4.26.1

Search documentation of mnesia

# Appendix B: Activity Access Callback Interface

Copy Markdown View Source

## mnesia_access Callback Behavior

    -module(mnesia_frag).

    %% Callback functions when accessed within an activity
    -export([
             lock/4,
             write/5, delete/5, delete_object/5,
             read/5, match_object/5, all_keys/4,
             select/5, select/6, select_cont/3,
             select_reverse/5, select_reverse/6,
             index_match_object/6, index_read/6,
             foldl/6, foldr/6, table_info/4,
             first/3, next/4, prev/4, last/3,
             clear_table/4
            ]).

    %% Callback functions which provides transparent
    %% access of fragmented tables from any activity
    %% access context.

    lock(ActivityId, Opaque, {table , Tab}, LockKind) ->
        case frag_names(Tab) of
            [Tab] ->
                mnesia:lock(ActivityId, Opaque, {table, Tab}, LockKind);
            Frags ->
                DeepNs = [mnesia:lock(ActivityId, Opaque, {table, F}, LockKind) ||
                             F <- Frags],
                mnesia_lib:uniq(lists:append(DeepNs))
        end;

    lock(ActivityId, Opaque, LockItem, LockKind) ->
        mnesia:lock(ActivityId, Opaque, LockItem, LockKind).

    write(ActivityId, Opaque, Tab, Rec, LockKind) ->
        Frag = record_to_frag_name(Tab, Rec),
        mnesia:write(ActivityId, Opaque, Frag, Rec, LockKind).

    delete(ActivityId, Opaque, Tab, Key, LockKind) ->
        Frag = key_to_frag_name(Tab, Key),
        mnesia:delete(ActivityId, Opaque, Frag, Key, LockKind).

    delete_object(ActivityId, Opaque, Tab, Rec, LockKind) ->
        Frag = record_to_frag_name(Tab, Rec),
        mnesia:delete_object(ActivityId, Opaque, Frag, Rec, LockKind).

    read(ActivityId, Opaque, Tab, Key, LockKind) ->
        Frag = key_to_frag_name(Tab, Key),
        mnesia:read(ActivityId, Opaque, Frag, Key, LockKind).

    match_object(ActivityId, Opaque, Tab, HeadPat, LockKind) ->
        MatchSpec = [{HeadPat, [], ['$_']}],
        select(ActivityId, Opaque, Tab, MatchSpec, LockKind).

    select(ActivityId, Opaque, Tab, MatchSpec, LockKind) ->
        do_select(ActivityId, Opaque, Tab, MatchSpec, LockKind).

    select(ActivityId, Opaque, Tab, MatchSpec, Limit, LockKind) ->
        init_select(ActivityId, Opaque, Tab, MatchSpec, Limit, LockKind).

    select_reverse(ActivityId, Opaque, Tab, MatchSpec, LockKind) ->
        select(ActivityId, Opaque, Tab, MatchSpec, LockKind).

    select_reverse(ActivityId, Opaque, Tab, MatchSpec, Limit, LockKind) ->
        select(ActivityId, Opaque, Tab, MatchSpec, Limit, LockKind).

    select_cont(_Tid,_,{frag_cont, '$end_of_table', [],_}) -> '$end_of_table';
    select_cont(Tid,Ts,{frag_cont, '$end_of_table', [{Tab,Node,Type}|Rest],Args}) ->
        {Spec,LockKind,Limit} = Args,
        InitFun = fun(FixedSpec) -> mnesia:dirty_sel_init(Node,Tab,FixedSpec,Limit,Type) end,
        Res = mnesia:fun_select(Tid,Ts,Tab,Spec,LockKind,Tab,InitFun,Limit,Node,Type),
        frag_sel_cont(Res, Rest, Args);
    select_cont(Tid,Ts,{frag_cont, Cont, TabL, Args}) ->
        frag_sel_cont(mnesia:select_cont(Tid,Ts,Cont),TabL,Args);
    select_cont(Tid,Ts,Else) ->
        mnesia:select_cont(Tid,Ts,Else).

    all_keys(ActivityId, Opaque, Tab, LockKind) ->
        Match = [mnesia:all_keys(ActivityId, Opaque, Frag, LockKind)
                 || Frag <- frag_names(Tab)],
        lists:append(Match).

    clear_table(ActivityId, Opaque, Tab, Obj) ->
        [mnesia:clear_table(ActivityId, Opaque, Frag, Obj)  || Frag <- frag_names(Tab)],
        ok.

    index_match_object(ActivityId, Opaque, Tab, Pat, Attr, LockKind) ->
        Match =
            [mnesia:index_match_object(ActivityId, Opaque, Frag, Pat, Attr, LockKind)
             || Frag <- frag_names(Tab)],
        lists:append(Match).

    index_read(ActivityId, Opaque, Tab, Key, Attr, LockKind) ->
        Match =
            [mnesia:index_read(ActivityId, Opaque, Frag, Key, Attr, LockKind)
             || Frag <- frag_names(Tab)],
        lists:append(Match).

    foldl(ActivityId, Opaque, Fun, Acc, Tab, LockKind) ->
        Fun2 = fun(Frag, A) ->
                       mnesia:foldl(ActivityId, Opaque, Fun, A, Frag, LockKind)
               end,
        lists:foldl(Fun2, Acc, frag_names(Tab)).

    foldr(ActivityId, Opaque, Fun, Acc, Tab, LockKind) ->
        Fun2 = fun(Frag, A) ->
                       mnesia:foldr(ActivityId, Opaque, Fun, A, Frag, LockKind)
               end,
        lists:foldr(Fun2, Acc, frag_names(Tab)).

    table_info(ActivityId, Opaque, {Tab, Key}, Item) ->
        Frag = key_to_frag_name(Tab, Key),
        table_info2(ActivityId, Opaque, Tab, Frag, Item);
    table_info(ActivityId, Opaque, Tab, Item) ->
        table_info2(ActivityId, Opaque, Tab, Tab, Item).

    table_info2(ActivityId, Opaque, Tab, Frag, Item) ->
        case Item of
            size ->
                SumFun = fun({_, Size}, Acc) -> Acc + Size end,
                lists:foldl(SumFun, 0, frag_size(ActivityId, Opaque, Tab));
            memory ->
                SumFun = fun({_, Size}, Acc) -> Acc + Size end,
                lists:foldl(SumFun, 0, frag_memory(ActivityId, Opaque, Tab));
            base_table ->
                lookup_prop(Tab, base_table);
            node_pool ->
                lookup_prop(Tab, node_pool);
            n_fragments ->
                FH = lookup_frag_hash(Tab),
                FH#frag_state.n_fragments;
            foreign_key ->
                FH = lookup_frag_hash(Tab),
                FH#frag_state.foreign_key;
            foreigners ->
                lookup_foreigners(Tab);
            n_ram_copies ->
                length(val({Tab, ram_copies}));
            n_disc_copies ->
                length(val({Tab, disc_copies}));
            n_disc_only_copies ->
                length(val({Tab, disc_only_copies}));
            n_external_copies ->
                length(val({Tab, external_copies}));

            frag_names ->
                frag_names(Tab);
            frag_dist ->
                frag_dist(Tab);
            frag_size ->
                frag_size(ActivityId, Opaque, Tab);
            frag_memory ->
                frag_memory(ActivityId, Opaque, Tab);
            _ ->
                mnesia:table_info(ActivityId, Opaque, Frag, Item)
        end.

    first(ActivityId, Opaque, Tab) ->
        case ?catch_val({Tab, frag_hash}) of
            {'EXIT', _} ->
                mnesia:first(ActivityId, Opaque, Tab);
            FH ->
                FirstFrag = Tab,
                case mnesia:first(ActivityId, Opaque, FirstFrag) of
                    '$end_of_table' ->
                        search_first(ActivityId, Opaque, Tab, 1, FH);
                    Next ->
                        Next
                end
        end.

    search_first(ActivityId, Opaque, Tab, N, FH) when N < FH#frag_state.n_fragments ->
        NextN = N + 1,
        NextFrag = n_to_frag_name(Tab, NextN),
        case mnesia:first(ActivityId, Opaque, NextFrag) of
            '$end_of_table' ->
                search_first(ActivityId, Opaque, Tab, NextN, FH);
            Next ->
                Next
        end;
    search_first(_ActivityId, _Opaque, _Tab, _N, _FH) ->
        '$end_of_table'.

    last(ActivityId, Opaque, Tab) ->
        case ?catch_val({Tab, frag_hash}) of
            {'EXIT', _} ->
                mnesia:last(ActivityId, Opaque, Tab);
            FH ->
                LastN = FH#frag_state.n_fragments,
                search_last(ActivityId, Opaque, Tab, LastN, FH)
        end.

    search_last(ActivityId, Opaque, Tab, N, FH) when N >= 1 ->
        Frag = n_to_frag_name(Tab, N),
        case mnesia:last(ActivityId, Opaque, Frag) of
            '$end_of_table' ->
                PrevN = N - 1,
                search_last(ActivityId, Opaque, Tab, PrevN, FH);
            Prev ->
                Prev
        end;
    search_last(_ActivityId, _Opaque, _Tab, _N, _FH) ->
        '$end_of_table'.

    prev(ActivityId, Opaque, Tab, Key) ->
        case ?catch_val({Tab, frag_hash}) of
            {'EXIT', _} ->
                mnesia:prev(ActivityId, Opaque, Tab, Key);
            FH ->
                N = key_to_n(FH, Key),
                Frag = n_to_frag_name(Tab, N),
                case mnesia:prev(ActivityId, Opaque, Frag, Key) of
                    '$end_of_table' ->
                        search_prev(ActivityId, Opaque, Tab, N);
                    Prev ->
                        Prev
                end
        end.

    search_prev(ActivityId, Opaque, Tab, N) when N > 1 ->
        PrevN = N - 1,
        PrevFrag = n_to_frag_name(Tab, PrevN),
        case mnesia:last(ActivityId, Opaque, PrevFrag) of
            '$end_of_table' ->
                search_prev(ActivityId, Opaque, Tab, PrevN);
            Prev ->
                Prev
        end;
    search_prev(_ActivityId, _Opaque, _Tab, _N) ->
        '$end_of_table'.

    next(ActivityId, Opaque, Tab, Key) ->
        case ?catch_val({Tab, frag_hash}) of
            {'EXIT', _} ->
                mnesia:next(ActivityId, Opaque, Tab, Key);
            FH ->
                N = key_to_n(FH, Key),
                Frag = n_to_frag_name(Tab, N),
                case mnesia:next(ActivityId, Opaque, Frag, Key) of
                    '$end_of_table' ->
                        search_next(ActivityId, Opaque, Tab, N, FH);
                    Prev ->
                        Prev
                end
        end.

    search_next(ActivityId, Opaque, Tab, N, FH) when N < FH#frag_state.n_fragments ->
        NextN = N + 1,
        NextFrag = n_to_frag_name(Tab, NextN),
        case mnesia:first(ActivityId, Opaque, NextFrag) of
            '$end_of_table' ->
                search_next(ActivityId, Opaque, Tab, NextN, FH);
            Next ->
                Next
        end;
    search_next(_ActivityId, _Opaque, _Tab, _N, _FH) ->
        '$end_of_table'.

← Previous Page Appendix A: Backup Callback Interface
Next Page → Appendix C: Fragmented Table Hashing Callback Interface