diff --git a/src/riak_core.app.src b/src/riak_core.app.src index 246fed3bf..d05cdeb08 100644 --- a/src/riak_core.app.src +++ b/src/riak_core.app.src @@ -1,9 +1,6 @@ {application,riak_core, [{description,"Riak Core Lite"}, - {vsn,"0.9.0"}, - {modules,[]}, - {registered,[]}, - {included_applications,[syntax_tools, compiler]}, + {vsn,"0.9.1"}, {applications, [kernel,stdlib,crypto,os_mon,poolboy] }, diff --git a/src/riak_core_mochiglobal.erl b/src/riak_core_mochiglobal.erl deleted file mode 100644 index c7fde0027..000000000 --- a/src/riak_core_mochiglobal.erl +++ /dev/null @@ -1,107 +0,0 @@ -%% @author Bob Ippolito -%% @copyright 2010 Mochi Media, Inc. -%% @doc Abuse module constant pools as a "read-only shared heap" (since erts 5.6) -%% [1]. --module(riak_core_mochiglobal). --author("Bob Ippolito "). --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), - {module, 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 -%% --ifdef(TEST). --include_lib("eunit/include/eunit.hrl"). -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. diff --git a/src/riak_core_ring_manager.erl b/src/riak_core_ring_manager.erl index 822f7d8c6..504834199 100644 --- a/src/riak_core_ring_manager.erl +++ b/src/riak_core_ring_manager.erl @@ -24,22 +24,17 @@ %% %% Numerous processes concurrently read and access the ring in a %% variety of time sensitive code paths. To make this efficient, -%% `riak_core' uses `mochiglobal' which exploits the Erlang constant -%% pool to provide constant-time access to the ring without needing -%% to copy data into individual process heaps. -%% -%% However, updating a `mochiglobal' value is very slow, and becomes slower -%% the larger the item being stored. With large rings, the delay can -%% become too long during periods of high ring churn, where hundreds of -%% ring events are being triggered a second. +%% `riak_core' uses `persistent_term' to provide constant-time access +%% to the ring without needing to copy data into individual process heaps. +%% See http://erlang.org/doc/man/persistent_term.html %% %% As of Riak 1.4, `riak_core' uses a hybrid approach to solve this %% problem. When a ring is first written, it is written to a shared ETS %% table. If no ring events have occurred for 90 seconds, the ring is -%% then promoted to `mochiglobal'. This provides fast updates during +%% then promoted to `persistent_term'. This provides fast updates during %% periods of ring churn, while eventually providing very fast reads %% after the ring stabilizes. The downside is that reading from the ETS -%% table before promotion is slower than `mochiglobal', and requires +%% table before promotion is slower than `persistent_term', and requires %% copying the ring into individual process heaps. %% %% To alleviate the slow down while in the ETS phase, `riak_core' @@ -127,7 +122,7 @@ start_link(test) -> %% @spec get_my_ring() -> {ok, riak_core_ring:riak_core_ring()} | {error, Reason} get_my_ring() -> - Ring = case riak_core_mochiglobal:get(?RING_KEY) of + Ring = case persistent_term:get(?RING_KEY, undefined) of ets -> case ets:lookup(?ETS, ring) of [{_, RingETS}] -> @@ -543,18 +538,18 @@ cleanup_ets(test) -> ets:delete(?ETS). reset_ring_id() -> - %% Maintain ring id epoch using mochiglobal to ensure ring id remains + %% Maintain ring id epoch using persistent_term to ensure ring id remains %% monotonic even if the riak_core_ring_manager crashes and restarts - Epoch = case riak_core_mochiglobal:get(riak_ring_id_epoch) of + Epoch = case persistent_term:get(riak_ring_id_epoch, undefined) of undefined -> 0; Value -> Value end, - riak_core_mochiglobal:put(riak_ring_id_epoch, Epoch + 1), + persistent_term:put(riak_ring_id_epoch, Epoch + 1), {Epoch + 1, 0}. -%% Set the ring in mochiglobal/ETS. Exported during unit testing +%% Set the ring in persistent_term/ETS. Exported during unit testing %% to make test setup simpler - no need to spin up a riak_core_ring_manager %% process. set_ring_global(Ring) -> @@ -564,7 +559,7 @@ set_ring_global(Ring) -> _ -> [] end, - %% run fixups on the ring before storing it in mochiglobal + %% run fixups on the ring before storing it in persistent_term FixedRing = case riak_core:bucket_fixups() of [] -> Ring; Fixups -> @@ -613,17 +608,17 @@ set_ring_global(Ring) -> {chashbin, CHBin} | BucketMeta2], ets:insert(?ETS, Actions), ets:match_delete(?ETS, {{bucket, '_'}, undefined}), - case riak_core_mochiglobal:get(?RING_KEY) of + case persistent_term:get(?RING_KEY, undefined) of ets -> ok; _ -> - riak_core_mochiglobal:put(?RING_KEY, ets) + persistent_term:put(?RING_KEY, ets) end, ok. promote_ring() -> {ok, Ring} = get_my_ring(), - riak_core_mochiglobal:put(?RING_KEY, Ring). + persistent_term:put(?RING_KEY, Ring). %% Persist a new ring file, set the global value and notify any listeners prune_write_notify_ring(Ring, State) -> @@ -674,7 +669,7 @@ set_ring_global_test() -> Ring = riak_core_ring:fresh(), set_ring_global(Ring), promote_ring(), - ?assert(riak_core_ring:nearly_equal(Ring, riak_core_mochiglobal:get(?RING_KEY))), + ?assert(riak_core_ring:nearly_equal(Ring, persistent_term:get(?RING_KEY, undefined))), cleanup_ets(test). set_my_ring_test() ->