Current section
Files
Jump to
Current section
Files
lib/amnesia/access.ex
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# Version 2, December 2004
#
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
#
# 0. You just DO WHAT THE FUCK YOU WANT TO.
defmodule Amnesia.Access do
@moduledoc """
This behavior is used to implement a different system while taking advantage
of mnesia.
It's used by mnesia itself to implement fragmentation using `mnesia_frag` and
`mnesia:activity`.
"""
@opaque id :: { :tid, integer, pid } | { :async_dirty, pid } | { :sync_dirty, pid } | { :ets, pid }
@type lock_item :: { :table, atom } | { :global, any, [node] }
@type lock_kind :: :write | :read | :sticky_write
@callback lock(id, any, lock_item, lock_kind) :: [node] | :ok | no_return
@callback write(id, any, atom, tuple, lock_kind) :: :ok | no_return
@callback delete(id, any, atom, any, lock_kind) :: :ok | no_return
@callback delete_object(id, any, atom, tuple, lock_kind) :: :ok | no_return
@callback read(id, any, atom, any, lock_kind) :: [tuple] | no_return
@callback match_object(id, any, atom, any, lock_kind) :: [any] | no_return
@callback all_keys(id, any, atom, lock_kind) :: [any] | no_return
@callback select(id, any, atom, any, lock_kind) :: [any]
@callback select(id, any, atom, any, integer, lock_kind) :: [any]
@callback select_cont(id, any, any) :: :"$end_of_table" | { [any], any }
@callback index_match_object(id, any, atom, any, atom | integer, lock_kind) :: [any] | no_return
@callback index_read(id, any, atom, any, atom | integer, lock_kind) :: [tuple] | no_return
@callback foldl(id, any, (tuple, any -> any), any, atom, lock_kind) :: any | no_return
@callback foldr(id, any, (tuple, any -> any), any, atom, lock_kind) :: any | no_return
@callback table_info(id, any, atom | { atom, atom }, atom) :: any
@callback first(id, any, atom) :: any
@callback next(id, any, atom, any) :: any
@callback prev(id, any, atom, any) :: any
@callback last(id, any, atom) :: any
@callback clear_table(id, any, atom, any) :: { :atomic, :ok } | { :aborted, any }
@spec lock(id, any, lock_item, lock_kind) :: [node] | :ok | no_return
def lock(id, opaque, item, kind) do
:mnesia.lock(id, opaque, item, kind)
end
@spec write(id, any, atom, tuple, lock_kind) :: :ok | no_return
def write(id, opaque, table, record, lock) do
:mnesia.write(id, opaque, table, record, lock)
end
@spec delete(id, any, atom, atom, lock_kind) :: :ok | no_return
def delete(id, opaque, table, key, lock) do
:mnesia.delete(id, opaque, table, key, lock)
end
@spec delete_object(id, any, atom, tuple, lock_kind) :: :ok | no_return
def delete_object(id, opaque, table, record, lock) do
:mnesia.delete_object(id, opaque, table, record, lock)
end
@spec read(id, any, atom, any, lock_kind) :: [tuple] | no_return
def read(id, opaque, table, key, lock) do
:mnesia.read(id, opaque, table, key, lock)
end
@spec match_object(id, any, atom, any, lock_kind) :: [tuple] | no_return
def match_object(id, opaque, table, pattern, lock) do
:mnesia.match_object(id, opaque, table, pattern, lock)
end
@spec all_keys(id, any, atom, lock_kind) :: [any]
def all_keys(id, opaque, table, lock) do
:mnesia.all_keys(id, opaque, table, lock)
end
@spec select(id, any, atom, any, lock_kind) :: [any]
def select(id, opaque, table, spec, lock) do
:mnesia.select(id, opaque, table, spec, lock)
end
@spec select(id, any, atom, any, integer, lock_kind) :: [any]
def select(id, opaque, table, spec, limit, lock) do
:mnesia.select(id, opaque, table, spec, limit, lock)
end
@spec select_cont(id, any, any) :: :"$end_of_table" | { [any], any }
def select_cont(id, opaque, cont) do
:mnesia.select_cont(id, opaque, cont)
end
@spec index_match_object(id, any, atom, any, atom | integer, lock_kind) :: [any] | no_return
def index_match_object(id, opaque, table, pattern, attribute, lock) do
:mnesia.index_match_object(id, opaque, table, pattern, attribute, lock)
end
@spec index_read(id, any, atom, any, atom | integer, lock_kind) :: [tuple] | no_return
def index_read(id, opaque, table, key, attribute, lock) do
:mnesia.index_read(id, opaque, table, key, attribute, lock)
end
@spec foldl(id, any, function, any, atom, lock_kind) :: any | no_return
def foldl(id, opaque, fun, acc, table, lock) do
:mnesia.foldl(id, opaque, fun, acc, table, lock)
end
@spec foldr(id, any, function, any, atom, lock_kind) :: any | no_return
def foldr(id, opaque, fun, acc, table, lock) do
:mnesia.foldr(id, opaque, fun, acc, table, lock)
end
@spec table_info(id, any, atom | { atom, atom }, atom) :: any
def table_info(id, opaque, of, key) do
:mnesia.table_info(id, opaque, of, key)
end
@spec first(id, any, atom) :: any
def first(id, opaque, table) do
:mnesia.first(id, opaque, table)
end
@spec next(id, any, atom, any) :: any
def next(id, opaque, table, key) do
:mnesia.next(id, opaque, table, key)
end
@spec prev(id, any, atom, any) :: any
def prev(id, opaque, table, key) do
:mnesia.prev(id, opaque, table, key)
end
@spec last(id, any, atom) :: any
def last(id, opaque, table) do
:mnesia.last(id, opaque, table)
end
@spec clear_table(id, any, atom, any) :: { :atomic, :ok } | { :aborted, any }
def clear_table(id, opaque, table, object) do
:mnesia.clear_table(id, opaque, table, object)
end
defmacro __using__(opts) do
quote do
@target unquote(opts[:module] || __MODULE__)
if @target == __MODULE__ do
@behaviour Amnesia.Access
end
require Amnesia.Helper
@doc """
Start a transaction with the given block or function, see `mnesia:transaction`.
"""
@spec transaction([do: term] | term) :: any | no_return
defmacro transaction(do: block) do
quote do
Amnesia.Helper.result(:mnesia.activity(:transaction,
fn -> unquote(block) end, [], unquote(@target)))
end
end
defmacro transaction(term) do
quote do
Amnesia.Helper.result(:mnesia.activity(:transaction,
unquote(term), [], unquote(@target)))
end
end
@doc """
Start a transaction with the given function passing the passed arguments to
it, see `mnesia:transaction`.
"""
@spec transaction(function, list) :: any | no_return
def transaction(fun, args) when is_function fun, length args do
Amnesia.Helper.result(:mnesia.activity(:transaction, fun, args, @target))
end
@doc """
Start a transaction with the given function passing the passed arguments to it,
trying to take a lock maximum *retries* times, see `mnesia:transaction`.
"""
@spec transaction(function, list, integer) :: any | no_return
def transaction(fun, args, retries) when is_function fun, length args do
Amnesia.Helper.result(:mnesia.activity({ :transaction, retries },
fun, args, @target))
end
@doc """
Start a synchronous transaction with the given block or function, see
`mnesia:sync_transaction`.
"""
@spec transaction!([] | function) :: any | no_return
defmacro transaction!(do: block) do
quote do
Amnesia.Helper.result(:mnesia.activity(:sync_transaction,
fn -> unquote(block) end, [], unquote(@target)))
end
end
defmacro transaction!(term) do
quote do
Amnesia.Helper.result(:mnesia.activity(:sync_transaction,
unquote(term), [], unquote(@target)))
end
end
@doc """
Start a synchronous transaction with the given function passing the passed
arguments to it, see `mnesia:sync_transaction`.
"""
@spec transaction!(function, list) :: any | no_return
def transaction!(fun, args) when is_function fun, length args do
Amnesia.Helper.result(:mnesia.activity(:sync_transaction, fun, args, @target))
end
@doc """
Start a synchronous transaction with the given function passing the passed
arguments to it, trying to take a lock maximum *retries* times, see
`mnesia:sync_transaction`.
"""
@spec transaction!(function, list, integer) :: any | no_return
def transaction!(fun, args, retries) when is_function fun, length args do
Amnesia.Helper.result(:mnesia.activity({ :sync_transaction, retries },
fun, args, @target))
end
@doc """
Run the passed function or block in the ETS context, see `mnesia:ets`.
"""
@spec ets([] | function) :: any | no_return
defmacro ets(do: block) do
quote do
:mnesia.activity(:ets, fn -> unquote(block) end, [], unquote(@target))
end
end
defmacro ets(term) do
quote do
:mnesia.activity(:ets, unquote(term), [], unquote(@target))
end
end
@doc """
Run the passed function in the ETS context passing over the passed arguments,
see `mnesia:ets`.
"""
@spec ets(function, list) :: any | no_return
def ets(fun, args) when is_function fun, length args do
:mnesia.activity(:ets, fun, args, @target)
end
@doc """
Run the passed function or block in a dirty asynchronous context, see
`mnesia:async_dirty`.
"""
@spec async([] | function) :: any | no_return
defmacro async(do: block) do
quote do
:mnesia.activity(:async_dirty, fn -> unquote(block) end, [], unquote(@target))
end
end
defmacro async(term) do
quote do
:mnesia.activity(:async_dirty, unquote(term), [], unquote(@target))
end
end
@doc """
Run the passed function in a dirty asynchronous context passing over the
passed arguments, see `mnesia:async_dirty`.
"""
@spec async(function, list) :: any | no_return
def async(fun, args) when is_function fun, length args do
:mnesia.activity(:async_dirty, fun, args, @target)
end
@doc """
Run the passed function or block in a dirty synchronous context, see
`mnesia:sync_dirty`.
"""
@spec sync([] | function) :: any | no_return
defmacro sync(do: block) do
quote do
:mnesia.activity(:sync_dirty, fn -> unquote(block) end, [], unquote(@target))
end
end
defmacro sync(term) do
quote do
:mnesia.activity(:sync_dirty, unquote(term), [], unquote(@target))
end
end
@doc """
Run the passed function in a dirty synchronous context passing over the
passed arguments, see `mnesia:sync_dirty`.
"""
@spec sync(function, list) :: any
def sync(fun, args) when is_function fun, length args do
:mnesia.activity(:sync_dirty, fun, args, @target)
end
end
end
end