diff options
Diffstat (limited to 'src/mango/src/mango_idx.erl')
-rw-r--r-- | src/mango/src/mango_idx.erl | 207 |
1 files changed, 62 insertions, 145 deletions
diff --git a/src/mango/src/mango_idx.erl b/src/mango/src/mango_idx.erl index 5d06a8fe3..37b6e03eb 100644 --- a/src/mango/src/mango_idx.erl +++ b/src/mango/src/mango_idx.erl @@ -19,7 +19,6 @@ -export([ list/1, - recover/1, new/2, validate_new/2, @@ -33,7 +32,6 @@ name/1, type/1, def/1, - partitioned/1, opts/1, columns/1, is_usable/3, @@ -51,11 +49,35 @@ -include_lib("couch/include/couch_db.hrl"). -include("mango.hrl"). -include("mango_idx.hrl"). +-include_lib("couch_views/include/couch_views.hrl"). list(Db) -> - {ok, Indexes} = ddoc_cache:open(db_to_name(Db), ?MODULE), - Indexes. + DDocs = couch_views_ddoc:get_mango_list(Db), + DbName = fabric2_db:name(Db), + Indexes = lists:foldl(fun(DDoc, Acc) -> + {Props} = couch_doc:to_json_obj(DDoc, []), + + case proplists:get_value(<<"language">>, Props) == <<"query">> of + true -> + {ok, Mrst} = couch_mrview_util:ddoc_to_mrst(DbName, DDoc), + + IsInteractive = couch_views_ddoc:is_interactive(DDoc), + BuildState = couch_views_fdb:get_build_status(Db, Mrst), + + Idxs = lists:map(fun(Idx) -> + Idx#idx{ + build_status = BuildState, + interactive = IsInteractive + } + end, from_ddoc(Db, DDoc)), + Acc ++ Idxs; + false -> + Acc + end + + end, [], DDocs), + Indexes ++ special(Db). get_usable_indexes(Db, Selector, Opts) -> @@ -63,14 +85,14 @@ get_usable_indexes(Db, Selector, Opts) -> GlobalIndexes = mango_cursor:remove_indexes_with_partial_filter_selector( ExistingIndexes ), + BuiltIndexes = remove_unbuilt_indexes(GlobalIndexes), UserSpecifiedIndex = mango_cursor:maybe_filter_indexes_by_ddoc(ExistingIndexes, Opts), - UsableIndexes0 = lists:usort(GlobalIndexes ++ UserSpecifiedIndex), - UsableIndexes1 = filter_partition_indexes(UsableIndexes0, Opts), + UsableIndexes0 = lists:usort(BuiltIndexes ++ UserSpecifiedIndex), SortFields = get_sort_fields(Opts), UsableFilter = fun(I) -> is_usable(I, Selector, SortFields) end, - case lists:filter(UsableFilter, UsableIndexes1) of + case lists:filter(UsableFilter, UsableIndexes0) of [] -> mango_sort_error(Db, Opts); UsableIndexes -> @@ -78,30 +100,8 @@ get_usable_indexes(Db, Selector, Opts) -> end. -mango_sort_error(Db, Opts) -> - case {fabric_util:is_partitioned(Db), is_opts_partitioned(Opts)} of - {false, _} -> - ?MANGO_ERROR({no_usable_index, missing_sort_index}); - {true, true} -> - ?MANGO_ERROR({no_usable_index, missing_sort_index_partitioned}); - {true, false} -> - ?MANGO_ERROR({no_usable_index, missing_sort_index_global}) - end. - - -recover(Db) -> - {ok, DDocs0} = mango_util:open_ddocs(Db), - Pred = fun({Props}) -> - case proplists:get_value(<<"language">>, Props) of - <<"query">> -> true; - _ -> false - end - end, - DDocs = lists:filter(Pred, DDocs0), - Special = special(Db), - {ok, Special ++ lists:flatmap(fun(Doc) -> - from_ddoc(Db, Doc) - end, DDocs)}. +mango_sort_error(_Db, _Opts) -> + ?MANGO_ERROR({no_usable_index, missing_sort_index}). get_sort_fields(Opts) -> @@ -124,7 +124,6 @@ new(Db, Opts) -> name = IdxName, type = Type, def = Def, - partitioned = get_idx_partitioned(Opts), opts = filter_opts(Opts) }}. @@ -136,11 +135,10 @@ validate_new(Idx, Db) -> add(DDoc, Idx) -> Mod = idx_mod(Idx), - {ok, NewDDoc1} = Mod:add(DDoc, Idx), - NewDDoc2 = set_ddoc_partitioned(NewDDoc1, Idx), + {ok, NewDDoc} = Mod:add(DDoc, Idx), % Round trip through JSON for normalization - Body = ?JSON_DECODE(?JSON_ENCODE(NewDDoc2#doc.body)), - {ok, NewDDoc2#doc{body = Body}}. + Body = ?JSON_DECODE(?JSON_ENCODE(NewDDoc#doc.body)), + {ok, NewDDoc#doc{body = Body}}. remove(DDoc, Idx) -> @@ -173,16 +171,17 @@ delete(Filt, Db, Indexes, DelOpts) -> end. -from_ddoc(Db, {Props}) -> +from_ddoc(Db, #doc{id = DDocId} = DDoc) -> + {Props} = couch_doc:to_json_obj(DDoc, []), DbName = db_to_name(Db), - DDoc = proplists:get_value(<<"_id">>, Props), + DDocId = proplists:get_value(<<"_id">>, Props), case proplists:get_value(<<"language">>, Props) of <<"query">> -> ok; _ -> ?MANGO_ERROR(invalid_query_ddoc_language) end, - IdxMods = case clouseau_rpc:connected() of + IdxMods = case is_text_service_available() of true -> [mango_idx_view, mango_idx_text]; false -> @@ -192,8 +191,7 @@ from_ddoc(Db, {Props}) -> lists:map(fun(Idx) -> Idx#idx{ dbname = DbName, - ddoc = DDoc, - partitioned = get_idx_partitioned(Db, Props) + ddoc = DDocId } end, Idxs). @@ -204,7 +202,8 @@ special(Db) -> name = <<"_all_docs">>, type = <<"special">>, def = all_docs, - opts = [] + opts = [], + build_status = ?INDEX_READY }, % Add one for _update_seq [AllDocs]. @@ -230,10 +229,6 @@ def(#idx{def=Def}) -> Def. -partitioned(#idx{partitioned=Partitioned}) -> - Partitioned. - - opts(#idx{opts=Opts}) -> Opts. @@ -294,7 +289,7 @@ db_to_name(Name) when is_binary(Name) -> db_to_name(Name) when is_list(Name) -> iolist_to_binary(Name); db_to_name(Db) -> - couch_db:name(Db). + fabric2_db:name(Db). get_idx_def(Opts) -> @@ -309,7 +304,7 @@ get_idx_def(Opts) -> get_idx_type(Opts) -> case proplists:get_value(type, Opts) of <<"json">> -> <<"json">>; - <<"text">> -> case clouseau_rpc:connected() of + <<"text">> -> case is_text_service_available() of true -> <<"text">>; false -> @@ -322,6 +317,11 @@ get_idx_type(Opts) -> end. +is_text_service_available() -> + erlang:function_exported(clouseau_rpc, connected, 0) andalso + clouseau_rpc:connected(). + + get_idx_ddoc(Idx, Opts) -> case proplists:get_value(ddoc, Opts) of <<"_design/", _Rest/binary>> = Name -> @@ -350,97 +350,6 @@ gen_name(Idx, Opts0) -> mango_util:enc_hex(Sha). -get_idx_partitioned(Opts) -> - case proplists:get_value(partitioned, Opts) of - B when is_boolean(B) -> - B; - db_default -> - % Default to the partitioned setting on - % the database. - undefined - end. - - -set_ddoc_partitioned(DDoc, Idx) -> - % We have to verify that the new index being added - % to this design document either matches the current - % ddoc's design options *or* this is a new design doc - #doc{ - id = DDocId, - revs = Revs, - body = {BodyProps} - } = DDoc, - OldDOpts = couch_util:get_value(<<"options">>, BodyProps), - OldOpt = case OldDOpts of - {OldDOptProps} when is_list(OldDOptProps) -> - couch_util:get_value(<<"partitioned">>, OldDOptProps); - _ -> - undefined - end, - % If new matches old we're done - if Idx#idx.partitioned == OldOpt -> DDoc; true -> - % If we're creating a ddoc then we can set the options - case Revs == {0, []} of - true when Idx#idx.partitioned /= undefined -> - set_ddoc_partitioned_option(DDoc, Idx#idx.partitioned); - true when Idx#idx.partitioned == undefined -> - DDoc; - false -> - ?MANGO_ERROR({partitioned_option_mismatch, DDocId}) - end - end. - - -set_ddoc_partitioned_option(DDoc, Partitioned) -> - #doc{ - body = {BodyProps} - } = DDoc, - NewProps = case couch_util:get_value(<<"options">>, BodyProps) of - {Existing} when is_list(Existing) -> - Opt = {<<"partitioned">>, Partitioned}, - New = lists:keystore(<<"partitioned">>, 1, Existing, Opt), - lists:keystore(<<"options">>, 1, BodyProps, {<<"options">>, New}); - undefined -> - New = {<<"options">>, {[{<<"partitioned">>, Partitioned}]}}, - lists:keystore(<<"options">>, 1, BodyProps, New) - end, - DDoc#doc{body = {NewProps}}. - - -get_idx_partitioned(Db, DDocProps) -> - Default = fabric_util:is_partitioned(Db), - case couch_util:get_value(<<"options">>, DDocProps) of - {DesignOpts} -> - case couch_util:get_value(<<"partitioned">>, DesignOpts) of - P when is_boolean(P) -> - P; - undefined -> - Default - end; - undefined -> - Default - end. - -is_opts_partitioned(Opts) -> - case couch_util:get_value(partition, Opts, <<>>) of - <<>> -> - false; - Partition when is_binary(Partition) -> - true - end. - - -filter_partition_indexes(Indexes, Opts) -> - PFilt = case is_opts_partitioned(Opts) of - false -> - fun(#idx{partitioned = P}) -> not P end; - true -> - fun(#idx{partitioned = P}) -> P end - end, - Filt = fun(Idx) -> type(Idx) == <<"special">> orelse PFilt(Idx) end, - lists:filter(Filt, Indexes). - - filter_opts([]) -> []; filter_opts([{user_ctx, _} | Rest]) -> @@ -451,10 +360,6 @@ filter_opts([{name, _} | Rest]) -> filter_opts(Rest); filter_opts([{type, _} | Rest]) -> filter_opts(Rest); -filter_opts([{w, _} | Rest]) -> - filter_opts(Rest); -filter_opts([{partitioned, _} | Rest]) -> - filter_opts(Rest); filter_opts([Opt | Rest]) -> [Opt | filter_opts(Rest)]. @@ -478,6 +383,17 @@ get_legacy_selector(Def) -> Selector -> Selector end. +% remove any interactive indexes that are not built. If an index is not +% interactive than we do not remove it as it will be built when queried +remove_unbuilt_indexes(Indexes) -> + lists:filter(fun(Idx) -> + case Idx#idx.interactive of + true -> Idx#idx.build_status == ?INDEX_READY; + _ -> true + end + end, Indexes). + + -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). @@ -488,8 +404,9 @@ index(SelectorName, Selector) -> <<"Selected">>,<<"json">>, {[{<<"fields">>,{[{<<"location">>,<<"asc">>}]}}, {SelectorName,{Selector}}]}, - false, - [{<<"def">>,{[{<<"fields">>,[<<"location">>]}]}}] + [{<<"def">>,{[{<<"fields">>,[<<"location">>]}]}}], + <<"ready">>, + false }. get_partial_filter_all_docs_test() -> |