Test case for inner retries; add mrdb_stats.erl; update docs

This commit is contained in:
Ulf Wiger 2022-11-03 12:41:14 +01:00
parent 95abe4e36e
commit 3635eac717
21 changed files with 2982 additions and 41 deletions

View File

@ -2,4 +2,5 @@
{application,mnesia_rocksdb}.
{modules,[mnesia_rocksdb,mnesia_rocksdb_admin,mnesia_rocksdb_app,
mnesia_rocksdb_lib,mnesia_rocksdb_params,mnesia_rocksdb_sup,
mnesia_rocksdb_tuning,mrdb,mrdb_index,mrdb_mutex,mrdb_select]}.
mnesia_rocksdb_tuning,mrdb,mrdb_index,mrdb_mutex,
mrdb_mutex_serializer,mrdb_select,mrdb_stats]}.

17
doc/index.html Normal file
View File

@ -0,0 +1,17 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>The mnesia_rocksdb application</title>
</head>
<frameset cols="20%,80%">
<frame src="modules-frame.html" name="modulesFrame" title="">
<frame src="overview-summary.html" name="overviewFrame" title="">
<noframes>
<h2>This page uses frames</h2>
<p>Your browser does not accept frames.
<br>You should go to the <a href="overview-summary.html">non-frame version</a> instead.
</p>
</noframes>
</frameset>
</html>

529
doc/mnesia_rocksdb.html Normal file
View File

@ -0,0 +1,529 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Module mnesia_rocksdb</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<hr>
<h1>Module mnesia_rocksdb</h1>
<ul class="index"><li><a href="#description">Description</a></li><li><a href="#types">Data Types</a></li><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>rocksdb storage backend for Mnesia.
<p><b>Behaviours:</b> <a href="gen_server.html"><tt>gen_server</tt></a>, <a href="mnesia_backend_type.html"><tt>mnesia_backend_type</tt></a>.</p>
<h2><a name="description">Description</a></h2><p>rocksdb storage backend for Mnesia.</p>
This module implements a mnesia backend callback plugin.
It's specifically documented to try to explain the workings of
backend plugins.
<h2><a name="types">Data Types</a></h2>
<h3 class="typedecl"><a name="type-alias">alias()</a></h3>
<p><tt>alias() = atom()</tt></p>
<h3 class="typedecl"><a name="type-data_tab">data_tab()</a></h3>
<p><tt>data_tab() = atom()</tt></p>
<h3 class="typedecl"><a name="type-error">error()</a></h3>
<p><tt>error() = {error, any()}</tt></p>
<h3 class="typedecl"><a name="type-index_info">index_info()</a></h3>
<p><tt>index_info() = {<a href="#type-index_pos">index_pos()</a>, <a href="#type-index_type">index_type()</a>}</tt></p>
<h3 class="typedecl"><a name="type-index_pos">index_pos()</a></h3>
<p><tt>index_pos() = integer() | {atom()}</tt></p>
<h3 class="typedecl"><a name="type-index_tab">index_tab()</a></h3>
<p><tt>index_tab() = {<a href="#type-data_tab">data_tab()</a>, index, <a href="#type-index_info">index_info()</a>}</tt></p>
<h3 class="typedecl"><a name="type-index_type">index_type()</a></h3>
<p><tt>index_type() = ordered</tt></p>
<h3 class="typedecl"><a name="type-retainer_name">retainer_name()</a></h3>
<p><tt>retainer_name() = any()</tt></p>
<h3 class="typedecl"><a name="type-retainer_tab">retainer_tab()</a></h3>
<p><tt>retainer_tab() = {<a href="#type-data_tab">data_tab()</a>, retainer, <a href="#type-retainer_name">retainer_name()</a>}</tt></p>
<h3 class="typedecl"><a name="type-table">table()</a></h3>
<p><tt>table() = <a href="#type-data_tab">data_tab()</a> | <a href="#type-index_tab">index_tab()</a> | <a href="#type-retainer_tab">retainer_tab()</a></tt></p>
<h3 class="typedecl"><a name="type-table_type">table_type()</a></h3>
<p><tt>table_type() = set | ordered_set | bag</tt></p>
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#add_aliases-1">add_aliases/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#check_definition-4">check_definition/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#close_table-2">close_table/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#code_change-3">code_change/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#create_schema-1">create_schema/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#create_schema-2">create_schema/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#create_table-3">create_table/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#decode_key-1">decode_key/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#decode_key-2">decode_key/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#decode_val-1">decode_val/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#decode_val-3">decode_val/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#default_alias-0">default_alias/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#delete-3">delete/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#delete_table-2">delete_table/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#encode_key-1">encode_key/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#encode_key-2">encode_key/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#encode_val-1">encode_val/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#encode_val-2">encode_val/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#first-2">first/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#fixtable-3">fixtable/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#handle_call-3">handle_call/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#handle_cast-2">handle_cast/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#handle_info-2">handle_info/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#index_is_consistent-3">index_is_consistent/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#info-3">info/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#init-1">init/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#init_backend-0">init_backend/0</a></td><td>Called by mnesia_schema in order to intialize the backend.</td></tr>
<tr><td valign="top"><a href="#insert-3">insert/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#is_index_consistent-2">is_index_consistent/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#ix_listvals-3">ix_listvals/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#ix_prefixes-3">ix_prefixes/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#last-2">last/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#load_table-4">load_table/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#lookup-3">lookup/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#match_delete-3">match_delete/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#next-3">next/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#prev-3">prev/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#real_suffixes-0">real_suffixes/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#receive_data-5">receive_data/5</a></td><td></td></tr>
<tr><td valign="top"><a href="#receive_done-4">receive_done/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#receiver_first_message-4">receiver_first_message/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#register-0">register/0</a></td><td>Equivalent to <a href="#register-1"><tt>register(rocksdb_copies)</tt></a>.
</td></tr>
<tr><td valign="top"><a href="#register-1">register/1</a></td><td>Convenience function for registering a mnesia_rocksdb backend plugin.</td></tr>
<tr><td valign="top"><a href="#remove_aliases-1">remove_aliases/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#repair_continuation-2">repair_continuation/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#select-1">select/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#select-3">select/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#select-4">select/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#semantics-2">semantics/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#sender_handle_info-5">sender_handle_info/5</a></td><td></td></tr>
<tr><td valign="top"><a href="#sender_init-4">sender_init/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#show_table-1">show_table/1</a></td><td>A debug function that shows the rocksdb table content.</td></tr>
<tr><td valign="top"><a href="#show_table-2">show_table/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#slot-3">slot/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#start_proc-6">start_proc/6</a></td><td></td></tr>
<tr><td valign="top"><a href="#sync_close_table-2">sync_close_table/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#terminate-2">terminate/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#tmp_suffixes-0">tmp_suffixes/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#update_counter-4">update_counter/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#validate_key-6">validate_key/6</a></td><td></td></tr>
<tr><td valign="top"><a href="#validate_record-6">validate_record/6</a></td><td></td></tr>
</table>
<h2><a name="functions">Function Details</a></h2>
<h3 class="function"><a name="add_aliases-1">add_aliases/1</a></h3>
<div class="spec">
<p><tt>add_aliases(Aliases) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="check_definition-4">check_definition/4</a></h3>
<div class="spec">
<p><tt>check_definition(Alias, Tab, Nodes, Props) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="close_table-2">close_table/2</a></h3>
<div class="spec">
<p><tt>close_table(Alias, Tab) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="code_change-3">code_change/3</a></h3>
<div class="spec">
<p><tt>code_change(FromVsn, St, Extra) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="create_schema-1">create_schema/1</a></h3>
<div class="spec">
<p><tt>create_schema(Nodes) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="create_schema-2">create_schema/2</a></h3>
<div class="spec">
<p><tt>create_schema(Nodes, Aliases) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="create_table-3">create_table/3</a></h3>
<div class="spec">
<p><tt>create_table(Alias, Tab, Props) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="decode_key-1">decode_key/1</a></h3>
<div class="spec">
<p><tt>decode_key(Key) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="decode_key-2">decode_key/2</a></h3>
<div class="spec">
<p><tt>decode_key(Key, Metadata) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="decode_val-1">decode_val/1</a></h3>
<div class="spec">
<p><tt>decode_val(Val) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="decode_val-3">decode_val/3</a></h3>
<div class="spec">
<p><tt>decode_val(Val, Key, Metadata) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="default_alias-0">default_alias/0</a></h3>
<div class="spec">
<p><tt>default_alias() -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="delete-3">delete/3</a></h3>
<div class="spec">
<p><tt>delete(Alias, Tab, Key) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="delete_table-2">delete_table/2</a></h3>
<div class="spec">
<p><tt>delete_table(Alias, Tab) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="encode_key-1">encode_key/1</a></h3>
<div class="spec">
<p><tt>encode_key(Key) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="encode_key-2">encode_key/2</a></h3>
<div class="spec">
<p><tt>encode_key(Key, Metadata) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="encode_val-1">encode_val/1</a></h3>
<div class="spec">
<p><tt>encode_val(Val) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="encode_val-2">encode_val/2</a></h3>
<div class="spec">
<p><tt>encode_val(Val, Metadata) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="first-2">first/2</a></h3>
<div class="spec">
<p><tt>first(Alias, Tab) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="fixtable-3">fixtable/3</a></h3>
<div class="spec">
<p><tt>fixtable(Alias, Tab, Bool) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="handle_call-3">handle_call/3</a></h3>
<div class="spec">
<p><tt>handle_call(M, From, St) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="handle_cast-2">handle_cast/2</a></h3>
<div class="spec">
<p><tt>handle_cast(X1, St) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="handle_info-2">handle_info/2</a></h3>
<div class="spec">
<p><tt>handle_info(EXIT, St) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="index_is_consistent-3">index_is_consistent/3</a></h3>
<div class="spec">
<p><tt>index_is_consistent(Alias, X2, Bool) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="info-3">info/3</a></h3>
<div class="spec">
<p><tt>info(Alias, Tab, Item) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="init-1">init/1</a></h3>
<div class="spec">
<p><tt>init(X1) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="init_backend-0">init_backend/0</a></h3>
<div class="spec">
<p><tt>init_backend() -&gt; any()</tt></p>
<p> </p>
</div><p><p>Called by mnesia_schema in order to intialize the backend</p>
<p>This is called when the backend is registered with the first alias, or ...</p>
<p>See OTP issue #425 (16 Feb 2021). This callback is supposed to be called
before first use of the backend, but unfortunately, it is only called at
mnesia startup and when a backend module is registered MORE THAN ONCE.
This means we need to handle this function being called multiple times.</p>
<p>The bug has been fixed as of OTP 24.0-rc3</p>
<p>If processes need to be started, this can be done using
<code>mnesia_ext_sup:start_proc(Name, Mod, F, Args [, Opts])</code>
where Opts are parameters for the supervised child:</p>
* <code>restart</code> (default: <code>transient</code>)
* <code>shutdown</code> (default: <code>120000</code>)
* <code>type</code> (default: <code>worker</code>)
* <code>modules</code> (default: <code>[Mod]</code>)</p>
<h3 class="function"><a name="insert-3">insert/3</a></h3>
<div class="spec">
<p><tt>insert(Alias, Tab, Obj) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="is_index_consistent-2">is_index_consistent/2</a></h3>
<div class="spec">
<p><tt>is_index_consistent(Alias, X2) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="ix_listvals-3">ix_listvals/3</a></h3>
<div class="spec">
<p><tt>ix_listvals(Tab, Pos, Obj) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="ix_prefixes-3">ix_prefixes/3</a></h3>
<div class="spec">
<p><tt>ix_prefixes(Tab, Pos, Obj) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="last-2">last/2</a></h3>
<div class="spec">
<p><tt>last(Alias, Tab) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="load_table-4">load_table/4</a></h3>
<div class="spec">
<p><tt>load_table(Alias, Tab, LoadReason, Props) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="lookup-3">lookup/3</a></h3>
<div class="spec">
<p><tt>lookup(Alias, Tab, Key) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="match_delete-3">match_delete/3</a></h3>
<div class="spec">
<p><tt>match_delete(Alias, Tab, Pat) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="next-3">next/3</a></h3>
<div class="spec">
<p><tt>next(Alias, Tab, Key) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="prev-3">prev/3</a></h3>
<div class="spec">
<p><tt>prev(Alias, Tab, Key) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="real_suffixes-0">real_suffixes/0</a></h3>
<div class="spec">
<p><tt>real_suffixes() -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="receive_data-5">receive_data/5</a></h3>
<div class="spec">
<p><tt>receive_data(Data, Alias, Tab, Sender, State) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="receive_done-4">receive_done/4</a></h3>
<div class="spec">
<p><tt>receive_done(Alias, Tab, Sender, State) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="receiver_first_message-4">receiver_first_message/4</a></h3>
<div class="spec">
<p><tt>receiver_first_message(Pid, Msg, Alias, Tab) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="register-0">register/0</a></h3>
<div class="spec">
<p><tt>register() -&gt; {ok, <a href="#type-alias">alias()</a>} | {error, term()}</tt><br></p>
<p> </p>
</div><p>Equivalent to <a href="#register-1"><tt>register(rocksdb_copies)</tt></a>.</p>
<h3 class="function"><a name="register-1">register/1</a></h3>
<div class="spec">
<p><tt>register(Alias::<a href="#type-alias">alias()</a>) -&gt; {ok, <a href="#type-alias">alias()</a>} | <a href="#type-error">error()</a></tt><br></p>
<p> </p>
</div><p><p>Convenience function for registering a mnesia_rocksdb backend plugin</p>
The function used to register a plugin is <code>mnesia_schema:add_backend_type(Alias, Module)</code>
where <code>Module</code> implements a backend_type behavior. <code>Alias</code> is an atom, and is used
in the same way as <code>ram_copies</code> etc. The default alias is <code>rocksdb_copies</code>.</p>
<h3 class="function"><a name="remove_aliases-1">remove_aliases/1</a></h3>
<div class="spec">
<p><tt>remove_aliases(Aliases) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="repair_continuation-2">repair_continuation/2</a></h3>
<div class="spec">
<p><tt>repair_continuation(Cont, Ms) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="select-1">select/1</a></h3>
<div class="spec">
<p><tt>select(Cont) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="select-3">select/3</a></h3>
<div class="spec">
<p><tt>select(Alias, Tab, Ms) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="select-4">select/4</a></h3>
<div class="spec">
<p><tt>select(Alias, IxTab, Ms, Limit) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="semantics-2">semantics/2</a></h3>
<div class="spec">
<p><tt>semantics(Alias, X2) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="sender_handle_info-5">sender_handle_info/5</a></h3>
<div class="spec">
<p><tt>sender_handle_info(Msg, Alias, Tab, ReceiverPid, Cont) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="sender_init-4">sender_init/4</a></h3>
<div class="spec">
<p><tt>sender_init(Alias, Tab, RemoteStorage, Pid) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="show_table-1">show_table/1</a></h3>
<div class="spec">
<p><tt>show_table(Tab) -&gt; any()</tt></p>
<p> </p>
</div><p>A debug function that shows the rocksdb table content</p>
<h3 class="function"><a name="show_table-2">show_table/2</a></h3>
<div class="spec">
<p><tt>show_table(Tab, Limit) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="slot-3">slot/3</a></h3>
<div class="spec">
<p><tt>slot(Alias, Tab, Pos) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="start_proc-6">start_proc/6</a></h3>
<div class="spec">
<p><tt>start_proc(Alias, Tab, Type, ProcName, Props, RdbOpts) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="sync_close_table-2">sync_close_table/2</a></h3>
<div class="spec">
<p><tt>sync_close_table(Alias, Tab) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="terminate-2">terminate/2</a></h3>
<div class="spec">
<p><tt>terminate(Reason, St) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="tmp_suffixes-0">tmp_suffixes/0</a></h3>
<div class="spec">
<p><tt>tmp_suffixes() -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="update_counter-4">update_counter/4</a></h3>
<div class="spec">
<p><tt>update_counter(Alias, Tab, C, Val) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="validate_key-6">validate_key/6</a></h3>
<div class="spec">
<p><tt>validate_key(Alias, Tab, RecName, Arity, Type, Key) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="validate_record-6">validate_record/6</a></h3>
<div class="spec">
<p><tt>validate_record(Alias, Tab, RecName, Arity, Type, Obj) -&gt; any()</tt></p>
<p> </p>
</div>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated by EDoc</i></p>
</body>
</html>

