From eadd61d754131dfe046674b5bf5d1160a63809fc Mon Sep 17 00:00:00 2001 From: Fred Dushin Date: Tue, 7 Mar 2017 16:55:02 -0500 Subject: [PATCH 1/2] Removed rs_migration code, tests, and logic that relies on it. --- riak_test/yz_rs_migration_test.erl | 291 ----------------------------- src/yz_app.erl | 17 +- src/yz_rs_migration.erl | 109 ----------- src/yz_wm_search.erl | 8 +- 4 files changed, 2 insertions(+), 423 deletions(-) delete mode 100644 riak_test/yz_rs_migration_test.erl delete mode 100644 src/yz_rs_migration.erl diff --git a/riak_test/yz_rs_migration_test.erl b/riak_test/yz_rs_migration_test.erl deleted file mode 100644 index 8fba686f..00000000 --- a/riak_test/yz_rs_migration_test.erl +++ /dev/null @@ -1,291 +0,0 @@ --module(yz_rs_migration_test). --compile(export_all). --include("yokozuna.hrl"). --include_lib("eunit/include/eunit.hrl"). --include_lib("kernel/include/file.hrl"). - -%% @doc Test the migration path from Riak Search to Yokozuna. -%% -%% 1. A rolling upgrade is performed and on each node Yokozuna is -%% enabled in the app.config. -%% -%% 2. For every index in Riak Search the user must create a comparable -%% index in Yokozuna. -%% -%% 3. For every bucket which is indexed by Riak Search the user must -%% add the `search_index' bucket property to point to the Yokozuna index -%% which is going to eventually be migrated to. -%% -%% 4. As objects are written or modified they will be indexed by both -%% Riak Search and Yokozuna. But the HTTP and PB query interfaces -%% will continue to use Riak Search. -%% -%% 5a. The YZ AAE trees must be manually cleared so that AAE will notice -%% the missing indexes. -%% -%% 5b. In the background AAE will start building trees for Yokozuna and -%% exchange them with KV. These exchanges will notice objects are -%% missing and index them in Yokozuna. -%% -%% 5c. The user wants Yokozuna to index the missing objects as fast as -%% possible. A command may be used (repair? bucket map-reduce? custom -%% fold function?) to immediately re-index data. -%% -%% 6. Eventually all partitions will be exchanged (or buckets -%% re-indexed) and the user will be satisfied that queries can now -%% migrate to Yokozuna. This will be accomplished via the AAE status. -%% -%% 7. The user will call some command that hands HTTP and PB query -%% control to Yokozuna. -%% -%% 8. The user must then set the `search' bucket property to `false' -%% for all indexed buckets. -%% -%% 9. Then the user can disable Riak Search on all nodes. -%% -%% 10. Eventually, when the user is convinced the Riak Search data is -%% no longer needed the merge index directories may be deleted to -%% reclaim disk space. - --define(CFG, - [{riak_core, - [ - {ring_creation_size, 16} - ]}, - {riak_search, - [ - {enabled, true} - ]}, - {yokozuna, [{?SOLRQ_DRAIN_ENABLE, true}]} - ]). --define(FRUIT_BUCKET, <<"fruit">>). - -%% TODO: migration by re-index command -confirm() -> - lager:info("ticktime: ~p", [net_kernel:get_net_ticktime()]), - case yz_rt:bb_driver_setup() of - {ok, YZBenchDir} -> - lager:info("YZBenchDir: ~p", [YZBenchDir]), - - TestMetaData = riak_test_runner:metadata(), - OldVsn = proplists:get_value(upgrade_version, TestMetaData, legacy), - - Cluster = rt:build_cluster(lists:duplicate(3, {OldVsn, ?CFG})), - - create_index(Cluster, riak_search), - load_data(Cluster, YZBenchDir, 1000), - query_data(Cluster, YZBenchDir, 1000, 1, <<"value">>), - - %% In real scenarios the cluster will likely have incoming index - %% and search operations during upgrade. I'm avoiding them in - %% this test because Riak Search can fail on search while in a - %% mixed-cluster. - rolling_upgrade(Cluster), - - load_data(Cluster, YZBenchDir, 5000), - query_data(Cluster, YZBenchDir, 5000, 1, <<"value">>), - - check_for_errors(Cluster), - - create_index(Cluster, yokozuna), - yz_rt:set_index(hd(Cluster), ?FRUIT_BUCKET, ?FRUIT_BUCKET), - - clear_aae_trees(Cluster), - wait_for_aae(Cluster), - - switch_to_yokozuna(Cluster), - query_data(Cluster, YZBenchDir, 5000, 1, <<"text">>), - - %% TODO: use BB to check PB - PB = create_pb_conn(hd(Cluster)), - {ok,{search_results,R,_Score,Found}} = - riakc_pb_socket:search(PB, ?FRUIT_BUCKET, <<"text:apple">>), - lager:info("PB R: ~p", [R]), - ?assertEqual(5000, Found), - close_pb_conn(PB), - - set_search_false(Cluster, ?FRUIT_BUCKET), - disable_riak_search(), - stop_riak_search(Cluster), - check_for_errors(Cluster), - - %% TODO: need to verify that `riak_core:register' stuff is undone, - %% - %% need to make sure `riak_search' service is marked as down - remove_mi_data(Cluster), - %% TODO: what about removing the proxy objects under _rsid_? - - lager:info("Verify missing merge_index dirs don't hurt anything"), - restart(Cluster), - check_for_errors(Cluster), - - %% Disabling anti-entropy here prevents a race condition we would occasionally - %% see when AAE kicked in during the load_data step. It was possible for more - %% data to be written to YZ between the KV and YZ trees being snapshotted, which - %% would then cause the data to be removed from YZ as a remote_missing repair. - %% (At least, until the next AAE sweep came around and fixed everything.) - [rpc:call(Node, yz_entropy_mgr, set_mode, [manual]) || Node <- Cluster], - load_data(Cluster, YZBenchDir, 10000), - query_data(Cluster, YZBenchDir, 10000, 1, <<"text">>), - check_for_errors(Cluster), - - pass; - {error, bb_driver_build_failed} -> - lager:info("Failed to build the yokozuna basho_bench driver" - " required for this test"), - fail - end. - -clear_aae_trees(Cluster) -> - lager:info("Clearing AAE trees across cluster"), - [ok = rpc:call(Node, yz_entropy_mgr, clear_trees, []) || Node <- Cluster]. - -restart(Cluster) -> - [rt:stop_and_wait(Node) || Node <- Cluster], - [rt:start_and_wait(Node) || Node <- Cluster], - rt:wait_for_cluster_service(Cluster, riak_kv), - rt:wait_for_cluster_service(Cluster, yokozuna). - -remove_mi_data(Cluster) -> - rt:clean_data_dir(Cluster, "merge_index"). - -stop_riak_search(Cluster) -> - [?assertEqual(ok,rpc:call(Node, application, stop, [riak_search])) - || Node <- Cluster]. - -%% @doc Disable the search hook on `Bucket'. -set_search_false(Cluster, Bucket) -> - lager:info("Uninstall search hook for bucket ~p", [Bucket]), - ok = rpc:call(hd(Cluster), riak_search_kv_hook, uninstall, [Bucket]), - F = fun(Node) -> - PB = create_pb_conn(Node), - PC = pb_get_bucket_prop(PB, ?FRUIT_BUCKET, precommit, false), - close_pb_conn(PB), - PC == [] - end, - yz_rt:wait_until(Cluster, F), - ok. - -%% @doc Disable Riak Search in all app.config files. -disable_riak_search() -> - %% Rely on fact that `all' means no nodes will be restarted. - rt:update_app_config(all, [{riak_search, [{enabled, false}]}]). - -switch_to_yokozuna(Cluster) -> - lager:info("Switching search handling to Yokozuna ~p", [Cluster]), - [rpc:call(Node, yokozuna, switch_to_yokozuna, []) || Node <- Cluster]. - -%% Use AAE status to verify that exchange has occurred for all -%% partitions since the time this function was invoked. --spec wait_for_aae([node()]) -> ok. -wait_for_aae(Cluster) -> - lager:info("Wait for AAE to migrate/repair indexes"), - yz_rt:wait_for_all_trees(Cluster), - yz_rt:wait_for_full_exchange_round(Cluster, erlang:now()), - ok. - -is_error_or_crash_log({FileName,_}) -> - Base = filename:basename(FileName, ".log"), - (Base == "error") or (Base == "crash"). - -has_content({FileName,_}) -> - lager:info("Checking for content in file ~p", [FileName]), - {ok, FI} = file:read_file_info(FileName), - FI#file_info.size > 0. - -check_for_errors(_Cluster) -> - %% This call returns [{FileName,ErlangPort}] - Root = filename:absname(proplists:get_value(root, rt_config:get(rtdev_path))), - Logs = [{Root ++ "/" ++ FileName, Port} - || {FileName, Port} <- rt:get_node_logs()], - Logs2 = lists:filter(fun is_error_or_crash_log/1, Logs), - Logs3 = lists:filter(fun has_content/1, Logs2), - [lager:error("Check the log file ~p", [LogFile]) || {LogFile, _} <- Logs3]. - %% TODO: close ports - %% ?assertEqual(0, length(Logs3)). - -create_index([Node1|_]=Cluster, riak_search) -> - rt:enable_search_hook(Node1, ?FRUIT_BUCKET), - F = fun(Node) -> - lager:info("Verify Riak Search index ~p [~p]", [?FRUIT_BUCKET, Node]), - PB = create_pb_conn(Node), - PBEnabled = pb_get_bucket_prop(PB, ?FRUIT_BUCKET, search, false), - close_pb_conn(PB), - Http = yz_rt:riak_http(element(2, hd(rt:connection_info([Node])))), - HTTPEnabled = http_get_bucket_prop(Http, ?FRUIT_BUCKET, <<"search">>, false), - PBEnabled or HTTPEnabled - end, - yz_rt:wait_until(Cluster, F); -create_index(Cluster, yokozuna) -> - Idx = ?FRUIT_BUCKET, - yz_rt:create_index(Cluster, Idx). - -close_pb_conn(PB) -> - riakc_pb_socket:stop(PB). - -create_pb_conn(Node) -> - {IP, Port} = yz_rt:riak_pb(element(2, hd(rt:connection_info([Node])))), - {ok, PB} = riakc_pb_socket:start_link(IP, Port), - PB. - -load_data(Cluster, YZBenchDir, NumKeys) -> - {ExitCode, _} = yz_rt:load_data(Cluster, ?FRUIT_BUCKET, YZBenchDir, NumKeys), - ?assertEqual(0,ExitCode), - yz_rt:drain_solrqs(Cluster), - yz_rt:commit(Cluster, ?FRUIT_BUCKET). - -query_data(Cluster, YZBenchDir, NumKeys, Time, DefaultField) -> - lager:info("Run query against cluster ~p", [Cluster]), - Idx = binary_to_list(?FRUIT_BUCKET), - Hosts = yz_rt:host_entries(rt:connection_info(Cluster)), - Concurrent = length(Hosts), - Op = {search,"apple","id",NumKeys}, - %% Op = {random_fruit_search, ["id"], 3, NumKeys}, - Cfg = [{mode, {rate,8}}, - {duration, Time}, - {concurrent, Concurrent}, - {code_paths, [YZBenchDir]}, - {driver, yz_driver}, - {operations, [{Op,1}]}, - {http_conns, Hosts}, - {pb_conns, []}, - {default_field, DefaultField}, - {search_path, "/solr/" ++ Idx ++ "/select"}, - {shutdown_on_error, true}], - File = "bb-query-fruit-" ++ Idx, - yz_rt:write_terms(File, Cfg), - {ExitCode, _StdOut} = yz_rt:run_bb(sync, File), - ?assertEqual(0, ExitCode). - -pb_get_bucket_prop(PB, Bucket, Prop, Default) -> - {ok, Props} = riakc_pb_socket:get_bucket(PB, Bucket), - proplists:get_value(Prop, Props, Default). - -http_get_bucket_prop({Host, Port}, Bucket, Prop, Default) -> - URL = lists:flatten(io_lib:format("http://~s:~s/riak/~s", - [Host, integer_to_list(Port), Bucket])), - %% Headers = [{"accept", "text/plain"}], - {ok, "200", _, R} = ibrowse:send_req(URL, [], get, [], []), - Struct = mochijson2:decode(R), - {struct, Props} = element(2,hd(element(2, Struct))), - proplists:get_value(Prop, Props, Default). - -rolling_upgrade(Cluster) -> - SolrPorts = lists:seq(11000, 11000 + length(Cluster) - 1), - Cluster2 = lists:zip(SolrPorts, Cluster), - [begin - Cfg = [{riak_kv, [{anti_entropy, {on, [debug]}}, - {anti_entropy_concurrency, 12}, - {anti_entropy_build_limit, {6,500}} - ]}, - {yokozuna, [{anti_entropy, {on, [debug]}}, - {anti_entropy_concurrency, 12}, - {anti_entropy_build_limit, {6,500}}, - {anti_entropy_tick, 1000}, - {enabled, true}, - {solr_port, SolrPort}]}], - yz_rt:rolling_upgrade(Node, - current, - Cfg, - [riak_kv, riak_search, yokozuna]) - end || {SolrPort, Node} <- Cluster2]. diff --git a/src/yz_app.erl b/src/yz_app.erl index 7f31afa3..80d4a2b9 100644 --- a/src/yz_app.erl +++ b/src/yz_app.erl @@ -122,9 +122,6 @@ initialize_atoms() -> maybe_setup(false) -> ok; maybe_setup(true) -> - Ring = yz_misc:get_ring(raw), - RSEnabled = yz_rs_migration:is_riak_search_enabled(), - yz_rs_migration:strip_rs_hooks(RSEnabled, Ring), Routes = yz_wm_search:routes() ++ yz_wm_extract:routes() ++ yz_wm_index:routes() ++ yz_wm_schema:routes(), ok = yz_events:add_guarded_handler(yz_events, []), @@ -141,20 +138,8 @@ maybe_setup(true) -> ok = yz_schema:setup_schema_bucket(), ok = set_ibrowse_config(), yz_misc:add_routes(Routes), - maybe_register_pb(RSEnabled), ok. -%% @doc Conditionally register PB service IFF Riak Search is not -%% enabled. --spec maybe_register_pb(boolean()) -> ok. -maybe_register_pb(true) -> - lager:info("Not registering Yokozuna protocol buffer services" - " because Riak Search is enabled as well"), - ok; -maybe_register_pb(false) -> - ok = riak_api_pb_service:register(?QUERY_SERVICES), - ok = riak_api_pb_service:register(?ADMIN_SERVICES). - %% @private %% %% @doc Determine if direct stats are being used or not. If not setup @@ -177,4 +162,4 @@ set_ibrowse_config() -> ?YZ_CONFIG_IBROWSE_MAX_PIPELINE_SIZE, ?YZ_CONFIG_IBROWSE_MAX_PIPELINE_SIZE_DEFAULT)} ], - yz_solr:set_ibrowse_config(Config). \ No newline at end of file + yz_solr:set_ibrowse_config(Config). diff --git a/src/yz_rs_migration.erl b/src/yz_rs_migration.erl deleted file mode 100644 index 51e6c67f..00000000 --- a/src/yz_rs_migration.erl +++ /dev/null @@ -1,109 +0,0 @@ -%% ------------------------------------------------------------------- -%% -%% Copyright (c) 2013 Basho Technologies, Inc. All Rights Reserved. -%% -%% 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. -%% -%% ------------------------------------------------------------------- -%% @doc This code is only needed for riak search migration and can be -%% pulled once riak search is removed from riak. - --module(yz_rs_migration). --compile(export_all). --include("yokozuna.hrl"). - -%% @doc Determine if Riak Search is enabled. --spec is_riak_search_enabled() -> boolean(). -is_riak_search_enabled() -> - app_helper:get_env(?RS_SVC, enabled, false). - -%% @doc Remove Riak Search pre-commit hook from all buckets when Riak -%% Search is disabled. -%% -%% Previous versions of Riak had a bug in `set_bucket' which caused -%% bucket fixups to leak into the raw ring. If a user is upgrading -%% from one of these versions, and enabled search on a bucket, then -%% the Riak Searc hook will be in the raw ring. After migrating to -%% Yokozuna these hooks must be removed to avoid errors. --spec strip_rs_hooks(IsRSEnabled :: boolean(), ring()) -> ok. -strip_rs_hooks(true, _) -> - ok; -strip_rs_hooks(false, Ring) -> - Buckets = riak_core_ring:get_buckets(Ring), - strip_rs_hooks_2(Ring, Buckets). - -%%%=================================================================== -%%% EVERYTHING BELOW IS FOR BUG CAUSED BY LEAKED BUCKET FIXUPS. -%%% -%%% Much of this code was copied from `riak_search_kv_hook'. -%%%=================================================================== - -%% @private -%% -%% @doc Given current pre-commit hook generate a new one with all -%% instances of the Riak Search hook removed. -%% -%% `Changed' - A boolean indicating if the `Precommit' value changed. -%% -%% `NewPrecommit' - The new pre-commit hook. --spec gen_new_precommit([term()]) -> {Changed :: boolean(), - NewPrecommit :: [term()]}. -gen_new_precommit(Precommit) -> - %% Strip ALL Riak Search hooks. - NewPrecommit = lists:filter(fun ?MODULE:not_rs_hook/1, Precommit), - Changed = not (Precommit =:= NewPrecommit), - {Changed, NewPrecommit}. - -%% @private -%% -%% @doc Retrieve the pre-commit hook from bucket properties. If it -%% doesn not exist then default to the empty list. --spec get_precommit([term()]) -> [term()]. -get_precommit(BProps) -> - case proplists:get_value(precommit, BProps, []) of - X when is_list(X) -> X; - {struct, _}=X -> [X] - end. - -%% @private -%% -%% @doc Predicate function which returns `true' if the `Hook' is NOT a -%% Riak Search hook. For use with `lists:filter/2'. --spec not_rs_hook(term()) -> boolean(). -not_rs_hook(Hook) -> - not (Hook == rs_precommit_def()). - -%% @private -%% -%% @doc The definition of the Riak Search pre-commit hook. --spec rs_precommit_def() -> term(). -rs_precommit_def() -> - {struct, [{<<"mod">>,<<"riak_search_kv_hook">>}, - {<<"fun">>,<<"precommit">>}]}. - -strip_rs_hooks_2(_Ring, []) -> - ok; -strip_rs_hooks_2(Ring, [Bucket|Rest]) -> - BProps = riak_core_bucket:get_bucket(Bucket, Ring), - Precommit = get_precommit(BProps), - {Changed, NewPreHook} = gen_new_precommit(Precommit), - case Changed of - true -> - riak_core_bucket:set_bucket(Bucket, [{precommit, NewPreHook}]), - ok; - false -> - ok - end, - strip_rs_hooks_2(Ring, Rest). diff --git a/src/yz_wm_search.erl b/src/yz_wm_search.erl index f2a9d099..6d0519e6 100644 --- a/src/yz_wm_search.erl +++ b/src/yz_wm_search.erl @@ -35,13 +35,7 @@ %% @doc Return the list of routes provided by this resource. -spec routes() -> [tuple()]. routes() -> - Routes1 = [{["search", "query", index], ?MODULE, []}], - case yz_rs_migration:is_riak_search_enabled() of - false -> - [{["solr", index, "select"], ?MODULE, []}|Routes1]; - true -> - Routes1 - end. + [{["solr", index, "select"], ?MODULE, []}]. %%%=================================================================== %%% Callbacks From 56236968d83636ee45cfc047d3d9068b0ec7139b Mon Sep 17 00:00:00 2001 From: Fred Dushin Date: Fri, 10 Mar 2017 13:49:27 -0500 Subject: [PATCH 2/2] Removed vestige of riak_search --- include/yokozuna.hrl | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/yokozuna.hrl b/include/yokozuna.hrl index f9aec24c..1b3a240d 100644 --- a/include/yokozuna.hrl +++ b/include/yokozuna.hrl @@ -220,8 +220,6 @@ %% microseconds. -define(YZ_TIME_ELAPSED(StartTime), timer:now_diff(os:timestamp(), StartTime)). --define(RS_SVC, riak_search). - -define(SOLR_HOST_CONTEXT, "/internal_solr"). %%%===================================================================