summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBessenyei Balázs Donát <bessbd@users.noreply.github.com>2021-05-15 09:08:18 +0200
committerGitHub <noreply@github.com>2021-05-15 09:08:18 +0200
commit27c1268deb9d5c91d6e403b7bfdde4e1acbd9a5e (patch)
tree6590ed54f5d1d0ec22e31e8736872c587f3ae1b6
parentff4ca2ab5b1d696f819342c18c16aaf523f1dd30 (diff)
downloadcouchdb-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.erl8
-rw-r--r--src/couch_eval/test/couch_eval_error_tests.erl54
-rw-r--r--src/couch_views/src/couch_views_indexer.erl10
-rw-r--r--src/couch_views/test/couch_views_indexer_test.erl28
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},