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 2023/04/29 16:01:48 UTC

[couchdb] 01/01: finish partitioned support for nouveau

This is an automated email from the ASF dual-hosted git repository.

rnewson pushed a commit to branch nouveau-partition-support
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit d5f4f08bf0a2a8da2416a8b0e31215c4b97e5b0b
Author: Robert Newson <rn...@apache.org>
AuthorDate: Sat Apr 29 17:01:34 2023 +0100

    finish partitioned support for nouveau
---
 src/nouveau/src/nouveau_api.erl           | 11 +++--
 src/nouveau/src/nouveau_httpd.erl         |  6 +++
 src/nouveau/src/nouveau_index_updater.erl |  8 +++-
 test/elixir/test/config/nouveau.elixir    |  5 ++-
 test/elixir/test/nouveau_test.exs         | 70 +++++++++++++++++++++++++++++++
 5 files changed, 94 insertions(+), 6 deletions(-)

diff --git a/src/nouveau/src/nouveau_api.erl b/src/nouveau/src/nouveau_api.erl
index 5bf6b1731..d69e7a0a8 100644
--- a/src/nouveau/src/nouveau_api.erl
+++ b/src/nouveau/src/nouveau_api.erl
@@ -24,7 +24,7 @@
     delete_path/1,
     delete_path/2,
     delete_doc/3,
-    update_doc/4,
+    update_doc/5,
     search/2
 ]).
 
