Erlang -- Appendix D: The Fragmented Table Hashing Call Back Interface

User's Guide
Reference Manual
Release Notes
PDF
Top

Mnesia
User's Guide
Version 4.7.1

Expand All
Contract All

Chapters

- Introduction
  - Top of chapter
  - About Mnesia
  - The Mnesia DataBase Management System (DBMS)
- Getting Started with Mnesia
  - Top of chapter
  - Starting Mnesia for the first time
  - An Introductory Example
- Building A Mnesia Database
  - Top of chapter
  - Defining a Schema
  - The Data Model
  - Starting Mnesia
  - Creating New Tables
- Transactions and Other Access Contexts
  - Top of chapter
  - Transaction Properties
  - Locking
  - Dirty Operations
  - Record Names versus Table Names
  - Activity Concept and Various Access Contexts
  - Nested transactions
  - Pattern Matching
  - Iteration
- Miscellaneous Mnesia Features
  - Top of chapter
  - Indexing
  - Distribution and Fault Tolerance
  - Table Fragmentation
  - Local Content Tables
  - Disc-less Nodes
  - More Schema Management
  - Mnesia Event Handling
  - Debugging Mnesia Applications
  - Concurrent Processes in Mnesia
  - Prototyping
  - Object Based Programming with Mnesia
- Mnesia System Information
  - Top of chapter
  - Database Configuration Data
  - Core Dumps
  - Dumping Tables
  - Checkpoints
  - Files
  - Loading of Tables at Start-up
  - Recovery from Communication Failure
  - Recovery of Transactions
  - Backup, Fallback, and Disaster Recovery
- Combining Mnesia with SNMP
  - Top of chapter
  - Combining Mnesia and SNMP
- Appendix A: Mnesia Error Messages
  - Top of chapter
  - Errors in Mnesia
- Appendix B: The Backup Call Back Interface
  - Top of chapter
  - mnesia_backup callback behavior
- Appendix C: The Activity Access Call Back Interface
  - Top of chapter
  - mnesia_access callback behavior
- Appendix D: The Fragmented Table Hashing Call Back Interface
  - Top of chapter
  - mnesia_frag_hash callback behavior

# 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,
    	 function}).

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

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

    convert_old_state({hash_state, N, P, L}) ->
        #hash_state{n_fragments     = N,
    		next_n_to_split = P,
    		n_doubles       = L,
    		function        = phash}.

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

    add_frag(#hash_state{next_n_to_split = SplitN, n_doubles = L, n_fragments = N} = State) ->
        P = SplitN + 1,
        NewN = N + 1,
        State2 = case power2(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]};
    add_frag(OldState) ->
        State = convert_old_state(OldState),
        add_frag(State).

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

    del_frag(#hash_state{next_n_to_split = SplitN, n_doubles = L, n_fragments = N} = State) ->
        P = SplitN - 1,
        if
    	P < 1 ->
    	    L2 = L - 1,
    	    MergeN = power2(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;
    del_frag(OldState) ->
        State = convert_old_state(OldState),
        del_frag(State).

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

    key_to_frag_number(#hash_state{function = phash, n_fragments = N, n_doubles = L}, Key) ->
        A = erlang:phash(Key, power2(L + 1)),
        if
    	A > N ->
    	    A - power2(L);
    	true ->
    	    A
        end;
    key_to_frag_number(#hash_state{function = phash2, n_fragments = N, n_doubles = L}, Key) ->
        A = erlang:phash2(Key, power2(L + 1)) + 1,
        if
    	A > N ->
    	    A - power2(L);
    	true ->
    	    A
        end;
    key_to_frag_number(OldState, Key) ->
        State = convert_old_state(OldState),
        key_to_frag_number(State, Key).

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

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

    power2(Y) ->
        1 bsl Y. % trunc(math:pow(2, Y)).