mnesia:clear_table

Hakan Mattsson hakan@REDACTED
Tue Aug 16 14:54:37 CEST 2005


A long time ago I added some severe restrictions on
schema transactions in Mnesia in order to get a
truly relieble system. 

Of course it is possible to relax some restrictions
that feels too annoying and do like Uffe suggests.
But if such a solution should be included in Mnesia,
it would have to be more general and also handle
reads within the transaction in a consistent manner.
Uffes solution does only handle writes.

/Håkan

On Tue, 16 Aug 2005, Serge Aleynikov wrote:

SA> How much nicer would it be if do_clear_table were exported!  :-)
SA> 
SA> If schema transaction don't support nesting, I am not sure your answer
SA> clarifies why the following code should work if schema transaction don't
SA> support nesting:
SA> 
SA> mnesia:transaction(
SA>   fun() ->
SA>     mnesia:clear_table(test),
SA>   end).
SA> 
SA> Indeed what led me to the original confusion was that my simple prototype
SA> with clearing/loading a single table inside a transaction worked, but when I
SA> extended that into multiple tables, it failed miserably for the reason you
SA> indicated below.
SA> 
SA> So, is it expected that only a single schema trancation can be encapsulated
SA> in another transaction, and is it safe to use the transaction above?
SA> 
SA> Serge
SA> 
SA> Ulf Wiger (AL/EAB) wrote:
SA> > 
SA> > mnesia:clear_table/1 calls mnesia_schema:clear_table/1,
SA> > which in its turn does the following:
SA> > 
SA> > clear_table(Tab) ->
SA> >   schema_transaction(fun() -> do_clear_table(Tab) end).
SA> > 
SA> > 
SA> > Schema transactions don't support nesting... or you could possibly have a
SA> > schema transaction at the top and nest
SA> > regular transactions in it(*), but as mnesia_schema:do_clear_table/1
SA> > is not exported, you'll have a hard time doing even that.
SA> > 
SA> > 
SA> > (*) There may be serious issues with this - I can't say.
SA> > 
SA> > 
SA> > If you really, really want to do this, and don't want to hack mnesia so as
SA> > to export do_clear_table/1, you can emulate it easily enough. This is how
SA> > it's implemented:
SA> > 
SA> > do_clear_table(schema) ->
SA> >     mnesia:abort({bad_type, schema});
SA> > do_clear_table(Tab) ->
SA> >     TidTs = get_tid_ts_and_lock(schema, write),
SA> >     get_tid_ts_and_lock(Tab, write),
SA> >     insert_schema_ops(TidTs, make_clear_table(Tab)).
SA> > 
SA> > make_clear_table(Tab) ->
SA> >     ensure_writable(schema),
SA> >     Cs = val({Tab, cstruct}),
SA> >     ensure_active(Cs),
SA> >     ensure_writable(Tab),
SA> >     [{op, clear_table, cs2list(Cs)}].
SA> > 
SA> > The functions that are not exported from mnesia_schema are:
SA> > - do_clear_table/1
SA> > - make_clear_table/1
SA> > - ensure_writable/1
SA> > 
SA> > ensure_writable/1 looks like this:
SA> > 
SA> > ensure_writable(Tab) ->
SA> >     case val({Tab, where_to_write}) of
SA> >         [] -> mnesia:abort({read_only, Tab});
SA> >         _ -> ok
SA> >     end.
SA> > 
SA> > 
SA> > So, you can copy the code for ensure_writable/1 and make_clear_table/1.
SA> > Then, your code becomes:
SA> > 
SA> > my_do_clear_table(schema) ->
SA> >    mnesia:abort({bad_type, schema});
SA> > my_do_clear_table(Tab) ->
SA> >    TidTs = mnesia_schema:get_tid_ts_and_lock(schema, write),
SA> >    mnesia_schema:get_tid_ts_and_lock(Tab, write),
SA> >    mnesia_schema:insert_schema_ops(TidTs, my_make_clear_table(Tab)).
SA> > 
SA> > my_make_clear_table(Tab) ->
SA> >     my_ensure_writable(schema),
SA> >     Cs = mnesia_lib:val({Tab, cstruct}),
SA> >     mnesia_schema:ensure_active(Cs),
SA> >     my_ensure_writable(Tab),
SA> >     [{op, clear_table, mnesia_schema:cs2list(Cs)}].
SA> > 
SA> > my_ensure_writable(Tab) ->
SA> >     case mnesia_lib:val({Tab, where_to_write}) of
SA> >         [] -> mnesia:abort({read_only, Tab});
SA> >         _ -> ok
SA> >     end.
SA> > 
SA> > 
SA> > Then you can combine this with other ops inside a top-level
SA> > schema_transaction (important!)
SA> > 
SA> > 
SA> > (n2@REDACTED)6> mnesia:create_table(test, [{ram_copies, [node()]}]).
SA> > {atomic,ok}
SA> > (n2@REDACTED)7> mnesia:create_table(test1, [{ram_copies,[node()]}]).
SA> > {atomic,ok}
SA> > (n2@REDACTED)8> mnesia:dirty_write({test,a,1}).
SA> > ok
SA> > (n2@REDACTED)9> mnesia:dirty_write({test1,a,1}).
SA> > ok
SA> > (n2@REDACTED)11> mnesia_schema:schema_transaction(fun() ->
SA> > cleart:my_do_clear_table(test), cleart:my_do_clear_table(test1),
SA> > mnesia:write({test,b,1}), mnesia:write({test1,b,1}) end).
SA> > {atomic,ok}
SA> > (n2@REDACTED)12> ets:tab2list(test).
SA> > [{test,b,1}]
SA> > (n2@REDACTED)13> mnesia_schema:schema_transaction(fun() ->
SA> > cleart:my_do_clear_table(test), cleart:my_do_clear_table(test1),
SA> > mnesia:transaction(fun() -> mnesia:write({test,b,1}),
SA> > mnesia:write({test1,b,1}) end) end).
SA> > {atomic,{atomic,ok}}
SA> > (n2@REDACTED)14> ets:tab2list(test).
SA> > [{test,b,1}]                                                                    
SA> > 
SA> > 
SA> > mnesia_schema:schema_transaction(
SA> >    fun() ->
SA> >        my_clear_table(Tab),
SA> >        mnesia:transaction(fun() ->                              ...
SA> >                           end)).
SA> > 
SA> > (:
SA> > 
SA> > /Uffe
SA> > 
SA> > 
SA> > > -----Original Message-----
SA> > > From: owner-erlang-questions@REDACTED
SA> > > [mailto:owner-erlang-questions@REDACTED]On Behalf Of Serge Aleynikov
SA> > > Sent: den 16 augusti 2005 03:10
SA> > > To: Claes Wikstrom
SA> > > Cc: Erlang Questions
SA> > > Subject: Re: mnesia:clear_table
SA> > > 
SA> > > 
SA> > > Indeed when I do:
SA> > > 
SA> > > F = fun() ->
SA> > >         mnesia:clear_table(Tab)
SA> > >     end,
SA> > > mnesia:transaction(F).
SA> > > 
SA> > > It works.  That means that nested transactions are supported, however
SA> > > this code returns an error:
SA> > > 
SA> > > p>erl -sname t
SA> > > Erlang (BEAM) emulator version 5.4.8 [source] [hipe] [threads:0]
SA> > > Eshell V5.4.8  (abort with ^G)
SA> > > (t@REDACTED)1> mnesia:create_schema([node()]).
SA> > > ok
SA> > > (t@REDACTED)2> mnesia:start().
SA> > > ok
SA> > > (t@REDACTED)3> mnesia:create_table(test, [{ram_copies, [node()]}]).
SA> > > {atomic,ok}
SA> > > (t@REDACTED)4> mnesia:create_table(test1, [{ram_copies, [node()]}]). 
SA> > > {atomic,ok}
SA> > > (t@REDACTED)5> F = fun() -> mnesia:clear_table(test),
SA> > > mnesia:clear_table(test1) end.
SA> > > #Fun<erl_eval.20.102880425>
SA> > > (t@REDACTED)6> mnesia:transaction(F). 
SA> > > {atomic,{aborted,nested_transaction}}
SA> > > 
SA> > > Am I doing something unconventional, or there is a limit on the depth of
SA> > > nested transactions?
SA> > > 
SA> > > Serge
SA> > > 
SA> > > Claes Wikstrom wrote:
SA> > > 
SA> > > > Serge Aleynikov wrote:
SA> > > > 
SA> > > > 
SA> > > > > Hi,
SA> > > > > 
SA> > > > > I am wondering why the mnesia:clear_table/1 function is 
SA> > > 
SA> > > encapsulated 
SA> > > > > in a transaction of its own.  It prevents this function to 
SA> > > 
SA> > > be included 
SA> > > > > in another transaction.
SA> > > > > 
SA> > > > 
SA> > > > Transactions can be nested arbitrarily deep. Nesting doesn't
SA> > > > come for free, but it works.
SA> > > > 
SA> > > > 
SA> > > > /klacke
SA> 

/Håkan


More information about the erlang-questions mailing list