This is an automated email from the ASF dual-hosted git repository. rnewson pushed a commit to branch user-partitioned-dbs-6 in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit c88d71e7751177f443807bac7fbe7d61e6305757 Author: Robert Newson <[email protected]> AuthorDate: Thu Aug 9 13:43:17 2018 +0100 WIP crappy _all_docs hack --- src/chttpd/src/chttpd_db.erl | 9 ++- src/couch_mrview/src/couch_mrview.erl | 7 +- src/couch_mrview/src/couch_mrview_util.erl | 104 ++++++++++++++++++++++++++--- src/fabric/src/fabric.erl | 7 +- src/fabric/src/fabric_view.erl | 7 +- src/fabric/src/fabric_view_all_docs.erl | 2 +- src/mem3/src/mem3.erl | 5 +- 7 files changed, 118 insertions(+), 23 deletions(-) diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl index 57d85e1..83d0489 100644 --- a/src/chttpd/src/chttpd_db.erl +++ b/src/chttpd/src/chttpd_db.erl @@ -684,12 +684,15 @@ multi_all_docs_view(Req, Db, OP, Queries) -> all_docs_view(Req, Db, Keys, OP) -> Args0 = couch_mrview_http:parse_params(Req, Keys), Args1 = Args0#mrargs{view_type=map}, - Args2 = couch_mrview_util:validate_args(Args1), - Args3 = set_namespace(OP, Args2), + DbPartitioned = mem3:is_partitioned(couch_db:name(Db)), + Args2 = couch_mrview_util:set_extra(Args1, partitioned, DbPartitioned), + Args3 = couch_mrview_util:set_extra(Args2, style, all_docs), + Args4 = couch_mrview_util:validate_args(Args3), + Args5 = set_namespace(OP, Args4), Options = [{user_ctx, Req#httpd.user_ctx}], Max = chttpd:chunked_response_buffer_size(), VAcc = #vacc{db=Db, req=Req, threshold=Max}, - {ok, Resp} = fabric:all_docs(Db, Options, fun couch_mrview_http:view_cb/2, VAcc, Args3), + {ok, Resp} = fabric:all_docs(Db, Options, fun couch_mrview_http:view_cb/2, VAcc, Args5), {ok, Resp#vacc.resp}. db_doc_req(#httpd{method='DELETE'}=Req, Db, DocId) -> diff --git a/src/couch_mrview/src/couch_mrview.erl b/src/couch_mrview/src/couch_mrview.erl index db467f0..e1db906 100644 --- a/src/couch_mrview/src/couch_mrview.erl +++ b/src/couch_mrview/src/couch_mrview.erl @@ -228,12 +228,13 @@ query_all_docs(Db, Args0, Callback, Acc) -> couch_index_util:hexsig(couch_hash:md5_hash(term_to_binary(Info))) end), Args1 = Args0#mrargs{view_type=map}, - Args2 = couch_mrview_util:validate_args(Args1), - {ok, Acc1} = case Args2#mrargs.preflight_fun of + Args2 = couch_mrview_util:set_extra(Args1, style, all_docs), + Args3 = couch_mrview_util:validate_args(Args2), + {ok, Acc1} = case Args3#mrargs.preflight_fun of PFFun when is_function(PFFun, 2) -> PFFun(Sig, Acc); _ -> {ok, Acc} end, - all_docs_fold(Db, Args2, Callback, Acc1). + all_docs_fold(Db, Args3, Callback, Acc1). query_view(Db, DDoc, VName) -> diff --git a/src/couch_mrview/src/couch_mrview_util.erl b/src/couch_mrview/src/couch_mrview_util.erl index e4f06ff..2505148 100644 --- a/src/couch_mrview/src/couch_mrview_util.erl +++ b/src/couch_mrview/src/couch_mrview_util.erl @@ -580,20 +580,38 @@ validate_args(Args) -> _ -> mrverror(<<"Invalid value for `sorted`.">>) end, - case {get_extra(Args, partitioned, false), get_extra(Args, partition)} of - {true, undefined} -> + Style = get_extra(Args, style, normal), + Partitioned = get_extra(Args, partitioned, false), + Partition = get_extra(Args, partition), + + case {Style, Partitioned, Partition} of + {all_docs, true, _} -> + ok; % _all_docs can be called with or without partition parameter. + {all_docs, false, undefined} -> + ok; + {all_docs, false, _Partition} -> + mrverror(<<"`partition` parameter is not supported in this db.">>); + {normal, true, undefined} -> mrverror(<<"`partition` parameter is mandatory for queries to this view.">>); - {true, _Partition} -> + {normal, true, _Partition} -> ok; - {false, undefined} -> + {normal, false, undefined} -> ok; - {false, _Partition} -> + {normal, false, _Partition} -> mrverror(<<"`partition` parameter is not supported in this view.">>) end, - Args1 = case get_extra(Args, partitioned, false) of - true -> apply_partition(Args); - false -> Args + Args1 = case {Style, Partitioned, Partition} of + {all_docs, true, undefined} -> + Args; + {all_docs, true, Partition} -> + apply_partition(Args, all_docs); + {all_docs, false, _} -> + Args; + {normal, true, _} -> + apply_partition(Args, normal); + {normal, false, _} -> + Args end, Args1#mrargs{ @@ -614,15 +632,18 @@ determine_group_level(#mrargs{group=true, group_level=undefined}) -> determine_group_level(#mrargs{group_level=GroupLevel}) -> GroupLevel. -apply_partition(#mrargs{} = Args0) -> +apply_partition(#mrargs{} = Args0, Style) -> case get_extra(Args0, partition_applied, false) of true -> Args0; false -> Partition = get_extra(Args0, partition), - Args1 = apply_partition(Partition, Args0), + Args1 = case Style of + normal -> apply_partition(Partition, Args0); + all_docs -> apply_all_docs_partition(Partition, Args0) + end, set_extra(Args1, partition_applied, true) - end. + end; apply_partition(Partition, #mrargs{direction=fwd, start_key=undefined, end_key=undefined} = Args) -> Args#mrargs{start_key=[Partition, ?LOWEST_KEY], end_key=[Partition, ?HIGHEST_KEY]}; @@ -646,6 +667,67 @@ apply_partition(Partition, #mrargs{start_key=SK0, end_key=EK0} = Args) -> Args#mrargs{start_key=[Partition, SK0], end_key=[Partition, EK0]}. +%% all_docs is special as it's not really a view and is already +%% effectively partitioned as the partition is a prefix of key for the +%% all_docs b+tree. +apply_all_docs_partition(Partition, #mrargs{direction=fwd, start_key=undefined, end_key=undefined} = Args) -> + Args#mrargs{start_key = <<Partition/binary, $:>>, end_key = <<Partition/binary, $;>>}; + +apply_all_docs_partition(Partition, #mrargs{direction=rev, start_key=undefined, end_key=undefined} = Args) -> + Args#mrargs{start_key = <<Partition/binary, $;>>, end_key = <<Partition/binary, $:>>}; + +apply_all_docs_partition(Partition, #mrargs{direction=fwd, start_key=SK0, end_key=undefined} = Args) -> + case prefix(SK0, <<Partition/binary, $:>>) of + true -> + Args#mrargs{start_key = SK0, end_key = <<Partition/binary, $;>>}; + false -> + mrverror(<<"`start_key` must be prefixed with selected partition.">>) + end; + +apply_all_docs_partition(Partition, #mrargs{direction=rev, start_key=SK0, end_key=undefined} = Args) -> + case prefix(SK0, <<Partition/binary, $:>>) of + true -> + Args#mrargs{start_key = SK0, end_key = <<Partition/binary, $:>>}; + false -> + mrverror(<<"`start_key` must be prefixed with selected partition.">>) + end; + +apply_all_docs_partition(Partition, #mrargs{direction=fwd, start_key=undefined, end_key=EK0} = Args) -> + case prefix(EK0, <<Partition/binary, $:>>) of + true -> + Args#mrargs{start_key = <<Partition/binary, $:>>, end_key = EK0}; + false -> + mrverror(<<"`end_key` must be prefixed with selected partition.">>) + end; + +apply_all_docs_partition(Partition, #mrargs{direction=rev, start_key=undefined, end_key=EK0} = Args) -> + case prefix(EK0, <<Partition/binary, $:>>) of + true -> + Args#mrargs{start_key = EK0, end_key = <<Partition/binary, $:>>}; + false -> + mrverror(<<"`end_key` must be prefixed with selected partition.">>) + end; + +apply_all_docs_partition(Partition, #mrargs{start_key=SK0, end_key=EK0} = Args) -> + case {prefix(SK0, <<Partition/binary, $:>>), prefix(EK0, <<Partition/binary, $:>>)} of + {false, false} -> + mrverror(<<"`start_key` and `end_key` must be prefixed with selected partition.">>); + {false, true} -> + mrverror(<<"`start_key` must be prefixed with selected partition.">>); + {true, false} -> + mrverror(<<"`end_key` must be prefixed with selected partition.">>); + {true, true} -> + Args + end. + +prefix(Subject, Prefix) -> + case binary:match(Subject, Prefix) of + {0, _} -> + true; + _ -> + false + end. + check_range(#mrargs{start_key=undefined}, _Cmp) -> ok; check_range(#mrargs{end_key=undefined}, _Cmp) -> diff --git a/src/fabric/src/fabric.erl b/src/fabric/src/fabric.erl index 98f9280..359c4af 100644 --- a/src/fabric/src/fabric.erl +++ b/src/fabric/src/fabric.erl @@ -294,9 +294,12 @@ all_docs(DbName, Callback, Acc, QueryArgs) -> #mrargs{} | [option()]) -> {ok, any()} | {error, Reason :: term()}. -all_docs(DbName, Options, Callback, Acc0, #mrargs{} = QueryArgs) when + +all_docs(DbName, Options, Callback, Acc0, #mrargs{} = QueryArgs0) when is_function(Callback, 2) -> - fabric_view_all_docs:go(dbname(DbName), opts(Options), QueryArgs, Callback, Acc0); + DbPartitioned = mem3:is_partitioned(dbname(DbName)), + QueryArgs1 = couch_mrview_util:set_extra(QueryArgs0, partitioned, DbPartitioned), + fabric_view_all_docs:go(dbname(DbName), opts(Options), QueryArgs1, Callback, Acc0); %% @doc convenience function that takes a keylist rather than a record %% @equiv all_docs(DbName, Callback, Acc0, kl_to_query_args(QueryArgs)) diff --git a/src/fabric/src/fabric_view.erl b/src/fabric/src/fabric_view.erl index 994c739..c38c209 100644 --- a/src/fabric/src/fabric_view.erl +++ b/src/fabric/src/fabric_view.erl @@ -122,7 +122,7 @@ maybe_send_row(State) -> user_acc = AccIn, query_args = QueryArgs } = State, - Partitioned = couch_mrview_util:get_extra(QueryArgs, partitioned, false), + Partitioned = couch_mrview_util:get_extra(QueryArgs, partitioned), case fabric_dict:any(0, Counters) of true -> {ok, State}; @@ -205,7 +205,10 @@ possibly_embed_doc(#collector{db_name=DbName, query_args=Args}, detach_partition(#view_row{key=[_Partition, Key]} = Row) -> Row#view_row{key = Key}; detach_partition(#view_row{key=null} = Row) -> - Row#view_row{key = null}. + Row#view_row{key = null}; +detach_partition(#view_row{} = Row) -> + Row. + keydict(undefined) -> diff --git a/src/fabric/src/fabric_view_all_docs.erl b/src/fabric/src/fabric_view_all_docs.erl index ac16dac..d515ab8 100644 --- a/src/fabric/src/fabric_view_all_docs.erl +++ b/src/fabric/src/fabric_view_all_docs.erl @@ -118,7 +118,7 @@ go(DbName, _Options, Workers, QueryArgs, Callback, Acc0) -> #mrargs{limit = Limit, skip = Skip, update_seq = UpdateSeq} = QueryArgs, State = #collector{ db_name = DbName, - query_args = QueryArgs, + query_args = couch_mrview_util:set_extra(QueryArgs, style, all_docs), callback = Callback, counters = fabric_dict:init(Workers, 0), skip = Skip, diff --git a/src/mem3/src/mem3.erl b/src/mem3/src/mem3.erl index aecca2f..f113357 100644 --- a/src/mem3/src/mem3.erl +++ b/src/mem3/src/mem3.erl @@ -352,7 +352,10 @@ is_partitioned(DbName0) when is_binary(DbName0) -> is_partitioned(mem3:shards(DbName)) end; -is_partitioned(Shards) when is_list(Shards) -> +is_partitioned([#shard{} | _] = Shards) -> + lists:all(fun is_partitioned/1, Shards); + +is_partitioned([#ordered_shard{} | _] = Shards) -> lists:all(fun is_partitioned/1, Shards); is_partitioned(#shard{opts=Opts}) ->
