You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by rn...@apache.org on 2018/08/13 11:21:34 UTC

[couchdb] 03/03: WIP crappy _all_docs hack

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 <rn...@apache.org>
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}) ->