View File

@ -0,0 +1,294 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Module mnesia_rocksdb_admin</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<hr>
<h1>Module mnesia_rocksdb_admin</h1>
<ul class="index"><li><a href="#types">Data Types</a></li><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>
<p><b>Behaviours:</b> <a href="gen_server.html"><tt>gen_server</tt></a>.</p>
<h2><a name="types">Data Types</a></h2>
<h3 class="typedecl"><a name="type-alias">alias()</a></h3>
<p><tt>alias() = atom()</tt></p>
<h3 class="typedecl"><a name="type-backend">backend()</a></h3>
<p><tt>backend() = #{db_ref := <a href="#type-db_ref">db_ref()</a>, cf_info := #{<a href="#type-table">table()</a> := <a href="#type-cf">cf()</a>}}</tt></p>
<h3 class="typedecl"><a name="type-cf">cf()</a></h3>
<p><tt>cf() = <a href="/home/uwiger/ae/mnesia_rocksdb/doc/mrdb.html#type-db_ref">mrdb:db_ref()</a></tt></p>
<h3 class="typedecl"><a name="type-db_ref">db_ref()</a></h3>
<p><tt>db_ref() = <a href="/home/uwiger/ae/mnesia_rocksdb/_build/default/lib/rocksdb/doc/rocksdb.html#type-db_handle">rocksdb:db_handle()</a></tt></p>
<h3 class="typedecl"><a name="type-gen_server_noreply">gen_server_noreply()</a></h3>
<p><tt>gen_server_noreply() = {noreply, <a href="#type-st">st()</a>} | {stop, <a href="#type-reason">reason()</a>, <a href="#type-st">st()</a>}</tt></p>
<h3 class="typedecl"><a name="type-gen_server_reply">gen_server_reply()</a></h3>
<p><tt>gen_server_reply() = {reply, <a href="#type-reply">reply()</a>, <a href="#type-st">st()</a>} | {stop, <a href="#type-reason">reason()</a>, <a href="#type-reply">reply()</a>, <a href="#type-st">st()</a>}</tt></p>
<h3 class="typedecl"><a name="type-properties">properties()</a></h3>
<p><tt>properties() = [{atom(), any()}]</tt></p>
<h3 class="typedecl"><a name="type-reason">reason()</a></h3>
<p><tt>reason() = any()</tt></p>
<h3 class="typedecl"><a name="type-reply">reply()</a></h3>
<p><tt>reply() = any()</tt></p>
<h3 class="typedecl"><a name="type-req">req()</a></h3>
<p><tt>req() = {create_table, <a href="#type-table">table()</a>, <a href="#type-properties">properties()</a>} | {delete_table, <a href="#type-table">table()</a>} | {load_table, <a href="#type-table">table()</a>, <a href="#type-properties">properties()</a>} | {related_resources, <a href="#type-table">table()</a>} | {get_ref, <a href="#type-table">table()</a>} | {add_aliases, [<a href="#type-alias">alias()</a>]} | {write_table_property, <a href="#type-tabname">tabname()</a>, tuple()} | {remove_aliases, [<a href="#type-alias">alias()</a>]} | {migrate, [{<a href="#type-tabname">tabname()</a>, map()}], <a href="#type-rpt">rpt()</a>} | {prep_close, <a href="#type-table">table()</a>} | {close_table, <a href="#type-table">table()</a>} | {clear_table, <a href="#type-table">table()</a> | <a href="#type-cf">cf()</a>}</tt></p>
<h3 class="typedecl"><a name="type-rpt">rpt()</a></h3>
<p><tt>rpt() = undefined | map()</tt></p>
<h3 class="typedecl"><a name="type-st">st()</a></h3>
<p><tt>st() = #st{backends = #{<a href="#type-alias">alias()</a> =&gt; <a href="#type-backend">backend()</a>}, standalone = #{{<a href="#type-alias">alias()</a>, <a href="#type-table">table()</a>} := <a href="#type-cf">cf()</a>}, default_opts = [{atom(), term()}]}</tt></p>
<h3 class="typedecl"><a name="type-table">table()</a></h3>
<p><tt>table() = <a href="#type-tabname">tabname()</a> | {admin, <a href="#type-alias">alias()</a>} | {<a href="#type-tabname">tabname()</a>, index, any()} | {<a href="#type-tabname">tabname()</a>, retainer, any()}</tt></p>
<h3 class="typedecl"><a name="type-tabname">tabname()</a></h3>
<p><tt>tabname() = atom()</tt></p>
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#add_aliases-1">add_aliases/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#clear_table-1">clear_table/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#close_table-2">close_table/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#code_change-3">code_change/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#create_table-3">create_table/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#delete_table-2">delete_table/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#ensure_started-0">ensure_started/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#get_cached_env-2">get_cached_env/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#get_ref-1">get_ref/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#get_ref-2">get_ref/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#handle_call-3">handle_call/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#handle_cast-2">handle_cast/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#handle_info-2">handle_info/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#init-1">init/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#load_table-3">load_table/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#meta-0">meta/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#migrate_standalone-2">migrate_standalone/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#migrate_standalone-3">migrate_standalone/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#prep_close-2">prep_close/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#read_info-1">read_info/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#read_info-2">read_info/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#read_info-4">read_info/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#related_resources-2">related_resources/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#remove_aliases-1">remove_aliases/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#request_ref-2">request_ref/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#set_and_cache_env-2">set_and_cache_env/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#start_link-0">start_link/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#terminate-2">terminate/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#write_info-4">write_info/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#write_table_property-3">write_table_property/3</a></td><td></td></tr>
</table>
<h2><a name="functions">Function Details</a></h2>
<h3 class="function"><a name="add_aliases-1">add_aliases/1</a></h3>
<div class="spec">
<p><tt>add_aliases(Aliases) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="clear_table-1">clear_table/1</a></h3>
<div class="spec">
<p><tt>clear_table(Name) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="close_table-2">close_table/2</a></h3>
<div class="spec">
<p><tt>close_table(Alias, Name) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="code_change-3">code_change/3</a></h3>
<div class="spec">
<p><tt>code_change(FromVsn, St, Extra) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="create_table-3">create_table/3</a></h3>
<div class="spec">
<p><tt>create_table(Alias, Name, Props) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="delete_table-2">delete_table/2</a></h3>
<div class="spec">
<p><tt>delete_table(Alias::<a href="#type-alias">alias()</a>, Name::<a href="#type-tabname">tabname()</a>) -&gt; ok</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="ensure_started-0">ensure_started/0</a></h3>
<div class="spec">
<p><tt>ensure_started() -&gt; ok</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="get_cached_env-2">get_cached_env/2</a></h3>
<div class="spec">
<p><tt>get_cached_env(Key, Default) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="get_ref-1">get_ref/1</a></h3>
<div class="spec">
<p><tt>get_ref(Name) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="get_ref-2">get_ref/2</a></h3>
<div class="spec">
<p><tt>get_ref(Name, Default) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="handle_call-3">handle_call/3</a></h3>
<div class="spec">
<p><tt>handle_call(Req::{<a href="#type-alias">alias()</a>, <a href="#type-req">req()</a>}, From::any(), St::<a href="#type-st">st()</a>) -&gt; <a href="#type-gen_server_reply">gen_server_reply()</a></tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="handle_cast-2">handle_cast/2</a></h3>
<div class="spec">
<p><tt>handle_cast(Msg::any(), St::<a href="#type-st">st()</a>) -&gt; <a href="#type-gen_server_noreply">gen_server_noreply()</a></tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="handle_info-2">handle_info/2</a></h3>
<div class="spec">
<p><tt>handle_info(Msg::any(), St::<a href="#type-st">st()</a>) -&gt; <a href="#type-gen_server_noreply">gen_server_noreply()</a></tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="init-1">init/1</a></h3>
<div class="spec">
<p><tt>init(X1) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="load_table-3">load_table/3</a></h3>
<div class="spec">
<p><tt>load_table(Alias, Name, Props) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="meta-0">meta/0</a></h3>
<div class="spec">
<p><tt>meta() -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="migrate_standalone-2">migrate_standalone/2</a></h3>
<div class="spec">
<p><tt>migrate_standalone(Alias, Tabs) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="migrate_standalone-3">migrate_standalone/3</a></h3>
<div class="spec">
<p><tt>migrate_standalone(Alias, Tabs, Rpt0) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="prep_close-2">prep_close/2</a></h3>
<div class="spec">
<p><tt>prep_close(Alias, Tab) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="read_info-1">read_info/1</a></h3>
<div class="spec">
<p><tt>read_info(TRec) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="read_info-2">read_info/2</a></h3>
<div class="spec">
<p><tt>read_info(Alias, Tab) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="read_info-4">read_info/4</a></h3>
<div class="spec">
<p><tt>read_info(Alias, Tab, K, Default) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="related_resources-2">related_resources/2</a></h3>
<div class="spec">
<p><tt>related_resources(Alias, Name) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="remove_aliases-1">remove_aliases/1</a></h3>
<div class="spec">
<p><tt>remove_aliases(Aliases) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="request_ref-2">request_ref/2</a></h3>
<div class="spec">
<p><tt>request_ref(Alias, Name) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="set_and_cache_env-2">set_and_cache_env/2</a></h3>
<div class="spec">
<p><tt>set_and_cache_env(Key, Value) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="start_link-0">start_link/0</a></h3>
<div class="spec">
<p><tt>start_link() -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="terminate-2">terminate/2</a></h3>
<div class="spec">
<p><tt>terminate(X1, St) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="write_info-4">write_info/4</a></h3>
<div class="spec">
<p><tt>write_info(Alias, Tab, K, V) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="write_table_property-3">write_table_property/3</a></h3>
<div class="spec">
<p><tt>write_table_property(Alias, Tab, Prop) -&gt; any()</tt></p>
<p> </p>
</div>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated by EDoc</i></p>
</body>
</html>

View File

@ -0,0 +1,40 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Module mnesia_rocksdb_app</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<hr>
<h1>Module mnesia_rocksdb_app</h1>
<ul class="index"><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>
<p><b>Behaviours:</b> <a href="application.html"><tt>application</tt></a>.</p>
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#start-2">start/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#stop-1">stop/1</a></td><td></td></tr>
</table>
<h2><a name="functions">Function Details</a></h2>
<h3 class="function"><a name="start-2">start/2</a></h3>
<div class="spec">
<p><tt>start(StartType, StartArgs) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="stop-1">stop/1</a></h3>
<div class="spec">
<p><tt>stop(State) -&gt; any()</tt></p>
<p> </p>
</div>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated by EDoc</i></p>
</body>
</html>

181
doc/mnesia_rocksdb_lib.html Normal file
View File

