25
Erlang Data Storage Modules Tutorial by Flavio Ishii

Erlang Data Storage Modules

  • Upload
    flavio

  • View
    1.298

  • Download
    2

Embed Size (px)

DESCRIPTION

A tutorial for the Erlang-based data storage modules: ETS, DETS, and Mnesia.

Citation preview

Erlang Data Storage Modules Tutorial

by Flavio Ishii

Erlang Data Storage Modules

•Modules:•Erlang Terms Storage (ETS)•Disk Erlang Term Storage (DETS)•Mnesia Distributed DBMS

• Data Storage Design

Flavio Ishii, Sept. 17, 2009

Tuples

•A Tuple groups items into one entity/term.

•Used in Erlang data storage modules.

Flavio Ishii, Sept. 17, 2009

Tuples

> N = { “Flavio Ishii” }.

> S = [“cycling”,"ultimate frisbee" ].

> P = { person, { 1, N, S } }.

> { person, Properties } = P.

> Properties.

> { Id, Fullname, Sports } = Properties.

> X = lists:append( Sports, [“basketball”] ).

> X.

Flavio Ishii, Sept. 17, 2009

ETS

• Erlang Term Storage

• Constant access time (excl. ordered_set)• Table Options:

• access rights: private | public | *protected• types: *set | ordered_set | bag | duplicate_bag• transfer ownership: {heir, Pid, HeirData}, or

give_away/3

• Various methods to query the table: mnesia function (pattern matching) or qlc

* defaultFlavio Ishii, Sept. 17, 2009

ETS Table Access Rights

• private - Only owner process can read/write

• public - All processes with table id can read/write

• protected - Only owner process can write and any process with table id can read.

Flavio Ishii, Sept. 17, 2009

ETS Table Types

• set - unique {key, value}, inserts may overwrite. • [ {b,2}, {a,5} ]

• ordered_set - key ordered and unique tuple• [ {a,5}, {b,2} ]

• bag - duplicate key allowed• [ {a,5}, {b,2}, {b,4} ]

• duplicate_bag - duplicate tuple allowed• [ {a,5}, {b,2}, {b,2} ]

• hash tables: set, bag, and duplicate_bag• balanced binary tree: ordered_set

Flavio Ishii, Sept. 17, 2009

ETS

> Tab = ets:new(user, []).

> ets:insert(Tab, [{1,flavio},{2,ralph},{3,melissa},{4,bob}]).

> ets:info(Tab).

> ets:match(Tab,'$1').

> ets:match(Tab,{'$1',bob}).

> ets:match_object(Tab,{'$1',bob}).

> ets:select(Tab,[{{'$1',bob},[],['$$']}]).

> ets:select(Tab,[{{'$1',bob},[],['$_']}]).

> qlc:eval( qlc:q([{Y} || {X,Y} <- ets:table(Tab), (X > 2) and (X < 4)])).

Flavio Ishii, Sept. 17, 2009

DETS

• Stores persistent data in disk/file (disk seeks)

• Process needs to open the file.• Table may be shared by local processes.• No ordered_set table type.

• Must be properly closed when process is terminated.

• Checks for consistency on startup after crash.

Flavio Ishii, Sept. 17, 2009

DETS> dets:open_file(user, []).

> dets:insert(user, [{1,flavio},{2,ralph},{3,melissa},{4,bob}]).

> dets:info(user).

> dets:match(user,'$1').

> dets:match(user,{'$1',bob}).

> dets:match_object(user,{'$1',bob}).

> dets:select(user,[{{'$1',bob},[],['$$']}]).

> dets:select(user,[{{'$1',bob},[],['$_']}]).

> qlc:eval( qlc:q([{Y} || {X,Y} <- dets:table(user), (X > 2) and (X < 4)])).

Flavio Ishii, Sept. 17, 2009

Mnesia

• Erlang’s distributed DBMS

• ETS & DETS core• Location Transparency• Fault Tolerance via Table Replication &/or

Fragmentation across nodes

• Transactions, Locking, & Dirty Operations• Schema Manipulation at runtime

• ACID Properties

Flavio Ishii, Sept. 17, 2009

Mnesia ACID Properties

• Atomicity - succeed on all or no nodes• Consistency - ensure consistent state

after crash• Isolation - isolate manipulations on

same record• Durability - changes are committed to

disk.

Flavio Ishii, Sept. 17, 2009

Mnesia Table Options

• {type, Type} % set, ordered_set, bag• {record_name, Name}• {ram_copies, NodeList} % fastest• {disc_copies, NodeList} % RAM and disc copies• {disc_only_copies, NodeList} % slowest• {attributes, AtomList}• {index, IndexAtomList}

Flavio Ishii, Sept. 17, 2009

Terminal Time!

• Create record structure• Create schema and tables• Insert records• Query records

Flavio Ishii, Sept. 17, 2009

api.hrl

% this file defines the records

-record(counter,{id_name,value}).

-record(user_details,{password,firstname,lastname,sports=[]}).

-record(user,{id,username,user_details}).

Flavio Ishii, Sept. 17, 2009

