store_mnesia.erl 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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/translations.hrl").
  17. -include_lib("stdlib/include/qlc.hrl").
  18. -compile(export_all).
  19. start() -> mnesia:start().
  20. stop() -> mnesia:stop().
  21. join() -> mnesia:change_table_copy_type(schema, node(), disc_copies), initialize().
  22. join(Node) ->
  23. mnesia:change_config(extra_db_nodes, [Node]),
  24. mnesia:change_table_copy_type(schema, node(), disc_copies),
  25. [{Tb, mnesia:add_table_copy(Tb, node(), Type)}
  26. || {Tb, [{Node, Type}]} <- [{T, mnesia:table_info(T, where_to_commit)}
  27. || T <- mnesia:system_info(tables)]].
  28. delete() -> mnesia:delete_schema([node()]).
  29. version() -> {version,"KVS MNESIA Embedded"}.
  30. initialize() ->
  31. error_logger:info_msg("Mnesia Init"),
  32. mnesia:create_schema([node()]),
  33. [ Module:init(store_mnesia) || Module <- kvs:modules() ],
  34. wait_for_tables(),
  35. ok.
  36. wait_for_tables() ->
  37. mnesia:wait_for_tables([user,product,group,entry,comment,subscription,group_subscription],5000).
  38. dir() ->
  39. Tables = mnesia:system_info(local_tables),
  40. [{table,atom_to_list(T)}||T<-Tables].
  41. get(RecordName, Key) -> just_one(fun() -> mnesia:read(RecordName, Key) end).
  42. put(Records) when is_list(Records) -> void(fun() -> lists:foreach(fun mnesia:write/1, Records) end);
  43. put(Record) -> put([Record]).
  44. delete(Keys) when is_list(Keys) -> void(fun() -> lists:foreach(fun mnesia:delete_object/1, Keys) end);
  45. delete(Keys) -> delete([Keys]).
  46. delete(Tab, Key) -> mnesia:transaction(fun()-> mnesia:delete({Tab, Key}) end), ok.
  47. multi_select(RecordName, Keys) when is_list(Keys) -> flatten(fun() -> [mnesia:read({RecordName, Key}) || Key <- Keys] end).
  48. select(From, PredicateFunction) when is_function(PredicateFunction) -> exec(qlc:q([Record || Record <- mnesia:table(From), apply(PredicateFunction, [Record])]));
  49. select(From, [{where, Fn}, {order, {Idx, Order}}]) -> exec(qlc:q([R || R <- qlc:keysort(Idx, mnesia:table(From), [{order, Order}]), apply(Fn, [R])]));
  50. select(From, [{where, Fn}, {order, {Idx, Order}}, {limit, {1, Length}}]) ->
  51. {atomic, Recs} = mnesia:transaction(fun()->
  52. QC = qlc:cursor(qlc:q(
  53. [R || R <- qlc:keysort(Idx, mnesia:table(From), [{order, Order}]), apply(Fn, [R])])),
  54. Ret = qlc:eval(qlc:next_answers(QC, Length)),
  55. qlc:delete_cursor(QC),
  56. Ret
  57. end),
  58. Recs;
  59. select(From, [{where, Fn}, {order, {Idx, Order}}, {limit, {Offset, Length}}]) ->
  60. {atomic, Recs} = mnesia:transaction(fun()->
  61. QC = qlc:cursor(qlc:q(
  62. [R || R <- qlc:keysort(Idx, mnesia:table(From), [{order, Order}]), apply(Fn, [R])])),
  63. qlc:next_answers(QC, Offset - 1),
  64. Ret = qlc:eval(qlc:next_answers(QC, Length)),
  65. qlc:delete_cursor(QC),
  66. Ret
  67. end),
  68. Recs;
  69. select(RecordName, Key) -> many(fun() -> mnesia:read({RecordName, Key}) end).
  70. count(RecordName) -> mnesia:table_info(RecordName, size).
  71. all(RecordName) -> flatten(fun() -> Lists = mnesia:all_keys(RecordName), [ mnesia:read({RecordName, G}) || G <- Lists ] end).
  72. all_by_index(RecordName,Key,Value) -> flatten(fun() -> mnesia:index_read(RecordName,Value,Key) end).
  73. next_id(RecordName) -> next_id(RecordName, 1).
  74. next_id(RecordName, Incr) -> mnesia:dirty_update_counter({id_seq, RecordName}, Incr).
  75. just_one(Fun) ->
  76. case mnesia:transaction(Fun) of
  77. {atomic, []} -> {error, not_found};
  78. {atomic, [R]} -> {ok, R};
  79. {atomic, [_|_]} -> {error, duplicated};
  80. _ -> {error, not_found} end.
  81. flatten(Fun) -> case mnesia:transaction(Fun) of {atomic, R} -> lists:flatten(R); _ -> [] end.
  82. many(Fun) -> case mnesia:transaction(Fun) of {atomic, R} -> R; _ -> [] end.
  83. void(Fun) -> case mnesia:transaction(Fun) of {atomic, ok} -> ok; {aborted, Error} -> {error, Error} end.
  84. create_table(Record, RecordInfo, Opts0) ->
  85. Attr = [{attributes, RecordInfo}],
  86. Opts = transform_opts(Opts0),
  87. AllOpts = lists:concat([Opts, Attr]),
  88. case mnesia:create_table(Record, lists:flatten(AllOpts)) of
  89. {atomic, ok} -> ok;
  90. {aborted, {already_exists, Record}} -> ok;
  91. {aborted, Err} -> {error, Err} end.
  92. add_table_index(Record, Field) ->
  93. catch case mnesia:add_table_index(Record, Field) of
  94. {atomic, ok} -> ok;
  95. {aborted,Reason} -> {aborted,Reason};
  96. Err -> Err end.
  97. transform_opts(Opts) -> transform_opts(Opts, []).
  98. transform_opts([], Acc) -> lists:reverse(Acc);
  99. transform_opts([{storage, Value} | Rest], Acc0) ->
  100. NewOpts = storage_to_mnesia_type(Value),
  101. Acc = [NewOpts | Acc0],
  102. transform_opts(Rest, Acc);
  103. transform_opts([Other | Rest], Acc0) ->
  104. Acc = [Other | Acc0],
  105. transform_opts(Rest, Acc).
  106. storage_to_mnesia_type(permanent) -> {disc_copies, [node()]};
  107. storage_to_mnesia_type(temporary) -> {ram_copies, [node()]};
  108. storage_to_mnesia_type(ondisk) -> {disc_only_copies, [node()]}.
  109. exec(Q) -> F = fun() -> qlc:e(Q) end, {atomic, Val} = mnesia:transaction(F), Val.
  110. % index funs
  111. products(UId) -> all_by_index(user_product, #user_product.username, UId).
  112. subscriptions(UId) -> all_by_index(subscription, #subscription.who, UId).
  113. subscribed(Who) -> all_by_index(subscription, #subscription.whom, Who).
  114. participate(UserName) -> all_by_index(group_subscription, #group_subscription.who, UserName).
  115. members(GroupName) -> all_by_index(group_subscription, #group_subscription.where, GroupName).
  116. user_tournaments(UId) -> all_by_index(play_record, #play_record.who, UId).
  117. tournament_users(TId) -> all_by_index(play_record, #play_record.tournament, TId).
  118. author_comments(Who) ->
  119. EIDs = [E || #comment{entry_id=E} <- all_by_index(comment,#comment.from, Who) ],
  120. lists:flatten([ all_by_index(entry, #entry.id,EID) || EID <- EIDs]).