Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 610D3200C39 for ; Thu, 16 Mar 2017 16:50:50 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id 5FB7B160B8B; Thu, 16 Mar 2017 15:50:50 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id ABACA160B78 for ; Thu, 16 Mar 2017 16:50:49 +0100 (CET) Received: (qmail 58613 invoked by uid 500); 16 Mar 2017 15:50:48 -0000 Mailing-List: contact commits-help@couchdb.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@couchdb.apache.org Delivered-To: mailing list commits@couchdb.apache.org Received: (qmail 58594 invoked by uid 99); 16 Mar 2017 15:50:48 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 16 Mar 2017 15:50:48 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 464FFDFE8F; Thu, 16 Mar 2017 15:50:48 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: davisp@apache.org To: commits@couchdb.apache.org Message-Id: <71cddb12ce554a888acdb3a1d0b7b4d9@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: chttpd commit: updated refs/heads/COUCHDB-3326-clustered-purge to a6572cf [Forced Update!] Date: Thu, 16 Mar 2017 15:50:48 +0000 (UTC) archived-at: Thu, 16 Mar 2017 15:50:50 -0000 Repository: couchdb-chttpd Updated Branches: refs/heads/COUCHDB-3326-clustered-purge b22c5b2d4 -> a6572cfb4 (forced update) Implement clustered purge HTTP endpoint COUCHDB-3326 Project: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/commit/a6572cfb Tree: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/tree/a6572cfb Diff: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/diff/a6572cfb Branch: refs/heads/COUCHDB-3326-clustered-purge Commit: a6572cfb4bedcb77484536587ae938176b224dc4 Parents: d672352 Author: Mayya Sharipova Authored: Thu Nov 17 17:55:02 2016 -0500 Committer: Paul J. Davis Committed: Thu Mar 16 10:50:41 2017 -0500 ---------------------------------------------------------------------- src/chttpd_db.erl | 47 ++++++++++++---- test/chttpd_purge_tests.erl | 112 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/a6572cfb/src/chttpd_db.erl ---------------------------------------------------------------------- diff --git a/src/chttpd_db.erl b/src/chttpd_db.erl index 738cfe4..0bd7b8a 100644 --- a/src/chttpd_db.erl +++ b/src/chttpd_db.erl @@ -496,19 +496,20 @@ db_req(#httpd{path_parts=[_, <<"_bulk_get">>]}=Req, _Db) -> db_req(#httpd{method='POST',path_parts=[_,<<"_purge">>]}=Req, Db) -> chttpd:validate_ctype(Req, "application/json"), + W = chttpd:qs_value(Req, "w", integer_to_list(mem3:quorum(Db))), + Options = [{user_ctx, Req#httpd.user_ctx}, {w, W}], {IdsRevs} = chttpd:json_body_obj(Req), IdsRevs2 = [{Id, couch_doc:parse_revs(Revs)} || {Id, Revs} <- IdsRevs], - case fabric:purge_docs(Db, IdsRevs2) of - {ok, PurgeSeq, PurgedIdsRevs} -> - PurgedIdsRevs2 = [{Id, couch_doc:revs_to_strs(Revs)} || {Id, Revs} - <- PurgedIdsRevs], - send_json(Req, 200, {[ - {<<"purge_seq">>, PurgeSeq}, - {<<"purged">>, {PurgedIdsRevs2}} - ]}); - Error -> - throw(Error) - end; + {Status, {PurgeSeq, Results}} = fabric:purge_docs(Db, IdsRevs2, Options), + Code = case Status of + ok -> 201; + accepted -> 202 + end, + Purged = lists:zipwith(fun purge_result_to_json/2, IdsRevs2, Results), + send_json(Req, Code, {[ + {purged, Purged}, + {purge_seq, PurgeSeq} + ]}); db_req(#httpd{path_parts=[_,<<"_purge">>]}=Req, _Db) -> send_method_not_allowed(Req, "POST"); @@ -607,6 +608,21 @@ db_req(#httpd{method='GET',path_parts=[_,<<"_revs_limit">>]}=Req, Db) -> db_req(#httpd{path_parts=[_,<<"_revs_limit">>]}=Req, _Db) -> send_method_not_allowed(Req, "PUT,GET"); +db_req(#httpd{method='PUT',path_parts=[_,<<"_purged_docs_limit">>]}=Req, Db) -> + Limit = chttpd:json_body(Req), + Options = [{user_ctx, Req#httpd.user_ctx}], + case chttpd:json_body(Req) of + Limit when is_integer(Limit), Limit > 0 -> + ok = fabric:set_purged_docs_limit(Db, Limit, Options), + send_json(Req, {[{<<"ok">>, true}]}); + _-> + throw({bad_request, "`purged_docs_limit` must be positive integer"}) + end; + +db_req(#httpd{method='GET',path_parts=[_,<<"_purged_docs_limit">>]}=Req, Db) -> + send_json(Req, fabric:get_purged_docs_limit(Db)); + + % Special case to enable using an unencoded slash in the URL of design docs, % as slashes in document IDs must otherwise be URL encoded. db_req(#httpd{method='GET', mochi_req=MochiReq, path_parts=[_DbName, <<"_design/", _/binary>> | _]}=Req, _Db) -> @@ -954,6 +970,15 @@ update_doc_result_to_json(DocId, Error) -> {[{id, DocId}, {error, ErrorStr}, {reason, Reason}]}. +purge_result_to_json({DocId, _Revs}, {ok, PRevs}) -> + {[{ok, true}, {id, DocId}, {revs, couch_doc:revs_to_strs(PRevs)}]}; +purge_result_to_json({DocId, _Revs}, {accepted, PRevs}) -> + {[{ok, true}, {id, DocId}, {revs, couch_doc:revs_to_strs(PRevs)}, {accepted, true}]}; +purge_result_to_json({DocId, _Revs}, Error) -> + {_Code, ErrorStr, Reason} = chttpd:error_info(Error), + {[{id, DocId}, {error, ErrorStr}, {reason, Reason}]}. + + send_updated_doc(Req, Db, DocId, Json) -> send_updated_doc(Req, Db, DocId, Json, []). http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/a6572cfb/test/chttpd_purge_tests.erl ---------------------------------------------------------------------- diff --git a/test/chttpd_purge_tests.erl b/test/chttpd_purge_tests.erl new file mode 100644 index 0000000..3b18e3e --- /dev/null +++ b/test/chttpd_purge_tests.erl @@ -0,0 +1,112 @@ +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +-module(chttpd_purge_tests). + + +-include_lib("couch/include/couch_eunit.hrl"). +-include_lib("couch/include/couch_db.hrl"). + + +-define(USER, "chttpd_db_test_admin"). +-define(PASS, "pass"). +-define(AUTH, {basic_auth, {?USER, ?PASS}}). +-define(CONTENT_JSON, {"Content-Type", "application/json"}). + + +setup() -> + ok = config:set("admins", ?USER, ?PASS, _Persist=false), + TmpDb = ?tempdb(), + Addr = config:get("chttpd", "bind_address", "127.0.0.1"), + Port = mochiweb_socket_server:get(chttpd, port), + Url = lists:concat(["http://", Addr, ":", Port, "/", ?b2l(TmpDb)]), + create_db(Url), + Url. + + +teardown(Url) -> + delete_db(Url), + ok = config:delete("admins", ?USER, _Persist=false). + + +create_db(Url) -> + {ok, Status, _, _} = test_request:put(Url, [?CONTENT_JSON, ?AUTH], "{}"), + ?assert(Status =:= 201 orelse Status =:= 202). + + +create_doc(Url, Id) -> + test_request:put(Url ++ "/" ++ Id, + [?CONTENT_JSON, ?AUTH], "{\"mr\": \"rockoartischocko\"}"). + + +delete_db(Url) -> + {ok, 200, _, _} = test_request:delete(Url, [?AUTH]). + + +purge_test_() -> + { + "chttpd db tests", + { + setup, + fun chttpd_test_util:start_couch/0, + fun chttpd_test_util:stop_couch/1, + { + foreach, + fun setup/0, + fun teardown/1, + [ + fun test_ok_purge_request/1, + fun should_error_set_purged_docs_limit_to0/1 + ] + } + } + }. + + +test_ok_purge_request(Url) -> + ?_test(begin + {ok, _, _, Body} = create_doc(Url, "doc1"), + {Json} = ?JSON_DECODE(Body), + Rev1 = couch_util:get_value(<<"rev">>, Json, undefined), + {ok, _, _, Body2} = create_doc(Url, "doc2"), + {Json2} = ?JSON_DECODE(Body2), + Rev2 = couch_util:get_value(<<"rev">>, Json2, undefined), + {ok, _, _, Body3} = create_doc(Url, "doc3"), + {Json3} = ?JSON_DECODE(Body3), + Rev3 = couch_util:get_value(<<"rev">>, Json3, undefined), + IdsRevs = "{\"doc1\": [\"" ++ ?b2l(Rev1) ++ "\"], \"doc2\": [\"" ++ + ?b2l(Rev2) ++ "\"], \"doc3\": [\"" ++ ?b2l(Rev3) ++ "\"] }", + + {ok, Status, _, ResultBody} = test_request:post(Url ++ "/_purge/", + [?CONTENT_JSON, ?AUTH], IdsRevs), + ?assert(Status =:= 201 orelse Status =:= 202), + ResultJson = ?JSON_DECODE(ResultBody), + ?assertMatch( + {[ + {<<"purged">>, [ + {[{<<"ok">>,true}, {<<"id">>,<<"doc1">>}, {<<"revs">>,[Rev1]}]}, + {[{<<"ok">>,true}, {<<"id">>,<<"doc2">>}, {<<"revs">>,[Rev2]}]}, + {[{<<"ok">>,true}, {<<"id">>,<<"doc3">>}, {<<"revs">>,[Rev3]}]} + ]}, + {<<"purge_seq">>, _} + ]}, + ResultJson + ) + end). + + +should_error_set_purged_docs_limit_to0(Url) -> + ?_test(begin + {ok, Status, _, _} = test_request:put(Url ++ "/_purged_docs_limit/", + [?CONTENT_JSON, ?AUTH], "0"), + ?assert(Status =:= 400) + end).