Part 1/4 of api_db.erl

% this file defines the records

-module(api_db).

-export([init_db/0, add_sport/2, mne_fun_query/1, qlc_query/1]).

-include("api.hrl").

-include_lib("stdlib/include/qlc.hrl").

init_db() ->

mnesia:create_schema([node()]),

io:format("Mnesia schema created~n"),

mnesia:start(),

mnesia:change_table_copy_type(schema, node(), disc_copies),

mnesia:create_table(counter, [{disc_copies,[node()]}

, {attributes, record_info(fields, counter)}]),

mnesia:create_table(user, [{disc_copies,[node()]}, {index, [username]}

, {attributes, record_info(fields, user)}]),

io:format("Mnesia tables created~n"),

add_sample_data().

Flavio Ishii, Sept. 17, 2009

Part 2/4 of api_db.erl

insert_user(UserRecord) ->

case UserRecord#user.id =:= undefined of

true -> NewUser = UserRecord#user{ id = mnesia:dirty_update_counter(counter, user_id, 1) };

false -> NewUser = UserRecord

end,

% mnesia:dirty_write(NewUser). or use a transaction...

Fun = fun() ->

mnesia:write(NewUser)

end,

mnesia:transaction(Fun).

add_sample_data() ->

Flavio = #user{username="flavio"

, user_details=#user_details{ password="mypassword", firstname="Flavio", lastname="Ishii", sports=["biking","basketball"]}},

insert_user(Flavio),

Bob = #user{username="bob", user_details=#user_details{ password="hispassword", firstname="Bob", lastname="The Builder", sports=["soccer"]}},

insert_user(Bob),

io:format("Users added to table.~n").

Flavio Ishii, Sept. 17, 2009

Part 3/4 of api_db.erl

% > api_db:add_sport("flavio","football").

add_sport(Un,NewSport) ->

[User] = mne_fun_query({username,Un}),

UserDetails = User#user.user_details,

Sports = UserDetails#user_details.sports,

NewList = lists:append(Sports,[NewSport]),

NewUser = User#user{user_details=#user_details{sports=NewList}},

insert_user(NewUser).

% This is one method of querying a user.

% > api_db:qlc_query({username,"flavio"}).

qlc_query({username,Username}) ->

F = fun() ->

qlc:e(qlc:q([U#user.user_details || U <- mnesia:table(user)

, U#user.username =:= Username

]))

end,

mnesia:transaction(F).

Flavio Ishii, Sept. 17, 2009

Part 4/4 of api_db.erl

% This may not be ideal but it demonstrates the use of Pattern Matching

% > api_db:mne_fun_query({username,"flavio"}).

mne_fun_query({username,Un}) ->

MatchHead = #user{username='$1', _='_'},

Guard = [{'=:=','$1',Un}],

Result = ['$_'],

MatchSpec = [{MatchHead, Guard, Result}],

mnesia:dirty_select(user, MatchSpec);

% > api_db:mne_fun_query({sport,"soccer"}).

mne_fun_query({sport,Sport}) ->

UserDetails = #user_details{_='_',sports='$1'},

MatchHead = #user{user_details=UserDetails,_='_'},

Guard = [{'=:=','$1',[Sport]}],

Result = ['$_'],

MatchSpec = [{MatchHead, Guard, Result}],

F = fun() -> mnesia:select(user, MatchSpec) end,

mnesia:transaction(F);

mne_fun_query(_) -> io:format("No match~n").

Flavio Ishii, Sept. 17, 2009

ETS DETS MnesiaPersistent storageComplex search queriesDistributed Replicated data storageTable FragmentationFault tolerance via replicationTight Erlang couplingComplex objects & relationshipsDynamic reconfigurationTable indexingDistributed Transactions

X XX X XX X X

XX X XX X X

XX X X

XX

Head to Head Feature List

Flavio Ishii, Sept. 17, 2009

Possible Design Permutations

Flavio Ishii, Sept. 17, 2009

More Permutations

• Table access (i.e. public, protected)

• Table type (i.e. set, bag...)

• Table locks

• Distribution via replication and/or table fragmentation

Flavio Ishii, Sept. 17, 2009

Useful Mnesia Functions

• change_table_access_mode/2

• change_table_copy_type/3

• backup/2

• install_fallback/2

• restore/2

• dump_tables/1

• lock/2

• move_table_copy/3

• async_dirty/2

• sync_dirty/2

• add_table_copy/3

• transform_table/3

• change_table_frag/2

• activity/4Flavio Ishii, Sept. 17, 2009

Resources

• Programming Erlang, Joe Armstrong

• ets, dets, qlc, mnesia manuals: • http://www.erlang.org/doc/man/

• Mnesia User’s Guide: • http://www.erlang.org/doc/apps/mnesia

• Mnesia - A Distributed Robust DBMS for Telecommunications Applications, Håkan Mattsson, Hans Nilsson and Claes Wikström

Flavio Ishii, Sept. 17, 2009

Contact Info

USASK - MADMUC Lab

http://flavioishii.com

@flavioishii

Flavio Ishii, Sept. 17, 2009