Mnesia Questions

Ulf Wiger etxuwig@REDACTED
Wed Apr 10 09:27:11 CEST 2002

On Tue, 9 Apr 2002, Martin J. Logan wrote:

>Hello All,
>    I have a few quiestions regarding mnesia policy and capability.

>1. I know that dirty operations do not aquire a lock on a table
>but do they respect one?

No, they don't. Dirty operations honour replication and indexing,
but do not check for the presence of locks. Since they cannot
acquire locks, forcing them to wait for locks could cause
unpleasant effects (like starvation of dirty ops, which are
really intended to be blindingly fast.)

>2. I have a situation where I am reloading some data on the fly. It is not
>   acceptable to lock the table delete the old data and reload
>   the new. Since the data is competely differant it is also not
>   possible to simply update the records. I must have this done
>   quickly. I am wondering if there is some method similar to a
>   pointer switch in C where in I could fill up another table with
>   the data and then simply switch the pointer from the old table to
>   the new - perhaps like a code change. If this is not possible, and
>   I can think of a few reasons why it wouldn't be, does anyone have
>   any suggestions on how I might rapidly exchange my data.
>            Thanks,
>            Martin

If you're storing your data in mnesia, you can do something like
this (just snipping from a call prefix analysis program that I
wrote a long time ago):

%% We start by finding out which is the active tab, then we stay
%% within that tab. This is so that we may switch to a new tab
%% after editing numbers off-line. The old tab must remain for
%% a few millisecs to ensure that no lookups are made to it
%% anymore, then it may be removed.

lookup(Num) ->
    Tab = where_to_read(),
    case get_lengths(Num, Tab) of
        [] ->   [];
        Ls ->
            match_lengths(Ls, (length(Num) bsl 3),
                          lists:reverse(Num), Tab)

where_to_read() ->
    ets:lookup_element(anax, where_to_read, 2).

That is, keep an active table and a "scratch" table. You may edit
the scratch table and build your data there, and then switch, by
updating a "pointer" in a central table. This is fairly common
when building/editing prefix lookup tables. The active and
scratch tables can be configured to have exactly the same record
representation.... Come to think of it, I use practically the
same setup in CCviewer's cross-reference tables: I select a table
based on the "config spec" (ClearCase branch), but here, I
select tables using an algorithm and the venerable
list_to_atom() function.

list_exports(Module, CS) ->
    Tab = table_name(exports, CS),
    case ets:lookup(Tab, to_int_module(Module)) of
        [] ->
            {error, not_found};
        [#ccv_exports{exports = Exports}] ->
            {ok, Exports}

table_name(xrefs, CS) ->    list_to_atom("ccv_xrefs_" ++ CS);
table_name(exports, CS) ->  list_to_atom("ccv_exports_" ++ CS);
table_name(includes, CS) -> list_to_atom("ccv_includes_" ++ CS);
table_name(records, CS) ->  list_to_atom("ccv_records_" ++ CS);
table_name(defines, CS) ->  list_to_atom("ccv_defines_" ++ CS).

= = = =

If you keep your data on the heap, you can make quite exensive
updates quite cheaply as long as you consider how data is stored
and updated on the heap. You should avoid, for example, keeping
your data in a huge record, as the entire record (essentially
a pointer array) is copied each time you change an attribute. In
e.g. gb_trees and dict, you may keep a large access structure
with quite large objects on the heap and very cheaply update
objects without extensive copying.


More information about the erlang-questions mailing list