You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ch...@apache.org on 2014/02/27 21:02:32 UTC

couch-mrview commit: updated refs/heads/1993-bigcouch-couch-mrview to 3015c85

Repository: couchdb-couch-mrview
Updated Branches:
  refs/heads/1993-bigcouch-couch-mrview 22ec9d906 -> 3015c8554


Add support for multi query views

This adds support for making multiple view queries in one request by
supplying a "queries" list in a POST request body. The primary
implementation was ported over from chttpd_view:multi_query_view/5.

The support added here is two fold. First, we add multi_query_view
support to the single node interface in couch_mrview_http. Second we
add support in couch_mrview_http:view_cb/2 to allow chttpd to utilize
this callback as well.

This also switches updates the #vacc record from setting a multi_query
flag, to instead setting a should_close flag. Now
couch_mrview_http:view_cb/2 will only start a new delayed response if
#vacc.resp is undefined, and similarly, it will only close a delayed
response if #vacc.should_close is true.

COUCHDB-523
COUCHDB-1993


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-mrview/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-mrview/commit/3015c855
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-mrview/tree/3015c855
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-mrview/diff/3015c855

Branch: refs/heads/1993-bigcouch-couch-mrview
Commit: 3015c8554ae38fc3fa7890209c5e394e5995e1c8
Parents: 22ec9d9
Author: Russell Branca <ch...@apache.org>
Authored: Thu Feb 27 11:43:12 2014 -0800
Committer: Russell Branca <ch...@apache.org>
Committed: Thu Feb 27 11:43:12 2014 -0800

----------------------------------------------------------------------
 include/couch_mrview.hrl  |  2 +-
 src/couch_mrview_http.erl | 98 ++++++++++++++----------------------------
 src/couch_mrview_util.erl | 24 +++++++++++
 3 files changed, 57 insertions(+), 67 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-mrview/blob/3015c855/include/couch_mrview.hrl
----------------------------------------------------------------------
diff --git a/include/couch_mrview.hrl b/include/couch_mrview.hrl
index 8791249..b279d8c 100644
--- a/include/couch_mrview.hrl
+++ b/include/couch_mrview.hrl
@@ -87,5 +87,5 @@
     resp,
     prepend,
     etag,
-    multi_query
+    should_close = false
 }).

http://git-wip-us.apache.org/repos/asf/couchdb-couch-mrview/blob/3015c855/src/couch_mrview_http.erl
----------------------------------------------------------------------
diff --git a/src/couch_mrview_http.erl b/src/couch_mrview_http.erl
index 87a56b0..f29a089 100644
--- a/src/couch_mrview_http.erl
+++ b/src/couch_mrview_http.erl
@@ -20,6 +20,7 @@
     handle_compact_req/3,
     handle_cleanup_req/2,
     parse_params/2,
+    parse_params/3,
     view_cb/2,
     row_to_json/1,
     row_to_json/2,