@ -0,0 +1,181 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Module mnesia_rocksdb_lib</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<hr>
<h1>Module mnesia_rocksdb_lib</h1>
<ul class="index"><li><a href="#description">Description</a></li><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>RocksDB update wrappers, in separate module for easy tracing and mocking.
<h2><a name="description">Description</a></h2>RocksDB update wrappers, in separate module for easy tracing and mocking.
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#check_encoding-2">check_encoding/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#create_mountpoint-1">create_mountpoint/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#data_mountpoint-1">data_mountpoint/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#decode-2">decode/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#decode_key-1">decode_key/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#decode_key-2">decode_key/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#decode_val-1">decode_val/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#decode_val-3">decode_val/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#default_encoding-3">default_encoding/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#delete-3">delete/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#encode-2">encode/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#encode_key-1">encode_key/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#encode_key-2">encode_key/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#encode_val-1">encode_val/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#encode_val-2">encode_val/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#keypos-1">keypos/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#open_rocksdb-3">open_rocksdb/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#put-4">put/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#tabname-1">tabname/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#valid_key_type-2">valid_key_type/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#valid_obj_type-2">valid_obj_type/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#write-3">write/3</a></td><td></td></tr>
</table>
<h2><a name="functions">Function Details</a></h2>
<h3 class="function"><a name="check_encoding-2">check_encoding/2</a></h3>
<div class="spec">
<p><tt>check_encoding(Encoding, Attributes) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="create_mountpoint-1">create_mountpoint/1</a></h3>
<div class="spec">
<p><tt>create_mountpoint(Tab) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="data_mountpoint-1">data_mountpoint/1</a></h3>
<div class="spec">
<p><tt>data_mountpoint(Tab) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="decode-2">decode/2</a></h3>
<div class="spec">
<p><tt>decode(Val, X2) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="decode_key-1">decode_key/1</a></h3>
<div class="spec">
<p><tt>decode_key(CodedKey::binary()) -&gt; any()</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="decode_key-2">decode_key/2</a></h3>
<div class="spec">
<p><tt>decode_key(CodedKey, Enc) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="decode_val-1">decode_val/1</a></h3>
<div class="spec">
<p><tt>decode_val(CodedVal::binary()) -&gt; any()</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="decode_val-3">decode_val/3</a></h3>
<div class="spec">
<p><tt>decode_val(CodedVal, K, Ref) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="default_encoding-3">default_encoding/3</a></h3>
<div class="spec">
<p><tt>default_encoding(X1, Type, As) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="delete-3">delete/3</a></h3>
<div class="spec">
<p><tt>delete(Ref, K, Opts) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="encode-2">encode/2</a></h3>
<div class="spec">
<p><tt>encode(Value, X2) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="encode_key-1">encode_key/1</a></h3>
<div class="spec">
<p><tt>encode_key(Key::any()) -&gt; binary()</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="encode_key-2">encode_key/2</a></h3>
<div class="spec">
<p><tt>encode_key(Key, X2) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="encode_val-1">encode_val/1</a></h3>
<div class="spec">
<p><tt>encode_val(Val::any()) -&gt; binary()</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="encode_val-2">encode_val/2</a></h3>
<div class="spec">
<p><tt>encode_val(Val, Enc) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="keypos-1">keypos/1</a></h3>
<div class="spec">
<p><tt>keypos(Tab) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="open_rocksdb-3">open_rocksdb/3</a></h3>
<div class="spec">
<p><tt>open_rocksdb(MPd, RdbOpts, CFs) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="put-4">put/4</a></h3>
<div class="spec">
<p><tt>put(Ref, K, V, Opts) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="tabname-1">tabname/1</a></h3>
<div class="spec">
<p><tt>tabname(Tab) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="valid_key_type-2">valid_key_type/2</a></h3>
<div class="spec">
<p><tt>valid_key_type(X1, Key) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="valid_obj_type-2">valid_obj_type/2</a></h3>
<div class="spec">
<p><tt>valid_obj_type(X1, Obj) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="write-3">write/3</a></h3>
<div class="spec">
<p><tt>write(X1, L, Opts) -&gt; any()</tt></p>
<p> </p>
</div>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated by EDoc</i></p>
</body>
</html>

View File

@ -0,0 +1,96 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Module mnesia_rocksdb_params</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<hr>
<h1>Module mnesia_rocksdb_params</h1>
<ul class="index"><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>
<p><b>Behaviours:</b> <a href="gen_server.html"><tt>gen_server</tt></a>.</p>
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#code_change-3">code_change/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#delete-1">delete/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#handle_call-3">handle_call/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#handle_cast-2">handle_cast/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#handle_info-2">handle_info/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#init-1">init/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#lookup-2">lookup/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#start_link-0">start_link/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#store-2">store/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#terminate-2">terminate/2</a></td><td></td></tr>
</table>
<h2><a name="functions">Function Details</a></h2>
<h3 class="function"><a name="code_change-3">code_change/3</a></h3>
<div class="spec">
<p><tt>code_change(X1, S, X3) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="delete-1">delete/1</a></h3>
<div class="spec">
<p><tt>delete(Tab) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="handle_call-3">handle_call/3</a></h3>
<div class="spec">
<p><tt>handle_call(X1, X2, S) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="handle_cast-2">handle_cast/2</a></h3>
<div class="spec">
<p><tt>handle_cast(X1, S) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="handle_info-2">handle_info/2</a></h3>
<div class="spec">
<p><tt>handle_info(X1, S) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="init-1">init/1</a></h3>
<div class="spec">
<p><tt>init(X1) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="lookup-2">lookup/2</a></h3>
<div class="spec">
<p><tt>lookup(Tab, Default) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="start_link-0">start_link/0</a></h3>
<div class="spec">
<p><tt>start_link() -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="store-2">store/2</a></h3>
<div class="spec">
<p><tt>store(Tab, Params) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="terminate-2">terminate/2</a></h3>
<div class="spec">
<p><tt>terminate(X1, X2) -&gt; any()</tt></p>
<p> </p>
</div>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated by EDoc</i></p>
</body>
</html>

View File

@ -0,0 +1,40 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Module mnesia_rocksdb_sup</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<hr>
<h1>Module mnesia_rocksdb_sup</h1>
<ul class="index"><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>
<p><b>Behaviours:</b> <a href="supervisor.html"><tt>supervisor</tt></a>.</p>
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#init-1">init/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#start_link-0">start_link/0</a></td><td></td></tr>
</table>
<h2><a name="functions">Function Details</a></h2>
<h3 class="function"><a name="init-1">init/1</a></h3>
<div class="spec">
<p><tt>init(X1) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="start_link-0">start_link/0</a></h3>
<div class="spec">
<p><tt>start_link() -&gt; any()</tt></p>
<p> </p>
</div>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated by EDoc</i></p>
</body>
</html>

View File

@ -0,0 +1,151 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Module mnesia_rocksdb_tuning</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<hr>
<h1>Module mnesia_rocksdb_tuning</h1>
<ul class="index"><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#cache-1">cache/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#calc_sizes-0">calc_sizes/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#calc_sizes-1">calc_sizes/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#count_rdb_tabs-0">count_rdb_tabs/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#count_rdb_tabs-1">count_rdb_tabs/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#default-1">default/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#describe_env-0">describe_env/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#get_avail_ram-0">get_avail_ram/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#get_maxfiles-0">get_maxfiles/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#get_maxfiles-1">get_maxfiles/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#ideal_max_files-0">ideal_max_files/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#ideal_max_files-1">ideal_max_files/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#max_files-1">max_files/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#rdb_indexes-0">rdb_indexes/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#rdb_indexes-1">rdb_indexes/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#rdb_tabs-0">rdb_tabs/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#rdb_tabs-1">rdb_tabs/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#write_buffer-1">write_buffer/1</a></td><td></td></tr>
</table>
<h2><a name="functions">Function Details</a></h2>
<h3 class="function"><a name="cache-1">cache/1</a></h3>
<div class="spec">
<p><tt>cache(X1) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="calc_sizes-0">calc_sizes/0</a></h3>
<div class="spec">
<p><tt>calc_sizes() -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="calc_sizes-1">calc_sizes/1</a></h3>
<div class="spec">
<p><tt>calc_sizes(D) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="count_rdb_tabs-0">count_rdb_tabs/0</a></h3>
<div class="spec">
<p><tt>count_rdb_tabs() -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="count_rdb_tabs-1">count_rdb_tabs/1</a></h3>
<div class="spec">
<p><tt>count_rdb_tabs(Db) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="default-1">default/1</a></h3>
<div class="spec">
<p><tt>default(X1) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="describe_env-0">describe_env/0</a></h3>
<div class="spec">
<p><tt>describe_env() -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="get_avail_ram-0">get_avail_ram/0</a></h3>
<div class="spec">
<p><tt>get_avail_ram() -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="get_maxfiles-0">get_maxfiles/0</a></h3>
<div class="spec">
<p><tt>get_maxfiles() -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="get_maxfiles-1">get_maxfiles/1</a></h3>
<div class="spec">
<p><tt>get_maxfiles(X1) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="ideal_max_files-0">ideal_max_files/0</a></h3>
<div class="spec">
<p><tt>ideal_max_files() -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="ideal_max_files-1">ideal_max_files/1</a></h3>
<div class="spec">
<p><tt>ideal_max_files(D) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="max_files-1">max_files/1</a></h3>
<div class="spec">
<p><tt>max_files(X1) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="rdb_indexes-0">rdb_indexes/0</a></h3>
<div class="spec">
<p><tt>rdb_indexes() -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="rdb_indexes-1">rdb_indexes/1</a></h3>
<div class="spec">
<p><tt>rdb_indexes(Db) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="rdb_tabs-0">rdb_tabs/0</a></h3>
<div class="spec">
<p><tt>rdb_tabs() -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="rdb_tabs-1">rdb_tabs/1</a></h3>
<div class="spec">
<p><tt>rdb_tabs(Db) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="write_buffer-1">write_buffer/1</a></h3>
<div class="spec">
<p><tt>write_buffer(X1) -&gt; any()</tt></p>
<p> </p>
</div>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated by EDoc</i></p>
</body>
</html>

24
doc/modules-frame.html Normal file
View File

@ -0,0 +1,24 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>The mnesia_rocksdb application</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<h2 class="indextitle">Modules</h2>
<table width="100%" border="0" summary="list of modules">
<tr><td><a href="mnesia_rocksdb.html" target="overviewFrame" class="module">mnesia_rocksdb</a></td></tr>
<tr><td><a href="mnesia_rocksdb_admin.html" target="overviewFrame" class="module">mnesia_rocksdb_admin</a></td></tr>
<tr><td><a href="mnesia_rocksdb_app.html" target="overviewFrame" class="module">mnesia_rocksdb_app</a></td></tr>
<tr><td><a href="mnesia_rocksdb_lib.html" target="overviewFrame" class="module">mnesia_rocksdb_lib</a></td></tr>
<tr><td><a href="mnesia_rocksdb_params.html" target="overviewFrame" class="module">mnesia_rocksdb_params</a></td></tr>
<tr><td><a href="mnesia_rocksdb_sup.html" target="overviewFrame" class="module">mnesia_rocksdb_sup</a></td></tr>
<tr><td><a href="mnesia_rocksdb_tuning.html" target="overviewFrame" class="module">mnesia_rocksdb_tuning</a></td></tr>
<tr><td><a href="mrdb.html" target="overviewFrame" class="module">mrdb</a></td></tr>
<tr><td><a href="mrdb_index.html" target="overviewFrame" class="module">mrdb_index</a></td></tr>
<tr><td><a href="mrdb_mutex.html" target="overviewFrame" class="module">mrdb_mutex</a></td></tr>
<tr><td><a href="mrdb_mutex_serializer.html" target="overviewFrame" class="module">mrdb_mutex_serializer</a></td></tr>
<tr><td><a href="mrdb_select.html" target="overviewFrame" class="module">mrdb_select</a></td></tr>
<tr><td><a href="mrdb_stats.html" target="overviewFrame" class="module">mrdb_stats</a></td></tr></table>
</body>
</html>

728
doc/mrdb.html Normal file
View File

