ETS, DETS & Mnesia
Access: public / protected (default) / private.
32.1 ETS — in-memory term storage
T = ets:new(users, [set, named_table, public, {read_concurrency, true}]),
ets:insert(users, {1, "Ann", 30}),
ets:insert(users, [{2, "Bob", 25}, {3, "Eve", 35}]),
ets:insert_new(users, {1, "Dup", 0}), % false: key exists
ets:lookup(users, 1), % [{1,"Ann",30}]
ets:lookup_element(users, 1, 2), % "Ann"
ets:member(users, 2),
ets:delete(users, 2),
ets:update_element(users, 1, {3, 31}),
ets:update_counter(stats, hits, {2, 1}, {hits, 0}),
ets:tab2list(users),
ets:foldl(fun(Obj, Acc) -> [Obj | Acc] end, [], users),
ets:first(users), ets:next(users, 1),
ets:info(users, size),
ets:delete(users).32.2 Table types & options
duplicate keys, unique objects Access: public / protected (default) / private. Options: named_table, {keypos, N}, {read_concurrency, true}, {write_concurrency, true | auto}, {decentralized_counters, true}, compressed, {heir, Pid, Data}.
A table is owned by its creating process and deleted when the owner dies (unless an heir is set).
32.3 Match specifications
ets:match(users, {'$1', '_', 30}), % [[1]]
ets:match_object(users, {'_', "Ann", '_'}),
ets:select(users, [{{'$1', '$2', '$3'}, [{'>', '$3', 26}], ['$2']}]),
ets:select_delete(users, [{{'_', '_', '$1'}, [{'<', '$1', 18}], [true]}]),
%% Readable match specs with fun2ms (needs the parse transform header)
-include_lib("stdlib/include/ms_transform.hrl").
MS = ets:fun2ms(fun({Id, Name, Age}) when Age > 26 -> {Id, Name} end),
ets:select(users, MS).32.4 DETS — disk-based tables
Max 2 GB per file; no ordered_set.
{ok, T} = dets:open_file(store, [{file, "store.dets"}, {type, set}]),
dets:insert(T, {k, v}), dets:lookup(T, k), dets:close(T).32.5 Mnesia — distributed DBMS
Storage types: ram_copies, disc_copies, disc_only_copies. Features: replication across nodes, transactions, indexes, fragmentation. Best for config/session data in Erlang clusters; for large data consider external DBs.
-record(account, {id, owner, balance = 0}).
setup() ->
mnesia:create_schema([node()]),
mnesia:start(),
mnesia:create_table(account, [{attributes, record_info(fields, account)},
{disc_copies, [node()]},
{index, [owner]}]).
deposit(Id, Amount) ->
F = fun() ->
[Acc] = mnesia:read(account, Id, write),
mnesia:write(Acc#account{balance = Acc#account.balance + Amount})
end,
mnesia:transaction(F). % {atomic, Result} | {aborted, Reason}
mnesia:dirty_read(account, 1), % fast, non-transactional
mnesia:select(account, MatchSpec),
qlc:e(qlc:q([A || A <- mnesia:table(account), A#account.balance > 100])).32.6 persistent_term, atomics & counters
persistent_term:put({myapp, config}, #{port => 80}),
persistent_term:get({myapp, config}), % very fast reads, expensive updates
C = counters:new(1, [write_concurrency]),
counters:add(C, 1, 5), counters:get(C, 1),
A = atomics:new(1, []), atomics:compare_exchange(A, 1, 0, 1).