mnesia:clear_table

Serge Aleynikov serge@REDACTED
Tue Aug 16 13:48:26 CEST 2005


How much nicer would it be if do_clear_table were exported!  :-)

If schema transaction don't support nesting, I am not sure your answer 
clarifies why the following code should work if schema transaction don't 
support nesting:

mnesia:transaction(
   fun() ->
     mnesia:clear_table(test),
   end).

Indeed what led me to the original confusion was that my simple 
prototype with clearing/loading a single table inside a transaction 
worked, but when I extended that into multiple tables, it failed 
miserably for the reason you indicated below.

So, is it expected that only a single schema trancation can be 
encapsulated in another transaction, and is it safe to use the 
transaction above?

Serge

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



More information about the erlang-questions mailing list