summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarren Smith <garren.smith@gmail.com>2018-08-29 13:59:48 +0100
committerRobert Newson <rnewson@apache.org>2018-08-29 14:05:59 +0100
commita41624492d7a3de047c7b2ed7d55f4e058811cbd (patch)
tree9dce55334137186674c90b911cf0d7107d9e0394
parentdf7efb5919e906fdb975d12d1b2e88410d3f0a38 (diff)
downloadcouchdb-a41624492d7a3de047c7b2ed7d55f4e058811cbd.tar.gz
add /_partition/partition/designdoc/ endpoints
-rw-r--r--src/chttpd/src/chttpd_db.erl79
-rw-r--r--src/chttpd/src/chttpd_handlers.erl10
-rw-r--r--src/chttpd/src/chttpd_httpd_handlers.erl6
-rw-r--r--src/chttpd/src/chttpd_view.erl17
-rw-r--r--src/couch_mrview/src/couch_mrview.erl1
-rw-r--r--src/couch_mrview/src/couch_mrview_util.erl14
-rw-r--r--src/mango/src/mango_error.erl7
-rw-r--r--src/mango/src/mango_httpd.erl85
-rw-r--r--src/mango/src/mango_httpd_handlers.erl6
9 files changed, 203 insertions, 22 deletions
diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl
index 06b329669..f03b480da 100644
--- a/src/chttpd/src/chttpd_db.erl
+++ b/src/chttpd/src/chttpd_db.erl
@@ -18,7 +18,8 @@
db_req/2, couch_doc_open/4,handle_changes_req/2,
update_doc_result_to_json/1, update_doc_result_to_json/2,
handle_design_info_req/3, handle_view_cleanup_req/2,
- update_doc/4, http_code_from_status/1]).
+ update_doc/4, http_code_from_status/1,
+ handle_partition_req/2]).
-import(chttpd,
[send_json/2,send_json/3,send_json/4,send_method_not_allowed/2,
@@ -250,21 +251,83 @@ handle_view_cleanup_req(Req, Db) ->
ok = fabric:cleanup_index_files_all_nodes(Db),
send_json(Req, 202, {[{ok, true}]}).
+
+handle_partition_req(#httpd{
+ path_parts=[DbName, <<"_partition">>, Partition, _Design, Name, <<"_",_/binary>> = Action | _Rest]
+ }=Req, Db) ->
+
+ validate_partition_req(Req, Partition, DbName),
+ DDoc = get_design_doc(DbName, Name),
+ Partitioned = couch_mrview:get_partitioned_opt(DDoc#doc.body, true),
+
+ case Partitioned of
+ true ->
+ Handler = chttpd_handlers:partition_design_handler(Action, fun bad_action_partition_design_req/4),
+ Handler(Req, Db, DDoc, Partition);
+ false ->
+ throw({bad_request, <<"partition query is not supported in this design doc.">>})
+ end;
+
+handle_partition_req(#httpd{
+ path_parts=[DbName, <<"_partition">>, Partition, Action | _Rest]
+ }=Req, Db) ->
+ validate_partition_req(Req, Partition, DbName),
+ Handler = chttpd_handlers:partition_handler(Action, fun bad_action_partition_req/3),
+ Handler(Req, Db, Partition);
+
+handle_partition_req(_Req, _Db) ->
+ throw({bad_request, <<"missing partition key">>}).
+
+
+bad_action_partition_design_req(Req, _Db, _DDoc, _PartitionKey) ->
+ chttpd:send_error(Req, 404, <<"partition_error">>, <<"Invalid path.">>).
+
+
+bad_action_partition_req(Req, _Db, _PartitionKey) ->
+ chttpd:send_error(Req, 404, <<"partition_error">>, <<"Invalid path.">>).
+
+
+validate_partition_req(Req, Partition, DbName) ->
+ couch_doc:validate_docid(Partition, DbName),
+ validate_no_partition_in_qs(Req),
+
+ case mem3:is_partitioned(DbName) of
+ false -> throw({bad_request, <<"Database is not partitioned">>});
+ true -> ok
+ end.
+
+
handle_design_req(#httpd{
path_parts=[_DbName, _Design, Name, <<"_",_/binary>> = Action | _Rest]
}=Req, Db) ->
+ validate_no_partition_in_qs(Req),
DbName = mem3:dbname(couch_db:name(Db)),
- case ddoc_cache:open(DbName, <<"_design/", Name/binary>>) of
- {ok, DDoc} ->
- Handler = chttpd_handlers:design_handler(Action, fun bad_action_req/3),
- Handler(Req, Db, DDoc);
- Error ->
- throw(Error)
- end;
+ DDoc = get_design_doc(DbName, Name),
+ Handler = chttpd_handlers:design_handler(Action, fun bad_action_req/3),
+ Handler(Req, Db, DDoc);
handle_design_req(Req, Db) ->
db_req(Req, Db).
+
+get_design_doc(DbName, Name) ->
+ case ddoc_cache:open(DbName, <<"_design/", Name/binary>>) of
+ {ok, DDoc} ->
+ DDoc;
+ Error ->
+ throw(Error)
+ end.
+
+
+validate_no_partition_in_qs(Req) ->
+ case chttpd:qs_value(Req, "partition") of
+ undefined ->
+ ok;
+ _ ->
+ throw({bad_request, <<"Partition is not allowed in the query string">>})
+ end.
+
+
bad_action_req(#httpd{path_parts=[_, _, Name|FileNameParts]}=Req, Db, _DDoc) ->
db_attachment_req(Req, Db, <<"_design/",Name/binary>>, FileNameParts).
diff --git a/src/chttpd/src/chttpd_handlers.erl b/src/chttpd/src/chttpd_handlers.erl
index 930563230..f2098bef2 100644
--- a/src/chttpd/src/chttpd_handlers.erl
+++ b/src/chttpd/src/chttpd_handlers.erl
@@ -15,7 +15,9 @@
-export([
url_handler/2,
db_handler/2,
- design_handler/2
+ design_handler/2,
+ partition_handler/2,
+ partition_design_handler/2
]).
-define(SERVICE_ID, chttpd_handlers).
@@ -35,6 +37,12 @@ db_handler(HandlerKey, DefaultFun) ->
design_handler(HandlerKey, DefaultFun) ->
select(collect(design_handler, [HandlerKey]), DefaultFun).
+partition_handler(HandlerKey, DefaultFun) ->
+ select(collect(partition_handler, [HandlerKey]), DefaultFun).
+
+partition_design_handler(HandlerKey, DefaultFun) ->
+ select(collect(partition_design_handler, [HandlerKey]), DefaultFun).
+
%% ------------------------------------------------------------------
%% Internal Function Definitions
%% ------------------------------------------------------------------
diff --git a/src/chttpd/src/chttpd_httpd_handlers.erl b/src/chttpd/src/chttpd_httpd_handlers.erl
index cb52e2c40..2659d39f5 100644
--- a/src/chttpd/src/chttpd_httpd_handlers.erl
+++ b/src/chttpd/src/chttpd_httpd_handlers.erl
@@ -12,7 +12,7 @@
-module(chttpd_httpd_handlers).
--export([url_handler/1, db_handler/1, design_handler/1]).
+-export([url_handler/1, db_handler/1, design_handler/1, partition_design_handler/1]).
url_handler(<<>>) -> fun chttpd_misc:handle_welcome_req/1;
url_handler(<<"favicon.ico">>) -> fun chttpd_misc:handle_favicon_req/1;
@@ -32,6 +32,7 @@ url_handler(_) -> no_match.
db_handler(<<"_view_cleanup">>) -> fun chttpd_db:handle_view_cleanup_req/2;
db_handler(<<"_compact">>) -> fun chttpd_db:handle_compact_req/2;
db_handler(<<"_design">>) -> fun chttpd_db:handle_design_req/2;
+db_handler(<<"_partition">>) -> fun chttpd_db:handle_partition_req/2;
db_handler(<<"_temp_view">>) -> fun chttpd_view:handle_temp_view_req/2;
db_handler(<<"_changes">>) -> fun chttpd_db:handle_changes_req/2;
db_handler(_) -> no_match.
@@ -43,3 +44,6 @@ design_handler(<<"_update">>) -> fun chttpd_show:handle_doc_update_req/3;
design_handler(<<"_info">>) -> fun chttpd_db:handle_design_info_req/3;
design_handler(<<"_rewrite">>) -> fun chttpd_rewrite:handle_rewrite_req/3;
design_handler(_) -> no_match.
+
+partition_design_handler(<<"_view">>) -> fun chttpd_view:handle_partition_view_req/4;
+partition_design_handler(_) -> no_match.
diff --git a/src/chttpd/src/chttpd_view.erl b/src/chttpd/src/chttpd_view.erl
index 6b9570656..627663cbc 100644
--- a/src/chttpd/src/chttpd_view.erl
+++ b/src/chttpd/src/chttpd_view.erl
@@ -14,7 +14,7 @@
-include_lib("couch/include/couch_db.hrl").
-include_lib("couch_mrview/include/couch_mrview.hrl").
--export([handle_view_req/3, handle_temp_view_req/2]).
+-export([handle_view_req/3, handle_temp_view_req/2, handle_partition_view_req/4]).
multi_query_view(Req, Db, DDoc, ViewName, Queries) ->
Args0 = couch_mrview_http:parse_params(Req, undefined),
@@ -42,6 +42,10 @@ multi_query_view(Req, Db, DDoc, ViewName, Queries) ->
design_doc_view(Req, Db, DDoc, ViewName, Keys) ->
Args = couch_mrview_http:parse_params(Req, Keys),
+ design_doc_view_int(Req, Db, DDoc, ViewName, Args).
+
+
+design_doc_view_int(Req, Db, DDoc, ViewName, Args) ->
couch_mrview_util:validate_args(Args, [view]),
Max = chttpd:chunked_response_buffer_size(),
VAcc = #vacc{db=Db, req=Req, threshold=Max},
@@ -102,6 +106,17 @@ handle_temp_view_req(Req, _Db) ->
chttpd:send_error(Req, 410, gone, Msg).
+handle_partition_view_req(#httpd{method='GET',
+ path_parts=[_, _, _, _, _, _, ViewName]} = Req, Db, DDoc, Partition) ->
+ Keys = chttpd:qs_json_value(Req, "keys", undefined),
+ Args = couch_mrview_http:parse_params(Req, Keys),
+ Args1 = couch_mrview_util:set_extra(Args, partition, Partition),
+ Args2 = couch_mrview_util:set_extra(Args1, partitioned, true),
+ design_doc_view_int(Req, Db, DDoc, ViewName, Args2);
+
+handle_partition_view_req(Req, _Db, _DDoc, _Pk) ->
+ chttpd:send_method_not_allowed(Req, "GET").
+
-ifdef(TEST).
diff --git a/src/couch_mrview/src/couch_mrview.erl b/src/couch_mrview/src/couch_mrview.erl
index 7862afb1e..1b1a06b74 100644
--- a/src/couch_mrview/src/couch_mrview.erl
+++ b/src/couch_mrview/src/couch_mrview.erl
@@ -24,6 +24,7 @@
-export([refresh/2]).
-export([compact/2, compact/3, cancel_compaction/2]).
-export([cleanup/1]).
+-export([get_partitioned_opt/2]).
-include_lib("couch/include/couch_db.hrl").
-include_lib("couch_mrview/include/couch_mrview.hrl").
diff --git a/src/couch_mrview/src/couch_mrview_util.erl b/src/couch_mrview/src/couch_mrview_util.erl
index 794b69482..0fa5c1faa 100644
--- a/src/couch_mrview/src/couch_mrview_util.erl
+++ b/src/couch_mrview/src/couch_mrview_util.erl
@@ -617,6 +617,20 @@ validate_args(Args, ValidateOptions) ->
ok
end,
+ case {Partitioned, Args#mrargs.conflicts} of
+ {true, true} ->
+ mrverror(<<"`conflicts=true` is not supported in this view.">>);
+ {_, _} ->
+ ok
+ end,
+
+ case {Partitioned, Args#mrargs.stable} of
+ {true, true} ->
+ mrverror(<<"`stable=true` is not supported in this view.">>);
+ {_, _} ->
+ ok
+ end,
+
Args1 = case {Style, Partitioned, Partition} of
{all_docs, true, undefined} ->
Args;
diff --git a/src/mango/src/mango_error.erl b/src/mango/src/mango_error.erl
index b2bbb392a..603fb5fd4 100644
--- a/src/mango/src/mango_error.erl
+++ b/src/mango/src/mango_error.erl
@@ -73,6 +73,13 @@ info(mango_fields, {invalid_field_json, BadField}) ->
fmt("Invalid JSON for field spec: ~w", [BadField])
};
+info(mango_httpd, partition_field_error) ->
+ {
+ 400,
+ <<"bad request">>,
+ <<"`partition` is not a valid parameter.">>
+ };
+
info(mango_httpd, error_saving_ddoc) ->
{
500,
diff --git a/src/mango/src/mango_httpd.erl b/src/mango/src/mango_httpd.erl
index 2e8777135..9a5c266db 100644
--- a/src/mango/src/mango_httpd.erl
+++ b/src/mango/src/mango_httpd.erl
@@ -14,7 +14,8 @@
-export([
- handle_req/2
+ handle_req/2,
+ handle_partition_req/3
]).
@@ -38,13 +39,7 @@ handle_req(#httpd{} = Req, Db0) ->
handle_req_int(Req, Db)
catch
throw:{mango_error, Module, Reason} ->
- case mango_error:info(Module, Reason) of
- {500, ErrorStr, ReasonStr} ->
- Stack = erlang:get_stacktrace(),
- chttpd:send_error(Req, {ErrorStr, ReasonStr, Stack});
- {Code, ErrorStr, ReasonStr} ->
- chttpd:send_error(Req, Code, ErrorStr, ReasonStr)
- end
+ handle_req_error(Req, Module, Reason)
end.
@@ -58,6 +53,34 @@ handle_req_int(_, _) ->
throw({not_found, missing}).
+handle_partition_req(#httpd{} = Req, Db0, Partition) ->
+ try
+ Db = set_user_ctx(Req, Db0),
+ handle_partition_req_int(Req, Db, Partition)
+ catch
+ throw:{mango_error, Module, Reason} ->
+ handle_req_error(Req, Module, Reason)
+ end.
+
+
+handle_partition_req_int(#httpd{path_parts=[_, _, _, <<"_explain">> | _]} = Req, Db, Partition) ->
+ handle_partition_explain_req(Req, Db, Partition);
+handle_partition_req_int(#httpd{path_parts=[_, _, _,<<"_find">> | _]} = Req, Db, Partition) ->
+ handle_partition_find_req(Req, Db, Partition);
+handle_partition_req_int(_, _, _) ->
+ throw({not_found, missing}).
+
+
+handle_req_error(Req, Module, Reason) ->
+ case mango_error:info(Module, Reason) of
+ {500, ErrorStr, ReasonStr} ->
+ Stack = erlang:get_stacktrace(),
+ chttpd:send_error(Req, {ErrorStr, ReasonStr, Stack});
+ {Code, ErrorStr, ReasonStr} ->
+ chttpd:send_error(Req, Code, ErrorStr, ReasonStr)
+ end.
+
+
handle_index_req(#httpd{method='GET', path_parts=[_, _]}=Req, Db) ->
Params = lists:flatmap(fun({K, V}) -> parse_index_param(K, V) end,
chttpd:qs(Req)),
@@ -170,7 +193,9 @@ handle_index_req(#httpd{path_parts=[_, _, _DDocId0, _Type, _Name]}=Req, _Db) ->
handle_explain_req(#httpd{method='POST'}=Req, Db) ->
chttpd:validate_ctype(Req, "application/json"),
- {ok, Opts0} = mango_opts:validate_find(chttpd:json_body_obj(Req)),
+ {Body0} = chttpd:json_body_obj(Req),
+ check_for_partition_param(Body0),
+ {ok, Opts0} = mango_opts:validate_find({Body0}),
{value, {selector, Sel}, Opts} = lists:keytake(selector, 1, Opts0),
Resp = mango_crud:explain(Db, Sel, Opts),
chttpd:send_json(Req, Resp);
@@ -179,9 +204,23 @@ handle_explain_req(Req, _Db) ->
chttpd:send_method_not_allowed(Req, "POST").
+handle_partition_explain_req(#httpd{method='POST'}=Req, Db, Partition) ->
+ chttpd:validate_ctype(Req, "application/json"),
+ {ok, Body} = add_partition_to_query(Req, Partition),
+ {ok, Opts0} = mango_opts:validate_find(Body),
+ {value, {selector, Sel}, Opts} = lists:keytake(selector, 1, Opts0),
+ Resp = mango_crud:explain(Db, Sel, Opts),
+ chttpd:send_json(Req, Resp);
+
+handle_partition_explain_req(Req, _Db, _Partition) ->
+ chttpd:send_method_not_allowed(Req, "POST").
+
+
handle_find_req(#httpd{method='POST'}=Req, Db) ->
chttpd:validate_ctype(Req, "application/json"),
- {ok, Opts0} = mango_opts:validate_find(chttpd:json_body_obj(Req)),
+ {Body0} = chttpd:json_body_obj(Req),
+ check_for_partition_param(Body0),
+ {ok, Opts0} = mango_opts:validate_find({Body0}),
{value, {selector, Sel}, Opts} = lists:keytake(selector, 1, Opts0),
{ok, Resp0} = start_find_resp(Req),
{ok, AccOut} = run_find(Resp0, Db, Sel, Opts),
@@ -191,6 +230,32 @@ handle_find_req(Req, _Db) ->
chttpd:send_method_not_allowed(Req, "POST").
+handle_partition_find_req(#httpd{method='POST'}=Req, Db, Partition) ->
+ chttpd:validate_ctype(Req, "application/json"),
+ {ok, Body} = add_partition_to_query(Req, Partition),
+ {ok, Opts0} = mango_opts:validate_find(Body),
+ {value, {selector, Sel}, Opts} = lists:keytake(selector, 1, Opts0),
+ {ok, Resp0} = start_find_resp(Req),
+ {ok, AccOut} = run_find(Resp0, Db, Sel, Opts),
+ end_find_resp(AccOut);
+
+handle_partition_find_req(Req, _Db, _Partition) ->
+ chttpd:send_method_not_allowed(Req, "POST").
+
+check_for_partition_param(Body) ->
+ case lists:keyfind(<<"partition">>, 1, Body) of
+ false -> ok;
+ _ -> ?MANGO_ERROR(partition_field_error)
+ end.
+
+
+add_partition_to_query(Req, Partition) ->
+ {Body0} = chttpd:json_body_obj(Req),
+ check_for_partition_param(Body0),
+ Body1 = [{<<"partition">>, Partition} | Body0],
+ {ok, {Body1}}.
+
+
set_user_ctx(#httpd{user_ctx=Ctx}, Db) ->
{ok, NewDb} = couch_db:set_user_ctx(Db, Ctx),
NewDb.
diff --git a/src/mango/src/mango_httpd_handlers.erl b/src/mango/src/mango_httpd_handlers.erl
index 80e5e277e..8589b7e14 100644
--- a/src/mango/src/mango_httpd_handlers.erl
+++ b/src/mango/src/mango_httpd_handlers.erl
@@ -12,7 +12,7 @@
-module(mango_httpd_handlers).
--export([url_handler/1, db_handler/1, design_handler/1]).
+-export([url_handler/1, db_handler/1, design_handler/1, partition_handler/1]).
url_handler(_) -> no_match.
@@ -22,3 +22,7 @@ db_handler(<<"_find">>) -> fun mango_httpd:handle_req/2;
db_handler(_) -> no_match.
design_handler(_) -> no_match.
+
+partition_handler(<<"_find">>) -> fun mango_httpd:handle_partition_req/3;
+partition_handler(<<"_explain">>) -> fun mango_httpd:handle_partition_req/3;
+partition_handler(_) -> no_match.