/apps/ejabberd/src/ejabberd_riak.erl

https://github.com/pgal/ejabberd · Erlang · 115 lines · 94 code · 17 blank · 4 comment · 0 complexity · c0c11aed0efcd31aa081f01d79e7ca32 MD5 · raw file

  1. -module(ejabberd_riak).
  2. %% Public interface
  3. -export([start_link/1,
  4. get/2,
  5. set/3,
  6. delete/1,
  7. delete/2,
  8. list_keys/1,
  9. mapred_bucket/2]).
  10. -include("ejabberd.hrl").
  11. start_link(WorkerId) ->
  12. {Host, Port} = {get_host(), get_port()},
  13. {ok, Pid} = connect(Host, Port),
  14. ejabberd_riak_sup:register(WorkerId, Pid),
  15. {ok, Pid}.
  16. get(Bucket, Key) ->
  17. case get_obj(Bucket, Key) of
  18. {ok, Obj} ->
  19. {ok, binary_to_term(riakc_obj:get_value(Obj))};
  20. Error ->
  21. Error
  22. end.
  23. -spec get_obj(binary(), term()) -> {ok, term()} | {error, any()}.
  24. get_obj(Bucket, Key) ->
  25. BinaryKey = term_to_binary(Key),
  26. riakc_pb_socket:get(get_worker(), Bucket, BinaryKey).
  27. -spec set(binary(), term(), term()) -> ok | {error, any()}.
  28. set(Bucket, Key, Value) ->
  29. BinaryKey = term_to_binary(Key),
  30. BinaryValue = term_to_binary(Value),
  31. case get_obj(Bucket, Key) of
  32. {ok, Obj} ->
  33. NewObj = riakc_obj:update_value(Obj, BinaryValue),
  34. riakc_pb_socket:put(get_worker(), NewObj);
  35. {error, notfound} ->
  36. NewObj = riakc_obj:new(Bucket, BinaryKey, BinaryValue),
  37. riakc_pb_socket:put(get_worker(), NewObj);
  38. Else ->
  39. Else
  40. end.
  41. %% Delete whole bucket.
  42. %% TODO: I feel it's far from elegant.
  43. -spec delete(binary()) -> ok | {error, any()}.
  44. delete(Bucket) ->
  45. case riakc_pb_socket:list_keys(get_worker(), Bucket) of
  46. {ok, BinKeys} ->
  47. lists:foreach(
  48. fun(Key) ->
  49. riakc_pb_socket:delete(get_worker(), Bucket, Key) end,
  50. BinKeys);
  51. Error ->
  52. Error
  53. end.
  54. %% Delete object by key.
  55. -spec delete(binary(), term()) -> ok | {error, any()}.
  56. delete(Bucket, Key) ->
  57. riakc_pb_socket:delete(get_worker(), Bucket, term_to_binary(Key)).
  58. -spec list_keys(binary()) -> {ok, [binary()]} | {error, any()}.
  59. list_keys(Bucket) ->
  60. case riakc_pb_socket:list_keys(get_worker(), Bucket) of
  61. {ok, BinKeys} ->
  62. lists:map(fun erlang:binary_to_term/1, BinKeys);
  63. Error ->
  64. Error
  65. end.
  66. -spec mapred_bucket(binary(), list()) -> any().
  67. mapred_bucket(Bucket, Query) ->
  68. riakc_pb_socket:mapred_bucket(get_worker(), Bucket, Query).
  69. get_host() ->
  70. get_config(riak_host, "127.0.0.1").
  71. get_port() ->
  72. get_config(riak_port, 8087).
  73. get_timeout() ->
  74. get_config(riak_initial_connection_timeout, 10).
  75. get_config(Key, Default) ->
  76. case ejabberd_config:get_local_option({Key, ?MYNAME}) of
  77. undefined ->
  78. Default;
  79. Value ->
  80. Value
  81. end.
  82. get_worker() ->
  83. ejabberd_riak_sup:get_worker().
  84. -spec connect(string(), integer()) -> {ok, pid()} | {error, term()}.
  85. connect(Host, Port) ->
  86. random:seed(now()),
  87. connect(Host, Port, 10, get_timeout()).
  88. -spec connect(string(), integer(), integer(), integer()) -> {ok, pid()} | {error, term()}.
  89. connect(Host, Port, 0, _) ->
  90. riakc_pb_socket:start_link(Host, Port);
  91. connect(Host, Port, Retries, WaitTime) ->
  92. case riakc_pb_socket:start_link(Host, Port) of
  93. {ok, Pid} ->
  94. {ok, Pid};
  95. _Else ->
  96. timer:sleep(WaitTime+random:uniform(WaitTime)),
  97. connect(Host, Port, Retries-1, WaitTime*2)
  98. end.