blob: d4cb7caa1471d489aa9991365728f81c62d320fc [file] [log] [blame]
% Licensed 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(mem3_reshard_index).
-export([
design_docs/1,
target_indices/2,
spawn_builders/1
]).
-include_lib("mem3/include/mem3.hrl").
-include_lib("couch/include/couch_db.hrl").
%% Public API
design_docs(DbName) ->
try
case fabric_design_docs(mem3:dbname(DbName)) of
{error, {maintenance_mode, _, _Node}} ->
{ok, []};
{ok, DDocs} ->
JsonDocs = [couch_doc:from_json_obj(DDoc) || DDoc <- DDocs],
{ok, JsonDocs};
Else ->
Else
end
catch error:database_does_not_exist ->
{ok, []}
end.
target_indices(Docs, Targets) ->
Indices = [[indices(N, D) || D <- Docs] || #shard{name = N} <- Targets],
lists:flatten(Indices).
spawn_builders(Indices) ->
Results = [build_index(Index) || Index <- Indices],
Oks = [{ok, Pid} || {ok, Pid} <- Results, is_pid(Pid)],
case Results -- Oks of
[] ->
{ok, [Pid || {ok, Pid} <- Results]};
Error ->
% Do a all or nothing pattern, if some indices could not be
% spawned, kill the spawned ones and and return the error.
ErrMsg = "~p failed to spawn index builders: ~p ~p",
couch_log:error(ErrMsg, [?MODULE, Error, Indices]),
lists:foreach(fun({ok, Pid}) ->
catch unlink(Pid),
catch exit(Pid, kill)
end, Oks),
{error, Error}
end.
%% Private API
fabric_design_docs(DbName) ->
case couch_util:with_proc(fabric, design_docs, [DbName], infinity) of
{ok, Resp} -> Resp;
{error, Error} -> Error
end.
indices(DbName, Doc) ->
mrview_indices(DbName, Doc)
++ [dreyfus_indices(DbName, Doc) || has_app(dreyfus)]
++ [hastings_indices(DbName, Doc) || has_app(hastings)].
mrview_indices(DbName, Doc) ->
try
{ok, MRSt} = couch_mrview_util:ddoc_to_mrst(DbName, Doc),
Views = couch_mrview_index:get(views, MRSt),
case Views =/= [] of
true ->
[{mrview, DbName, MRSt}];
false ->
[]
end
catch
Tag:Err ->
Msg = "~p couldn't get mrview index ~p ~p ~p:~p",
couch_log:error(Msg, [?MODULE, DbName, Doc, Tag, Err]),
[]
end.
dreyfus_indices(DbName, Doc) ->
try
Indices = dreyfus_index:design_doc_to_indexes(Doc),
[{dreyfus, DbName, Index} || Index <- Indices]
catch
Tag:Err ->
Msg = "~p couldn't get dreyfus indices ~p ~p ~p:~p",
couch_log:error(Msg, [?MODULE, DbName, Doc, Tag, Err]),
[]
end.
hastings_indices(DbName, Doc) ->
try
Indices = hastings_index:design_doc_to_indexes(Doc),
[{hastings, DbName, Index} || Index <- Indices]
catch
Tag:Err ->
Msg = "~p couldn't get hasting indices ~p ~p ~p:~p",
couch_log:error(Msg, [?MODULE, DbName, Doc, Tag, Err]),
[]
end.
build_index({mrview, DbName, MRSt}) ->
case couch_index_server:get_index(couch_mrview_index, MRSt) of
{ok, Pid} ->
Args = [Pid, get_update_seq(DbName)],
WPid = spawn_link(couch_index, get_state, Args),
{ok, WPid};
Error ->
Error
end;
build_index({dreyfus, DbName, Index})->
case dreyfus_index_manager:get_index(DbName, Index) of
{ok, Pid} ->
Args = [Pid, get_update_seq(DbName)],
WPid = spawn_link(dreyfus_index, await, Args),
{ok, WPid};
Error ->
Error
end;
build_index({hastings, DbName, Index}) ->
case hastings_index_manager:get_index(DbName, Index) of
{ok, Pid} ->
Args = [Pid, get_update_seq(DbName)],
WPid = spawn_link(hastings_index, await, Args),
{ok, WPid};
Error ->
Error
end.
has_app(App) ->
code:lib_dir(App) /= {error, bad_name}.
get_update_seq(DbName) ->
couch_util:with_db(DbName, fun(Db) ->
couch_db:get_update_seq(Db)
end).