Commits

Andy Gross  committed e29b04a

store ring in mochiglobal instead of ets

  • Participants
  • Parent commits 2b7be7c

Comments (0)

Files changed (3)

File apps/mochiweb/ebin/mochiweb.app

  [{description, "MochiMedia Web Server"},
   {vsn, "0.9"},
   {modules, [
+        mochiglobal,            
         mochihex,
         mochijson,
         mochijson2,
         mochiweb_app,
         mochiweb_charref,
         mochiweb_cookies,
-	    mochiweb_cover,
+        mochiweb_cover,
         mochiweb_echo,
         mochiweb_headers,
         mochiweb_html,

File apps/mochiweb/src/mochiglobal.erl

+%% @author Bob Ippolito <bob@mochimedia.com>
+%% @copyright 2010 Mochi Media, Inc.
+%% @doc Abuse module constant pools as a "read-only shared heap" (since erts 5.6)
+%%      <a href="http://www.erlang.org/pipermail/erlang-questions/2009-March/042503.html">[1]</a>.
+-module(mochiglobal).
+-author("Bob Ippolito <bob@mochimedia.com>").
+-export([get/1, get/2, put/2, delete/1]).
+
+-spec get(atom()) -> any() | undefined.
+%% @equiv get(K, undefined)
+get(K) ->
+    get(K, undefined).
+
+-spec get(atom(), T) -> any() | T.
+%% @doc Get the term for K or return Default.
+get(K, Default) ->
+    get(K, Default, key_to_module(K)).
+
+get(_K, Default, Mod) ->
+    try Mod:term()
+    catch error:undef ->
+            Default
+    end.
+
+-spec put(atom(), any()) -> ok.
+%% @doc Store term V at K, replaces an existing term if present.
+put(K, V) ->
+    put(K, V, key_to_module(K)).
+
+put(_K, V, Mod) ->
+    Bin = compile(Mod, V),
+    code:purge(Mod),
+    code:load_binary(Mod, atom_to_list(Mod) ++ ".erl", Bin),
+    ok.
+
+-spec delete(atom()) -> boolean().
+%% @doc Delete term stored at K, no-op if non-existent.
+delete(K) ->
+    delete(K, key_to_module(K)).
+
+delete(_K, Mod) ->
+    code:purge(Mod),
+    code:delete(Mod).
+
+-spec key_to_module(atom()) -> atom().
+key_to_module(K) ->
+    list_to_atom("mochiglobal:" ++ atom_to_list(K)).
+
+-spec compile(atom(), any()) -> binary().
+compile(Module, T) ->
+    {ok, Module, Bin} = compile:forms(forms(Module, T),
+                                      [verbose, report_errors]),
+    Bin.
+
+-spec forms(atom(), any()) -> [erl_syntax:syntaxTree()].
+forms(Module, T) ->
+    [erl_syntax:revert(X) || X <- term_to_abstract(Module, term, T)].
+
+-spec term_to_abstract(atom(), atom(), any()) -> [erl_syntax:syntaxTree()].
+term_to_abstract(Module, Getter, T) ->
+    [%% -module(Module).
+     erl_syntax:attribute(
+       erl_syntax:atom(module),
+       [erl_syntax:atom(Module)]),
+     %% -export([Getter/0]).
+     erl_syntax:attribute(
+       erl_syntax:atom(export),
+       [erl_syntax:list(
+         [erl_syntax:arity_qualifier(
+            erl_syntax:atom(Getter),
+            erl_syntax:integer(0))])]),
+     %% Getter() -> T.
+     erl_syntax:function(
+       erl_syntax:atom(Getter),
+       [erl_syntax:clause([], none, [erl_syntax:abstract(T)])])].
+
+%%
+%% Tests
+%%
+-include_lib("eunit/include/eunit.hrl").
+-ifdef(TEST).
+get_put_delete_test() ->
+    K = '$$test$$mochiglobal',
+    delete(K),
+    ?assertEqual(
+       bar,
+       get(K, bar)),
+    try
+        ?MODULE:put(K, baz),
+        ?assertEqual(
+           baz,
+           get(K, bar)),
+        ?MODULE:put(K, wibble),
+        ?assertEqual(
+           wibble,
+           ?MODULE:get(K))
+    after
+        delete(K)
+    end,
+    ?assertEqual(
+       bar,
+       get(K, bar)),
+    ?assertEqual(
+       undefined,
+       ?MODULE:get(K)),
+    ok.
+-endif.

File apps/riak/src/riak_ring_manager.erl

 
 -module(riak_ring_manager).
 -include_lib("eunit/include/eunit.hrl").
-
+-define(RING_KEY, riak_ring).
 -behaviour(gen_server2).
 -export([start_link/0,start_link/1,stop/0]).
 -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
 %% @private
 init([]) ->
     Ring = riak_ring:fresh(),
-    ets:new(nodelocal_ring, [protected, named_table]),
-    ets:insert(nodelocal_ring, {ring, Ring}),
+    mochiglobal:put(?RING_KEY, Ring),
     {ok, stateless_server};
 init([test]) ->
     Ring = riak_ring:fresh(16,node()),
-    ets:new(nodelocal_ring, [protected, named_table]),
-    ets:insert(nodelocal_ring, {ring, Ring}),
+    mochiglobal:put(?RING_KEY, Ring),
     {ok, test}.
 
 %% @spec get_my_ring() -> {ok, riak_ring:riak_ring()} | {error, Reason}
 get_my_ring() ->
-    case ets:match(nodelocal_ring, {ring, '$1'}) of
-        [[Ring]] -> {ok, Ring};
-        [] -> {error, no_ring}
+    case mochiglobal:get(?RING_KEY) of
+        Ring when is_tuple(Ring) -> {ok, Ring};
+        undefined -> {error, no_ring}
     end.
+
 %% @spec set_my_ring(riak_ring:riak_ring()) -> ok
 set_my_ring(Ring) -> gen_server2:call(?MODULE, {set_my_ring, Ring}).
 %% @spec write_ringfile() -> ok
 
 %% @private
 handle_call({set_my_ring, Ring}, _From, State) -> 
-    ets:insert(nodelocal_ring, {ring, Ring}),
+    mochiglobal:put(?RING_KEY, Ring),
     {reply,ok,State}.
 
 %% @private