summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTony Sun <tony.sun427@gmail.com>2017-10-31 17:54:28 -0700
committerGitHub <noreply@github.com>2017-10-31 17:54:28 -0700
commit96046e5996f110c616a5ad07b943e7bbba5c25ce (patch)
tree3e0a9e4f8b1c1820cb21c863d340f09932927473
parentc4ac5c04d051f4e1336f90ebdca82706b2b9633b (diff)
downloadcouchdb-96046e5996f110c616a5ad07b943e7bbba5c25ce.tar.gz
fix external size bug when seq btree exists (#849)
When users specify "options": {"seq_indexed": true}, we will run reduced_external_size/1 on seq btrees. The reduce will return an integer because the reduce function is: couch_db_updater:btree_by_seq_reduce/2. This leads to a bad match error. Thanks @jiangphcn for finding this.
-rw-r--r--src/couch_mrview/src/couch_mrview.erl18
-rw-r--r--src/couch_mrview/src/couch_mrview_util.erl34
-rw-r--r--src/couch_mrview/test/couch_mrview_map_views_tests.erl23
3 files changed, 63 insertions, 12 deletions
diff --git a/src/couch_mrview/src/couch_mrview.erl b/src/couch_mrview/src/couch_mrview.erl
index 07e36687d..83a03ffa1 100644
--- a/src/couch_mrview/src/couch_mrview.erl
+++ b/src/couch_mrview/src/couch_mrview.erl
@@ -314,15 +314,17 @@ count_view_changes_since(Db, DDoc, VName, SinceSeq, Options) ->
true -> View#mrview.key_byseq_btree;
_ -> View#mrview.seq_btree
end,
+ RedFun = fun(_SeqStart, PartialReds, 0) ->
+ {ok, couch_btree:final_reduce(Btree, PartialReds)}
+ end,
lists:foldl(fun(Opts, Acc0) ->
- {ok, N} = couch_btree:fold_reduce(
- Btree, fun(_SeqStart, PartialReds, 0) ->
- {ok, couch_btree:final_reduce(
- Btree, PartialReds)}
- end,
- 0, Opts),
- Acc0 + N
- end, 0, OptList);
+ case couch_btree:fold_reduce(Btree, RedFun, 0, Opts) of
+ {ok, N} when is_integer(N) ->
+ Acc0 + N;
+ {ok, N} when is_tuple(N) ->
+ Acc0 + element(1, N)
+ end
+ end, 0, OptList);
_ ->
{error, seqs_not_indexed}
end.
diff --git a/src/couch_mrview/src/couch_mrview_util.erl b/src/couch_mrview/src/couch_mrview_util.erl
index 0d58e4f35..d26df94f2 100644
--- a/src/couch_mrview/src/couch_mrview_util.erl
+++ b/src/couch_mrview/src/couch_mrview_util.erl
@@ -299,7 +299,7 @@ open_view(Db, Fd, Lang, ViewState, View) ->
],
{ok, Btree} = couch_btree:open(BTState, Fd, ViewBtOpts),
- BySeqReduceFun = fun couch_db_updater:btree_by_seq_reduce/2,
+ BySeqReduceFun = make_seq_reduce_fun(),
{ok, SeqBtree} = if View#mrview.seq_indexed ->
SeqBTState = get_seq_btree_state(ViewState),
ViewSeqBtOpts = [{reduce, BySeqReduceFun},
@@ -804,16 +804,24 @@ reduced_external_size(Tree) ->
end.
+reduced_seq_external_size(Tree) ->
+ case couch_btree:full_reduce(Tree) of
+ {ok, {_, Size}} -> Size;
+ % return 0 for older versions that only returned number of docs
+ {ok, NumDocs} when is_integer(NumDocs) -> 0
+ end.
+
+
calculate_external_size(Views) ->
SumFun = fun(#mrview{btree=Bt, seq_btree=SBt, key_byseq_btree=KSBt}, Acc) ->
Size0 = sum_btree_sizes(Acc, reduced_external_size(Bt)),
Size1 = case SBt of
nil -> Size0;
- _ -> sum_btree_sizes(Size0, reduced_external_size(SBt))
+ _ -> sum_btree_sizes(Size0, reduced_seq_external_size(SBt))
end,
case KSBt of
nil -> Size1;
- _ -> sum_btree_sizes(Size1, reduced_external_size(KSBt))
+ _ -> sum_btree_sizes(Size1, reduced_seq_external_size(KSBt))
end
end,
{ok, lists:foldl(SumFun, 0, Views)}.
@@ -1044,6 +1052,10 @@ 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;
@@ -1072,6 +1084,22 @@ make_reduce_fun(Lang, ReduceFuns) ->
{Counts, Result, ExternalSize}
end.
+make_seq_reduce_fun() ->
+ fun
+ (reduce, KVs0) ->
+ KVs = detuple_kvs(expand_dups(KVs0, []), []),
+ NumDocs = length(KVs),
+ ExternalSize = kv_external_size(KVs, NumDocs),
+ {NumDocs, ExternalSize};
+ (rereduce, Reds) ->
+ ExtractFun = fun(Red, {NumDocsAcc0, ExtAcc0}) ->
+ NumDocsAcc = NumDocsAcc0 + get_count(Red),
+ ExtAcc = ExtAcc0 + get_external_size_reds(Red),
+ {NumDocsAcc, ExtAcc}
+ end,
+ lists:foldl(ExtractFun, {0, 0}, Reds)
+ end.
+
maybe_define_less_fun(#mrview{options = Options}) ->
case couch_util:get_value(<<"collation">>, Options) of
diff --git a/src/couch_mrview/test/couch_mrview_map_views_tests.erl b/src/couch_mrview/test/couch_mrview_map_views_tests.erl
index 229af183d..805dc6c74 100644
--- a/src/couch_mrview/test/couch_mrview_map_views_tests.erl
+++ b/src/couch_mrview/test/couch_mrview_map_views_tests.erl
@@ -42,7 +42,8 @@ map_views_test_() ->
fun should_map_with_range/1,
fun should_map_with_limit_and_skip/1,
fun should_map_with_include_docs/1,
- fun should_map_empty_views/1
+ fun should_map_empty_views/1,
+ fun should_give_ext_size_seq_indexed_test/1
]
}
}
@@ -118,6 +119,26 @@ should_map_empty_views(Db) ->
]},
?_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);}">>}
+ ]}}
+ ]}
+ }
+ ]}),
+ {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]),
+ couch_mrview:query_view(Db1, DDoc1, <<"view1">>, [{update, true}]),
+ {ok, Info} = couch_mrview:get_info(Db1, DDoc),
+ Size = couch_util:get_nested_json_value({Info}, [sizes, external]),
+ ok = couch_db:close(Db1),
+ ?_assert(is_number(Size)).
+
run_query(Db, Opts) ->
couch_mrview:query_view(Db, <<"_design/bar">>, <<"baz">>, Opts).