summaryrefslogtreecommitdiff
path: root/src/couch_mrview
diff options
context:
space:
mode:
authorNick Vatamaniuc <vatamane@gmail.com>2021-11-20 01:00:08 -0500
committerNick Vatamaniuc <nickva@users.noreply.github.com>2021-11-22 17:31:31 -0500
commitb78ccf18cb4ed6e183ed0bf4e5cbe40d7a7dc493 (patch)
tree82158f0b6c7e97e6955bf0c558aac6eb0329b410 /src/couch_mrview
parent6e87e43fae23647b281ede250ad9f1a68a8f1cde (diff)
downloadcouchdb-b78ccf18cb4ed6e183ed0bf4e5cbe40d7a7dc493.tar.gz
Apply erlfmt formatting to source tree
These exceptions from main were ported over to 3.x ``` --- a/src/chttpd/src/chttpd.erl +++ b/src/chttpd/src/chttpd.erl @@ -491,6 +491,7 @@ extract_cookie(#httpd{mochi_req = MochiReq}) -> end. %%% end hack +%% erlfmt-ignore set_auth_handlers() -> AuthenticationDefault = "{chttpd_auth, cookie_authentication_handler}, ``` ``` --- a/src/couch/src/couch_debug.erl +++ b/src/couch/src/couch_debug.erl @@ -49,6 +49,7 @@ help() -> ]. -spec help(Function :: atom()) -> ok. +%% erlfmt-ignore help(opened_files) -> ```
Diffstat (limited to 'src/couch_mrview')
-rw-r--r--src/couch_mrview/src/couch_mrview.erl609
-rw-r--r--src/couch_mrview/src/couch_mrview_cleanup.erl63
-rw-r--r--src/couch_mrview/src/couch_mrview_compactor.erl173
-rw-r--r--src/couch_mrview/src/couch_mrview_http.erl517
-rw-r--r--src/couch_mrview/src/couch_mrview_index.erl174
-rw-r--r--src/couch_mrview/src/couch_mrview_show.erl357
-rw-r--r--src/couch_mrview/src/couch_mrview_test_util.erl141
-rw-r--r--src/couch_mrview/src/couch_mrview_update_notifier.erl4
-rw-r--r--src/couch_mrview/src/couch_mrview_updater.erl264
-rw-r--r--src/couch_mrview/src/couch_mrview_util.erl778
-rw-r--r--src/couch_mrview/test/eunit/couch_mrview_all_docs_tests.erl109
-rw-r--r--src/couch_mrview/test/eunit/couch_mrview_collation_tests.erl121
-rw-r--r--src/couch_mrview/test/eunit/couch_mrview_compact_tests.erl57
-rw-r--r--src/couch_mrview/test/eunit/couch_mrview_ddoc_updated_tests.erl84
-rw-r--r--src/couch_mrview/test/eunit/couch_mrview_ddoc_validation_tests.erl655
-rw-r--r--src/couch_mrview/test/eunit/couch_mrview_design_docs_tests.erl106
-rw-r--r--src/couch_mrview/test/eunit/couch_mrview_http_tests.erl23
-rw-r--r--src/couch_mrview/test/eunit/couch_mrview_index_info_tests.erl20
-rw-r--r--src/couch_mrview/test/eunit/couch_mrview_local_docs_tests.erl112
-rw-r--r--src/couch_mrview/test/eunit/couch_mrview_map_views_tests.erl114
-rw-r--r--src/couch_mrview/test/eunit/couch_mrview_purge_docs_fabric_tests.erl352
-rw-r--r--src/couch_mrview/test/eunit/couch_mrview_purge_docs_tests.erl468
-rw-r--r--src/couch_mrview/test/eunit/couch_mrview_red_views_tests.erl66
-rw-r--r--src/couch_mrview/test/eunit/couch_mrview_util_tests.erl28
24 files changed, 2944 insertions, 2451 deletions
diff --git a/src/couch_mrview/src/couch_mrview.erl b/src/couch_mrview/src/couch_mrview.erl
index 1cdc91809..798b939c7 100644
--- a/src/couch_mrview/src/couch_mrview.erl
+++ b/src/couch_mrview/src/couch_mrview.erl
@@ -27,7 +27,7 @@
-record(mracc, {
db,
- meta_sent=false,
+ meta_sent = false,
total_rows,
offset,
limit,
@@ -36,82 +36,100 @@
doc_info,
callback,
user_acc,
- last_go=ok,
+ last_go = ok,
reduce_fun,
finalizer,
update_seq,
args
}).
-
-
validate_ddoc_fields(DDoc) ->
MapFuncType = map_function_type(DDoc),
- lists:foreach(fun(Path) ->
- validate_ddoc_fields(DDoc, Path)
- end, [
- [{<<"filters">>, object}, {any, [object, string]}],
- [{<<"language">>, string}],
- [{<<"lists">>, object}, {any, [object, string]}],
- [{<<"options">>, object}],
- [{<<"options">>, object}, {<<"include_design">>, boolean}],
- [{<<"options">>, object}, {<<"local_seq">>, boolean}],
- [{<<"options">>, object}, {<<"partitioned">>, boolean}],
- [{<<"rewrites">>, [string, array]}],
- [{<<"shows">>, object}, {any, [object, string]}],
- [{<<"updates">>, object}, {any, [object, string]}],
- [{<<"validate_doc_update">>, string}],
- [{<<"views">>, object}, {<<"lib">>, object}],
- [{<<"views">>, object}, {any, object}, {<<"map">>, MapFuncType}],
- [{<<"views">>, object}, {any, object}, {<<"reduce">>, string}]
- ]),
+ lists:foreach(
+ fun(Path) ->
+ validate_ddoc_fields(DDoc, Path)
+ end,
+ [
+ [{<<"filters">>, object}, {any, [object, string]}],
+ [{<<"language">>, string}],
+ [{<<"lists">>, object}, {any, [object, string]}],
+ [{<<"options">>, object}],
+ [{<<"options">>, object}, {<<"include_design">>, boolean}],
+ [{<<"options">>, object}, {<<"local_seq">>, boolean}],
+ [{<<"options">>, object}, {<<"partitioned">>, boolean}],
+ [{<<"rewrites">>, [string, array]}],
+ [{<<"shows">>, object}, {any, [object, string]}],
+ [{<<"updates">>, object}, {any, [object, string]}],
+ [{<<"validate_doc_update">>, string}],
+ [{<<"views">>, object}, {<<"lib">>, object}],
+ [{<<"views">>, object}, {any, object}, {<<"map">>, MapFuncType}],
+ [{<<"views">>, object}, {any, object}, {<<"reduce">>, string}]
+ ]
+ ),
require_map_function_for_views(DDoc),
ok.
require_map_function_for_views({Props}) ->
case couch_util:get_value(<<"views">>, Props) of
- undefined -> ok;
+ undefined ->
+ ok;
{Views} ->
- lists:foreach(fun
- ({<<"lib">>, _}) -> ok;
- ({Key, {Value}}) ->
- case couch_util:get_value(<<"map">>, Value) of
- undefined -> throw({invalid_design_doc,
- <<"View `", Key/binary, "` must contain map function">>});
- _ -> ok
- end
- end, Views),
+ lists:foreach(
+ fun
+ ({<<"lib">>, _}) ->
+ ok;
+ ({Key, {Value}}) ->
+ case couch_util:get_value(<<"map">>, Value) of
+ undefined ->
+ throw(
+ {invalid_design_doc,
+ <<"View `", Key/binary, "` must contain map function">>}
+ );
+ _ ->
+ ok
+ end
+ end,
+ Views
+ ),
ok
end.
validate_ddoc_fields(DDoc, Path) ->
case validate_ddoc_fields(DDoc, Path, []) of
- ok -> ok;
+ ok ->
+ ok;
{error, {FailedPath0, Type0}} ->
FailedPath = iolist_to_binary(join(FailedPath0, <<".">>)),
Type = format_type(Type0),
- throw({invalid_design_doc,
- <<"`", FailedPath/binary, "` field must have ",
- Type/binary, " type">>})
+ throw(
+ {invalid_design_doc,
+ <<"`", FailedPath/binary, "` field must have ", Type/binary, " type">>}
+ )
end.
validate_ddoc_fields(undefined, _, _) ->
ok;
validate_ddoc_fields(_, [], _) ->
ok;
-validate_ddoc_fields({KVS}=Props, [{any, Type} | Rest], Acc) ->
- lists:foldl(fun
- ({Key, _}, ok) ->
- validate_ddoc_fields(Props, [{Key, Type} | Rest], Acc);
- ({_, _}, {error, _}=Error) ->
- Error
- end, ok, KVS);
-validate_ddoc_fields({KVS}=Props, [{Key, Type} | Rest], Acc) ->
+validate_ddoc_fields({KVS} = Props, [{any, Type} | Rest], Acc) ->
+ lists:foldl(
+ fun
+ ({Key, _}, ok) ->
+ validate_ddoc_fields(Props, [{Key, Type} | Rest], Acc);
+ ({_, _}, {error, _} = Error) ->
+ Error
+ end,
+ ok,
+ KVS
+ );
+validate_ddoc_fields({KVS} = Props, [{Key, Type} | Rest], Acc) ->
case validate_ddoc_field(Props, {Key, Type}) of
ok ->
- validate_ddoc_fields(couch_util:get_value(Key, KVS),
- Rest,
- [Key | Acc]);
+ validate_ddoc_fields(
+ couch_util:get_value(Key, KVS),
+ Rest,
+ [Key | Acc]
+ );
error ->
{error, {[Key | Acc], Type}};
{error, Key1} ->
@@ -123,10 +141,14 @@ validate_ddoc_field(undefined, Type) when is_atom(Type) ->
validate_ddoc_field(_, any) ->
ok;
validate_ddoc_field(Value, Types) when is_list(Types) ->
- lists:foldl(fun
- (_, ok) -> ok;
- (Type, _) -> validate_ddoc_field(Value, Type)
- end, error, Types);
+ lists:foldl(
+ fun
+ (_, ok) -> ok;
+ (Type, _) -> validate_ddoc_field(Value, Type)
+ end,
+ error,
+ Types
+ );
validate_ddoc_field(Value, string) when is_binary(Value) ->
ok;
validate_ddoc_field(Value, array) when is_list(Value) ->
@@ -165,36 +187,38 @@ format_type(Types) when is_list(Types) ->
join(L, Sep) ->
join(L, Sep, []).
-join([H|[]], _, Acc) ->
+join([H | []], _, Acc) ->
[H | Acc];
-join([H|T], Sep, Acc) ->
+join([H | T], Sep, Acc) ->
join(T, Sep, [Sep, H | Acc]).
-
-validate(Db, DDoc) ->
+validate(Db, DDoc) ->
ok = validate_ddoc_fields(DDoc#doc.body),
GetName = fun
(#mrview{map_names = [Name | _]}) -> Name;
(#mrview{reduce_funs = [{Name, _} | _]}) -> Name;
(_) -> null
end,
- ValidateView = fun(Proc, #mrview{def=MapSrc, reduce_funs=Reds}=View) ->
+ ValidateView = fun(Proc, #mrview{def = MapSrc, reduce_funs = Reds} = View) ->
couch_query_servers:try_compile(Proc, map, GetName(View), MapSrc),
- lists:foreach(fun
- ({_RedName, <<"_sum", _/binary>>}) ->
- ok;
- ({_RedName, <<"_count", _/binary>>}) ->
- ok;
- ({_RedName, <<"_stats", _/binary>>}) ->
- ok;
- ({_RedName, <<"_approx_count_distinct", _/binary>>}) ->
- ok;
- ({_RedName, <<"_", _/binary>> = Bad}) ->
- Msg = ["`", Bad, "` is not a supported reduce function."],
- throw({invalid_design_doc, Msg});
- ({RedName, RedSrc}) ->
- couch_query_servers:try_compile(Proc, reduce, RedName, RedSrc)
- end, Reds)
+ lists:foreach(
+ fun
+ ({_RedName, <<"_sum", _/binary>>}) ->
+ ok;
+ ({_RedName, <<"_count", _/binary>>}) ->
+ ok;
+ ({_RedName, <<"_stats", _/binary>>}) ->
+ ok;
+ ({_RedName, <<"_approx_count_distinct", _/binary>>}) ->
+ ok;
+ ({_RedName, <<"_", _/binary>> = Bad}) ->
+ Msg = ["`", Bad, "` is not a supported reduce function."],
+ throw({invalid_design_doc, Msg});
+ ({RedName, RedSrc}) ->
+ couch_query_servers:try_compile(Proc, reduce, RedName, RedSrc)
+ end,
+ Reds
+ )
end,
{ok, #mrst{
language = Lang,
@@ -204,9 +228,12 @@ validate(Db, DDoc) ->
case {couch_db:is_partitioned(Db), Partitioned} of
{false, true} ->
- throw({invalid_design_doc,
- <<"partitioned option cannot be true in a "
- "non-partitioned database.">>});
+ throw(
+ {invalid_design_doc, <<
+ "partitioned option cannot be true in a "
+ "non-partitioned database."
+ >>}
+ );
{_, _} ->
ok
end,
@@ -220,16 +247,15 @@ validate(Db, DDoc) ->
after
couch_query_servers:ret_os_process(Proc)
end
- catch {unknown_query_language, _Lang} ->
- %% Allow users to save ddocs written in unknown languages
- ok
+ catch
+ {unknown_query_language, _Lang} ->
+ %% Allow users to save ddocs written in unknown languages
+ ok
end.
-
query_all_docs(Db, Args) ->
query_all_docs(Db, Args, fun default_cb/2, []).
-
query_all_docs(Db, Args, Callback, Acc) when is_list(Args) ->
query_all_docs(Db, to_mrargs(Args), Callback, Acc);
query_all_docs(Db, Args0, Callback, Acc) ->
@@ -237,44 +263,41 @@ query_all_docs(Db, Args0, Callback, Acc) ->
{ok, Info} = couch_db:get_db_info(WDb),
couch_index_util:hexsig(couch_hash:md5_hash(term_to_binary(Info)))
end),
- Args1 = Args0#mrargs{view_type=map},
+ Args1 = Args0#mrargs{view_type = map},
Args2 = couch_mrview_util:validate_all_docs_args(Db, Args1),
- {ok, Acc1} = case Args2#mrargs.preflight_fun of
- PFFun when is_function(PFFun, 2) -> PFFun(Sig, Acc);
- _ -> {ok, Acc}
- end,
+ {ok, Acc1} =
+ case Args2#mrargs.preflight_fun of
+ PFFun when is_function(PFFun, 2) -> PFFun(Sig, Acc);
+ _ -> {ok, Acc}
+ end,
all_docs_fold(Db, Args2, Callback, Acc1).
-
query_view(Db, DDoc, VName) ->
query_view(Db, DDoc, VName, #mrargs{}).
-
query_view(Db, DDoc, VName, Args) when is_list(Args) ->
query_view(Db, DDoc, VName, to_mrargs(Args), fun default_cb/2, []);
query_view(Db, DDoc, VName, Args) ->
query_view(Db, DDoc, VName, Args, fun default_cb/2, []).
-
query_view(Db, DDoc, VName, Args, Callback, Acc) when is_list(Args) ->
query_view(Db, DDoc, VName, to_mrargs(Args), Callback, Acc);
query_view(Db, DDoc, VName, Args0, Callback, Acc0) ->
case couch_mrview_util:get_view(Db, DDoc, VName, Args0) of
{ok, VInfo, Sig, Args} ->
- {ok, Acc1} = case Args#mrargs.preflight_fun of
- PFFun when is_function(PFFun, 2) -> PFFun(Sig, Acc0);
- _ -> {ok, Acc0}
- end,
+ {ok, Acc1} =
+ case Args#mrargs.preflight_fun of
+ PFFun when is_function(PFFun, 2) -> PFFun(Sig, Acc0);
+ _ -> {ok, Acc0}
+ end,
query_view(Db, VInfo, Args, Callback, Acc1);
ddoc_updated ->
Callback(ok, ddoc_updated)
end.
-
get_view_index_pid(Db, DDoc, ViewName, Args0) ->
couch_mrview_util:get_view_index_pid(Db, DDoc, ViewName, Args0).
-
query_view(Db, {Type, View, Ref}, Args, Callback, Acc) ->
try
case Type of
@@ -285,12 +308,10 @@ query_view(Db, {Type, View, Ref}, Args, Callback, Acc) ->
erlang:demonitor(Ref, [flush])
end.
-
get_info(Db, DDoc) ->
{ok, Pid} = couch_index_server:get_index(couch_mrview_index, Db, DDoc),
couch_index:get_info(Pid).
-
trigger_update(Db, DDoc) ->
trigger_update(Db, DDoc, couch_db:get_update_seq(Db)).
@@ -300,22 +321,27 @@ trigger_update(Db, DDoc, UpdateSeq) ->
%% get informations on a view
get_view_info(Db, DDoc, VName) ->
- {ok, {_, View, _}, _, _Args} = couch_mrview_util:get_view(Db, DDoc, VName,
- #mrargs{}),
+ {ok, {_, View, _}, _, _Args} = couch_mrview_util:get_view(
+ Db,
+ DDoc,
+ VName,
+ #mrargs{}
+ ),
%% get the total number of rows
- {ok, TotalRows} = couch_mrview_util:get_row_count(View),
-
- {ok, [{update_seq, View#mrview.update_seq},
- {purge_seq, View#mrview.purge_seq},
- {total_rows, TotalRows}]}.
+ {ok, TotalRows} = couch_mrview_util:get_row_count(View),
+ {ok, [
+ {update_seq, View#mrview.update_seq},
+ {purge_seq, View#mrview.purge_seq},
+ {total_rows, TotalRows}
+ ]}.
%% @doc refresh a view index
-refresh(DbName, DDoc) when is_binary(DbName)->
+refresh(DbName, DDoc) when is_binary(DbName) ->
UpdateSeq = couch_util:with_db(DbName, fun(WDb) ->
- couch_db:get_update_seq(WDb)
- end),
+ couch_db:get_update_seq(WDb)
+ end),
case couch_index_server:get_index(couch_mrview_index, DbName, DDoc) of
{ok, Pid} ->
@@ -326,48 +352,43 @@ refresh(DbName, DDoc) when is_binary(DbName)->
Error ->
{error, Error}
end;
-
refresh(Db, DDoc) ->
refresh(couch_db:name(Db), DDoc).
compact(Db, DDoc) ->
compact(Db, DDoc, []).
-
compact(Db, DDoc, Opts) ->
{ok, Pid} = couch_index_server:get_index(couch_mrview_index, Db, DDoc),
couch_index:compact(Pid, Opts).
-
cancel_compaction(Db, DDoc) ->
{ok, IPid} = couch_index_server:get_index(couch_mrview_index, Db, DDoc),
{ok, CPid} = couch_index:get_compactor_pid(IPid),
ok = couch_index_compactor:cancel(CPid),
% Cleanup the compaction file if it exists
- {ok, #mrst{sig=Sig, db_name=DbName}} = couch_index:get_state(IPid, 0),
+ {ok, #mrst{sig = Sig, db_name = DbName}} = couch_index:get_state(IPid, 0),
couch_mrview_util:delete_compaction_file(DbName, Sig),
ok.
-
cleanup(Db) ->
couch_mrview_cleanup:run(Db).
-
-all_docs_fold(Db, #mrargs{keys=undefined}=Args, Callback, UAcc) ->
+all_docs_fold(Db, #mrargs{keys = undefined} = Args, Callback, UAcc) ->
ReduceFun = get_reduce_fun(Args),
Total = get_total_rows(Db, Args),
UpdateSeq = get_update_seq(Db, Args),
Acc = #mracc{
- db=Db,
- total_rows=Total,
- limit=Args#mrargs.limit,
- skip=Args#mrargs.skip,
- callback=Callback,
- user_acc=UAcc,
- reduce_fun=ReduceFun,
- update_seq=UpdateSeq,
- args=Args
+ db = Db,
+ total_rows = Total,
+ limit = Args#mrargs.limit,
+ skip = Args#mrargs.skip,
+ callback = Callback,
+ user_acc = UAcc,
+ reduce_fun = ReduceFun,
+ update_seq = UpdateSeq,
+ args = Args
},
[Opts1] = couch_mrview_util:all_docs_key_opts(Args),
% TODO: This is a terrible hack for now. We'll probably have
@@ -375,243 +396,262 @@ all_docs_fold(Db, #mrargs{keys=undefined}=Args, Callback, UAcc) ->
% a btree. For now non-btree's will just have to pass 0 or
% some fake reductions to get an offset.
Opts2 = [include_reductions | Opts1],
- FunName = case couch_util:get_value(namespace, Args#mrargs.extra) of
- <<"_design">> -> fold_design_docs;
- <<"_local">> -> fold_local_docs;
- _ -> fold_docs
- end,
+ FunName =
+ case couch_util:get_value(namespace, Args#mrargs.extra) of
+ <<"_design">> -> fold_design_docs;
+ <<"_local">> -> fold_local_docs;
+ _ -> fold_docs
+ end,
{ok, Offset, FinalAcc} = couch_db:FunName(Db, fun map_fold/3, Acc, Opts2),
finish_fold(FinalAcc, [{total, Total}, {offset, Offset}]);
-all_docs_fold(Db, #mrargs{direction=Dir, keys=Keys0}=Args, Callback, UAcc) ->
+all_docs_fold(Db, #mrargs{direction = Dir, keys = Keys0} = Args, Callback, UAcc) ->
ReduceFun = get_reduce_fun(Args),
Total = get_total_rows(Db, Args),
UpdateSeq = get_update_seq(Db, Args),
Acc = #mracc{
- db=Db,
- total_rows=Total,
- limit=Args#mrargs.limit,
- skip=Args#mrargs.skip,
- callback=Callback,
- user_acc=UAcc,
- reduce_fun=ReduceFun,
- update_seq=UpdateSeq,
- args=Args
+ db = Db,
+ total_rows = Total,
+ limit = Args#mrargs.limit,
+ skip = Args#mrargs.skip,
+ callback = Callback,
+ user_acc = UAcc,
+ reduce_fun = ReduceFun,
+ update_seq = UpdateSeq,
+ args = Args
},
% Backwards compatibility hack. The old _all_docs iterates keys
% in reverse if descending=true was passed. Here we'll just
% reverse the list instead.
- Keys = if Dir =:= fwd -> Keys0; true -> lists:reverse(Keys0) end,
+ Keys =
+ if
+ Dir =:= fwd -> Keys0;
+ true -> lists:reverse(Keys0)
+ end,
FoldFun = fun(Key, Acc0) ->
DocInfo = (catch couch_db:get_doc_info(Db, Key)),
- {Doc, Acc1} = case DocInfo of
- {ok, #doc_info{id=Id, revs=[RevInfo | _RestRevs]}=DI} ->
- Rev = couch_doc:rev_to_str(RevInfo#rev_info.rev),
- Props = [{rev, Rev}] ++ case RevInfo#rev_info.deleted of
- true -> [{deleted, true}];
- false -> []
- end,
- {{{Id, Id}, {Props}}, Acc0#mracc{doc_info=DI}};
- not_found ->
- {{{Key, error}, not_found}, Acc0}
- end,
+ {Doc, Acc1} =
+ case DocInfo of
+ {ok, #doc_info{id = Id, revs = [RevInfo | _RestRevs]} = DI} ->
+ Rev = couch_doc:rev_to_str(RevInfo#rev_info.rev),
+ Props =
+ [{rev, Rev}] ++
+ case RevInfo#rev_info.deleted of
+ true -> [{deleted, true}];
+ false -> []
+ end,
+ {{{Id, Id}, {Props}}, Acc0#mracc{doc_info = DI}};
+ not_found ->
+ {{{Key, error}, not_found}, Acc0}
+ end,
{_, Acc2} = map_fold(Doc, {[], [{0, 0, 0}]}, Acc1),
Acc2
end,
FinalAcc = lists:foldl(FoldFun, Acc, Keys),
finish_fold(FinalAcc, [{total, Total}]).
-
map_fold(Db, View, Args, Callback, UAcc) ->
{ok, Total} = couch_mrview_util:get_row_count(View),
Acc = #mracc{
- db=Db,
- total_rows=Total,
- limit=Args#mrargs.limit,
- skip=Args#mrargs.skip,
- callback=Callback,
- user_acc=UAcc,
- reduce_fun=fun couch_mrview_util:reduce_to_count/1,
- update_seq=View#mrview.update_seq,
- args=Args
+ db = Db,
+ total_rows = Total,
+ limit = Args#mrargs.limit,
+ skip = Args#mrargs.skip,
+ callback = Callback,
+ user_acc = UAcc,
+ reduce_fun = fun couch_mrview_util:reduce_to_count/1,
+ update_seq = View#mrview.update_seq,
+ args = Args
},
OptList = couch_mrview_util:key_opts(Args),
- {Reds, Acc2} = lists:foldl(fun(Opts, {_, Acc0}) ->
- {ok, R, A} = couch_mrview_util:fold(View, fun map_fold/3, Acc0, Opts),
- {R, A}
- end, {nil, Acc}, OptList),
+ {Reds, Acc2} = lists:foldl(
+ fun(Opts, {_, Acc0}) ->
+ {ok, R, A} = couch_mrview_util:fold(View, fun map_fold/3, Acc0, Opts),
+ {R, A}
+ end,
+ {nil, Acc},
+ OptList
+ ),
Offset = couch_mrview_util:reduce_to_count(Reds),
finish_fold(Acc2, [{total, Total}, {offset, Offset}]).
-
map_fold(#full_doc_info{} = FullDocInfo, OffsetReds, Acc) ->
% matches for _all_docs and translates #full_doc_info{} -> KV pair
case couch_doc:to_doc_info(FullDocInfo) of
- #doc_info{id=Id, revs=[#rev_info{deleted=false, rev=Rev}|_]} = DI ->
+ #doc_info{id = Id, revs = [#rev_info{deleted = false, rev = Rev} | _]} = DI ->
Value = {[{rev, couch_doc:rev_to_str(Rev)}]},
- map_fold({{Id, Id}, Value}, OffsetReds, Acc#mracc{doc_info=DI});
- #doc_info{revs=[#rev_info{deleted=true}|_]} ->
+ map_fold({{Id, Id}, Value}, OffsetReds, Acc#mracc{doc_info = DI});
+ #doc_info{revs = [#rev_info{deleted = true} | _]} ->
{ok, Acc}
end;
-map_fold(_KV, _Offset, #mracc{skip=N}=Acc) when N > 0 ->
- {ok, Acc#mracc{skip=N-1, last_go=ok}};
-map_fold(KV, OffsetReds, #mracc{offset=undefined}=Acc) ->
+map_fold(_KV, _Offset, #mracc{skip = N} = Acc) when N > 0 ->
+ {ok, Acc#mracc{skip = N - 1, last_go = ok}};
+map_fold(KV, OffsetReds, #mracc{offset = undefined} = Acc) ->
#mracc{
- total_rows=Total,
- callback=Callback,
- user_acc=UAcc0,
- reduce_fun=Reduce,
- update_seq=UpdateSeq,
- args=Args
+ total_rows = Total,
+ callback = Callback,
+ user_acc = UAcc0,
+ reduce_fun = Reduce,
+ update_seq = UpdateSeq,
+ args = Args
} = Acc,
Offset = Reduce(OffsetReds),
Meta = make_meta(Args, UpdateSeq, [{total, Total}, {offset, Offset}]),
{Go, UAcc1} = Callback(Meta, UAcc0),
- Acc1 = Acc#mracc{meta_sent=true, offset=Offset, user_acc=UAcc1, last_go=Go},
+ Acc1 = Acc#mracc{meta_sent = true, offset = Offset, user_acc = UAcc1, last_go = Go},
case Go of
ok -> map_fold(KV, OffsetReds, Acc1);
stop -> {stop, Acc1}
end;
-map_fold(_KV, _Offset, #mracc{limit=0}=Acc) ->
+map_fold(_KV, _Offset, #mracc{limit = 0} = Acc) ->
{stop, Acc};
map_fold({{Key, Id}, Val}, _Offset, Acc) ->
#mracc{
- db=Db,
- limit=Limit,
- doc_info=DI,
- callback=Callback,
- user_acc=UAcc0,
- args=Args
+ db = Db,
+ limit = Limit,
+ doc_info = DI,
+ callback = Callback,
+ user_acc = UAcc0,
+ args = Args
} = Acc,
- Doc = case DI of
- #doc_info{} -> couch_mrview_util:maybe_load_doc(Db, DI, Args);
- _ -> couch_mrview_util:maybe_load_doc(Db, Id, Val, Args)
- end,
+ Doc =
+ case DI of
+ #doc_info{} -> couch_mrview_util:maybe_load_doc(Db, DI, Args);
+ _ -> couch_mrview_util:maybe_load_doc(Db, Id, Val, Args)
+ end,
Row = [{id, Id}, {key, Key}, {value, Val}] ++ Doc,
{Go, UAcc1} = Callback({row, Row}, UAcc0),
{Go, Acc#mracc{
- limit=Limit-1,
- doc_info=undefined,
- user_acc=UAcc1,
- last_go=Go
+ limit = Limit - 1,
+ doc_info = undefined,
+ user_acc = UAcc1,
+ last_go = Go
}};
map_fold(#doc{id = <<"_local/", _/binary>>} = Doc, _Offset, #mracc{} = Acc) ->
#mracc{
- limit=Limit,
- callback=Callback,
- user_acc=UAcc0,
- args=Args
+ limit = Limit,
+ callback = Callback,
+ user_acc = UAcc0,
+ args = Args
} = Acc,
#doc{
id = DocId,
revs = {Pos, [RevId | _]}
} = Doc,
Rev = {Pos, RevId},
- Row = [
- {id, DocId},
- {key, DocId},
- {value, {[{rev, couch_doc:rev_to_str(Rev)}]}}
- ] ++ if not Args#mrargs.include_docs -> []; true ->
- [{doc, couch_doc:to_json_obj(Doc, Args#mrargs.doc_options)}]
- end,
+ Row =
+ [
+ {id, DocId},
+ {key, DocId},
+ {value, {[{rev, couch_doc:rev_to_str(Rev)}]}}
+ ] ++
+ if
+ not Args#mrargs.include_docs -> [];
+ true -> [{doc, couch_doc:to_json_obj(Doc, Args#mrargs.doc_options)}]
+ end,
{Go, UAcc1} = Callback({row, Row}, UAcc0),
{Go, Acc#mracc{
- limit=Limit-1,
- reduce_fun=undefined,
- doc_info=undefined,
- user_acc=UAcc1,
- last_go=Go
+ limit = Limit - 1,
+ reduce_fun = undefined,
+ doc_info = undefined,
+ user_acc = UAcc1,
+ last_go = Go
}}.
-red_fold(Db, {NthRed, _Lang, View}=RedView, Args, Callback, UAcc) ->
- Finalizer = case couch_util:get_value(finalizer, Args#mrargs.extra) of
- undefined ->
- {_, FunSrc} = lists:nth(NthRed, View#mrview.reduce_funs),
- FunSrc;
- CustomFun->
- CustomFun
- end,
+red_fold(Db, {NthRed, _Lang, View} = RedView, Args, Callback, UAcc) ->
+ Finalizer =
+ case couch_util:get_value(finalizer, Args#mrargs.extra) of
+ undefined ->
+ {_, FunSrc} = lists:nth(NthRed, View#mrview.reduce_funs),
+ FunSrc;
+ CustomFun ->
+ CustomFun
+ end,
Acc = #mracc{
- db=Db,
- total_rows=null,
- limit=Args#mrargs.limit,
- skip=Args#mrargs.skip,
- group_level=Args#mrargs.group_level,
- callback=Callback,
- user_acc=UAcc,
- update_seq=View#mrview.update_seq,
- finalizer=Finalizer,
- args=Args
+ db = Db,
+ total_rows = null,
+ limit = Args#mrargs.limit,
+ skip = Args#mrargs.skip,
+ group_level = Args#mrargs.group_level,
+ callback = Callback,
+ user_acc = UAcc,
+ update_seq = View#mrview.update_seq,
+ finalizer = Finalizer,
+ args = Args
},
Grouping = {key_group_level, Args#mrargs.group_level},
OptList = couch_mrview_util:key_opts(Args, [Grouping]),
- Acc2 = lists:foldl(fun(Opts, Acc0) ->
- {ok, Acc1} =
- couch_mrview_util:fold_reduce(RedView, fun red_fold/3, Acc0, Opts),
- Acc1
- end, Acc, OptList),
+ Acc2 = lists:foldl(
+ fun(Opts, Acc0) ->
+ {ok, Acc1} =
+ couch_mrview_util:fold_reduce(RedView, fun red_fold/3, Acc0, Opts),
+ Acc1
+ end,
+ Acc,
+ OptList
+ ),
finish_fold(Acc2, []).
red_fold({p, _Partition, Key}, Red, Acc) ->
red_fold(Key, Red, Acc);
-red_fold(_Key, _Red, #mracc{skip=N}=Acc) when N > 0 ->
- {ok, Acc#mracc{skip=N-1, last_go=ok}};
-red_fold(Key, Red, #mracc{meta_sent=false}=Acc) ->
+red_fold(_Key, _Red, #mracc{skip = N} = Acc) when N > 0 ->
+ {ok, Acc#mracc{skip = N - 1, last_go = ok}};
+red_fold(Key, Red, #mracc{meta_sent = false} = Acc) ->
#mracc{
- args=Args,
- callback=Callback,
- user_acc=UAcc0,
- update_seq=UpdateSeq
+ args = Args,
+ callback = Callback,
+ user_acc = UAcc0,
+ update_seq = UpdateSeq
} = Acc,
Meta = make_meta(Args, UpdateSeq, []),
{Go, UAcc1} = Callback(Meta, UAcc0),
- Acc1 = Acc#mracc{user_acc=UAcc1, meta_sent=true, last_go=Go},
+ Acc1 = Acc#mracc{user_acc = UAcc1, meta_sent = true, last_go = Go},
case Go of
ok -> red_fold(Key, Red, Acc1);
_ -> {Go, Acc1}
end;
-red_fold(_Key, _Red, #mracc{limit=0} = Acc) ->
+red_fold(_Key, _Red, #mracc{limit = 0} = Acc) ->
{stop, Acc};
-red_fold(_Key, Red, #mracc{group_level=0} = Acc) ->
+red_fold(_Key, Red, #mracc{group_level = 0} = Acc) ->
#mracc{
- finalizer=Finalizer,
- limit=Limit,
- callback=Callback,
- user_acc=UAcc0
+ finalizer = Finalizer,
+ limit = Limit,
+ callback = Callback,
+ user_acc = UAcc0
} = Acc,
Row = [{key, null}, {value, maybe_finalize(Red, Finalizer)}],
{Go, UAcc1} = Callback({row, Row}, UAcc0),
- {Go, Acc#mracc{user_acc=UAcc1, limit=Limit-1, last_go=Go}};
-red_fold(Key, Red, #mracc{group_level=exact} = Acc) ->
+ {Go, Acc#mracc{user_acc = UAcc1, limit = Limit - 1, last_go = Go}};
+red_fold(Key, Red, #mracc{group_level = exact} = Acc) ->
#mracc{
- finalizer=Finalizer,
- limit=Limit,
- callback=Callback,
- user_acc=UAcc0
+ finalizer = Finalizer,
+ limit = Limit,
+ callback = Callback,
+ user_acc = UAcc0
} = Acc,
Row = [{key, Key}, {value, maybe_finalize(Red, Finalizer)}],
{Go, UAcc1} = Callback({row, Row}, UAcc0),
- {Go, Acc#mracc{user_acc=UAcc1, limit=Limit-1, last_go=Go}};
-red_fold(K, Red, #mracc{group_level=I} = Acc) when I > 0, is_list(K) ->
+ {Go, Acc#mracc{user_acc = UAcc1, limit = Limit - 1, last_go = Go}};
+red_fold(K, Red, #mracc{group_level = I} = Acc) when I > 0, is_list(K) ->
#mracc{
- finalizer=Finalizer,
- limit=Limit,
- callback=Callback,
- user_acc=UAcc0
+ finalizer = Finalizer,
+ limit = Limit,
+ callback = Callback,
+ user_acc = UAcc0
} = Acc,
Row = [{key, lists:sublist(K, I)}, {value, maybe_finalize(Red, Finalizer)}],
{Go, UAcc1} = Callback({row, Row}, UAcc0),
- {Go, Acc#mracc{user_acc=UAcc1, limit=Limit-1, last_go=Go}};
-red_fold(K, Red, #mracc{group_level=I} = Acc) when I > 0 ->
+ {Go, Acc#mracc{user_acc = UAcc1, limit = Limit - 1, last_go = Go}};
+red_fold(K, Red, #mracc{group_level = I} = Acc) when I > 0 ->
#mracc{
- finalizer=Finalizer,
- limit=Limit,
- callback=Callback,
- user_acc=UAcc0
+ finalizer = Finalizer,
+ limit = Limit,
+ callback = Callback,
+ user_acc = UAcc0
} = Acc,
Row = [{key, K}, {value, maybe_finalize(Red, Finalizer)}],
{Go, UAcc1} = Callback({row, Row}, UAcc0),
- {Go, Acc#mracc{user_acc=UAcc1, limit=Limit-1, last_go=Go}}.
+ {Go, Acc#mracc{user_acc = UAcc1, limit = Limit - 1, last_go = Go}}.
maybe_finalize(Red, null) ->
Red;
@@ -619,31 +659,31 @@ maybe_finalize(Red, RedSrc) ->
{ok, Finalized} = couch_query_servers:finalize(RedSrc, Red),
Finalized.
-finish_fold(#mracc{last_go=ok, update_seq=UpdateSeq}=Acc, ExtraMeta) ->
- #mracc{callback=Callback, user_acc=UAcc, args=Args}=Acc,
+finish_fold(#mracc{last_go = ok, update_seq = UpdateSeq} = Acc, ExtraMeta) ->
+ #mracc{callback = Callback, user_acc = UAcc, args = Args} = Acc,
% Possible send meta info
Meta = make_meta(Args, UpdateSeq, ExtraMeta),
- {Go, UAcc1} = case Acc#mracc.meta_sent of
- false -> Callback(Meta, UAcc);
- _ -> {ok, Acc#mracc.user_acc}
- end,
+ {Go, UAcc1} =
+ case Acc#mracc.meta_sent of
+ false -> Callback(Meta, UAcc);
+ _ -> {ok, Acc#mracc.user_acc}
+ end,
% Notify callback that the fold is complete.
- {_, UAcc2} = case Go of
- ok -> Callback(complete, UAcc1);
- _ -> {ok, UAcc1}
- end,
+ {_, UAcc2} =
+ case Go of
+ ok -> Callback(complete, UAcc1);
+ _ -> {ok, UAcc1}
+ end,
{ok, UAcc2};
-finish_fold(#mracc{user_acc=UAcc}, _ExtraMeta) ->
+finish_fold(#mracc{user_acc = UAcc}, _ExtraMeta) ->
{ok, UAcc}.
-
make_meta(Args, UpdateSeq, Base) ->
case Args#mrargs.update_seq of
true -> {meta, Base ++ [{update_seq, UpdateSeq}]};
_ -> {meta, Base}
end.
-
get_reduce_fun(#mrargs{extra = Extra}) ->
case couch_util:get_value(namespace, Extra) of
<<"_local">> ->
@@ -652,7 +692,6 @@ get_reduce_fun(#mrargs{extra = Extra}) ->
fun couch_mrview_util:all_docs_reduce_to_count/1
end.
-
get_total_rows(Db, #mrargs{extra = Extra}) ->
case couch_util:get_value(namespace, Extra) of
<<"_local">> ->
@@ -665,7 +704,6 @@ get_total_rows(Db, #mrargs{extra = Extra}) ->
couch_util:get_value(doc_count, Info)
end.
-
get_update_seq(Db, #mrargs{extra = Extra}) ->
case couch_util:get_value(namespace, Extra) of
<<"_local">> ->
@@ -674,7 +712,6 @@ get_update_seq(Db, #mrargs{extra = Extra}) ->
couch_db:get_update_seq(Db)
end.
-
default_cb(complete, Acc) ->
{ok, lists:reverse(Acc)};
default_cb({final, Info}, []) ->
@@ -686,13 +723,15 @@ default_cb(ok, ddoc_updated) ->
default_cb(Row, Acc) ->
{ok, [Row | Acc]}.
-
to_mrargs(KeyList) ->
- lists:foldl(fun({Key, Value}, Acc) ->
- Index = lookup_index(couch_util:to_existing_atom(Key)),
- setelement(Index, Acc, Value)
- end, #mrargs{}, KeyList).
-
+ lists:foldl(
+ fun({Key, Value}, Acc) ->
+ Index = lookup_index(couch_util:to_existing_atom(Key)),
+ setelement(Index, Acc, Value)
+ end,
+ #mrargs{},
+ KeyList
+ ).
lookup_index(Key) ->
Index = lists:zip(
diff --git a/src/couch_mrview/src/couch_mrview_cleanup.erl b/src/couch_mrview/src/couch_mrview_cleanup.erl
index e0cb1c64f..417605c55 100644
--- a/src/couch_mrview/src/couch_mrview_cleanup.erl
+++ b/src/couch_mrview/src/couch_mrview_cleanup.erl
@@ -14,24 +14,26 @@
-export([run/1]).
-
-include_lib("couch/include/couch_db.hrl").
-include_lib("couch_mrview/include/couch_mrview.hrl").
-
run(Db) ->
RootDir = couch_index_util:root_dir(),
DbName = couch_db:name(Db),
{ok, DesignDocs} = couch_db:get_design_docs(Db),
- SigFiles = lists:foldl(fun(DDocInfo, SFAcc) ->
- {ok, DDoc} = couch_db:open_doc_int(Db, DDocInfo, [ejson_body]),
- {ok, InitState} = couch_mrview_util:ddoc_to_mrst(DbName, DDoc),
- Sig = InitState#mrst.sig,
- IFName = couch_mrview_util:index_file(DbName, Sig),
- CFName = couch_mrview_util:compaction_file(DbName, Sig),
- [IFName, CFName | SFAcc]
- end, [], [DD || DD <- DesignDocs, DD#full_doc_info.deleted == false]),
+ SigFiles = lists:foldl(
+ fun(DDocInfo, SFAcc) ->
+ {ok, DDoc} = couch_db:open_doc_int(Db, DDocInfo, [ejson_body]),
+ {ok, InitState} = couch_mrview_util:ddoc_to_mrst(DbName, DDoc),
+ Sig = InitState#mrst.sig,
+ IFName = couch_mrview_util:index_file(DbName, Sig),
+ CFName = couch_mrview_util:compaction_file(DbName, Sig),
+ [IFName, CFName | SFAcc]
+ end,
+ [],
+ [DD || DD <- DesignDocs, DD#full_doc_info.deleted == false]
+ ),
IdxDir = couch_index_util:index_dir(mrview, DbName),
DiskFiles = filelib:wildcard(filename:join(IdxDir, "*")),
@@ -39,21 +41,28 @@ run(Db) ->
% We need to delete files that have no ddoc.
ToDelete = DiskFiles -- SigFiles,
- lists:foreach(fun(FN) ->
- couch_log:debug("Deleting stale view file: ~s", [FN]),
- couch_file:delete(RootDir, FN, [sync]),
- case couch_mrview_util:verify_view_filename(FN) of
- true ->
- Sig = couch_mrview_util:get_signature_from_filename(FN),
- DocId = couch_mrview_util:get_local_purge_doc_id(Sig),
- case couch_db:open_doc(Db, DocId, []) of
- {ok, LocalPurgeDoc} ->
- couch_db:update_doc(Db,
- LocalPurgeDoc#doc{deleted=true}, [?ADMIN_CTX]);
- {not_found, _} ->
- ok
- end;
- false -> ok
- end
- end, ToDelete),
+ lists:foreach(
+ fun(FN) ->
+ couch_log:debug("Deleting stale view file: ~s", [FN]),
+ couch_file:delete(RootDir, FN, [sync]),
+ case couch_mrview_util:verify_view_filename(FN) of
+ true ->
+ Sig = couch_mrview_util:get_signature_from_filename(FN),
+ DocId = couch_mrview_util:get_local_purge_doc_id(Sig),
+ case couch_db:open_doc(Db, DocId, []) of
+ {ok, LocalPurgeDoc} ->
+ couch_db:update_doc(
+ Db,
+ LocalPurgeDoc#doc{deleted = true},
+ [?ADMIN_CTX]
+ );
+ {not_found, _} ->
+ ok
+ end;
+ false ->
+ ok
+ end
+ end,
+ ToDelete
+ ),
ok.
diff --git a/src/couch_mrview/src/couch_mrview_compactor.erl b/src/couch_mrview/src/couch_mrview_compactor.erl
index d42edc054..28e5a9b3d 100644
--- a/src/couch_mrview/src/couch_mrview_compactor.erl
+++ b/src/couch_mrview/src/couch_mrview_compactor.erl
@@ -18,12 +18,12 @@
-export([compact/3, swap_compacted/2, remove_compacted/1]).
-record(acc, {
- btree = nil,
- last_id = nil,
- kvs = [],
- kvs_size = 0,
- changes = 0,
- total_changes
+ btree = nil,
+ last_id = nil,
+ kvs = [],
+ kvs_size = 0,
+ changes = 0,
+ total_changes
}).
-define(DEFAULT_RECOMPACT_RETRY_COUNT, 3).
@@ -36,12 +36,12 @@ compact(_Db, State, Opts) ->
compact(State) ->
#mrst{
- db_name=DbName,
- idx_name=IdxName,
- sig=Sig,
- update_seq=Seq,
- id_btree=IdBtree,
- views=Views
+ db_name = DbName,
+ idx_name = IdxName,
+ sig = Sig,
+ update_seq = Seq,
+ id_btree = IdBtree,
+ views = Views
} = State,
erlang:put(io_priority, {view_compact, DbName, IdxName}),
@@ -65,7 +65,9 @@ compact(State) ->
{ok, Kvs} = couch_mrview_util:get_row_count(View),
Acc + Kvs
end,
- NumDocIds, Views),
+ NumDocIds,
+ Views
+ ),
couch_task_status:add_task([
{type, view_compaction},
@@ -83,24 +85,29 @@ compact(State) ->
FoldFun = fun({DocId, ViewIdKeys} = KV, Acc) ->
#acc{btree = Bt, kvs = Kvs, kvs_size = KvsSize} = Acc,
- NewKvs = case Kvs of
- [{DocId, OldViewIdKeys} | Rest] ->
- couch_log:error("Dupes of ~s in ~s ~s",
- [DocId, DbName, IdxName]),
- [{DocId, ViewIdKeys ++ OldViewIdKeys} | Rest];
- _ ->
- [KV | Kvs]
- end,
+ NewKvs =
+ case Kvs of
+ [{DocId, OldViewIdKeys} | Rest] ->
+ couch_log:error(
+ "Dupes of ~s in ~s ~s",
+ [DocId, DbName, IdxName]
+ ),
+ [{DocId, ViewIdKeys ++ OldViewIdKeys} | Rest];
+ _ ->
+ [KV | Kvs]
+ end,
KvsSize2 = KvsSize + ?term_size(KV),
case KvsSize2 >= BufferSize of
true ->
{ok, Bt2} = couch_btree:add(Bt, lists:reverse(NewKvs)),
Acc2 = update_task(Acc, length(NewKvs)),
{ok, Acc2#acc{
- btree = Bt2, kvs = [], kvs_size = 0, last_id = DocId}};
+ btree = Bt2, kvs = [], kvs_size = 0, last_id = DocId
+ }};
_ ->
{ok, Acc#acc{
- kvs = NewKvs, kvs_size = KvsSize2, last_id = DocId}}
+ kvs = NewKvs, kvs_size = KvsSize2, last_id = DocId
+ }}
end
end,
@@ -110,26 +117,26 @@ compact(State) ->
{ok, NewIdBtree} = couch_btree:add(Bt3, lists:reverse(Uncopied)),
FinalAcc2 = update_task(FinalAcc, length(Uncopied)),
-
- {NewViews, _} = lists:mapfoldl(fun({View, EmptyView}, Acc) ->
- compact_view(View, EmptyView, BufferSize, Acc)
- end, FinalAcc2, lists:zip(Views, EmptyViews)),
+ {NewViews, _} = lists:mapfoldl(
+ fun({View, EmptyView}, Acc) ->
+ compact_view(View, EmptyView, BufferSize, Acc)
+ end,
+ FinalAcc2,
+ lists:zip(Views, EmptyViews)
+ ),
unlink(EmptyState#mrst.fd),
{ok, EmptyState#mrst{
- id_btree=NewIdBtree,
- views=NewViews,
- update_seq=Seq
+ id_btree = NewIdBtree,
+ views = NewViews,
+ update_seq = Seq
}}.
-
recompact(State) ->
recompact(State, recompact_retry_count()).
-recompact(#mrst{db_name=DbName, idx_name=IdxName}, 0) ->
- erlang:error({exceeded_recompact_retry_count,
- [{db_name, DbName}, {idx_name, IdxName}]});
-
+recompact(#mrst{db_name = DbName, idx_name = IdxName}, 0) ->
+ erlang:error({exceeded_recompact_retry_count, [{db_name, DbName}, {idx_name, IdxName}]});
recompact(State, RetryCount) ->
Self = self(),
link(State#mrst.fd),
@@ -159,27 +166,35 @@ recompact_retry_count() ->
?DEFAULT_RECOMPACT_RETRY_COUNT
).
-
%% @spec compact_view(View, EmptyView, Retry, Acc) -> {CompactView, NewAcc}
-compact_view(#mrview{id_num=VID}=View, EmptyView, BufferSize, Acc0) ->
-
- {NewBt, FinalAcc} = compact_view_btree(View#mrview.btree,
- EmptyView#mrview.btree,
- VID, BufferSize, Acc0),
+compact_view(#mrview{id_num = VID} = View, EmptyView, BufferSize, Acc0) ->
+ {NewBt, FinalAcc} = compact_view_btree(
+ View#mrview.btree,
+ EmptyView#mrview.btree,
+ VID,
+ BufferSize,
+ Acc0
+ ),
- {EmptyView#mrview{btree=NewBt,
- update_seq=View#mrview.update_seq,
- purge_seq=View#mrview.purge_seq}, FinalAcc}.
+ {
+ EmptyView#mrview{
+ btree = NewBt,
+ update_seq = View#mrview.update_seq,
+ purge_seq = View#mrview.purge_seq
+ },
+ FinalAcc
+ }.
compact_view_btree(Btree, EmptyBtree, VID, BufferSize, Acc0) ->
Fun = fun(KV, #acc{btree = Bt, kvs = Kvs, kvs_size = KvsSize} = Acc) ->
KvsSize2 = KvsSize + ?term_size(KV),
- if KvsSize2 >= BufferSize ->
- {ok, Bt2} = couch_btree:add(Bt, lists:reverse([KV | Kvs])),
- Acc2 = update_task(VID, Acc, 1 + length(Kvs)),
- {ok, Acc2#acc{btree = Bt2, kvs = [], kvs_size = 0}};
- true ->
- {ok, Acc#acc{kvs = [KV | Kvs], kvs_size = KvsSize2}}
+ if
+ KvsSize2 >= BufferSize ->
+ {ok, Bt2} = couch_btree:add(Bt, lists:reverse([KV | Kvs])),
+ Acc2 = update_task(VID, Acc, 1 + length(Kvs)),
+ {ok, Acc2#acc{btree = Bt2, kvs = [], kvs_size = 0}};
+ true ->
+ {ok, Acc#acc{kvs = [KV | Kvs], kvs_size = KvsSize2}}
end
end,
@@ -193,11 +208,18 @@ compact_view_btree(Btree, EmptyBtree, VID, BufferSize, Acc0) ->
update_task(Acc, ChangesInc) ->
update_task(null, Acc, ChangesInc).
-
-update_task(VID, #acc{changes=Changes, total_changes=Total}=Acc, ChangesInc) ->
- Phase = if is_integer(VID) -> view; true -> ids end,
+update_task(VID, #acc{changes = Changes, total_changes = Total} = Acc, ChangesInc) ->
+ Phase =
+ if
+ is_integer(VID) -> view;
+ true -> ids
+ end,
Changes2 = Changes + ChangesInc,
- Progress = if Total == 0 -> 0; true -> (Changes2 * 100) div Total end,
+ Progress =
+ if
+ Total == 0 -> 0;
+ true -> (Changes2 * 100) div Total
+ end,
couch_task_status:update([
{phase, Phase},
{view, VID},
@@ -207,15 +229,14 @@ update_task(VID, #acc{changes=Changes, total_changes=Total}=Acc, ChangesInc) ->
]),
Acc#acc{changes = Changes2}.
-
swap_compacted(OldState, NewState) ->
#mrst{
fd = Fd
} = OldState,
#mrst{
- sig=Sig,
- db_name=DbName,
- fd=NewFd
+ sig = Sig,
+ db_name = DbName,
+ fd = NewFd
} = NewState,
link(NewState#mrst.fd),
@@ -227,16 +248,18 @@ swap_compacted(OldState, NewState) ->
{ok, Pre} = couch_file:bytes(Fd),
{ok, Post} = couch_file:bytes(NewFd),
- couch_log:notice("Compaction swap for view ~s ~p ~p", [IndexFName,
- Pre, Post]),
+ couch_log:notice("Compaction swap for view ~s ~p ~p", [
+ IndexFName,
+ Pre,
+ Post
+ ]),
ok = couch_file:delete(RootDir, IndexFName),
ok = file:rename(CompactFName, IndexFName),
unlink(OldState#mrst.fd),
erlang:demonitor(OldState#mrst.fd_monitor, [flush]),
- {ok, NewState#mrst{fd_monitor=Ref}}.
-
+ {ok, NewState#mrst{fd_monitor = Ref}}.
remove_compacted(#mrst{sig = Sig, db_name = DbName} = State) ->
RootDir = couch_index_util:root_dir(),
@@ -244,7 +267,6 @@ remove_compacted(#mrst{sig = Sig, db_name = DbName} = State) ->
ok = couch_file:delete(RootDir, CompactFName),
{ok, State}.
-
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
@@ -268,27 +290,28 @@ recompact_test_() ->
recompact_success_after_progress() ->
?_test(begin
- ok = meck:expect(couch_index_updater, update, fun
- (Pid, _, #mrst{update_seq=0} = State) ->
- Pid ! {'$gen_cast', {new_state, State#mrst{update_seq = 1}}},
- timer:sleep(100),
- exit({updated, self(), State#mrst{update_seq = 2}})
+ ok = meck:expect(couch_index_updater, update, fun(Pid, _, #mrst{update_seq = 0} = State) ->
+ Pid ! {'$gen_cast', {new_state, State#mrst{update_seq = 1}}},
+ timer:sleep(100),
+ exit({updated, self(), State#mrst{update_seq = 2}})
end),
- State = #mrst{fd=self(), update_seq=0},
+ State = #mrst{fd = self(), update_seq = 0},
?assertEqual({ok, State#mrst{update_seq = 2}}, recompact(State))
end).
recompact_exceeded_retry_count() ->
?_test(begin
- ok = meck:expect(couch_index_updater, update,
+ ok = meck:expect(
+ couch_index_updater,
+ update,
fun(_, _, _) ->
exit(error)
- end),
+ end
+ ),
ok = meck:expect(couch_log, warning, fun(_, _) -> ok end),
- State = #mrst{fd=self(), db_name=foo, idx_name=bar},
- ExpectedError = {exceeded_recompact_retry_count,
- [{db_name, foo}, {idx_name, bar}]},
- ?assertError(ExpectedError, recompact(State))
+ State = #mrst{fd = self(), db_name = foo, idx_name = bar},
+ ExpectedError = {exceeded_recompact_retry_count, [{db_name, foo}, {idx_name, bar}]},
+ ?assertError(ExpectedError, recompact(State))
end).
-endif.
diff --git a/src/couch_mrview/src/couch_mrview_http.erl b/src/couch_mrview/src/couch_mrview_http.erl
index 802739b82..fa3fab386 100644
--- a/src/couch_mrview/src/couch_mrview_http.erl
+++ b/src/couch_mrview/src/couch_mrview_http.erl
@@ -43,37 +43,41 @@
-include_lib("couch/include/couch_db.hrl").
-include_lib("couch_mrview/include/couch_mrview.hrl").
-
-handle_all_docs_req(#httpd{method='GET'}=Req, Db) ->
+handle_all_docs_req(#httpd{method = 'GET'} = Req, Db) ->
all_docs_req(Req, Db, undefined);
-handle_all_docs_req(#httpd{method='POST'}=Req, Db) ->
+handle_all_docs_req(#httpd{method = 'POST'} = Req, Db) ->
chttpd:validate_ctype(Req, "application/json"),
Keys = couch_mrview_util:get_view_keys(chttpd:json_body_obj(Req)),
all_docs_req(Req, Db, Keys);
handle_all_docs_req(Req, _Db) ->
chttpd:send_method_not_allowed(Req, "GET,POST,HEAD").
-handle_local_docs_req(#httpd{method='GET'}=Req, Db) ->
+handle_local_docs_req(#httpd{method = 'GET'} = Req, Db) ->
all_docs_req(Req, Db, undefined, <<"_local">>);
-handle_local_docs_req(#httpd{method='POST'}=Req, Db) ->
+handle_local_docs_req(#httpd{method = 'POST'} = Req, Db) ->
chttpd:validate_ctype(Req, "application/json"),
Keys = couch_mrview_util:get_view_keys(chttpd:json_body_obj(Req)),
all_docs_req(Req, Db, Keys, <<"_local">>);
handle_local_docs_req(Req, _Db) ->
chttpd:send_method_not_allowed(Req, "GET,POST,HEAD").
-handle_design_docs_req(#httpd{method='GET'}=Req, Db) ->
+handle_design_docs_req(#httpd{method = 'GET'} = Req, Db) ->
all_docs_req(Req, Db, undefined, <<"_design">>);
-handle_design_docs_req(#httpd{method='POST'}=Req, Db) ->
+handle_design_docs_req(#httpd{method = 'POST'} = Req, Db) ->
chttpd:validate_ctype(Req, "application/json"),
Keys = couch_mrview_util:get_view_keys(chttpd:json_body_obj(Req)),
all_docs_req(Req, Db, Keys, <<"_design">>);
handle_design_docs_req(Req, _Db) ->
chttpd:send_method_not_allowed(Req, "GET,POST,HEAD").
-handle_reindex_req(#httpd{method='POST',
- path_parts=[_, _, DName,<<"_reindex">>]}=Req,
- Db, _DDoc) ->
+handle_reindex_req(
+ #httpd{
+ method = 'POST',
+ path_parts = [_, _, DName, <<"_reindex">>]
+ } = Req,
+ Db,
+ _DDoc
+) ->
chttpd:validate_ctype(Req, "application/json"),
ok = couch_db:check_is_admin(Db),
couch_mrview:trigger_update(Db, <<"_design/", DName/binary>>),
@@ -81,23 +85,30 @@ handle_reindex_req(#httpd{method='POST',
handle_reindex_req(Req, _Db, _DDoc) ->
chttpd:send_method_not_allowed(Req, "POST").
-
-handle_view_req(#httpd{method='GET',
- path_parts=[_, _, DDocName, _, VName, <<"_info">>]}=Req,
- Db, _DDoc) ->
+handle_view_req(
+ #httpd{
+ method = 'GET',
+ path_parts = [_, _, DDocName, _, VName, <<"_info">>]
+ } = Req,
+ Db,
+ _DDoc
+) ->
DbName = couch_db:name(Db),
- DDocId = <<"_design/", DDocName/binary >>,
+ DDocId = <<"_design/", DDocName/binary>>,
{ok, Info} = couch_mrview:get_view_info(DbName, DDocId, VName),
- FinalInfo = [{db_name, DbName},
- {ddoc, DDocId},
- {view, VName}] ++ Info,
+ FinalInfo =
+ [
+ {db_name, DbName},
+ {ddoc, DDocId},
+ {view, VName}
+ ] ++ Info,
chttpd:send_json(Req, 200, {FinalInfo});
-handle_view_req(#httpd{method='GET'}=Req, Db, DDoc) ->
+handle_view_req(#httpd{method = 'GET'} = Req, Db, DDoc) ->
[_, _, _, _, ViewName] = Req#httpd.path_parts,
couch_stats:increment_counter([couchdb, httpd, view_reads]),
design_doc_view(Req, Db, DDoc, ViewName, undefined);
-handle_view_req(#httpd{method='POST'}=Req, Db, DDoc) ->
+handle_view_req(#httpd{method = 'POST'} = Req, Db, DDoc) ->
chttpd:validate_ctype(Req, "application/json"),
[_, _, _, _, ViewName] = Req#httpd.path_parts,
Props = chttpd:json_body_obj(Req),
@@ -122,8 +133,7 @@ handle_view_req(#httpd{method='POST'}=Req, Db, DDoc) ->
handle_view_req(Req, _Db, _DDoc) ->
chttpd:send_method_not_allowed(Req, "GET,POST,HEAD").
-
-handle_temp_view_req(#httpd{method='POST'}=Req, Db) ->
+handle_temp_view_req(#httpd{method = 'POST'} = Req, Db) ->
chttpd:validate_ctype(Req, "application/json"),
ok = couch_db:check_is_admin(Db),
{Body} = chttpd:json_body_obj(Req),
@@ -134,19 +144,21 @@ handle_temp_view_req(#httpd{method='POST'}=Req, Db) ->
handle_temp_view_req(Req, _Db) ->
chttpd:send_method_not_allowed(Req, "POST").
-
-handle_info_req(#httpd{method='GET'}=Req, Db, DDoc) ->
+handle_info_req(#httpd{method = 'GET'} = Req, Db, DDoc) ->
[_, _, Name, _] = Req#httpd.path_parts,
{ok, Info} = couch_mrview:get_info(Db, DDoc),
- chttpd:send_json(Req, 200, {[
- {name, Name},
- {view_index, {Info}}
- ]});
+ chttpd:send_json(
+ Req,
+ 200,
+ {[
+ {name, Name},
+ {view_index, {Info}}
+ ]}
+ );
handle_info_req(Req, _Db, _DDoc) ->
chttpd:send_method_not_allowed(Req, "GET").
-
-handle_compact_req(#httpd{method='POST'}=Req, Db, DDoc) ->
+handle_compact_req(#httpd{method = 'POST'} = Req, Db, DDoc) ->
chttpd:validate_ctype(Req, "application/json"),
ok = couch_db:check_is_admin(Db),
ok = couch_mrview:compact(Db, DDoc),
@@ -154,8 +166,7 @@ handle_compact_req(#httpd{method='POST'}=Req, Db, DDoc) ->
handle_compact_req(Req, _Db, _DDoc) ->
chttpd:send_method_not_allowed(Req, "POST").
-
-handle_cleanup_req(#httpd{method='POST'}=Req, Db) ->
+handle_cleanup_req(#httpd{method = 'POST'} = Req, Db) ->
chttpd:validate_ctype(Req, "application/json"),
ok = couch_db:check_is_admin(Db),
ok = couch_mrview:cleanup(Db),
@@ -163,29 +174,30 @@ handle_cleanup_req(#httpd{method='POST'}=Req, Db) ->
handle_cleanup_req(Req, _Db) ->
chttpd:send_method_not_allowed(Req, "POST").
-
all_docs_req(Req, Db, Keys) ->
all_docs_req(Req, Db, Keys, undefined).
all_docs_req(Req, Db, Keys, NS) ->
case is_restricted(Db, NS) of
- true ->
- case (catch couch_db:check_is_admin(Db)) of
- ok ->
- do_all_docs_req(Req, Db, Keys, NS);
- _ when NS == <<"_local">> ->
- throw({forbidden, <<"Only admins can access _local_docs">>});
- _ ->
- case is_public_fields_configured(Db) of
- true ->
+ true ->
+ case (catch couch_db:check_is_admin(Db)) of
+ ok ->
do_all_docs_req(Req, Db, Keys, NS);
- false ->
- throw({forbidden, <<"Only admins can access _all_docs",
- " of system databases.">>})
- end
- end;
- false ->
- do_all_docs_req(Req, Db, Keys, NS)
+ _ when NS == <<"_local">> ->
+ throw({forbidden, <<"Only admins can access _local_docs">>});
+ _ ->
+ case is_public_fields_configured(Db) of
+ true ->
+ do_all_docs_req(Req, Db, Keys, NS);
+ false ->
+ throw(
+ {forbidden,
+ <<"Only admins can access _all_docs", " of system databases.">>}
+ )
+ end
+ end;
+ false ->
+ do_all_docs_req(Req, Db, Keys, NS)
end.
is_restricted(_Db, <<"_local">>) ->
@@ -196,18 +208,19 @@ is_restricted(Db, _) ->
is_public_fields_configured(Db) ->
DbName = ?b2l(couch_db:name(Db)),
case config:get("couch_httpd_auth", "authentication_db", "_users") of
- DbName ->
- UsersDbPublic = chttpd_util:get_chttpd_auth_config(
- "users_db_public", "false"),
- PublicFields = chttpd_util:get_chttpd_auth_config("public_fields"),
- case {UsersDbPublic, PublicFields} of
- {"true", PublicFields} when PublicFields =/= undefined ->
- true;
- {_, _} ->
+ DbName ->
+ UsersDbPublic = chttpd_util:get_chttpd_auth_config(
+ "users_db_public", "false"
+ ),
+ PublicFields = chttpd_util:get_chttpd_auth_config("public_fields"),
+ case {UsersDbPublic, PublicFields} of
+ {"true", PublicFields} when PublicFields =/= undefined ->
+ true;
+ {_, _} ->
+ false
+ end;
+ _ ->
false
- end;
- _ ->
- false
end.
do_all_docs_req(Req, Db, Keys, NS) ->
@@ -216,14 +229,16 @@ do_all_docs_req(Req, Db, Keys, NS) ->
ETagFun = fun(Sig, Acc0) ->
check_view_etag(Sig, Acc0, Req)
end,
- Args = Args1#mrargs{preflight_fun=ETagFun},
+ Args = Args1#mrargs{preflight_fun = ETagFun},
{ok, Resp} = couch_httpd:etag_maybe(Req, fun() ->
Max = chttpd:chunked_response_buffer_size(),
- VAcc0 = #vacc{db=Db, req=Req, threshold=Max},
+ VAcc0 = #vacc{db = Db, req = Req, threshold = Max},
DbName = ?b2l(couch_db:name(Db)),
- UsersDbName = config:get("couch_httpd_auth",
- "authentication_db",
- "_users"),
+ UsersDbName = config:get(
+ "couch_httpd_auth",
+ "authentication_db",
+ "_users"
+ ),
IsAdmin = is_admin(Db),
Callback = get_view_callback(DbName, UsersDbName, IsAdmin),
couch_mrview:query_all_docs(Db, Args, Callback, VAcc0)
@@ -238,13 +253,12 @@ set_namespace(NS, #mrargs{extra = Extra} = Args) ->
is_admin(Db) ->
case catch couch_db:check_is_admin(Db) of
- {unauthorized, _} ->
- false;
- ok ->
- true
+ {unauthorized, _} ->
+ false;
+ ok ->
+ true
end.
-
% admin users always get all fields
get_view_callback(_, _, true) ->
fun view_cb/2;
@@ -256,16 +270,15 @@ get_view_callback(_DbName, _DbName, false) ->
get_view_callback(_, _, _) ->
fun view_cb/2.
-
design_doc_view(Req, Db, DDoc, ViewName, Keys) ->
Args0 = parse_params(Req, Keys),
ETagFun = fun(Sig, Acc0) ->
check_view_etag(Sig, Acc0, Req)
end,
- Args = Args0#mrargs{preflight_fun=ETagFun},
+ Args = Args0#mrargs{preflight_fun = ETagFun},
{ok, Resp} = couch_httpd:etag_maybe(Req, fun() ->
Max = chttpd:chunked_response_buffer_size(),
- VAcc0 = #vacc{db=Db, req=Req, threshold=Max},
+ VAcc0 = #vacc{db = Db, req = Req, threshold = Max},
couch_mrview:query_view(Db, DDoc, ViewName, Args, fun view_cb/2, VAcc0)
end),
case is_record(Resp, vacc) of
@@ -273,30 +286,36 @@ design_doc_view(Req, Db, DDoc, ViewName, Keys) ->
_ -> {ok, Resp}
end.
-
multi_query_view(Req, Db, DDoc, ViewName, Queries) ->
Args0 = parse_params(Req, undefined),
{ok, _, _, Args1} = couch_mrview_util:get_view(Db, DDoc, ViewName, Args0),
- ArgQueries = lists:map(fun({Query}) ->
- QueryArg = parse_params(Query, undefined, Args1),
- couch_mrview_util:validate_args(Db, DDoc, QueryArg)
- end, Queries),
+ ArgQueries = lists:map(
+ fun({Query}) ->
+ QueryArg = parse_params(Query, undefined, Args1),
+ couch_mrview_util:validate_args(Db, DDoc, QueryArg)
+ end,
+ Queries
+ ),
{ok, Resp2} = couch_httpd:etag_maybe(Req, fun() ->
Max = chttpd:chunked_response_buffer_size(),
- VAcc0 = #vacc{db=Db, req=Req, prepend="\r\n", threshold=Max},
+ VAcc0 = #vacc{db = Db, req = Req, prepend = "\r\n", threshold = Max},
%% TODO: proper calculation of etag
Etag = [$", couch_uuids:new(), $"],
Headers = [{"ETag", Etag}],
FirstChunk = "{\"results\":[",
{ok, Resp0} = chttpd:start_delayed_json_response(VAcc0#vacc.req, 200, Headers, FirstChunk),
- VAcc1 = VAcc0#vacc{resp=Resp0},
- VAcc2 = lists:foldl(fun(Args, Acc0) ->
- {ok, Acc1} = couch_mrview:query_view(Db, DDoc, ViewName, Args, fun view_cb/2, Acc0),
- Acc1
- end, VAcc1, ArgQueries),
+ VAcc1 = VAcc0#vacc{resp = Resp0},
+ VAcc2 = lists:foldl(
+ fun(Args, Acc0) ->
+ {ok, Acc1} = couch_mrview:query_view(Db, DDoc, ViewName, Args, fun view_cb/2, Acc0),
+ Acc1
+ end,
+ VAcc1,
+ ArgQueries
+ ),
{ok, Resp1} = chttpd:send_delayed_chunk(VAcc2#vacc.resp, "\r\n]}"),
{ok, Resp2} = chttpd:end_delayed_json_response(Resp1),
- {ok, VAcc2#vacc{resp=Resp2}}
+ {ok, VAcc2#vacc{resp = Resp2}}
end),
case is_record(Resp2, vacc) of
true -> {ok, Resp2#vacc.resp};
@@ -304,94 +323,99 @@ multi_query_view(Req, Db, DDoc, ViewName, Queries) ->
end.
filtered_view_cb({row, Row0}, Acc) ->
- Row1 = lists:map(fun({doc, null}) ->
- {doc, null};
- ({doc, Body}) ->
- Doc = couch_users_db:strip_non_public_fields(#doc{body=Body}),
- {doc, Doc#doc.body};
- (KV) ->
- KV
- end, Row0),
+ Row1 = lists:map(
+ fun
+ ({doc, null}) ->
+ {doc, null};
+ ({doc, Body}) ->
+ Doc = couch_users_db:strip_non_public_fields(#doc{body = Body}),
+ {doc, Doc#doc.body};
+ (KV) ->
+ KV
+ end,
+ Row0
+ ),
view_cb({row, Row1}, Acc);
filtered_view_cb(Obj, Acc) ->
view_cb(Obj, Acc).
-
%% these clauses start (and possibly end) the response
-view_cb({error, Reason}, #vacc{resp=undefined}=Acc) ->
+view_cb({error, Reason}, #vacc{resp = undefined} = Acc) ->
{ok, Resp} = chttpd:send_error(Acc#vacc.req, Reason),
- {ok, Acc#vacc{resp=Resp}};
-
-view_cb(complete, #vacc{resp=undefined}=Acc) ->
+ {ok, Acc#vacc{resp = Resp}};
+view_cb(complete, #vacc{resp = undefined} = Acc) ->
% Nothing in view
{ok, Resp} = chttpd:send_json(Acc#vacc.req, 200, {[{rows, []}]}),
- {ok, Acc#vacc{resp=Resp}};
-
-view_cb(Msg, #vacc{resp=undefined}=Acc) ->
+ {ok, Acc#vacc{resp = Resp}};
+view_cb(Msg, #vacc{resp = undefined} = Acc) ->
%% Start response
Headers = [],
{ok, Resp} = chttpd:start_delayed_json_response(Acc#vacc.req, 200, Headers),
- view_cb(Msg, Acc#vacc{resp=Resp, should_close=true});
-
+ view_cb(Msg, Acc#vacc{resp = Resp, should_close = true});
%% ---------------------------------------------------
%% From here on down, the response has been started.
-view_cb({error, Reason}, #vacc{resp=Resp}=Acc) ->
+view_cb({error, Reason}, #vacc{resp = Resp} = Acc) ->
{ok, Resp1} = chttpd:send_delayed_error(Resp, Reason),
- {ok, Acc#vacc{resp=Resp1}};
-
-view_cb(complete, #vacc{resp=Resp, buffer=Buf, threshold=Max}=Acc) ->
+ {ok, Acc#vacc{resp = Resp1}};
+view_cb(complete, #vacc{resp = Resp, buffer = Buf, threshold = Max} = Acc) ->
% Finish view output and possibly end the response
{ok, Resp1} = chttpd:close_delayed_json_object(Resp, Buf, "\r\n]}", Max),
case Acc#vacc.should_close of
true ->
{ok, Resp2} = chttpd:end_delayed_json_response(Resp1),
- {ok, Acc#vacc{resp=Resp2}};
+ {ok, Acc#vacc{resp = Resp2}};
_ ->
- {ok, Acc#vacc{resp=Resp1, meta_sent=false, row_sent=false,
- prepend=",\r\n", buffer=[], bufsize=0}}
+ {ok, Acc#vacc{
+ resp = Resp1,
+ meta_sent = false,
+ row_sent = false,
+ prepend = ",\r\n",
+ buffer = [],
+ bufsize = 0
+ }}
end;
-
-view_cb({meta, Meta}, #vacc{meta_sent=false, row_sent=false}=Acc) ->
+view_cb({meta, Meta}, #vacc{meta_sent = false, row_sent = false} = Acc) ->
% Sending metadata as we've not sent it or any row yet
- Parts = case couch_util:get_value(total, Meta) of
- undefined -> [];
- Total -> [io_lib:format("\"total_rows\":~p", [Total])]
- end ++ case couch_util:get_value(offset, Meta) of
- undefined -> [];
- Offset -> [io_lib:format("\"offset\":~p", [Offset])]
- end ++ case couch_util:get_value(update_seq, Meta) of
- undefined -> [];
- null ->
- ["\"update_seq\":null"];
- UpdateSeq when is_integer(UpdateSeq) ->
- [io_lib:format("\"update_seq\":~B", [UpdateSeq])];
- UpdateSeq when is_binary(UpdateSeq) ->
- [io_lib:format("\"update_seq\":\"~s\"", [UpdateSeq])]
- end ++ ["\"rows\":["],
+ Parts =
+ case couch_util:get_value(total, Meta) of
+ undefined -> [];
+ Total -> [io_lib:format("\"total_rows\":~p", [Total])]
+ end ++
+ case couch_util:get_value(offset, Meta) of
+ undefined -> [];
+ Offset -> [io_lib:format("\"offset\":~p", [Offset])]
+ end ++
+ case couch_util:get_value(update_seq, Meta) of
+ undefined ->
+ [];
+ null ->
+ ["\"update_seq\":null"];
+ UpdateSeq when is_integer(UpdateSeq) ->
+ [io_lib:format("\"update_seq\":~B", [UpdateSeq])];
+ UpdateSeq when is_binary(UpdateSeq) ->
+ [io_lib:format("\"update_seq\":\"~s\"", [UpdateSeq])]
+ end ++ ["\"rows\":["],
Chunk = [prepend_val(Acc), "{", string:join(Parts, ","), "\r\n"],
{ok, AccOut} = maybe_flush_response(Acc, Chunk, iolist_size(Chunk)),
- {ok, AccOut#vacc{prepend="", meta_sent=true}};
-
-view_cb({meta, _Meta}, #vacc{}=Acc) ->
+ {ok, AccOut#vacc{prepend = "", meta_sent = true}};
+view_cb({meta, _Meta}, #vacc{} = Acc) ->
%% ignore metadata
{ok, Acc};
-
-view_cb({row, Row}, #vacc{meta_sent=false}=Acc) ->
+view_cb({row, Row}, #vacc{meta_sent = false} = Acc) ->
%% sorted=false and row arrived before meta
% Adding another row
Chunk = [prepend_val(Acc), "{\"rows\":[\r\n", row_to_json(Row)],
- maybe_flush_response(Acc#vacc{meta_sent=true, row_sent=true}, Chunk, iolist_size(Chunk));
-
-view_cb({row, Row}, #vacc{meta_sent=true}=Acc) ->
+ maybe_flush_response(Acc#vacc{meta_sent = true, row_sent = true}, Chunk, iolist_size(Chunk));
+view_cb({row, Row}, #vacc{meta_sent = true} = Acc) ->
% Adding another row
Chunk = [prepend_val(Acc), row_to_json(Row)],
- maybe_flush_response(Acc#vacc{row_sent=true}, Chunk, iolist_size(Chunk)).
+ maybe_flush_response(Acc#vacc{row_sent = true}, Chunk, iolist_size(Chunk)).
-
-maybe_flush_response(#vacc{bufsize=Size, threshold=Max} = Acc, Data, Len)
- when Size > 0 andalso (Size + Len) > Max ->
+maybe_flush_response(#vacc{bufsize = Size, threshold = Max} = Acc, Data, Len) when
+ Size > 0 andalso (Size + Len) > Max
+->
#vacc{buffer = Buffer, resp = Resp} = Acc,
{ok, R1} = chttpd:send_delayed_chunk(Resp, Buffer),
{ok, Acc#vacc{prepend = ",\r\n", buffer = Data, bufsize = Len, resp = R1}};
@@ -404,7 +428,7 @@ maybe_flush_response(Acc0, Data, Len) ->
},
{ok, Acc}.
-prepend_val(#vacc{prepend=Prepend}) ->
+prepend_val(#vacc{prepend = Prepend}) ->
case Prepend of
undefined ->
"";
@@ -412,72 +436,83 @@ prepend_val(#vacc{prepend=Prepend}) ->
Prepend
end.
-
row_to_json(Row) ->
Id = couch_util:get_value(id, Row),
row_to_json(Id, Row).
-
row_to_json(error, Row) ->
% Special case for _all_docs request with KEYS to
% match prior behavior.
Key = couch_util:get_value(key, Row),
Val = couch_util:get_value(value, Row),
Reason = couch_util:get_value(reason, Row),
- ReasonProp = if Reason == undefined -> []; true ->
- [{reason, Reason}]
- end,
+ ReasonProp =
+ if
+ Reason == undefined -> [];
+ true -> [{reason, Reason}]
+ end,
Obj = {[{key, Key}, {error, Val}] ++ ReasonProp},
?JSON_ENCODE(Obj);
row_to_json(Id0, Row) ->
- Id = case Id0 of
- undefined -> [];
- Id0 -> [{id, Id0}]
- end,
+ Id =
+ case Id0 of
+ undefined -> [];
+ Id0 -> [{id, Id0}]
+ end,
Key = couch_util:get_value(key, Row, null),
Val = couch_util:get_value(value, Row),
- Doc = case couch_util:get_value(doc, Row) of
- undefined -> [];
- Doc0 -> [{doc, Doc0}]
- end,
+ Doc =
+ case couch_util:get_value(doc, Row) of
+ undefined -> [];
+ Doc0 -> [{doc, Doc0}]
+ end,
Obj = {Id ++ [{key, Key}, {value, Val}] ++ Doc},
?JSON_ENCODE(Obj).
-
-parse_params(#httpd{}=Req, Keys) ->
+parse_params(#httpd{} = Req, Keys) ->
parse_params(chttpd:qs(Req), Keys);
parse_params(Props, Keys) ->
Args = #mrargs{},
parse_params(Props, Keys, Args).
-
parse_params(Props, Keys, Args) ->
parse_params(Props, Keys, Args, []).
-parse_params(Props, Keys, #mrargs{}=Args0, Options) ->
+parse_params(Props, Keys, #mrargs{} = Args0, Options) ->
IsDecoded = lists:member(decoded, Options),
- Args1 = case lists:member(keep_group_level, Options) of
- true ->
- Args0;
- _ ->
- % group_level set to undefined to detect if explicitly set by user
- Args0#mrargs{keys=Keys, group=undefined, group_level=undefined}
- end,
- lists:foldl(fun({K, V}, Acc) ->
- parse_param(K, V, Acc, IsDecoded)
- end, Args1, Props).
-
-
-parse_body_and_query(#httpd{method='POST'} = Req, Keys) ->
+ Args1 =
+ case lists:member(keep_group_level, Options) of
+ true ->
+ Args0;
+ _ ->
+ % group_level set to undefined to detect if explicitly set by user
+ Args0#mrargs{keys = Keys, group = undefined, group_level = undefined}
+ end,
+ lists:foldl(
+ fun({K, V}, Acc) ->
+ parse_param(K, V, Acc, IsDecoded)
+ end,
+ Args1,
+ Props
+ ).
+
+parse_body_and_query(#httpd{method = 'POST'} = Req, Keys) ->
Props = chttpd:json_body_obj(Req),
parse_body_and_query(Req, Props, Keys);
-
parse_body_and_query(Req, Keys) ->
- parse_params(chttpd:qs(Req), Keys, #mrargs{keys=Keys, group=undefined,
- group_level=undefined}, [keep_group_level]).
+ parse_params(
+ chttpd:qs(Req),
+ Keys,
+ #mrargs{
+ keys = Keys,
+ group = undefined,
+ group_level = undefined
+ },
+ [keep_group_level]
+ ).
parse_body_and_query(Req, {Props}, Keys) ->
- Args = #mrargs{keys=Keys, group=undefined, group_level=undefined},
+ Args = #mrargs{keys = Keys, group = undefined, group_level = undefined},
BodyArgs = parse_params(Props, Keys, Args, [decoded]),
parse_params(chttpd:qs(Req), Keys, BodyArgs, [keep_group_level]).
@@ -488,101 +523,101 @@ parse_param(Key, Val, Args, IsDecoded) ->
"" ->
Args;
"reduce" ->
- Args#mrargs{reduce=parse_boolean(Val)};
+ Args#mrargs{reduce = parse_boolean(Val)};
"key" when IsDecoded ->
- Args#mrargs{start_key=Val, end_key=Val};
+ Args#mrargs{start_key = Val, end_key = Val};
"key" ->
JsonKey = ?JSON_DECODE(Val),
- Args#mrargs{start_key=JsonKey, end_key=JsonKey};
+ Args#mrargs{start_key = JsonKey, end_key = JsonKey};
"keys" when IsDecoded ->
- Args#mrargs{keys=Val};
+ Args#mrargs{keys = Val};
"keys" ->
- Args#mrargs{keys=?JSON_DECODE(Val)};
+ Args#mrargs{keys = ?JSON_DECODE(Val)};
"startkey" when IsDecoded ->
- Args#mrargs{start_key=Val};
+ Args#mrargs{start_key = Val};
"start_key" when IsDecoded ->
- Args#mrargs{start_key=Val};
+ Args#mrargs{start_key = Val};
"startkey" ->
- Args#mrargs{start_key=?JSON_DECODE(Val)};
+ Args#mrargs{start_key = ?JSON_DECODE(Val)};
"start_key" ->
- Args#mrargs{start_key=?JSON_DECODE(Val)};
+ Args#mrargs{start_key = ?JSON_DECODE(Val)};
"startkey_docid" ->
- Args#mrargs{start_key_docid=couch_util:to_binary(Val)};
+ Args#mrargs{start_key_docid = couch_util:to_binary(Val)};
"start_key_doc_id" ->
- Args#mrargs{start_key_docid=couch_util:to_binary(Val)};
+ Args#mrargs{start_key_docid = couch_util:to_binary(Val)};
"endkey" when IsDecoded ->
- Args#mrargs{end_key=Val};
+ Args#mrargs{end_key = Val};
"end_key" when IsDecoded ->
- Args#mrargs{end_key=Val};
+ Args#mrargs{end_key = Val};
"endkey" ->
- Args#mrargs{end_key=?JSON_DECODE(Val)};
+ Args#mrargs{end_key = ?JSON_DECODE(Val)};
"end_key" ->
- Args#mrargs{end_key=?JSON_DECODE(Val)};
+ Args#mrargs{end_key = ?JSON_DECODE(Val)};
"endkey_docid" ->
- Args#mrargs{end_key_docid=couch_util:to_binary(Val)};
+ Args#mrargs{end_key_docid = couch_util:to_binary(Val)};
"end_key_doc_id" ->
- Args#mrargs{end_key_docid=couch_util:to_binary(Val)};
+ Args#mrargs{end_key_docid = couch_util:to_binary(Val)};
"limit" ->
- Args#mrargs{limit=parse_pos_int(Val)};
+ Args#mrargs{limit = parse_pos_int(Val)};
"stale" when Val == "ok" orelse Val == <<"ok">> ->
- Args#mrargs{stable=true, update=false};
+ Args#mrargs{stable = true, update = false};
"stale" when Val == "update_after" orelse Val == <<"update_after">> ->
- Args#mrargs{stable=true, update=lazy};
+ Args#mrargs{stable = true, update = lazy};
"stale" ->
throw({query_parse_error, <<"Invalid value for `stale`.">>});
"stable" when Val == "true" orelse Val == <<"true">> orelse Val == true ->
- Args#mrargs{stable=true};
+ Args#mrargs{stable = true};
"stable" when Val == "false" orelse Val == <<"false">> orelse Val == false ->
- Args#mrargs{stable=false};
+ Args#mrargs{stable = false};
"stable" ->
throw({query_parse_error, <<"Invalid value for `stable`.">>});
"update" when Val == "true" orelse Val == <<"true">> orelse Val == true ->
- Args#mrargs{update=true};
+ Args#mrargs{update = true};
"update" when Val == "false" orelse Val == <<"false">> orelse Val == false ->
- Args#mrargs{update=false};
+ Args#mrargs{update = false};
"update" when Val == "lazy" orelse Val == <<"lazy">> ->
- Args#mrargs{update=lazy};
+ Args#mrargs{update = lazy};
"update" ->
throw({query_parse_error, <<"Invalid value for `update`.">>});
"descending" ->
case parse_boolean(Val) of
- true -> Args#mrargs{direction=rev};
- _ -> Args#mrargs{direction=fwd}
+ true -> Args#mrargs{direction = rev};
+ _ -> Args#mrargs{direction = fwd}
end;
"skip" ->
- Args#mrargs{skip=parse_pos_int(Val)};
+ Args#mrargs{skip = parse_pos_int(Val)};
"group" ->
- Args#mrargs{group=parse_boolean(Val)};
+ Args#mrargs{group = parse_boolean(Val)};
"group_level" ->
- Args#mrargs{group_level=parse_pos_int(Val)};
+ Args#mrargs{group_level = parse_pos_int(Val)};
"inclusive_end" ->
- Args#mrargs{inclusive_end=parse_boolean(Val)};
+ Args#mrargs{inclusive_end = parse_boolean(Val)};
"include_docs" ->
- Args#mrargs{include_docs=parse_boolean(Val)};
+ Args#mrargs{include_docs = parse_boolean(Val)};
"attachments" ->
case parse_boolean(Val) of
- true ->
- Opts = Args#mrargs.doc_options,
- Args#mrargs{doc_options=[attachments|Opts]};
- false ->
- Args
+ true ->
+ Opts = Args#mrargs.doc_options,
+ Args#mrargs{doc_options = [attachments | Opts]};
+ false ->
+ Args
end;
"att_encoding_info" ->
case parse_boolean(Val) of
- true ->
- Opts = Args#mrargs.doc_options,
- Args#mrargs{doc_options=[att_encoding_info|Opts]};
- false ->
- Args
+ true ->
+ Opts = Args#mrargs.doc_options,
+ Args#mrargs{doc_options = [att_encoding_info | Opts]};
+ false ->
+ Args
end;
"update_seq" ->
- Args#mrargs{update_seq=parse_boolean(Val)};
+ Args#mrargs{update_seq = parse_boolean(Val)};
"conflicts" ->
- Args#mrargs{conflicts=parse_boolean(Val)};
+ Args#mrargs{conflicts = parse_boolean(Val)};
"callback" ->
- Args#mrargs{callback=couch_util:to_binary(Val)};
+ Args#mrargs{callback = couch_util:to_binary(Val)};
"sorted" ->
- Args#mrargs{sorted=parse_boolean(Val)};
+ Args#mrargs{sorted = parse_boolean(Val)};
"partition" ->
Partition = couch_util:to_binary(Val),
couch_partition:validate_partition(Partition),
@@ -590,52 +625,50 @@ parse_param(Key, Val, Args, IsDecoded) ->
_ ->
BKey = couch_util:to_binary(Key),
BVal = couch_util:to_binary(Val),
- Args#mrargs{extra=[{BKey, BVal} | Args#mrargs.extra]}
+ Args#mrargs{extra = [{BKey, BVal} | Args#mrargs.extra]}
end.
-
parse_boolean(true) ->
true;
parse_boolean(false) ->
false;
-
parse_boolean(Val) when is_binary(Val) ->
parse_boolean(?b2l(Val));
-
parse_boolean(Val) ->
case string:to_lower(Val) of
- "true" -> true;
- "false" -> false;
- _ ->
- Msg = io_lib:format("Invalid boolean parameter: ~p", [Val]),
- throw({query_parse_error, ?l2b(Msg)})
+ "true" ->
+ true;
+ "false" ->
+ false;
+ _ ->
+ Msg = io_lib:format("Invalid boolean parameter: ~p", [Val]),
+ throw({query_parse_error, ?l2b(Msg)})
end.
parse_int(Val) when is_integer(Val) ->
Val;
parse_int(Val) ->
case (catch list_to_integer(Val)) of
- IntVal when is_integer(IntVal) ->
- IntVal;
- _ ->
- Msg = io_lib:format("Invalid value for integer: ~p", [Val]),
- throw({query_parse_error, ?l2b(Msg)})
+ IntVal when is_integer(IntVal) ->
+ IntVal;
+ _ ->
+ Msg = io_lib:format("Invalid value for integer: ~p", [Val]),
+ throw({query_parse_error, ?l2b(Msg)})
end.
parse_pos_int(Val) ->
case parse_int(Val) of
- IntVal when IntVal >= 0 ->
- IntVal;
- _ ->
- Fmt = "Invalid value for positive integer: ~p",
- Msg = io_lib:format(Fmt, [Val]),
- throw({query_parse_error, ?l2b(Msg)})
+ IntVal when IntVal >= 0 ->
+ IntVal;
+ _ ->
+ Fmt = "Invalid value for positive integer: ~p",
+ Msg = io_lib:format(Fmt, [Val]),
+ throw({query_parse_error, ?l2b(Msg)})
end.
-
check_view_etag(Sig, Acc0, Req) ->
ETag = chttpd:make_etag(Sig),
case chttpd:etag_match(Req, ETag) of
true -> throw({etag_match, ETag});
- false -> {ok, Acc0#vacc{etag=ETag}}
+ false -> {ok, Acc0#vacc{etag = ETag}}
end.
diff --git a/src/couch_mrview/src/couch_mrview_index.erl b/src/couch_mrview/src/couch_mrview_index.erl
index 68f1d2322..a024d35c8 100644
--- a/src/couch_mrview/src/couch_mrview_index.erl
+++ b/src/couch_mrview/src/couch_mrview_index.erl
@@ -12,7 +12,6 @@
-module(couch_mrview_index).
-
-export([get/2]).
-export([init/2, open/2, close/1, reset/1, delete/1, shutdown/1]).
-export([start_update/4, purge/4, process_doc/3, finish_update/1, commit/1]).
@@ -24,7 +23,6 @@
-include_lib("couch/include/couch_db.hrl").
-include_lib("couch_mrview/include/couch_mrview.hrl").
-
get(db_name, #mrst{db_name = DbName}) ->
DbName;
get(idx_name, #mrst{idx_name = IdxName}) ->
@@ -39,9 +37,18 @@ get(update_options, #mrst{design_opts = Opts}) ->
IncDesign = couch_util:get_value(<<"include_design">>, Opts, false),
LocalSeq = couch_util:get_value(<<"local_seq">>, Opts, false),
Partitioned = couch_util:get_value(<<"partitioned">>, Opts, false),
- if IncDesign -> [include_design]; true -> [] end
- ++ if LocalSeq -> [local_seq]; true -> [] end
- ++ if Partitioned -> [partitioned]; true -> [] end;
+ if
+ IncDesign -> [include_design];
+ true -> []
+ end ++
+ if
+ LocalSeq -> [local_seq];
+ true -> []
+ end ++
+ if
+ Partitioned -> [partitioned];
+ true -> []
+ end;
get(fd, #mrst{fd = Fd}) ->
Fd;
get(language, #mrst{language = Language}) ->
@@ -69,11 +76,12 @@ get(info, State) ->
{ok, [
{signature, list_to_binary(couch_index_util:hexsig(Sig))},
{language, Lang},
- {sizes, {[
- {file, FileSize},
- {active, ActiveSize},
- {external, ExternalSize}
- ]}},
+ {sizes,
+ {[
+ {file, FileSize},
+ {active, ActiveSize},
+ {external, ExternalSize}
+ ]}},
{update_seq, UpdateSeq},
{purge_seq, PurgeSeq},
{update_options, UpdateOptions}
@@ -81,16 +89,14 @@ get(info, State) ->
get(Other, _) ->
throw({unknown_index_property, Other}).
-
init(Db, DDoc) ->
{ok, State} = couch_mrview_util:ddoc_to_mrst(couch_db:name(Db), DDoc),
{ok, set_partitioned(Db, State)}.
-
open(Db, State0) ->
#mrst{
- db_name=DbName,
- sig=Sig
+ db_name = DbName,
+ sig = Sig
} = State = set_partitioned(Db, State0),
IndexFName = couch_mrview_util:index_file(DbName, Sig),
@@ -128,14 +134,18 @@ open(Db, State0) ->
ensure_local_purge_doc(Db, NewSt),
{ok, NewSt};
{ok, {WrongSig, _}} ->
- couch_log:error("~s has the wrong signature: expected: ~p but got ~p",
- [IndexFName, Sig, WrongSig]),
+ couch_log:error(
+ "~s has the wrong signature: expected: ~p but got ~p",
+ [IndexFName, Sig, WrongSig]
+ ),
NewSt = couch_mrview_util:reset_index(Db, Fd, State),
ensure_local_purge_doc(Db, NewSt),
{ok, NewSt};
{ok, Else} ->
- couch_log:error("~s has a bad header: got ~p",
- [IndexFName, Else]),
+ couch_log:error(
+ "~s has a bad header: got ~p",
+ [IndexFName, Else]
+ ),
NewSt = couch_mrview_util:reset_index(Db, Fd, State),
ensure_local_purge_doc(Db, NewSt),
{ok, NewSt};
@@ -145,17 +155,17 @@ open(Db, State0) ->
{ok, NewSt}
end;
{error, Reason} = Error ->
- couch_log:error("Failed to open view file '~s': ~s",
- [IndexFName, file:format_error(Reason)]),
+ couch_log:error(
+ "Failed to open view file '~s': ~s",
+ [IndexFName, file:format_error(Reason)]
+ ),
Error
end.
-
close(State) ->
erlang:demonitor(State#mrst.fd_monitor, [flush]),
couch_file:close(State#mrst.fd).
-
% This called after ddoc_updated event occurrs, and
% before we shutdown couch_index process.
% We unlink couch_index from corresponding couch_file and demonitor it.
@@ -167,19 +177,16 @@ shutdown(State) ->
erlang:demonitor(State#mrst.fd_monitor, [flush]),
unlink(State#mrst.fd).
-
-delete(#mrst{db_name=DbName, sig=Sig}=State) ->
+delete(#mrst{db_name = DbName, sig = Sig} = State) ->
couch_file:close(State#mrst.fd),
catch couch_mrview_util:delete_files(DbName, Sig).
-
reset(State) ->
couch_util:with_db(State#mrst.db_name, fun(Db) ->
NewState = couch_mrview_util:reset_index(Db, State#mrst.fd, State),
{ok, NewState}
end).
-
start_update(PartialDest, State, NumChanges, NumChangesDone) ->
couch_mrview_updater:start_update(
PartialDest,
@@ -188,94 +195,93 @@ start_update(PartialDest, State, NumChanges, NumChangesDone) ->
NumChangesDone
).
-
purge(Db, PurgeSeq, PurgedIdRevs, State) ->
couch_mrview_updater:purge(Db, PurgeSeq, PurgedIdRevs, State).
-
process_doc(Doc, Seq, State) ->
couch_mrview_updater:process_doc(Doc, Seq, State).
-
finish_update(State) ->
couch_mrview_updater:finish_update(State).
-
commit(State) ->
Header = {State#mrst.sig, couch_mrview_util:make_header(State)},
couch_file:write_header(State#mrst.fd, Header).
-
compact(Db, State, Opts) ->
couch_mrview_compactor:compact(Db, State, Opts).
-
swap_compacted(OldState, NewState) ->
couch_mrview_compactor:swap_compacted(OldState, NewState).
-
remove_compacted(State) ->
couch_mrview_compactor:remove_compacted(State).
-
index_file_exists(State) ->
#mrst{
- db_name=DbName,
- sig=Sig
+ db_name = DbName,
+ sig = Sig
} = State,
IndexFName = couch_mrview_util:index_file(DbName, Sig),
filelib:is_file(IndexFName).
-
verify_index_exists(DbName, Props) ->
try
Type = couch_util:get_value(<<"type">>, Props),
- if Type =/= <<"mrview">> -> false; true ->
- DDocId = couch_util:get_value(<<"ddoc_id">>, Props),
- couch_util:with_db(DbName, fun(Db) ->
- case couch_db:get_design_doc(Db, DDocId) of
- {ok, #doc{} = DDoc} ->
- {ok, IdxState} = couch_mrview_util:ddoc_to_mrst(
- DbName, DDoc),
- IdxSig = IdxState#mrst.sig,
- SigInLocal = couch_util:get_value(
- <<"signature">>, Props),
- couch_index_util:hexsig(IdxSig) == SigInLocal;
- {not_found, _} ->
- false
- end
- end)
+ if
+ Type =/= <<"mrview">> ->
+ false;
+ true ->
+ DDocId = couch_util:get_value(<<"ddoc_id">>, Props),
+ couch_util:with_db(DbName, fun(Db) ->
+ case couch_db:get_design_doc(Db, DDocId) of
+ {ok, #doc{} = DDoc} ->
+ {ok, IdxState} = couch_mrview_util:ddoc_to_mrst(
+ DbName, DDoc
+ ),
+ IdxSig = IdxState#mrst.sig,
+ SigInLocal = couch_util:get_value(
+ <<"signature">>, Props
+ ),
+ couch_index_util:hexsig(IdxSig) == SigInLocal;
+ {not_found, _} ->
+ false
+ end
+ end)
end
- catch _:_ ->
- false
+ catch
+ _:_ ->
+ false
end.
-
set_partitioned(Db, State) ->
#mrst{
design_opts = DesignOpts
} = State,
DbPartitioned = couch_db:is_partitioned(Db),
ViewPartitioned = couch_util:get_value(
- <<"partitioned">>, DesignOpts, DbPartitioned),
+ <<"partitioned">>, DesignOpts, DbPartitioned
+ ),
IsPartitioned = DbPartitioned andalso ViewPartitioned,
State#mrst{partitioned = IsPartitioned}.
-
ensure_local_purge_docs(DbName, DDocs) ->
couch_util:with_db(DbName, fun(Db) ->
- lists:foreach(fun(DDoc) ->
- try couch_mrview_util:ddoc_to_mrst(DbName, DDoc) of
- {ok, MRSt} ->
- ensure_local_purge_doc(Db, MRSt)
- catch _:_ ->
- ok
- end
- end, DDocs)
+ lists:foreach(
+ fun(DDoc) ->
+ try couch_mrview_util:ddoc_to_mrst(DbName, DDoc) of
+ {ok, MRSt} ->
+ ensure_local_purge_doc(Db, MRSt)
+ catch
+ _:_ ->
+ ok
+ end
+ end,
+ DDocs
+ )
end).
-
-ensure_local_purge_doc(Db, #mrst{}=State) ->
+ensure_local_purge_doc(Db, #mrst{} = State) ->
Sig = couch_index_util:hexsig(get(signature, State)),
DocId = couch_mrview_util:get_local_purge_doc_id(Sig),
case couch_db:open_doc(Db, DocId, []) of
@@ -285,33 +291,33 @@ ensure_local_purge_doc(Db, #mrst{}=State) ->
ok
end.
-
create_local_purge_doc(Db, State) ->
PurgeSeq = couch_db:get_purge_seq(Db),
update_local_purge_doc(Db, State, PurgeSeq).
-
update_local_purge_doc(Db, State) ->
update_local_purge_doc(Db, State, get(purge_seq, State)).
-
update_local_purge_doc(Db, State, PSeq) ->
Sig = couch_index_util:hexsig(State#mrst.sig),
DocId = couch_mrview_util:get_local_purge_doc_id(Sig),
{Mega, Secs, _} = os:timestamp(),
NowSecs = Mega * 1000000 + Secs,
- BaseDoc = couch_doc:from_json_obj({[
- {<<"_id">>, DocId},
- {<<"type">>, <<"mrview">>},
- {<<"purge_seq">>, PSeq},
- {<<"updated_on">>, NowSecs},
- {<<"ddoc_id">>, get(idx_name, State)},
- {<<"signature">>, Sig}
- ]}),
- Doc = case couch_db:open_doc(Db, DocId, []) of
- {ok, #doc{revs = Revs}} ->
- BaseDoc#doc{revs = Revs};
- {not_found, _} ->
- BaseDoc
- end,
+ BaseDoc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, DocId},
+ {<<"type">>, <<"mrview">>},
+ {<<"purge_seq">>, PSeq},
+ {<<"updated_on">>, NowSecs},
+ {<<"ddoc_id">>, get(idx_name, State)},
+ {<<"signature">>, Sig}
+ ]}
+ ),
+ Doc =
+ case couch_db:open_doc(Db, DocId, []) of
+ {ok, #doc{revs = Revs}} ->
+ BaseDoc#doc{revs = Revs};
+ {not_found, _} ->
+ BaseDoc
+ end,
couch_db:update_doc(Db, Doc, []).
diff --git a/src/couch_mrview/src/couch_mrview_show.erl b/src/couch_mrview/src/couch_mrview_show.erl
index 0268b706e..3e95be9cc 100644
--- a/src/couch_mrview/src/couch_mrview_show.erl
+++ b/src/couch_mrview/src/couch_mrview_show.erl
@@ -33,23 +33,28 @@ maybe_open_doc(Db, DocId) ->
{not_found, _} -> nil
end.
-handle_doc_show_req(#httpd{
- path_parts=[_, _, _, _, ShowName, DocId]
- }=Req, Db, DDoc) ->
-
+handle_doc_show_req(
+ #httpd{
+ path_parts = [_, _, _, _, ShowName, DocId]
+ } = Req,
+ Db,
+ DDoc
+) ->
% open the doc
Doc = maybe_open_doc(Db, DocId),
% we don't handle revs here b/c they are an internal api
% returns 404 if there is no doc with DocId
handle_doc_show(Req, Db, DDoc, ShowName, Doc, DocId);
-
-handle_doc_show_req(#httpd{
- path_parts=[_, _, _, _, ShowName, DocId|Rest]
- }=Req, Db, DDoc) ->
-
- DocParts = [DocId|Rest],
- DocId1 = ?l2b(string:join([?b2l(P)|| P <- DocParts], "/")),
+handle_doc_show_req(
+ #httpd{
+ path_parts = [_, _, _, _, ShowName, DocId | Rest]
+ } = Req,
+ Db,
+ DDoc
+) ->
+ DocParts = [DocId | Rest],
+ DocId1 = ?l2b(string:join([?b2l(P) || P <- DocParts], "/")),
% open the doc
Doc = maybe_open_doc(Db, DocId1),
@@ -57,13 +62,15 @@ handle_doc_show_req(#httpd{
% we don't handle revs here b/c they are an internal api
% pass 404 docs to the show function
handle_doc_show(Req, Db, DDoc, ShowName, Doc, DocId1);
-
-handle_doc_show_req(#httpd{
- path_parts=[_, _, _, _, ShowName]
- }=Req, Db, DDoc) ->
+handle_doc_show_req(
+ #httpd{
+ path_parts = [_, _, _, _, ShowName]
+ } = Req,
+ Db,
+ DDoc
+) ->
% with no docid the doc is nil
handle_doc_show(Req, Db, DDoc, ShowName, nil);
-
handle_doc_show_req(Req, _Db, _DDoc) ->
chttpd:send_error(Req, 404, <<"show_error">>, <<"Invalid path.">>).
@@ -77,21 +84,29 @@ handle_doc_show(Req, Db, DDoc, ShowName, Doc, DocId) ->
JsonReq = chttpd_external:json_req_obj(Req, Db, DocId),
JsonDoc = couch_query_servers:json_doc(Doc),
[<<"resp">>, ExternalResp] =
- couch_query_servers:ddoc_prompt(DDoc, [<<"shows">>, ShowName],
- [JsonDoc, JsonReq]),
+ couch_query_servers:ddoc_prompt(
+ DDoc,
+ [<<"shows">>, ShowName],
+ [JsonDoc, JsonReq]
+ ),
JsonResp = apply_etag(ExternalResp, CurrentEtag),
chttpd_external:send_external_response(Req, JsonResp)
end).
-
-show_etag(#httpd{user_ctx=UserCtx}=Req, Doc, DDoc, More) ->
+show_etag(#httpd{user_ctx = UserCtx} = Req, Doc, DDoc, More) ->
Accept = chttpd:header_value(Req, "Accept"),
- DocPart = case Doc of
- nil -> nil;
- Doc -> chttpd:doc_etag(Doc)
- end,
- chttpd:make_etag({chttpd:doc_etag(DDoc), DocPart, Accept,
- {UserCtx#user_ctx.name, UserCtx#user_ctx.roles}, More}).
+ DocPart =
+ case Doc of
+ nil -> nil;
+ Doc -> chttpd:doc_etag(Doc)
+ end,
+ chttpd:make_etag({
+ chttpd:doc_etag(DDoc),
+ DocPart,
+ Accept,
+ {UserCtx#user_ctx.name, UserCtx#user_ctx.roles},
+ More
+ }).
% updates a doc based on a request
% handle_doc_update_req(#httpd{method = 'GET'}=Req, _Db, _DDoc) ->
@@ -101,20 +116,25 @@ show_etag(#httpd{user_ctx=UserCtx}=Req, Doc, DDoc, More) ->
% This call is creating a new doc using an _update function to
% modify the provided request body.
% /db/_design/foo/_update/bar
-handle_doc_update_req(#httpd{
- path_parts=[_, _, _, _, UpdateName]
- }=Req, Db, DDoc) ->
+handle_doc_update_req(
+ #httpd{
+ path_parts = [_, _, _, _, UpdateName]
+ } = Req,
+ Db,
+ DDoc
+) ->
send_doc_update_response(Req, Db, DDoc, UpdateName, nil, null);
-
% /db/_design/foo/_update/bar/docid
-handle_doc_update_req(#httpd{
- path_parts=[_, _, _, _, UpdateName | DocIdParts]
- }=Req, Db, DDoc) ->
+handle_doc_update_req(
+ #httpd{
+ path_parts = [_, _, _, _, UpdateName | DocIdParts]
+ } = Req,
+ Db,
+ DDoc
+) ->
DocId = ?l2b(string:join([?b2l(P) || P <- DocIdParts], "/")),
Doc = maybe_open_doc(Db, DocId),
send_doc_update_response(Req, Db, DDoc, UpdateName, Doc, DocId);
-
-
handle_doc_update_req(Req, _Db, _DDoc) ->
chttpd:send_error(Req, 404, <<"update_error">>, <<"Invalid path.">>).
@@ -123,32 +143,36 @@ send_doc_update_response(Req, Db, DDoc, UpdateName, Doc, DocId) ->
JsonDoc = couch_query_servers:json_doc(Doc),
Cmd = [<<"updates">>, UpdateName],
UpdateResp = couch_query_servers:ddoc_prompt(DDoc, Cmd, [JsonDoc, JsonReq]),
- JsonResp = case UpdateResp of
- [<<"up">>, {NewJsonDoc}, {JsonResp0}] ->
- case chttpd:header_value(
- Req, "X-Couch-Full-Commit", "false") of
- "true" ->
- Options = [full_commit, {user_ctx, Req#httpd.user_ctx}];
- _ ->
- Options = [{user_ctx, Req#httpd.user_ctx}]
- end,
- NewDoc = couch_db:doc_from_json_obj_validate(Db, {NewJsonDoc}),
- {ok, NewRev} = couch_db:update_doc(Db, NewDoc, Options),
- NewRevStr = couch_doc:rev_to_str(NewRev),
- {JsonResp1} = apply_headers(JsonResp0, [
- {<<"X-Couch-Update-NewRev">>, NewRevStr},
- {<<"X-Couch-Id">>, couch_util:url_encode(NewDoc#doc.id)}
- ]),
- {[{<<"code">>, 201} | JsonResp1]};
- [<<"up">>, _Other, {JsonResp0}] ->
- {[{<<"code">>, 200} | JsonResp0]}
- end,
+ JsonResp =
+ case UpdateResp of
+ [<<"up">>, {NewJsonDoc}, {JsonResp0}] ->
+ case
+ chttpd:header_value(
+ Req, "X-Couch-Full-Commit", "false"
+ )
+ of
+ "true" ->
+ Options = [full_commit, {user_ctx, Req#httpd.user_ctx}];
+ _ ->
+ Options = [{user_ctx, Req#httpd.user_ctx}]
+ end,
+ NewDoc = couch_db:doc_from_json_obj_validate(Db, {NewJsonDoc}),
+ {ok, NewRev} = couch_db:update_doc(Db, NewDoc, Options),
+ NewRevStr = couch_doc:rev_to_str(NewRev),
+ {JsonResp1} = apply_headers(JsonResp0, [
+ {<<"X-Couch-Update-NewRev">>, NewRevStr},
+ {<<"X-Couch-Id">>, couch_util:url_encode(NewDoc#doc.id)}
+ ]),
+ {[{<<"code">>, 201} | JsonResp1]};
+ [<<"up">>, _Other, {JsonResp0}] ->
+ {[{<<"code">>, 200} | JsonResp0]}
+ end,
% todo set location field
chttpd_external:send_external_response(Req, JsonResp).
-
-handle_view_list_req(#httpd{method=Method}=Req, Db, DDoc)
- when Method =:= 'GET' orelse Method =:= 'OPTIONS' ->
+handle_view_list_req(#httpd{method = Method} = Req, Db, DDoc) when
+ Method =:= 'GET' orelse Method =:= 'OPTIONS'
+->
case Req#httpd.path_parts of
[_, _, _DName, _, LName, VName] ->
% Same design doc for view and list
@@ -161,7 +185,7 @@ handle_view_list_req(#httpd{method=Method}=Req, Db, DDoc)
_ ->
chttpd:send_error(Req, 404, <<"list_error">>, <<"Bad path.">>)
end;
-handle_view_list_req(#httpd{method='POST'}=Req, Db, DDoc) ->
+handle_view_list_req(#httpd{method = 'POST'} = Req, Db, DDoc) ->
chttpd:validate_ctype(Req, "application/json"),
{Props} = chttpd:json_body_obj(Req),
Keys = proplists:get_value(<<"keys">>, Props),
@@ -179,7 +203,6 @@ handle_view_list_req(#httpd{method='POST'}=Req, Db, DDoc) ->
handle_view_list_req(Req, _Db, _DDoc) ->
chttpd:send_method_not_allowed(Req, "GET,POST,HEAD").
-
handle_view_list(Req, Db, DDoc, LName, VDDoc, VName, Keys) ->
Args0 = couch_mrview_http:parse_body_and_query(Req, Keys),
ETagFun = fun(BaseSig, Acc0) ->
@@ -191,67 +214,73 @@ handle_view_list(Req, Db, DDoc, LName, VDDoc, VName, Keys) ->
ETag = chttpd:make_etag({BaseSig, Parts}),
case chttpd:etag_match(Req, ETag) of
true -> throw({etag_match, ETag});
- false -> {ok, Acc0#lacc{etag=ETag}}
+ false -> {ok, Acc0#lacc{etag = ETag}}
end
end,
- Args = Args0#mrargs{preflight_fun=ETagFun},
+ Args = Args0#mrargs{preflight_fun = ETagFun},
couch_httpd:etag_maybe(Req, fun() ->
couch_query_servers:with_ddoc_proc(DDoc, fun(QServer) ->
- Acc = #lacc{db=Db, req=Req, qserver=QServer, lname=LName},
+ Acc = #lacc{db = Db, req = Req, qserver = QServer, lname = LName},
case VName of
- <<"_all_docs">> ->
- couch_mrview:query_all_docs(Db, Args, fun list_cb/2, Acc);
- _ ->
- couch_mrview:query_view(Db, VDDoc, VName, Args, fun list_cb/2, Acc)
+ <<"_all_docs">> ->
+ couch_mrview:query_all_docs(Db, Args, fun list_cb/2, Acc);
+ _ ->
+ couch_mrview:query_view(Db, VDDoc, VName, Args, fun list_cb/2, Acc)
end
end)
end).
-
-list_cb({meta, Meta}, #lacc{code=undefined} = Acc) ->
- MetaProps = case couch_util:get_value(total, Meta) of
- undefined -> [];
- Total -> [{total_rows, Total}]
- end ++ case couch_util:get_value(offset, Meta) of
- undefined -> [];
- Offset -> [{offset, Offset}]
- end ++ case couch_util:get_value(update_seq, Meta) of
- undefined -> [];
- UpdateSeq -> [{update_seq, UpdateSeq}]
- end,
+list_cb({meta, Meta}, #lacc{code = undefined} = Acc) ->
+ MetaProps =
+ case couch_util:get_value(total, Meta) of
+ undefined -> [];
+ Total -> [{total_rows, Total}]
+ end ++
+ case couch_util:get_value(offset, Meta) of
+ undefined -> [];
+ Offset -> [{offset, Offset}]
+ end ++
+ case couch_util:get_value(update_seq, Meta) of
+ undefined -> [];
+ UpdateSeq -> [{update_seq, UpdateSeq}]
+ end,
start_list_resp({MetaProps}, Acc);
-list_cb({row, Row}, #lacc{code=undefined} = Acc) ->
+list_cb({row, Row}, #lacc{code = undefined} = Acc) ->
{ok, NewAcc} = start_list_resp({[]}, Acc),
send_list_row(Row, NewAcc);
list_cb({row, Row}, Acc) ->
send_list_row(Row, Acc);
list_cb(complete, Acc) ->
#lacc{qserver = {Proc, _}, req = Req, resp = Resp0} = Acc,
- if Resp0 =:= nil ->
- {ok, #lacc{resp = Resp}} = start_list_resp({[]}, Acc);
- true ->
- Resp = Resp0
+ if
+ Resp0 =:= nil ->
+ {ok, #lacc{resp = Resp}} = start_list_resp({[]}, Acc);
+ true ->
+ Resp = Resp0
end,
case couch_query_servers:proc_prompt(Proc, [<<"list_end">>]) of
[<<"end">>, Data, Headers] ->
- Acc2 = fixup_headers(Headers, Acc#lacc{resp=Resp}),
+ Acc2 = fixup_headers(Headers, Acc#lacc{resp = Resp}),
#lacc{resp = Resp2} = send_non_empty_chunk(Acc2, Data);
[<<"end">>, Data] ->
- #lacc{resp = Resp2} = send_non_empty_chunk(Acc#lacc{resp=Resp}, Data)
+ #lacc{resp = Resp2} = send_non_empty_chunk(Acc#lacc{resp = Resp}, Data)
end,
last_chunk(Req, Resp2),
{ok, Resp2}.
start_list_resp(Head, Acc) ->
- #lacc{db=Db, req=Req, qserver=QServer, lname=LName} = Acc,
+ #lacc{db = Db, req = Req, qserver = QServer, lname = LName} = Acc,
JsonReq = json_req_obj(Req, Db),
- [<<"start">>,Chunk,JsonResp] = couch_query_servers:ddoc_proc_prompt(QServer,
- [<<"lists">>, LName], [Head, JsonReq]),
+ [<<"start">>, Chunk, JsonResp] = couch_query_servers:ddoc_proc_prompt(
+ QServer,
+ [<<"lists">>, LName],
+ [Head, JsonReq]
+ ),
Acc2 = send_non_empty_chunk(fixup_headers(JsonResp, Acc), Chunk),
{ok, Acc2}.
-fixup_headers(Headers, #lacc{etag=ETag} = Acc) ->
+fixup_headers(Headers, #lacc{etag = ETag} = Acc) ->
Headers2 = apply_etag(Headers, ETag),
#extern_resp_args{
code = Code,
@@ -260,61 +289,66 @@ fixup_headers(Headers, #lacc{etag=ETag} = Acc) ->
} = chttpd_external:parse_external_response(Headers2),
Headers3 = chttpd_external:default_or_content_type(CType, ExtHeaders),
Headers4 = chttpd_util:maybe_add_csp_header("showlist", Headers3, "sandbox"),
- Acc#lacc{code=Code, headers=Headers4}.
+ Acc#lacc{code = Code, headers = Headers4}.
send_list_row(Row, #lacc{qserver = {Proc, _}, req = Req, resp = Resp} = Acc) ->
- RowObj = case couch_util:get_value(id, Row) of
- undefined -> [];
- Id -> [{id, Id}]
- end ++ case couch_util:get_value(key, Row) of
- undefined -> [];
- Key -> [{key, Key}]
- end ++ case couch_util:get_value(value, Row) of
- undefined -> [];
- Val -> [{value, Val}]
- end ++ case couch_util:get_value(doc, Row) of
- undefined -> [];
- Doc -> [{doc, Doc}]
- end,
+ RowObj =
+ case couch_util:get_value(id, Row) of
+ undefined -> [];
+ Id -> [{id, Id}]
+ end ++
+ case couch_util:get_value(key, Row) of
+ undefined -> [];
+ Key -> [{key, Key}]
+ end ++
+ case couch_util:get_value(value, Row) of
+ undefined -> [];
+ Val -> [{value, Val}]
+ end ++
+ case couch_util:get_value(doc, Row) of
+ undefined -> [];
+ Doc -> [{doc, Doc}]
+ end,
try couch_query_servers:proc_prompt(Proc, [<<"list_row">>, {RowObj}]) of
- [<<"chunks">>, Chunk, Headers] ->
- Acc2 = send_non_empty_chunk(fixup_headers(Headers, Acc), Chunk),
- {ok, Acc2};
- [<<"chunks">>, Chunk] ->
- Acc2 = send_non_empty_chunk(Acc, Chunk),
- {ok, Acc2};
- [<<"end">>, Chunk, Headers] ->
- #lacc{resp = Resp2} = send_non_empty_chunk(fixup_headers(Headers, Acc), Chunk),
- {ok, Resp3} = last_chunk(Req, Resp2),
- {stop, Resp3};
- [<<"end">>, Chunk] ->
- #lacc{resp = Resp2} = send_non_empty_chunk(Acc, Chunk),
- {ok, Resp3} = last_chunk(Req, Resp2),
- {stop, Resp3}
- catch Error ->
- {ok, Resp2} = case Resp of
- undefined ->
- {Code, _, _} = chttpd:error_info(Error),
- #lacc{req=Req, headers=Headers} = Acc,
- chttpd:start_chunked_response(Req, Code, Headers);
- _ ->
- {ok, Resp}
- end,
- {ok, Resp3} = chttpd:send_chunked_error(Resp2, Error),
- {stop, Resp3}
+ [<<"chunks">>, Chunk, Headers] ->
+ Acc2 = send_non_empty_chunk(fixup_headers(Headers, Acc), Chunk),
+ {ok, Acc2};
+ [<<"chunks">>, Chunk] ->
+ Acc2 = send_non_empty_chunk(Acc, Chunk),
+ {ok, Acc2};
+ [<<"end">>, Chunk, Headers] ->
+ #lacc{resp = Resp2} = send_non_empty_chunk(fixup_headers(Headers, Acc), Chunk),
+ {ok, Resp3} = last_chunk(Req, Resp2),
+ {stop, Resp3};
+ [<<"end">>, Chunk] ->
+ #lacc{resp = Resp2} = send_non_empty_chunk(Acc, Chunk),
+ {ok, Resp3} = last_chunk(Req, Resp2),
+ {stop, Resp3}
+ catch
+ Error ->
+ {ok, Resp2} =
+ case Resp of
+ undefined ->
+ {Code, _, _} = chttpd:error_info(Error),
+ #lacc{req = Req, headers = Headers} = Acc,
+ chttpd:start_chunked_response(Req, Code, Headers);
+ _ ->
+ {ok, Resp}
+ end,
+ {ok, Resp3} = chttpd:send_chunked_error(Resp2, Error),
+ {stop, Resp3}
end.
send_non_empty_chunk(Acc, []) ->
Acc;
-send_non_empty_chunk(#lacc{resp=undefined} = Acc, Chunk) ->
- #lacc{req=Req, code=Code, headers=Headers} = Acc,
+send_non_empty_chunk(#lacc{resp = undefined} = Acc, Chunk) ->
+ #lacc{req = Req, code = Code, headers = Headers} = Acc,
{ok, Resp} = chttpd:start_chunked_response(Req, Code, Headers),
send_non_empty_chunk(Acc#lacc{resp = Resp}, Chunk);
-send_non_empty_chunk(#lacc{resp=Resp} = Acc, Chunk) ->
+send_non_empty_chunk(#lacc{resp = Resp} = Acc, Chunk) ->
chttpd:send_chunk(Resp, Chunk),
Acc.
-
apply_etag(JsonResp, undefined) ->
JsonResp;
apply_etag({ExternalResponse}, CurrentEtag) ->
@@ -332,7 +366,7 @@ apply_headers(JsonResp, []) ->
apply_headers(JsonResp, NewHeaders) ->
case couch_util:get_value(<<"headers">>, JsonResp) of
undefined ->
- {[{<<"headers">>, {NewHeaders}}| JsonResp]};
+ {[{<<"headers">>, {NewHeaders}} | JsonResp]};
JsonHeaders ->
Headers = apply_headers1(JsonHeaders, NewHeaders),
NewKV = {<<"headers">>, Headers},
@@ -344,13 +378,11 @@ apply_headers1(JsonHeaders, [{Key, Value} | Rest]) ->
apply_headers1(JsonHeaders, []) ->
JsonHeaders.
-
% Maybe this is in the proplists API
% todo move to couch_util
json_apply_field(H, {L}) ->
json_apply_field(H, L, []).
-
json_apply_field({Key, NewValue}, [{Key, _OldVal} | Headers], Acc) ->
% drop matching keys
json_apply_field({Key, NewValue}, Headers, Acc);
@@ -359,8 +391,7 @@ json_apply_field({Key, NewValue}, [{OtherKey, OtherVal} | Headers], Acc) ->
json_apply_field({Key, NewValue}, Headers, [{OtherKey, OtherVal} | Acc]);
json_apply_field({Key, NewValue}, [], Acc) ->
% end of list, add ours
- {[{Key, NewValue}|Acc]}.
-
+ {[{Key, NewValue} | Acc]}.
% This loads the db info if we have a fully loaded db record, but we might not
% have the db locally on this node, so then load the info through fabric.
@@ -371,7 +402,9 @@ json_req_obj(Req, Db) ->
% and json_req_obj calls fabric:get_db_info()
JRO = fun() -> exit(chttpd_external:json_req_obj(Req, Db)) end,
{Pid, Ref} = spawn_monitor(JRO),
- receive {'DOWN', Ref, process, Pid, JsonReq} -> JsonReq end;
+ receive
+ {'DOWN', Ref, process, Pid, JsonReq} -> JsonReq
+ end;
false ->
chttpd_external:json_req_obj(Req, Db)
end.
@@ -381,7 +414,6 @@ last_chunk(Req, undefined) ->
last_chunk(_Req, Resp) ->
chttpd:send_chunk(Resp, []).
-
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
@@ -395,7 +427,7 @@ apply_headers_test_() ->
should_apply_headers() ->
?_test(begin
JsonResp = [{<<"code">>, 201}],
- Headers = [{<<"foo">>, <<"bar">>}],
+ Headers = [{<<"foo">>, <<"bar">>}],
{Props} = apply_headers(JsonResp, Headers),
JsonHeaders = couch_util:get_value(<<"headers">>, Props),
?assertEqual({Headers}, JsonHeaders)
@@ -404,7 +436,7 @@ should_apply_headers() ->
should_apply_headers_with_merge() ->
?_test(begin
BaseHeaders = [{<<"bar">>, <<"baz">>}],
- NewHeaders = [{<<"foo">>, <<"bar">>}],
+ NewHeaders = [{<<"foo">>, <<"bar">>}],
JsonResp = [
{<<"code">>, 201},
{<<"headers">>, {BaseHeaders}}
@@ -418,7 +450,7 @@ should_apply_headers_with_merge() ->
should_apply_headers_with_merge_overwrite() ->
?_test(begin
BaseHeaders = [{<<"foo">>, <<"bar">>}],
- NewHeaders = [{<<"foo">>, <<"baz">>}],
+ NewHeaders = [{<<"foo">>, <<"baz">>}],
JsonResp = [
{<<"code">>, 201},
{<<"headers">>, {BaseHeaders}}
@@ -428,7 +460,6 @@ should_apply_headers_with_merge_overwrite() ->
?assertEqual({NewHeaders}, JsonHeaders)
end).
-
send_list_row_test_() ->
Cases = couch_tests_combinatorics:product([
[
@@ -439,26 +470,40 @@ send_list_row_test_() ->
[
req,
undefined
- ]]),
+ ]
+ ]),
{"Ensure send_list_row returns a valid response on end or error",
{setup, fun setup/0, fun(_) -> meck:unload() end, [
{
lists:flatten(io_lib:format("~s -- ~p", [N, R])),
should_return_valid_response(F, R)
- } || [{N, F}, R] <- Cases
- ]}
- }.
+ }
+ || [{N, F}, R] <- Cases
+ ]}}.
setup() ->
ok = application:start(config, permanent),
- ok = meck:expect(chttpd, send_chunk,
- fun(Resp, _) -> {ok, Resp} end),
- ok = meck:expect(chttpd, send_chunked_error,
- fun(Resp, _) -> {ok, Resp} end),
- ok = meck:expect(chttpd, start_chunked_response,
- fun(_, _, _) -> {ok, resp} end),
- ok = meck:expect(chttpd_external, parse_external_response, 1,
- #extern_resp_args{headers = []}).
+ ok = meck:expect(
+ chttpd,
+ send_chunk,
+ fun(Resp, _) -> {ok, Resp} end
+ ),
+ ok = meck:expect(
+ chttpd,
+ send_chunked_error,
+ fun(Resp, _) -> {ok, Resp} end
+ ),
+ ok = meck:expect(
+ chttpd,
+ start_chunked_response,
+ fun(_, _, _) -> {ok, resp} end
+ ),
+ ok = meck:expect(
+ chttpd_external,
+ parse_external_response,
+ 1,
+ #extern_resp_args{headers = []}
+ ).
should_return_valid_response(Spec, Req) ->
?_test(begin
diff --git a/src/couch_mrview/src/couch_mrview_test_util.erl b/src/couch_mrview/src/couch_mrview_test_util.erl
index 2dfa64e61..918988ea3 100644
--- a/src/couch_mrview/src/couch_mrview_test_util.erl
+++ b/src/couch_mrview/src/couch_mrview_test_util.erl
@@ -18,17 +18,14 @@
-include_lib("couch/include/couch_db.hrl").
-include_lib("couch/include/couch_eunit.hrl").
-
init_db(Name, Type) ->
init_db(Name, Type, 10).
-
init_db(Name, Type, Count) ->
{ok, Db} = new_db(Name, Type),
Docs = make_docs(Type, Count),
save_docs(Db, Docs).
-
new_db(Name, Type) when Type == local; Type == design ->
couch_server:delete(Name, [?ADMIN_CTX]),
couch_db:create(Name, [?ADMIN_CTX]);
@@ -44,80 +41,96 @@ save_docs(Db, Docs) ->
{ok, _} = couch_db:update_docs(Db, Docs, []),
couch_db:reopen(Db).
-
make_docs(local, Count) ->
[local_doc(I) || I <- lists:seq(1, Count)];
make_docs(design, Count) ->
- lists:foldl(fun(I, Acc) ->
- [doc(I), ddoc(I) | Acc]
- end, [], lists:seq(1, Count));
+ lists:foldl(
+ fun(I, Acc) ->
+ [doc(I), ddoc(I) | Acc]
+ end,
+ [],
+ lists:seq(1, Count)
+ );
make_docs(_, Count) ->
[doc(I) || I <- lists:seq(1, Count)].
-
make_docs(_, Since, Count) ->
[doc(I) || I <- lists:seq(Since, Count)].
-
ddoc(map) ->
- couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/bar">>},
- {<<"views">>, {[
- {<<"baz">>, {[
- {<<"map">>, <<"function(doc) {emit(doc.val, doc.val);}">>}
- ]}},
- {<<"bing">>, {[
- {<<"map">>, <<"function(doc) {}">>}
- ]}},
- {<<"zing">>, {[
- {<<"map">>, <<
- "function(doc) {\n"
- " if(doc.foo !== undefined)\n"
- " emit(doc.foo, 0);\n"
- "}"
- >>}
- ]}}
- ]}}
- ]});
+ couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/bar">>},
+ {<<"views">>,
+ {[
+ {<<"baz">>,
+ {[
+ {<<"map">>, <<"function(doc) {emit(doc.val, doc.val);}">>}
+ ]}},
+ {<<"bing">>,
+ {[
+ {<<"map">>, <<"function(doc) {}">>}
+ ]}},
+ {<<"zing">>,
+ {[
+ {<<"map">>, <<
+ "function(doc) {\n"
+ " if(doc.foo !== undefined)\n"
+ " emit(doc.foo, 0);\n"
+ "}"
+ >>}
+ ]}}
+ ]}}
+ ]}
+ );
ddoc(red) ->
- couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/red">>},
- {<<"views">>, {[
- {<<"baz">>, {[
- {<<"map">>, <<
- "function(doc) {\n"
- " emit([doc.val % 2, doc.val], doc.val);\n"
- "}\n"
- >>},
- {<<"reduce">>, <<"function(keys, vals) {return sum(vals);}">>}
- ]}},
- {<<"zing">>, {[
- {<<"map">>, <<
- "function(doc) {\n"
- " if(doc.foo !== undefined)\n"
- " emit(doc.foo, null);\n"
- "}"
- >>},
- {<<"reduce">>, <<"_count">>}
- ]}}
- ]}}
- ]});
+ couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/red">>},
+ {<<"views">>,
+ {[
+ {<<"baz">>,
+ {[
+ {<<"map">>, <<
+ "function(doc) {\n"
+ " emit([doc.val % 2, doc.val], doc.val);\n"
+ "}\n"
+ >>},
+ {<<"reduce">>, <<"function(keys, vals) {return sum(vals);}">>}
+ ]}},
+ {<<"zing">>,
+ {[
+ {<<"map">>, <<
+ "function(doc) {\n"
+ " if(doc.foo !== undefined)\n"
+ " emit(doc.foo, null);\n"
+ "}"
+ >>},
+ {<<"reduce">>, <<"_count">>}
+ ]}}
+ ]}}
+ ]}
+ );
ddoc(Id) ->
- couch_doc:from_json_obj({[
- {<<"_id">>, list_to_binary(io_lib:format("_design/bar~2..0b", [Id]))},
- {<<"views">>, {[]}}
- ]}).
-
+ couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, list_to_binary(io_lib:format("_design/bar~2..0b", [Id]))},
+ {<<"views">>, {[]}}
+ ]}
+ ).
doc(Id) ->
- couch_doc:from_json_obj({[
- {<<"_id">>, list_to_binary(integer_to_list(Id))},
- {<<"val">>, Id}
- ]}).
-
+ couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, list_to_binary(integer_to_list(Id))},
+ {<<"val">>, Id}
+ ]}
+ ).
local_doc(Id) ->
- couch_doc:from_json_obj({[
- {<<"_id">>, list_to_binary(io_lib:format("_local/~b", [Id]))},
- {<<"val">>, Id}
- ]}).
+ couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, list_to_binary(io_lib:format("_local/~b", [Id]))},
+ {<<"val">>, Id}
+ ]}
+ ).
diff --git a/src/couch_mrview/src/couch_mrview_update_notifier.erl b/src/couch_mrview/src/couch_mrview_update_notifier.erl
index 803d39747..ac91131a0 100644
--- a/src/couch_mrview/src/couch_mrview_update_notifier.erl
+++ b/src/couch_mrview/src/couch_mrview_update_notifier.erl
@@ -20,7 +20,9 @@
-include_lib("couch/include/couch_db.hrl").
start_link(Exec) ->
- couch_event_sup:start_link(couch_mrview_update, {couch_mrview_update_notifier, make_ref()}, Exec).
+ couch_event_sup:start_link(
+ couch_mrview_update, {couch_mrview_update_notifier, make_ref()}, Exec
+ ).
notify(Event) ->
gen_event:notify(couch_mrview_update, Event).
diff --git a/src/couch_mrview/src/couch_mrview_updater.erl b/src/couch_mrview/src/couch_mrview_updater.erl
index 522367c1d..969a82028 100644
--- a/src/couch_mrview/src/couch_mrview_updater.erl
+++ b/src/couch_mrview/src/couch_mrview_updater.erl
@@ -26,22 +26,25 @@ start_update(Partial, State, NumChanges, NumChangesDone) ->
{ok, DocQueue} = couch_work_queue:new(QueueOpts),
{ok, WriteQueue} = couch_work_queue:new(QueueOpts),
InitState = State#mrst{
- first_build=State#mrst.update_seq==0,
- partial_resp_pid=Partial,
- doc_acc=[],
- doc_queue=DocQueue,
- write_queue=WriteQueue
+ first_build = State#mrst.update_seq == 0,
+ partial_resp_pid = Partial,
+ doc_acc = [],
+ doc_queue = DocQueue,
+ write_queue = WriteQueue
},
Self = self(),
MapFun = fun() ->
- erlang:put(io_priority,
- {view_update, State#mrst.db_name, State#mrst.idx_name}),
- Progress = case NumChanges of
- 0 -> 0;
- _ -> (NumChangesDone * 100) div NumChanges
- end,
+ erlang:put(
+ io_priority,
+ {view_update, State#mrst.db_name, State#mrst.idx_name}
+ ),
+ Progress =
+ case NumChanges of
+ 0 -> 0;
+ _ -> (NumChangesDone * 100) div NumChanges
+ end,
couch_task_status:add_task([
{indexer_pid, ?l2b(pid_to_list(Partial))},
{type, indexer},
@@ -55,8 +58,10 @@ start_update(Partial, State, NumChanges, NumChangesDone) ->
map_docs(Self, InitState)
end,
WriteFun = fun() ->
- erlang:put(io_priority,
- {view_update, State#mrst.db_name, State#mrst.idx_name}),
+ erlang:put(
+ io_priority,
+ {view_update, State#mrst.db_name, State#mrst.idx_name}
+ ),
write_results(Self, InitState)
end,
spawn_link(MapFun),
@@ -64,12 +69,11 @@ start_update(Partial, State, NumChanges, NumChangesDone) ->
{ok, InitState}.
-
purge(_Db, PurgeSeq, PurgedIdRevs, State) ->
#mrst{
- id_btree=IdBtree,
- views=Views,
- partitioned=Partitioned
+ id_btree = IdBtree,
+ views = Views,
+ partitioned = Partitioned
} = State,
Ids = [Id || {Id, _Revs} <- PurgedIdRevs],
@@ -81,10 +85,14 @@ purge(_Db, PurgeSeq, PurgedIdRevs, State) ->
({ViewNum, {Key, Seq, _Op}}, DictAcc2) ->
dict:append(ViewNum, {Key, Seq, DocId}, DictAcc2);
({ViewNum, RowKey0}, DictAcc2) ->
- RowKey = if not Partitioned -> RowKey0; true ->
- [{RK, _}] = inject_partition([{RowKey0, DocId}]),
- RK
- end,
+ RowKey =
+ if
+ not Partitioned ->
+ RowKey0;
+ true ->
+ [{RK, _}] = inject_partition([{RowKey0, DocId}]),
+ RK
+ end,
dict:append(ViewNum, {RowKey, DocId}, DictAcc2)
end,
lists:foldl(FoldFun, DictAcc, ViewNumRowKeys);
@@ -93,54 +101,54 @@ purge(_Db, PurgeSeq, PurgedIdRevs, State) ->
end,
KeysToRemove = lists:foldl(MakeDictFun, dict:new(), Lookups),
- RemKeysFun = fun(#mrview{id_num=ViewId}=View) ->
+ RemKeysFun = fun(#mrview{id_num = ViewId} = View) ->
ToRem = couch_util:dict_find(ViewId, KeysToRemove, []),
{ok, VBtree2} = couch_btree:add_remove(View#mrview.btree, [], ToRem),
- NewPurgeSeq = case VBtree2 =/= View#mrview.btree of
- true -> PurgeSeq;
- _ -> View#mrview.purge_seq
- end,
- View#mrview{btree=VBtree2, purge_seq=NewPurgeSeq}
+ NewPurgeSeq =
+ case VBtree2 =/= View#mrview.btree of
+ true -> PurgeSeq;
+ _ -> View#mrview.purge_seq
+ end,
+ View#mrview{btree = VBtree2, purge_seq = NewPurgeSeq}
end,
Views2 = lists:map(RemKeysFun, Views),
{ok, State#mrst{
- id_btree=IdBtree2,
- views=Views2,
- purge_seq=PurgeSeq
+ id_btree = IdBtree2,
+ views = Views2,
+ purge_seq = PurgeSeq
}}.
-
-process_doc(Doc, Seq, #mrst{doc_acc=Acc}=State) when length(Acc) > 100 ->
+process_doc(Doc, Seq, #mrst{doc_acc = Acc} = State) when length(Acc) > 100 ->
couch_work_queue:queue(State#mrst.doc_queue, lists:reverse(Acc)),
- process_doc(Doc, Seq, State#mrst{doc_acc=[]});
-process_doc(nil, Seq, #mrst{doc_acc=Acc}=State) ->
- {ok, State#mrst{doc_acc=[{nil, Seq, nil} | Acc]}};
-process_doc(#doc{id=Id, deleted=true}, Seq, #mrst{doc_acc=Acc}=State) ->
- {ok, State#mrst{doc_acc=[{Id, Seq, deleted} | Acc]}};
-process_doc(#doc{id=Id}=Doc, Seq, #mrst{doc_acc=Acc}=State) ->
- {ok, State#mrst{doc_acc=[{Id, Seq, Doc} | Acc]}}.
-
-
-finish_update(#mrst{doc_acc=Acc}=State) ->
- if Acc /= [] ->
- couch_work_queue:queue(State#mrst.doc_queue, Acc);
- true -> ok
+ process_doc(Doc, Seq, State#mrst{doc_acc = []});
+process_doc(nil, Seq, #mrst{doc_acc = Acc} = State) ->
+ {ok, State#mrst{doc_acc = [{nil, Seq, nil} | Acc]}};
+process_doc(#doc{id = Id, deleted = true}, Seq, #mrst{doc_acc = Acc} = State) ->
+ {ok, State#mrst{doc_acc = [{Id, Seq, deleted} | Acc]}};
+process_doc(#doc{id = Id} = Doc, Seq, #mrst{doc_acc = Acc} = State) ->
+ {ok, State#mrst{doc_acc = [{Id, Seq, Doc} | Acc]}}.
+
+finish_update(#mrst{doc_acc = Acc} = State) ->
+ if
+ Acc /= [] ->
+ couch_work_queue:queue(State#mrst.doc_queue, Acc);
+ true ->
+ ok
end,
couch_work_queue:close(State#mrst.doc_queue),
receive
{new_state, NewState} ->
{ok, NewState#mrst{
- first_build=undefined,
- partial_resp_pid=undefined,
- doc_acc=undefined,
- doc_queue=undefined,
- write_queue=undefined,
- qserver=nil
+ first_build = undefined,
+ partial_resp_pid = undefined,
+ doc_acc = undefined,
+ doc_queue = undefined,
+ write_queue = undefined,
+ qserver = nil
}}
end.
-
map_docs(Parent, #mrst{db_name = DbName, idx_name = IdxName} = State0) ->
erlang:put(io_priority, {view_update, DbName, IdxName}),
case couch_work_queue:dequeue(State0#mrst.doc_queue) of
@@ -150,10 +158,11 @@ map_docs(Parent, #mrst{db_name = DbName, idx_name = IdxName} = State0) ->
{ok, Dequeued} ->
% Run all the non deleted docs through the view engine and
% then pass the results on to the writer process.
- State1 = case State0#mrst.qserver of
- nil -> start_query_server(State0);
- _ -> State0
- end,
+ State1 =
+ case State0#mrst.qserver of
+ nil -> start_query_server(State0);
+ _ -> State0
+ end,
QServer = State1#mrst.qserver,
DocFun = fun
({nil, Seq, _}, {SeqAcc, Results}) ->
@@ -174,38 +183,37 @@ map_docs(Parent, #mrst{db_name = DbName, idx_name = IdxName} = State0) ->
map_docs(Parent, State1)
end.
-
write_results(Parent, #mrst{} = State) ->
case accumulate_writes(State, State#mrst.write_queue, nil) of
stop ->
Parent ! {new_state, State};
{Go, {Seq, ViewKVs, DocIdKeys}} ->
NewState = write_kvs(State, Seq, ViewKVs, DocIdKeys),
- if Go == stop ->
- Parent ! {new_state, NewState};
- true ->
- send_partial(NewState#mrst.partial_resp_pid, NewState),
- write_results(Parent, NewState)
+ if
+ Go == stop ->
+ Parent ! {new_state, NewState};
+ true ->
+ send_partial(NewState#mrst.partial_resp_pid, NewState),
+ write_results(Parent, NewState)
end
end.
-
start_query_server(State) ->
#mrst{
- language=Language,
- lib=Lib,
- views=Views
+ language = Language,
+ lib = Lib,
+ views = Views
} = State,
Defs = [View#mrview.def || View <- Views],
{ok, QServer} = couch_query_servers:start_doc_map(Language, Defs, Lib),
- State#mrst{qserver=QServer}.
-
+ State#mrst{qserver = QServer}.
accumulate_writes(State, W, Acc0) ->
- {Seq, ViewKVs, DocIdKVs} = case Acc0 of
- nil -> {0, [{V#mrview.id_num, []} || V <- State#mrst.views], []};
- _ -> Acc0
- end,
+ {Seq, ViewKVs, DocIdKVs} =
+ case Acc0 of
+ nil -> {0, [{V#mrview.id_num, []} || V <- State#mrst.views], []};
+ _ -> Acc0
+ end,
case couch_work_queue:dequeue(W) of
closed when Seq == 0 ->
stop;
@@ -219,15 +227,13 @@ accumulate_writes(State, W, Acc0) ->
end
end.
-
accumulate_more(NumDocIds, Acc) ->
% check if we have enough items now
MinItems = config:get("view_updater", "min_writer_items", "100"),
MinSize = config:get("view_updater", "min_writer_size", "16777216"),
CurrMem = ?term_size(Acc),
- NumDocIds < list_to_integer(MinItems)
- andalso CurrMem < list_to_integer(MinSize).
-
+ NumDocIds < list_to_integer(MinItems) andalso
+ CurrMem < list_to_integer(MinSize).
merge_results([], SeqAcc, ViewKVs, DocIdKeys) ->
{SeqAcc, ViewKVs, DocIdKeys};
@@ -238,7 +244,6 @@ merge_results([{Seq, Results} | Rest], SeqAcc, ViewKVs, DocIdKeys) ->
{ViewKVs1, DocIdKeys1} = lists:foldl(Fun, {ViewKVs, DocIdKeys}, Results),
merge_results(Rest, erlang:max(Seq, SeqAcc), ViewKVs1, DocIdKeys1).
-
merge_results({DocId, []}, ViewKVs, DocIdKeys) ->
{ViewKVs, [{DocId, []} | DocIdKeys]};
merge_results({DocId, RawResults}, ViewKVs, DocIdKeys) ->
@@ -252,7 +257,6 @@ merge_results({DocId, RawResults}, ViewKVs, DocIdKeys) ->
{ViewKVs1, [ViewIdKeys | DocIdKeys]}
end.
-
insert_results(DocId, [], [], ViewKVs, ViewIdKeys) ->
{lists:reverse(ViewKVs), {DocId, ViewIdKeys}};
insert_results(DocId, [KVs | RKVs], [{Id, VKVs} | RVKVs], VKVAcc, VIdKeys) ->
@@ -266,62 +270,67 @@ insert_results(DocId, [KVs | RKVs], [{Id, VKVs} | RVKVs], VKVAcc, VIdKeys) ->
end,
InitAcc = {[], VIdKeys},
couch_stats:increment_counter([couchdb, mrview, emits], length(KVs)),
- {Duped, VIdKeys0} = lists:foldl(CombineDupesFun, InitAcc,
- lists:sort(KVs)),
+ {Duped, VIdKeys0} = lists:foldl(
+ CombineDupesFun,
+ InitAcc,
+ lists:sort(KVs)
+ ),
FinalKVs = [{{Key, DocId}, Val} || {Key, Val} <- Duped] ++ VKVs,
insert_results(DocId, RKVs, RVKVs, [{Id, FinalKVs} | VKVAcc], VIdKeys0).
-
write_kvs(State, UpdateSeq, ViewKVs, DocIdKeys) ->
#mrst{
- id_btree=IdBtree,
- first_build=FirstBuild,
- partitioned=Partitioned
+ id_btree = IdBtree,
+ first_build = FirstBuild,
+ partitioned = Partitioned
} = State,
{ok, ToRemove, IdBtree2} = update_id_btree(IdBtree, DocIdKeys, FirstBuild),
ToRemByView = collapse_rem_keys(ToRemove, dict:new()),
- UpdateView = fun(#mrview{id_num=ViewId}=View, {ViewId, KVs0}) ->
+ UpdateView = fun(#mrview{id_num = ViewId} = View, {ViewId, KVs0}) ->
ToRem0 = couch_util:dict_find(ViewId, ToRemByView, []),
- {KVs, ToRem} = case Partitioned of
- true ->
- KVs1 = inject_partition(KVs0),
- ToRem1 = inject_partition(ToRem0),
- {KVs1, ToRem1};
- false ->
- {KVs0, ToRem0}
- end,
+ {KVs, ToRem} =
+ case Partitioned of
+ true ->
+ KVs1 = inject_partition(KVs0),
+ ToRem1 = inject_partition(ToRem0),
+ {KVs1, ToRem1};
+ false ->
+ {KVs0, ToRem0}
+ end,
{ok, VBtree2} = couch_btree:add_remove(View#mrview.btree, KVs, ToRem),
- NewUpdateSeq = case VBtree2 =/= View#mrview.btree of
- true -> UpdateSeq;
- _ -> View#mrview.update_seq
- end,
+ NewUpdateSeq =
+ case VBtree2 =/= View#mrview.btree of
+ true -> UpdateSeq;
+ _ -> View#mrview.update_seq
+ end,
- View2 = View#mrview{btree=VBtree2, update_seq=NewUpdateSeq},
+ View2 = View#mrview{btree = VBtree2, update_seq = NewUpdateSeq},
maybe_notify(State, View2, KVs, ToRem),
View2
end,
State#mrst{
- views=lists:zipwith(UpdateView, State#mrst.views, ViewKVs),
- update_seq=UpdateSeq,
- id_btree=IdBtree2
+ views = lists:zipwith(UpdateView, State#mrst.views, ViewKVs),
+ update_seq = UpdateSeq,
+ id_btree = IdBtree2
}.
-
inject_partition(Rows) ->
- lists:map(fun
- ({{Key, DocId}, Value}) ->
- % Adding a row to the view
- {Partition, _} = couch_partition:extract(DocId),
- {{{p, Partition, Key}, DocId}, Value};
- ({Key, DocId}) ->
- % Removing a row based on values in id_tree
- {Partition, _} = couch_partition:extract(DocId),
- {{p, Partition, Key}, DocId}
- end, Rows).
-
+ lists:map(
+ fun
+ ({{Key, DocId}, Value}) ->
+ % Adding a row to the view
+ {Partition, _} = couch_partition:extract(DocId),
+ {{{p, Partition, Key}, DocId}, Value};
+ ({Key, DocId}) ->
+ % Removing a row based on values in id_tree
+ {Partition, _} = couch_partition:extract(DocId),
+ {{p, Partition, Key}, DocId}
+ end,
+ Rows
+ ).
update_id_btree(Btree, DocIdKeys, true) ->
ToAdd = [{Id, DIKeys} || {Id, DIKeys} <- DocIdKeys, DIKeys /= []],
@@ -332,37 +341,38 @@ update_id_btree(Btree, DocIdKeys, _) ->
ToRem = [Id || {Id, DIKeys} <- DocIdKeys, DIKeys == []],
couch_btree:query_modify(Btree, ToFind, ToAdd, ToRem).
-
collapse_rem_keys([], Acc) ->
Acc;
collapse_rem_keys([{ok, {DocId, ViewIdKeys}} | Rest], Acc) ->
- NewAcc = lists:foldl(fun({ViewId, Key}, Acc2) ->
- dict:append(ViewId, {Key, DocId}, Acc2)
- end, Acc, ViewIdKeys),
+ NewAcc = lists:foldl(
+ fun({ViewId, Key}, Acc2) ->
+ dict:append(ViewId, {Key, DocId}, Acc2)
+ end,
+ Acc,
+ ViewIdKeys
+ ),
collapse_rem_keys(Rest, NewAcc);
collapse_rem_keys([{not_found, _} | Rest], Acc) ->
collapse_rem_keys(Rest, Acc).
-
send_partial(Pid, State) when is_pid(Pid) ->
gen_server:cast(Pid, {new_state, State});
send_partial(_, _) ->
ok.
-
update_task(NumChanges) ->
[Changes, Total] = couch_task_status:get([changes_done, total_changes]),
Changes2 = Changes + NumChanges,
- Progress = case Total of
- 0 ->
- % updater restart after compaction finishes
- 0;
- _ ->
- (Changes2 * 100) div Total
- end,
+ Progress =
+ case Total of
+ 0 ->
+ % updater restart after compaction finishes
+ 0;
+ _ ->
+ (Changes2 * 100) div Total
+ end,
couch_task_status:update([{progress, Progress}, {changes_done, Changes2}]).
-
maybe_notify(State, View, KVs, ToRem) ->
Updated = fun() ->
[Key || {{Key, _}, _} <- KVs]
diff --git a/src/couch_mrview/src/couch_mrview_util.erl b/src/couch_mrview/src/couch_mrview_util.erl
index d318a3f4a..b7220f71f 100644
--- a/src/couch_mrview/src/couch_mrview_util.erl
+++ b/src/couch_mrview/src/couch_mrview_util.erl
@@ -38,39 +38,54 @@
-define(GET_VIEW_RETRY_DELAY, 50).
-define(LOWEST_KEY, null).
-define(HIGHEST_KEY, {<<255, 255, 255, 255>>}).
--define(LOWEST(A, B), (if A < B -> A; true -> B end)).
--define(HIGHEST(A, B), (if A > B -> A; true -> B end)).
+-define(LOWEST(A, B),
+ (if
+ A < B -> A;
+ true -> B
+ end)
+).
+-define(HIGHEST(A, B),
+ (if
+ A > B -> A;
+ true -> B
+ end)
+).
-include_lib("couch/include/couch_db.hrl").
-include_lib("couch_mrview/include/couch_mrview.hrl").
-
get_local_purge_doc_id(Sig) ->
?l2b(?LOCAL_DOC_PREFIX ++ "purge-mrview-" ++ Sig).
-
get_value_from_options(Key, Options) ->
case couch_util:get_value(Key, Options) of
undefined ->
Reason = <<"'", Key/binary, "' must exists in options.">>,
throw({bad_request, Reason});
- Value -> Value
+ Value ->
+ Value
end.
-
verify_view_filename(FileName) ->
FilePathList = filename:split(FileName),
PureFN = lists:last(FilePathList),
case filename:extension(PureFN) of
".view" ->
Sig = filename:basename(PureFN),
- case [Ch || Ch <- Sig, not (((Ch >= $0) and (Ch =< $9))
- orelse ((Ch >= $a) and (Ch =< $f))
- orelse ((Ch >= $A) and (Ch =< $F)))] == [] of
+ case
+ [
+ Ch
+ || Ch <- Sig,
+ not (((Ch >= $0) and (Ch =< $9)) orelse
+ ((Ch >= $a) and (Ch =< $f)) orelse
+ ((Ch >= $A) and (Ch =< $F)))
+ ] == []
+ of
true -> true;
false -> false
end;
- _ -> false
+ _ ->
+ false
end.
get_signature_from_filename(FileName) ->
@@ -82,7 +97,7 @@ get_view(Db, DDoc, ViewName, Args0) ->
case get_view_index_state(Db, DDoc, ViewName, Args0) of
{ok, State, Args2} ->
Ref = erlang:monitor(process, State#mrst.fd),
- #mrst{language=Lang, views=Views} = State,
+ #mrst{language = Lang, views = Views} = State,
{Type, View, Args3} = extract_view(Lang, Args2, ViewName, Views),
check_range(Args3, view_cmp(View)),
Sig = view_sig(Db, State, View, Args3),
@@ -91,7 +106,6 @@ get_view(Db, DDoc, ViewName, Args0) ->
ddoc_updated
end.
-
get_view_index_pid(Db, DDoc, ViewName, Args0) ->
ArgCheck = fun(InitState) ->
Args1 = set_view_type(Args0, ViewName, InitState#mrst.views),
@@ -99,7 +113,6 @@ get_view_index_pid(Db, DDoc, ViewName, Args0) ->
end,
couch_index_server:get_index(?MOD, Db, DDoc, ArgCheck).
-
get_view_index_state(Db, DDoc, ViewName, Args0) ->
get_view_index_state(Db, DDoc, ViewName, Args0, ?GET_VIEW_RETRY_COUNT).
@@ -112,17 +125,18 @@ get_view_index_state(Db, DDoc, ViewName, Args0, RetryCount) ->
UpdateSeq = couch_util:with_db(Db, fun(WDb) ->
couch_db:get_update_seq(WDb)
end),
- State = case Args#mrargs.update of
- lazy ->
- spawn(fun() ->
- catch couch_index:get_state(Pid, UpdateSeq)
- end),
- couch_index:get_state(Pid, 0);
- false ->
- couch_index:get_state(Pid, 0);
- _ ->
- couch_index:get_state(Pid, UpdateSeq)
- end,
+ State =
+ case Args#mrargs.update of
+ lazy ->
+ spawn(fun() ->
+ catch couch_index:get_state(Pid, UpdateSeq)
+ end),
+ couch_index:get_state(Pid, 0);
+ false ->
+ couch_index:get_state(Pid, 0);
+ _ ->
+ couch_index:get_state(Pid, UpdateSeq)
+ end,
case State of
{ok, State0} -> {ok, State0, Args};
ddoc_updated -> ddoc_updated;
@@ -138,33 +152,37 @@ get_view_index_state(Db, DDoc, ViewName, Args0, RetryCount) ->
throw(Error)
end.
-
-ddoc_to_mrst(DbName, #doc{id=Id, body={Fields}}) ->
- MakeDict = fun({Name, {MRFuns}}, DictBySrcAcc) ->
- case couch_util:get_value(<<"map">>, MRFuns) of
- MapSrc when MapSrc /= undefined ->
- RedSrc = couch_util:get_value(<<"reduce">>, MRFuns, null),
- {ViewOpts} = couch_util:get_value(<<"options">>, MRFuns, {[]}),
- View = case dict:find({MapSrc, ViewOpts}, DictBySrcAcc) of
- {ok, View0} -> View0;
- error -> #mrview{def=MapSrc, options=ViewOpts}
- end,
- {MapNames, RedSrcs} = case RedSrc of
- null ->
- MNames = [Name | View#mrview.map_names],
- {MNames, View#mrview.reduce_funs};
- _ ->
- RedFuns = [{Name, RedSrc} | View#mrview.reduce_funs],
- {View#mrview.map_names, RedFuns}
- end,
- View2 = View#mrview{map_names=MapNames, reduce_funs=RedSrcs},
- dict:store({MapSrc, ViewOpts}, View2, DictBySrcAcc);
- undefined ->
- DictBySrcAcc
- end;
+ddoc_to_mrst(DbName, #doc{id = Id, body = {Fields}}) ->
+ MakeDict = fun
+ ({Name, {MRFuns}}, DictBySrcAcc) ->
+ case couch_util:get_value(<<"map">>, MRFuns) of
+ MapSrc when MapSrc /= undefined ->
+ RedSrc = couch_util:get_value(<<"reduce">>, MRFuns, null),
+ {ViewOpts} = couch_util:get_value(<<"options">>, MRFuns, {[]}),
+ View =
+ case dict:find({MapSrc, ViewOpts}, DictBySrcAcc) of
+ {ok, View0} -> View0;
+ error -> #mrview{def = MapSrc, options = ViewOpts}
+ end,
+ {MapNames, RedSrcs} =
+ case RedSrc of
+ null ->
+ MNames = [Name | View#mrview.map_names],
+ {MNames, View#mrview.reduce_funs};
+ _ ->
+ RedFuns = [{Name, RedSrc} | View#mrview.reduce_funs],
+ {View#mrview.map_names, RedFuns}
+ end,
+ View2 = View#mrview{map_names = MapNames, reduce_funs = RedSrcs},
+ dict:store({MapSrc, ViewOpts}, View2, DictBySrcAcc);
+ undefined ->
+ DictBySrcAcc
+ end;
({Name, Else}, DictBySrcAcc) ->
- couch_log:error("design_doc_to_view_group ~s views ~p",
- [Name, Else]),
+ couch_log:error(
+ "design_doc_to_view_group ~s views ~p",
+ [Name, Else]
+ ),
DictBySrcAcc
end,
{DesignOpts} = proplists:get_value(<<"options">>, Fields, {[]}),
@@ -174,7 +192,7 @@ ddoc_to_mrst(DbName, #doc{id=Id, body={Fields}}) ->
BySrc = lists:foldl(MakeDict, dict:new(), RawViews),
NumViews = fun({_, View}, N) ->
- {View#mrview{id_num=N}, N+1}
+ {View#mrview{id_num = N}, N + 1}
end,
{Views, _} = lists:mapfoldl(NumViews, 0, lists:sort(dict:to_list(BySrc))),
@@ -182,17 +200,16 @@ ddoc_to_mrst(DbName, #doc{id=Id, body={Fields}}) ->
Lib = couch_util:get_value(<<"lib">>, RawViews, {[]}),
IdxState = #mrst{
- db_name=DbName,
- idx_name=Id,
- lib=Lib,
- views=Views,
- language=Language,
- design_opts=DesignOpts,
- partitioned=Partitioned
+ db_name = DbName,
+ idx_name = Id,
+ lib = Lib,
+ views = Views,
+ language = Language,
+ design_opts = DesignOpts,
+ partitioned = Partitioned
},
SigInfo = {Views, Language, DesignOpts, couch_index_util:sort_lib(Lib)},
- {ok, IdxState#mrst{sig=couch_hash:md5_hash(term_to_binary(SigInfo))}}.
-
+ {ok, IdxState#mrst{sig = couch_hash:md5_hash(term_to_binary(SigInfo))}}.
set_view_type(_Args, _ViewName, []) ->
throw({not_found, missing_named_view});
@@ -201,48 +218,44 @@ set_view_type(Args, ViewName, [View | Rest]) ->
case lists:member(ViewName, RedNames) of
true ->
case Args#mrargs.reduce of
- false -> Args#mrargs{view_type=map};
- _ -> Args#mrargs{view_type=red}
+ false -> Args#mrargs{view_type = map};
+ _ -> Args#mrargs{view_type = red}
end;
false ->
case lists:member(ViewName, View#mrview.map_names) of
- true -> Args#mrargs{view_type=map};
+ true -> Args#mrargs{view_type = map};
false -> set_view_type(Args, ViewName, Rest)
end
end.
-
set_extra(#mrargs{} = Args, Key, Value) ->
Extra0 = Args#mrargs.extra,
Extra1 = lists:ukeysort(1, [{Key, Value} | Extra0]),
Args#mrargs{extra = Extra1}.
-
get_extra(#mrargs{} = Args, Key) ->
couch_util:get_value(Key, Args#mrargs.extra).
get_extra(#mrargs{} = Args, Key, Default) ->
couch_util:get_value(Key, Args#mrargs.extra, Default).
-
extract_view(_Lang, _Args, _ViewName, []) ->
throw({not_found, missing_named_view});
-extract_view(Lang, #mrargs{view_type=map}=Args, Name, [View | Rest]) ->
+extract_view(Lang, #mrargs{view_type = map} = Args, Name, [View | Rest]) ->
Names = View#mrview.map_names ++ [N || {N, _} <- View#mrview.reduce_funs],
case lists:member(Name, Names) of
true -> {map, View, Args};
_ -> extract_view(Lang, Args, Name, Rest)
end;
-extract_view(Lang, #mrargs{view_type=red}=Args, Name, [View | Rest]) ->
+extract_view(Lang, #mrargs{view_type = red} = Args, Name, [View | Rest]) ->
RedNames = [N || {N, _} <- View#mrview.reduce_funs],
case lists:member(Name, RedNames) of
true -> {red, {index_of(Name, RedNames), Lang, View}, Args};
false -> extract_view(Lang, Args, Name, Rest)
end.
-
-view_sig(Db, State, View, #mrargs{include_docs=true}=Args) ->
- BaseSig = view_sig(Db, State, View, Args#mrargs{include_docs=false}),
+view_sig(Db, State, View, #mrargs{include_docs = true} = Args) ->
+ BaseSig = view_sig(Db, State, View, Args#mrargs{include_docs = false}),
UpdateSeq = couch_db:get_update_seq(Db),
PurgeSeq = couch_db:get_purge_seq(Db),
Term = view_sig_term(BaseSig, UpdateSeq, PurgeSeq),
@@ -254,8 +267,8 @@ view_sig(_Db, State, View, Args0) ->
UpdateSeq = View#mrview.update_seq,
PurgeSeq = View#mrview.purge_seq,
Args = Args0#mrargs{
- preflight_fun=undefined,
- extra=[]
+ preflight_fun = undefined,
+ extra = []
},
Term = view_sig_term(Sig, UpdateSeq, PurgeSeq, Args),
couch_index_util:hexsig(couch_hash:md5_hash(term_to_binary(Term))).
@@ -266,26 +279,25 @@ view_sig_term(BaseSig, UpdateSeq, PurgeSeq) ->
view_sig_term(BaseSig, UpdateSeq, PurgeSeq, Args) ->
{BaseSig, UpdateSeq, PurgeSeq, Args}.
-
-init_state(Db, Fd, #mrst{views=Views}=State, nil) ->
+init_state(Db, Fd, #mrst{views = Views} = State, nil) ->
PurgeSeq = couch_db:get_purge_seq(Db),
Header = #mrheader{
- seq=0,
- purge_seq=PurgeSeq,
- id_btree_state=nil,
- view_states=[make_view_state(#mrview{}) || _ <- Views]
+ seq = 0,
+ purge_seq = PurgeSeq,
+ id_btree_state = nil,
+ view_states = [make_view_state(#mrview{}) || _ <- Views]
},
init_state(Db, Fd, State, Header);
init_state(Db, Fd, State, Header) ->
#mrst{
- language=Lang,
- views=Views
+ language = Lang,
+ views = Views
} = State,
#mrheader{
- seq=Seq,
- purge_seq=PurgeSeq,
- id_btree_state=IdBtreeState,
- view_states=ViewStates
+ seq = Seq,
+ purge_seq = PurgeSeq,
+ id_btree_state = IdBtreeState,
+ view_states = ViewStates
} = maybe_update_header(Header),
IdBtOpts = [
@@ -297,12 +309,12 @@ init_state(Db, Fd, State, Header) ->
Views2 = lists:zipwith(OpenViewFun, ViewStates, Views),
State#mrst{
- fd=Fd,
- fd_monitor=erlang:monitor(process, Fd),
- update_seq=Seq,
- purge_seq=PurgeSeq,
- id_btree=IdBtree,
- views=Views2
+ fd = Fd,
+ fd_monitor = erlang:monitor(process, Fd),
+ update_seq = Seq,
+ purge_seq = PurgeSeq,
+ id_btree = IdBtree,
+ views = Views2
}.
open_view(_Db, Fd, Lang, ViewState, View) ->
@@ -317,38 +329,42 @@ open_view(_Db, Fd, Lang, ViewState, View) ->
],
{ok, Btree} = couch_btree:open(BTState, Fd, ViewBtOpts),
- View#mrview{btree=Btree,
- update_seq=get_update_seq(ViewState),
- purge_seq=get_purge_seq(ViewState)}.
-
+ View#mrview{
+ btree = Btree,
+ update_seq = get_update_seq(ViewState),
+ purge_seq = get_purge_seq(ViewState)
+ }.
temp_view_to_ddoc({Props}) ->
Language = couch_util:get_value(<<"language">>, Props, <<"javascript">>),
Options = couch_util:get_value(<<"options">>, Props, {[]}),
View0 = [{<<"map">>, couch_util:get_value(<<"map">>, Props)}],
- View1 = View0 ++ case couch_util:get_value(<<"reduce">>, Props) of
- RedSrc when is_binary(RedSrc) -> [{<<"reduce">>, RedSrc}];
- _ -> []
- end,
- DDoc = {[
- {<<"_id">>, couch_uuids:random()},
- {<<"language">>, Language},
- {<<"options">>, Options},
- {<<"views">>, {[
- {<<"temp">>, {View1}}
- ]}}
- ]},
+ View1 =
+ View0 ++
+ case couch_util:get_value(<<"reduce">>, Props) of
+ RedSrc when is_binary(RedSrc) -> [{<<"reduce">>, RedSrc}];
+ _ -> []
+ end,
+ DDoc =
+ {[
+ {<<"_id">>, couch_uuids:random()},
+ {<<"language">>, Language},
+ {<<"options">>, Options},
+ {<<"views">>,
+ {[
+ {<<"temp">>, {View1}}
+ ]}}
+ ]},
couch_doc:from_json_obj(DDoc).
-
-get_row_count(#mrview{btree=Bt}) ->
- Count = case couch_btree:full_reduce(Bt) of
- {ok, {Count0, _Reds, _}} -> Count0;
- {ok, {Count0, _Reds}} -> Count0
- end,
+get_row_count(#mrview{btree = Bt}) ->
+ Count =
+ case couch_btree:full_reduce(Bt) of
+ {ok, {Count0, _Reds, _}} -> Count0;
+ {ok, {Count0, _Reds}} -> Count0
+ end,
{ok, Count}.
-
all_docs_reduce_to_count(Reductions) ->
Reduce = fun couch_bt_engine:id_tree_reduce/2,
{Count, _, _} = couch_btree:final_reduce(Reduce, Reductions),
@@ -361,8 +377,7 @@ reduce_to_count(Reductions) ->
FinalReduction = couch_btree:final_reduce(CountReduceFun, Reductions),
get_count(FinalReduction).
-
-fold(#mrview{btree=Bt}, Fun, Acc, Opts) ->
+fold(#mrview{btree = Bt}, Fun, Acc, Opts) ->
WrapperFun = fun(KV, Reds, Acc2) ->
fold_fun(Fun, expand_dups([KV], []), Reds, Acc2)
end,
@@ -370,19 +385,18 @@ fold(#mrview{btree=Bt}, Fun, Acc, Opts) ->
fold_fun(_Fun, [], _, Acc) ->
{ok, Acc};
-fold_fun(Fun, [KV|Rest], {KVReds, Reds}, Acc) ->
+fold_fun(Fun, [KV | Rest], {KVReds, Reds}, Acc) ->
case Fun(KV, {KVReds, Reds}, Acc) of
{ok, Acc2} ->
- fold_fun(Fun, Rest, {[KV|KVReds], Reds}, Acc2);
+ fold_fun(Fun, Rest, {[KV | KVReds], Reds}, Acc2);
{stop, Acc2} ->
{stop, Acc2}
end.
-
-fold_reduce({NthRed, Lang, View}, Fun, Acc, Options) ->
+fold_reduce({NthRed, Lang, View}, Fun, Acc, Options) ->
#mrview{
- btree=Bt,
- reduce_funs=RedFuns
+ btree = Bt,
+ reduce_funs = RedFuns
} = View,
ReduceFun = make_user_reds_reduce_fun(Lang, RedFuns, NthRed),
@@ -395,13 +409,11 @@ fold_reduce({NthRed, Lang, View}, Fun, Acc, Options) ->
couch_btree:fold_reduce(Bt, WrapperFun, Acc, Options).
-
validate_args(Db, DDoc, Args0) ->
{ok, State} = couch_mrview_index:init(Db, DDoc),
Args1 = apply_limit(State#mrst.partitioned, Args0),
validate_args(State, Args1).
-
validate_args(#mrst{} = State, Args0) ->
Args = validate_args(Args0),
@@ -410,45 +422,55 @@ validate_args(#mrst{} = State, Args0) ->
case {ViewPartitioned, Partition} of
{true, undefined} ->
- Msg1 = <<"`partition` parameter is mandatory "
- "for queries to this view.">>,
+ Msg1 = <<
+ "`partition` parameter is mandatory "
+ "for queries to this view."
+ >>,
mrverror(Msg1);
{true, _} ->
apply_partition(Args, Partition);
{false, undefined} ->
Args;
{false, Value} when is_binary(Value) ->
- Msg2 = <<"`partition` parameter is not "
- "supported in this design doc">>,
+ Msg2 = <<
+ "`partition` parameter is not "
+ "supported in this design doc"
+ >>,
mrverror(Msg2)
end.
-
apply_limit(ViewPartitioned, Args) ->
Options = Args#mrargs.extra,
IgnorePQLimit = lists:keyfind(ignore_partition_query_limit, 1, Options),
- LimitType = case {ViewPartitioned, IgnorePQLimit} of
- {true, false} -> "partition_query_limit";
- {true, _} -> "query_limit";
- {false, _} -> "query_limit"
- end,
+ LimitType =
+ case {ViewPartitioned, IgnorePQLimit} of
+ {true, false} -> "partition_query_limit";
+ {true, _} -> "query_limit";
+ {false, _} -> "query_limit"
+ end,
- MaxLimit = config:get_integer("query_server_config",
- LimitType, ?MAX_VIEW_LIMIT),
+ MaxLimit = config:get_integer(
+ "query_server_config",
+ LimitType,
+ ?MAX_VIEW_LIMIT
+ ),
% Set the highest limit possible if a user has not
% specified a limit
- Args1 = case Args#mrargs.limit == ?MAX_VIEW_LIMIT of
- true -> Args#mrargs{limit = MaxLimit};
- false -> Args
- end,
+ Args1 =
+ case Args#mrargs.limit == ?MAX_VIEW_LIMIT of
+ true -> Args#mrargs{limit = MaxLimit};
+ false -> Args
+ end,
- if Args1#mrargs.limit =< MaxLimit -> Args1; true ->
- Fmt = "Limit is too large, must not exceed ~p",
- mrverror(io_lib:format(Fmt, [MaxLimit]))
+ if
+ Args1#mrargs.limit =< MaxLimit ->
+ Args1;
+ true ->
+ Fmt = "Limit is too large, must not exceed ~p",
+ mrverror(io_lib:format(Fmt, [MaxLimit]))
end.
-
validate_all_docs_args(Db, Args0) ->
Args = validate_args(Args0),
@@ -465,7 +487,6 @@ validate_all_docs_args(Db, Args0) ->
Args
end.
-
validate_args(Args) ->
GroupLevel = determine_group_level(Args),
Reduce = Args#mrargs.reduce,
@@ -480,11 +501,13 @@ validate_args(Args) ->
end,
case {Args#mrargs.view_type, GroupLevel, Args#mrargs.keys} of
- {red, exact, _} -> ok;
+ {red, exact, _} ->
+ ok;
{red, _, KeyList} when is_list(KeyList) ->
Msg = <<"Multi-key fetchs for reduce views must use `group=true`">>,
mrverror(Msg);
- _ -> ok
+ _ ->
+ ok
end,
case Args#mrargs.keys of
@@ -493,13 +516,18 @@ validate_args(Args) ->
_ -> mrverror(<<"`keys` must be an array of strings.">>)
end,
- case {Args#mrargs.keys, Args#mrargs.start_key,
- Args#mrargs.end_key} of
- {undefined, _, _} -> ok;
- {[], _, _} -> ok;
- {[_|_], undefined, undefined} -> ok;
- _ -> mrverror(<<"`keys` is incompatible with `key`"
- ", `start_key` and `end_key`">>)
+ case {Args#mrargs.keys, Args#mrargs.start_key, Args#mrargs.end_key} of
+ {undefined, _, _} ->
+ ok;
+ {[], _, _} ->
+ ok;
+ {[_ | _], undefined, undefined} ->
+ ok;
+ _ ->
+ mrverror(<<
+ "`keys` is incompatible with `key`"
+ ", `start_key` and `end_key`"
+ >>)
end,
case Args#mrargs.start_key_docid of
@@ -571,17 +599,19 @@ validate_args(Args) ->
{red, _} -> mrverror(<<"`conflicts` is invalid for reduce views.">>)
end,
- SKDocId = case {Args#mrargs.direction, Args#mrargs.start_key_docid} of
- {fwd, undefined} -> <<>>;
- {rev, undefined} -> <<255>>;
- {_, SKDocId1} -> SKDocId1
- end,
+ SKDocId =
+ case {Args#mrargs.direction, Args#mrargs.start_key_docid} of
+ {fwd, undefined} -> <<>>;
+ {rev, undefined} -> <<255>>;
+ {_, SKDocId1} -> SKDocId1
+ end,
- EKDocId = case {Args#mrargs.direction, Args#mrargs.end_key_docid} of
- {fwd, undefined} -> <<255>>;
- {rev, undefined} -> <<>>;
- {_, EKDocId1} -> EKDocId1
- end,
+ EKDocId =
+ case {Args#mrargs.direction, Args#mrargs.end_key_docid} of
+ {fwd, undefined} -> <<255>>;
+ {rev, undefined} -> <<>>;
+ {_, EKDocId1} -> EKDocId1
+ end,
case is_boolean(Args#mrargs.sorted) of
true -> ok;
@@ -595,32 +625,30 @@ validate_args(Args) ->
end,
Args#mrargs{
- start_key_docid=SKDocId,
- end_key_docid=EKDocId,
- group_level=GroupLevel
+ start_key_docid = SKDocId,
+ end_key_docid = EKDocId,
+ group_level = GroupLevel
}.
-
-determine_group_level(#mrargs{group=undefined, group_level=undefined}) ->
+determine_group_level(#mrargs{group = undefined, group_level = undefined}) ->
0;
-determine_group_level(#mrargs{group=false, group_level=undefined}) ->
+determine_group_level(#mrargs{group = false, group_level = undefined}) ->
0;
-determine_group_level(#mrargs{group=false, group_level=Level}) when Level > 0 ->
+determine_group_level(#mrargs{group = false, group_level = Level}) when Level > 0 ->
mrverror(<<"Can't specify group=false and group_level>0 at the same time">>);
-determine_group_level(#mrargs{group=true, group_level=undefined}) ->
+determine_group_level(#mrargs{group = true, group_level = undefined}) ->
exact;
-determine_group_level(#mrargs{group_level=GroupLevel}) ->
+determine_group_level(#mrargs{group_level = GroupLevel}) ->
GroupLevel.
-apply_partition(#mrargs{keys=[{p, _, _} | _]} = Args, _Partition) ->
- Args; % already applied
-
-apply_partition(#mrargs{keys=Keys} = Args, Partition) when Keys /= undefined ->
- Args#mrargs{keys=[{p, Partition, K} || K <- Keys]};
-
-apply_partition(#mrargs{start_key={p, _, _}, end_key={p, _, _}} = Args, _Partition) ->
- Args; % already applied.
-
+apply_partition(#mrargs{keys = [{p, _, _} | _]} = Args, _Partition) ->
+ % already applied
+ Args;
+apply_partition(#mrargs{keys = Keys} = Args, Partition) when Keys /= undefined ->
+ Args#mrargs{keys = [{p, Partition, K} || K <- Keys]};
+apply_partition(#mrargs{start_key = {p, _, _}, end_key = {p, _, _}} = Args, _Partition) ->
+ % already applied.
+ Args;
apply_partition(Args, Partition) ->
#mrargs{
direction = Dir,
@@ -628,13 +656,22 @@ apply_partition(Args, Partition) ->
end_key = EndKey
} = Args,
- {DefSK, DefEK} = case Dir of
- fwd -> {?LOWEST_KEY, ?HIGHEST_KEY};
- rev -> {?HIGHEST_KEY, ?LOWEST_KEY}
- end,
+ {DefSK, DefEK} =
+ case Dir of
+ fwd -> {?LOWEST_KEY, ?HIGHEST_KEY};
+ rev -> {?HIGHEST_KEY, ?LOWEST_KEY}
+ end,
- SK0 = if StartKey /= undefined -> StartKey; true -> DefSK end,
- EK0 = if EndKey /= undefined -> EndKey; true -> DefEK end,
+ SK0 =
+ if
+ StartKey /= undefined -> StartKey;
+ true -> DefSK
+ end,
+ EK0 =
+ if
+ EndKey /= undefined -> EndKey;
+ true -> DefEK
+ end,
Args#mrargs{
start_key = {p, Partition, SK0},
@@ -650,92 +687,101 @@ apply_all_docs_partition(#mrargs{} = Args, Partition) ->
end_key = EndKey
} = Args,
- {DefSK, DefEK} = case Dir of
- fwd ->
- {
- couch_partition:start_key(Partition),
- couch_partition:end_key(Partition)
- };
- rev ->
- {
- couch_partition:end_key(Partition),
- couch_partition:start_key(Partition)
- }
- end,
+ {DefSK, DefEK} =
+ case Dir of
+ fwd ->
+ {
+ couch_partition:start_key(Partition),
+ couch_partition:end_key(Partition)
+ };
+ rev ->
+ {
+ couch_partition:end_key(Partition),
+ couch_partition:start_key(Partition)
+ }
+ end,
- SK0 = if StartKey == undefined -> DefSK; true -> StartKey end,
- EK0 = if EndKey == undefined -> DefEK; true -> EndKey end,
+ SK0 =
+ if
+ StartKey == undefined -> DefSK;
+ true -> StartKey
+ end,
+ EK0 =
+ if
+ EndKey == undefined -> DefEK;
+ true -> EndKey
+ end,
- {SK1, EK1} = case Dir of
- fwd -> {?HIGHEST(DefSK, SK0), ?LOWEST(DefEK, EK0)};
- rev -> {?LOWEST(DefSK, SK0), ?HIGHEST(DefEK, EK0)}
- end,
+ {SK1, EK1} =
+ case Dir of
+ fwd -> {?HIGHEST(DefSK, SK0), ?LOWEST(DefEK, EK0)};
+ rev -> {?LOWEST(DefSK, SK0), ?HIGHEST(DefEK, EK0)}
+ end,
Args#mrargs{
start_key = SK1,
end_key = EK1
}.
-
-check_range(#mrargs{start_key=undefined}, _Cmp) ->
+check_range(#mrargs{start_key = undefined}, _Cmp) ->
ok;
-check_range(#mrargs{end_key=undefined}, _Cmp) ->
+check_range(#mrargs{end_key = undefined}, _Cmp) ->
ok;
-check_range(#mrargs{start_key=K, end_key=K}, _Cmp) ->
+check_range(#mrargs{start_key = K, end_key = K}, _Cmp) ->
ok;
check_range(Args, Cmp) ->
#mrargs{
- direction=Dir,
- start_key=SK,
- start_key_docid=SKD,
- end_key=EK,
- end_key_docid=EKD
+ direction = Dir,
+ start_key = SK,
+ start_key_docid = SKD,
+ end_key = EK,
+ end_key_docid = EKD
} = Args,
case {Dir, Cmp({SK, SKD}, {EK, EKD})} of
{fwd, false} ->
- throw({query_parse_error,
- <<"No rows can match your key range, reverse your ",
- "start_key and end_key or set descending=true">>});
+ throw(
+ {query_parse_error,
+ <<"No rows can match your key range, reverse your ",
+ "start_key and end_key or set descending=true">>}
+ );
{rev, true} ->
- throw({query_parse_error,
- <<"No rows can match your key range, reverse your ",
- "start_key and end_key or set descending=false">>});
- _ -> ok
+ throw(
+ {query_parse_error,
+ <<"No rows can match your key range, reverse your ",
+ "start_key and end_key or set descending=false">>}
+ );
+ _ ->
+ ok
end.
-
view_cmp({_Nth, _Lang, View}) ->
view_cmp(View);
view_cmp(View) ->
fun(A, B) -> couch_btree:less(View#mrview.btree, A, B) end.
-
make_header(State) ->
#mrst{
- update_seq=Seq,
- purge_seq=PurgeSeq,
- id_btree=IdBtree,
- views=Views
+ update_seq = Seq,
+ purge_seq = PurgeSeq,
+ id_btree = IdBtree,
+ views = Views
} = State,
#mrheader{
- seq=Seq,
- purge_seq=PurgeSeq,
- id_btree_state=get_btree_state(IdBtree),
- view_states=[make_view_state(V) || V <- Views]
+ seq = Seq,
+ purge_seq = PurgeSeq,
+ id_btree_state = get_btree_state(IdBtree),
+ view_states = [make_view_state(V) || V <- Views]
}.
-
index_file(DbName, Sig) ->
FileName = couch_index_util:hexsig(Sig) ++ ".view",
couch_index_util:index_file(mrview, DbName, FileName).
-
compaction_file(DbName, Sig) ->
FileName = couch_index_util:hexsig(Sig) ++ ".compact.view",
couch_index_util:index_file(mrview, DbName, FileName).
-
open_file(FName) ->
case couch_file:open(FName, [nologifmissing]) of
{ok, Fd} -> {ok, Fd};
@@ -743,20 +789,16 @@ open_file(FName) ->
Error -> Error
end.
-
delete_files(DbName, Sig) ->
delete_index_file(DbName, Sig),
delete_compaction_file(DbName, Sig).
-
delete_index_file(DbName, Sig) ->
delete_file(index_file(DbName, Sig)).
-
delete_compaction_file(DbName, Sig) ->
delete_file(compaction_file(DbName, Sig)).
-
delete_file(FName) ->
case filelib:is_file(FName) of
true ->
@@ -766,87 +808,91 @@ delete_file(FName) ->
ok
end.
-
-reset_index(Db, Fd, #mrst{sig=Sig}=State) ->
+reset_index(Db, Fd, #mrst{sig = Sig} = State) ->
ok = couch_file:truncate(Fd, 0),
ok = couch_file:write_header(Fd, {Sig, nil}),
init_state(Db, Fd, reset_state(State), nil).
-
reset_state(State) ->
State#mrst{
- fd=nil,
- qserver=nil,
- update_seq=0,
- id_btree=nil,
- views=[View#mrview{btree=nil} || View <- State#mrst.views]
+ fd = nil,
+ qserver = nil,
+ update_seq = 0,
+ id_btree = nil,
+ views = [View#mrview{btree = nil} || View <- State#mrst.views]
}.
-
all_docs_key_opts(#mrargs{extra = Extra} = Args) ->
all_docs_key_opts(Args, Extra).
-all_docs_key_opts(#mrargs{keys=undefined}=Args, Extra) ->
- all_docs_key_opts(Args#mrargs{keys=[]}, Extra);
-all_docs_key_opts(#mrargs{keys=[], direction=Dir}=Args, Extra) ->
+all_docs_key_opts(#mrargs{keys = undefined} = Args, Extra) ->
+ all_docs_key_opts(Args#mrargs{keys = []}, Extra);
+all_docs_key_opts(#mrargs{keys = [], direction = Dir} = Args, Extra) ->
[[{dir, Dir}] ++ ad_skey_opts(Args) ++ ad_ekey_opts(Args) ++ Extra];
-all_docs_key_opts(#mrargs{keys=Keys, direction=Dir}=Args, Extra) ->
- lists:map(fun(K) ->
- [{dir, Dir}]
- ++ ad_skey_opts(Args#mrargs{start_key=K})
- ++ ad_ekey_opts(Args#mrargs{end_key=K})
- ++ Extra
- end, Keys).
-
+all_docs_key_opts(#mrargs{keys = Keys, direction = Dir} = Args, Extra) ->
+ lists:map(
+ fun(K) ->
+ [{dir, Dir}] ++
+ ad_skey_opts(Args#mrargs{start_key = K}) ++
+ ad_ekey_opts(Args#mrargs{end_key = K}) ++
+ Extra
+ end,
+ Keys
+ ).
-ad_skey_opts(#mrargs{start_key=SKey}) when is_binary(SKey) ->
+ad_skey_opts(#mrargs{start_key = SKey}) when is_binary(SKey) ->
[{start_key, SKey}];
-ad_skey_opts(#mrargs{start_key_docid=SKeyDocId}) ->
+ad_skey_opts(#mrargs{start_key_docid = SKeyDocId}) ->
[{start_key, SKeyDocId}].
-
-ad_ekey_opts(#mrargs{end_key=EKey}=Args) when is_binary(EKey) ->
- Type = if Args#mrargs.inclusive_end -> end_key; true -> end_key_gt end,
+ad_ekey_opts(#mrargs{end_key = EKey} = Args) when is_binary(EKey) ->
+ Type =
+ if
+ Args#mrargs.inclusive_end -> end_key;
+ true -> end_key_gt
+ end,
[{Type, EKey}];
-ad_ekey_opts(#mrargs{end_key_docid=EKeyDocId}=Args) ->
- Type = if Args#mrargs.inclusive_end -> end_key; true -> end_key_gt end,
+ad_ekey_opts(#mrargs{end_key_docid = EKeyDocId} = Args) ->
+ Type =
+ if
+ Args#mrargs.inclusive_end -> end_key;
+ true -> end_key_gt
+ end,
[{Type, EKeyDocId}].
-
key_opts(Args) ->
key_opts(Args, []).
-key_opts(#mrargs{keys=undefined, direction=Dir}=Args, Extra) ->
+key_opts(#mrargs{keys = undefined, direction = Dir} = Args, Extra) ->
[[{dir, Dir}] ++ skey_opts(Args) ++ ekey_opts(Args) ++ Extra];
-key_opts(#mrargs{keys=Keys, direction=Dir}=Args, Extra) ->
- lists:map(fun(K) ->
- [{dir, Dir}]
- ++ skey_opts(Args#mrargs{start_key=K})
- ++ ekey_opts(Args#mrargs{end_key=K})
- ++ Extra
- end, Keys).
-
+key_opts(#mrargs{keys = Keys, direction = Dir} = Args, Extra) ->
+ lists:map(
+ fun(K) ->
+ [{dir, Dir}] ++
+ skey_opts(Args#mrargs{start_key = K}) ++
+ ekey_opts(Args#mrargs{end_key = K}) ++
+ Extra
+ end,
+ Keys
+ ).
-skey_opts(#mrargs{start_key=undefined}) ->
+skey_opts(#mrargs{start_key = undefined}) ->
[];
-skey_opts(#mrargs{start_key=SKey, start_key_docid=SKeyDocId}) ->
+skey_opts(#mrargs{start_key = SKey, start_key_docid = SKeyDocId}) ->
[{start_key, {SKey, SKeyDocId}}].
-
-ekey_opts(#mrargs{end_key=undefined}) ->
+ekey_opts(#mrargs{end_key = undefined}) ->
[];
-ekey_opts(#mrargs{end_key=EKey, end_key_docid=EKeyDocId}=Args) ->
+ekey_opts(#mrargs{end_key = EKey, end_key_docid = EKeyDocId} = Args) ->
case Args#mrargs.inclusive_end of
true -> [{end_key, {EKey, EKeyDocId}}];
false -> [{end_key_gt, {EKey, reverse_key_default(EKeyDocId)}}]
end.
-
reverse_key_default(<<>>) -> <<255>>;
reverse_key_default(<<255>>) -> <<>>;
reverse_key_default(Key) -> Key.
-
reduced_external_size(Tree) ->
case couch_btree:full_reduce(Tree) of
{ok, {_, _, Size}} -> Size;
@@ -854,35 +900,31 @@ reduced_external_size(Tree) ->
{ok, {_, _}} -> 0
end.
-
calculate_external_size(Views) ->
SumFun = fun
- (#mrview{btree=nil}, Acc) ->
+ (#mrview{btree = nil}, Acc) ->
Acc;
- (#mrview{btree=Bt}, Acc) ->
+ (#mrview{btree = Bt}, Acc) ->
Acc + reduced_external_size(Bt)
end,
{ok, lists:foldl(SumFun, 0, Views)}.
-
calculate_active_size(Views) ->
FoldFun = fun
- (#mrview{btree=nil}, Acc) ->
+ (#mrview{btree = nil}, Acc) ->
Acc;
- (#mrview{btree=Bt}, Acc) ->
+ (#mrview{btree = Bt}, Acc) ->
Acc + couch_btree:size(Bt)
end,
{ok, lists:foldl(FoldFun, 0, Views)}.
-
detuple_kvs([], Acc) ->
lists:reverse(Acc);
detuple_kvs([KV | Rest], Acc) ->
- {{Key,Id},Value} = KV,
+ {{Key, Id}, Value} = KV,
NKV = [[Key, Id], Value],
detuple_kvs(Rest, [NKV | Acc]).
-
expand_dups([], Acc) ->
lists:reverse(Acc);
expand_dups([{Key, {dups, Vals}} | Rest], Acc) ->
@@ -891,56 +933,49 @@ expand_dups([{Key, {dups, Vals}} | Rest], Acc) ->
expand_dups([KV | Rest], Acc) ->
expand_dups(Rest, [KV | Acc]).
-
-maybe_load_doc(_Db, _DI, #mrargs{include_docs=false}) ->
+maybe_load_doc(_Db, _DI, #mrargs{include_docs = false}) ->
[];
-maybe_load_doc(Db, #doc_info{}=DI, #mrargs{conflicts=true, doc_options=Opts}) ->
+maybe_load_doc(Db, #doc_info{} = DI, #mrargs{conflicts = true, doc_options = Opts}) ->
doc_row(couch_index_util:load_doc(Db, DI, [conflicts]), Opts);
-maybe_load_doc(Db, #doc_info{}=DI, #mrargs{doc_options=Opts}) ->
+maybe_load_doc(Db, #doc_info{} = DI, #mrargs{doc_options = Opts}) ->
doc_row(couch_index_util:load_doc(Db, DI, []), Opts).
-
-maybe_load_doc(_Db, _Id, _Val, #mrargs{include_docs=false}) ->
+maybe_load_doc(_Db, _Id, _Val, #mrargs{include_docs = false}) ->
[];
-maybe_load_doc(Db, Id, Val, #mrargs{conflicts=true, doc_options=Opts}) ->
+maybe_load_doc(Db, Id, Val, #mrargs{conflicts = true, doc_options = Opts}) ->
doc_row(couch_index_util:load_doc(Db, docid_rev(Id, Val), [conflicts]), Opts);
-maybe_load_doc(Db, Id, Val, #mrargs{doc_options=Opts}) ->
+maybe_load_doc(Db, Id, Val, #mrargs{doc_options = Opts}) ->
doc_row(couch_index_util:load_doc(Db, docid_rev(Id, Val), []), Opts).
-
doc_row(null, _Opts) ->
[{doc, null}];
doc_row(Doc, Opts) ->
[{doc, couch_doc:to_json_obj(Doc, Opts)}].
-
docid_rev(Id, {Props}) ->
DocId = couch_util:get_value(<<"_id">>, Props, Id),
- Rev = case couch_util:get_value(<<"_rev">>, Props, nil) of
- nil -> nil;
- Rev0 -> couch_doc:parse_rev(Rev0)
- end,
+ Rev =
+ case couch_util:get_value(<<"_rev">>, Props, nil) of
+ nil -> nil;
+ Rev0 -> couch_doc:parse_rev(Rev0)
+ end,
{DocId, Rev};
docid_rev(Id, _) ->
{Id, nil}.
-
index_of(Key, List) ->
index_of(Key, List, 1).
-
index_of(_, [], _) ->
throw({error, missing_named_view});
index_of(Key, [Key | _], Idx) ->
Idx;
index_of(Key, [_ | Rest], Idx) ->
- index_of(Key, Rest, Idx+1).
-
+ index_of(Key, Rest, Idx + 1).
mrverror(Mesg) ->
throw({query_parse_error, Mesg}).
-
%% Updates 2.x view files to 3.x or later view files
%% transparently, the first time the 2.x view file is opened by
%% 3.x or later.
@@ -960,11 +995,11 @@ maybe_update_index_file(State) ->
% open in read-only mode so we don't create
% the file if it doesn't exist.
case file:open(NewIndexFile, [read, raw]) of
- {ok, Fd_Read} ->
- % the new index file exists, there is nothing to do here.
- file:close(Fd_Read);
- _Error ->
- update_index_file(State)
+ {ok, Fd_Read} ->
+ % the new index file exists, there is nothing to do here.
+ file:close(Fd_Read);
+ _Error ->
+ update_index_file(State)
end.
update_index_file(State) ->
@@ -975,26 +1010,35 @@ update_index_file(State) ->
% If we have an old index, rename it to the new position.
case file:read_file_info(IndexFile) of
- {ok, _FileInfo} ->
- % Crash if the rename fails for any reason.
- % If the target exists, e.g. the next request will find the
- % new file and we are good. We might need to catch this
- % further up to avoid a full server crash.
- NewIndexFile = index_file(DbName, State#mrst.sig),
- couch_log:notice("Attempting to update legacy view index file"
- " from ~p to ~s", [IndexFile, NewIndexFile]),
- ok = filelib:ensure_dir(NewIndexFile),
- ok = file:rename(IndexFile, NewIndexFile),
- couch_log:notice("Successfully updated legacy view index file"
- " ~s", [IndexFile]),
- Sig;
- {error, enoent} ->
- % Ignore missing index file
- ok;
- {error, Reason} ->
- couch_log:error("Failed to update legacy view index file"
- " ~s : ~s", [IndexFile, file:format_error(Reason)]),
- ok
+ {ok, _FileInfo} ->
+ % Crash if the rename fails for any reason.
+ % If the target exists, e.g. the next request will find the
+ % new file and we are good. We might need to catch this
+ % further up to avoid a full server crash.
+ NewIndexFile = index_file(DbName, State#mrst.sig),
+ couch_log:notice(
+ "Attempting to update legacy view index file"
+ " from ~p to ~s",
+ [IndexFile, NewIndexFile]
+ ),
+ ok = filelib:ensure_dir(NewIndexFile),
+ ok = file:rename(IndexFile, NewIndexFile),
+ couch_log:notice(
+ "Successfully updated legacy view index file"
+ " ~s",
+ [IndexFile]
+ ),
+ Sig;
+ {error, enoent} ->
+ % Ignore missing index file
+ ok;
+ {error, Reason} ->
+ couch_log:error(
+ "Failed to update legacy view index file"
+ " ~s : ~s",
+ [IndexFile, file:format_error(Reason)]
+ ),
+ ok
end.
sig_vsn_2x(State) ->
@@ -1010,21 +1054,21 @@ sig_vsn_2x(State) ->
couch_hash:md5_hash(term_to_binary(SigInfo)).
old_view_format(View, SI, KSI) ->
-{
- mrview,
- View#mrview.id_num,
- View#mrview.update_seq,
- View#mrview.purge_seq,
- View#mrview.map_names,
- View#mrview.reduce_funs,
- View#mrview.def,
- View#mrview.btree,
- nil,
- nil,
- SI,
- KSI,
- View#mrview.options
-}.
+ {
+ mrview,
+ View#mrview.id_num,
+ View#mrview.update_seq,
+ View#mrview.purge_seq,
+ View#mrview.map_names,
+ View#mrview.reduce_funs,
+ View#mrview.def,
+ View#mrview.btree,
+ nil,
+ nil,
+ SI,
+ KSI,
+ View#mrview.options
+ }.
maybe_update_header(#mrheader{} = Header) ->
Header;
@@ -1050,7 +1094,6 @@ make_view_state({BTState, _SeqBTState, _KSeqBTState, UpdateSeq, PurgeSeq}) ->
make_view_state(nil) ->
{nil, 0, 0}.
-
get_key_btree_state(ViewState) ->
element(1, ViewState).
@@ -1066,18 +1109,14 @@ get_count(Reduction) ->
get_user_reds(Reduction) ->
element(2, Reduction).
-
% This is for backwards compatibility for seq btree reduces
get_external_size_reds(Reduction) when is_integer(Reduction) ->
0;
-
get_external_size_reds(Reduction) when tuple_size(Reduction) == 2 ->
0;
-
get_external_size_reds(Reduction) when tuple_size(Reduction) == 3 ->
element(3, Reduction).
-
make_reduce_fun(Lang, ReduceFuns) ->
FunSrcs = [FunSrc || {_, FunSrc} <- ReduceFuns],
fun
@@ -1093,20 +1132,21 @@ make_reduce_fun(Lang, ReduceFuns) ->
ExtAcc = ExtAcc0 + get_external_size_reds(Red),
{CountsAcc, URedsAcc, ExtAcc}
end,
- {Counts, UReds, ExternalSize} = lists:foldl(ExtractFun,
- {0, [], 0}, Reds),
+ {Counts, UReds, ExternalSize} = lists:foldl(
+ ExtractFun,
+ {0, [], 0},
+ Reds
+ ),
{ok, Result} = couch_query_servers:rereduce(Lang, FunSrcs, UReds),
{Counts, Result, ExternalSize}
end.
-
maybe_define_less_fun(#mrview{options = Options}) ->
case couch_util:get_value(<<"collation">>, Options) of
<<"raw">> -> undefined;
_ -> fun couch_ejson_compare:less_json_ids/2
end.
-
count_reduce(reduce, KVs) ->
CountFun = fun
({_, {dups, Vals}}, Acc) -> Acc + length(Vals);
@@ -1121,7 +1161,6 @@ count_reduce(rereduce, Reds) ->
Count = lists:foldl(CountFun, 0, Reds),
{Count, []}.
-
make_user_reds_reduce_fun(Lang, ReduceFuns, NthRed) ->
LPad = lists:duplicate(NthRed - 1, []),
RPad = lists:duplicate(length(ReduceFuns) - NthRed, []),
@@ -1140,18 +1179,15 @@ make_user_reds_reduce_fun(Lang, ReduceFuns, NthRed) ->
{0, LPad ++ Result ++ RPad}
end.
-
get_btree_state(nil) ->
nil;
get_btree_state(#btree{} = Btree) ->
couch_btree:get_state(Btree).
-
-extract_view_reduce({red, {N, _Lang, #mrview{reduce_funs=Reds}}, _Ref}) ->
+extract_view_reduce({red, {N, _Lang, #mrview{reduce_funs = Reds}}, _Ref}) ->
{_Name, FunSrc} = lists:nth(N, Reds),
FunSrc.
-
get_view_keys({Props}) ->
case couch_util:get_value(<<"keys">>, Props) of
undefined ->
@@ -1162,7 +1198,6 @@ get_view_keys({Props}) ->
throw({bad_request, "`keys` member must be an array."})
end.
-
get_view_queries({Props}) ->
case couch_util:get_value(<<"queries">>, Props) of
undefined ->
@@ -1173,8 +1208,11 @@ get_view_queries({Props}) ->
throw({bad_request, "`queries` member must be an array."})
end.
-
kv_external_size(KVList, Reduction) ->
- lists:foldl(fun([[Key, _], Value], Acc) ->
- ?term_size(Key) + ?term_size(Value) + Acc
- end, ?term_size(Reduction), KVList).
+ lists:foldl(
+ fun([[Key, _], Value], Acc) ->
+ ?term_size(Key) + ?term_size(Value) + Acc
+ end,
+ ?term_size(Reduction),
+ KVList
+ ).
diff --git a/src/couch_mrview/test/eunit/couch_mrview_all_docs_tests.erl b/src/couch_mrview/test/eunit/couch_mrview_all_docs_tests.erl
index bf8eb7e5b..1a81d4f0a 100644
--- a/src/couch_mrview/test/eunit/couch_mrview_all_docs_tests.erl
+++ b/src/couch_mrview/test/eunit/couch_mrview_all_docs_tests.erl
@@ -17,8 +17,6 @@
-define(TIMEOUT, 1000).
-
-
setup() ->
{ok, Db} = couch_mrview_test_util:init_db(?tempdb(), map),
Db.
@@ -28,16 +26,17 @@ teardown(Db) ->
couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
-
all_docs_test_() ->
{
"_all_docs view tests",
{
setup,
- fun test_util:start_couch/0, fun test_util:stop_couch/1,
+ fun test_util:start_couch/0,
+ fun test_util:stop_couch/1,
{
foreach,
- fun setup/0, fun teardown/1,
+ fun setup/0,
+ fun teardown/1,
[
fun should_query/1,
fun should_query_with_range/1,
@@ -50,47 +49,50 @@ all_docs_test_() ->
}
}.
-
should_query(Db) ->
Result = run_query(Db, []),
- Expect = {ok, [
- {meta, [{total, 11}, {offset, 0}]},
- mk_row(<<"1">>, <<"1-08d53a5760b95fce6df2e2c5b008be39">>),
- mk_row(<<"10">>, <<"1-a05b6ea2bc0243949f103d5b4f15f71e">>),
- mk_row(<<"2">>, <<"1-b57c77a9e6f7574ca6469f0d6dcd78bb">>),
- mk_row(<<"3">>, <<"1-7fbf84d56f8017880974402d60f5acd6">>),
- mk_row(<<"4">>, <<"1-fcaf5852c08ffb239ac8ce16c409f253">>),
- mk_row(<<"5">>, <<"1-aaac5d460fd40f9286e57b9bf12e23d2">>),
- mk_row(<<"6">>, <<"1-aca21c2e7bc5f8951424fcfc5d1209d8">>),
- mk_row(<<"7">>, <<"1-4374aeec17590d82f16e70f318116ad9">>),
- mk_row(<<"8">>, <<"1-55b9a29311341e07ec0a7ca13bc1b59f">>),
- mk_row(<<"9">>, <<"1-558c8487d9aee25399a91b5d31d90fe2">>),
- mk_row(<<"_design/bar">>, <<"1-a44e1dd1994a7717bf89c894ebd1f081">>)
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 11}, {offset, 0}]},
+ mk_row(<<"1">>, <<"1-08d53a5760b95fce6df2e2c5b008be39">>),
+ mk_row(<<"10">>, <<"1-a05b6ea2bc0243949f103d5b4f15f71e">>),
+ mk_row(<<"2">>, <<"1-b57c77a9e6f7574ca6469f0d6dcd78bb">>),
+ mk_row(<<"3">>, <<"1-7fbf84d56f8017880974402d60f5acd6">>),
+ mk_row(<<"4">>, <<"1-fcaf5852c08ffb239ac8ce16c409f253">>),
+ mk_row(<<"5">>, <<"1-aaac5d460fd40f9286e57b9bf12e23d2">>),
+ mk_row(<<"6">>, <<"1-aca21c2e7bc5f8951424fcfc5d1209d8">>),
+ mk_row(<<"7">>, <<"1-4374aeec17590d82f16e70f318116ad9">>),
+ mk_row(<<"8">>, <<"1-55b9a29311341e07ec0a7ca13bc1b59f">>),
+ mk_row(<<"9">>, <<"1-558c8487d9aee25399a91b5d31d90fe2">>),
+ mk_row(<<"_design/bar">>, <<"1-a44e1dd1994a7717bf89c894ebd1f081">>)
+ ]},
?_assertEqual(Expect, Result).
should_query_with_range(Db) ->
Result = run_query(Db, [{start_key, <<"3">>}, {end_key, <<"5">>}]),
- Expect = {ok, [
- {meta, [{total, 11}, {offset, 3}]},
- mk_row(<<"3">>, <<"1-7fbf84d56f8017880974402d60f5acd6">>),
- mk_row(<<"4">>, <<"1-fcaf5852c08ffb239ac8ce16c409f253">>),
- mk_row(<<"5">>, <<"1-aaac5d460fd40f9286e57b9bf12e23d2">>)
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 11}, {offset, 3}]},
+ mk_row(<<"3">>, <<"1-7fbf84d56f8017880974402d60f5acd6">>),
+ mk_row(<<"4">>, <<"1-fcaf5852c08ffb239ac8ce16c409f253">>),
+ mk_row(<<"5">>, <<"1-aaac5d460fd40f9286e57b9bf12e23d2">>)
+ ]},
?_assertEqual(Expect, Result).
should_query_with_range_rev(Db) ->
Result = run_query(Db, [
{direction, rev},
- {start_key, <<"5">>}, {end_key, <<"3">>},
+ {start_key, <<"5">>},
+ {end_key, <<"3">>},
{inclusive_end, true}
]),
- Expect = {ok, [
- {meta, [{total, 11}, {offset, 5}]},
- mk_row(<<"5">>, <<"1-aaac5d460fd40f9286e57b9bf12e23d2">>),
- mk_row(<<"4">>, <<"1-fcaf5852c08ffb239ac8ce16c409f253">>),
- mk_row(<<"3">>, <<"1-7fbf84d56f8017880974402d60f5acd6">>)
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 11}, {offset, 5}]},
+ mk_row(<<"5">>, <<"1-aaac5d460fd40f9286e57b9bf12e23d2">>),
+ mk_row(<<"4">>, <<"1-fcaf5852c08ffb239ac8ce16c409f253">>),
+ mk_row(<<"3">>, <<"1-7fbf84d56f8017880974402d60f5acd6">>)
+ ]},
?_assertEqual(Expect, Result).
should_query_with_limit_and_skip(Db) ->
@@ -99,12 +101,13 @@ should_query_with_limit_and_skip(Db) ->
{limit, 3},
{skip, 3}
]),
- Expect = {ok, [
- {meta, [{total, 11}, {offset, 5}]},
- mk_row(<<"5">>, <<"1-aaac5d460fd40f9286e57b9bf12e23d2">>),
- mk_row(<<"6">>, <<"1-aca21c2e7bc5f8951424fcfc5d1209d8">>),
- mk_row(<<"7">>, <<"1-4374aeec17590d82f16e70f318116ad9">>)
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 11}, {offset, 5}]},
+ mk_row(<<"5">>, <<"1-aaac5d460fd40f9286e57b9bf12e23d2">>),
+ mk_row(<<"6">>, <<"1-aca21c2e7bc5f8951424fcfc5d1209d8">>),
+ mk_row(<<"7">>, <<"1-4374aeec17590d82f16e70f318116ad9">>)
+ ]},
?_assertEqual(Expect, Result).
should_query_with_include_docs(Db) ->
@@ -113,26 +116,28 @@ should_query_with_include_docs(Db) ->
{end_key, <<"8">>},
{include_docs, true}
]),
- Doc = {[
- {<<"_id">>,<<"8">>},
- {<<"_rev">>, <<"1-55b9a29311341e07ec0a7ca13bc1b59f">>},
- {<<"val">>, 8}
- ]},
+ Doc =
+ {[
+ {<<"_id">>, <<"8">>},
+ {<<"_rev">>, <<"1-55b9a29311341e07ec0a7ca13bc1b59f">>},
+ {<<"val">>, 8}
+ ]},
Val = {[{rev, <<"1-55b9a29311341e07ec0a7ca13bc1b59f">>}]},
- Expect = {ok, [
- {meta, [{total, 11}, {offset, 8}]},
- {row, [{id, <<"8">>}, {key, <<"8">>}, {value, Val}, {doc, Doc}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 11}, {offset, 8}]},
+ {row, [{id, <<"8">>}, {key, <<"8">>}, {value, Val}, {doc, Doc}]}
+ ]},
?_assertEqual(Expect, Result).
should_query_empty_views(Db) ->
Result = couch_mrview:query_view(Db, <<"_design/bar">>, <<"bing">>),
- Expect = {ok, [
- {meta, [{total, 0}, {offset, 0}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 0}, {offset, 0}]}
+ ]},
?_assertEqual(Expect, Result).
-
mk_row(Id, Rev) ->
{row, [{id, Id}, {key, Id}, {value, {[{rev, Rev}]}}]}.
diff --git a/src/couch_mrview/test/eunit/couch_mrview_collation_tests.erl b/src/couch_mrview/test/eunit/couch_mrview_collation_tests.erl
index 0d2afbe3c..c00b97b33 100644
--- a/src/couch_mrview/test/eunit/couch_mrview_collation_tests.erl
+++ b/src/couch_mrview/test/eunit/couch_mrview_collation_tests.erl
@@ -56,10 +56,8 @@
% Values with depth > 10 trigger the erlang collation fallback in couch_ejson_compare
{[{<<"x">>, [[[[[[[[[[[<<"y">>]]]]]]]]]]]}]}
-
]).
-
setup() ->
{ok, Db1} = couch_mrview_test_util:new_db(?tempdb(), map),
Docs = [couch_mrview_test_util:ddoc(red) | make_docs()],
@@ -71,16 +69,17 @@ teardown(Db) ->
couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
-
collation_test_() ->
{
"Collation tests",
{
setup,
- fun test_util:start_couch/0, fun test_util:stop_couch/1,
+ fun test_util:start_couch/0,
+ fun test_util:stop_couch/1,
{
foreach,
- fun setup/0, fun teardown/1,
+ fun setup/0,
+ fun teardown/1,
[
fun should_collate_fwd/1,
fun should_collate_rev/1,
@@ -96,7 +95,6 @@ collation_test_() ->
}
}.
-
should_collate_fwd(Db) ->
{ok, Results} = run_query(Db, []),
Expect = [{meta, [{total, length(?VALUES)}, {offset, 0}]}] ++ rows(),
@@ -108,100 +106,127 @@ should_collate_rev(Db) ->
?_assertEquiv(Expect, Results).
should_collate_range_(Db) ->
- Index = lists:zip(lists:seq(0, length(?VALUES)-1), ?VALUES),
- lists:map(fun(V) ->
- {ok, Results} = run_query(Db, [{start_key, V}, {end_key, V}]),
- Expect = [
- {meta, [{total, length(?VALUES)}, find_offset(Index, V)]} |
- find_matching_rows(Index, V)
- ],
- ?_assertEquiv(Expect, Results)
- end, ?VALUES).
+ Index = lists:zip(lists:seq(0, length(?VALUES) - 1), ?VALUES),
+ lists:map(
+ fun(V) ->
+ {ok, Results} = run_query(Db, [{start_key, V}, {end_key, V}]),
+ Expect = [
+ {meta, [{total, length(?VALUES)}, find_offset(Index, V)]}
+ | find_matching_rows(Index, V)
+ ],
+ ?_assertEquiv(Expect, Results)
+ end,
+ ?VALUES
+ ).
find_offset(Index, Value) ->
- [{Offset, _} | _] = lists:dropwhile(fun({_, V}) ->
- couch_ejson_compare:less(Value, V) =/= 0
- end, Index),
+ [{Offset, _} | _] = lists:dropwhile(
+ fun({_, V}) ->
+ couch_ejson_compare:less(Value, V) =/= 0
+ end,
+ Index
+ ),
{offset, Offset}.
find_matching_rows(Index, Value) ->
- Matches = lists:filter(fun({_, V}) ->
- couch_ejson_compare:less(Value, V) =:= 0
- end, Index),
- lists:map(fun({Id, V}) ->
- {row, [{id, list_to_binary(integer_to_list(Id))}, {key, V}, {value, 0}]}
- end, Matches).
+ Matches = lists:filter(
+ fun({_, V}) ->
+ couch_ejson_compare:less(Value, V) =:= 0
+ end,
+ Index
+ ),
+ lists:map(
+ fun({Id, V}) ->
+ {row, [{id, list_to_binary(integer_to_list(Id))}, {key, V}, {value, 0}]}
+ end,
+ Matches
+ ).
should_collate_with_inclusive_end_fwd(Db) ->
Opts = [{end_key, <<"b">>}, {inclusive_end, true}],
{ok, Rows0} = run_query(Db, Opts),
LastRow = lists:last(Rows0),
- Expect = {row, [{id,<<"10">>}, {key,<<"b">>}, {value,0}]},
+ Expect = {row, [{id, <<"10">>}, {key, <<"b">>}, {value, 0}]},
?_assertEqual(Expect, LastRow).
should_collate_with_inclusive_end_rev(Db) ->
Opts = [{end_key, <<"b">>}, {inclusive_end, true}, {direction, rev}],
{ok, Rows} = run_query(Db, Opts),
LastRow = lists:last(Rows),
- Expect = {row, [{id,<<"10">>}, {key,<<"b">>}, {value,0}]},
+ Expect = {row, [{id, <<"10">>}, {key, <<"b">>}, {value, 0}]},
?_assertEqual(Expect, LastRow).
should_collate_without_inclusive_end_fwd(Db) ->
Opts = [{end_key, <<"b">>}, {inclusive_end, false}],
{ok, Rows0} = run_query(Db, Opts),
LastRow = lists:last(Rows0),
- Expect = {row, [{id,<<"9">>}, {key,<<"aa">>}, {value,0}]},
+ Expect = {row, [{id, <<"9">>}, {key, <<"aa">>}, {value, 0}]},
?_assertEqual(Expect, LastRow).
should_collate_without_inclusive_end_rev(Db) ->
Opts = [{end_key, <<"b">>}, {inclusive_end, false}, {direction, rev}],
{ok, Rows} = run_query(Db, Opts),
LastRow = lists:last(Rows),
- Expect = {row, [{id,<<"11">>}, {key,<<"B">>}, {value,0}]},
+ Expect = {row, [{id, <<"11">>}, {key, <<"B">>}, {value, 0}]},
?_assertEqual(Expect, LastRow).
should_collate_with_endkey_docid(Db) ->
?_test(begin
{ok, Rows0} = run_query(Db, [
- {end_key, <<"b">>}, {end_key_docid, <<"10">>},
+ {end_key, <<"b">>},
+ {end_key_docid, <<"10">>},
{inclusive_end, false}
]),
Result0 = lists:last(Rows0),
- Expect0 = {row, [{id,<<"9">>}, {key,<<"aa">>}, {value,0}]},
+ Expect0 = {row, [{id, <<"9">>}, {key, <<"aa">>}, {value, 0}]},
?assertEqual(Expect0, Result0),
{ok, Rows1} = run_query(Db, [
- {end_key, <<"b">>}, {end_key_docid, <<"11">>},
+ {end_key, <<"b">>},
+ {end_key_docid, <<"11">>},
{inclusive_end, false}
]),
Result1 = lists:last(Rows1),
- Expect1 = {row, [{id,<<"10">>}, {key,<<"b">>}, {value,0}]},
+ Expect1 = {row, [{id, <<"10">>}, {key, <<"b">>}, {value, 0}]},
?assertEqual(Expect1, Result1)
end).
should_use_collator_for_reduce_grouping(Db) ->
- UniqueKeys = lists:usort(fun(A, B) ->
- not couch_ejson_compare:less_json(B, A)
- end, ?VALUES),
- {ok, [{meta,_} | Rows]} = reduce_query(Db, [{group_level, exact}]),
+ UniqueKeys = lists:usort(
+ fun(A, B) ->
+ not couch_ejson_compare:less_json(B, A)
+ end,
+ ?VALUES
+ ),
+ {ok, [{meta, _} | Rows]} = reduce_query(Db, [{group_level, exact}]),
?_assertEqual(length(UniqueKeys), length(Rows)).
make_docs() ->
- {Docs, _} = lists:foldl(fun(V, {Docs0, Count}) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, list_to_binary(integer_to_list(Count))},
- {<<"foo">>, V}
- ]}),
- {[Doc | Docs0], Count+1}
- end, {[], 0}, ?VALUES),
+ {Docs, _} = lists:foldl(
+ fun(V, {Docs0, Count}) ->
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, list_to_binary(integer_to_list(Count))},
+ {<<"foo">>, V}
+ ]}
+ ),
+ {[Doc | Docs0], Count + 1}
+ end,
+ {[], 0},
+ ?VALUES
+ ),
Docs.
rows() ->
- {Rows, _} = lists:foldl(fun(V, {Rows0, Count}) ->
- Id = list_to_binary(integer_to_list(Count)),
- Row = {row, [{id, Id}, {key, V}, {value, 0}]},
- {[Row | Rows0], Count+1}
- end, {[], 0}, ?VALUES),
+ {Rows, _} = lists:foldl(
+ fun(V, {Rows0, Count}) ->
+ Id = list_to_binary(integer_to_list(Count)),
+ Row = {row, [{id, Id}, {key, V}, {value, 0}]},
+ {[Row | Rows0], Count + 1}
+ end,
+ {[], 0},
+ ?VALUES
+ ),
lists:reverse(Rows).
run_query(Db, Opts) ->
diff --git a/src/couch_mrview/test/eunit/couch_mrview_compact_tests.erl b/src/couch_mrview/test/eunit/couch_mrview_compact_tests.erl
index 7664becdc..df035c649 100644
--- a/src/couch_mrview/test/eunit/couch_mrview_compact_tests.erl
+++ b/src/couch_mrview/test/eunit/couch_mrview_compact_tests.erl
@@ -17,7 +17,6 @@
-define(TIMEOUT, 1000).
-
setup() ->
{ok, Db} = couch_mrview_test_util:init_db(?tempdb(), map, 1000),
ok = meck:new(couch_mrview_compactor, [passthrough]),
@@ -29,16 +28,17 @@ teardown(Db) ->
couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
-
compaction_test_() ->
{
"Compaction tests",
{
setup,
- fun test_util:start_couch/0, fun test_util:stop_couch/1,
+ fun test_util:start_couch/0,
+ fun test_util:stop_couch/1,
{
foreach,
- fun setup/0, fun teardown/1,
+ fun setup/0,
+ fun teardown/1,
[
fun should_swap/1,
fun should_remove/1
@@ -47,7 +47,6 @@ compaction_test_() ->
}
}.
-
should_swap(Db) ->
?_test(begin
couch_mrview:query_view(Db, <<"_design/bar">>, <<"baz">>),
@@ -57,9 +56,12 @@ should_swap(Db) ->
{'DOWN', MonRef, process, _, _} -> ok
after ?TIMEOUT ->
erlang:error(
- {assertion_failed,
- [{module, ?MODULE}, {line, ?LINE},
- {reason, "compaction failed"}]})
+ {assertion_failed, [
+ {module, ?MODULE},
+ {line, ?LINE},
+ {reason, "compaction failed"}
+ ]}
+ )
end,
QPid ! {self(), continue},
receive
@@ -67,13 +69,15 @@ should_swap(Db) ->
?assertEqual(1000, Count)
after ?TIMEOUT ->
erlang:error(
- {assertion_failed,
- [{module, ?MODULE}, {line, ?LINE},
- {reason, "query failed"}]})
+ {assertion_failed, [
+ {module, ?MODULE},
+ {line, ?LINE},
+ {reason, "query failed"}
+ ]}
+ )
end
end).
-
should_remove(Db) ->
?_test(begin
DDoc = <<"_design/bar">>,
@@ -87,29 +91,40 @@ should_remove(Db) ->
receive
{'DOWN', MonRef, process, _, crash} ->
meck:wait(couch_mrview_compactor, remove_compacted, '_', 100),
- ?assertEqual(1, meck:num_calls(
- couch_mrview_compactor, remove_compacted, '_', IndexPid)),
+ ?assertEqual(
+ 1,
+ meck:num_calls(
+ couch_mrview_compactor, remove_compacted, '_', IndexPid
+ )
+ ),
?assert(is_process_alive(IndexPid)),
?assert(is_process_alive(CompactorPid))
after ?TIMEOUT ->
erlang:error(
{assertion_failed, [
- {module, ?MODULE}, {line, ?LINE},
- {reason, "compaction didn't exit :/"}]})
+ {module, ?MODULE},
+ {line, ?LINE},
+ {reason, "compaction didn't exit :/"}
+ ]}
+ )
end
end).
-
start_query(Db) ->
Self = self(),
Pid = spawn(fun() ->
CB = fun
- (_, wait) -> receive {Self, continue} -> {ok, 0} end;
- ({row, _}, Count) -> {ok, Count+1};
- (_, Count) -> {ok, Count}
+ (_, wait) ->
+ receive
+ {Self, continue} -> {ok, 0}
+ end;
+ ({row, _}, Count) ->
+ {ok, Count + 1};
+ (_, Count) ->
+ {ok, Count}
end,
{ok, Result} =
- couch_mrview:query_view(Db, <<"_design/bar">>, <<"baz">>, [], CB, wait),
+ couch_mrview:query_view(Db, <<"_design/bar">>, <<"baz">>, [], CB, wait),
Self ! {self(), Result}
end),
{ok, Pid}.
diff --git a/src/couch_mrview/test/eunit/couch_mrview_ddoc_updated_tests.erl b/src/couch_mrview/test/eunit/couch_mrview_ddoc_updated_tests.erl
index 4310157eb..2a6299448 100644
--- a/src/couch_mrview/test/eunit/couch_mrview_ddoc_updated_tests.erl
+++ b/src/couch_mrview/test/eunit/couch_mrview_ddoc_updated_tests.erl
@@ -17,30 +17,33 @@
-define(TIMEOUT, 1000).
-
setup() ->
Name = ?tempdb(),
couch_server:delete(Name, [?ADMIN_CTX]),
{ok, Db} = couch_db:create(Name, [?ADMIN_CTX]),
- DDoc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/bar">>},
- {<<"views">>, {[
- {<<"baz">>, {[
- {<<"map">>, <<
- "function(doc) {\n"
- " emit(doc.val, doc.val);\n"
- "}"
- >>}
- ]}}
- ]}}
- ]}),
+ DDoc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/bar">>},
+ {<<"views">>,
+ {[
+ {<<"baz">>,
+ {[
+ {<<"map">>, <<
+ "function(doc) {\n"
+ " emit(doc.val, doc.val);\n"
+ "}"
+ >>}
+ ]}}
+ ]}}
+ ]}
+ ),
[Doc1 | Docs999] = couch_mrview_test_util:make_docs(map, 100),
{ok, _} = couch_db:update_docs(Db, [DDoc, Doc1], []),
{ok, Db2} = couch_db:reopen(Db),
% run a query with 1 doc to initialize couch_index process
CB = fun
- ({row, _}, Count) -> {ok, Count+1};
+ ({row, _}, Count) -> {ok, Count + 1};
(_, Count) -> {ok, Count}
end,
{ok, _} =
@@ -63,16 +66,17 @@ teardown(Db) ->
couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
-
ddoc_update_test_() ->
{
"Check ddoc update actions",
{
setup,
- fun test_util:start_couch/0, fun test_util:stop_couch/1,
+ fun test_util:start_couch/0,
+ fun test_util:stop_couch/1,
{
foreach,
- fun setup/0, fun teardown/1,
+ fun setup/0,
+ fun teardown/1,
[
fun check_indexing_stops_on_ddoc_change/1
]
@@ -80,7 +84,6 @@ ddoc_update_test_() ->
}
}.
-
check_indexing_stops_on_ddoc_change(Db) ->
?_test(begin
DDocID = <<"_design/bar">>,
@@ -91,17 +94,20 @@ check_indexing_stops_on_ddoc_change(Db) ->
?assertEqual(1, length(AliveBefore)),
{ok, DDoc} = couch_db:open_doc(Db, DDocID, [ejson_body, ?ADMIN_CTX]),
- DDocJson2 = couch_doc:from_json_obj({[
- {<<"_id">>, DDocID},
- {<<"_deleted">>, true},
- {<<"_rev">>, couch_doc:rev_to_str(DDoc#doc.revs)}
- ]}),
+ DDocJson2 = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, DDocID},
+ {<<"_deleted">>, true},
+ {<<"_rev">>, couch_doc:rev_to_str(DDoc#doc.revs)}
+ ]}
+ ),
% spawn a process for query
Self = self(),
QPid = spawn(fun() ->
{ok, Result} = couch_mrview:query_view(
- Db, <<"_design/bar">>, <<"baz">>, []),
+ Db, <<"_design/bar">>, <<"baz">>, []
+ ),
Self ! {self(), Result}
end),
@@ -112,8 +118,12 @@ check_indexing_stops_on_ddoc_change(Db) ->
?assertEqual(Msg, ddoc_updated)
after ?TIMEOUT ->
erlang:error(
- {assertion_failed, [{module, ?MODULE}, {line, ?LINE},
- {reason, "test failed"}]})
+ {assertion_failed, [
+ {module, ?MODULE},
+ {line, ?LINE},
+ {reason, "test failed"}
+ ]}
+ )
end,
%% assert that previously running indexes are gone
@@ -123,11 +133,11 @@ check_indexing_stops_on_ddoc_change(Db) ->
?assertEqual(0, length(AliveAfter))
end).
-
get_indexes_by_ddoc(DDocID, N) ->
Indexes = test_util:wait(fun() ->
Indxs = ets:match_object(
- couchdb_indexes_by_db, {'$1', {DDocID, '$2'}}),
+ couchdb_indexes_by_db, {'$1', {DDocID, '$2'}}
+ ),
case length(Indxs) == N of
true ->
Indxs;
@@ -135,11 +145,13 @@ get_indexes_by_ddoc(DDocID, N) ->
wait
end
end),
- lists:foldl(fun({DbName, {_DDocID, Sig}}, Acc) ->
- case ets:lookup(couchdb_indexes_by_sig, {DbName, Sig}) of
- [{_, Pid}] -> [Pid|Acc];
- _ -> Acc
- end
- end, [], Indexes).
-
-
+ lists:foldl(
+ fun({DbName, {_DDocID, Sig}}, Acc) ->
+ case ets:lookup(couchdb_indexes_by_sig, {DbName, Sig}) of
+ [{_, Pid}] -> [Pid | Acc];
+ _ -> Acc
+ end
+ end,
+ [],
+ Indexes
+ ).
diff --git a/src/couch_mrview/test/eunit/couch_mrview_ddoc_validation_tests.erl b/src/couch_mrview/test/eunit/couch_mrview_ddoc_validation_tests.erl
index ce2be8904..3e4cbc84f 100644
--- a/src/couch_mrview/test/eunit/couch_mrview_ddoc_validation_tests.erl
+++ b/src/couch_mrview/test/eunit/couch_mrview_ddoc_validation_tests.erl
@@ -31,10 +31,12 @@ ddoc_validation_test_() ->
"ddoc validation tests",
{
setup,
- fun test_util:start_couch/0, fun test_util:stop_couch/1,
+ fun test_util:start_couch/0,
+ fun test_util:stop_couch/1,
{
foreach,
- fun setup/0, fun teardown/1,
+ fun setup/0,
+ fun teardown/1,
[
fun should_reject_invalid_js_map/1,
fun should_reject_invalid_js_reduce/1,
@@ -79,344 +81,477 @@ ddoc_validation_test_() ->
}.
should_reject_invalid_js_map(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_invalid_js_map">>},
- {<<"views">>, {[
- {<<"foo">>, {[
- {<<"map">>, <<"function(doc) }{">>}
- ]}}
- ]}}
- ]}),
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_invalid_js_map">>},
+ {<<"views">>,
+ {[
+ {<<"foo">>,
+ {[
+ {<<"map">>, <<"function(doc) }{">>}
+ ]}}
+ ]}}
+ ]}
+ ),
?_assertThrow(
{bad_request, compilation_error, _},
- couch_db:update_doc(Db, Doc, [])).
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_reject_invalid_js_reduce(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_invalid_js_reduce">>},
- {<<"views">>, {[
- {<<"foo">>, {[
- {<<"map">>, <<"function(doc) { emit(null); }">>},
- {<<"reduce">>, <<"function(k, v, r) }{}">>}
- ]}}
- ]}}
- ]}),
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_invalid_js_reduce">>},
+ {<<"views">>,
+ {[
+ {<<"foo">>,
+ {[
+ {<<"map">>, <<"function(doc) { emit(null); }">>},
+ {<<"reduce">>, <<"function(k, v, r) }{}">>}
+ ]}}
+ ]}}
+ ]}
+ ),
?_assertThrow(
{bad_request, compilation_error, _},
- couch_db:update_doc(Db, Doc, [])).
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_reject_invalid_builtin_reduce(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_invalid_builtin_reduce">>},
- {<<"views">>, {[
- {<<"foo">>, {[
- {<<"map">>, <<"function(doc) { emit(null); }">>},
- {<<"reduce">>, <<"_foobar">>}
- ]}}
- ]}}
- ]}),
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_invalid_builtin_reduce">>},
+ {<<"views">>,
+ {[
+ {<<"foo">>,
+ {[
+ {<<"map">>, <<"function(doc) { emit(null); }">>},
+ {<<"reduce">>, <<"_foobar">>}
+ ]}}
+ ]}}
+ ]}
+ ),
?_assertThrow(
{bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_reject_non_object_options(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_non_object_options">>},
- {<<"options">>, <<"invalid">>}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_non_object_options">>},
+ {<<"options">>, <<"invalid">>}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_reject_non_object_filters(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_non_object_filters">>},
- {<<"filters">>, <<"invalid">>}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_non_object_filters">>},
+ {<<"filters">>, <<"invalid">>}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_accept_obj_in_filters(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_accept_obj_in_filters">>},
- {<<"filters">>, ?LIB}
- ]}),
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_accept_obj_in_filters">>},
+ {<<"filters">>, ?LIB}
+ ]}
+ ),
?_assertMatch({ok, _}, couch_db:update_doc(Db, Doc, [])).
should_reject_non_object_lists(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_non_object_lists">>},
- {<<"lists">>, <<"invalid">>}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_non_object_lists">>},
+ {<<"lists">>, <<"invalid">>}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_reject_non_object_shows(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_non_object_shows">>},
- {<<"shows">>, <<"invalid">>}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_non_object_shows">>},
+ {<<"shows">>, <<"invalid">>}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_accept_obj_in_shows(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_accept_obj_in_shows">>},
- {<<"shows">>, ?LIB}
- ]}),
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_accept_obj_in_shows">>},
+ {<<"shows">>, ?LIB}
+ ]}
+ ),
?_assertMatch({ok, _}, couch_db:update_doc(Db, Doc, [])).
should_reject_non_object_updates(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_non_object_updates">>},
- {<<"updates">>, <<"invalid">>}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_non_object_updates">>},
+ {<<"updates">>, <<"invalid">>}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_accept_obj_in_updates(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_accept_obj_in_updates">>},
- {<<"updates">>, ?LIB}
- ]}),
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_accept_obj_in_updates">>},
+ {<<"updates">>, ?LIB}
+ ]}
+ ),
?_assertMatch({ok, _}, couch_db:update_doc(Db, Doc, [])).
should_reject_non_object_views(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_non_object_views">>},
- {<<"views">>, <<"invalid">>}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_non_object_views">>},
+ {<<"views">>, <<"invalid">>}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_reject_non_string_language(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_non_string_language">>},
- {<<"language">>, 1}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_non_string_language">>},
+ {<<"language">>, 1}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_reject_non_string_validate_doc_update(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_non_string_vdu">>},
- {<<"validate_doc_update">>, 1}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_non_string_vdu">>},
+ {<<"validate_doc_update">>, 1}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_accept_string_rewrites(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_non_array_rewrites">>},
- {<<"rewrites">>, <<"function(req){}">>}
- ]}),
- ?_assertMatch({ok,_}, couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_non_array_rewrites">>},
+ {<<"rewrites">>, <<"function(req){}">>}
+ ]}
+ ),
+ ?_assertMatch({ok, _}, couch_db:update_doc(Db, Doc, [])).
should_reject_bad_rewrites(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_non_array_rewrites">>},
- {<<"rewrites">>, 42}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_non_array_rewrites">>},
+ {<<"rewrites">>, 42}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_accept_option(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_accept_options">>},
- {<<"options">>, {[ {<<"option1">>, <<"function(doc,req){}">>} ]}}
- ]}),
- ?_assertMatch({ok,_}, couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_accept_options">>},
+ {<<"options">>, {[{<<"option1">>, <<"function(doc,req){}">>}]}}
+ ]}
+ ),
+ ?_assertMatch({ok, _}, couch_db:update_doc(Db, Doc, [])).
should_accept_any_option(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_accept_any_option">>},
- {<<"options">>, {[ {<<"option1">>, true} ]}}
- ]}),
- ?_assertMatch({ok,_}, couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_accept_any_option">>},
+ {<<"options">>, {[{<<"option1">>, true}]}}
+ ]}
+ ),
+ ?_assertMatch({ok, _}, couch_db:update_doc(Db, Doc, [])).
should_accept_filter(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_accept_filters">>},
- {<<"filters">>, {[ {<<"filter1">>, <<"function(doc,req){}">>} ]}}
- ]}),
- ?_assertMatch({ok,_}, couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_accept_filters">>},
+ {<<"filters">>, {[{<<"filter1">>, <<"function(doc,req){}">>}]}}
+ ]}
+ ),
+ ?_assertMatch({ok, _}, couch_db:update_doc(Db, Doc, [])).
should_reject_non_string_or_obj_filter_function(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_non_string_or_obj_filter_function">>},
- {<<"filters">>, {[ {<<"filter1">>, 1} ]}}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_non_string_or_obj_filter_function">>},
+ {<<"filters">>, {[{<<"filter1">>, 1}]}}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_accept_list(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_accept_lists">>},
- {<<"lists">>, {[ {<<"list1">>, <<"function(doc,req){}">>} ]}}
- ]}),
- ?_assertMatch({ok,_}, couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_accept_lists">>},
+ {<<"lists">>, {[{<<"list1">>, <<"function(doc,req){}">>}]}}
+ ]}
+ ),
+ ?_assertMatch({ok, _}, couch_db:update_doc(Db, Doc, [])).
should_reject_non_string_or_obj_list_function(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_non_string_or_obj_list_function">>},
- {<<"lists">>, {[ {<<"list1">>, 1} ]}}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_non_string_or_obj_list_function">>},
+ {<<"lists">>, {[{<<"list1">>, 1}]}}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_accept_obj_in_lists(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_accept_obj_in_lists">>},
- {<<"lists">>, ?LIB}
- ]}),
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_accept_obj_in_lists">>},
+ {<<"lists">>, ?LIB}
+ ]}
+ ),
?_assertMatch({ok, _}, couch_db:update_doc(Db, Doc, [])).
-
should_accept_show(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_accept_shows">>},
- {<<"shows">>, {[ {<<"show1">>, <<"function(doc,req){}">>} ]}}
- ]}),
- ?_assertMatch({ok,_}, couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_accept_shows">>},
+ {<<"shows">>, {[{<<"show1">>, <<"function(doc,req){}">>}]}}
+ ]}
+ ),
+ ?_assertMatch({ok, _}, couch_db:update_doc(Db, Doc, [])).
should_reject_non_string_or_obj_show_function(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_non_string_or_obj_show_function">>},
- {<<"shows">>, {[ {<<"show1">>, 1} ]}}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_non_string_or_obj_show_function">>},
+ {<<"shows">>, {[{<<"show1">>, 1}]}}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_accept_update(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_accept_updates">>},
- {<<"updates">>, {[ {<<"update1">>, <<"function(doc,req){}">>} ]}}
- ]}),
- ?_assertMatch({ok,_}, couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_accept_updates">>},
+ {<<"updates">>, {[{<<"update1">>, <<"function(doc,req){}">>}]}}
+ ]}
+ ),
+ ?_assertMatch({ok, _}, couch_db:update_doc(Db, Doc, [])).
should_reject_non_string_or_obj_update_function(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_non_string_or_obj_update_function">>},
- {<<"updates">>, {[ {<<"update1">>, 1} ]}}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_non_string_or_obj_update_function">>},
+ {<<"updates">>, {[{<<"update1">>, 1}]}}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_accept_view(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_accept_view">>},
- {<<"views">>, {[
- {<<"view1">>, {[{<<"map">>, <<"function(d){}">>}]}}
- ]}}
- ]}),
- ?_assertMatch({ok,_}, couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_accept_view">>},
+ {<<"views">>,
+ {[
+ {<<"view1">>, {[{<<"map">>, <<"function(d){}">>}]}}
+ ]}}
+ ]}
+ ),
+ ?_assertMatch({ok, _}, couch_db:update_doc(Db, Doc, [])).
should_accept_view_with_reduce(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_accept_view_with_reduce">>},
- {<<"views">>, {[
- {<<"view1">>, {[
- {<<"map">>, <<"function(d){}">>},
- {<<"reduce">>,<<"function(d){}">>}
- ]}}
- ]}}
- ]}),
- ?_assertMatch({ok,_}, couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_accept_view_with_reduce">>},
+ {<<"views">>,
+ {[
+ {<<"view1">>,
+ {[
+ {<<"map">>, <<"function(d){}">>},
+ {<<"reduce">>, <<"function(d){}">>}
+ ]}}
+ ]}}
+ ]}
+ ),
+ ?_assertMatch({ok, _}, couch_db:update_doc(Db, Doc, [])).
should_accept_view_with_lib(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_accept_view_with_lib">>},
- {<<"views">>, {[
- {<<"view1">>, {[
- {<<"map">>, <<"function(d){}">>}
- ]}},
- {<<"lib">>, {[
- {<<"lib1">>, <<"x=42">>}
- ]}}
- ]}}
- ]}),
- ?_assertMatch({ok,_}, couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_accept_view_with_lib">>},
+ {<<"views">>,
+ {[
+ {<<"view1">>,
+ {[
+ {<<"map">>, <<"function(d){}">>}
+ ]}},
+ {<<"lib">>,
+ {[
+ {<<"lib1">>, <<"x=42">>}
+ ]}}
+ ]}}
+ ]}
+ ),
+ ?_assertMatch({ok, _}, couch_db:update_doc(Db, Doc, [])).
should_reject_view_that_is_not_an_object(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_non_object_view">>},
- {<<"views">>, {[{<<"view1">>, <<"thisisbad">>}]}}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_non_object_view">>},
+ {<<"views">>, {[{<<"view1">>, <<"thisisbad">>}]}}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_reject_view_without_map_function(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_accept_view_without_map">>},
- {<<"views">>, {[
- {<<"view1">>, {[]}}
- ]}}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
-
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_accept_view_without_map">>},
+ {<<"views">>,
+ {[
+ {<<"view1">>, {[]}}
+ ]}}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_reject_view_with_non_string_map_function(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_view_with_nonstr_map">>},
- {<<"views">>, {[
- {<<"view1">>, {[
- {<<"map">>,{[]}}
- ]}}
- ]}}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_view_with_nonstr_map">>},
+ {<<"views">>,
+ {[
+ {<<"view1">>,
+ {[
+ {<<"map">>, {[]}}
+ ]}}
+ ]}}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_reject_view_with_non_string_reduce_function(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_view_with_nonstr_reduce">>},
- {<<"views">>, {[
- {<<"view1">>, {[
- {<<"map">>,<<"function(d){}">>},
- {<<"reduce">>,1}
- ]}}
- ]}}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_view_with_nonstr_reduce">>},
+ {<<"views">>,
+ {[
+ {<<"view1">>,
+ {[
+ {<<"map">>, <<"function(d){}">>},
+ {<<"reduce">>, 1}
+ ]}}
+ ]}}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
should_accept_any_in_lib(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_accept_any_in_lib">>},
- {<<"views">>, {[
- {<<"view1">>, {[
- {<<"map">>, <<"function(d){}">>}
- ]}},
- {<<"lib">>, {[{<<"lib1">>, {[]}}]}}
- ]}}
- ]}),
- ?_assertMatch({ok,_}, couch_db:update_doc(Db, Doc, [])).
-
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_accept_any_in_lib">>},
+ {<<"views">>,
+ {[
+ {<<"view1">>,
+ {[
+ {<<"map">>, <<"function(d){}">>}
+ ]}},
+ {<<"lib">>, {[{<<"lib1">>, {[]}}]}}
+ ]}}
+ ]}
+ ),
+ ?_assertMatch({ok, _}, couch_db:update_doc(Db, Doc, [])).
should_accept_map_object_for_queries(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_accept_map_objects_for_queries">>},
- {<<"language">>, <<"query">>},
- {<<"views">>, {[
- {<<"view1">>, {[
- {<<"map">>, {[
- {<<"x">>, <<"y">>}
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_accept_map_objects_for_queries">>},
+ {<<"language">>, <<"query">>},
+ {<<"views">>,
+ {[
+ {<<"view1">>,
+ {[
+ {<<"map">>,
+ {[
+ {<<"x">>, <<"y">>}
+ ]}}
+ ]}}
]}}
- ]}}
- ]}}
- ]}),
- ?_assertMatch({ok,_}, couch_db:update_doc(Db, Doc, [])).
-
+ ]}
+ ),
+ ?_assertMatch({ok, _}, couch_db:update_doc(Db, Doc, [])).
should_reject_map_non_objects_for_queries(Db) ->
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/should_reject_map_non_objects__with_nonstr_reduce">>},
- {<<"language">>, <<"query">>},
- {<<"views">>, {[
- {<<"view1">>, {[
- {<<"map">>, <<"function(d){}">>}
- ]}}
- ]}}
- ]}),
- ?_assertThrow({bad_request, invalid_design_doc, _},
- couch_db:update_doc(Db, Doc, [])).
+ Doc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/should_reject_map_non_objects__with_nonstr_reduce">>},
+ {<<"language">>, <<"query">>},
+ {<<"views">>,
+ {[
+ {<<"view1">>,
+ {[
+ {<<"map">>, <<"function(d){}">>}
+ ]}}
+ ]}}
+ ]}
+ ),
+ ?_assertThrow(
+ {bad_request, invalid_design_doc, _},
+ couch_db:update_doc(Db, Doc, [])
+ ).
diff --git a/src/couch_mrview/test/eunit/couch_mrview_design_docs_tests.erl b/src/couch_mrview/test/eunit/couch_mrview_design_docs_tests.erl
index aedd42865..b1de2839d 100644
--- a/src/couch_mrview/test/eunit/couch_mrview_design_docs_tests.erl
+++ b/src/couch_mrview/test/eunit/couch_mrview_design_docs_tests.erl
@@ -17,8 +17,6 @@
-define(TIMEOUT, 1000).
-
-
setup() ->
{ok, Db} = couch_mrview_test_util:init_db(?tempdb(), design),
Db.
@@ -28,16 +26,17 @@ teardown(Db) ->
couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
-
design_docs_test_() ->
{
"_design_docs view tests",
{
setup,
- fun test_util:start_couch/0, fun test_util:stop_couch/1,
+ fun test_util:start_couch/0,
+ fun test_util:stop_couch/1,
{
foreach,
- fun setup/0, fun teardown/1,
+ fun setup/0,
+ fun teardown/1,
[
fun should_query/1,
fun should_query_with_range/1,
@@ -49,22 +48,22 @@ design_docs_test_() ->
}
}.
-
should_query(Db) ->
Result = run_query(Db, []),
- Expect = {ok, [
- {meta, [{total, 10}, {offset, 10}]},
- mk_row(<<"_design/bar01">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
- mk_row(<<"_design/bar02">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
- mk_row(<<"_design/bar03">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
- mk_row(<<"_design/bar04">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
- mk_row(<<"_design/bar05">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
- mk_row(<<"_design/bar06">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
- mk_row(<<"_design/bar07">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
- mk_row(<<"_design/bar08">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
- mk_row(<<"_design/bar09">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
- mk_row(<<"_design/bar10">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>)
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 10}, {offset, 10}]},
+ mk_row(<<"_design/bar01">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
+ mk_row(<<"_design/bar02">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
+ mk_row(<<"_design/bar03">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
+ mk_row(<<"_design/bar04">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
+ mk_row(<<"_design/bar05">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
+ mk_row(<<"_design/bar06">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
+ mk_row(<<"_design/bar07">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
+ mk_row(<<"_design/bar08">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
+ mk_row(<<"_design/bar09">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
+ mk_row(<<"_design/bar10">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>)
+ ]},
?_assertEqual(Expect, Result).
should_query_with_range(Db) ->
@@ -72,26 +71,29 @@ should_query_with_range(Db) ->
{start_key, <<"_design/bar03">>},
{end_key, <<"_design/bar05">>}
]),
- Expect = {ok, [
- {meta, [{total, 10}, {offset, 12}]},
- mk_row(<<"_design/bar03">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
- mk_row(<<"_design/bar04">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
- mk_row(<<"_design/bar05">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>)
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 10}, {offset, 12}]},
+ mk_row(<<"_design/bar03">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
+ mk_row(<<"_design/bar04">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
+ mk_row(<<"_design/bar05">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>)
+ ]},
?_assertEqual(Expect, Result).
should_query_with_range_rev(Db) ->
Result = run_query(Db, [
{direction, rev},
- {start_key, <<"_design/bar05">>}, {end_key, <<"_design/bar03">>},
+ {start_key, <<"_design/bar05">>},
+ {end_key, <<"_design/bar03">>},
{inclusive_end, true}
]),
- Expect = {ok, [
- {meta, [{total, 10}, {offset, 5}]},
- mk_row(<<"_design/bar05">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
- mk_row(<<"_design/bar04">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
- mk_row(<<"_design/bar03">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>)
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 10}, {offset, 5}]},
+ mk_row(<<"_design/bar05">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
+ mk_row(<<"_design/bar04">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
+ mk_row(<<"_design/bar03">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>)
+ ]},
?_assertEqual(Expect, Result).
should_query_with_limit_and_skip(Db) ->
@@ -100,12 +102,13 @@ should_query_with_limit_and_skip(Db) ->
{limit, 3},
{skip, 3}
]),
- Expect = {ok, [
- {meta, [{total, 10}, {offset, 14}]},
- mk_row(<<"_design/bar05">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
- mk_row(<<"_design/bar06">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
- mk_row(<<"_design/bar07">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>)
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 10}, {offset, 14}]},
+ mk_row(<<"_design/bar05">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
+ mk_row(<<"_design/bar06">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>),
+ mk_row(<<"_design/bar07">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>)
+ ]},
?_assertEqual(Expect, Result).
should_query_with_include_docs(Db) ->
@@ -114,20 +117,25 @@ should_query_with_include_docs(Db) ->
{end_key, <<"_design/bar08">>},
{include_docs, true}
]),
- Doc = {[
- {<<"_id">>,<<"_design/bar08">>},
- {<<"_rev">>,<<"1-0b24e44a44af45e51e562fd124ce3007">>},
- {<<"views">>,{[]}}
- ]},
+ Doc =
+ {[
+ {<<"_id">>, <<"_design/bar08">>},
+ {<<"_rev">>, <<"1-0b24e44a44af45e51e562fd124ce3007">>},
+ {<<"views">>, {[]}}
+ ]},
Val = {[{rev, <<"1-0b24e44a44af45e51e562fd124ce3007">>}]},
- Expect = {ok, [
- {meta, [{total, 10}, {offset, 17}]},
- {row, [{id, <<"_design/bar08">>}, {key, <<"_design/bar08">>},
- {value, Val}, {doc, Doc}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 10}, {offset, 17}]},
+ {row, [
+ {id, <<"_design/bar08">>},
+ {key, <<"_design/bar08">>},
+ {value, Val},
+ {doc, Doc}
+ ]}
+ ]},
?_assertEqual(Expect, Result).
-
mk_row(Id, Rev) ->
{row, [{id, Id}, {key, Id}, {value, {[{rev, Rev}]}}]}.
diff --git a/src/couch_mrview/test/eunit/couch_mrview_http_tests.erl b/src/couch_mrview/test/eunit/couch_mrview_http_tests.erl
index bd11c7ad8..bfa4965a4 100644
--- a/src/couch_mrview/test/eunit/couch_mrview_http_tests.erl
+++ b/src/couch_mrview/test/eunit/couch_mrview_http_tests.erl
@@ -15,14 +15,23 @@
-include_lib("couch/include/couch_eunit.hrl").
-include_lib("couch_mrview/include/couch_mrview.hrl").
-
mrview_http_test_() ->
[
- ?_assertEqual(#mrargs{group_level=undefined, group=true},
- couch_mrview_http:parse_params([{"group", "true"}],
- undefined, #mrargs{})),
+ ?_assertEqual(
+ #mrargs{group_level = undefined, group = true},
+ couch_mrview_http:parse_params(
+ [{"group", "true"}],
+ undefined,
+ #mrargs{}
+ )
+ ),
- ?_assertEqual(#mrargs{group_level=1, group=undefined},
- couch_mrview_http:parse_params([{"group_level", "1"}],
- undefined, #mrargs{}))
+ ?_assertEqual(
+ #mrargs{group_level = 1, group = undefined},
+ couch_mrview_http:parse_params(
+ [{"group_level", "1"}],
+ undefined,
+ #mrargs{}
+ )
+ )
].
diff --git a/src/couch_mrview/test/eunit/couch_mrview_index_info_tests.erl b/src/couch_mrview/test/eunit/couch_mrview_index_info_tests.erl
index c4c765feb..bf64eaea3 100644
--- a/src/couch_mrview/test/eunit/couch_mrview_index_info_tests.erl
+++ b/src/couch_mrview/test/eunit/couch_mrview_index_info_tests.erl
@@ -17,20 +17,17 @@
-define(TIMEOUT, 1000).
-
setup() ->
{ok, Db} = couch_mrview_test_util:init_db(?tempdb(), map),
couch_mrview:query_view(Db, <<"_design/bar">>, <<"baz">>),
{ok, Info} = couch_mrview:get_info(Db, <<"_design/bar">>),
{Db, Info}.
-
teardown({Db, _}) ->
couch_db:close(Db),
couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
-
view_info_test_() ->
{
"Views index tests",
@@ -57,50 +54,41 @@ view_info_test_() ->
}
}.
-
sig_is_binary({_, Info}) ->
?_assert(is_binary(prop(signature, Info))).
-
language_is_js({_, Info}) ->
?_assertEqual(<<"javascript">>, prop(language, Info)).
-
file_size_is_non_neg_int({_, Info}) ->
?_assert(check_non_neg_int([sizes, file], Info)).
-
active_size_is_non_neg_int({_, Info}) ->
?_assert(check_non_neg_int([sizes, active], Info)).
-
external_size_is_non_neg_int({_, Info}) ->
?_assert(check_non_neg_int([sizes, external], Info)).
-
active_size_less_than_file_size({_, Info}) ->
?_assert(prop([sizes, active], Info) < prop([sizes, file], Info)).
-
update_seq_is_non_neg_int({_, Info}) ->
?_assert(check_non_neg_int(update_seq, Info)).
-
purge_seq_is_non_neg_int({_, Info}) ->
?_assert(check_non_neg_int(purge_seq, Info)).
-
update_opts_is_bin_list({_, Info}) ->
Opts = prop(update_options, Info),
- ?_assert(is_list(Opts) andalso
- (Opts == [] orelse lists:all([is_binary(B) || B <- Opts]))).
-
+ ?_assert(
+ is_list(Opts) andalso
+ (Opts == [] orelse lists:all([is_binary(B) || B <- Opts]))
+ ).
check_non_neg_int(Key, Info) ->
Size = prop(Key, Info),
is_integer(Size) andalso Size >= 0.
-
prop(Key, {Props}) when is_list(Props) ->
prop(Key, Props);
prop([Key], Info) ->
diff --git a/src/couch_mrview/test/eunit/couch_mrview_local_docs_tests.erl b/src/couch_mrview/test/eunit/couch_mrview_local_docs_tests.erl
index b0d25469a..7c812eeb0 100644
--- a/src/couch_mrview/test/eunit/couch_mrview_local_docs_tests.erl
+++ b/src/couch_mrview/test/eunit/couch_mrview_local_docs_tests.erl
@@ -17,8 +17,6 @@
-define(TIMEOUT, 1000).
-
-
setup() ->
{ok, Db} = couch_mrview_test_util:init_db(?tempdb(), local),
Db.
@@ -28,16 +26,17 @@ teardown(Db) ->
couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
-
all_docs_test_() ->
{
"_local_docs view tests",
{
setup,
- fun test_util:start_couch/0, fun test_util:stop_couch/1,
+ fun test_util:start_couch/0,
+ fun test_util:stop_couch/1,
{
foreach,
- fun setup/0, fun teardown/1,
+ fun setup/0,
+ fun teardown/1,
[
fun should_query/1,
fun should_query_with_range/1,
@@ -50,22 +49,22 @@ all_docs_test_() ->
}
}.
-
should_query(Db) ->
Result = run_query(Db, []),
- Expect = {ok, [
- {meta, [{total, null}, {offset, null}]},
- mk_row(1),
- mk_row(10),
- mk_row(2),
- mk_row(3),
- mk_row(4),
- mk_row(5),
- mk_row(6),
- mk_row(7),
- mk_row(8),
- mk_row(9)
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, null}, {offset, null}]},
+ mk_row(1),
+ mk_row(10),
+ mk_row(2),
+ mk_row(3),
+ mk_row(4),
+ mk_row(5),
+ mk_row(6),
+ mk_row(7),
+ mk_row(8),
+ mk_row(9)
+ ]},
?_assertEqual(Expect, Result).
should_query_with_range(Db) ->
@@ -73,26 +72,29 @@ should_query_with_range(Db) ->
{start_key, <<"_local/3">>},
{end_key, <<"_local/5">>}
]),
- Expect = {ok, [
- {meta, [{total, null}, {offset, null}]},
- mk_row(3),
- mk_row(4),
- mk_row(5)
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, null}, {offset, null}]},
+ mk_row(3),
+ mk_row(4),
+ mk_row(5)
+ ]},
?_assertEqual(Expect, Result).
should_query_with_range_rev(Db) ->
Result = run_query(Db, [
{direction, rev},
- {start_key, <<"_local/5">>}, {end_key, <<"_local/3">>},
+ {start_key, <<"_local/5">>},
+ {end_key, <<"_local/3">>},
{inclusive_end, true}
]),
- Expect = {ok, [
- {meta, [{total, null}, {offset, null}]},
- mk_row(5),
- mk_row(4),
- mk_row(3)
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, null}, {offset, null}]},
+ mk_row(5),
+ mk_row(4),
+ mk_row(3)
+ ]},
?_assertEqual(Expect, Result).
should_query_with_limit_and_skip(Db) ->
@@ -101,12 +103,13 @@ should_query_with_limit_and_skip(Db) ->
{limit, 3},
{skip, 3}
]),
- Expect = {ok, [
- {meta, [{total, null}, {offset, null}]},
- mk_row(5),
- mk_row(6),
- mk_row(7)
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, null}, {offset, null}]},
+ mk_row(5),
+ mk_row(6),
+ mk_row(7)
+ ]},
?_assertEqual(Expect, Result).
should_query_with_include_docs(Db) ->
@@ -116,15 +119,21 @@ should_query_with_include_docs(Db) ->
{include_docs, true}
]),
{row, Doc0} = mk_row(8),
- Doc = Doc0 ++ [{doc, {[
- {<<"_id">>, <<"_local/8">>},
- {<<"_rev">>, <<"0-1">>},
- {<<"val">>, 8}
- ]}}],
- Expect = {ok, [
- {meta, [{total, null}, {offset, null}]},
- {row, Doc}
- ]},
+ Doc =
+ Doc0 ++
+ [
+ {doc,
+ {[
+ {<<"_id">>, <<"_local/8">>},
+ {<<"_rev">>, <<"0-1">>},
+ {<<"val">>, 8}
+ ]}}
+ ],
+ Expect =
+ {ok, [
+ {meta, [{total, null}, {offset, null}]},
+ {row, Doc}
+ ]},
?_assertEqual(Expect, Result).
should_query_with_update_seq(Db) ->
@@ -133,10 +142,11 @@ should_query_with_update_seq(Db) ->
{limit, 1},
{update_seq, true}
]),
- Expect = {ok, [
- {meta, [{total, null}, {offset, null}, {update_seq, null}]},
- mk_row(2)
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, null}, {offset, null}, {update_seq, null}]},
+ mk_row(2)
+ ]},
?_assertEqual(Expect, Result).
mk_row(IntId) ->
diff --git a/src/couch_mrview/test/eunit/couch_mrview_map_views_tests.erl b/src/couch_mrview/test/eunit/couch_mrview_map_views_tests.erl
index 805dc6c74..0f8357a98 100644
--- a/src/couch_mrview/test/eunit/couch_mrview_map_views_tests.erl
+++ b/src/couch_mrview/test/eunit/couch_mrview_map_views_tests.erl
@@ -17,7 +17,6 @@
-define(TIMEOUT, 1000).
-
setup() ->
{ok, Db} = couch_mrview_test_util:init_db(?tempdb(), map),
Db.
@@ -27,16 +26,17 @@ teardown(Db) ->
couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
-
map_views_test_() ->
{
"Map views",
{
setup,
- fun test_util:start_couch/0, fun test_util:stop_couch/1,
+ fun test_util:start_couch/0,
+ fun test_util:stop_couch/1,
{
foreach,
- fun setup/0, fun teardown/1,
+ fun setup/0,
+ fun teardown/1,
[
fun should_map/1,
fun should_map_with_range/1,
@@ -49,36 +49,38 @@ map_views_test_() ->
}
}.
-
should_map(Db) ->
Result = run_query(Db, []),
- Expect = {ok, [
- {meta, [{total, 10}, {offset, 0}]},
- {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
- {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]},
- {row, [{id, <<"6">>}, {key, 6}, {value, 6}]},
- {row, [{id, <<"7">>}, {key, 7}, {value, 7}]},
- {row, [{id, <<"8">>}, {key, 8}, {value, 8}]},
- {row, [{id, <<"9">>}, {key, 9}, {value, 9}]},
- {row, [{id, <<"10">>}, {key, 10}, {value, 10}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 10}, {offset, 0}]},
+ {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
+ {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]},
+ {row, [{id, <<"6">>}, {key, 6}, {value, 6}]},
+ {row, [{id, <<"7">>}, {key, 7}, {value, 7}]},
+ {row, [{id, <<"8">>}, {key, 8}, {value, 8}]},
+ {row, [{id, <<"9">>}, {key, 9}, {value, 9}]},
+ {row, [{id, <<"10">>}, {key, 10}, {value, 10}]}
+ ]},
?_assertEqual(Expect, Result).
should_map_with_range(Db) ->
Result = run_query(Db, [
{direction, rev},
- {start_key, 5}, {end_key, 3},
+ {start_key, 5},
+ {end_key, 3},
{inclusive_end, true}
]),
- Expect = {ok, [
- {meta, [{total, 10}, {offset, 5}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 10}, {offset, 5}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]}
+ ]},
?_assertEqual(Expect, Result).
should_map_with_limit_and_skip(Db) ->
@@ -87,12 +89,13 @@ should_map_with_limit_and_skip(Db) ->
{limit, 3},
{skip, 3}
]),
- Expect = {ok, [
- {meta, [{total, 10}, {offset, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]},
- {row, [{id, <<"6">>}, {key, 6}, {value, 6}]},
- {row, [{id, <<"7">>}, {key, 7}, {value, 7}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 10}, {offset, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]},
+ {row, [{id, <<"6">>}, {key, 6}, {value, 6}]},
+ {row, [{id, <<"7">>}, {key, 7}, {value, 7}]}
+ ]},
?_assertEqual(Expect, Result).
should_map_with_include_docs(Db) ->
@@ -101,35 +104,41 @@ should_map_with_include_docs(Db) ->
{end_key, 8},
{include_docs, true}
]),
- Doc = {[
- {<<"_id">>,<<"8">>},
- {<<"_rev">>, <<"1-55b9a29311341e07ec0a7ca13bc1b59f">>},
- {<<"val">>,8}
- ]},
- Expect = {ok, [
- {meta, [{total, 10}, {offset, 7}]},
- {row, [{id, <<"8">>}, {key, 8}, {value, 8}, {doc, Doc}]}
- ]},
+ Doc =
+ {[
+ {<<"_id">>, <<"8">>},
+ {<<"_rev">>, <<"1-55b9a29311341e07ec0a7ca13bc1b59f">>},
+ {<<"val">>, 8}
+ ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 10}, {offset, 7}]},
+ {row, [{id, <<"8">>}, {key, 8}, {value, 8}, {doc, Doc}]}
+ ]},
?_assertEqual(Expect, Result).
should_map_empty_views(Db) ->
Result = couch_mrview:query_view(Db, <<"_design/bar">>, <<"bing">>),
- Expect = {ok, [
- {meta, [{total, 0}, {offset, 0}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 0}, {offset, 0}]}
+ ]},
?_assertEqual(Expect, Result).
should_give_ext_size_seq_indexed_test(Db) ->
- DDoc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/seqdoc">>},
- {<<"options">>, {[{<<"seq_indexed">>, true}]}},
- {<<"views">>, {[
- {<<"view1">>, {[
- {<<"map">>, <<"function(doc){emit(doc._id, doc._id);}">>}
+ DDoc = couch_doc:from_json_obj(
+ {[
+ {<<"_id">>, <<"_design/seqdoc">>},
+ {<<"options">>, {[{<<"seq_indexed">>, true}]}},
+ {<<"views">>,
+ {[
+ {<<"view1">>,
+ {[
+ {<<"map">>, <<"function(doc){emit(doc._id, doc._id);}">>}
+ ]}}
]}}
- ]}
- }
- ]}),
+ ]}
+ ),
{ok, _} = couch_db:update_doc(Db, DDoc, []),
{ok, Db1} = couch_db:open_int(couch_db:name(Db), []),
{ok, DDoc1} = couch_db:open_doc(Db1, <<"_design/seqdoc">>, [ejson_body]),
@@ -139,6 +148,5 @@ should_give_ext_size_seq_indexed_test(Db) ->
ok = couch_db:close(Db1),
?_assert(is_number(Size)).
-
run_query(Db, Opts) ->
couch_mrview:query_view(Db, <<"_design/bar">>, <<"baz">>, Opts).
diff --git a/src/couch_mrview/test/eunit/couch_mrview_purge_docs_fabric_tests.erl b/src/couch_mrview/test/eunit/couch_mrview_purge_docs_fabric_tests.erl
index b2969bba0..3207a3da3 100644
--- a/src/couch_mrview/test/eunit/couch_mrview_purge_docs_fabric_tests.erl
+++ b/src/couch_mrview/test/eunit/couch_mrview_purge_docs_fabric_tests.erl
@@ -17,20 +17,18 @@
-include_lib("mem3/include/mem3.hrl").
-include_lib("couch_mrview/include/couch_mrview.hrl").
--define(TIMEOUT, 60). % seconds
-
+% seconds
+-define(TIMEOUT, 60).
setup_all() ->
Ctx = test_util:start_couch([fabric, mem3]),
meck:new(couch_mrview_index, [passthrough]),
Ctx.
-
teardown_all(Ctx) ->
meck:unload(),
test_util:stop_couch(Ctx).
-
setup() ->
DbName = ?tempdb(),
ok = fabric:create_db(DbName, [?ADMIN_CTX, {q, 1}]),
@@ -40,11 +38,9 @@ setup() ->
end),
DbName.
-
teardown(DbName) ->
ok = fabric:delete_db(DbName, [?ADMIN_CTX]).
-
view_purge_fabric_test_() ->
{
"Map views",
@@ -64,152 +60,185 @@ view_purge_fabric_test_() ->
}
}.
-
test_purge_verify_index(DbName) ->
- {timeout, ?TIMEOUT, ?_test(begin
- Docs1 = couch_mrview_test_util:make_docs(normal, 5),
- {ok, _} = fabric:update_docs(DbName, Docs1, [?ADMIN_CTX]),
- {ok, _} = fabric:update_doc(
- DbName,
- couch_mrview_test_util:ddoc(map),
- [?ADMIN_CTX]
- ),
-
- Result1 = fabric:query_view(DbName, <<"bar">>, <<"baz">>, #mrargs{}),
- Expect1 = {ok, [
- {meta, [{total, 5}, {offset, 0}]},
- {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
- {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
- ]},
- ?assertEqual(Expect1, Result1),
-
- {ok, #doc{body = {Props1}}} = get_local_purge_doc(DbName),
- ?assertEqual(0, couch_util:get_value(<<"purge_seq">>, Props1)),
- ShardNames = [Sh || #shard{name = Sh} <- mem3:local_shards(DbName)],
- [ShardDbName | _Rest ] = ShardNames,
- ?assertEqual(true, couch_mrview_index:verify_index_exists(
- ShardDbName, Props1)),
-
- purge_docs(DbName, [<<"1">>]),
-
- Result2 = fabric:query_view(DbName, <<"bar">>, <<"baz">>, #mrargs{}),
- Expect2 = {ok, [
- {meta, [{total, 4}, {offset, 0}]},
- {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
- ]},
- ?assertEqual(Expect2, Result2),
-
- {ok, #doc{body = {Props2}}} = get_local_purge_doc(DbName),
- ?assertEqual(1, couch_util:get_value(<<"purge_seq">>, Props2)),
- ?assertEqual(true, couch_mrview_index:verify_index_exists(
- ShardDbName, Props2))
- end)}.
-
+ {timeout, ?TIMEOUT,
+ ?_test(begin
+ Docs1 = couch_mrview_test_util:make_docs(normal, 5),
+ {ok, _} = fabric:update_docs(DbName, Docs1, [?ADMIN_CTX]),
+ {ok, _} = fabric:update_doc(
+ DbName,
+ couch_mrview_test_util:ddoc(map),
+ [?ADMIN_CTX]
+ ),
+
+ Result1 = fabric:query_view(DbName, <<"bar">>, <<"baz">>, #mrargs{}),
+ Expect1 =
+ {ok, [
+ {meta, [{total, 5}, {offset, 0}]},
+ {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
+ {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
+ ]},
+ ?assertEqual(Expect1, Result1),
+
+ {ok, #doc{body = {Props1}}} = get_local_purge_doc(DbName),
+ ?assertEqual(0, couch_util:get_value(<<"purge_seq">>, Props1)),
+ ShardNames = [Sh || #shard{name = Sh} <- mem3:local_shards(DbName)],
+ [ShardDbName | _Rest] = ShardNames,
+ ?assertEqual(
+ true,
+ couch_mrview_index:verify_index_exists(
+ ShardDbName, Props1
+ )
+ ),
+
+ purge_docs(DbName, [<<"1">>]),
+
+ Result2 = fabric:query_view(DbName, <<"bar">>, <<"baz">>, #mrargs{}),
+ Expect2 =
+ {ok, [
+ {meta, [{total, 4}, {offset, 0}]},
+ {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
+ ]},
+ ?assertEqual(Expect2, Result2),
+
+ {ok, #doc{body = {Props2}}} = get_local_purge_doc(DbName),
+ ?assertEqual(1, couch_util:get_value(<<"purge_seq">>, Props2)),
+ ?assertEqual(
+ true,
+ couch_mrview_index:verify_index_exists(
+ ShardDbName, Props2
+ )
+ )
+ end)}.
test_purge_hook_before_compaction(DbName) ->
- {timeout, ?TIMEOUT, ?_test(begin
- Docs1 = couch_mrview_test_util:make_docs(normal, 5),
- {ok, _} = fabric:update_docs(DbName, Docs1, [?ADMIN_CTX]),
- {ok, _} = fabric:update_doc(
- DbName,
- couch_mrview_test_util:ddoc(map),
- [?ADMIN_CTX]
- ),
-
- Result1 = fabric:query_view(DbName, <<"bar">>, <<"baz">>, #mrargs{}),
- Expect1 = {ok, [
- {meta, [{total, 5}, {offset, 0}]},
- {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
- {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
- ]},
- ?assertEqual(Expect1, Result1),
-
- purge_docs(DbName, [<<"1">>]),
-
- Result2 = fabric:query_view(DbName, <<"bar">>, <<"baz">>, #mrargs{}),
- Expect2 = {ok, [
- {meta, [{total, 4}, {offset, 0}]},
- {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
- ]},
- ?assertEqual(Expect2, Result2),
-
- {ok, #doc{body = {Props1}}} = get_local_purge_doc(DbName),
- ?assertEqual(1, couch_util:get_value(<<"purge_seq">>, Props1)),
-
- [ShardName | _] = local_shards(DbName),
- couch_util:with_db(ShardName, fun(Db) ->
- {ok, _} = couch_db:start_compact(Db)
- end),
- wait_compaction(ShardName, ?LINE),
-
- ?assertEqual(ok, meck:wait(1, couch_mrview_index,
- ensure_local_purge_docs, '_', 5000)
- ),
-
- % Make sure compaction didn't change the update seq
- {ok, #doc{body = {Props1}}} = get_local_purge_doc(DbName),
- ?assertEqual(1, couch_util:get_value(<<"purge_seq">>, Props1)),
-
- purge_docs(DbName, [<<"2">>]),
-
- couch_util:with_db(ShardName, fun(Db) ->
- {ok, _} = couch_db:start_compact(Db)
- end),
- wait_compaction(ShardName, ?LINE),
-
- ?assertEqual(ok, meck:wait(2, couch_mrview_index,
- ensure_local_purge_docs, '_', 5000)
- ),
-
- % Make sure compaction after a purge didn't overwrite
- % the local purge doc for the index
- {ok, #doc{body = {Props2}}} = get_local_purge_doc(DbName),
- ?assertEqual(1, couch_util:get_value(<<"purge_seq">>, Props2)),
-
- % Force another update to ensure that we update
- % the local doc appropriate after compaction
- Result3 = fabric:query_view(DbName, <<"bar">>, <<"baz">>, #mrargs{}),
- Expect3 = {ok, [
- {meta, [{total, 3}, {offset, 0}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
- ]},
- ?assertEqual(Expect3, Result3),
-
- {ok, #doc{body = {Props3}}} = get_local_purge_doc(DbName),
- ?assertEqual(2, couch_util:get_value(<<"purge_seq">>, Props3)),
-
- % Check that if the local doc doesn't exist that one
- % is created for the index on compaction
- delete_local_purge_doc(DbName),
- ?assertMatch({not_found, _}, get_local_purge_doc(DbName)),
-
- couch_util:with_db(ShardName, fun(Db) ->
- {ok, _} = couch_db:start_compact(Db)
- end),
- wait_compaction(ShardName, ?LINE),
-
- ?assertEqual(ok, meck:wait(3, couch_mrview_index,
- ensure_local_purge_docs, '_', 5000)
- ),
-
- {ok, #doc{body = {Props4}}} = get_local_purge_doc(DbName),
- ?assertEqual(2, couch_util:get_value(<<"purge_seq">>, Props4))
- end)}.
-
+ {timeout, ?TIMEOUT,
+ ?_test(begin
+ Docs1 = couch_mrview_test_util:make_docs(normal, 5),
+ {ok, _} = fabric:update_docs(DbName, Docs1, [?ADMIN_CTX]),
+ {ok, _} = fabric:update_doc(
+ DbName,
+ couch_mrview_test_util:ddoc(map),
+ [?ADMIN_CTX]
+ ),
+
+ Result1 = fabric:query_view(DbName, <<"bar">>, <<"baz">>, #mrargs{}),
+ Expect1 =
+ {ok, [
+ {meta, [{total, 5}, {offset, 0}]},
+ {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
+ {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
+ ]},
+ ?assertEqual(Expect1, Result1),
+
+ purge_docs(DbName, [<<"1">>]),
+
+ Result2 = fabric:query_view(DbName, <<"bar">>, <<"baz">>, #mrargs{}),
+ Expect2 =
+ {ok, [
+ {meta, [{total, 4}, {offset, 0}]},
+ {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
+ ]},
+ ?assertEqual(Expect2, Result2),
+
+ {ok, #doc{body = {Props1}}} = get_local_purge_doc(DbName),
+ ?assertEqual(1, couch_util:get_value(<<"purge_seq">>, Props1)),
+
+ [ShardName | _] = local_shards(DbName),
+ couch_util:with_db(ShardName, fun(Db) ->
+ {ok, _} = couch_db:start_compact(Db)
+ end),
+ wait_compaction(ShardName, ?LINE),
+
+ ?assertEqual(
+ ok,
+ meck:wait(
+ 1,
+ couch_mrview_index,
+ ensure_local_purge_docs,
+ '_',
+ 5000
+ )
+ ),
+
+ % Make sure compaction didn't change the update seq
+ {ok, #doc{body = {Props1}}} = get_local_purge_doc(DbName),
+ ?assertEqual(1, couch_util:get_value(<<"purge_seq">>, Props1)),
+
+ purge_docs(DbName, [<<"2">>]),
+
+ couch_util:with_db(ShardName, fun(Db) ->
+ {ok, _} = couch_db:start_compact(Db)
+ end),
+ wait_compaction(ShardName, ?LINE),
+
+ ?assertEqual(
+ ok,
+ meck:wait(
+ 2,
+ couch_mrview_index,
+ ensure_local_purge_docs,
+ '_',
+ 5000
+ )
+ ),
+
+ % Make sure compaction after a purge didn't overwrite
+ % the local purge doc for the index
+ {ok, #doc{body = {Props2}}} = get_local_purge_doc(DbName),
+ ?assertEqual(1, couch_util:get_value(<<"purge_seq">>, Props2)),
+
+ % Force another update to ensure that we update
+ % the local doc appropriate after compaction
+ Result3 = fabric:query_view(DbName, <<"bar">>, <<"baz">>, #mrargs{}),
+ Expect3 =
+ {ok, [
+ {meta, [{total, 3}, {offset, 0}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
+ ]},
+ ?assertEqual(Expect3, Result3),
+
+ {ok, #doc{body = {Props3}}} = get_local_purge_doc(DbName),
+ ?assertEqual(2, couch_util:get_value(<<"purge_seq">>, Props3)),
+
+ % Check that if the local doc doesn't exist that one
+ % is created for the index on compaction
+ delete_local_purge_doc(DbName),
+ ?assertMatch({not_found, _}, get_local_purge_doc(DbName)),
+
+ couch_util:with_db(ShardName, fun(Db) ->
+ {ok, _} = couch_db:start_compact(Db)
+ end),
+ wait_compaction(ShardName, ?LINE),
+
+ ?assertEqual(
+ ok,
+ meck:wait(
+ 3,
+ couch_mrview_index,
+ ensure_local_purge_docs,
+ '_',
+ 5000
+ )
+ ),
+
+ {ok, #doc{body = {Props4}}} = get_local_purge_doc(DbName),
+ ?assertEqual(2, couch_util:get_value(<<"purge_seq">>, Props4))
+ end)}.
get_local_purge_doc(DbName) ->
{ok, DDoc} = fabric:open_doc(DbName, <<"_design/bar">>, []),
@@ -222,7 +251,6 @@ get_local_purge_doc(DbName) ->
couch_db:open_doc(Db, DocId, [])
end).
-
delete_local_purge_doc(DbName) ->
{ok, DDoc} = fabric:open_doc(DbName, <<"_design/bar">>, []),
{ok, IdxState} = couch_mrview_util:ddoc_to_mrst(DbName, DDoc),
@@ -235,21 +263,21 @@ delete_local_purge_doc(DbName) ->
{ok, _} = couch_db:update_doc(Db, NewDoc, [])
end).
-
get_rev(#full_doc_info{} = FDI) ->
#doc_info{
revs = [#rev_info{} = PrevRev | _]
} = couch_doc:to_doc_info(FDI),
PrevRev#rev_info.rev.
-
purge_docs(DbName, DocIds) ->
- lists:foreach(fun(DocId) ->
- FDI = fabric:get_full_doc_info(DbName, DocId, []),
- Rev = get_rev(FDI),
- {ok, [{ok, _}]} = fabric:purge_docs(DbName, [{DocId, [Rev]}], [])
- end, DocIds).
-
+ lists:foreach(
+ fun(DocId) ->
+ FDI = fabric:get_full_doc_info(DbName, DocId, []),
+ Rev = get_rev(FDI),
+ {ok, [{ok, _}]} = fabric:purge_docs(DbName, [{DocId, [Rev]}], [])
+ end,
+ DocIds
+ ).
wait_compaction(DbName, Line) ->
WaitFun = fun() ->
@@ -260,23 +288,23 @@ wait_compaction(DbName, Line) ->
end,
case test_util:wait(WaitFun, 10000) of
timeout ->
- erlang:error({assertion_failed, [
+ erlang:error(
+ {assertion_failed, [
{module, ?MODULE},
{line, Line},
{reason, "Timeout waiting for database compaction"}
- ]});
+ ]}
+ );
_ ->
ok
end.
-
is_compaction_running(DbName) ->
{ok, DbInfo} = couch_util:with_db(DbName, fun(Db) ->
couch_db:get_db_info(Db)
end),
couch_util:get_value(compact_running, DbInfo).
-
local_shards(DbName) ->
try
[ShardName || #shard{name = ShardName} <- mem3:local_shards(DbName)]
diff --git a/src/couch_mrview/test/eunit/couch_mrview_purge_docs_tests.erl b/src/couch_mrview/test/eunit/couch_mrview_purge_docs_tests.erl
index 62e1410cb..63c5de458 100644
--- a/src/couch_mrview/test/eunit/couch_mrview_purge_docs_tests.erl
+++ b/src/couch_mrview/test/eunit/couch_mrview_purge_docs_tests.erl
@@ -18,7 +18,6 @@
-define(TIMEOUT, 1000).
-
setup() ->
meck:new(couch_index_updater, [passthrough]),
{ok, Db} = couch_mrview_test_util:init_db(?tempdb(), map, 5),
@@ -57,51 +56,52 @@ view_purge_test_() ->
}
}.
-
test_purge_single(Db) ->
?_test(begin
Result = run_query(Db, []),
- Expect = {ok, [
- {meta, [{total, 5}, {offset, 0}]},
- {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
- {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 5}, {offset, 0}]},
+ {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
+ {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
+ ]},
?assertEqual(Expect, Result),
FDI = couch_db:get_full_doc_info(Db, <<"1">>),
Rev = get_rev(FDI),
{ok, [{ok, _PRevs}]} = couch_db:purge_docs(
- Db,
- [{<<"UUID1">>, <<"1">>, [Rev]}]
- ),
+ Db,
+ [{<<"UUID1">>, <<"1">>, [Rev]}]
+ ),
{ok, Db2} = couch_db:reopen(Db),
Result2 = run_query(Db2, []),
- Expect2 = {ok, [
- {meta, [{total, 4}, {offset, 0}]},
- {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
- ]},
+ Expect2 =
+ {ok, [
+ {meta, [{total, 4}, {offset, 0}]},
+ {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
+ ]},
?assertEqual(Expect2, Result2)
end).
-
test_purge_single_for_docid_with_list(Db) ->
?_test(begin
Result = run_query(Db, []),
- Expect = {ok, [
- {meta, [{total, 5}, {offset, 0}]},
- {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
- {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 5}, {offset, 0}]},
+ {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
+ {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
+ ]},
?assertEqual(Expect, Result),
FDI = couch_db:get_full_doc_info(Db, <<"1">>),
@@ -113,35 +113,39 @@ test_purge_single_for_docid_with_list(Db) ->
{ok, Db2} = couch_db:reopen(Db),
Result2 = run_query(Db2, []),
- Expect2 = {ok, [
- {meta, [{total, 4}, {offset, 0}]},
- {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
- ]},
+ Expect2 =
+ {ok, [
+ {meta, [{total, 4}, {offset, 0}]},
+ {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
+ ]},
?assertEqual(Expect2, Result2)
end).
test_purge_partial(Db) ->
?_test(begin
Result = run_query(Db, []),
- Expect = {ok, [
- {meta, [{total, 5}, {offset, 0}]},
- {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
- {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 5}, {offset, 0}]},
+ {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
+ {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
+ ]},
?assertEqual(Expect, Result),
- FDI1 = couch_db:get_full_doc_info(Db, <<"1">>), Rev1 = get_rev(FDI1),
- Update = {[
- {'_id', <<"1">>},
- {'_rev', couch_doc:rev_to_str({1, [couch_hash:md5_hash(<<"1.2">>)]})},
- {'val', 1.2}
- ]},
+ FDI1 = couch_db:get_full_doc_info(Db, <<"1">>),
+ Rev1 = get_rev(FDI1),
+ Update =
+ {[
+ {'_id', <<"1">>},
+ {'_rev', couch_doc:rev_to_str({1, [couch_hash:md5_hash(<<"1.2">>)]})},
+ {'val', 1.2}
+ ]},
{ok, [_Rev2]} = save_docs(Db, [Update], [replicated_changes]),
PurgeInfos = [{<<"UUID1">>, <<"1">>, [Rev1]}],
@@ -150,34 +154,38 @@ test_purge_partial(Db) ->
{ok, Db2} = couch_db:reopen(Db),
Result2 = run_query(Db2, []),
- Expect2 = {ok, [
- {meta, [{total, 5}, {offset, 0}]},
- {row, [{id, <<"1">>}, {key, 1.2}, {value, 1.2}]},
- {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
- ]},
+ Expect2 =
+ {ok, [
+ {meta, [{total, 5}, {offset, 0}]},
+ {row, [{id, <<"1">>}, {key, 1.2}, {value, 1.2}]},
+ {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
+ ]},
?assertEqual(Expect2, Result2)
end).
-
test_purge_complete(Db) ->
?_test(begin
Result = run_query(Db, []),
- Expect = {ok, [
- {meta, [{total, 5}, {offset, 0}]},
- {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
- {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 5}, {offset, 0}]},
+ {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
+ {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
+ ]},
?assertEqual(Expect, Result),
- FDI1 = couch_db:get_full_doc_info(Db, <<"1">>), Rev1 = get_rev(FDI1),
- FDI2 = couch_db:get_full_doc_info(Db, <<"2">>), Rev2 = get_rev(FDI2),
- FDI5 = couch_db:get_full_doc_info(Db, <<"5">>), Rev5 = get_rev(FDI5),
+ FDI1 = couch_db:get_full_doc_info(Db, <<"1">>),
+ Rev1 = get_rev(FDI1),
+ FDI2 = couch_db:get_full_doc_info(Db, <<"2">>),
+ Rev2 = get_rev(FDI2),
+ FDI5 = couch_db:get_full_doc_info(Db, <<"5">>),
+ Rev5 = get_rev(FDI5),
PurgeInfos = [
{<<"UUID1">>, <<"1">>, [Rev1]},
@@ -188,31 +196,35 @@ test_purge_complete(Db) ->
{ok, Db2} = couch_db:reopen(Db),
Result2 = run_query(Db2, []),
- Expect2 = {ok, [
- {meta, [{total, 2}, {offset, 0}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]}
- ]},
+ Expect2 =
+ {ok, [
+ {meta, [{total, 2}, {offset, 0}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]}
+ ]},
?assertEqual(Expect2, Result2)
end).
-
test_purge_complete_for_docid_with_list(Db) ->
?_test(begin
Result = run_query(Db, []),
- Expect = {ok, [
- {meta, [{total, 5}, {offset, 0}]},
- {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
- {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 5}, {offset, 0}]},
+ {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
+ {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
+ ]},
?assertEqual(Expect, Result),
- FDI1 = couch_db:get_full_doc_info(Db, <<"1">>), Rev1 = get_rev(FDI1),
- FDI2 = couch_db:get_full_doc_info(Db, <<"2">>), Rev2 = get_rev(FDI2),
- FDI5 = couch_db:get_full_doc_info(Db, <<"5">>), Rev5 = get_rev(FDI5),
+ FDI1 = couch_db:get_full_doc_info(Db, <<"1">>),
+ Rev1 = get_rev(FDI1),
+ FDI2 = couch_db:get_full_doc_info(Db, <<"2">>),
+ Rev2 = get_rev(FDI2),
+ FDI5 = couch_db:get_full_doc_info(Db, <<"5">>),
+ Rev5 = get_rev(FDI5),
PurgeInfos = [
{<<"UUID1">>, "1", [Rev1]},
@@ -223,26 +235,27 @@ test_purge_complete_for_docid_with_list(Db) ->
{ok, Db2} = couch_db:reopen(Db),
Result2 = run_query(Db2, []),
- Expect2 = {ok, [
- {meta, [{total, 2}, {offset, 0}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]}
- ]},
+ Expect2 =
+ {ok, [
+ {meta, [{total, 2}, {offset, 0}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]}
+ ]},
?assertEqual(Expect2, Result2)
end).
-
test_purge_nochange(Db) ->
?_test(begin
Result = run_query(Db, []),
- Expect = {ok, [
- {meta, [{total, 5}, {offset, 0}]},
- {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
- {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 5}, {offset, 0}]},
+ {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
+ {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
+ ]},
?assertEqual(Expect, Result),
FDI1 = couch_db:get_full_doc_info(Db, <<"1">>),
@@ -255,40 +268,44 @@ test_purge_nochange(Db) ->
{ok, Db2} = couch_db:reopen(Db),
Result2 = run_query(Db2, []),
- Expect2 = {ok, [
- {meta, [{total, 5}, {offset, 0}]},
- {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
- {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
- ]},
+ Expect2 =
+ {ok, [
+ {meta, [{total, 5}, {offset, 0}]},
+ {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
+ {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
+ ]},
?assertEqual(Expect2, Result2)
end).
-
test_purge_index_reset(Db) ->
?_test(begin
ok = couch_db:set_purge_infos_limit(Db, 2),
{ok, Db1} = couch_db:reopen(Db),
Result = run_query(Db1, []),
- Expect = {ok, [
- {meta, [{total, 5}, {offset, 0}]},
- {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
- {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
- {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
- {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
- {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, [{total, 5}, {offset, 0}]},
+ {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
+ {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]},
+ {row, [{id, <<"4">>}, {key, 4}, {value, 4}]},
+ {row, [{id, <<"5">>}, {key, 5}, {value, 5}]}
+ ]},
?assertEqual(Expect, Result),
- PurgeInfos = lists:map(fun(I) ->
- DocId = list_to_binary(integer_to_list(I)),
- FDI = couch_db:get_full_doc_info(Db, DocId),
- Rev = get_rev(FDI),
- {couch_uuids:random(), DocId, [Rev]}
- end, lists:seq(1, 5)),
+ PurgeInfos = lists:map(
+ fun(I) ->
+ DocId = list_to_binary(integer_to_list(I)),
+ FDI = couch_db:get_full_doc_info(Db, DocId),
+ Rev = get_rev(FDI),
+ {couch_uuids:random(), DocId, [Rev]}
+ end,
+ lists:seq(1, 5)
+ ),
{ok, _} = couch_db:purge_docs(Db1, PurgeInfos),
{ok, Db2} = couch_db:reopen(Db1),
@@ -309,22 +326,22 @@ test_purge_index_reset(Db) ->
{ok, Db3} = couch_db:reopen(Db2),
Result2 = run_query(Db3, []),
- Expect2 = {ok, [
- {meta, [{total, 0}, {offset, 0}]}
- ]},
+ Expect2 =
+ {ok, [
+ {meta, [{total, 0}, {offset, 0}]}
+ ]},
?assertEqual(Expect2, Result2),
% Assert that we had a reset
meck:wait(
- 1,
- couch_index_updater,
- handle_info,
- [{'EXIT', '_', {reset, '_'}}, '_'],
- 5000
- )
+ 1,
+ couch_index_updater,
+ handle_info,
+ [{'EXIT', '_', {reset, '_'}}, '_'],
+ 5000
+ )
end).
-
test_purge_compact_size_check(Db) ->
?_test(begin
DbName = couch_db:name(Db),
@@ -334,24 +351,28 @@ test_purge_compact_size_check(Db) ->
DiskSizeBefore = db_disk_size(DbName),
PurgedDocsNum = 150,
- IdsRevs = lists:foldl(fun(Id, CIdRevs) ->
- Id1 = docid(Id),
- FDI1 = couch_db:get_full_doc_info(Db1, Id1),
- Rev1 = get_rev(FDI1),
- UUID1 = uuid(Id),
- [{UUID1, Id1, [Rev1]} | CIdRevs]
- end, [], lists:seq(1, PurgedDocsNum)),
+ IdsRevs = lists:foldl(
+ fun(Id, CIdRevs) ->
+ Id1 = docid(Id),
+ FDI1 = couch_db:get_full_doc_info(Db1, Id1),
+ Rev1 = get_rev(FDI1),
+ UUID1 = uuid(Id),
+ [{UUID1, Id1, [Rev1]} | CIdRevs]
+ end,
+ [],
+ lists:seq(1, PurgedDocsNum)
+ ),
{ok, _} = couch_db:purge_docs(Db1, IdsRevs),
{ok, Db2} = couch_db:reopen(Db1),
_Result1 = run_query(Db2, []),
{ok, PurgedIdRevs} = couch_db:fold_purge_infos(
- Db2,
- 0,
- fun fold_fun/2,
- [],
- []
- ),
+ Db2,
+ 0,
+ fun fold_fun/2,
+ [],
+ []
+ ),
?assertEqual(PurgedDocsNum, length(PurgedIdRevs)),
config:set("couchdb", "file_compression", "snappy", false),
@@ -363,7 +384,6 @@ test_purge_compact_size_check(Db) ->
?assert(DiskSizeBefore > DiskSizeAfter)
end).
-
test_purge_compact_for_stale_purge_cp_without_client(Db) ->
?_test(begin
DbName = couch_db:name(Db),
@@ -378,23 +398,27 @@ test_purge_compact_for_stale_purge_cp_without_client(Db) ->
% purge 150 documents
PurgedDocsNum = 150,
- PurgeInfos = lists:foldl(fun(Id, CIdRevs) ->
- Id1 = docid(Id),
- FDI1 = couch_db:get_full_doc_info(Db1, Id1),
- Rev1 = get_rev(FDI1),
- UUID1 = uuid(Id),
- [{UUID1, Id1, [Rev1]} | CIdRevs]
- end, [], lists:seq(1, PurgedDocsNum)),
+ PurgeInfos = lists:foldl(
+ fun(Id, CIdRevs) ->
+ Id1 = docid(Id),
+ FDI1 = couch_db:get_full_doc_info(Db1, Id1),
+ Rev1 = get_rev(FDI1),
+ UUID1 = uuid(Id),
+ [{UUID1, Id1, [Rev1]} | CIdRevs]
+ end,
+ [],
+ lists:seq(1, PurgedDocsNum)
+ ),
{ok, _} = couch_db:purge_docs(Db1, PurgeInfos),
{ok, Db2} = couch_db:reopen(Db1),
{ok, PurgedIdRevs} = couch_db:fold_purge_infos(
- Db2,
- 0,
- fun fold_fun/2,
- [],
- []
- ),
+ Db2,
+ 0,
+ fun fold_fun/2,
+ [],
+ []
+ ),
?assertEqual(PurgedDocsNum, length(PurgedIdRevs)),
% run compaction to trigger pruning of purge tree
@@ -407,16 +431,15 @@ test_purge_compact_for_stale_purge_cp_without_client(Db) ->
{ok, Db4} = couch_db:reopen(Db3),
OldestPSeq = couch_db:get_oldest_purge_seq(Db4),
{ok, PurgedIdRevs2} = couch_db:fold_purge_infos(
- Db4,
- OldestPSeq - 1,
- fun fold_fun/2,
- [],
- []
- ),
+ Db4,
+ OldestPSeq - 1,
+ fun fold_fun/2,
+ [],
+ []
+ ),
?assertEqual(PurgedDocsLimit, length(PurgedIdRevs2))
end).
-
test_purge_compact_for_stale_purge_cp_with_client(Db) ->
?_test(begin
DbName = couch_db:name(Db),
@@ -432,36 +455,44 @@ test_purge_compact_for_stale_purge_cp_with_client(Db) ->
% first purge 30 documents
PurgedDocsNum1 = 30,
- IdsRevs = lists:foldl(fun(Id, CIdRevs) ->
- Id1 = docid(Id),
- FDI1 = couch_db:get_full_doc_info(Db1, Id1),
- Rev1 = get_rev(FDI1),
- UUID1 = uuid(Id),
- [{UUID1, Id1, [Rev1]} | CIdRevs]
- end, [], lists:seq(1, PurgedDocsNum1)),
+ IdsRevs = lists:foldl(
+ fun(Id, CIdRevs) ->
+ Id1 = docid(Id),
+ FDI1 = couch_db:get_full_doc_info(Db1, Id1),
+ Rev1 = get_rev(FDI1),
+ UUID1 = uuid(Id),
+ [{UUID1, Id1, [Rev1]} | CIdRevs]
+ end,
+ [],
+ lists:seq(1, PurgedDocsNum1)
+ ),
{ok, _} = couch_db:purge_docs(Db1, IdsRevs),
{ok, Db2} = couch_db:reopen(Db1),
% run query again to reflect purge request to mrview
_Result1 = run_query(Db2, []),
{ok, PurgedIdRevs} = couch_db:fold_purge_infos(
- Db2,
- 0,
- fun fold_fun/2,
- [],
- []
- ),
+ Db2,
+ 0,
+ fun fold_fun/2,
+ [],
+ []
+ ),
?assertEqual(PurgedDocsNum1, length(PurgedIdRevs)),
% then purge 120 documents
PurgedDocsNum2 = 150,
- IdsRevs2 = lists:foldl(fun(Id, CIdRevs) ->
- Id1 = docid(Id),
- FDI1 = couch_db:get_full_doc_info(Db1, Id1),
- Rev1 = get_rev(FDI1),
- UUID1 = uuid(Id),
- [{UUID1, Id1, [Rev1]} | CIdRevs]
- end, [], lists:seq(PurgedDocsNum1 + 1, PurgedDocsNum2)),
+ IdsRevs2 = lists:foldl(
+ fun(Id, CIdRevs) ->
+ Id1 = docid(Id),
+ FDI1 = couch_db:get_full_doc_info(Db1, Id1),
+ Rev1 = get_rev(FDI1),
+ UUID1 = uuid(Id),
+ [{UUID1, Id1, [Rev1]} | CIdRevs]
+ end,
+ [],
+ lists:seq(PurgedDocsNum1 + 1, PurgedDocsNum2)
+ ),
{ok, _} = couch_db:purge_docs(Db2, IdsRevs2),
% run compaction to trigger pruning of purge tree
@@ -475,16 +506,15 @@ test_purge_compact_for_stale_purge_cp_with_client(Db) ->
{ok, Db4} = couch_db:reopen(Db3),
OldestPSeq = couch_db:get_oldest_purge_seq(Db4),
{ok, PurgedIdRevs2} = couch_db:fold_purge_infos(
- Db4,
- OldestPSeq - 1,
- fun fold_fun/2,
- [],
- []
- ),
+ Db4,
+ OldestPSeq - 1,
+ fun fold_fun/2,
+ [],
+ []
+ ),
?assertEqual(PurgedDocsNum2 - PurgedDocsNum1, length(PurgedIdRevs2))
end).
-
get_local_purge_doc(Db) ->
{ok, DDoc} = couch_db:open_doc(Db, <<"_design/bar">>, []),
{ok, IdxState} = couch_mrview_util:ddoc_to_mrst(couch_db:name(Db), DDoc),
@@ -493,48 +523,50 @@ get_local_purge_doc(Db) ->
DocId = couch_mrview_util:get_local_purge_doc_id(HexSig),
couch_db:open_doc(Db, DocId, []).
-
run_query(Db, Opts) ->
couch_mrview:query_view(Db, <<"_design/bar">>, <<"baz">>, Opts).
-
save_docs(Db, JsonDocs, Options) ->
- Docs = lists:map(fun(JDoc) ->
- couch_doc:from_json_obj(?JSON_DECODE(?JSON_ENCODE(JDoc)))
- end, JsonDocs),
+ Docs = lists:map(
+ fun(JDoc) ->
+ couch_doc:from_json_obj(?JSON_DECODE(?JSON_ENCODE(JDoc)))
+ end,
+ JsonDocs
+ ),
Opts = [full_commit | Options],
case lists:member(replicated_changes, Options) of
true ->
{ok, []} = couch_db:update_docs(
- Db, Docs, Opts, replicated_changes),
- {ok, lists:map(fun(Doc) ->
- {Pos, [RevId | _]} = Doc#doc.revs,
- {Pos, RevId}
- end, Docs)};
+ Db, Docs, Opts, replicated_changes
+ ),
+ {ok,
+ lists:map(
+ fun(Doc) ->
+ {Pos, [RevId | _]} = Doc#doc.revs,
+ {Pos, RevId}
+ end,
+ Docs
+ )};
false ->
{ok, Resp} = couch_db:update_docs(Db, Docs, Opts),
{ok, [Rev || {ok, Rev} <- Resp]}
end.
-
get_rev(#full_doc_info{} = FDI) ->
#doc_info{
revs = [#rev_info{} = PrevRev | _]
} = couch_doc:to_doc_info(FDI),
PrevRev#rev_info.rev.
-
db_disk_size(DbName) ->
{ok, Db} = couch_db:open_int(DbName, []),
{ok, Info} = couch_db:get_db_info(Db),
ok = couch_db:close(Db),
active_size(Info).
-
active_size(Info) ->
couch_util:get_nested_json_value({Info}, [sizes, active]).
-
wait_compaction(DbName, Kind, Line) ->
WaitFun = fun() ->
case is_compaction_running(DbName) of
@@ -544,32 +576,32 @@ wait_compaction(DbName, Kind, Line) ->
end,
case test_util:wait(WaitFun, 10000) of
timeout ->
- erlang:error({assertion_failed,
- [{module, ?MODULE},
+ erlang:error(
+ {assertion_failed, [
+ {module, ?MODULE},
{line, Line},
- {reason, "Timeout waiting for "
- ++ Kind
- ++ " database compaction"}]});
+ {reason,
+ "Timeout waiting for " ++
+ Kind ++
+ " database compaction"}
+ ]}
+ );
_ ->
ok
end.
-
is_compaction_running(DbName) ->
{ok, Db} = couch_db:open_int(DbName, []),
{ok, DbInfo} = couch_db:get_db_info(Db),
couch_db:close(Db),
couch_util:get_value(compact_running, DbInfo).
-
fold_fun({_PSeq, _UUID, Id, Revs}, Acc) ->
{ok, [{Id, Revs} | Acc]}.
-
docid(I) ->
list_to_binary(integer_to_list(I)).
-
uuid(I) ->
Str = io_lib:format("UUID~4..0b", [I]),
iolist_to_binary(Str).
diff --git a/src/couch_mrview/test/eunit/couch_mrview_red_views_tests.erl b/src/couch_mrview/test/eunit/couch_mrview_red_views_tests.erl
index b83686113..b6042b6c7 100644
--- a/src/couch_mrview/test/eunit/couch_mrview_red_views_tests.erl
+++ b/src/couch_mrview/test/eunit/couch_mrview_red_views_tests.erl
@@ -17,7 +17,6 @@
-define(TIMEOUT, 1000).
-
setup() ->
{ok, Db} = couch_mrview_test_util:init_db(?tempdb(), red),
Db.
@@ -27,16 +26,17 @@ teardown(Db) ->
couch_server:delete(couch_db:name(Db), [?ADMIN_CTX]),
ok.
-
reduce_views_test_() ->
{
"Reduce views",
{
setup,
- fun test_util:start_couch/0, fun test_util:stop_couch/1,
+ fun test_util:start_couch/0,
+ fun test_util:stop_couch/1,
{
foreach,
- fun setup/0, fun teardown/1,
+ fun setup/0,
+ fun teardown/1,
[
fun should_reduce_basic/1,
fun should_reduce_key_range/1,
@@ -47,49 +47,51 @@ reduce_views_test_() ->
}
}.
-
should_reduce_basic(Db) ->
Result = run_query(Db, []),
- Expect = {ok, [
- {meta, []},
- {row, [{key, null}, {value, 55}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, []},
+ {row, [{key, null}, {value, 55}]}
+ ]},
?_assertEqual(Expect, Result).
should_reduce_key_range(Db) ->
Result = run_query(Db, [{start_key, [0, 2]}, {end_key, [0, 4]}]),
- Expect = {ok, [
- {meta, []},
- {row, [{key, null}, {value, 6}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, []},
+ {row, [{key, null}, {value, 6}]}
+ ]},
?_assertEqual(Expect, Result).
should_reduce_with_group_level(Db) ->
Result = run_query(Db, [{group_level, 1}]),
- Expect = {ok, [
- {meta, []},
- {row, [{key, [0]}, {value, 30}]},
- {row, [{key, [1]}, {value, 25}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, []},
+ {row, [{key, [0]}, {value, 30}]},
+ {row, [{key, [1]}, {value, 25}]}
+ ]},
?_assertEqual(Expect, Result).
should_reduce_with_group_exact(Db) ->
Result = run_query(Db, [{group_level, exact}]),
- Expect = {ok, [
- {meta, []},
- {row, [{key, [0, 2]}, {value, 2}]},
- {row, [{key, [0, 4]}, {value, 4}]},
- {row, [{key, [0, 6]}, {value, 6}]},
- {row, [{key, [0, 8]}, {value, 8}]},
- {row, [{key, [0, 10]}, {value, 10}]},
- {row, [{key, [1, 1]}, {value, 1}]},
- {row, [{key, [1, 3]}, {value, 3}]},
- {row, [{key, [1, 5]}, {value, 5}]},
- {row, [{key, [1, 7]}, {value, 7}]},
- {row, [{key, [1, 9]}, {value, 9}]}
- ]},
+ Expect =
+ {ok, [
+ {meta, []},
+ {row, [{key, [0, 2]}, {value, 2}]},
+ {row, [{key, [0, 4]}, {value, 4}]},
+ {row, [{key, [0, 6]}, {value, 6}]},
+ {row, [{key, [0, 8]}, {value, 8}]},
+ {row, [{key, [0, 10]}, {value, 10}]},
+ {row, [{key, [1, 1]}, {value, 1}]},
+ {row, [{key, [1, 3]}, {value, 3}]},
+ {row, [{key, [1, 5]}, {value, 5}]},
+ {row, [{key, [1, 7]}, {value, 7}]},
+ {row, [{key, [1, 9]}, {value, 9}]}
+ ]},
?_assertEqual(Expect, Result).
-
run_query(Db, Opts) ->
couch_mrview:query_view(Db, <<"_design/red">>, <<"baz">>, Opts).
diff --git a/src/couch_mrview/test/eunit/couch_mrview_util_tests.erl b/src/couch_mrview/test/eunit/couch_mrview_util_tests.erl
index 7046c9bb2..a495fd82c 100644
--- a/src/couch_mrview/test/eunit/couch_mrview_util_tests.erl
+++ b/src/couch_mrview/test/eunit/couch_mrview_util_tests.erl
@@ -15,25 +15,23 @@
-include_lib("couch/include/couch_eunit.hrl").
-include_lib("couch_mrview/include/couch_mrview.hrl").
-
-
couch_mrview_util_test_() ->
[
- ?_assertEqual(0, validate_group_level(undefined, undefined)),
- ?_assertEqual(exact, validate_group_level(true, undefined)),
- ?_assertEqual(0, validate_group_level(false, undefined)),
- ?_assertEqual(1, validate_group_level(undefined, 1)),
- ?_assertEqual(0, validate_group_level(true, 0)),
- ?_assertEqual(0, validate_group_level(undefined, 0)),
- ?_assertEqual(1, validate_group_level(true, 1)),
- ?_assertEqual(0, validate_group_level(false, 0)),
- ?_assertThrow({query_parse_error,
- <<"Can't specify group=false and group_level>0 at the same time">>},
- validate_group_level(false,1))
+ ?_assertEqual(0, validate_group_level(undefined, undefined)),
+ ?_assertEqual(exact, validate_group_level(true, undefined)),
+ ?_assertEqual(0, validate_group_level(false, undefined)),
+ ?_assertEqual(1, validate_group_level(undefined, 1)),
+ ?_assertEqual(0, validate_group_level(true, 0)),
+ ?_assertEqual(0, validate_group_level(undefined, 0)),
+ ?_assertEqual(1, validate_group_level(true, 1)),
+ ?_assertEqual(0, validate_group_level(false, 0)),
+ ?_assertThrow(
+ {query_parse_error, <<"Can't specify group=false and group_level>0 at the same time">>},
+ validate_group_level(false, 1)
+ )
].
validate_group_level(Group, GroupLevel) ->
- Args0 = #mrargs{group=Group, group_level=GroupLevel, view_type=red},
+ Args0 = #mrargs{group = Group, group_level = GroupLevel, view_type = red},
Args1 = couch_mrview_util:validate_args(Args0),
Args1#mrargs.group_level.
-