@@ -110,10 +110,13 @@ delete_doc(#index{} = Index, DocId, UpdateSeq) when
             send_error(Reason)
     end.
 
-update_doc(#index{} = Index, DocId, UpdateSeq, Fields) when
-    is_binary(DocId), is_integer(UpdateSeq), is_list(Fields)
+update_doc(#index{} = Index, DocId, UpdateSeq, Partition, Fields) when
+    is_binary(DocId), is_integer(UpdateSeq), (is_binary(Partition) orelse Partition == null), is_list(Fields)
 ->
-    ReqBody = {[{<<"seq">>, UpdateSeq}, {<<"fields">>, Fields}]},
+    ReqBody = #{
+        seq => UpdateSeq,
+        partition => Partition,
+        fields => Fields},
     Resp = send_if_enabled(
         doc_url(Index, DocId), [?JSON_CONTENT_TYPE], put, jiffy:encode(ReqBody)
     ),
diff --git a/src/nouveau/src/nouveau_httpd.erl b/src/nouveau/src/nouveau_httpd.erl
index 8d27048a1..5cb50de6a 100644
--- a/src/nouveau/src/nouveau_httpd.erl
+++ b/src/nouveau/src/nouveau_httpd.erl
@@ -65,6 +65,7 @@ handle_search_req_int(#httpd{method = 'GET', path_parts = [_, _, _, _, IndexName
     DbName = couch_db:name(Db),
     QueryArgs = validate_query_args(#{
         query => chttpd:qs_value(Req, "q"),
+        partition => chttpd:qs_value(Req, "partition"),
         limit => chttpd:qs_value(Req, "limit"),
         sort => chttpd:qs_value(Req, "sort"),
         ranges => chttpd:qs_value(Req, "ranges"),
@@ -82,6 +83,7 @@ handle_search_req_int(
     ReqBody = chttpd:json_body(Req, [return_maps]),
     QueryArgs = validate_query_args(#{
         query => maps:get(<<"q">>, ReqBody, undefined),
+        partition => chttpd:qs_value(Req, "partition"),
         limit => maps:get(<<"limit">>, ReqBody, undefined),
         sort => json_or_undefined(<<"sort">>, ReqBody),
         ranges => json_or_undefined(<<"ranges">>, ReqBody),
@@ -175,6 +177,10 @@ validate_query_arg(query, undefined) ->
     throw({query_parse_error, <<"q parameter is mandatory">>});
 validate_query_arg(query, Val) when is_list(Val); is_binary(Val) ->
     couch_util:to_binary(Val);
+validate_query_arg(partition, undefined) ->
+    null;
+validate_query_arg(partition, Val) when is_list(Val); is_binary(Val) ->
+    couch_util:to_binary(Val);
 validate_query_arg(limit, undefined) ->
     25;
 validate_query_arg(limit, Limit) when is_integer(Limit), Limit > 0 ->
diff --git a/src/nouveau/src/nouveau_index_updater.erl b/src/nouveau/src/nouveau_index_updater.erl
index af39faecf..99d2b147e 100644
--- a/src/nouveau/src/nouveau_index_updater.erl
+++ b/src/nouveau/src/nouveau_index_updater.erl
@@ -86,11 +86,17 @@ load_docs(FDI, {Db, Index, Proc, ChangesDone, TotalChanges}) ->
             {ok, Doc} = couch_db:open_doc(Db, DI, []),
             Json = couch_doc:to_json_obj(Doc, []),
             [Fields | _] = proc_prompt(Proc, [<<"nouveau_index_doc">>, Json]),
+            Partition = case couch_db:is_partitioned(Db) of
+                true ->
+                    couch_partition:from_docid(Id);
+                false ->
+                    null
+            end,
             case Fields of
                 [] ->
                     ok = nouveau_api:delete_doc(Index, Id, Seq);
                 _ ->
-                    case nouveau_api:update_doc(Index, Id, Seq, Fields) of
+                    case nouveau_api:update_doc(Index, Id, Seq, Partition, Fields) of
                         ok ->
                             ok;
                         {error, Reason} ->
diff --git a/test/elixir/test/config/nouveau.elixir b/test/elixir/test/config/nouveau.elixir
index fdcc66de2..5c13aac2b 100644
--- a/test/elixir/test/config/nouveau.elixir
+++ b/test/elixir/test/config/nouveau.elixir
@@ -14,6 +14,9 @@
     "ranges",
     "ranges (open)",
     "mango search by number",
-    "mango search by string"
+    "mango search by string",
+    "search GET (partitioned)",
+    "search POST (partitioned)",
+    "mango (partitioned)"
   ]
 }
diff --git a/test/elixir/test/nouveau_test.exs b/test/elixir/test/nouveau_test.exs
index 33e3f66db..3bea874d9 100644
--- a/test/elixir/test/nouveau_test.exs
+++ b/test/elixir/test/nouveau_test.exs
@@ -20,6 +20,19 @@ defmodule NouveauTest do
     assert resp.status_code in [201]
   end
 
+  def create_partitioned_search_docs(db_name) do
+    resp = Couch.post("/#{db_name}/_bulk_docs",
+      headers: ["Content-Type": "application/json"],
+      body: %{:docs => [
+                %{"_id" => "foo:doc4", "foo" => "foo", "bar" => 42},
+                %{"_id" => "bar:doc3", "foo" => "bar", "bar" => 12.0},
+                %{"_id" => "foo:doc1", "foo" => "baz", "bar" => 0},
+                %{"_id" => "bar:doc2", "foo" => "foobar", "bar" => 100},
+      ]}
+    )
+    assert resp.status_code in [201]
+  end
+
   def create_ddoc(db_name, opts \\ %{}) do
     default_ddoc = %{
       nouveau: %{
@@ -290,4 +303,61 @@ defmodule NouveauTest do
     assert ids == ["doc4"]
   end
 
+  @tag :with_partitioned_db
+  test "search GET (partitioned)", context do
+    db_name = context[:db_name]
+    create_partitioned_search_docs(db_name)
+    create_ddoc(db_name)
+
+    url = "/#{db_name}/_partition/foo/_design/foo/_nouveau/bar"
+    resp = Couch.get(url, query: %{q: "*:*", include_docs: true})
+    assert_status_code(resp, 200)
+    ids = get_ids(resp)
+    assert ids == ["foo:doc1", "foo:doc4"]
+
+    url = "/#{db_name}/_partition/bar/_design/foo/_nouveau/bar"
+    resp = Couch.get(url, query: %{q: "*:*", include_docs: true})
+    assert_status_code(resp, 200)
+    ids = get_ids(resp)
+    assert ids == ["bar:doc2", "bar:doc3"]
+  end
+
+  @tag :with_partitioned_db
+  test "search POST (partitioned)", context do
+    db_name = context[:db_name]
+    create_partitioned_search_docs(db_name)
+    create_ddoc(db_name)
+
+    url = "/#{db_name}/_partition/foo/_design/foo/_nouveau/bar"
+    resp = Couch.post(url, body: %{q: "*:*", include_docs: true})
+    assert_status_code(resp, 200)
+    ids = get_ids(resp)
+    assert ids == ["foo:doc1", "foo:doc4"]
+
+    url = "/#{db_name}/_partition/bar/_design/foo/_nouveau/bar"
+    resp = Couch.post(url, body: %{q: "*:*", include_docs: true})
+    assert_status_code(resp, 200)
+    ids = get_ids(resp)
+    assert ids == ["bar:doc2", "bar:doc3"]
+  end
+
+  @tag :with_partitioned_db
+  test "mango (partitioned)", context do
+    db_name = context[:db_name]
+    create_partitioned_search_docs(db_name)
+    create_mango_index(db_name)
+
+    url = "/#{db_name}/_partition/foo/_find"
+    resp = Couch.post(url, body: %{selector: %{foo: %{"$eq": "foo"}}})
+    assert_status_code(resp, 200)
+    ids = get_mango_ids(resp)
+    assert ids == ["foo:doc4"]
+
+    url = "/#{db_name}/_partition/bar/_find"
+    resp = Couch.post(url, body: %{selector: %{foo: %{"$eq": "bar"}}})
+    assert_status_code(resp, 200)
+    ids = get_mango_ids(resp)
+    assert ids == ["bar:doc3"]
+  end
+
 end