updating a newly created table within the same transaction

Ulf Wiger (TN/EAB) ulf.wiger@REDACTED
Mon Jul 17 19:37:02 CEST 2006


I keep running into the nuisance that I can't create a mnesia table and
then write to it in the same transaction. Currently, one has to use
mnesia's restore for that kind of thing - not quite as convenient.


Here's a patch (not quite finished) that seems to do the trick.


Example:

5> mnesia_schema:schema_transaction(fun() ->
mnesia_schema:do_create_table(mnesia_schema:list2cs([{name,test}])),
mnesia:write({test,a,17}) end).
{atomic,ok}
6> ets:tab2list(test).
[{test,a,17}]

...and it also fixes the slight bug that one has been able to read from
a table that's just been deleted, as long as one does it within the same
transaction (mnesia doesn't detect that it's been deleted until it tries
to commit the update.)

7> mnesia_schema:schema_transaction(fun() ->
mnesia_schema:do_delete_table(test), mnesia:activity(transaction,fun()
-> mnesia:write({test,b,18}) end) end).
{aborted,{aborted,{no_exists,test}}}




Patches, relative to mnesia-4.3.1 (OTP R11B) below, and attached, an
access module that is automatically used as a wrapper to any
user-defined access module, if mnesia_tm detects that it's a schema
transaction (first time I've ever found a use for parameterized modules
;) The access module only handles write and delete at this time. The
idea is that it needs to emulate all ops using only the transaction
store (objects in a newly created table cannot be anywhere else until
the transaction is committed.)


BR,
Ulf W

> diff mnesia_schema.erl
$OTP_ROOT/lib/mnesia-4.3.1/src/mnesia_schema.erl 
107d106
< -export([is_schema_transaction/0]).
591,598d589
< is_schema_transaction() ->
<     case process_info(self(), initial_call) of
<         {_, {?MODULE, schema_coordinator,_}} ->
<             true;
<         _ ->
<             false
<     end.
< 
615,618c606
<     Res = case catch mnesia:activity(transaction, Fun) of
<               {'EXIT', BadRes} -> {aborted, BadRes};
<               GoodRes -> {atomic, GoodRes}
<           end,
---
>     Res = mnesia:transaction(Fun),



> diff mnesia_tm.erl $OTP_ROOT/lib/mnesia-4.3.1/src/mnesia_tm.erl
62d61
<              tab_info = [],
772c771
< transaction(OldTidTs, Fun, Args, Retries, Mod0, Type) ->
---
> transaction(OldTidTs, Fun, Args, Retries, Mod, Type) ->
774,779d772
<     Mod = case mnesia_schema:is_schema_transaction() of
<             true ->
<                 mnesia_schema_access:new(Mod0);
<             false ->
<                 Mod0
<         end,
1161,1164c1154
<     case catch begin
<                  Prep1 = do_arrange_schema(Tid, Store, Prep),
<                  do_arrange(Tid, Store, Key, Prep1, N)
<              end of
---
>     case catch do_arrange(Tid, Store, Key, Prep, N) of
1194,1207d1183
< do_arrange_schema(Tid, Store, Prep) ->
<     SchemaKey = op,
<     Items = ?ets_lookup(Store, SchemaKey),
<     TabInfo =
<         lists:foldl(
<           fun({op, delete_table, [{name, Tab}|_]}, I) ->
<                   orddict:store(Tab, [], I);
<              ({op, _, [{name, Tab}|_] = Opts}, I) ->
<                   orddict:store(Tab, Opts, I);
<              (_, I) ->
<                   I
<           end, orddict:new(), Items),
<     prepare_schema_items(Tid, Items, Prep#prep{tab_info = TabInfo}).
<   
1216,1217c1192,1194
<     %%% schema items handled separately
<     do_arrange(Tid, Store, ?ets_next(Store, SchemaKey), Prep, N + 1);
---
>     Items = ?ets_lookup(Store, SchemaKey), %% Store is a bag
>     P2 = prepare_schema_items(Tid, Items, Prep),
>     do_arrange(Tid, Store, ?ets_next(Store, SchemaKey), P2, N + 1);
1258c1235
< prepare_items(Tid, Tab, Key, Items, #prep{tab_info = []} = Prep) ->
---
> prepare_items(Tid, Tab, Key, Items, Prep) ->
1272,1297c1249
<     end;
< 
< prepare_items(Tid, Tab, Key, Items, #prep{tab_info = TI} = Prep) ->
<     case orddict:find(Tab, TI) of
<         {ok, []} ->
<             mnesia:abort({no_exists, Tab});
<         {ok, TabInfo} ->
<             Snmp = proplists:get_value(snmp, TabInfo),
<             Types =  % where_to_commit
<                 where_to_commit(TabInfo, [node() | nodes()]),
<             Recs2 = do_prepare_items(Tid, Tab, Key, Types, 
<                                      Snmp, Items, Prep#prep.records),
<             Prep2 = Prep#prep{records = Recs2, prev_tab = Tab, 
<                               prev_types = Types, prev_snmp = Snmp},
<             check_prep(Prep2, Types);
<         error ->
<             mnesia:abort({no_exists, Tab})
<     end.
< 
< where_to_commit(TI, LiveNodes) ->
<     Cs = fun(Type) ->
<                  [{N, Type} || N <- proplists:get_value(Type, TI),
<                                lists:member(N, LiveNodes)]
<          end,
<     lists:concat([Cs(T) || T <- [ram_copies, disc_copies,
disc_only_copies]]).
< 
---
>     end.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: mnesia_schema_access.erl
Type: application/octet-stream
Size: 4992 bytes
Desc: mnesia_schema_access.erl
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20060717/a7c205fc/attachment.obj>


More information about the erlang-questions mailing list