## 11 Appendix D: The Fragmented Table Hashing Call Back Interface

### 11.1 mnesia_frag_hash callback behavior

    -module(mnesia_frag_hash).

    %% Fragmented Table Hashing callback functions
    -export([
             init_state/2,
             add_frag/1,
             del_frag/1,
             key_to_frag_number/2,
             match_spec_to_frag_numbers/2
            ]).

    -record(hash_state, {n_fragments, next_n_to_split, n_doubles}).

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    init_state(_Tab, State) when State == undefined ->
        #hash_state{n_fragments = 1,
                    next_n_to_split = 1,
                    n_doubles = 0}.

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    add_frag(State) when record(State, hash_state) ->
        SplitN = State#hash_state.next_n_to_split,
        P = SplitN + 1,
        L = State#hash_state.n_doubles,
        NewN = State#hash_state.n_fragments + 1,
        State2 = case trunc(math:pow(2, L)) + 1 of
                     P2 when P2 == P ->
                         State#hash_state{n_fragments = NewN,
                                          n_doubles = L + 1,
                                          next_n_to_split = 1};
                     _ ->
                         State#hash_state{n_fragments = NewN,
                                          next_n_to_split = P}
                 end,
        {State2, [SplitN], [NewN]}.

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    del_frag(State) when record(State, hash_state) ->
        P = State#hash_state.next_n_to_split - 1,
        L = State#hash_state.n_doubles,
        N = State#hash_state.n_fragments,
        if
            P < 1 ->
                L2 = L - 1,
                MergeN = trunc(math:pow(2, L2)),
                State2 = State#hash_state{n_fragments = N - 1,
                                          next_n_to_split = MergeN,
                                          n_doubles = L2},
                {State2, [N], [MergeN]};
            true ->
                MergeN = P,
                State2 = State#hash_state{n_fragments = N - 1,
                                          next_n_to_split = MergeN},
                {State2, [N], [MergeN]}
            end.

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    key_to_frag_number(State, Key) when record(State, hash_state) ->
        L = State#hash_state.n_doubles,
        A = erlang:phash(Key, trunc(math:pow(2, L))),
        P = State#hash_state.next_n_to_split,
        if
            A < P ->
                erlang:phash(Key, trunc(math:pow(2, L + 1)));
            true ->
                A
        end.

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    match_spec_to_frag_numbers(State, MatchSpec) when record(State, hash_state) ->
        case MatchSpec of
            [{HeadPat, _, _}] when tuple(HeadPat), size(HeadPat) > 2 ->
                KeyPat = element(2, HeadPat),
                case has_var(KeyPat) of
                    false ->
                        [key_to_frag_number(State, KeyPat)];
                    true ->
                        lists:seq(1, State#hash_state.n_fragments)
                end;
            _ ->
                lists:seq(1, State#hash_state.n_fragments)
        end.

Copyright © 1991-2006 Ericsson AB