2013-09-22 04:49:36 +00:00
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
%%
|
|
|
|
%% Copyright (c) 2013 Basho Technologies, Inc.
|
|
|
|
%%
|
|
|
|
%% This file is provided to you under the Apache License,
|
|
|
|
%% Version 2.0 (the "License"); you may not use this file
|
|
|
|
%% except in compliance with the License. You may obtain
|
|
|
|
%% a copy of the License at
|
|
|
|
%%
|
|
|
|
%% http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
%%
|
|
|
|
%% Unless required by applicable law or agreed to in writing,
|
|
|
|
%% software distributed under the License is distributed on an
|
|
|
|
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
|
|
%% KIND, either express or implied. See the License for the
|
|
|
|
%% specific language governing permissions and limitations
|
|
|
|
%% under the License.
|
|
|
|
%%
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
-module(cluster_meta_basic).
|
|
|
|
-behavior(riak_test).
|
2013-11-21 21:57:54 +00:00
|
|
|
-export([confirm/0, object_count/2]).
|
2013-09-22 04:49:36 +00:00
|
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
|
|
|
|
|
|
-define(PREFIX1, {a, b}).
|
2013-11-21 21:57:54 +00:00
|
|
|
-define(PREFIX2, {fold, prefix}).
|
2013-09-22 04:49:36 +00:00
|
|
|
-define(KEY1, key1).
|
2013-11-21 21:57:54 +00:00
|
|
|
-define(KEY2, key2).
|
2013-09-22 04:49:36 +00:00
|
|
|
-define(VAL1, val1).
|
|
|
|
-define(VAL2, val2).
|
|
|
|
|
|
|
|
confirm() ->
|
2013-11-21 21:57:54 +00:00
|
|
|
Nodes = rt:build_cluster(5),
|
|
|
|
ok = test_fold_full_prefix(Nodes),
|
|
|
|
ok = test_metadata_conflicts(Nodes),
|
2014-05-22 21:54:23 +00:00
|
|
|
ok = test_writes_after_partial_cluster_failure(Nodes),
|
|
|
|
pass.
|
2013-11-21 21:57:54 +00:00
|
|
|
|
|
|
|
%% 1. write a key and waits til it propogates around the cluster
|
|
|
|
%% 2. stop the immediate eager peers of the node that performed the write
|
|
|
|
%% 3. perform an update of the key from the same node and wait until it reaches all alive nodes
|
|
|
|
%% 4. bring up stopped nodes and ensure that either lazily queued messages or anti-entropy repair
|
|
|
|
%% propogates key to all nodes in cluster
|
|
|
|
test_writes_after_partial_cluster_failure([N1 | _]=Nodes) ->
|
2014-02-01 01:04:18 +00:00
|
|
|
lager:info("testing writes after partial cluster failure"),
|
2013-09-22 04:49:36 +00:00
|
|
|
metadata_put(N1, ?PREFIX1, ?KEY1, ?VAL1),
|
|
|
|
wait_until_metadata_value(Nodes, ?PREFIX1, ?KEY1, ?VAL1),
|
|
|
|
print_tree(N1, Nodes),
|
|
|
|
|
|
|
|
StopNodes = eager_peers(N1, N1),
|
|
|
|
AliveNodes = Nodes -- StopNodes,
|
|
|
|
lager:info("stopping nodes: ~p remaining nodes: ~p", [StopNodes, AliveNodes]),
|
|
|
|
[rt:stop(N) || N <- StopNodes],
|
|
|
|
|
|
|
|
metadata_put(N1, ?PREFIX1, ?KEY1, ?VAL2),
|
|
|
|
wait_until_metadata_value(AliveNodes, ?PREFIX1, ?KEY1, ?VAL2),
|
|
|
|
|
|
|
|
lager:info("bring stopped nodes back up: ~p", [StopNodes]),
|
|
|
|
[rt:start(N) || N <- StopNodes],
|
|
|
|
wait_until_metadata_value(Nodes, ?PREFIX1, ?KEY1, ?VAL2),
|
|
|
|
ok.
|
|
|
|
|
2013-11-21 21:57:54 +00:00
|
|
|
%% 1. write several keys to a prefix, fold over them accumulating a list
|
|
|
|
%% 2. ensure list of keys and values match those written to prefix
|
|
|
|
test_fold_full_prefix([N1 | _]=Nodes) ->
|
|
|
|
rt:load_modules_on_nodes([?MODULE], Nodes),
|
|
|
|
lager:info("testing prefix (~p) fold on ~p", [?PREFIX2, N1]),
|
|
|
|
KeysAndVals = [{I, I} || I <- lists:seq(1, 10)],
|
|
|
|
[metadata_put(N1, ?PREFIX2, K, V) || {K, V} <- KeysAndVals],
|
|
|
|
%% we don't use a resolver but shouldn't have conflicts either, so assume that in
|
|
|
|
%% head of fold function
|
|
|
|
FoldRes = [{K, V} || {K, [V]} <- metadata_to_list(N1, ?PREFIX2)],
|
|
|
|
SortedRes = lists:ukeysort(1, FoldRes),
|
|
|
|
?assertEqual(KeysAndVals, SortedRes),
|
|
|
|
ok.
|
|
|
|
|
|
|
|
test_metadata_conflicts([N1, N2 | _]=Nodes) ->
|
|
|
|
rt:load_modules_on_nodes([?MODULE], Nodes),
|
|
|
|
lager:info("testing conflicting writes to a key"),
|
|
|
|
write_conflicting(N1, N2, ?PREFIX1, ?KEY2, ?VAL1, ?VAL2),
|
|
|
|
|
|
|
|
%% assert that we still have siblings since write_conflicting uses allow_put=false
|
|
|
|
lager:info("checking object count after resolve on get w/o put"),
|
|
|
|
?assertEqual(2, rpc:call(N1, ?MODULE, object_count, [?PREFIX1, ?KEY2])),
|
|
|
|
?assertEqual(2, rpc:call(N2, ?MODULE, object_count, [?PREFIX1, ?KEY2])),
|
|
|
|
|
|
|
|
%% iterate over the values and ensure we can resolve w/o doing a put
|
|
|
|
?assertEqual([{?KEY2, lists:usort([?VAL1, ?VAL2])}],
|
|
|
|
metadata_to_list(N1, ?PREFIX1, [{allow_put, false}])),
|
|
|
|
?assertEqual([{?KEY2, lists:usort([?VAL1, ?VAL2])}],
|
|
|
|
metadata_to_list(N2, ?PREFIX1, [{allow_put, false}])),
|
|
|
|
lager:info("checking object count after resolve on itr_key_values w/o put"),
|
|
|
|
?assertEqual(2, rpc:call(N1, ?MODULE, object_count, [?PREFIX1, ?KEY2])),
|
|
|
|
?assertEqual(2, rpc:call(N2, ?MODULE, object_count, [?PREFIX1, ?KEY2])),
|
|
|
|
|
|
|
|
%% assert that we no longer have siblings when allow_put=true
|
|
|
|
lager:info("checking object count afger resolve on get w/ put"),
|
2014-02-01 01:04:18 +00:00
|
|
|
wait_until_metadata_value(N1, ?PREFIX1, ?KEY2,
|
2013-11-21 21:57:54 +00:00
|
|
|
[{resolver, fun list_resolver/2}],
|
|
|
|
lists:usort([?VAL1, ?VAL2])),
|
2014-02-01 01:04:18 +00:00
|
|
|
wait_until_metadata_value([N1, N2], ?PREFIX1, ?KEY2,
|
|
|
|
[{resolver, fun list_resolver/2}, {allow_put, false}],
|
|
|
|
lists:usort([?VAL1, ?VAL2])),
|
|
|
|
wait_until_object_count([N1, N2], ?PREFIX1, ?KEY2, 1),
|
2013-11-21 21:57:54 +00:00
|
|
|
ok.
|
|
|
|
|
|
|
|
write_conflicting(N1, N2, Prefix, Key, Val1, Val2) ->
|
|
|
|
rpc:call(N1, riak_core_metadata_manager, put, [{Prefix, Key}, undefined, Val1]),
|
|
|
|
rpc:call(N2, riak_core_metadata_manager, put, [{Prefix, Key}, undefined, Val2]),
|
|
|
|
wait_until_metadata_value([N1, N2], Prefix, Key,
|
|
|
|
[{resolver, fun list_resolver/2},
|
|
|
|
{allow_put, false}],
|
|
|
|
lists:usort([Val1, Val2])).
|
|
|
|
|
|
|
|
|
|
|
|
object_count(Prefix, Key) ->
|
|
|
|
Obj = riak_core_metadata_manager:get({Prefix, Key}),
|
|
|
|
case Obj of
|
|
|
|
undefined -> 0;
|
|
|
|
_ -> riak_core_metadata_object:value_count(Obj)
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
|
|
list_resolver(X1, X2) when is_list(X2) andalso is_list(X1) ->
|
|
|
|
lists:usort(X1 ++ X2);
|
|
|
|
list_resolver(X1, X2) when is_list(X2) ->
|
|
|
|
lists:usort([X1 | X2]);
|
|
|
|
list_resolver(X1, X2) when is_list(X1) ->
|
|
|
|
lists:usort(X1 ++ [X2]);
|
|
|
|
list_resolver(X1, X2) ->
|
|
|
|
lists:usort([X1, X2]).
|
|
|
|
|
|
|
|
metadata_to_list(Node, FullPrefix) ->
|
|
|
|
metadata_to_list(Node, FullPrefix, []).
|
|
|
|
|
|
|
|
metadata_to_list(Node, FullPrefix, Opts) ->
|
|
|
|
rpc:call(Node, riak_core_metadata, to_list, [FullPrefix, Opts]).
|
|
|
|
|
2013-09-22 04:49:36 +00:00
|
|
|
metadata_put(Node, Prefix, Key, FunOrVal) ->
|
|
|
|
ok = rpc:call(Node, riak_core_metadata, put, [Prefix, Key, FunOrVal]).
|
|
|
|
|
2013-11-21 21:57:54 +00:00
|
|
|
metadata_get(Node, Prefix, Key, Opts) ->
|
|
|
|
rpc:call(Node, riak_core_metadata, get, [Prefix, Key, Opts]).
|
|
|
|
|
|
|
|
wait_until_metadata_value(Nodes, Prefix, Key, Val) ->
|
|
|
|
wait_until_metadata_value(Nodes, Prefix, Key, [], Val).
|
2013-09-22 04:49:36 +00:00
|
|
|
|
2013-11-21 21:57:54 +00:00
|
|
|
wait_until_metadata_value(Nodes, Prefix, Key, Opts, Val) when is_list(Nodes) ->
|
|
|
|
[wait_until_metadata_value(Node, Prefix, Key, Opts, Val) || Node <- Nodes];
|
|
|
|
wait_until_metadata_value(Node, Prefix, Key, Opts, Val) ->
|
2013-09-22 04:49:36 +00:00
|
|
|
lager:info("wait until {~p, ~p} equals ~p on ~p", [Prefix, Key, Val, Node]),
|
|
|
|
F = fun() ->
|
2013-11-21 21:57:54 +00:00
|
|
|
Val =:= metadata_get(Node, Prefix, Key, Opts)
|
2013-09-22 04:49:36 +00:00
|
|
|
end,
|
|
|
|
?assertEqual(ok, rt:wait_until(F)),
|
|
|
|
ok.
|
|
|
|
|
2014-02-01 01:04:18 +00:00
|
|
|
wait_until_object_count(Nodes, Prefix, Key, Count) when is_list(Nodes) ->
|
|
|
|
[wait_until_object_count(Node, Prefix, Key, Count) || Node <- Nodes];
|
|
|
|
wait_until_object_count(Node, Prefix, Key, Count) ->
|
|
|
|
lager:info("wait until {~p, ~p} has object count ~p on ~p", [Prefix, Key, Count, Node]),
|
|
|
|
F = fun() ->
|
|
|
|
Count =:= rpc:call(Node, ?MODULE, object_count, [Prefix, Key])
|
|
|
|
end,
|
|
|
|
?assertEqual(ok, rt:wait_until(F)),
|
|
|
|
ok.
|
|
|
|
|
|
|
|
|
2013-09-22 04:49:36 +00:00
|
|
|
eager_peers(Node, Root) ->
|
|
|
|
{Eagers, _} = rpc:call(Node, riak_core_broadcast, debug_get_peers, [Node, Root]),
|
|
|
|
Eagers.
|
|
|
|
|
|
|
|
print_tree(Root, Nodes) ->
|
|
|
|
Tree = rpc:call(Root, riak_core_broadcast, debug_get_tree, [Root, Nodes]),
|
|
|
|
lager:info("broadcast tree: ~p", [Tree]).
|