PageRenderTime 55ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/rdbms/mnesia_patches/src/mnesia.erl

https://github.com/gebi/jungerl
Erlang | 2779 lines | 2285 code | 310 blank | 184 comment | 41 complexity | 74adda6f0a42b3a008e541753cbd3c19 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, AGPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. %% ``The contents of this file are subject to the Erlang Public License,
  2. %% Version 1.1, (the "License"); you may not use this file except in
  3. %% compliance with the License. You should have received a copy of the
  4. %% Erlang Public License along with this software. If not, it can be
  5. %% retrieved via the world wide web at http://www.erlang.org/.
  6. %%
  7. %% Software distributed under the License is distributed on an "AS IS"
  8. %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  9. %% the License for the specific language governing rights and limitations
  10. %% under the License.
  11. %%
  12. %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
  13. %% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
  14. %% AB. All Rights Reserved.''
  15. %%
  16. %% $Id$
  17. %%
  18. %% This module exports the public interface of the Mnesia DBMS engine
  19. -module(mnesia).
  20. %-behaviour(mnesia_access).
  21. -export([
  22. %% Start, stop and debugging
  23. start/0, start/1, stop/0, % Not for public use
  24. set_debug_level/1, lkill/0, kill/0, % Not for public use
  25. ms/0, nc/0, nc/1, ni/0, ni/1, % Not for public use
  26. change_config/2,
  27. %% Activity mgt
  28. abort/1, transaction/1, transaction/2, transaction/3,
  29. sync_transaction/1, sync_transaction/2, sync_transaction/3,
  30. async_dirty/1, async_dirty/2, sync_dirty/1, sync_dirty/2, ets/1, ets/2,
  31. activity/2, activity/3, activity/4, % Not for public use
  32. %% Access within an activity - Lock acquisition
  33. lock/2, lock/4,
  34. read_lock_table/1,
  35. write_lock_table/1,
  36. %% Access within an activity - Updates
  37. write/1, s_write/1, write/3, write/5,
  38. delete/1, s_delete/1, delete/3, delete/5,
  39. delete_object/1, s_delete_object/1, delete_object/3, delete_object/5,
  40. %% Access within an activity - Reads
  41. read/1, wread/1, read/3, read/5,
  42. match_object/1, match_object/3, match_object/5,
  43. select/1,select/2,select/3,select/4,select/5,select/6,
  44. all_keys/1, all_keys/4,
  45. index_match_object/2, index_match_object/4, index_match_object/6,
  46. index_read/3, index_read/6,
  47. first/1, next/2, last/1, prev/2,
  48. %% Iterators within an activity
  49. foldl/3, foldl/4, foldr/3, foldr/4,
  50. %% Dirty access regardless of activities - Updates
  51. dirty_write/1, dirty_write/2,
  52. dirty_delete/1, dirty_delete/2,
  53. dirty_delete_object/1, dirty_delete_object/2,
  54. dirty_update_counter/2, dirty_update_counter/3,
  55. %% Dirty access regardless of activities - Read
  56. dirty_read/1, dirty_read/2,
  57. dirty_select/2,
  58. dirty_match_object/1, dirty_match_object/2, dirty_all_keys/1,
  59. dirty_index_match_object/2, dirty_index_match_object/3,
  60. dirty_index_read/3, dirty_slot/2,
  61. dirty_first/1, dirty_next/2, dirty_last/1, dirty_prev/2,
  62. %% Info
  63. table_info/2, table_info/4, schema/0, schema/1,
  64. error_description/1, info/0, system_info/1,
  65. system_info/0, % Not for public use
  66. %% Database mgt
  67. create_schema/1, delete_schema/1,
  68. backup/1, backup/2, traverse_backup/4, traverse_backup/6,
  69. install_fallback/1, install_fallback/2,
  70. uninstall_fallback/0, uninstall_fallback/1,
  71. activate_checkpoint/1, deactivate_checkpoint/1,
  72. backup_checkpoint/2, backup_checkpoint/3, restore/2,
  73. %% Table mgt
  74. create_table/1, create_table/2, delete_table/1,
  75. add_table_copy/3, del_table_copy/2, move_table_copy/3,
  76. add_table_index/2, del_table_index/2,
  77. transform_table/3, transform_table/4,
  78. change_table_copy_type/3,
  79. read_table_property/2, write_table_property/2, delete_table_property/2,
  80. change_table_frag/2,
  81. clear_table/1,
  82. %% Table load
  83. dump_tables/1, wait_for_tables/2, force_load_table/1,
  84. change_table_access_mode/2, change_table_load_order/2,
  85. set_master_nodes/1, set_master_nodes/2,
  86. onload_fun/2, % UW 2005-12-22
  87. %% Misc admin
  88. dump_log/0, subscribe/1, unsubscribe/1, report_event/1,
  89. %% Snmp
  90. snmp_open_table/2, snmp_close_table/1,
  91. snmp_get_row/2, snmp_get_next_index/2, snmp_get_mnesia_key/2,
  92. %% Textfile access
  93. load_textfile/1, dump_to_textfile/1,
  94. %% QLC functions
  95. table/1, table/2,
  96. %% Mnemosyne exclusive
  97. get_activity_id/0, put_activity_id/1, % Not for public use
  98. %% Mnesia internal functions
  99. dirty_rpc/4, % Not for public use
  100. has_var/1, fun_select/7, fun_select/10, select_cont/3, dirty_sel_init/5,
  101. foldl/6, foldr/6,
  102. %% Module internal callback functions
  103. raw_table_info/2, % Not for public use
  104. remote_dirty_match_object/2, % Not for public use
  105. remote_dirty_select/2 % Not for public use
  106. ]).
  107. -export([begin_activity/4, end_activity/4]).
  108. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  109. -include("mnesia.hrl").
  110. -import(mnesia_lib, [verbose/2]).
  111. -define(DEFAULT_ACCESS, ?MODULE).
  112. %% Select
  113. -define(PATTERN_TO_OBJECT_MATCH_SPEC(Pat), [{Pat,[],['$_']}]).
  114. -define(PATTERN_TO_BINDINGS_MATCH_SPEC(Pat), [{Pat,[],['$$']}]).
  115. begin_activity(_Type, _Factor, _Tid, _Ts) ->
  116. ok.
  117. end_activity(_Result, _Type, _Tid, _Ts) ->
  118. ok.
  119. %% Local function in order to avoid external function call
  120. val(Var) ->
  121. case ?catch_val(Var) of
  122. {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason);
  123. Value -> Value
  124. end.
  125. is_dollar_digits(Var) ->
  126. case atom_to_list(Var) of
  127. [$$ | Digs] ->
  128. is_digits(Digs);
  129. _ ->
  130. false
  131. end.
  132. is_digits([Dig | Tail]) ->
  133. if
  134. $0 =< Dig, Dig =< $9 ->
  135. is_digits(Tail);
  136. true ->
  137. false
  138. end;
  139. is_digits([]) ->
  140. true.
  141. has_var(X) when atom(X) ->
  142. if
  143. X == '_' ->
  144. true;
  145. atom(X) ->
  146. is_dollar_digits(X);
  147. true ->
  148. false
  149. end;
  150. has_var(X) when tuple(X) ->
  151. e_has_var(X, size(X));
  152. has_var([H|T]) ->
  153. case has_var(H) of
  154. false -> has_var(T);
  155. Other -> Other
  156. end;
  157. has_var(_) -> false.
  158. e_has_var(_, 0) -> false;
  159. e_has_var(X, Pos) ->
  160. case has_var(element(Pos, X))of
  161. false -> e_has_var(X, Pos-1);
  162. Other -> Other
  163. end.
  164. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  165. %% Start and stop
  166. start() ->
  167. {Time , Res} = timer:tc(application, start, [?APPLICATION, temporary]),
  168. Secs = Time div 1000000,
  169. case Res of
  170. ok ->
  171. verbose("Mnesia started, ~p seconds~n",[ Secs]),
  172. ok;
  173. {error, {already_started, mnesia}} ->
  174. verbose("Mnesia already started, ~p seconds~n",[ Secs]),
  175. ok;
  176. {error, R} ->
  177. verbose("Mnesia failed to start, ~p seconds: ~p~n",[ Secs, R]),
  178. {error, R}
  179. end.
  180. start(ExtraEnv) when list(ExtraEnv) ->
  181. case mnesia_lib:ensure_loaded(?APPLICATION) of
  182. ok ->
  183. patched_start(ExtraEnv);
  184. Error ->
  185. Error
  186. end;
  187. start(ExtraEnv) ->
  188. {error, {badarg, ExtraEnv}}.
  189. patched_start([{Env, Val} | Tail]) when atom(Env) ->
  190. case mnesia_monitor:patch_env(Env, Val) of
  191. {error, Reason} ->
  192. {error, Reason};
  193. _NewVal ->
  194. patched_start(Tail)
  195. end;
  196. patched_start([Head | _]) ->
  197. {error, {bad_type, Head}};
  198. patched_start([]) ->
  199. start().
  200. stop() ->
  201. case application:stop(?APPLICATION) of
  202. ok -> stopped;
  203. {error, {not_started, ?APPLICATION}} -> stopped;
  204. Other -> Other
  205. end.
  206. change_config(extra_db_nodes, Ns) when list(Ns) ->
  207. mnesia_controller:connect_nodes(Ns);
  208. change_config(BadKey, _BadVal) ->
  209. {error, {badarg, BadKey}}.
  210. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  211. %% Debugging
  212. set_debug_level(Level) ->
  213. mnesia_subscr:set_debug_level(Level).
  214. lkill() ->
  215. mnesia_sup:kill().
  216. kill() ->
  217. rpc:multicall(mnesia_sup, kill, []).
  218. ms() ->
  219. [
  220. mnesia,
  221. mnesia_backup,
  222. mnesia_bup,
  223. mnesia_checkpoint,
  224. mnesia_checkpoint_sup,
  225. mnesia_controller,
  226. mnesia_dumper,
  227. mnesia_loader,
  228. mnesia_frag,
  229. mnesia_frag_hash,
  230. mnesia_frag_old_hash,
  231. mnesia_index,
  232. mnesia_kernel_sup,
  233. mnesia_late_loader,
  234. mnesia_lib,
  235. mnesia_log,
  236. mnesia_registry,
  237. mnesia_schema,
  238. mnesia_snmp_hook,
  239. mnesia_snmp_sup,
  240. mnesia_subscr,
  241. mnesia_sup,
  242. mnesia_text,
  243. mnesia_tm,
  244. mnesia_recover,
  245. mnesia_locker,
  246. %% Keep these last in the list, so
  247. %% mnesia_sup kills these last
  248. mnesia_monitor,
  249. mnesia_event
  250. ].
  251. nc() ->
  252. Mods = ms(),
  253. nc(Mods).
  254. nc(Mods) when list(Mods)->
  255. [Mod || Mod <- Mods, ok /= load(Mod, compile)].
  256. ni() ->
  257. Mods = ms(),
  258. ni(Mods).
  259. ni(Mods) when list(Mods) ->
  260. [Mod || Mod <- Mods, ok /= load(Mod, interpret)].
  261. load(Mod, How) when atom(Mod) ->
  262. case try_load(Mod, How) of
  263. ok ->
  264. ok;
  265. _ ->
  266. mnesia_lib:show( "~n RETRY ~p FROM: ", [Mod]),
  267. Abs = mod2abs(Mod),
  268. load(Abs, How)
  269. end;
  270. load(Abs, How) ->
  271. case try_load(Abs, How) of
  272. ok ->
  273. ok;
  274. {error, Reason} ->
  275. mnesia_lib:show( " *** ERROR *** ~p~n", [Reason]),
  276. {error, Reason}
  277. end.
  278. try_load(Mod, How) ->
  279. mnesia_lib:show( " ~p ", [Mod]),
  280. Flags = [{d, debug}],
  281. case How of
  282. compile ->
  283. case catch c:nc(Mod, Flags) of
  284. {ok, _} -> ok;
  285. Other -> {error, Other}
  286. end;
  287. interpret ->
  288. case catch int:ni(Mod, Flags) of
  289. {module, _} -> ok;
  290. Other -> {error, Other}
  291. end
  292. end.
  293. mod2abs(Mod) ->
  294. ModString = atom_to_list(Mod),
  295. SubDir =
  296. case lists:suffix("test", ModString) of
  297. true -> test;
  298. false -> src
  299. end,
  300. filename:join([code:lib_dir(?APPLICATION), SubDir, ModString]).
  301. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  302. %% Activity mgt
  303. abort(Reason) ->
  304. exit({aborted, Reason}).
  305. transaction(Fun) ->
  306. transaction(get(mnesia_activity_state), Fun, [], infinity, ?DEFAULT_ACCESS, async).
  307. transaction(Fun, Retries) when integer(Retries), Retries >= 0 ->
  308. transaction(get(mnesia_activity_state), Fun, [], Retries, ?DEFAULT_ACCESS, async);
  309. transaction(Fun, Retries) when Retries == infinity ->
  310. transaction(get(mnesia_activity_state), Fun, [], Retries, ?DEFAULT_ACCESS, async);
  311. transaction(Fun, Args) ->
  312. transaction(get(mnesia_activity_state), Fun, Args, infinity, ?DEFAULT_ACCESS, async).
  313. transaction(Fun, Args, Retries) ->
  314. transaction(get(mnesia_activity_state), Fun, Args, Retries, ?DEFAULT_ACCESS, async).
  315. sync_transaction(Fun) ->
  316. transaction(get(mnesia_activity_state), Fun, [], infinity, ?DEFAULT_ACCESS, sync).
  317. sync_transaction(Fun, Retries) when integer(Retries), Retries >= 0 ->
  318. transaction(get(mnesia_activity_state), Fun, [], Retries, ?DEFAULT_ACCESS, sync);
  319. sync_transaction(Fun, Retries) when Retries == infinity ->
  320. transaction(get(mnesia_activity_state), Fun, [], Retries, ?DEFAULT_ACCESS, sync);
  321. sync_transaction(Fun, Args) ->
  322. transaction(get(mnesia_activity_state), Fun, Args, infinity, ?DEFAULT_ACCESS, sync).
  323. sync_transaction(Fun, Args, Retries) ->
  324. transaction(get(mnesia_activity_state), Fun, Args, Retries, ?DEFAULT_ACCESS, sync).
  325. transaction(State, Fun, Args, Retries, Mod, Kind)
  326. when function(Fun), list(Args), Retries == infinity, atom(Mod) ->
  327. mnesia_tm:transaction(State, Fun, Args, Retries, Mod, Kind);
  328. transaction(State, Fun, Args, Retries, Mod, Kind)
  329. when function(Fun), list(Args), integer(Retries), Retries >= 0, atom(Mod) ->
  330. mnesia_tm:transaction(State, Fun, Args, Retries, Mod, Kind);
  331. transaction(_State, Fun, Args, Retries, Mod, _Kind) ->
  332. {aborted, {badarg, Fun, Args, Retries, Mod}}.
  333. non_transaction(State, Fun, Args, ActivityKind, Mod)
  334. when function(Fun), list(Args), atom(Mod) ->
  335. mnesia_tm:non_transaction(State, Fun, Args, ActivityKind, Mod);
  336. non_transaction(_State, Fun, Args, _ActivityKind, _Mod) ->
  337. {aborted, {badarg, Fun, Args}}.
  338. async_dirty(Fun) ->
  339. async_dirty(Fun, []).
  340. async_dirty(Fun, Args) ->
  341. non_transaction(get(mnesia_activity_state), Fun, Args, async_dirty, ?DEFAULT_ACCESS).
  342. sync_dirty(Fun) ->
  343. sync_dirty(Fun, []).
  344. sync_dirty(Fun, Args) ->
  345. non_transaction(get(mnesia_activity_state), Fun, Args, sync_dirty, ?DEFAULT_ACCESS).
  346. ets(Fun) ->
  347. ets(Fun, []).
  348. ets(Fun, Args) ->
  349. non_transaction(get(mnesia_activity_state), Fun, Args, ets, ?DEFAULT_ACCESS).
  350. activity(Kind, Fun) ->
  351. activity(Kind, Fun, []).
  352. activity(Kind, Fun, Args) when list(Args) ->
  353. activity(Kind, Fun, Args, mnesia_monitor:get_env(access_module));
  354. activity(Kind, Fun, Mod) ->
  355. activity(Kind, Fun, [], Mod).
  356. activity(Kind, Fun, Args, Mod) ->
  357. State = get(mnesia_activity_state),
  358. case Kind of
  359. ets -> non_transaction(State, Fun, Args, Kind, Mod);
  360. async_dirty -> non_transaction(State, Fun, Args, Kind, Mod);
  361. sync_dirty -> non_transaction(State, Fun, Args, Kind, Mod);
  362. transaction -> wrap_trans(State, Fun, Args, infinity, Mod, async);
  363. {transaction, Retries} -> wrap_trans(State, Fun, Args, Retries, Mod, async);
  364. sync_transaction -> wrap_trans(State, Fun, Args, infinity, Mod, sync);
  365. {sync_transaction, Retries} -> wrap_trans(State, Fun, Args, Retries, Mod, sync);
  366. _ -> {aborted, {bad_type, Kind}}
  367. end.
  368. wrap_trans(State, Fun, Args, Retries, Mod, Kind) ->
  369. case transaction(State, Fun, Args, Retries, Mod, Kind) of
  370. {atomic, GoodRes} -> GoodRes;
  371. BadRes -> exit(BadRes)
  372. end.
  373. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  374. %% Access within an activity - lock acquisition
  375. %% Grab a lock on an item in the global lock table
  376. %% Item may be any term. Lock may be write or read.
  377. %% write lock is set on all the given nodes
  378. %% read lock is only set on the first node
  379. %% Nodes may either be a list of nodes or one node as an atom
  380. %% Mnesia on all Nodes must be connected to each other, but
  381. %% it is not neccessary that they are up and running.
  382. lock(LockItem, LockKind) ->
  383. case get(mnesia_activity_state) of
  384. {?DEFAULT_ACCESS, Tid, Ts} ->
  385. lock(Tid, Ts, LockItem, LockKind);
  386. {Mod, Tid, Ts} ->
  387. Mod:lock(Tid, Ts, LockItem, LockKind);
  388. _ ->
  389. abort(no_transaction)
  390. end.
  391. lock(Tid, Ts, LockItem, LockKind) ->
  392. case element(1, Tid) of
  393. tid ->
  394. case LockItem of
  395. {record, Tab, Key} ->
  396. lock_record(Tid, Ts, Tab, Key, LockKind);
  397. {table, Tab} ->
  398. lock_table(Tid, Ts, Tab, LockKind);
  399. {global, GlobalKey, Nodes} ->
  400. global_lock(Tid, Ts, GlobalKey, LockKind, Nodes);
  401. _ ->
  402. abort({bad_type, LockItem})
  403. end;
  404. _Protocol ->
  405. []
  406. end.
  407. %% Grab a read lock on a whole table
  408. read_lock_table(Tab) ->
  409. lock({table, Tab}, read),
  410. ok.
  411. %% Grab a write lock on a whole table
  412. write_lock_table(Tab) ->
  413. lock({table, Tab}, write),
  414. ok.
  415. lock_record(Tid, Ts, Tab, Key, LockKind) when atom(Tab) ->
  416. Store = Ts#tidstore.store,
  417. Oid = {Tab, Key},
  418. case LockKind of
  419. read ->
  420. mnesia_locker:rlock(Tid, Store, Oid);
  421. write ->
  422. mnesia_locker:wlock(Tid, Store, Oid);
  423. sticky_write ->
  424. mnesia_locker:sticky_wlock(Tid, Store, Oid);
  425. none ->
  426. [];
  427. _ ->
  428. abort({bad_type, Tab, LockKind})
  429. end;
  430. lock_record(_Tid, _Ts, Tab, _Key, _LockKind) ->
  431. abort({bad_type, Tab}).
  432. lock_table(Tid, Ts, Tab, LockKind) when atom(Tab) ->
  433. Store = Ts#tidstore.store,
  434. case LockKind of
  435. read ->
  436. mnesia_locker:rlock_table(Tid, Store, Tab);
  437. write ->
  438. mnesia_locker:wlock_table(Tid, Store, Tab);
  439. sticky_write ->
  440. mnesia_locker:sticky_wlock_table(Tid, Store, Tab);
  441. none ->
  442. [];
  443. _ ->
  444. abort({bad_type, Tab, LockKind})
  445. end;
  446. lock_table(_Tid, _Ts, Tab, _LockKind) ->
  447. abort({bad_type, Tab}).
  448. global_lock(Tid, Ts, Item, Kind, Nodes) when list(Nodes) ->
  449. case element(1, Tid) of
  450. tid ->
  451. Store = Ts#tidstore.store,
  452. GoodNs = good_global_nodes(Nodes),
  453. if
  454. Kind /= read, Kind /= write ->
  455. abort({bad_type, Kind});
  456. true ->
  457. mnesia_locker:global_lock(Tid, Store, Item, Kind, GoodNs)
  458. end;
  459. _Protocol ->
  460. []
  461. end;
  462. global_lock(_Tid, _Ts, _Item, _Kind, Nodes) ->
  463. abort({bad_type, Nodes}).
  464. good_global_nodes(Nodes) ->
  465. Recover = [node() | val(recover_nodes)],
  466. mnesia_lib:intersect(Nodes, Recover).
  467. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  468. %% Access within an activity - updates
  469. write(Val) when tuple(Val), size(Val) > 2 ->
  470. Tab = element(1, Val),
  471. write(Tab, Val, write);
  472. write(Val) ->
  473. abort({bad_type, Val}).
  474. s_write(Val) when tuple(Val), size(Val) > 2 ->
  475. Tab = element(1, Val),
  476. write(Tab, Val, sticky_write).
  477. write(Tab, Val, LockKind) ->
  478. case get(mnesia_activity_state) of
  479. {?DEFAULT_ACCESS, Tid, Ts} ->
  480. write(Tid, Ts, Tab, Val, LockKind);
  481. {Mod, Tid, Ts} ->
  482. Mod:write(Tid, Ts, Tab, Val, LockKind);
  483. _ ->
  484. abort(no_transaction)
  485. end.
  486. write(Tid, Ts, Tab, Val, LockKind)
  487. when atom(Tab), Tab /= schema, tuple(Val), size(Val) > 2 ->
  488. case element(1, Tid) of
  489. ets ->
  490. ?ets_insert(Tab, Val),
  491. ok;
  492. tid ->
  493. Store = Ts#tidstore.store,
  494. Oid = {Tab, element(2, Val)},
  495. case LockKind of
  496. write ->
  497. mnesia_locker:wlock(Tid, Store, Oid);
  498. sticky_write ->
  499. mnesia_locker:sticky_wlock(Tid, Store, Oid);
  500. _ ->
  501. abort({bad_type, Tab, LockKind})
  502. end,
  503. write_to_store(Tab, Store, Oid, Val);
  504. Protocol ->
  505. do_dirty_write(Protocol, Tab, Val)
  506. end;
  507. write(_Tid, _Ts, Tab, Val, LockKind) ->
  508. abort({bad_type, Tab, Val, LockKind}).
  509. write_to_store(Tab, Store, Oid, Val) ->
  510. case ?catch_val({Tab, record_validation}) of
  511. {RecName, Arity, Type}
  512. when size(Val) == Arity, RecName == element(1, Val) ->
  513. case Type of
  514. bag ->
  515. ?ets_insert(Store, {Oid, Val, write});
  516. _ ->
  517. ?ets_delete(Store, Oid),
  518. ?ets_insert(Store, {Oid, Val, write})
  519. end,
  520. ok;
  521. {'EXIT', _} ->
  522. abort({no_exists, Tab});
  523. _ ->
  524. abort({bad_type, Val})
  525. end.
  526. delete({Tab, Key}) ->
  527. delete(Tab, Key, write);
  528. delete(Oid) ->
  529. abort({bad_type, Oid}).
  530. s_delete({Tab, Key}) ->
  531. delete(Tab, Key, sticky_write);
  532. s_delete(Oid) ->
  533. abort({bad_type, Oid}).
  534. delete(Tab, Key, LockKind) ->
  535. case get(mnesia_activity_state) of
  536. {?DEFAULT_ACCESS, Tid, Ts} ->
  537. delete(Tid, Ts, Tab, Key, LockKind);
  538. {Mod, Tid, Ts} ->
  539. Mod:delete(Tid, Ts, Tab, Key, LockKind);
  540. _ ->
  541. abort(no_transaction)
  542. end.
  543. delete(Tid, Ts, Tab, Key, LockKind)
  544. when atom(Tab), Tab /= schema ->
  545. case element(1, Tid) of
  546. ets ->
  547. ?ets_delete(Tab, Key),
  548. ok;
  549. tid ->
  550. Store = Ts#tidstore.store,
  551. Oid = {Tab, Key},
  552. case LockKind of
  553. write ->
  554. mnesia_locker:wlock(Tid, Store, Oid);
  555. sticky_write ->
  556. mnesia_locker:sticky_wlock(Tid, Store, Oid);
  557. _ ->
  558. abort({bad_type, Tab, LockKind})
  559. end,
  560. ?ets_delete(Store, Oid),
  561. ?ets_insert(Store, {Oid, Oid, delete}),
  562. ok;
  563. Protocol ->
  564. do_dirty_delete(Protocol, Tab, Key)
  565. end;
  566. delete(_Tid, _Ts, Tab, _Key, _LockKind) ->
  567. abort({bad_type, Tab}).
  568. delete_object(Val) when tuple(Val), size(Val) > 2 ->
  569. Tab = element(1, Val),
  570. delete_object(Tab, Val, write);
  571. delete_object(Val) ->
  572. abort({bad_type, Val}).
  573. s_delete_object(Val) when tuple(Val), size(Val) > 2 ->
  574. Tab = element(1, Val),
  575. delete_object(Tab, Val, sticky_write);
  576. s_delete_object(Val) ->
  577. abort({bad_type, Val}).
  578. delete_object(Tab, Val, LockKind) ->
  579. case get(mnesia_activity_state) of
  580. {?DEFAULT_ACCESS, Tid, Ts} ->
  581. delete_object(Tid, Ts, Tab, Val, LockKind);
  582. {Mod, Tid, Ts} ->
  583. Mod:delete_object(Tid, Ts, Tab, Val, LockKind);
  584. _ ->
  585. abort(no_transaction)
  586. end.
  587. delete_object(Tid, Ts, Tab, Val, LockKind)
  588. when atom(Tab), Tab /= schema, tuple(Val), size(Val) > 2 ->
  589. case element(1, Tid) of
  590. ets ->
  591. ?ets_match_delete(Tab, Val),
  592. ok;
  593. tid ->
  594. Store = Ts#tidstore.store,
  595. Oid = {Tab, element(2, Val)},
  596. case LockKind of
  597. write ->
  598. mnesia_locker:wlock(Tid, Store, Oid);
  599. sticky_write ->
  600. mnesia_locker:sticky_wlock(Tid, Store, Oid);
  601. _ ->
  602. abort({bad_type, Tab, LockKind})
  603. end,
  604. case val({Tab, setorbag}) of
  605. bag ->
  606. ?ets_match_delete(Store, {Oid, Val, '_'}),
  607. ?ets_insert(Store, {Oid, Val, delete_object});
  608. _ ->
  609. case ?ets_match_object(Store, {Oid, '_', write}) of
  610. [] ->
  611. ?ets_match_delete(Store, {Oid, Val, '_'}),
  612. ?ets_insert(Store, {Oid, Val, delete_object});
  613. _ ->
  614. ?ets_delete(Store, Oid),
  615. ?ets_insert(Store, {Oid, Oid, delete})
  616. end
  617. end,
  618. ok;
  619. Protocol ->
  620. do_dirty_delete_object(Protocol, Tab, Val)
  621. end;
  622. delete_object(_Tid, _Ts, Tab, _Key, _LockKind) ->
  623. abort({bad_type, Tab}).
  624. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  625. %% Access within an activity - read
  626. read({Tab, Key}) ->
  627. read(Tab, Key, read);
  628. read(Oid) ->
  629. abort({bad_type, Oid}).
  630. wread({Tab, Key}) ->
  631. read(Tab, Key, write);
  632. wread(Oid) ->
  633. abort({bad_type, Oid}).
  634. read(Tab, Key, LockKind) ->
  635. case get(mnesia_activity_state) of
  636. {?DEFAULT_ACCESS, Tid, Ts} ->
  637. read(Tid, Ts, Tab, Key, LockKind);
  638. {Mod, Tid, Ts} ->
  639. Mod:read(Tid, Ts, Tab, Key, LockKind);
  640. _ ->
  641. abort(no_transaction)
  642. end.
  643. read(Tid, Ts, Tab, Key, LockKind)
  644. when atom(Tab), Tab /= schema ->
  645. case element(1, Tid) of
  646. ets ->
  647. ?ets_lookup(Tab, Key);
  648. tid ->
  649. Store = Ts#tidstore.store,
  650. Oid = {Tab, Key},
  651. Objs =
  652. case LockKind of
  653. read ->
  654. mnesia_locker:rlock(Tid, Store, Oid);
  655. write ->
  656. mnesia_locker:rwlock(Tid, Store, Oid);
  657. sticky_write ->
  658. mnesia_locker:sticky_rwlock(Tid, Store, Oid);
  659. _ ->
  660. abort({bad_type, Tab, LockKind})
  661. end,
  662. add_written(?ets_lookup(Store, Oid), Tab, Objs);
  663. _Protocol ->
  664. dirty_read(Tab, Key)
  665. end;
  666. read(_Tid, _Ts, Tab, _Key, _LockKind) ->
  667. abort({bad_type, Tab}).
  668. first(Tab) ->
  669. case get(mnesia_activity_state) of
  670. {?DEFAULT_ACCESS, Tid, Ts} ->
  671. first(Tid, Ts, Tab);
  672. {Mod, Tid, Ts} ->
  673. Mod:first(Tid, Ts, Tab);
  674. _ ->
  675. abort(no_transaction)
  676. end.
  677. first(Tid, Ts, Tab)
  678. when atom(Tab), Tab /= schema ->
  679. case element(1, Tid) of
  680. ets ->
  681. ?ets_first(Tab);
  682. tid ->
  683. lock_table(Tid, Ts, Tab, read),
  684. do_fixtable(Tab,Ts),
  685. Key = dirty_first(Tab),
  686. stored_keys(Tab,Key,'$end_of_table',Ts,next,
  687. val({Tab, setorbag}));
  688. _Protocol ->
  689. dirty_first(Tab)
  690. end;
  691. first(_Tid, _Ts,Tab) ->
  692. abort({bad_type, Tab}).
  693. last(Tab) ->
  694. case get(mnesia_activity_state) of
  695. {?DEFAULT_ACCESS, Tid, Ts} ->
  696. last(Tid, Ts, Tab);
  697. {Mod, Tid, Ts} ->
  698. Mod:last(Tid, Ts, Tab);
  699. _ ->
  700. abort(no_transaction)
  701. end.
  702. last(Tid, Ts, Tab)
  703. when atom(Tab), Tab /= schema ->
  704. case element(1, Tid) of
  705. ets ->
  706. ?ets_last(Tab);
  707. tid ->
  708. lock_table(Tid, Ts, Tab, read),
  709. do_fixtable(Tab,Ts),
  710. Key = dirty_last(Tab),
  711. stored_keys(Tab,Key,'$end_of_table',Ts,prev,
  712. val({Tab, setorbag}));
  713. _Protocol ->
  714. dirty_last(Tab)
  715. end;
  716. last(_Tid, _Ts,Tab) ->
  717. abort({bad_type, Tab}).
  718. next(Tab,Key) ->
  719. case get(mnesia_activity_state) of
  720. {?DEFAULT_ACCESS,Tid,Ts} ->
  721. next(Tid,Ts,Tab,Key);
  722. {Mod,Tid,Ts} ->
  723. Mod:next(Tid,Ts,Tab,Key);
  724. _ ->
  725. abort(no_transaction)
  726. end.
  727. next(Tid,Ts,Tab,Key)
  728. when atom(Tab), Tab /= schema ->
  729. case element(1, Tid) of
  730. ets ->
  731. ?ets_next(Tab,Key);
  732. tid ->
  733. lock_table(Tid, Ts, Tab, read),
  734. do_fixtable(Tab,Ts),
  735. New = (catch dirty_next(Tab,Key)),
  736. stored_keys(Tab,New,Key,Ts,next,
  737. val({Tab, setorbag}));
  738. _Protocol ->
  739. dirty_next(Tab,Key)
  740. end;
  741. next(_Tid, _Ts,Tab,_) ->
  742. abort({bad_type, Tab}).
  743. prev(Tab,Key) ->
  744. case get(mnesia_activity_state) of
  745. {?DEFAULT_ACCESS,Tid,Ts} ->
  746. prev(Tid,Ts,Tab,Key);
  747. {Mod,Tid,Ts} ->
  748. Mod:prev(Tid,Ts,Tab,Key);
  749. _ ->
  750. abort(no_transaction)
  751. end.
  752. prev(Tid,Ts,Tab,Key)
  753. when atom(Tab), Tab /= schema ->
  754. case element(1, Tid) of
  755. ets ->
  756. ?ets_prev(Tab,Key);
  757. tid ->
  758. lock_table(Tid, Ts, Tab, read),
  759. do_fixtable(Tab,Ts),
  760. New = (catch dirty_prev(Tab,Key)),
  761. stored_keys(Tab,New,Key,Ts,prev,
  762. val({Tab, setorbag}));
  763. _Protocol ->
  764. dirty_prev(Tab,Key)
  765. end;
  766. prev(_Tid, _Ts,Tab,_) ->
  767. abort({bad_type, Tab}).
  768. %% Compensate for transaction written and/or deleted records
  769. stored_keys(Tab,'$end_of_table',Prev,Ts,Op,Type) ->
  770. case ts_keys(Ts#tidstore.store,Tab,Op,Type,[]) of
  771. [] -> '$end_of_table';
  772. Keys when Type == ordered_set->
  773. get_ordered_tskey(Prev,Keys,Op);
  774. Keys ->
  775. get_next_tskey(Prev,Keys,Tab)
  776. end;
  777. stored_keys(Tab,{'EXIT',{aborted,R={badarg,[Tab,Key]}}},
  778. Key,#tidstore{store=Store},Op,Type) ->
  779. %% Had to match on error, ouch..
  780. case ?ets_match(Store, {{Tab, Key}, '_', '$1'}) of
  781. [] -> abort(R);
  782. Ops ->
  783. case lists:last(Ops) of
  784. [delete] -> abort(R);
  785. _ ->
  786. case ts_keys(Store,Tab,Op,Type,[]) of
  787. [] -> '$end_of_table';
  788. Keys -> get_next_tskey(Key,Keys,Tab)
  789. end
  790. end
  791. end;
  792. stored_keys(_,{'EXIT',{aborted,R}},_,_,_,_) ->
  793. abort(R);
  794. stored_keys(Tab,Key,Prev,#tidstore{store=Store},Op,ordered_set) ->
  795. case ?ets_match(Store, {{Tab, Key}, '_', '$1'}) of
  796. [] ->
  797. Keys = ts_keys(Store,Tab,Op,ordered_set,[Key]),
  798. get_ordered_tskey(Prev,Keys,Op);
  799. Ops ->
  800. case lists:last(Ops) of
  801. [delete] ->
  802. mnesia:Op(Tab,Key);
  803. _ ->
  804. Keys = ts_keys(Store,Tab,Op,ordered_set,[Key]),
  805. get_ordered_tskey(Prev,Keys,Op)
  806. end
  807. end;
  808. stored_keys(Tab,Key,_,#tidstore{store=Store},Op,_) ->
  809. case ?ets_match(Store, {{Tab, Key}, '_', '$1'}) of
  810. [] -> Key;
  811. Ops ->
  812. case lists:last(Ops) of
  813. [delete] -> mnesia:Op(Tab,Key);
  814. _ -> Key
  815. end
  816. end.
  817. get_ordered_tskey('$end_of_table', [First|_],_) -> First;
  818. get_ordered_tskey(Prev, [First|_], next) when Prev < First -> First;
  819. get_ordered_tskey(Prev, [First|_], prev) when Prev > First -> First;
  820. get_ordered_tskey(Prev, [_|R],Op) -> get_ordered_tskey(Prev,R,Op);
  821. get_ordered_tskey(_, [],_) -> '$end_of_table'.
  822. get_next_tskey(_, [],_) -> '$end_of_table';
  823. get_next_tskey(Key,Keys,Tab) ->
  824. Next =
  825. if Key == '$end_of_table' -> hd(Keys);
  826. true ->
  827. case lists:dropwhile(fun(A) -> A /= Key end, Keys) of
  828. [] -> hd(Keys); %% First stored key
  829. [Key] -> '$end_of_table';
  830. [Key,Next2|_] -> Next2
  831. end
  832. end,
  833. case Next of
  834. '$end_of_table' -> '$end_of_table';
  835. _ -> %% Really slow anybody got another solution??
  836. case dirty_read(Tab, Next) of
  837. [] -> Next;
  838. _ ->
  839. %% Updated value we already returned this key
  840. get_next_tskey(Next,Keys,Tab)
  841. end
  842. end.
  843. ts_keys(Store, Tab, Op, Type, Def) ->
  844. All = ?ets_match(Store, {{Tab,'$1'},'_','$2'}),
  845. Keys = ts_keys_1(All, Def),
  846. if
  847. Type == ordered_set, Op == prev ->
  848. lists:reverse(lists:sort(Keys));
  849. Type == ordered_set ->
  850. lists:sort(Keys);
  851. Op == next ->
  852. lists:reverse(Keys);
  853. true ->
  854. Keys
  855. end.
  856. ts_keys_1([[Key, write]|R], []) ->
  857. ts_keys_1(R, [Key]);
  858. ts_keys_1([[Key, write]|R], Acc=[Key|_]) ->
  859. ts_keys_1(R, Acc);
  860. ts_keys_1([[Key, write]|R], Acc) ->
  861. ts_keys_1(R, [Key|Acc]);
  862. ts_keys_1([[Key, delete]|R], [Key|Acc]) ->
  863. ts_keys_1(R, Acc);
  864. ts_keys_1([_|R], Acc) ->
  865. ts_keys_1(R, Acc);
  866. ts_keys_1([], Acc) ->
  867. Acc.
  868. %%%%%%%%%%%%%%%%%%%%%
  869. %% Iterators
  870. foldl(Fun, Acc, Tab) ->
  871. foldl(Fun, Acc, Tab, read).
  872. foldl(Fun, Acc, Tab, LockKind) when function(Fun) ->
  873. case get(mnesia_activity_state) of
  874. {?DEFAULT_ACCESS, Tid, Ts} ->
  875. foldl(Tid, Ts, Fun, Acc, Tab, LockKind);
  876. {Mod, Tid, Ts} ->
  877. Mod:foldl(Tid, Ts, Fun, Acc, Tab, LockKind);
  878. _ ->
  879. abort(no_transaction)
  880. end.
  881. foldl(ActivityId, Opaque, Fun, Acc, Tab, LockKind) ->
  882. {Type, Prev} = init_iteration(ActivityId, Opaque, Tab, LockKind),
  883. Res = (catch do_foldl(ActivityId, Opaque, Tab, dirty_first(Tab), Fun, Acc, Type, Prev)),
  884. close_iteration(Res, Tab).
  885. do_foldl(A, O, Tab, '$end_of_table', Fun, RAcc, _Type, Stored) ->
  886. lists:foldl(fun(Key, Acc) ->
  887. lists:foldl(Fun, Acc, read(A, O, Tab, Key, read))
  888. end, RAcc, Stored);
  889. do_foldl(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H == Key ->
  890. NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
  891. {_, Tid, Ts} = get(mnesia_activity_state),
  892. do_foldl(Tid, Ts, Tab, dirty_next(Tab, Key), Fun, NewAcc, ordered_set, Stored);
  893. do_foldl(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H < Key ->
  894. NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, H, read)),
  895. {_, Tid, Ts} = get(mnesia_activity_state),
  896. do_foldl(Tid, Ts, Tab, Key, Fun, NewAcc, ordered_set, Stored);
  897. do_foldl(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H > Key ->
  898. NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
  899. {_, Tid, Ts} = get(mnesia_activity_state),
  900. do_foldl(Tid, Ts, Tab, dirty_next(Tab, Key), Fun, NewAcc, ordered_set, [H |Stored]);
  901. do_foldl(A, O, Tab, Key, Fun, Acc, Type, Stored) -> %% Type is set or bag
  902. NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
  903. NewStored = ordsets:del_element(Key, Stored),
  904. {_, Tid, Ts} = get(mnesia_activity_state),
  905. do_foldl(Tid, Ts, Tab, dirty_next(Tab, Key), Fun, NewAcc, Type, NewStored).
  906. foldr(Fun, Acc, Tab) ->
  907. foldr(Fun, Acc, Tab, read).
  908. foldr(Fun, Acc, Tab, LockKind) when function(Fun) ->
  909. case get(mnesia_activity_state) of
  910. {?DEFAULT_ACCESS, Tid, Ts} ->
  911. foldr(Tid, Ts, Fun, Acc, Tab, LockKind);
  912. {Mod, Tid, Ts} ->
  913. Mod:foldr(Tid, Ts, Fun, Acc, Tab, LockKind);
  914. _ ->
  915. abort(no_transaction)
  916. end.
  917. foldr(ActivityId, Opaque, Fun, Acc, Tab, LockKind) ->
  918. {Type, TempPrev} = init_iteration(ActivityId, Opaque, Tab, LockKind),
  919. Prev =
  920. if
  921. Type == ordered_set ->
  922. lists:reverse(TempPrev);
  923. true -> %% Order doesn't matter for set and bag
  924. TempPrev %% Keep the order so we can use ordsets:del_element
  925. end,
  926. Res = (catch do_foldr(ActivityId, Opaque, Tab, dirty_last(Tab), Fun, Acc, Type, Prev)),
  927. close_iteration(Res, Tab).
  928. do_foldr(A, O, Tab, '$end_of_table', Fun, RAcc, _Type, Stored) ->
  929. lists:foldl(fun(Key, Acc) ->
  930. lists:foldl(Fun, Acc, read(A, O, Tab, Key, read))
  931. end, RAcc, Stored);
  932. do_foldr(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H == Key ->
  933. NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
  934. {_, Tid, Ts} = get(mnesia_activity_state),
  935. do_foldr(Tid, Ts, Tab, dirty_prev(Tab, Key), Fun, NewAcc, ordered_set, Stored);
  936. do_foldr(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H > Key ->
  937. NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, H, read)),
  938. {_, Tid, Ts} = get(mnesia_activity_state),
  939. do_foldr(Tid, Ts, Tab, Key, Fun, NewAcc, ordered_set, Stored);
  940. do_foldr(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H < Key ->
  941. NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
  942. {_, Tid, Ts} = get(mnesia_activity_state),
  943. do_foldr(Tid, Ts, Tab, dirty_prev(Tab, Key), Fun, NewAcc, ordered_set, [H |Stored]);
  944. do_foldr(A, O, Tab, Key, Fun, Acc, Type, Stored) -> %% Type is set or bag
  945. NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
  946. NewStored = ordsets:del_element(Key, Stored),
  947. {_, Tid, Ts} = get(mnesia_activity_state),
  948. do_foldr(Tid, Ts, Tab, dirty_prev(Tab, Key), Fun, NewAcc, Type, NewStored).
  949. init_iteration(ActivityId, Opaque, Tab, LockKind) ->
  950. lock(ActivityId, Opaque, {table, Tab}, LockKind),
  951. Type = val({Tab, setorbag}),
  952. Previous = add_previous(ActivityId, Opaque, Type, Tab),
  953. St = val({Tab, storage_type}),
  954. if
  955. St == unknown ->
  956. ignore;
  957. true ->
  958. mnesia_lib:db_fixtable(St, Tab, true)
  959. end,
  960. {Type, Previous}.
  961. close_iteration(Res, Tab) ->
  962. case val({Tab, storage_type}) of
  963. unknown ->
  964. ignore;
  965. St ->
  966. mnesia_lib:db_fixtable(St, Tab, false)
  967. end,
  968. case Res of
  969. {'EXIT', {aborted, What}} ->
  970. abort(What);
  971. {'EXIT', What} ->
  972. abort(What);
  973. _ ->
  974. Res
  975. end.
  976. add_previous(_ActivityId, non_transaction, _Type, _Tab) ->
  977. [];
  978. add_previous(_Tid, Ts, _Type, Tab) ->
  979. Previous = ?ets_match(Ts#tidstore.store, {{Tab, '$1'}, '_', write}),
  980. lists:sort(lists:concat(Previous)).
  981. %% This routine fixes up the return value from read/1 so that
  982. %% it is correct with respect to what this particular transaction
  983. %% has already written, deleted .... etc
  984. add_written([], _Tab, Objs) ->
  985. Objs; % standard normal fast case
  986. add_written(Written, Tab, Objs) ->
  987. case val({Tab, setorbag}) of
  988. bag ->
  989. add_written_to_bag(Written, Objs, []);
  990. _ ->
  991. add_written_to_set(Written)
  992. end.
  993. add_written_to_set(Ws) ->
  994. case lists:last(Ws) of
  995. {_, _, delete} -> [];
  996. {_, Val, write} -> [Val];
  997. {_, _, delete_object} -> []
  998. end.
  999. add_written_to_bag([{_, Val, write} | Tail], Objs, Ack) ->
  1000. add_written_to_bag(Tail, lists:delete(Val, Objs), [Val | Ack]);
  1001. add_written_to_bag([], Objs, Ack) ->
  1002. Objs ++ lists:reverse(Ack); %% Oldest write first as in ets
  1003. add_written_to_bag([{_, _ , delete} | Tail], _Objs, _Ack) ->
  1004. %% This transaction just deleted all objects
  1005. %% with this key
  1006. add_written_to_bag(Tail, [], []);
  1007. add_written_to_bag([{_, Val, delete_object} | Tail], Objs, Ack) ->
  1008. add_written_to_bag(Tail, lists:delete(Val, Objs), lists:delete(Val, Ack)).
  1009. match_object(Pat) when tuple(Pat), size(Pat) > 2 ->
  1010. Tab = element(1, Pat),
  1011. match_object(Tab, Pat, read);
  1012. match_object(Pat) ->
  1013. abort({bad_type, Pat}).
  1014. match_object(Tab, Pat, LockKind) ->
  1015. case get(mnesia_activity_state) of
  1016. {?DEFAULT_ACCESS, Tid, Ts} ->
  1017. match_object(Tid, Ts, Tab, Pat, LockKind);
  1018. {Mod, Tid, Ts} ->
  1019. Mod:match_object(Tid, Ts, Tab, Pat, LockKind);
  1020. _ ->
  1021. abort(no_transaction)
  1022. end.
  1023. match_object(Tid, Ts, Tab, Pat, LockKind)
  1024. when atom(Tab), Tab /= schema, tuple(Pat), size(Pat) > 2 ->
  1025. case element(1, Tid) of
  1026. ets ->
  1027. mnesia_lib:db_match_object(ram_copies, Tab, Pat);
  1028. tid ->
  1029. Key = element(2, Pat),
  1030. case has_var(Key) of
  1031. false -> lock_record(Tid, Ts, Tab, Key, LockKind);
  1032. true -> lock_table(Tid, Ts, Tab, LockKind)
  1033. end,
  1034. Objs = dirty_match_object(Tab, Pat),
  1035. add_written_match(Ts#tidstore.store, Pat, Tab, Objs);
  1036. _Protocol ->
  1037. dirty_match_object(Tab, Pat)
  1038. end;
  1039. match_object(_Tid, _Ts, Tab, Pat, _LockKind) ->
  1040. abort({bad_type, Tab, Pat}).
  1041. add_written_match(S, Pat, Tab, Objs) ->
  1042. Ops = find_ops(S, Tab, Pat),
  1043. add_match(Ops, Objs, val({Tab, setorbag})).
  1044. find_ops(S, Tab, Pat) ->
  1045. GetWritten = [{{{Tab, '_'}, Pat, write}, [], ['$_']},
  1046. {{{Tab, '_'}, '_', delete}, [], ['$_']},
  1047. {{{Tab, '_'}, Pat, delete_object}, [], ['$_']}],
  1048. ets:select(S, GetWritten).
  1049. add_match([], Objs, _Type) ->
  1050. Objs;
  1051. add_match(Written, Objs, ordered_set) ->
  1052. %% Must use keysort which is stable
  1053. add_ordered_match(lists:keysort(1,Written), Objs, []);
  1054. add_match([{Oid, _, delete}|R], Objs, Type) ->
  1055. add_match(R, deloid(Oid, Objs), Type);
  1056. add_match([{_Oid, Val, delete_object}|R], Objs, Type) ->
  1057. add_match(R, lists:delete(Val, Objs), Type);
  1058. add_match([{_Oid, Val, write}|R], Objs, bag) ->
  1059. add_match(R, [Val | lists:delete(Val, Objs)], bag);
  1060. add_match([{Oid, Val, write}|R], Objs, set) ->
  1061. add_match(R, [Val | deloid(Oid,Objs)],set).
  1062. %% For ordered_set only !!
  1063. add_ordered_match(Written = [{{_, Key}, _, _}|_], [Obj|Objs], Acc)
  1064. when Key > element(2, Obj) ->
  1065. add_ordered_match(Written, Objs, [Obj|Acc]);
  1066. add_ordered_match([{{_, Key}, Val, write}|Rest], Objs =[Obj|_], Acc)
  1067. when Key < element(2, Obj) ->
  1068. add_ordered_match(Rest, [Val|Objs],Acc);
  1069. add_ordered_match([{{_, Key}, _, _DelOP}|Rest], Objs =[Obj|_], Acc)
  1070. when Key < element(2, Obj) ->
  1071. add_ordered_match(Rest,Objs,Acc);
  1072. %% Greater than last object
  1073. add_ordered_match([{_, Val, write}|Rest], [], Acc) ->
  1074. add_ordered_match(Rest, [Val], Acc);
  1075. add_ordered_match([_|Rest], [], Acc) ->
  1076. add_ordered_match(Rest, [], Acc);
  1077. %% Keys are equal from here
  1078. add_ordered_match([{_, Val, write}|Rest], [_Obj|Objs], Acc) ->
  1079. add_ordered_match(Rest, [Val|Objs], Acc);
  1080. add_ordered_match([{_, _Val, delete}|Rest], [_Obj|Objs], Acc) ->
  1081. add_ordered_match(Rest, Objs, Acc);
  1082. add_ordered_match([{_, Val, delete_object}|Rest], [Val|Objs], Acc) ->
  1083. add_ordered_match(Rest, Objs, Acc);
  1084. add_ordered_match([{_, _, delete_object}|Rest], Objs, Acc) ->
  1085. add_ordered_match(Rest, Objs, Acc);
  1086. add_ordered_match([], Objs, Acc) ->
  1087. lists:reverse(Acc, Objs).
  1088. %% For select chunk
  1089. add_sel_match(Sorted, Objs, ordered_set) ->
  1090. add_sel_ordered_match(Sorted, Objs, []);
  1091. add_sel_match(Written, Objs, Type) ->
  1092. add_sel_match(Written, Objs, Type, []).
  1093. add_sel_match([], Objs, _Type, Acc) ->
  1094. {Objs,lists:reverse(Acc)};
  1095. add_sel_match([Op={Oid, _, delete}|R], Objs, Type, Acc) ->
  1096. case deloid(Oid, Objs) of
  1097. Objs ->
  1098. add_sel_match(R, Objs, Type, [Op|Acc]);
  1099. NewObjs when Type == set ->
  1100. add_sel_match(R, NewObjs, Type, Acc);
  1101. NewObjs -> %% If bag we may get more in next chunk
  1102. add_sel_match(R, NewObjs, Type, [Op|Acc])
  1103. end;
  1104. add_sel_match([Op = {_Oid, Val, delete_object}|R], Objs, Type, Acc) ->
  1105. case lists:delete(Val, Objs) of
  1106. Objs ->
  1107. add_sel_match(R, Objs, Type, [Op|Acc]);
  1108. NewObjs when Type == set ->
  1109. add_sel_match(R, NewObjs, Type, Acc);
  1110. NewObjs ->
  1111. add_sel_match(R, NewObjs, Type, [Op|Acc])
  1112. end;
  1113. add_sel_match([Op={Oid={_,Key}, Val, write}|R], Objs, bag, Acc) ->
  1114. case lists:keymember(Key, 2, Objs) of
  1115. true ->
  1116. add_sel_match(R,[Val|lists:delete(Val,Objs)],bag,
  1117. [{Oid,Val,delete_object}|Acc]);
  1118. false ->
  1119. add_sel_match(R,Objs,bag,[Op|Acc])
  1120. end;
  1121. add_sel_match([Op={Oid, Val, write}|R], Objs, set, Acc) ->
  1122. case deloid(Oid,Objs) of
  1123. Objs ->
  1124. add_sel_match(R, Objs,set, [Op|Acc]);
  1125. NewObjs ->
  1126. add_sel_match(R, [Val | NewObjs],set, Acc)
  1127. end.
  1128. %% For ordered_set only !!
  1129. add_sel_ordered_match(Written = [{{_, Key}, _, _}|_], [Obj|Objs],Acc)
  1130. when Key > element(2, Obj) ->
  1131. add_sel_ordered_match(Written, Objs, [Obj|Acc]);
  1132. add_sel_ordered_match([{{_, Key}, Val, write}|Rest], Objs =[Obj|_],Acc)
  1133. when Key < element(2, Obj) ->
  1134. add_sel_ordered_match(Rest,[Val|Objs],Acc);
  1135. add_sel_ordered_match([{{_, Key}, _, _DelOP}|Rest], Objs =[Obj|_], Acc)
  1136. when Key < element(2, Obj) ->
  1137. add_sel_ordered_match(Rest,Objs,Acc);
  1138. %% Greater than last object
  1139. add_sel_ordered_match(Ops1, [], Acc) ->
  1140. {lists:reverse(Acc), Ops1};
  1141. %% Keys are equal from here
  1142. add_sel_ordered_match([{_, Val, write}|Rest], [_Obj|Objs], Acc) ->
  1143. add_sel_ordered_match(Rest, [Val|Objs], Acc);
  1144. add_sel_ordered_match([{_, _Val, delete}|Rest], [_Obj|Objs], Acc) ->
  1145. add_sel_ordered_match(Rest, Objs, Acc);
  1146. add_sel_ordered_match([{_, Val, delete_object}|Rest], [Val|Objs], Acc) ->
  1147. add_sel_ordered_match(Rest, Objs, Acc);
  1148. add_sel_ordered_match([{_, _, delete_object}|Rest], Objs, Acc) ->
  1149. add_sel_ordered_match(Rest, Objs, Acc);
  1150. add_sel_ordered_match([], Objs, Acc) ->
  1151. {lists:reverse(Acc, Objs),[]}.
  1152. deloid(_Oid, []) ->
  1153. [];
  1154. deloid({Tab, Key}, [H | T]) when element(2, H) == Key ->
  1155. deloid({Tab, Key}, T);
  1156. deloid(Oid, [H | T]) ->
  1157. [H | deloid(Oid, T)].
  1158. %%%%%%%%%%%%%%%%%%
  1159. % select
  1160. select(Tab, Pat) ->
  1161. select(Tab, Pat, read).
  1162. select(Tab, Pat, LockKind)
  1163. when atom(Tab), Tab /= schema, list(Pat) ->
  1164. case get(mnesia_activity_state) of
  1165. {?DEFAULT_ACCESS, Tid, Ts} ->
  1166. select(Tid, Ts, Tab, Pat, LockKind);
  1167. {Mod, Tid, Ts} ->
  1168. Mod:select(Tid, Ts, Tab, Pat, LockKind);
  1169. _ ->
  1170. abort(no_transaction)
  1171. end;
  1172. select(Tab, Pat, _Lock) ->
  1173. abort({badarg, Tab, Pat}).
  1174. select(Tid, Ts, Tab, Spec, LockKind) ->
  1175. SelectFun = fun(FixedSpec) -> dirty_select(Tab, FixedSpec) end,
  1176. fun_select(Tid, Ts, Tab, Spec, LockKind, Tab, SelectFun).
  1177. fun_select(Tid, Ts, Tab, Spec, LockKind, TabPat, SelectFun) ->
  1178. case element(1, Tid) of
  1179. ets ->
  1180. mnesia_lib:db_select(ram_copies, Tab, Spec);
  1181. tid ->
  1182. select_lock(Tid,Ts,LockKind,Spec,Tab),
  1183. Store = Ts#tidstore.store,
  1184. Written = ?ets_match_object(Store, {{TabPat, '_'}, '_', '_'}),
  1185. case Written of
  1186. [] ->
  1187. %% Nothing changed in the table during this transaction,
  1188. %% Simple case get results from [d]ets
  1189. SelectFun(Spec);
  1190. _ ->
  1191. %% Hard (slow case) records added or deleted earlier
  1192. %% in the transaction, have to cope with that.
  1193. Type = val({Tab, setorbag}),
  1194. FixedSpec = get_record_pattern(Spec),
  1195. TabRecs = SelectFun(FixedSpec),
  1196. FixedRes = add_match(Written, TabRecs, Type),
  1197. CMS = ets:match_spec_compile(Spec),
  1198. ets:match_spec_run(FixedRes, CMS)
  1199. end;
  1200. _Protocol ->
  1201. SelectFun(Spec)
  1202. end.
  1203. select_lock(Tid,Ts,LockKind,Spec,Tab) ->
  1204. %% Avoid table lock if possible
  1205. case Spec of
  1206. [{HeadPat,_, _}] when tuple(HeadPat), size(HeadPat) > 2 ->
  1207. Key = element(2, HeadPat),
  1208. case has_var(Key) of
  1209. false -> lock_record(Tid, Ts, Tab, Key, LockKind);
  1210. true -> lock_table(Tid, Ts, Tab, LockKind)
  1211. end;
  1212. _ ->
  1213. lock_table(Tid, Ts, Tab, LockKind)
  1214. end.
  1215. %% Breakable Select
  1216. select(Tab, Pat, NObjects, LockKind)
  1217. when atom(Tab), Tab /= schema, list(Pat), number(NObjects) ->
  1218. case get(mnesia_activity_state) of
  1219. {?DEFAULT_ACCESS, Tid, Ts} ->
  1220. select(Tid, Ts, Tab, Pat, NObjects, LockKind);
  1221. {Mod, Tid, Ts} ->
  1222. Mod:select(Tid, Ts, Tab, Pat, NObjects, LockKind);
  1223. _ ->
  1224. abort(no_transaction)
  1225. end;
  1226. select(Tab, Pat, NObjects, _Lock) ->
  1227. abort({badarg, Tab, Pat, NObjects}).
  1228. select(Tid, Ts, Tab, Spec, NObjects, LockKind) ->
  1229. Where = val({Tab,where_to_read}),
  1230. Type = mnesia_lib:storage_type_at_node(Where,Tab),
  1231. InitFun = fun(FixedSpec) -> dirty_sel_init(Where,Tab,FixedSpec,NObjects,Type) end,
  1232. fun_select(Tid,Ts,Tab,Spec,LockKind,Tab,InitFun,NObjects,Where,Type).
  1233. -record(mnesia_select, {tab,tid,node,storage,cont,written=[],spec,type,orig}).
  1234. fun_select(Tid, Ts, Tab, Spec, LockKind, TabPat, Init, NObjects, Node, Storage) ->
  1235. Def = #mnesia_select{tid=Tid,node=Node,storage=Storage,tab=Tab,orig=Spec},
  1236. case element(1, Tid) of
  1237. ets ->
  1238. select_state(mnesia_lib:db_select_init(ram_copies,Tab,Spec,NObjects),Def);
  1239. tid ->
  1240. select_lock(Tid,Ts,LockKind,Spec,Tab),
  1241. Store = Ts#tidstore.store,
  1242. do_fixtable(Tab, Store),
  1243. Written0 = ?ets_match_object(Store, {{TabPat, '_'}, '_', '_'}),
  1244. case Written0 of
  1245. [] ->
  1246. %% Nothing changed in the table during this transaction,
  1247. %% Simple case get results from [d]ets
  1248. select_state(Init(Spec),Def);
  1249. _ ->
  1250. %% Hard (slow case) records added or deleted earlier
  1251. %% in the transaction, have to cope with that.
  1252. Type = val({Tab, setorbag}),
  1253. Written =
  1254. if Type == ordered_set -> %% Sort stable
  1255. lists:keysort(1,Written0);
  1256. true ->
  1257. Written0
  1258. end,
  1259. FixedSpec = get_record_pattern(Spec),
  1260. CMS = ets:match_spec_compile(Spec),
  1261. trans_select(Init(FixedSpec),
  1262. Def#mnesia_select{written=Written,spec=CMS,type=Type})
  1263. end;
  1264. _Protocol ->
  1265. select_state(Init(Spec),Def)
  1266. end.
  1267. select(Cont) ->
  1268. case get(mnesia_activity_state) of
  1269. {?DEFAULT_ACCESS, Tid, Ts} ->
  1270. select_cont(Tid,Ts,Cont);
  1271. {Mod, Tid, Ts} ->
  1272. Mod:select_cont(Tid,Ts,Cont);
  1273. _ ->
  1274. abort(no_transaction)
  1275. end.
  1276. select_cont(_Tid,_Ts,'$end_of_table') ->
  1277. '$end_of_table';
  1278. select_cont(Tid,_Ts,State=#mnesia_select{tid=Tid,cont=Cont, orig=Ms})
  1279. when element(1,Tid) == ets ->
  1280. case Cont of
  1281. '$end_of_table' -> '$end_of_table';
  1282. _ -> select_state(mnesia_lib:db_select_cont(ram_copies,Cont,Ms),State)
  1283. end;
  1284. select_cont(Tid,_,State=#mnesia_select{tid=Tid,written=[]}) ->
  1285. select_state(dirty_sel_cont(State),State);
  1286. select_cont(Tid,_Ts,State=#mnesia_select{tid=Tid}) ->
  1287. trans_select(dirty_sel_cont(State), State);
  1288. select_cont(_Tid2,_,#mnesia_select{tid=_Tid1}) -> % Missmatching tids
  1289. abort(wrong_transaction);
  1290. select_cont(_,_,Cont) ->
  1291. abort({badarg, Cont}).
  1292. trans_select('$end_of_table', #mnesia_select{written=Written0,spec=CMS,type=Type}) ->
  1293. Written = add_match(Written0, [], Type),
  1294. {ets:match_spec_run(Written, CMS), '$end_of_table'};
  1295. trans_select({TabRecs,Cont}, State = #mnesia_select{written=Written0,spec=CMS,type=Type}) ->
  1296. {FixedRes,Written} = add_sel_match(Written0, TabRecs, Type),
  1297. select_state({ets:match_spec_run(FixedRes, CMS),Cont},
  1298. State#mnesia_select{written=Written}).
  1299. select_state({Matches, Cont}, MS) ->
  1300. {Matches, MS#mnesia_select{cont=Cont}};
  1301. select_state('$end_of_table',_) -> '$end_of_table'.
  1302. get_record_pattern([]) -> [];
  1303. get_record_pattern([{M,C,_B}|R]) ->
  1304. [{M,C,['$_']} | get_record_pattern(R)].
  1305. all_keys(Tab) ->
  1306. case get(mnesia_activity_state) of
  1307. {?DEFAULT_ACCESS, Tid, Ts} ->
  1308. all_keys(Tid, Ts, Tab, read);
  1309. {Mod, Tid, Ts} ->
  1310. Mod:all_keys(Tid, Ts, Tab, read);
  1311. _ ->
  1312. abort(no_transaction)
  1313. end.
  1314. all_keys(Tid, Ts, Tab, LockKind)
  1315. when atom(Tab), Tab /= schema ->
  1316. Pat0 = val({Tab, wild_pattern}),
  1317. Pat = setelement(2, Pat0, '$1'),
  1318. Keys = select(Tid, Ts, Tab, [{Pat, [], ['$1']}], LockKind),
  1319. case val({Tab, setorbag}) of
  1320. bag ->
  1321. mnesia_lib:uniq(Keys);
  1322. _ ->
  1323. Keys
  1324. end;
  1325. all_keys(_Tid, _Ts, Tab, _LockKind) ->
  1326. abort({bad_type, Tab}).
  1327. index_match_object(Pat, Attr) when tuple(Pat), size(Pat) > 2 ->
  1328. Tab = element(1, Pat),
  1329. index_match_object(Tab, Pat, Attr, read);
  1330. index_match_object(Pat, _Attr) ->
  1331. abort({bad_type, Pat}).
  1332. index_match_object(Tab, Pat, Attr, LockKind) ->
  1333. case get(mnesia_activity_state) of
  1334. {?DEFAULT_ACCESS, Tid, Ts} ->
  1335. index_match_object(Tid, Ts, Tab, Pat, Attr, LockKind);
  1336. {Mod, Tid, Ts} ->
  1337. Mod:index_match_object(Tid, Ts, Tab, Pat, Attr, LockKind);
  1338. _ ->
  1339. abort(no_transaction)
  1340. end.
  1341. index_match_object(Tid, Ts, Tab, Pat, Attr, LockKind)
  1342. when atom(Tab), Tab /= schema, tuple(Pat), size(Pat) > 2 ->
  1343. case element(1, Tid) of
  1344. ets ->
  1345. dirty_index_match_object(Tab, Pat, Attr); % Should be optimized?
  1346. tid ->
  1347. case mnesia_schema:attr_tab_to_pos(Tab, Attr) of
  1348. Pos when Pos =< size(Pat) ->
  1349. case LockKind of
  1350. read ->
  1351. Store = Ts#tidstore.store,
  1352. mnesia_locker:rlock_table(Tid, Store, Tab),
  1353. Objs = dirty_index_match_object(Tab, Pat, Attr),
  1354. add_written_match(Store, Pat, Tab, Objs);
  1355. _ ->
  1356. abort({bad_type, Tab, LockKind})
  1357. end;
  1358. BadPos ->
  1359. abort({bad_type, Tab, BadPos})
  1360. end;
  1361. _Protocol ->
  1362. dirty_index_match_object(Tab, Pat, Attr)
  1363. end;
  1364. index_match_object(_Tid, _Ts, Tab, Pat, _Attr, _LockKind) ->
  1365. abort({bad_type, Tab, Pat}).
  1366. index_read(Tab, Key, Attr) ->
  1367. case get(mnesia_activity_state) of
  1368. {?DEFAULT_ACCESS, Tid, Ts} ->
  1369. index_read(Tid, Ts, Tab, Key, Attr, read);
  1370. {Mod, Tid, Ts} ->
  1371. Mod:index_read(Tid, Ts, Tab, Key, Attr, read);
  1372. _ ->
  1373. abort(no_transaction)
  1374. end.
  1375. index_read(Tid, Ts, Tab, Key, Attr, LockKind)
  1376. when atom(Tab), Tab /= schema ->
  1377. case element(1, Tid) of
  1378. ets ->
  1379. dirty_index_read(Tab, Key, Attr); % Should be optimized?
  1380. tid ->
  1381. Pos = mnesia_schema:attr_tab_to_pos(Tab, Attr),
  1382. case LockKind of
  1383. read ->
  1384. case has_var(Key) of
  1385. false ->
  1386. Store = Ts#tidstore.store,
  1387. Objs = mnesia_index:read(Tid, Store, Tab, Key, Pos),
  1388. Pat = setelement(Pos, val({Tab, wild_pattern}), Key),
  1389. add_written_match(Store, Pat, Tab, Objs);
  1390. true ->
  1391. abort({bad_type, Tab, Attr, Key})
  1392. end;
  1393. _ ->
  1394. abort({bad_type, Tab, LockKind})
  1395. end;
  1396. _Protocol ->
  1397. dirty_index_read(Tab, Key, Attr)
  1398. end;
  1399. index_read(_Tid, _Ts, Tab, _Key, _Attr, _LockKind) ->
  1400. abort({bad_type, Tab}).
  1401. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1402. %% Dirty access regardless of activities - updates
  1403. dirty_write(Val) when tuple(Val), size(Val) > 2 ->
  1404. Tab = element(1, Val),
  1405. dirty_write(Tab, Val);
  1406. dirty_write(Val) ->
  1407. abort({bad_type, Val}).
  1408. dirty_write(Tab, Val) ->
  1409. do_dirty_write(async_dirty, Tab, Val).
  1410. do_dirty_write(SyncMode, Tab, Val)
  1411. when atom(Tab), Tab /= schema, tuple(Val), size(Val) > 2 ->
  1412. case ?catch_val({Tab, record_validation}) of
  1413. {RecName, Arity, _Type}
  1414. when size(Val) == Arity, RecName == element(1, Val) ->
  1415. Oid = {Tab, element(2, Val)},
  1416. mnesia_tm:dirty(SyncMode, {Oid, Val, write});
  1417. {'EXIT', _} ->
  1418. abort({no_exists, Tab});
  1419. _ ->
  1420. abort({bad_type, Val})
  1421. end;
  1422. do_dirty_write(_SyncMode, Tab, Val) ->
  1423. abort({bad_type, Tab, Val}).
  1424. dirty_delete({Tab, Key}) ->
  1425. dirty_delete(Tab, Key);
  1426. dirty_delete(Oid) ->
  1427. abort({bad_type, Oid}).
  1428. dirty_delete(Tab, Key) ->
  1429. do_dirty_delete(async_dirty, Tab, Key).
  1430. do_dirty_delete(SyncMode, Tab, Key) when atom(Tab), Tab /= schema ->
  1431. Oid = {Tab, Key},
  1432. mnesia_tm:dirty(SyncMode, {Oid, Oid, delete});
  1433. do_dirty_delete(_SyncMode, Tab, _Key) ->
  1434. abort({bad_type, Tab}).
  1435. dirty_delete_object(Val) when tuple(Val), size(Val) > 2 ->
  1436. Tab = element(1, Val),
  1437. dirty_delete_object(Tab, Val);
  1438. dirty_delete_object(Val) ->
  1439. abort({bad_type, Val}).
  1440. dirty_delete_object(Tab, Val) ->
  1441. do_dirty_delete_object(async_dirty, Tab, Val).
  1442. do_dirty_delete_object(SyncMode, Tab, Val)
  1443. when atom(Tab), Tab /= schema, tuple(Val), size(Val) > 2 ->
  1444. Oid = {Tab, element(2, Val)},
  1445. mnesia_tm:dirty(SyncMode, {Oid, Val, delete_object});
  1446. do_dirty_delete_object(_SyncMode, Tab, Val) ->
  1447. abort({bad_type, Tab, Val}).
  1448. %% A Counter is an Oid being {CounterTab, CounterName}
  1449. dirty_update_counter({Tab, Key}, Incr) ->
  1450. dirty_update_counter(Tab, Key, Incr);
  1451. dirty_update_counter(Counter, _Incr) ->
  1452. abort({bad_type, Counter}).
  1453. dirty_update_counter(Tab, Key, Incr) ->
  1454. do_dirty_update_counter(async_dirty, Tab, Key, Incr).
  1455. do_dirty_update_counter(SyncMode, Tab, Key, Incr)
  1456. when atom(Tab), Tab /= schema, integer(Incr) ->
  1457. case ?catch_val({Tab, record_validation}) of
  1458. {RecName, 3, set} ->
  1459. Oid = {Tab, Key},
  1460. mnesia_tm:dirty(SyncMode, {Oid, {RecName, Incr}, update_counter});
  1461. _ ->
  1462. abort({combine_error, Tab, update_counter})
  1463. end;
  1464. do_dirty_update_counter(_SyncMode, Tab, _Key, Incr) ->
  1465. abort({bad_type, Tab, Incr}).
  1466. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1467. %% Dirty access regardless of activities - read
  1468. dirty_read({Tab, Key}) ->
  1469. dirty_read(Tab, Key);
  1470. dirty_read(Oid) ->
  1471. abort({bad_type, Oid}).
  1472. dirty_read(Tab, Key)
  1473. when atom(Tab), Tab /= schema ->
  1474. %% case catch ?ets_lookup(Tab, Key) of
  1475. %% {'EXIT', _} ->
  1476. %% Bad luck, we have to perform a real lookup
  1477. dirty

Large files files are truncated, but you can click here to view the full file