@@ -37,7 +38,7 @@
 handle_all_docs_req(#httpd{method='GET'}=Req, Db) ->
     all_docs_req(Req, Db, undefined);
 handle_all_docs_req(#httpd{method='POST'}=Req, Db) ->
-    Keys = get_view_keys(couch_httpd:json_body_obj(Req)),
+    Keys = couch_mrview_util:get_view_keys(couch_httpd:json_body_obj(Req)),
     all_docs_req(Req, Db, Keys);
 handle_all_docs_req(Req, _Db) ->
     couch_httpd:send_method_not_allowed(Req, "GET,POST,HEAD").
@@ -50,8 +51,8 @@ handle_view_req(#httpd{method='GET'}=Req, Db, DDoc) ->
 handle_view_req(#httpd{method='POST'}=Req, Db, DDoc) ->
     [_, _, _, _, ViewName] = Req#httpd.path_parts,
     Props = couch_httpd:json_body_obj(Req),
-    Keys = get_view_keys(Props),
-    Queries = get_view_queries(Props),
+    Keys = couch_mrview_util:get_view_keys(Props),
+    Queries = couch_mrview_util:get_view_queries(Props),
     case {Queries, Keys} of
         {Queries, undefined} when is_list(Queries) ->
             [couch_stats_collector:increment({httpd, view_reads}) || _I <- Queries],
@@ -76,7 +77,7 @@ handle_temp_view_req(#httpd{method='POST'}=Req, Db) ->
     ok = couch_db:check_is_admin(Db),
     {Body} = couch_httpd:json_body_obj(Req),
     DDoc = couch_mrview_util:temp_view_to_ddoc({Body}),
-    Keys = get_view_keys({Body}),
+    Keys = couch_mrview_util:get_view_keys({Body}),
     couch_stats_collector:increment({httpd, temporary_view_reads}),
     design_doc_view(Req, Db, DDoc, <<"temp">>, Keys);
 handle_temp_view_req(Req, _Db) ->
@@ -161,26 +162,16 @@ design_doc_view(Req, Db, DDoc, ViewName, Keys) ->
 
 multi_query_view(Req, Db, DDoc, ViewName, Queries) ->
     Args0 = parse_params(Req, undefined),
-    %% ETagFun = fun(Sig, Acc0) ->
-    %%     check_view_etag(Sig, Acc0, Req)
-    %% end,
-    %% Args = Args0#mrargs{preflight_fun=ETagFun},
-    %% Args2 = couch_util:with_db(
-    %%     DbName,
-    %%     fun(WDb) ->
-    %%         {ok, _VInfo, _Sig, Args1} =
-    %%             couch_mrview_util:get_view(WDb, DDoc, ViewName, Args0),
-    %%         Args1
-    %%     end
-    %% ),
     {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(QueryArg)
     end, Queries),
     {ok, Resp2} = couch_httpd:etag_maybe(Req, fun() ->
-        VAcc0 = #vacc{db=Db, req=Req, multi_query=true},
-        Headers = [{"ETag", VAcc0#vacc.etag}],
+        VAcc0 = #vacc{db=Db, req=Req, prepend="\r\n"},
+        %% 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},
@@ -198,19 +189,13 @@ multi_query_view(Req, Db, DDoc, ViewName, Queries) ->
     end.
 
 
-view_cb({meta, Meta}, #vacc{resp=undefined, multi_query=undefined}=Acc) ->
+view_cb({meta, Meta}, #vacc{resp=undefined}=Acc) ->
     % Map function starting
     Headers = [{"ETag", Acc#vacc.etag}],
     {ok, Resp} = chttpd:start_delayed_json_response(Acc#vacc.req, 200, Headers),
-    view_cb({meta, Meta}, Acc#vacc{resp=Resp});
-view_cb({meta, Meta}, #vacc{resp=Resp, prepend=Prepend0}=Acc) ->
+    view_cb({meta, Meta}, Acc#vacc{resp=Resp, should_close=true});
+view_cb({meta, Meta}, #vacc{resp=Resp}=Acc) ->
     % Sending metadata
-    Prepend = case Prepend0 of
-        undefined ->
-            "";
-        _ ->
-            Prepend0
-    end,
     Parts = case couch_util:get_value(total, Meta) of
         undefined -> [];
         Total -> [io_lib:format("\"total_rows\":~p", [Total])]
@@ -221,34 +206,38 @@ view_cb({meta, Meta}, #vacc{resp=Resp, prepend=Prepend0}=Acc) ->
         undefined -> [];
         UpdateSeq -> [io_lib:format("\"update_seq\":~p", [UpdateSeq])]
     end ++ ["\"rows\":["],
+    Prepend = prepend_val(Acc),
     Chunk = lists:flatten(Prepend ++ "{" ++ string:join(Parts, ",") ++ "\r\n"),
     {ok, Resp1} = chttpd:send_delayed_chunk(Resp, Chunk),
     {ok, Acc#vacc{resp=Resp1, prepend=""}};
-view_cb({row, Row}, #vacc{resp=undefined}=Acc) ->
-    % Reduce function starting
-    Headers = [{"ETag", Acc#vacc.etag}],
-    {ok, Resp} = chttpd:start_delayed_json_response(Acc#vacc.req, 200, Headers),
-    Chunk = ["{\"rows\":[\r\n", row_to_json(Row)],
-    {ok, Resp1} = chttpd:send_delayed_chunk(Resp, Chunk),
-    {ok, Acc#vacc{resp=Resp1, prepend=",\r\n"}};
 view_cb({row, Row}, Acc) ->
     % Adding another row
-    Chunk = [Acc#vacc.prepend, row_to_json(Row)],
+    Chunk = [prepend_val(Acc), row_to_json(Row)],
     {ok, Resp1} = chttpd:send_delayed_chunk(Acc#vacc.resp, Chunk),
     {ok, Acc#vacc{prepend=",\r\n", resp=Resp1}};
 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(complete, #vacc{resp=Resp0, multi_query=true}=Acc) ->
-    % Finish current query of a multiquery view output
-    {ok, Resp1} = chttpd:send_delayed_chunk(Resp0, "\r\n]}"),
-    {ok, Acc#vacc{resp=Resp1, prepend=",\r\n"}};
 view_cb(complete, #vacc{resp=Resp}=Acc) ->
-    % Finish view output
-    chttpd:send_delayed_chunk(Resp, "\r\n]}"),
-    chttpd:end_delayed_json_response(Resp),
-    {ok, Acc}.
+    % Finish view output and possibly end the response
+    {ok, Resp1} = chttpd:send_delayed_chunk(Resp, "\r\n]}"),
+    case Acc#vacc.should_close of
+        true ->
+            {ok, Resp2} = chttpd:end_delayed_json_response(Resp1),
+            {ok, Acc#vacc{resp=Resp2}};
+        _ ->
+            {ok, Acc#vacc{resp=Resp1, prepend=",\r\n"}}
+    end.
+
+
+prepend_val(#vacc{prepend=Prepend}) ->
+    case Prepend of
+        undefined ->
+            "";
+        _ ->
+            Prepend
+    end.
 
 
 row_to_json(Row) ->
@@ -278,29 +267,6 @@ row_to_json(Id0, Row) ->
     ?JSON_ENCODE(Obj).
 
 
-get_view_keys({Props}) ->
-    case couch_util:get_value(<<"keys">>, Props) of
-        undefined ->
-            ?LOG_DEBUG("POST with no keys member.", []),
-            undefined;
-        Keys when is_list(Keys) ->
-            Keys;
-        _ ->
-            throw({bad_request, "`keys` member must be a array."})
-    end.
-
-
-get_view_queries({Props}) ->
-    case couch_util:get_value(<<"queries">>, Props) of
-        undefined ->
-            undefined;
-        Queries when is_list(Queries) ->
-            Queries;
-        _ ->
-            throw({bad_request, "`queries` member must be a array."})
-    end.
-
-
 parse_params(#httpd{}=Req, Keys) ->
     parse_params(couch_httpd:qs(Req), Keys);
 parse_params(Props, Keys) ->

http://git-wip-us.apache.org/repos/asf/couchdb-couch-mrview/blob/3015c855/src/couch_mrview_util.erl
----------------------------------------------------------------------
diff --git a/src/couch_mrview_util.erl b/src/couch_mrview_util.erl
index ae8079d..8a36c0b 100644
--- a/src/couch_mrview_util.erl
+++ b/src/couch_mrview_util.erl
@@ -25,6 +25,7 @@
 -export([validate_args/1]).
 -export([maybe_load_doc/3, maybe_load_doc/4]).
 -export([extract_view_reduce/1]).
+-export([get_view_keys/1, get_view_queries/1]).
 
 -define(MOD, couch_mrview_index).
 
@@ -713,3 +714,26 @@ mrverror(Mesg) ->
 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 ->
+            ?LOG_DEBUG("POST with no keys member.", []),
+            undefined;
+        Keys when is_list(Keys) ->
+            Keys;
+        _ ->
+            throw({bad_request, "`keys` member must be a array."})
+    end.
+
+
+get_view_queries({Props}) ->
+    case couch_util:get_value(<<"queries">>, Props) of
+        undefined ->
+            undefined;
+        Queries when is_list(Queries) ->
+            Queries;
+        _ ->
+            throw({bad_request, "`queries` member must be a array."})
+    end.