You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

107 lines
2.8 KiB

14 years ago
14 years ago
  1. %% @author Bob Ippolito <bob@mochimedia.com>
  2. %% @copyright 2010 Mochi Media, Inc.
  3. %% @doc Abuse module constant pools as a "read-only shared heap" (since erts 5.6)
  4. %% <a href="http://www.erlang.org/pipermail/erlang-questions/2009-March/042503.html">[1]</a>.
  5. -module(lager_mochiglobal).
  6. -author("Bob Ippolito <bob@mochimedia.com>").
  7. -export([get/1, get/2, put/2, delete/1]).
  8. -spec get(atom()) -> any() | undefined.
  9. %% @equiv get(K, undefined)
  10. get(K) ->
  11. get(K, undefined).
  12. -spec get(atom(), T) -> any() | T.
  13. %% @doc Get the term for K or return Default.
  14. get(K, Default) ->
  15. get(K, Default, key_to_module(K)).
  16. get(_K, Default, Mod) ->
  17. try Mod:term()
  18. catch error:undef ->
  19. Default
  20. end.
  21. -spec put(atom(), any()) -> ok.
  22. %% @doc Store term V at K, replaces an existing term if present.
  23. put(K, V) ->
  24. put(K, V, key_to_module(K)).
  25. put(_K, V, Mod) ->
  26. Bin = compile(Mod, V),
  27. code:purge(Mod),
  28. {module, Mod} = code:load_binary(Mod, atom_to_list(Mod) ++ ".erl", Bin),
  29. ok.
  30. -spec delete(atom()) -> boolean().
  31. %% @doc Delete term stored at K, no-op if non-existent.
  32. delete(K) ->
  33. delete(K, key_to_module(K)).
  34. delete(_K, Mod) ->
  35. code:purge(Mod),
  36. code:delete(Mod).
  37. -spec key_to_module(atom()) -> atom().
  38. key_to_module(K) ->
  39. list_to_atom("lager_mochiglobal:" ++ atom_to_list(K)).
  40. -spec compile(atom(), any()) -> binary().
  41. compile(Module, T) ->
  42. {ok, Module, Bin} = compile:forms(forms(Module, T),
  43. [verbose, report_errors]),
  44. Bin.
  45. -spec forms(atom(), any()) -> [erl_syntax:syntaxTree()].
  46. forms(Module, T) ->
  47. [erl_syntax:revert(X) || X <- term_to_abstract(Module, term, T)].
  48. -spec term_to_abstract(atom(), atom(), any()) -> [erl_syntax:syntaxTree()].
  49. term_to_abstract(Module, Getter, T) ->
  50. [%% -module(Module).
  51. erl_syntax:attribute(
  52. erl_syntax:atom(module),
  53. [erl_syntax:atom(Module)]),
  54. %% -export([Getter/0]).
  55. erl_syntax:attribute(
  56. erl_syntax:atom(export),
  57. [erl_syntax:list(
  58. [erl_syntax:arity_qualifier(
  59. erl_syntax:atom(Getter),
  60. erl_syntax:integer(0))])]),
  61. %% Getter() -> T.
  62. erl_syntax:function(
  63. erl_syntax:atom(Getter),
  64. [erl_syntax:clause([], none, [erl_syntax:abstract(T)])])].
  65. %%
  66. %% Tests
  67. %%
  68. -ifdef(TEST).
  69. -include_lib("eunit/include/eunit.hrl").
  70. get_put_delete_test() ->
  71. K = '$$test$$mochiglobal',
  72. delete(K),
  73. ?assertEqual(
  74. bar,
  75. get(K, bar)),
  76. try
  77. ?MODULE:put(K, baz),
  78. ?assertEqual(
  79. baz,
  80. get(K, bar)),
  81. ?MODULE:put(K, wibble),
  82. ?assertEqual(
  83. wibble,
  84. ?MODULE:get(K))
  85. after
  86. delete(K)
  87. end,
  88. ?assertEqual(
  89. bar,
  90. get(K, bar)),
  91. ?assertEqual(
  92. undefined,
  93. ?MODULE:get(K)),
  94. ok.
  95. -endif.