@ -0,0 +1,728 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Module mrdb</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<hr>
<h1>Module mrdb</h1>
<ul class="index"><li><a href="#description">Description</a></li><li><a href="#types">Data Types</a></li><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>Mid-level access API for Mnesia-managed rocksdb tables.
<h2><a name="description">Description</a></h2><p>Mid-level access API for Mnesia-managed rocksdb tables</p>
<p>This module implements access functions for the mnesia_rocksdb
backend plugin. The functions are designed to also support
direct access to rocksdb with little overhead. Such direct
access will maintain existing indexes, but not support
replication.</p>
<p>Each table has a metadata structure stored as a persistent
term for fast access. The structure of the metadata is as
follows:</p>
<pre> #{ name := &lt;Logical table name&gt;
, db_ref := &lt;Rocksdb database Ref&gt;
, cf_handle := &lt;Rocksdb column family handle&gt;
, activity := Ongoing batch or transaction, if any (map())
, attr_pos := #{AttrName := Pos}
, mode := &lt;Set to 'mnesia' for mnesia access flows&gt;
, properties := &lt;Mnesia table props in map format&gt;
, type := column_family | standalone
}</pre>
<p>Helper functions like <code>as_batch(Ref, fun(R) -&gt; ... end)</code> and
<code>with_iterator(Ref, fun(I) -&gt; ... end)</code> add some extra
convenience on top of the <code>rocksdb</code> API.</p>
Note that no automatic provision exists to manage concurrent
updates via mnesia AND direct access to this API. It's advisable
to use ONE primary mode of access. If replication is used,
the mnesia API will support this, but direct <code>mrdb</code> updates will
not be replicated.
<h2><a name="types">Data Types</a></h2>
<h3 class="typedecl"><a name="type-activity">activity()</a></h3>
<p><tt>activity() = <a href="#type-tx_activity">tx_activity()</a> | <a href="#type-batch_activity">batch_activity()</a></tt></p>
<h3 class="typedecl"><a name="type-activity_type">activity_type()</a></h3>
<p><tt>activity_type() = <a href="#type-mrdb_activity_type">mrdb_activity_type()</a> | <a href="#type-mnesia_activity_type">mnesia_activity_type()</a></tt></p>
<h3 class="typedecl"><a name="type-admin_tab">admin_tab()</a></h3>
<p><tt>admin_tab() = {admin, <a href="#type-alias">alias()</a>}</tt></p>
<h3 class="typedecl"><a name="type-alias">alias()</a></h3>
<p><tt>alias() = atom()</tt></p>
<h3 class="typedecl"><a name="type-attr_pos">attr_pos()</a></h3>
<p><tt>attr_pos() = #{atom() := <a href="#type-pos">pos()</a>}</tt></p>
<h3 class="typedecl"><a name="type-batch_activity">batch_activity()</a></h3>
<p><tt>batch_activity() = #{type := batch, handle := <a href="#type-batch_handle">batch_handle()</a>}</tt></p>
<h3 class="typedecl"><a name="type-batch_handle">batch_handle()</a></h3>
<p><tt>batch_handle() = <a href="/home/uwiger/ae/mnesia_rocksdb/_build/default/lib/rocksdb/doc/rocksdb.html#type-batch_handle">rocksdb:batch_handle()</a></tt></p>
<h3 class="typedecl"><a name="type-cf_handle">cf_handle()</a></h3>
<p><tt>cf_handle() = <a href="/home/uwiger/ae/mnesia_rocksdb/_build/default/lib/rocksdb/doc/rocksdb.html#type-cf_handle">rocksdb:cf_handle()</a></tt></p>
<h3 class="typedecl"><a name="type-db_handle">db_handle()</a></h3>
<p><tt>db_handle() = <a href="/home/uwiger/ae/mnesia_rocksdb/_build/default/lib/rocksdb/doc/rocksdb.html#type-db_handle">rocksdb:db_handle()</a></tt></p>
<h3 class="typedecl"><a name="type-db_ref">db_ref()</a></h3>
<p><tt>db_ref() = #{name =&gt; <a href="#type-table">table()</a>, alias =&gt; atom(), vsn =&gt; non_neg_integer(), db_ref := <a href="#type-db_handle">db_handle()</a>, cf_handle := <a href="#type-cf_handle">cf_handle()</a>, semantics := <a href="#type-semantics">semantics()</a>, encoding := <a href="#type-encoding">encoding()</a>, attr_pos := <a href="#type-attr_pos">attr_pos()</a>, type := column_family | standalone, status := open | closed | pre_existing, properties := <a href="#type-properties">properties()</a>, mode =&gt; mnesia, ix_vals_f =&gt; fun((tuple()) -&gt; [any()]), activity =&gt; <a href="#type-activity">activity()</a>, term() =&gt; term()}</tt></p>
<h3 class="typedecl"><a name="type-encoding">encoding()</a></h3>
<p><tt>encoding() = raw | sext | term | {<a href="#type-key_encoding">key_encoding()</a>, <a href="#type-val_encoding">val_encoding()</a>}</tt></p>
<h3 class="typedecl"><a name="type-error">error()</a></h3>
<p><tt>error() = {error, any()}</tt></p>
<h3 class="typedecl"><a name="type-index">index()</a></h3>
<p><tt>index() = {<a href="#type-tab_name">tab_name()</a>, index, any()}</tt></p>
<h3 class="typedecl"><a name="type-index_position">index_position()</a></h3>
<p><tt>index_position() = atom() | <a href="#type-pos">pos()</a></tt></p>
<h3 class="typedecl"><a name="type-inner">inner()</a></h3>
<p><tt>inner() = non_neg_integer()</tt></p>
<h3 class="typedecl"><a name="type-iterator_action">iterator_action()</a></h3>
<p><tt>iterator_action() = first | last | next | prev | binary() | {seek, binary()} | {seek_for_prev, binary()}</tt></p>
<h3 class="typedecl"><a name="type-itr_handle">itr_handle()</a></h3>
<p><tt>itr_handle() = <a href="/home/uwiger/ae/mnesia_rocksdb/_build/default/lib/rocksdb/doc/rocksdb.html#type-itr_handle">rocksdb:itr_handle()</a></tt></p>
<h3 class="typedecl"><a name="type-key">key()</a></h3>
<p><tt>key() = any()</tt></p>
<h3 class="typedecl"><a name="type-key_encoding">key_encoding()</a></h3>
<p><tt>key_encoding() = raw | sext | term</tt></p>
<h3 class="typedecl"><a name="type-mnesia_activity_type">mnesia_activity_type()</a></h3>
<p><tt>mnesia_activity_type() = transaction | sync_transaction | async_dirty | sync_dirty</tt></p>
<h3 class="typedecl"><a name="type-mrdb_activity_type">mrdb_activity_type()</a></h3>
<p><tt>mrdb_activity_type() = tx | {tx, <a href="#type-tx_options">tx_options()</a>} | batch</tt></p>
<h3 class="typedecl"><a name="type-mrdb_iterator">mrdb_iterator()</a></h3>
<p><tt>mrdb_iterator() = #mrdb_iter{i = <a href="#type-itr_handle">itr_handle()</a>, ref = <a href="#type-db_ref">db_ref()</a>}</tt></p>
<h3 class="typedecl"><a name="type-obj">obj()</a></h3>
<p><tt>obj() = tuple()</tt></p>
<h3 class="typedecl"><a name="type-outer">outer()</a></h3>
<p><tt>outer() = non_neg_integer()</tt></p>
<h3 class="typedecl"><a name="type-pos">pos()</a></h3>
<p><tt>pos() = non_neg_integer()</tt></p>
<h3 class="typedecl"><a name="type-properties">properties()</a></h3>
<p><tt>properties() = #{record_name := atom(), attributes := [atom()], index := [{<a href="#type-pos">pos()</a>, bag | ordered}]}</tt></p>
<h3 class="typedecl"><a name="type-read_options">read_options()</a></h3>
<p><tt>read_options() = [{verify_checksums, boolean()} | {fill_cache, boolean()} | {iterate_upper_bound, binary()} | {iterate_lower_bound, binary()} | {tailing, boolean()} | {total_order_seek, boolean()} | {prefix_same_as_start, boolean()} | {snapshot, <a href="#type-snapshot_handle">snapshot_handle()</a>}]</tt></p>
<h3 class="typedecl"><a name="type-ref_or_tab">ref_or_tab()</a></h3>
<p><tt>ref_or_tab() = <a href="#type-table">table()</a> | <a href="#type-db_ref">db_ref()</a></tt></p>
<h3 class="typedecl"><a name="type-retainer">retainer()</a></h3>
<p><tt>retainer() = {<a href="#type-tab_name">tab_name()</a>, retainer, any()}</tt></p>
<h3 class="typedecl"><a name="type-retries">retries()</a></h3>
<p><tt>retries() = <a href="#type-outer">outer()</a> | {<a href="#type-inner">inner()</a>, <a href="#type-outer">outer()</a>}</tt></p>
<h3 class="typedecl"><a name="type-semantics">semantics()</a></h3>
<p><tt>semantics() = bag | set</tt></p>
<h3 class="typedecl"><a name="type-snapshot_handle">snapshot_handle()</a></h3>
<p><tt>snapshot_handle() = <a href="/home/uwiger/ae/mnesia_rocksdb/_build/default/lib/rocksdb/doc/rocksdb.html#type-snapshot_handle">rocksdb:snapshot_handle()</a></tt></p>
<h3 class="typedecl"><a name="type-tab_name">tab_name()</a></h3>
<p><tt>tab_name() = atom()</tt></p>
<h3 class="typedecl"><a name="type-table">table()</a></h3>
<p><tt>table() = atom() | <a href="#type-admin_tab">admin_tab()</a> | <a href="#type-index">index()</a> | <a href="#type-retainer">retainer()</a></tt></p>
<h3 class="typedecl"><a name="type-tx_activity">tx_activity()</a></h3>
<p><tt>tx_activity() = #{type := tx, handle := <a href="#type-tx_handle">tx_handle()</a>, attempt := undefined | <a href="#type-retries">retries()</a>}</tt></p>
<h3 class="typedecl"><a name="type-tx_handle">tx_handle()</a></h3>
<p><tt>tx_handle() = <a href="/home/uwiger/ae/mnesia_rocksdb/_build/default/lib/rocksdb/doc/rocksdb.html#type-transaction_handle">rocksdb:transaction_handle()</a></tt></p>
<h3 class="typedecl"><a name="type-tx_options">tx_options()</a></h3>
<p><tt>tx_options() = #{retries =&gt; <a href="#type-retries">retries()</a>, no_snapshot =&gt; boolean()}</tt></p>
<h3 class="typedecl"><a name="type-val_encoding">val_encoding()</a></h3>
<p><tt>val_encoding() = {value | object, term | raw} | raw</tt></p>
<h3 class="typedecl"><a name="type-write_options">write_options()</a></h3>
<p><tt>write_options() = [{sync, boolean()} | {disable_wal, boolean()} | {ignore_missing_column_families, boolean()} | {no_slowdown, boolean()} | {low_pri, boolean()}]</tt></p>
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#abort-1">abort/1</a></td><td>Aborts an ongoing <a docgen-rel="seemfa" docgen-href="#activity/2" href="#activity-2"><code>activity/2</code></a></td></tr>
<tr><td valign="top"><a href="#activity-3">activity/3</a></td><td>Run an activity (similar to <a docgen-rel="seemfa" docgen-href="mnesia:mnesia#activity/2" href="/home/uwiger/ae/mnesia/doc/mnesia.html#activity-2"><code>//mnesia/mnesia:activity/2</code></a>).</td></tr>
<tr><td valign="top"><a href="#alias_of-1">alias_of/1</a></td><td>Returns the alias of a given table or table reference.</td></tr>
<tr><td valign="top"><a href="#as_batch-2">as_batch/2</a></td><td>Creates a <code>rocksdb</code> batch context and executes the fun <code>F</code> in it.</td></tr>
<tr><td valign="top"><a href="#as_batch-3">as_batch/3</a></td><td>as <a docgen-rel="seemfa" docgen-href="#as_batch/2" href="#as_batch-2"><code>as_batch/2</code></a>, but with the ability to pass <code>Opts</code> to <code>rocksdb:write_batch/2</code></td></tr>
<tr><td valign="top"><a href="#batch_write-2">batch_write/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#batch_write-3">batch_write/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#clear_table-1">clear_table/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#current_context-0">current_context/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#delete-2">delete/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#delete-3">delete/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#delete_object-2">delete_object/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#delete_object-3">delete_object/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#ensure_ref-1">ensure_ref/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#ensure_ref-2">ensure_ref/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#first-1">first/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#first-2">first/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#fold-3">fold/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#fold-4">fold/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#fold-5">fold/5</a></td><td></td></tr>
<tr><td valign="top"><a href="#get_batch-1">get_batch/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#get_ref-1">get_ref/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#index_read-3">index_read/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#insert-2">insert/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#insert-3">insert/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#iterator-1">iterator/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#iterator-2">iterator/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#iterator_close-1">iterator_close/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#iterator_move-2">iterator_move/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#last-1">last/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#last-2">last/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#match_delete-2">match_delete/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#new_tx-1">new_tx/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#new_tx-2">new_tx/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#next-2">next/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#next-3">next/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#prev-2">prev/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#prev-3">prev/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#rdb_delete-2">rdb_delete/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#rdb_delete-3">rdb_delete/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#rdb_fold-4">rdb_fold/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#rdb_fold-5">rdb_fold/5</a></td><td></td></tr>
<tr><td valign="top"><a href="#rdb_get-2">rdb_get/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#rdb_get-3">rdb_get/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#rdb_iterator-1">rdb_iterator/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#rdb_iterator-2">rdb_iterator/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#rdb_iterator_move-2">rdb_iterator_move/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#rdb_put-3">rdb_put/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#rdb_put-4">rdb_put/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#read-2">read/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#read-3">read/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#read_info-1">read_info/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#read_info-2">read_info/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#release_snapshot-1">release_snapshot/1</a></td><td>release a snapshot created by <a docgen-rel="seemfa" docgen-href="#snapshot/1" href="#snapshot-1"><code>snapshot/1</code></a>.</td></tr>
<tr><td valign="top"><a href="#select-1">select/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#select-2">select/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#select-3">select/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#snapshot-1">snapshot/1</a></td><td>Create a snapshot of the database instance associated with the
table reference, table name or alias.</td></tr>
<tr><td valign="top"><a href="#tx_commit-1">tx_commit/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#tx_ref-2">tx_ref/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#update_counter-3">update_counter/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#update_counter-4">update_counter/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#with_iterator-2">with_iterator/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#with_iterator-3">with_iterator/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#with_rdb_iterator-2">with_rdb_iterator/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#with_rdb_iterator-3">with_rdb_iterator/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#write_info-3">write_info/3</a></td><td></td></tr>
</table>
<h2><a name="functions">Function Details</a></h2>
<h3 class="function"><a name="abort-1">abort/1</a></h3>
<div class="spec">
<p><tt>abort(Reason) -&gt; any()</tt></p>
<p> </p>
</div><p>Aborts an ongoing <a docgen-rel="seemfa" docgen-href="#activity/2" href="#activity-2"><code>activity/2</code></a></p>
<h3 class="function"><a name="activity-3">activity/3</a></h3>
<div class="spec">
<p><tt>activity(Type::<a href="#type-activity_type">activity_type()</a>, Alias::<a href="#type-alias">alias()</a>, F::fun(() -&gt; Res)) -&gt; Res</tt><br></p>
<p> </p>
</div><p><p>Run an activity (similar to <a docgen-rel="seemfa" docgen-href="mnesia:mnesia#activity/2" href="/home/uwiger/ae/mnesia/doc/mnesia.html#activity-2"><code>//mnesia/mnesia:activity/2</code></a>).</p>
Supported activity types are:
<ul>
<li> <code>transaction</code> - An optimistic <code>rocksdb</code> transaction</li>
<li> <code>{tx, TxOpts}</code> - A <code>rocksdb</code> transaction with sligth modifications</li>
<li> <code>batch</code> - A <code>rocksdb</code> batch operation</li>
</ul>
<p>By default, transactions are combined with a snapshot with 1 retry.
The snapshot ensures that writes from concurrent transactions don't leak into the transaction context.
A transaction will be retried if it detects that the commit set conflicts with recent changes.
A mutex is used to ensure that only one of potentially conflicting <code>mrdb</code> transactions is run at a time.
The re-run transaction may still fail, if new transactions, or non-transaction writes interfere with
the commit set. It will then be re-run again, until the retry count is exhausted.</p>
<p>For finer-grained retries, it's possible to set <code>retries =&gt; {Inner, Outer}</code>. Setting the retries to a
single number, <code>Retries</code>, is analogous to <code>{0, Retries}`. Each outer retry requests a</code>mutex lock' by
waiting in a FIFO queue. Once it receives the lock, it will try the activity once + as many retries
as specified by <code>Inner</code>. If these fail, the activity again goes to the FIFO queue (ending up last
in line) if there are outer retries remaining. When all retries are exhaused, the activity aborts
with <code>retry_limit</code>. Note that transactions, being optimistic, do not request a lock on the first
attempt, but only on outer retries (the first retry is always an outer retry).</p>
<p>Valid <code>TxOpts</code> are <code>#{no_snapshot =&gt; boolean(), retries =&gt; retries()}</code>.</p>
To simplify code adaptation, <code>tx | transaction | sync_transaction</code> are synonyms, and
<code>batch | async_dirty | sync_dirty</code> are synonyms.</p>
<h3 class="function"><a name="alias_of-1">alias_of/1</a></h3>
<div class="spec">
<p><tt>alias_of(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>) -&gt; <a href="#type-alias">alias()</a></tt><br></p>
<p> </p>
</div><p>Returns the alias of a given table or table reference.</p>
<h3 class="function"><a name="as_batch-2">as_batch/2</a></h3>
<div class="spec">
<p><tt>as_batch(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>, F::fun((<a href="#type-db_ref">db_ref()</a>) -&gt; Res)) -&gt; Res</tt><br></p>
<p> </p>
</div><p><p>Creates a <code>rocksdb</code> batch context and executes the fun <code>F</code> in it.</p>
%% Rocksdb batches aren't tied to a specific DbRef until written.
This can cause surprising problems if we're juggling multiple
rocksdb instances (as we do if we have standalone tables).
At the time of writing, all objects end up in the DbRef the batch
is written to, albeit not necessarily in the intended column family.
This will probably change, but no failure mode is really acceptable.
The code below ensures that separate batches are created for each
DbRef, under a unique reference stored in the pdict. When writing,
all batches are written separately to the corresponding DbRef,
and when releasing, all batches are released. This will not ensure
atomicity, but there is no way in rocksdb to achieve atomicity
across db instances. At least, data should end up where you expect.
</p>
<h3 class="function"><a name="as_batch-3">as_batch/3</a></h3>
<div class="spec">
<p><tt>as_batch(Tab, F, Opts) -&gt; any()</tt></p>
<p> </p>
</div><p>as <a docgen-rel="seemfa" docgen-href="#as_batch/2" href="#as_batch-2"><code>as_batch/2</code></a>, but with the ability to pass <code>Opts</code> to <code>rocksdb:write_batch/2</code></p>
<h3 class="function"><a name="batch_write-2">batch_write/2</a></h3>
<div class="spec">
<p><tt>batch_write(Tab, L) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="batch_write-3">batch_write/3</a></h3>
<div class="spec">
<p><tt>batch_write(Tab, L, Opts) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="clear_table-1">clear_table/1</a></h3>
<div class="spec">
<p><tt>clear_table(Tab) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="current_context-0">current_context/0</a></h3>
<div class="spec">
<p><tt>current_context() -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="delete-2">delete/2</a></h3>
<div class="spec">
<p><tt>delete(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>, Key::<a href="#type-key">key()</a>) -&gt; ok</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="delete-3">delete/3</a></h3>
<div class="spec">
<p><tt>delete(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>, Key::<a href="#type-key">key()</a>, Opts::<a href="#type-write_options">write_options()</a>) -&gt; ok</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="delete_object-2">delete_object/2</a></h3>
<div class="spec">
<p><tt>delete_object(Tab, Obj) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="delete_object-3">delete_object/3</a></h3>
<div class="spec">
<p><tt>delete_object(Tab, Obj, Opts) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="ensure_ref-1">ensure_ref/1</a></h3>
<div class="spec">
<p><tt>ensure_ref(R::<a href="#type-ref_or_tab">ref_or_tab()</a>) -&gt; <a href="#type-db_ref">db_ref()</a></tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="ensure_ref-2">ensure_ref/2</a></h3>
<div class="spec">
<p><tt>ensure_ref(Ref, R) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="first-1">first/1</a></h3>
<div class="spec">
<p><tt>first(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>) -&gt; <a href="#type-key">key()</a> | '$end_of_table'</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="first-2">first/2</a></h3>
<div class="spec">
<p><tt>first(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>, Opts::<a href="#type-read_options">read_options()</a>) -&gt; <a href="#type-key">key()</a> | '$end_of_table'</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="fold-3">fold/3</a></h3>
<div class="spec">
<p><tt>fold(Tab, Fun, Acc) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="fold-4">fold/4</a></h3>
<div class="spec">
<p><tt>fold(Tab, Fun, Acc, MatchSpec) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="fold-5">fold/5</a></h3>
<div class="spec">
<p><tt>fold(Tab, Fun, Acc, MatchSpec, Limit) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="get_batch-1">get_batch/1</a></h3>
<div class="spec">
<p><tt>get_batch(X1) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="get_ref-1">get_ref/1</a></h3>
<div class="spec">
<p><tt>get_ref(Tab::<a href="#type-table">table()</a>) -&gt; <a href="#type-db_ref">db_ref()</a></tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="index_read-3">index_read/3</a></h3>
<div class="spec">
<p><tt>index_read(Tab, Val, Ix) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="insert-2">insert/2</a></h3>
<div class="spec">
<p><tt>insert(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>, Obj::<a href="#type-obj">obj()</a>) -&gt; ok</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="insert-3">insert/3</a></h3>
<div class="spec">
<p><tt>insert(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>, Obj0::<a href="#type-obj">obj()</a>, Opts::<a href="#type-write_options">write_options()</a>) -&gt; ok</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="iterator-1">iterator/1</a></h3>
<div class="spec">
<p><tt>iterator(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>) -&gt; {ok, <a href="#type-mrdb_iterator">mrdb_iterator()</a>} | {error, term()}</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="iterator-2">iterator/2</a></h3>
<div class="spec">
<p><tt>iterator(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>, Opts::<a href="#type-read_options">read_options()</a>) -&gt; {ok, <a href="#type-mrdb_iterator">mrdb_iterator()</a>} | {error, term()}</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="iterator_close-1">iterator_close/1</a></h3>
<div class="spec">
<p><tt>iterator_close(Mrdb_iter::<a href="#type-mrdb_iterator">mrdb_iterator()</a>) -&gt; ok</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="iterator_move-2">iterator_move/2</a></h3>
<div class="spec">
<p><tt>iterator_move(Mrdb_iter::<a href="#type-mrdb_iterator">mrdb_iterator()</a>, Dir::<a href="#type-iterator_action">iterator_action()</a>) -&gt; {ok, tuple()} | {error, any()}</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="last-1">last/1</a></h3>
<div class="spec">
<p><tt>last(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>) -&gt; <a href="#type-key">key()</a> | '$end_of_table'</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="last-2">last/2</a></h3>
<div class="spec">
<p><tt>last(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>, Opts::<a href="#type-read_options">read_options()</a>) -&gt; <a href="#type-key">key()</a> | '$end_of_table'</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="match_delete-2">match_delete/2</a></h3>
<div class="spec">
<p><tt>match_delete(Tab, Pat) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="new_tx-1">new_tx/1</a></h3>
<div class="spec">
<p><tt>new_tx(Tab::<a href="#type-table">table()</a> | <a href="#type-db_ref">db_ref()</a>) -&gt; <a href="#type-db_ref">db_ref()</a></tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="new_tx-2">new_tx/2</a></h3>
<div class="spec">
<p><tt>new_tx(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>, Opts::<a href="#type-write_options">write_options()</a>) -&gt; <a href="#type-db_ref">db_ref()</a></tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="next-2">next/2</a></h3>
<div class="spec">
<p><tt>next(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>, K::<a href="#type-key">key()</a>) -&gt; <a href="#type-key">key()</a> | '$end_of_table'</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="next-3">next/3</a></h3>
<div class="spec">
<p><tt>next(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>, K::<a href="#type-key">key()</a>, Opts::<a href="#type-read_options">read_options()</a>) -&gt; <a href="#type-key">key()</a> | '$end_of_table'</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="prev-2">prev/2</a></h3>
<div class="spec">
<p><tt>prev(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>, K::<a href="#type-key">key()</a>) -&gt; <a href="#type-key">key()</a> | '$end_of_table'</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="prev-3">prev/3</a></h3>
<div class="spec">
<p><tt>prev(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>, K::<a href="#type-key">key()</a>, Opts::<a href="#type-read_options">read_options()</a>) -&gt; <a href="#type-key">key()</a> | '$end_of_table'</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="rdb_delete-2">rdb_delete/2</a></h3>
<div class="spec">
<p><tt>rdb_delete(R, K) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="rdb_delete-3">rdb_delete/3</a></h3>
<div class="spec">
<p><tt>rdb_delete(R, K, Opts) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="rdb_fold-4">rdb_fold/4</a></h3>
<div class="spec">
<p><tt>rdb_fold(Tab, Fun, Acc, Prefix) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="rdb_fold-5">rdb_fold/5</a></h3>
<div class="spec">
<p><tt>rdb_fold(Tab, Fun, Acc, Prefix, Limit) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="rdb_get-2">rdb_get/2</a></h3>
<div class="spec">
<p><tt>rdb_get(R, K) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="rdb_get-3">rdb_get/3</a></h3>
<div class="spec">
<p><tt>rdb_get(R, K, Opts) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="rdb_iterator-1">rdb_iterator/1</a></h3>
<div class="spec">
<p><tt>rdb_iterator(R) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="rdb_iterator-2">rdb_iterator/2</a></h3>
<div class="spec">
<p><tt>rdb_iterator(R, Opts) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="rdb_iterator_move-2">rdb_iterator_move/2</a></h3>
<div class="spec">
<p><tt>rdb_iterator_move(I, Dir) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="rdb_put-3">rdb_put/3</a></h3>
<div class="spec">
<p><tt>rdb_put(R, K, V) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="rdb_put-4">rdb_put/4</a></h3>
<div class="spec">
<p><tt>rdb_put(R, K, V, Opts) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="read-2">read/2</a></h3>
<div class="spec">
<p><tt>read(Tab, Key) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="read-3">read/3</a></h3>
<div class="spec">
<p><tt>read(Tab, Key, Opts) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="read_info-1">read_info/1</a></h3>
<div class="spec">
<p><tt>read_info(Tab) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="read_info-2">read_info/2</a></h3>
<div class="spec">
<p><tt>read_info(Tab, K) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="release_snapshot-1">release_snapshot/1</a></h3>
<div class="spec">
<p><tt>release_snapshot(SHandle::<a href="#type-snapshot_handle">snapshot_handle()</a>) -&gt; ok | <a href="#type-error">error()</a></tt><br></p>
<p> </p>
</div><p>release a snapshot created by <a docgen-rel="seemfa" docgen-href="#snapshot/1" href="#snapshot-1"><code>snapshot/1</code></a>.</p>
<h3 class="function"><a name="select-1">select/1</a></h3>
<div class="spec">
<p><tt>select(Cont) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="select-2">select/2</a></h3>
<div class="spec">
<p><tt>select(Tab, Pat) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="select-3">select/3</a></h3>
<div class="spec">
<p><tt>select(Tab, Pat, Limit) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="snapshot-1">snapshot/1</a></h3>
<div class="spec">
<p><tt>snapshot(Name::<a href="#type-alias">alias()</a> | <a href="#type-ref_or_tab">ref_or_tab()</a>) -&gt; {ok, <a href="#type-snapshot_handle">snapshot_handle()</a>} | <a href="#type-error">error()</a></tt><br></p>
<p> </p>
</div><p><p>Create a snapshot of the database instance associated with the
table reference, table name or alias.</p>
Snapshots provide consistent read-only views over the entire state of the key-value store.</p>
<h3 class="function"><a name="tx_commit-1">tx_commit/1</a></h3>
<div class="spec">
<p><tt>tx_commit(TxH::<a href="#type-tx_handle">tx_handle()</a> | <a href="#type-db_ref">db_ref()</a>) -&gt; ok</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="tx_ref-2">tx_ref/2</a></h3>
<div class="spec">
<p><tt>tx_ref(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a> | <a href="#type-db_ref">db_ref()</a> | <a href="#type-db_ref">db_ref()</a>, TxH::<a href="#type-tx_handle">tx_handle()</a>) -&gt; <a href="#type-db_ref">db_ref()</a></tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="update_counter-3">update_counter/3</a></h3>
<div class="spec">
<p><tt>update_counter(Tab, C, Val) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="update_counter-4">update_counter/4</a></h3>
<div class="spec">
<p><tt>update_counter(Tab, C, Val, Opts) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="with_iterator-2">with_iterator/2</a></h3>
<div class="spec">
<p><tt>with_iterator(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>, Fun::fun((<a href="#type-mrdb_iterator">mrdb_iterator()</a>) -&gt; Res)) -&gt; Res</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="with_iterator-3">with_iterator/3</a></h3>
<div class="spec">
<p><tt>with_iterator(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>, Fun::fun((<a href="#type-mrdb_iterator">mrdb_iterator()</a>) -&gt; Res), Opts::<a href="#type-read_options">read_options()</a>) -&gt; Res</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="with_rdb_iterator-2">with_rdb_iterator/2</a></h3>
<div class="spec">
<p><tt>with_rdb_iterator(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>, Fun::fun((<a href="#type-itr_handle">itr_handle()</a>) -&gt; Res)) -&gt; Res</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="with_rdb_iterator-3">with_rdb_iterator/3</a></h3>
<div class="spec">
<p><tt>with_rdb_iterator(Tab::<a href="#type-ref_or_tab">ref_or_tab()</a>, Fun::fun((<a href="#type-itr_handle">itr_handle()</a>) -&gt; Res), Opts::<a href="#type-read_options">read_options()</a>) -&gt; Res</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="write_info-3">write_info/3</a></h3>
<div class="spec">
<p><tt>write_info(Tab, K, V) -&gt; any()</tt></p>
<p> </p>
</div>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated by EDoc</i></p>
</body>
</html>

71
doc/mrdb_index.html Normal file
View File

@ -0,0 +1,71 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Module mrdb_index</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<hr>
<h1>Module mrdb_index</h1>
<ul class="index"><li><a href="#types">Data Types</a></li><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>
<h2><a name="types">Data Types</a></h2>
<h3 class="typedecl"><a name="type-index_value">index_value()</a></h3>
<p><tt>index_value() = any()</tt></p>
<h3 class="typedecl"><a name="type-iterator_action">iterator_action()</a></h3>
<p><tt>iterator_action() = <a href="/home/uwiger/ae/mnesia_rocksdb/doc/mrdb.html#type-iterator_action">mrdb:iterator_action()</a></tt></p>
<h3 class="typedecl"><a name="type-ix_iterator">ix_iterator()</a></h3>
<p><tt>ix_iterator() = #mrdb_ix_iter{i = <a href="/home/uwiger/ae/mnesia_rocksdb/doc/mrdb.html#type-iterator">mrdb:iterator()</a>, type = set | bag, sub = <a href="/home/uwiger/ae/mnesia_rocksdb/doc/mrdb.html#type-ref">mrdb:ref()</a> | pid()}</tt></p>
<h3 class="typedecl"><a name="type-object">object()</a></h3>
<p><tt>object() = tuple()</tt></p>
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#iterator-2">iterator/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#iterator_close-1">iterator_close/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#iterator_move-2">iterator_move/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#with_iterator-3">with_iterator/3</a></td><td></td></tr>
</table>
<h2><a name="functions">Function Details</a></h2>
<h3 class="function"><a name="iterator-2">iterator/2</a></h3>
<div class="spec">
<p><tt>iterator(Tab::<a href="/home/uwiger/ae/mnesia_rocksdb/doc/mrdb.html#type-ref_or_tab">mrdb:ref_or_tab()</a>, IxPos::<a href="/home/uwiger/ae/mnesia_rocksdb/doc/mrdb.html#type-index_position">mrdb:index_position()</a>) -&gt; {ok, <a href="#type-ix_iterator">ix_iterator()</a>} | {error, term()}</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="iterator_close-1">iterator_close/1</a></h3>
<div class="spec">
<p><tt>iterator_close(Mrdb_ix_iter::<a href="#type-ix_iterator">ix_iterator()</a>) -&gt; ok</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="iterator_move-2">iterator_move/2</a></h3>
<div class="spec">
<p><tt>iterator_move(Mrdb_ix_iter::<a href="#type-ix_iterator">ix_iterator()</a>, Dir::<a href="#type-iterator_action">iterator_action()</a>) -&gt; {ok, <a href="#type-index_value">index_value()</a>, <a href="#type-object">object()</a>} | {error, term()}</tt><br></p>
<p> </p>
</div>
<h3 class="function"><a name="with_iterator-3">with_iterator/3</a></h3>
<div class="spec">
<p><tt>with_iterator(Tab::<a href="/home/uwiger/ae/mnesia_rocksdb/doc/mrdb.html#type-ref_or_tab">mrdb:ref_or_tab()</a>, IxPos::<a href="/home/uwiger/ae/mnesia_rocksdb/doc/mrdb.html#type-index_position">mrdb:index_position()</a>, Fun::fun((<a href="#type-ix_iterator">ix_iterator()</a>) -&gt; Res)) -&gt; Res</tt><br></p>
<p> </p>
</div>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated by EDoc</i></p>
</body>
</html>

32
doc/mrdb_mutex.html Normal file
View File

@ -0,0 +1,32 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Module mrdb_mutex</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<hr>
<h1>Module mrdb_mutex</h1>
<ul class="index"><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#do-2">do/2</a></td><td></td></tr>
</table>
<h2><a name="functions">Function Details</a></h2>
<h3 class="function"><a name="do-2">do/2</a></h3>
<div class="spec">
<p><tt>do(Rsrc, F) -&gt; any()</tt></p>
<p> </p>
</div>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated by EDoc</i></p>
</body>
</html>

View File

@ -0,0 +1,88 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Module mrdb_mutex_serializer</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<hr>
<h1>Module mrdb_mutex_serializer</h1>
<ul class="index"><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#code_change-3">code_change/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#done-2">done/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#handle_call-3">handle_call/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#handle_cast-2">handle_cast/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#handle_info-2">handle_info/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#init-1">init/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#start_link-0">start_link/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#terminate-2">terminate/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#wait-1">wait/1</a></td><td></td></tr>
</table>
<h2><a name="functions">Function Details</a></h2>
<h3 class="function"><a name="code_change-3">code_change/3</a></h3>
<div class="spec">
<p><tt>code_change(FromVsn, St, Extra) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="done-2">done/2</a></h3>
<div class="spec">
<p><tt>done(Rsrc, Ref) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="handle_call-3">handle_call/3</a></h3>
<div class="spec">
<p><tt>handle_call(X1, From, St) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="handle_cast-2">handle_cast/2</a></h3>
<div class="spec">
<p><tt>handle_cast(X1, St) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="handle_info-2">handle_info/2</a></h3>
<div class="spec">
<p><tt>handle_info(X1, St) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="init-1">init/1</a></h3>
<div class="spec">
<p><tt>init(X1) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="start_link-0">start_link/0</a></h3>
<div class="spec">
<p><tt>start_link() -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="terminate-2">terminate/2</a></h3>
<div class="spec">
<p><tt>terminate(X1, X2) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="wait-1">wait/1</a></h3>
<div class="spec">
<p><tt>wait(Rsrc) -&gt; any()</tt></p>
<p> </p>
</div>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated by EDoc</i></p>
</body>
</html>

67
doc/mrdb_select.html Normal file
View File

@ -0,0 +1,67 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Module mrdb_select</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<hr>
<h1>Module mrdb_select</h1>
<ul class="index"><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#continuation_info-2">continuation_info/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#fold-5">fold/5</a></td><td></td></tr>
<tr><td valign="top"><a href="#rdb_fold-5">rdb_fold/5</a></td><td></td></tr>
<tr><td valign="top"><a href="#select-1">select/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#select-3">select/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#select-4">select/4</a></td><td></td></tr>
</table>
<h2><a name="functions">Function Details</a></h2>
<h3 class="function"><a name="continuation_info-2">continuation_info/2</a></h3>
<div class="spec">
<p><tt>continuation_info(Item, C) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="fold-5">fold/5</a></h3>
<div class="spec">
<p><tt>fold(Ref, Fun, Acc, MS, Limit) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="rdb_fold-5">rdb_fold/5</a></h3>
<div class="spec">
<p><tt>rdb_fold(Ref, Fun, Acc, Prefix, Limit) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="select-1">select/1</a></h3>
<div class="spec">
<p><tt>select(Cont) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="select-3">select/3</a></h3>
<div class="spec">
<p><tt>select(Ref, MS, Limit) -&gt; any()</tt></p>
<p> </p>
</div>
<h3 class="function"><a name="select-4">select/4</a></h3>
<div class="spec">
<p><tt>select(Ref, MS, AccKeys, Limit) -&gt; any()</tt></p>
<p> </p>
</div>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated by EDoc</i></p>
</body>
</html>

87
doc/mrdb_stats.html Normal file
View File

@ -0,0 +1,87 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Module mrdb_stats</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<hr>
<h1>Module mrdb_stats</h1>
<ul class="index"><li><a href="#description">Description</a></li><li><a href="#types">Data Types</a></li><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>Statistics API for the mnesia_rocksdb plugin.
<h2><a name="description">Description</a></h2><p>Statistics API for the mnesia_rocksdb plugin</p>
Some counters are maintained for each active alias. Currently, the following
counters are supported:
* inner_retries
* outer_retries
<h2><a name="types">Data Types</a></h2>
<h3 class="typedecl"><a name="type-alias">alias()</a></h3>
<p><tt>alias() = <a href="/home/uwiger/ae/mnesia_rocksdb/doc/mnesia_rocksdb.html#type-alias">mnesia_rocksdb:alias()</a></tt></p>
<h3 class="typedecl"><a name="type-counter">counter()</a></h3>
<p><tt>counter() = atom()</tt></p>
<h3 class="typedecl"><a name="type-counters">counters()</a></h3>
<p><tt>counters() = #{<a href="#type-counter">counter()</a> := integer()}</tt></p>
<h3 class="typedecl"><a name="type-db_ref">db_ref()</a></h3>
<p><tt>db_ref() = <a href="/home/uwiger/ae/mnesia_rocksdb/doc/mrdb.html#type-db_ref">mrdb:db_ref()</a></tt></p>
<h3 class="typedecl"><a name="type-increment">increment()</a></h3>
<p><tt>increment() = integer()</tt></p>
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#get-1">get/1</a></td><td>Fetches all known counters for <code>Alias</code>, in the form of a map,
<code>#{Counter =&gt; Value}</code>.</td></tr>
<tr><td valign="top"><a href="#get-2">get/2</a></td><td>Fetches the integer value of the known counter <code>Ctr</code> for <code>Alias</code>.</td></tr>
<tr><td valign="top"><a href="#incr-3">incr/3</a></td><td>Increment <code>Ctr</code> counter for <code>Alias` with increment `N</code>.</td></tr>
<tr><td valign="top"><a href="#new-0">new/0</a></td><td></td></tr>
</table>
<h2><a name="functions">Function Details</a></h2>
<h3 class="function"><a name="get-1">get/1</a></h3>
<div class="spec">
<p><tt>get(Alias::<a href="#type-alias">alias()</a> | <a href="#type-db_ref">db_ref()</a>) -&gt; <a href="#type-counters">counters()</a></tt><br></p>
<p> </p>
</div><p>Fetches all known counters for <code>Alias</code>, in the form of a map,
<code>#{Counter =&gt; Value}</code>.</p>
<h3 class="function"><a name="get-2">get/2</a></h3>
<div class="spec">
<p><tt>get(Alias::<a href="#type-alias">alias()</a> | <a href="#type-db_ref">db_ref()</a>, Ctr::<a href="#type-counter">counter()</a>) -&gt; integer()</tt><br></p>
<p> </p>
</div><p>Fetches the integer value of the known counter <code>Ctr</code> for <code>Alias</code>.</p>
<h3 class="function"><a name="incr-3">incr/3</a></h3>
<div class="spec">
<p><tt>incr(Alias::<a href="#type-alias">alias()</a> | <a href="#type-db_ref">db_ref()</a>, Ctr::<a href="#type-counter">counter()</a>, N::<a href="#type-increment">increment()</a>) -&gt; ok</tt><br></p>
<p> </p>
</div><p><p>Increment <code>Ctr</code> counter for <code>Alias` with increment `N</code>.</p>
Note that the first argument may also be a <code>db_ref()</code> map,
corresponding to <code>mrdb:get_ref({admin, Alias})</code>.</p>
<h3 class="function"><a name="new-0">new/0</a></h3>
<div class="spec">
<p><tt>new() -&gt; any()</tt></p>
<p> </p>
</div>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated by EDoc</i></p>
</body>
</html>

254
doc/overview-summary.html Normal file
View File

@ -0,0 +1,254 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Mnesia Rocksdb - Rocksdb backend plugin for Mnesia
</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<h1>Mnesia Rocksdb - Rocksdb backend plugin for Mnesia
</h1>
<p>Copyright © 2013-21 Klarna AB</p>
<p><b>Authors:</b> Ulf Wiger (<a href="mailto:ulf@wiger.net"><tt>ulf@wiger.net</tt></a>).</p>
<p>The Mnesia DBMS, part of Erlang/OTP, supports 'backend plugins', making
it possible to utilize more capable key-value stores than the <code>dets</code>
module (limited to 2 GB per table). Unfortunately, this support is
undocumented. Below, some informal documentation for the plugin system
is provided.</p>
<h3><a name="Table_of_Contents">Table of Contents</a></h3>
<ol>
<li><a href="#Usage">Usage</a></li>
<ol>
<li><a href="#Prerequisites">Prerequisites</a></li>
<li><a href="#Getting_started">Getting started</a></li>
<li><a href="#Special_features">Special features</a></li>
<li><a href="#Customization">Customization</a></li>
<li><a href="#Handling_of_errors_in_write_operations">Handling of errors in write operations</a></li>
<li><a href="#Caveats">Caveats</a></li>
</ol>
<li><a href="#Mnesia_backend_plugins">Mnesia backend plugins</a></li>
<ol>
<li><a href="#Background">Background</a></li>
<li><a href="#Design">Design</a></li>
</ol>
<li><a href="#Mnesia_index_plugins">Mnesia index plugins</a></li>
<li><a href="#Rocksdb">Rocksdb</a></li>
</ol>
<h3><a name="Usage">Usage</a></h3>
<h4><a name="Prerequisites">Prerequisites</a></h4>
<ul>
<li>rocksdb (included as dependency)</li>
<li>sext (included as dependency)</li>
<li>Erlang/OTP 21.0 or newer (https://github.com/erlang/otp)</li>
</ul>
<h4><a name="Getting_started">Getting started</a></h4>
<p>Call <code>mnesia_rocksdb:register()</code> immediately after
starting mnesia.</p>
<p>Put <code>{rocksdb_copies, [node()]}</code> into the table definitions of
tables you want to be in RocksDB.</p>
<h4><a name="Special_features">Special features</a></h4>
<p>RocksDB tables support efficient selects on <em>prefix keys</em>.</p>
<p>The backend uses the <code>sext</code> module (see
<a href="https://github.com/uwiger/sext" target="_top"><tt>https://github.com/uwiger/sext</tt></a>) for mapping between Erlang terms and the
binary data stored in the tables. This provides two useful properties:</p>
<ul>
<li>The records are stored in the Erlang term order of their keys.</li>
<li>A prefix of a composite key is ordered just before any key for which
it is a prefix. For example, <code>{x, '_'}</code> is a prefix for keys <code>{x, a}</code>,
<code>{x, b}</code> and so on.</li>
</ul>
<p>This means that a prefix key identifies the start of the sequence of
entries whose keys match the prefix. The backend uses this to optimize
selects on prefix keys.</p>
<p>### Customization</p>
<p>RocksDB supports a number of customization options. These can be specified
by providing a <code>{Key, Value}</code> list named <code>rocksdb_opts</code> under <code>user_properties</code>,
for example:</p>
<pre>mnesia:create_table(foo, [{rocksdb_copies, [node()]},
...
{user_properties,
[{rocksdb_opts, [{max_open_files, 1024}]}]
}])</pre>
<p>Consult the <a href="https://github.com/facebook/rocksdb/wiki/Setup-Options-and-Basic-Tuning">RocksDB documentation</a>
for information on configuration parameters. Also see the section below on handling write errors.</p>
The default configuration for tables in <code>mnesia_rocksdb</code> is:
<pre>default_open_opts() -&gt;
[ {create_if_missing, true}
, {cache_size,
list_to_integer(get_env_default("ROCKSDB_CACHE_SIZE", "32212254"))}
, {block_size, 1024}
, {max_open_files, 100}
, {write_buffer_size,
list_to_integer(get_env_default(
"ROCKSDB_WRITE_BUFFER_SIZE", "4194304"))}
, {compression,
list_to_atom(get_env_default("ROCKSDB_COMPRESSION", "true"))}
, {use_bloomfilter, true}
].</pre>
<p>It is also possible, for larger databases, to produce a tuning parameter file.
This is experimental, and mostly copied from <code>mnesia_leveldb</code>. Consult the
source code in <code>mnesia_rocksdb_tuning.erl</code> and <code>mnesia_rocksdb_params.erl</code>.
Contributions are welcome.</p>
<h4><a name="Caveats">Caveats</a></h4>
<p>Avoid placing <code>bag</code> tables in RocksDB. Although they work, each write
requires additional reads, causing substantial runtime overheads. There
are better ways to represent and process bag data (see above about
<em>prefix keys</em>).</p>
<p>The <code>mnesia:table_info(T, size)</code> call always returns zero for RocksDB
tables. RocksDB itself does not track the number of elements in a table, and
although it is possible to make the <code>mnesia_rocksdb</code> backend maintain a size
counter, it incurs a high runtime overhead for writes and deletes since it
forces them to first do a read to check the existence of the key. If you
depend on having an up to date size count at all times, you need to maintain
it yourself. If you only need the size occasionally, you may traverse the
table to count the elements.</p>
<h3><a name="Mnesia_backend_plugins">Mnesia backend plugins</a></h3>
<h4><a name="Background">Background</a></h4>
<p>Mnesia was initially designed to be a RAM-only DBMS, and Erlang's
<code>ets</code> tables were developed for this purpose. In order to support
persistence, e.g. for configuration data, a disk-based version of <code>ets</code>
(called <code>dets</code>) was created. The <code>dets</code> API mimicks the <code>ets</code> API,
and <code>dets</code> is quite convenient and fast for (nowadays) small datasets.
However, using a 32-bit bucket system, it is limited to 2GB of data.
It also doesn't support ordered sets. When used in Mnesia, dets-based
tables are called <code>disc_only_copies</code>.</p>
<p>To circumvent these limitations, another table type, called <code>disc_copies</code>
was added. This is a combination of <code>ets</code> and <code>disk_log</code>, where Mnesia
periodically snapshots the <code>ets</code> data to a log file on disk, and meanwhile
maintains a log of updates, which can be applied at startup. These tables
are quite performant (especially on read access), but all data is kept in
RAM, which can become a serious limitation.</p>
<p>A backend plugin system was proposed by Ulf Wiger in 2016, and further
developed with Klarna's support, to finally become included in OTP 19.
Klarna uses a LevelDb backend, but Aeternity, in 2017, instead chose
to implement a Rocksdb backend plugin.</p>
<h3><a name="Design">Design</a></h3>
<p>As backend plugins were added on a long-since legacy-stable Mnesia,
they had to conform to the existing code structure. For this reason,
the plugin callbacks hook into the already present low-level access
API in the <code>mnesia_lib</code> module. As a consequence, backend plugins have
the same access semantics and granularity as <code>ets</code> and <code>dets</code>. This
isn't much of a disadvantage for key-value stores like LevelDb and RocksDB,
but a more serious issue is that the update part of this API is called
on <em>after</em> the point of no return. That is, Mnesia does not expect
these updates to fail, and has no recourse if they do. As an aside,
this could also happen if a <code>disc_only_copies</code> table exceeds the 2 GB
limit (mnesia will not check it, and <code>dets</code> will not complain, but simply
drop the update.)</p>
<h3><a name="Mnesia_index_plugins">Mnesia index plugins</a></h3>
<p>When adding support for backend plugins, index plugins were also added. Unfortunately, they remain undocumented.</p>
<p>An index plugin can be added in one of two ways:</p>
<ol>
<li>When creating a schema, provide <code>{index_plugins, [{Name, Module, Function}]}</code> options.</li>
<li>Call the function <code>mnesia_schema:add_index_plugin(Name, Module, Function)</code></li>
</ol>
<p><code>Name</code> must be an atom wrapped as a 1-tuple, e.g. <code>{words}</code>.</p>
<p>The plugin callback is called as <code>Module:Function(Table, Pos, Obj)</code>, where <code>Pos=={words}</code> in
our example. It returns a list of index terms.</p>
<p><strong>Example</strong></p>
<p>Given the following index plugin implementation:</p>
<pre>-module(words).
-export([words_f/3]).
words_f(_,_,Obj) when is_tuple(Obj) -&gt;
words_(tuple_to_list(Obj)).
words_(Str) when is_binary(Str) -&gt;
string:lexemes(Str, [$\s, $\n, [$\r,$\n]]);
words_(L) when is_list(L) -&gt;
lists:flatmap(fun words_/1, L);
words_(_) -&gt;
[].</pre>
<p>We can register the plugin and use it in table definitions:</p>
<pre>Eshell V12.1.3 (abort with ^G)
1&gt; mnesia:start().
ok
2&gt; mnesia_schema:add_index_plugin({words}, words, words_f).
{atomic,ok}
3&gt; mnesia:create_table(i, [{index, [{words}]}]).
{atomic,ok}</pre>
<p>Note that in this case, we had neither a backend plugin, nor even a persistent schema.
Index plugins can be used with all table types. The registered indexing function (arity 3) must exist
as an exported function along the node's code path.</p>
<p>To see what happens when we insert an object, we can turn on call trace.</p>
<pre>4&gt; dbg:tracer().
{ok,&lt;0.108.0&gt;}
5&gt; dbg:tp(words, x).
{ok,[{matched,nonode@nohost,3},{saved,x}]}
6&gt; dbg:p(all,[c]).
{ok,[{matched,nonode@nohost,60}]}
7&gt; mnesia:dirty_write({i,&lt;&lt;"one two"&gt;&gt;, [&lt;&lt;"three"&gt;&gt;, &lt;&lt;"four"&gt;&gt;]}).
(&lt;0.84.0&gt;) call words:words_f(i,{words},{i,&lt;&lt;"one two"&gt;&gt;,[&lt;&lt;"three"&gt;&gt;,&lt;&lt;"four"&gt;&gt;]})
(&lt;0.84.0&gt;) returned from words:words_f/3 -&gt; [&lt;&lt;"one"&gt;&gt;,&lt;&lt;"two"&gt;&gt;,&lt;&lt;"three"&gt;&gt;,
&lt;&lt;"four"&gt;&gt;]
(&lt;0.84.0&gt;) call words:words_f(i,{words},{i,&lt;&lt;"one two"&gt;&gt;,[&lt;&lt;"three"&gt;&gt;,&lt;&lt;"four"&gt;&gt;]})
(&lt;0.84.0&gt;) returned from words:words_f/3 -&gt; [&lt;&lt;"one"&gt;&gt;,&lt;&lt;"two"&gt;&gt;,&lt;&lt;"three"&gt;&gt;,
&lt;&lt;"four"&gt;&gt;]
ok
8&gt; dbg:ctp('_'), dbg:stop().
ok
9&gt; mnesia:dirty_index_read(i, &lt;&lt;"one"&gt;&gt;, {words}).
[{i,&lt;&lt;"one two"&gt;&gt;,[&lt;&lt;"three"&gt;&gt;,&lt;&lt;"four"&gt;&gt;]}]</pre>
<p>(The fact that the indexing function is called twice, seems like a performance bug.)</p>
<p>We can observe that the indexing callback is able to operate on the whole object.
It needs to be side-effect free and efficient, since it will be called at least once for each update
(if an old object exists in the table, the indexing function will be called on it too, before it is
replaced by the new object.)</p>
<h3><a name="Rocksdb">Rocksdb</a></h3>
<h3><a name="Usage">Usage</a></h3>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated by EDoc</i></p>
</body>
</html>

View File

@ -407,12 +407,14 @@ try_load_admin_db(Alias, AliasOpts, #st{ backends = Bs
%% We need to store the persistent ref explicitly here,
%% since mnesia knows nothing of our admin table.
AdminTab = {admin, Alias},
Stats = mrdb_stats:new(),
CfI = update_cf_info(AdminTab, #{ status => open
, name => AdminTab
, vsn => ?VSN
, encoding => {sext,{value,term}}
, attr_pos => #{key => 1,
value => 2}
, stats => Stats
, mountpoint => MP
, properties =>
#{ attributes => [key, val]

View File

@ -117,7 +117,9 @@
| index()
| retainer().
-type retries() :: non_neg_integer().
-type inner() :: non_neg_integer().
-type outer() :: non_neg_integer().
-type retries() :: outer() | {inner(), outer()}.
%% activity type 'ets' makes no sense in this context
-type mnesia_activity_type() :: transaction
@ -143,7 +145,7 @@
-type tx_activity() :: #{ type := 'tx'
, handle := tx_handle()
, attempt := non_neg_integer() }.
, attempt := 'undefined' | retries() }.
-type batch_activity() :: #{ type := 'batch'
, handle := batch_handle() }.
-type activity() :: tx_activity() | batch_activity().
@ -256,6 +258,14 @@ release_snapshot(SHandle) ->
%% The re-run transaction may still fail, if new transactions, or non-transaction writes interfere with
%% the commit set. It will then be re-run again, until the retry count is exhausted.
%%
%% For finer-grained retries, it's possible to set `retries => {Inner, Outer}'. Setting the retries to a
%% single number, `Retries', is analogous to `{0, Retries}`. Each outer retry requests a 'mutex lock' by
%% waiting in a FIFO queue. Once it receives the lock, it will try the activity once + as many retries
%% as specified by `Inner'. If these fail, the activity again goes to the FIFO queue (ending up last
%% in line) if there are outer retries remaining. When all retries are exhaused, the activity aborts
%% with `retry_limit'. Note that transactions, being optimistic, do not request a lock on the first
%% attempt, but only on outer retries (the first retry is always an outer retry).
%%
%% Valid `TxOpts' are `#{no_snapshot => boolean(), retries => retries()}'.
%%
%% To simplify code adaptation, `tx | transaction | sync_transaction' are synonyms, and
@ -277,32 +287,66 @@ activity(Type, Alias, F) ->
, alias => Alias
, db_ref => DbRef }
end,
do_activity(F, Alias, Ctxt, false).
do_activity(F, Alias, Ctxt).
do_activity(F, Alias, Ctxt, WithLock) ->
try run_f(F, Ctxt, WithLock, Alias) of
do_activity(F, Alias, Ctxt) ->
try try_f(F, Ctxt)
catch
throw:{?MODULE, busy} ->
retry_activity(F, Alias, Ctxt)
end.
try_f(F, Ctxt) ->
try run_f(F, Ctxt) of
Res ->
try commit_and_pop(Res)
catch
throw:{?MODULE, busy} ->
do_activity(F, Alias, Ctxt, true)
end
commit_and_pop(Res)
catch
Cat:Err ->
abort_and_pop(Cat, Err)
end.
-spec run_f(_, #{'activity':=#{'handle':=_, 'type':='batch' | 'tx', 'attempt'=>1, 'no_snapshot'=>boolean(), 'retries'=>non_neg_integer(), _=>_}, 'alias':=_, 'db_ref':=_, 'no_snapshot'=>boolean(), 'retries'=>non_neg_integer(), _=>_}, boolean(), _) -> any().
run_f(F, Ctxt, false, _) ->
run_f(F, Ctxt) ->
push_ctxt(Ctxt),
F();
run_f(F, Ctxt, true, Alias) ->
push_ctxt(incr_attempt(Ctxt)),
mrdb_mutex:do(Alias, F).
F().
incr_attempt(#{ activity := #{type := tx, attempt := A} = Act, db_ref := DbRef } = C) ->
incr_attempt(0, {_,O}) when O > 0 ->
{outer, {0,1}};
incr_attempt({I,O}, {Ri,Ro}) when is_integer(I), is_integer(O),
is_integer(Ri), is_integer(Ro) ->
if I < Ri -> {inner, {I+1, O}};
O < Ro -> {outer, {0, O+1}};
true ->
error
end;
incr_attempt(_, _) ->
error.
retry_activity(F, Alias, #{activity := #{ type := Type
, attempt := A
, retries := R} = Act} = Ctxt) ->
case incr_attempt(A, R) of
{RetryCtxt, A1} ->
Act1 = Act#{attempt := A1},
Ctxt1 = Ctxt#{activity := Act1},
try retry_activity_(RetryCtxt, F, Alias, restart_ctxt(Ctxt1))
catch
throw:{?MODULE, busy} ->
retry_activity(F, Alias, Ctxt1)
end;
error ->
return_abort(Type, error, retry_limit)
end.
retry_activity_(inner, F, Alias, Ctxt) ->
mrdb_stats:incr(Alias, inner_retries, 1),
try_f(F, Ctxt);
retry_activity_(outer, F, Alias, Ctxt) ->
mrdb_stats:incr(Alias, outer_retries, 1),
mrdb_mutex:do(Alias, fun() -> try_f(F, Ctxt) end).
restart_ctxt(#{ activity := #{type := tx} = Act, db_ref := DbRef } = C) ->
{ok, TxH} = rdb_transaction(DbRef, []),
Act1 = Act#{attempt := A+1, handle := TxH},
Act1 = Act#{handle := TxH},
C1 = C#{ activity := Act1 },
case maps:is_key(snapshot, C) of
true ->
@ -375,10 +419,14 @@ check_tx_opts(Opts) ->
end.
check_retries(#{retries := Retries} = Opts) ->
if is_integer(Retries), Retries >= 0 ->
Opts;
true ->
error({invalid_tx_option, {retries, Retries}})
case Retries of
_ when is_integer(Retries), Retries >= 0 ->
Opts#{retries := {0, Retries}};
{Inner, Outer} when is_integer(Inner), is_integer(Outer),
Inner >= 0, Outer >= 0 ->
Opts;
_ ->
error({invalid_tx_option, {retries, Retries}})
end.
check_nosnap(#{no_snapshot := NoSnap} = Opts) ->
@ -393,7 +441,7 @@ create_tx(Opts, DbRef) ->
{ok, TxH} = rdb_transaction(DbRef, []),
Opts#{activity => maps:merge(Opts, #{ type => tx
, handle => TxH
, attempt => 1})}.
, attempt => 0 })}.
maybe_snapshot(#{no_snapshot := NoSnap} = Opts, DbRef) ->
case NoSnap of
@ -413,8 +461,7 @@ commit_and_pop(Res) ->
Res;
{error, {error, "Resource busy" ++ _ = Busy}} ->
case A of
#{retries := Retries, attempt := Att}
when Att =< Retries ->
#{retries := {I,O}} when I > 0; O > 0 ->
throw({?MODULE, busy});
_ ->
error({error, Busy})
@ -530,7 +577,7 @@ new_tx(#{activity := _}, _) ->
new_tx(Tab, Opts) ->
#{db_ref := DbRef} = R = ensure_ref(Tab),
{ok, TxH} = rdb_transaction(DbRef, write_opts(R, Opts)),
R#{activity => #{type => tx, handle => TxH, attempt => 1}}.
R#{activity => #{type => tx, handle => TxH, attempt => 0}}.
-spec tx_ref(ref_or_tab() | db_ref() | db_ref(), tx_handle()) -> db_ref().
tx_ref(Tab, TxH) ->
@ -540,7 +587,7 @@ tx_ref(Tab, TxH) ->
#{activity := #{type := tx, handle := OtherTxH}} ->
error({tx_handle_conflict, OtherTxH});
R ->
R#{activity => #{type => tx, handle => TxH, attempt => 1}}
R#{activity => #{type => tx, handle => TxH, attempt => 0}}
end.
-spec tx_commit(tx_handle() | db_ref()) -> ok.

74
src/mrdb_stats.erl Normal file
View File

@ -0,0 +1,74 @@
%% -*- mode: erlang; erlang-indent-level: 4; indent-tabs-mode: nil -*-
%% @doc Statistics API for the mnesia_rocksdb plugin
%%
%% Some counters are maintained for each active alias. Currently, the following
%% counters are supported:
%% * inner_retries
%% * outer_retries
%%
-module(mrdb_stats).
-export([new/0]).
-export([incr/3,
get/1,
get/2]).
-type alias() :: mnesia_rocksdb:alias().
-type db_ref() :: mrdb:db_ref().
-type counter() :: atom().
-type increment() :: integer().
-type counters() :: #{ counter() := integer() }.
new() ->
#{ ref => counters:new(map_size(ctr_meta()), [write_concurrency])
, meta => ctr_meta()}.
ctr_meta() ->
#{ inner_retries => 1
, outer_retries => 2 }.
-spec incr(alias() | db_ref(), counter(), increment()) -> ok.
%% @doc Increment `Ctr' counter for `Alias` with increment `N'.
%%
%% Note that the first argument may also be a `db_ref()' map,
%% corresponding to `mrdb:get_ref({admin, Alias})'.
%% @end
incr(Alias, Ctr, N) when is_atom(Alias) ->
#{stats := #{ref := Ref, meta := Meta}} = mrdb:get_ref({admin, Alias}),
incr_(Ref, Meta, Ctr, N);
incr(#{stats := #{ref := Ref, meta := Meta}}, Ctr, N) ->
incr_(Ref, Meta, Ctr, N).
-spec get(alias() | db_ref(), counter()) -> integer().
%% @doc Fetches the integer value of the known counter `Ctr' for `Alias'.
%% @end
get(Alias, Ctr) when is_atom(Alias) ->
#{stats := #{ref := Ref, meta := Meta}} = mrdb:get_ref({admin, Alias}),
get_(Ref, Meta, Ctr);
get(#{stats := #{ref := Ref, meta := Meta}}, Ctr) ->
get_(Ref, Meta, Ctr).
-spec get(alias() | db_ref()) -> counters().
%% @doc Fetches all known counters for `Alias', in the form of a map,
%% `#{Counter => Value}'.
%% @end
get(Alias) when is_atom(Alias) ->
get_(mrdb:get_ref({admin, Alias}));
get(Ref) when is_map(Ref) ->
get_(Ref).
get_(#{stats := #{ref := Ref, meta := Meta}}) ->
lists:foldl(
fun({K, P}, M) ->
M#{K := counters:get(Ref, P)}
end, Meta, maps:to_list(Meta)).
get_(Ref, Meta, Attr) ->
Ix = maps:get(Attr, Meta),
counters:get(Ref, Ix).
incr_(Ref, Meta, Attr, N) ->
Ix = maps:get(Attr, Meta),
counters:add(Ref, Ix, N).

View File

@ -24,6 +24,7 @@
, mrdb_abort/1
, mrdb_two_procs/1
, mrdb_two_procs_tx_restart/1
, mrdb_two_procs_tx_inner_restart/1
, mrdb_two_procs_snap/1
, mrdb_three_procs/1
]).
@ -53,6 +54,7 @@ groups() ->
, mrdb_abort
, mrdb_two_procs
, mrdb_two_procs_tx_restart
, mrdb_two_procs_tx_inner_restart
, mrdb_two_procs_snap
, mrdb_three_procs ]}
].
@ -287,10 +289,17 @@ mrdb_abort(Config) ->
mrdb_two_procs(Config) ->
tr_ct:with_trace(fun mrdb_two_procs_/1, Config,
tr_flags(
{self(), [call, sos, p]},
{self(), [call, sos, p, 'receive']},
tr_patterns(
mrdb, [ {mrdb, insert, 2, x}
, {mrdb, read, 2, x}
, {mrdb, retry_activity, 3, x}
, {mrdb, try_f, 2, x}
, {mrdb, incr_attempt, 2, x}
, {mrdb_mutex, do, 2, x}
, {mrdb_mutex_serializer, do, 2, x}
, {?MODULE, wait_for_other, 2, x}
, {?MODULE, go_ahead_other, 1, x}
, {mrdb, activity, x}], tr_opts()))).
mrdb_two_procs_(Config) ->
@ -314,11 +323,16 @@ mrdb_two_procs_(Config) ->
Pre = mrdb:read(R, a),
go_ahead_other(POther),
await_other_down(POther, MRef, ?LINE),
%% The test proc is still inside the transaction, and POther
%% has terminated/committed. If we now read 'a', we should see
%% the value that POther wrote (no isolation).
[{R, a, 17}] = mrdb:read(R, a),
ok = mrdb:insert(R, {R, a, 18})
end,
go_ahead_other(1, POther),
go_ahead_other(0, POther),
Do0 = get_dict(),
%% Our transaction should fail due to the resource conflict, and because
%% we're not using retries.
try mrdb:activity({tx, #{no_snapshot => true,
retries => 0}}, rdb, F1) of
ok -> error(unexpected)
@ -339,6 +353,7 @@ mrdb_two_procs_tx_restart_(Config) ->
R = ?FUNCTION_NAME,
Parent = self(),
Created = create_tabs([{R, []}], Config),
check_stats(rdb),
mrdb:insert(R, {R, a, 1}),
Pre = mrdb:read(R, a),
F0 = fun() ->
@ -354,7 +369,7 @@ mrdb_two_procs_tx_restart_(Config) ->
OtherWrite = [{R, a, 17}],
Att = get_attempt(),
Expected = case Att of
1 -> Pre;
0 -> Pre;
_ -> OtherWrite
end,
Expected = mrdb:read(R, a),
@ -363,14 +378,88 @@ mrdb_two_procs_tx_restart_(Config) ->
OtherWrite = mrdb:read(R, a),
ok = mrdb:insert(R, {R, a, 18})
end,
go_ahead_other(1, POther),
go_ahead_other(0, POther),
Do0 = get_dict(),
mrdb:activity({tx, #{no_snapshot => true}}, rdb, F1),
dictionary_unchanged(Do0),
check_stats(rdb),
[{R, a, 18}] = mrdb:read(R, a),
delete_tabs(Created),
ok.
mrdb_two_procs_tx_inner_restart(Config) ->
tr_ct:with_trace(fun mrdb_two_procs_tx_inner_restart_/1, Config,
dbg_tr_opts()).
mrdb_two_procs_tx_inner_restart_(Config) ->
R = ?FUNCTION_NAME,
Parent = self(),
Created = create_tabs([{R, []}], Config),
mrdb:insert(R, {R, a, 1}),
mrdb:insert(R, {R, b, 1}),
PreA = mrdb:read(R, a),
PreB = mrdb:read(R, b),
#{inner_retries := Ri0, outer_retries := Ro0} = check_stats(rdb),
F0 = fun() ->
wait_for_other(Parent, ?LINE),
ok = mrdb:insert(R, {R, a, 17}),
wait_for_other(Parent, ?LINE)
end,
F1 = fun() ->
wait_for_other(Parent, ?LINE),
ok = mrdb:insert(R, {R, b, 147}),
wait_for_other(Parent, ?LINE)
end,
Spawn = fun(F) ->
Res = spawn_opt(
fun() ->
ok = mrdb:activity(tx, rdb, F)
end, [monitor]),
Res
end,
{P1, MRef1} = Spawn(F0),
{P2, MRef2} = Spawn(F1),
F2 = fun() ->
PostA = [{R, a, 17}], % once F0 (P1) has committed
PostB = [{R, b, 147}], % once F1 (P2) has committed
ARes = mrdb:read(R, a), % We need to read first to establish a pre-image
BRes = mrdb:read(R, b),
Att = get_attempt(),
ct:log("Att = ~p", [Att]),
case Att of
0 -> % This is the first run (no retry yet)
ARes = PreA,
BRes = PreB,
go_ahead_other(0, P1), % Having our pre-image, now let P1 write
go_ahead_other(0, P1), % Let P1 commit, then await DOWN (normal)
await_other_down(P1, MRef1, ?LINE),
PostA = mrdb:read(R, a); % now, P1's write should leak through here
{0, 1} -> % This is the first (outer) retry
go_ahead_other(0, P2), % Let P2 write
go_ahead_other(0, P2), % Let P2 commit, then await DOWN (normal)
await_other_down(P2, MRef2, ?LINE),
PostA = mrdb:read(R, a), % now we should see writes from both P1
PostB = mrdb:read(R, b); % ... and P2
{1, 1} ->
PostA = mrdb:read(R, a),
PostB = mrdb:read(R, b),
ok
end,
mrdb:insert(R, {R, a, 18}),
mrdb:insert(R, {R, b, 18})
end,
Do0 = get_dict(),
mrdb:activity({tx, #{no_snapshot => true, retries => {1,1}}}, rdb, F2),
check_stats(rdb),
dictionary_unchanged(Do0),
[{R, a, 18}] = mrdb:read(R, a),
[{R, b, 18}] = mrdb:read(R, b),
#{inner_retries := Ri1, outer_retries := Ro1} = check_stats(rdb),
{restarts, {1, 1}} = {restarts, {Ri1 - Ri0, Ro1 - Ro0}},
delete_tabs(Created),
ok.
%
%% For testing purposes, we use side-effects inside the transactions
@ -383,7 +472,7 @@ mrdb_two_procs_tx_restart_(Config) ->
%% attempt, and ignore the sync ops on retries.
%%
-define(IF_FIRST(N, Expr),
if N == 1 ->
if N == 0 ->
Expr;
true ->
ok
@ -413,8 +502,8 @@ mrdb_two_procs_snap(Config) ->
go_ahead_other(Att, POther),
ARes = mrdb:read(R, a),
ARes = case Att of
1 -> Pre;
2 -> [{R, a, 17}]
0 -> Pre;
_ -> [{R, a, 17}]
end,
await_other_down(POther, MRef, ?LINE),
PreB = mrdb:read(R, b),
@ -434,7 +523,7 @@ mrdb_two_procs_snap(Config) ->
%% We make sure that P2 commits before finishing the other two, and P3 and the
%% main thread sync, so as to maximize the contention for the retry lock.
mrdb_three_procs(Config) ->
tr_ct:with_trace(fun mrdb_three_procs_/1, Config, light_tr_opts()).
tr_ct:with_trace(fun mrdb_three_procs_/1, Config, dbg_tr_opts()).
mrdb_three_procs_(Config) ->
R = ?FUNCTION_NAME,
@ -452,7 +541,7 @@ mrdb_three_procs_(Config) ->
spawn_opt(fun() ->
D0 = get_dict(),
do_when_p_allows(
1, Parent, ?LINE,
0, Parent, ?LINE,
fun() ->
ok = mrdb:activity({tx,#{retries => 0}}, rdb, F1)
end),
@ -488,8 +577,8 @@ mrdb_three_procs_(Config) ->
fun() ->
Att = get_attempt(),
ARes = case Att of
1 -> [A0];
2 -> [A1]
0 -> [A0];
_ -> [A1]
end,
%% First, ensure that P2 tx is running
go_ahead_other(Att, P2),
@ -519,6 +608,7 @@ tr_opts() ->
, {?MODULE, await_other_down, 3, x}
, {?MODULE, do_when_p_allows, 4, x}
, {?MODULE, allow_p, 3, x}
, {?MODULE, check_stats, 1, x}
]}.
light_tr_opts() ->
@ -529,6 +619,22 @@ light_tr_opts() ->
, {mrdb, read, 2, x}
, {mrdb, activity, x} ], tr_opts())).
dbg_tr_opts() ->
tr_flags(
{self(), [call, sos, p, 'receive']},
tr_patterns(
mrdb, [ {mrdb, insert, 2, x}
, {mrdb, read, 2, x}
, {mrdb, retry_activity, 3, x}
, {mrdb, try_f, 2, x}
, {mrdb, incr_attempt, 2, x}
, {mrdb, current_context, 0, x}
, {mrdb_mutex, do, 2, x}
, {mrdb_mutex_serializer, do, 2, x}
, {?MODULE, wait_for_other, 2, x}
, {?MODULE, go_ahead_other, 1, x}
, {mrdb, activity, x} ], tr_opts())).
tr_patterns(Mod, Ps, #{patterns := Pats} = Opts) ->
Pats1 = [P || P <- Pats, element(1,P) =/= Mod],
Opts#{patterns => Ps ++ Pats1}.
@ -542,12 +648,13 @@ wait_for_other(Parent, L) ->
wait_for_other(Att, Parent, L) ->
wait_for_other(Att, Parent, 1000, L).
wait_for_other(1, Parent, Timeout, L) ->
wait_for_other(0, Parent, Timeout, L) ->
MRef = monitor(process, Parent),
Parent ! {self(), ready},
receive
{Parent, cont} ->
demonitor(MRef),
Parent ! {self(), cont_ack},
ok;
{'DOWN', MRef, _, _, Reason} ->
ct:log("Parent died, Reason = ~p", [Reason]),
@ -586,7 +693,13 @@ go_ahead_other(Att, POther, Timeout) ->
go_ahead_other_(POther, Timeout) ->
receive
{POther, ready} ->
POther ! {self(), cont}
POther ! {self(), cont},
receive
{POther, cont_ack} ->
ok
after Timeout ->
error(cont_ack_timeout)
end
after Timeout ->
error(go_ahead_timeout)
end.
@ -645,3 +758,8 @@ dictionary_unchanged(Old) ->
, added := [] } = #{ deleted => Old -- New
, added => New -- Old },
ok.
check_stats(Alias) ->
Stats = mrdb_stats:get(Alias),
ct:log("Stats: ~p", [Stats]),
Stats.