store_mnesia.erl 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. -module(store_mnesia).
  2. -author('Maxim Sokhatsky').
  3. -copyright('Synrc Research Center s.r.o.').
  4. -include_lib("kvs/include/config.hrl").
  5. -include_lib("kvs/include/users.hrl").
  6. -include_lib("kvs/include/groups.hrl").
  7. -include_lib("kvs/include/feeds.hrl").
  8. -include_lib("kvs/include/acls.hrl").
  9. -include_lib("kvs/include/invites.hrl").
  10. -include_lib("kvs/include/meetings.hrl").
  11. -include_lib("kvs/include/membership.hrl").
  12. -include_lib("kvs/include/payments.hrl").
  13. -include_lib("kvs/include/purchases.hrl").
  14. -include_lib("kvs/include/products.hrl").
  15. -include_lib("kvs/include/accounts.hrl").
  16. -include_lib("kvs/include/log.hrl").
  17. -include_lib("kvs/include/translations.hrl").
  18. -include_lib("stdlib/include/qlc.hrl").
  19. -compile(export_all).
  20. -define(CREATE_TAB(T), create_table(T, record_info(fields, T), [{storage, permanent}]) ).
  21. start() -> mnesia:start().
  22. stop() -> mnesia:stop().
  23. single() -> mnesia:change_table_copy_type(schema, node(), disc_copies), initialize().
  24. join(Node) ->
  25. mnesia:change_config(extra_db_nodes, [Node]),
  26. mnesia:change_table_copy_type(schema, node(), disc_copies),
  27. [{Tb, mnesia:add_table_copy(Tb, node(), Type)}
  28. || {Tb, [{Node, Type}]} <- [{T, mnesia:table_info(T, where_to_commit)}
  29. || T <- mnesia:system_info(tables)]].
  30. delete() -> mnesia:delete_schema([node()]).
  31. version() -> {version,"KVS MNESIA Embedded"}.
  32. add_indexes() ->
  33. add_table_index(comment, entry_id),
  34. add_table_index(comment, author_id),
  35. add_table_index(subscription, who),
  36. add_table_index(subscription, whom),
  37. add_table_index(group_subscription, who),
  38. add_table_index(group_subscription, where),
  39. add_table_index(entry, feed_id),
  40. add_table_index(entry, entry_id),
  41. add_table_index(entry, from),
  42. add_table_index(user, facebook_id),
  43. add_table_index(user, googleplus_id),
  44. add_table_index(user, twitter_id),
  45. add_table_index(user, github_id),
  46. add_table_index(user, email),
  47. ok.
  48. create_users() -> ?CREATE_TAB(user).
  49. initialize() ->
  50. error_logger:info_msg("Mnesia Init"),
  51. mnesia:create_schema([node()]),
  52. ?CREATE_TAB(payment),
  53. ?CREATE_TAB(acl),
  54. ?CREATE_TAB(acl_entry),
  55. ?CREATE_TAB(feed),
  56. ?CREATE_TAB(team),
  57. ?CREATE_TAB(entry),
  58. ?CREATE_TAB(comment),
  59. ?CREATE_TAB(user),
  60. ?CREATE_TAB(user_product),
  61. ?CREATE_TAB(user_payment),
  62. ?CREATE_TAB(user_status),
  63. ?CREATE_TAB(membership),
  64. ?CREATE_TAB(account),
  65. ?CREATE_TAB(subscription),
  66. ?CREATE_TAB(group_subscription),
  67. ?CREATE_TAB(group),
  68. ?CREATE_TAB(id_seq),
  69. ?CREATE_TAB(transaction),
  70. ?CREATE_TAB(translation),
  71. ?CREATE_TAB(product),
  72. ?CREATE_TAB(product_category),
  73. mnesia:wait_for_tables([comment,subscription,group,group_subscription,user,entry],5000),
  74. add_indexes(),
  75. ok.
  76. dir() ->
  77. Tables = mnesia:system_info(local_tables),
  78. [{table,atom_to_list(T)}||T<-Tables].
  79. get(RecordName, Key) -> just_one(fun() -> mnesia:read(RecordName, Key) end).
  80. put(Records) when is_list(Records) -> void(fun() -> lists:foreach(fun mnesia:write/1, Records) end);
  81. put(Record) -> put([Record]).
  82. delete(Keys) when is_list(Keys) -> void(fun() -> lists:foreach(fun mnesia:delete_object/1, Keys) end);
  83. delete(Keys) -> delete([Keys]).
  84. delete(Tab, Key) -> mnesia:transaction(fun()-> mnesia:delete({Tab, Key}) end), ok.
  85. multi_select(RecordName, Keys) when is_list(Keys) -> flatten(fun() -> [mnesia:read({RecordName, Key}) || Key <- Keys] end).
  86. select(From, PredicateFunction) when is_function(PredicateFunction) -> exec(qlc:q([Record || Record <- mnesia:table(From), apply(PredicateFunction, [Record])]));
  87. select(From, [{where, Fn}, {order, {Idx, Order}}]) -> exec(qlc:q([R || R <- qlc:keysort(Idx, mnesia:table(From), [{order, Order}]), apply(Fn, [R])]));
  88. select(From, [{where, Fn}, {order, {Idx, Order}}, {limit, {1, Length}}]) ->
  89. {atomic, Recs} = mnesia:transaction(fun()->
  90. QC = qlc:cursor(qlc:q(
  91. [R || R <- qlc:keysort(Idx, mnesia:table(From), [{order, Order}]), apply(Fn, [R])])),
  92. Ret = qlc:eval(qlc:next_answers(QC, Length)),
  93. qlc:delete_cursor(QC),
  94. Ret
  95. end),
  96. Recs;
  97. select(From, [{where, Fn}, {order, {Idx, Order}}, {limit, {Offset, Length}}]) ->
  98. {atomic, Recs} = mnesia:transaction(fun()->
  99. QC = qlc:cursor(qlc:q(
  100. [R || R <- qlc:keysort(Idx, mnesia:table(From), [{order, Order}]), apply(Fn, [R])])),
  101. qlc:next_answers(QC, Offset - 1),
  102. Ret = qlc:eval(qlc:next_answers(QC, Length)),
  103. qlc:delete_cursor(QC),
  104. Ret
  105. end),
  106. Recs;
  107. select(RecordName, Key) -> many(fun() -> mnesia:read({RecordName, Key}) end).
  108. count(RecordName) -> mnesia:table_info(RecordName, size).
  109. all(RecordName) -> flatten(fun() -> Lists = mnesia:all_keys(RecordName), [ mnesia:read({RecordName, G}) || G <- Lists ] end).
  110. all_by_index(RecordName,Key,Value) -> flatten(fun() -> mnesia:index_read(RecordName,Value,Key) end).
  111. next_id(RecordName) -> next_id(RecordName, 1).
  112. next_id(RecordName, Incr) -> mnesia:dirty_update_counter({id_seq, RecordName}, Incr).
  113. just_one(Fun) ->
  114. case mnesia:transaction(Fun) of
  115. {atomic, []} -> {error, not_found};
  116. {atomic, [R]} -> {ok, R};
  117. {atomic, [_|_]} -> {error, duplicated};
  118. _ -> {error, not_found} end.
  119. flatten(Fun) -> case mnesia:transaction(Fun) of {atomic, R} -> lists:flatten(R); _ -> [] end.
  120. many(Fun) -> case mnesia:transaction(Fun) of {atomic, R} -> R; _ -> [] end.
  121. void(Fun) -> case mnesia:transaction(Fun) of {atomic, ok} -> ok; {aborted, Error} -> {error, Error} end.
  122. create_table(Record, RecordInfo, Opts0) ->
  123. Attr = [{attributes, RecordInfo}],
  124. Opts = transform_opts(Opts0),
  125. AllOpts = lists:concat([Opts, Attr]),
  126. case mnesia:create_table(Record, lists:flatten(AllOpts)) of
  127. {atomic, ok} -> ok;
  128. {aborted, {already_exists, Record}} -> ok;
  129. {aborted, Err} -> {error, Err} end.
  130. add_table_index(Record, Field) ->
  131. catch case mnesia:add_table_index(Record, Field) of
  132. {atomic, ok} -> ok;
  133. {aborted,Reason} -> {aborted,Reason};
  134. Err -> Err end.
  135. transform_opts(Opts) -> transform_opts(Opts, []).
  136. transform_opts([], Acc) -> lists:reverse(Acc);
  137. transform_opts([{storage, Value} | Rest], Acc0) ->
  138. NewOpts = storage_to_mnesia_type(Value),
  139. Acc = [NewOpts | Acc0],
  140. transform_opts(Rest, Acc);
  141. transform_opts([Other | Rest], Acc0) ->
  142. Acc = [Other | Acc0],
  143. transform_opts(Rest, Acc).
  144. storage_to_mnesia_type(permanent) -> {disc_copies, [node()]};
  145. storage_to_mnesia_type(temporary) -> {ram_copies, [node()]};
  146. storage_to_mnesia_type(ondisk) -> {disc_only_copies, [node()]}.
  147. exec(Q) -> F = fun() -> qlc:e(Q) end, {atomic, Val} = mnesia:transaction(F), Val.
  148. % index funs
  149. products(UId) -> all_by_index(user_product, #user_product.username, UId).
  150. subscriptions(UId) -> all_by_index(subsciption, #subscription.who, UId).
  151. subscribed(Who) -> all_by_index(subscription, #subscription.whom, Who).
  152. participate(UserName) -> all_by_index(group_subscription, #group_subscription.who, UserName).
  153. members(GroupName) -> all_by_index(group_subscription, #group_subscription.where, GroupName).
  154. user_tournaments(UId) -> all_by_index(play_record, #play_record.who, UId).
  155. tournament_users(TId) -> all_by_index(play_record, #play_record.tournament, TId).
  156. author_comments(Who) ->
  157. EIDs = [E || #comment{entry_id=E} <- all_by_index(comment,#comment.author_id, Who) ],
  158. lists:flatten([ all_by_index(entry, #entry.id,EID) || EID <- EIDs]).