diff options
author | Bessenyei Balázs Donát <bessbd@users.noreply.github.com> | 2021-05-15 09:08:18 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-15 09:08:18 +0200 |
commit | 27c1268deb9d5c91d6e403b7bfdde4e1acbd9a5e (patch) | |
tree | 6590ed54f5d1d0ec22e31e8736872c587f3ae1b6 | |
parent | ff4ca2ab5b1d696f819342c18c16aaf523f1dd30 (diff) | |
download | couchdb-27c1268deb9d5c91d6e403b7bfdde4e1acbd9a5e.tar.gz |
Add error propagation to couch_eval and couch_views_indexer (#3553)
When ApiMod:acquire_map_context returns with {error, any()}, the caller(s) fail with badmatch. This commit changes the caller hierarchy so that those {error, _} are propagated back and a failing update gets retried (up to retry_limit times).
-rw-r--r-- | src/couch_eval/src/couch_eval.erl | 8 | ||||
-rw-r--r-- | src/couch_eval/test/couch_eval_error_tests.erl | 54 | ||||
-rw-r--r-- | src/couch_views/src/couch_views_indexer.erl | 10 | ||||
-rw-r--r-- | src/couch_views/test/couch_views_indexer_test.erl | 28 |
4 files changed, 92 insertions, 8 deletions
diff --git a/src/couch_eval/src/couch_eval.erl b/src/couch_eval/src/couch_eval.erl index f87ba97b9..059507d4e 100644 --- a/src/couch_eval/src/couch_eval.erl +++ b/src/couch_eval/src/couch_eval.erl @@ -86,8 +86,12 @@ acquire_map_context(DbName, DDocId, Language, Sig, Lib, MapFuns) -> lib => Lib, map_funs => MapFuns }, - {ok, Ctx} = ApiMod:acquire_map_context(CtxOpts), - {ok, {ApiMod, Ctx}}. + case ApiMod:acquire_map_context(CtxOpts) of + {ok, Ctx} -> + {ok, {ApiMod, Ctx}}; + {error, Error} -> + {error, Error} + end. -spec release_map_context(context()) -> ok | {error, any()}. diff --git a/src/couch_eval/test/couch_eval_error_tests.erl b/src/couch_eval/test/couch_eval_error_tests.erl new file mode 100644 index 000000000..6713c8afe --- /dev/null +++ b/src/couch_eval/test/couch_eval_error_tests.erl @@ -0,0 +1,54 @@ +% 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(couch_eval_error_tests). + +-include_lib("couch/include/couch_eunit.hrl"). +-include_lib("couch/include/couch_db.hrl"). + +-define(LANG_BINARY, <<"foo_lang">>). +-define(LANG_STRING, binary_to_list(?LANG_BINARY)). + + +setup() -> + meck:new(mock_language_server, [non_strict]), + Ctx = test_util:start_couch(), + config:set("couch_eval.languages", ?LANG_STRING, + atom_to_list(mock_language_server)), + Ctx. + + +teardown(Ctx) -> + test_util:stop_couch(Ctx), + meck:unload(). + + +error_test_() -> + { + "Error tests", + { + setup, + fun setup/0, fun teardown/1, + [ + fun acquire_map_context_error_handled/0 + ] + } + }. + + +acquire_map_context_error_handled() -> + meck:expect(mock_language_server, acquire_map_context, fun(_) -> + {error, foo_error} + end), + Result = couch_eval:acquire_map_context(<<"foo">>, <<"bar">>, ?LANG_BINARY, + <<"baz">>, <<"quux">>, [<<"quuz">>]), + ?assertEqual({error, foo_error}, Result). diff --git a/src/couch_views/src/couch_views_indexer.erl b/src/couch_views/src/couch_views_indexer.erl index 7f0e2d5f2..9a1295ee7 100644 --- a/src/couch_views/src/couch_views_indexer.erl +++ b/src/couch_views/src/couch_views_indexer.erl @@ -561,15 +561,19 @@ start_query_server(#mrst{qserver = nil} = Mrst) -> lib = Lib, views = Views } = Mrst, - {ok, QServer} = couch_eval:acquire_map_context( + case couch_eval:acquire_map_context( DbName, DDocId, Language, Sig, Lib, [View#mrview.def || View <- Views] - ), - Mrst#mrst{qserver = QServer}; + ) of + {ok, QServer} -> + Mrst#mrst{qserver = QServer}; + {error, Error} -> + error(Error) + end; start_query_server(#mrst{} = Mrst) -> Mrst. diff --git a/src/couch_views/test/couch_views_indexer_test.erl b/src/couch_views/test/couch_views_indexer_test.erl index c41db3b4f..9613ba327 100644 --- a/src/couch_views/test/couch_views_indexer_test.erl +++ b/src/couch_views/test/couch_views_indexer_test.erl @@ -21,6 +21,8 @@ -define(MAP_FUN1, <<"map_fun1">>). -define(MAP_FUN2, <<"map_fun2">>). +-define(QUERY_SERVER_LANG_BINARY, <<"foo_lang">>). +-define(QUERY_SERVER_LANG_STRING, binary_to_list(?QUERY_SERVER_LANG_BINARY)). indexer_test_() -> @@ -53,7 +55,8 @@ indexer_test_() -> ?TDEF_FE(handle_db_recreated_when_running), ?TDEF_FE(handle_db_recreated_after_finished), ?TDEF_FE(handle_doc_updated_when_running), - ?TDEF_FE(index_can_recover_from_crash, 60) + ?TDEF_FE(index_can_recover_from_crash, 60), + ?TDEF_FE(handle_acquire_map_context_error) ] } } @@ -448,7 +451,8 @@ multiple_doc_update_with_existing_rows(Db) -> ?assertEqual([ row(<<"0">>, 0, 0), row(<<"1">>, 2, 2) - ], Out2). + ], Out2). + handle_db_recreated_when_running(Db) -> DbName = fabric2_db:name(Db), @@ -569,7 +573,8 @@ handle_doc_updated_when_running(Db) -> }, couch_jobs:wait(SubId, finished, infinity)), Args = #mrargs{update = false}, - {ok, Out2} = couch_views:query(Db, DDoc, ?MAP_FUN1, fun fold_fun/2, [], Args), + {ok, Out2} = couch_views:query(Db, DDoc, ?MAP_FUN1, fun fold_fun/2, [], + Args), ?assertEqual([ row(<<"0">>, 0, 0) ], Out2). @@ -610,6 +615,23 @@ index_can_recover_from_crash(Db) -> ], Out). +handle_acquire_map_context_error(_) -> + meck:new(mock_language_server, [non_strict]), + config:set("couch_eval.languages", ?QUERY_SERVER_LANG_STRING, + atom_to_list(mock_language_server)), + meck:expect(mock_language_server, acquire_map_context, fun(_) -> + {error, foo_error} + end), + ?assertError(foo_error, couch_views_indexer:start_query_server(#mrst{ + db_name = "DbName", + idx_name = "DDocId", + language = ?QUERY_SERVER_LANG_BINARY, + sig = "Sig", + lib = "Lib", + views = [] + })). + + row(Id, Key, Value) -> {row, [ {id, Id}, |