couchbase 4.2.6-dev.1 → 4.2.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. package/CONTRIBUTING.md +97 -0
  2. package/deps/couchbase-cxx-client/.github/workflows/windows.yml +0 -3
  3. package/deps/couchbase-cxx-client/CMakeLists.txt +4 -0
  4. package/deps/couchbase-cxx-client/bin/build-tests.rb +1 -1
  5. package/deps/couchbase-cxx-client/core/impl/lookup_in.cxx +1 -0
  6. package/deps/couchbase-cxx-client/core/impl/lookup_in_all_replicas.cxx +176 -0
  7. package/deps/couchbase-cxx-client/core/impl/lookup_in_all_replicas.hxx +80 -0
  8. package/deps/couchbase-cxx-client/core/impl/lookup_in_any_replica.cxx +167 -0
  9. package/deps/couchbase-cxx-client/core/impl/lookup_in_any_replica.hxx +75 -0
  10. package/deps/couchbase-cxx-client/core/impl/lookup_in_replica.cxx +97 -0
  11. package/deps/couchbase-cxx-client/core/impl/lookup_in_replica.hxx +67 -0
  12. package/deps/couchbase-cxx-client/core/io/dns_client.cxx +48 -10
  13. package/deps/couchbase-cxx-client/core/io/http_session.hxx +24 -1
  14. package/deps/couchbase-cxx-client/core/io/mcbp_session.cxx +22 -1
  15. package/deps/couchbase-cxx-client/core/logger/custom_rotating_file_sink.cxx +1 -1
  16. package/deps/couchbase-cxx-client/core/logger/logger.cxx +80 -20
  17. package/deps/couchbase-cxx-client/core/logger/logger.hxx +31 -0
  18. package/deps/couchbase-cxx-client/core/meta/features.hxx +19 -0
  19. package/deps/couchbase-cxx-client/core/operations/document_lookup_in_all_replicas.hxx +192 -0
  20. package/deps/couchbase-cxx-client/core/operations/document_lookup_in_any_replica.hxx +188 -0
  21. package/deps/couchbase-cxx-client/core/operations.hxx +2 -0
  22. package/deps/couchbase-cxx-client/core/protocol/cmd_hello.hxx +1 -0
  23. package/deps/couchbase-cxx-client/core/protocol/cmd_lookup_in_replica.cxx +107 -0
  24. package/deps/couchbase-cxx-client/core/protocol/cmd_lookup_in_replica.hxx +137 -0
  25. package/deps/couchbase-cxx-client/core/protocol/hello_feature.hxx +6 -0
  26. package/deps/couchbase-cxx-client/core/protocol/hello_feature_fmt.hxx +3 -0
  27. package/deps/couchbase-cxx-client/core/range_scan_orchestrator.cxx +22 -1
  28. package/deps/couchbase-cxx-client/core/topology/capabilities.hxx +2 -0
  29. package/deps/couchbase-cxx-client/core/topology/capabilities_fmt.hxx +6 -0
  30. package/deps/couchbase-cxx-client/core/topology/configuration.hxx +10 -0
  31. package/deps/couchbase-cxx-client/core/topology/configuration_json.hxx +4 -1
  32. package/deps/couchbase-cxx-client/couchbase/collection.hxx +111 -0
  33. package/deps/couchbase-cxx-client/couchbase/get_and_lock_options.hxx +2 -2
  34. package/deps/couchbase-cxx-client/couchbase/get_and_touch_options.hxx +2 -2
  35. package/deps/couchbase-cxx-client/couchbase/get_options.hxx +2 -2
  36. package/deps/couchbase-cxx-client/couchbase/insert_options.hxx +3 -3
  37. package/deps/couchbase-cxx-client/couchbase/lookup_in_all_replicas_options.hxx +109 -0
  38. package/deps/couchbase-cxx-client/couchbase/lookup_in_any_replica_options.hxx +101 -0
  39. package/deps/couchbase-cxx-client/couchbase/lookup_in_options.hxx +2 -2
  40. package/deps/couchbase-cxx-client/couchbase/lookup_in_replica_result.hxx +74 -0
  41. package/deps/couchbase-cxx-client/couchbase/lookup_in_result.hxx +26 -0
  42. package/deps/couchbase-cxx-client/couchbase/mutate_in_options.hxx +2 -2
  43. package/deps/couchbase-cxx-client/couchbase/remove_options.hxx +2 -2
  44. package/deps/couchbase-cxx-client/couchbase/replace_options.hxx +3 -3
  45. package/deps/couchbase-cxx-client/couchbase/touch_options.hxx +2 -2
  46. package/deps/couchbase-cxx-client/couchbase/unlock_options.hxx +2 -2
  47. package/deps/couchbase-cxx-client/couchbase/upsert_options.hxx +3 -3
  48. package/deps/couchbase-cxx-client/docs/cbc-analytics.md +3 -2
  49. package/deps/couchbase-cxx-client/docs/cbc-get.md +3 -2
  50. package/deps/couchbase-cxx-client/docs/cbc-pillowfight.md +3 -2
  51. package/deps/couchbase-cxx-client/docs/cbc-query.md +3 -2
  52. package/deps/couchbase-cxx-client/test/test_integration_subdoc.cxx +655 -0
  53. package/deps/couchbase-cxx-client/test/utils/logger.cxx +7 -0
  54. package/deps/couchbase-cxx-client/tools/utils.cxx +9 -2
  55. package/dist/binding.d.ts +47 -0
  56. package/dist/collection.d.ts +53 -1
  57. package/dist/collection.js +139 -1
  58. package/dist/couchbase.d.ts +15 -0
  59. package/dist/couchbase.js +22 -1
  60. package/dist/crudoptypes.d.ts +24 -0
  61. package/dist/crudoptypes.js +14 -1
  62. package/package.json +13 -13
  63. package/src/binding.cpp +28 -0
  64. package/src/connection.cpp +4 -0
  65. package/src/connection.hpp +2 -0
  66. package/src/connection_autogen.cpp +28 -0
  67. package/src/jstocbpp_autogen.hpp +262 -0
@@ -0,0 +1,97 @@
1
+ # Contributing
2
+
3
+ In addition to filing bugs, you may contribute by submitting patches to fix bugs in the library. Contributions may be submitted to <http://review.couchbase.com>. We use Gerrit as our code review system - and thus submitting a change requires an account there. While Github pull requests are not ignored, Gerrit pull requests will be responded to more quickly (and most likely with more detail).
4
+
5
+ For something to be accepted into the codebase, it must be formatted properly and have undergone proper testing.
6
+
7
+ ## Branches and Tags
8
+
9
+ * The `master` branch represents the mainline branch. The master branch typically consists of content going into the next release.
10
+ * For older series of the Couchbase Node.js SDK see the corresponding branches: 2.x = `v2` and 3.x = `v3`.
11
+
12
+ ## Contributing Patches
13
+
14
+ If you wish to contribute a new feature or a bug fix to the library, try to follow the following guidelines to help ensure your change gets merged upstream.
15
+
16
+ ### Before you begin
17
+
18
+ For any code change, ensure the new code you write looks similar to the code surrounding it. We have no strict code style policies, but do request that your code stand out as little as possible from its surrounding neighborhood (unless of course your change is stylistic in nature).
19
+
20
+ If your change is going to involve a substantial amount of time or effort, please attempt to discuss it with the project developers first who will provide assistance and direction where possible.
21
+
22
+ #### For new features
23
+
24
+ Ensure the feature you are adding does not already exist, and think about how this feature may be useful for other users. In general less intrusive changes are more likely to be accepted.
25
+
26
+ #### For fixing bugs
27
+
28
+ Ensure the bug you are fixing is actually a bug (and not a usage) error, and that it has not been fixed in a more recent version. Please read the [release notes](https://docs.couchbase.com/nodejs-sdk/current/project-docs/sdk-release-notes.html) as well as the [issue tracker](https://issues.couchbase.com/projects/JSCBC/issues/) to see a list of open and resolved issues.
29
+
30
+ ### Code Review
31
+
32
+ #### Signing up on Gerrit
33
+
34
+ Everything that is merged into the library goes through a code review process. The code review process is done via [Gerrit](http://review.couchbase.org).
35
+
36
+ To sign up for a Gerrit account, go to http://review.couchbase.org and click on the _Register_ link at the top right. Once you've signed in you will need to agree to the CLA (Contributor License Agreement) by going you your Gerrit account page and selecting the _Agreements_ link on the left. When you've done that, everything should flow through just fine. Be sure that you have registered your email address at http://review.couchbase.org/#/settings/contact as many sign-up methods won't pass emails along. Note that your email address in your code commit and in the Gerrit settings must match.
37
+
38
+ Add your public SSH key to Gerrit before submitting.
39
+
40
+ #### Setting up your fork with Gerrit
41
+
42
+ Assuming you have a repository created like so:
43
+
44
+ ```
45
+ $ git clone https://github.com/couchbase/couchnode.git
46
+ ```
47
+
48
+ you can simply perform two simple steps to get started with Gerrit:
49
+
50
+ ```
51
+ $ git remote add gerrit ssh://${USERNAME}@review.couchbase.org:29418/couchnode
52
+ $ scp -P 29418 ${USERNAME}@review.couchbase.org:hooks/commit-msg .git/hooks
53
+ $ chmod a+x .git/hooks/commit-msg
54
+ ```
55
+
56
+ The last change is required for annotating each commit message with a special header known as `Change-Id`. This allows Gerrit to group together different revisions of the same patch.
57
+
58
+ #### Pushing a changeset
59
+
60
+ Now that you have your change and a Gerrit account to push to, you need to upload the change for review. To do so, invoke the following incantation:
61
+
62
+ ```
63
+ $ git push gerrit HEAD:refs/for/master
64
+ ```
65
+
66
+ Where `gerrit` is the name of the _remote_ added earlier.
67
+
68
+ #### Pushing a new patchset
69
+
70
+ After a change has been pushed to Gerrit, further revisions can be made and then uploaded. These revisions are called patchsets and are associated with the the `Change-Id` created from the initial commit (see above). To push a new revision, simply ammend the commit (can also add the `--no-edit` option if no edits to the commit message are needed):
71
+
72
+ ```
73
+ $ git commit --amend
74
+ ```
75
+
76
+ Then push the revision to Gerrit:
77
+
78
+ ```
79
+ $ git push gerrit HEAD:refs/for/master
80
+ ```
81
+
82
+ Where `gerrit` is the name of the _remote_ added earlier.
83
+
84
+ #### Troubleshooting
85
+
86
+ You may encounter some errors when pushing. The most common are:
87
+
88
+ * "You are not authorized to push to this repository". You will get this if your account has not yet been approved. Please reach out in the [forums](https://www.couchbase.com/forums/c/node-js-sdk/12) if blocked.
89
+ * "Missing Change-Id". You need to install the `commit-msg` hook as described above. Note that even once you do this, you will need to ensure that any prior commits already have this header - this may be done by doing an interactive rebase (e.g. `git rebase -i origin/master` and selecting `reword` for all the commits; which will automatically fill in the Change-Id).
90
+
91
+ #### Reviewers
92
+
93
+ Once you've pushed your changeset you can add people to review. Currently these are:
94
+
95
+ * Jared Casey
96
+ * Matt Wozakowski
97
+ * Brett Lawson
@@ -13,9 +13,6 @@ jobs:
13
13
  os: [windows-2022, windows-2019]
14
14
  runs-on: ${{ matrix.os }}
15
15
  steps:
16
- - name: Install build environment
17
- run: |
18
- choco install --no-progress openssl
19
16
  - uses: actions/checkout@v2
20
17
  with:
21
18
  submodules: recursive
@@ -233,6 +233,7 @@ set(couchbase_cxx_client_FILES
233
233
  core/protocol/cmd_increment.cxx
234
234
  core/protocol/cmd_insert.cxx
235
235
  core/protocol/cmd_lookup_in.cxx
236
+ core/protocol/cmd_lookup_in_replica.cxx
236
237
  core/protocol/cmd_mutate_in.cxx
237
238
  core/protocol/cmd_noop.cxx
238
239
  core/protocol/cmd_observe_seqno.cxx
@@ -311,6 +312,9 @@ set(couchbase_cxx_client_FILES
311
312
  core/impl/key_value_error_category.cxx
312
313
  core/impl/key_value_error_context.cxx
313
314
  core/impl/lookup_in.cxx
315
+ core/impl/lookup_in_replica.cxx
316
+ core/impl/lookup_in_all_replicas.cxx
317
+ core/impl/lookup_in_any_replica.cxx
314
318
  core/impl/management_error_category.cxx
315
319
  core/impl/manager_error_context.cxx
316
320
  core/impl/match_all_query.cxx
@@ -86,7 +86,7 @@ FileUtils.mkdir_p(BUILD_DIR, verbose: true)
86
86
 
87
87
  Dir.chdir(BUILD_DIR) do
88
88
  if RUBY_PLATFORM =~ /mswin|mingw/
89
- CB_CMAKE_EXTRAS << "-DOPENSSL_ROOT_DIR=C:/Program Files/OpenSSL-Win64"
89
+ CB_CMAKE_EXTRAS << "-DOPENSSL_ROOT_DIR=C:/Program Files/OpenSSL"
90
90
  else
91
91
  CB_CMAKE_EXTRAS << "-DCMAKE_C_COMPILER=#{CB_CC}" << "-DCMAKE_CXX_COMPILER=#{CB_CXX}"
92
92
  end
@@ -60,6 +60,7 @@ initiate_lookup_in_operation(std::shared_ptr<couchbase::core::cluster> core,
60
60
  std::move(entry.value),
61
61
  entry.original_index,
62
62
  entry.exists,
63
+ entry.ec,
63
64
  });
64
65
  }
65
66
  return handler(std::move(resp.ctx), lookup_in_result{ resp.cas, std::move(entries), resp.deleted });
@@ -0,0 +1,176 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2020-Present Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include "lookup_in_all_replicas.hxx"
19
+ #include "lookup_in_replica.hxx"
20
+
21
+ #include "core/cluster.hxx"
22
+ #include "core/error_context/key_value.hxx"
23
+ #include "core/operations/document_lookup_in.hxx"
24
+ #include "core/topology/configuration.hxx"
25
+
26
+ namespace couchbase::core::impl
27
+ {
28
+
29
+ void
30
+ initiate_lookup_in_all_replicas_operation(std::shared_ptr<cluster> core,
31
+ const std::string& bucket_name,
32
+ const std::string& scope_name,
33
+ const std::string& collection_name,
34
+ std::string document_key,
35
+ const std::vector<subdoc::command>& specs,
36
+ lookup_in_all_replicas_options::built options,
37
+ lookup_in_all_replicas_handler&& handler)
38
+ {
39
+ return initiate_lookup_in_all_replicas_operation(std::move(core),
40
+ bucket_name,
41
+ scope_name,
42
+ collection_name,
43
+ std::move(document_key),
44
+ specs,
45
+ options.timeout,
46
+ movable_lookup_in_all_replicas_handler{ std::move(handler) });
47
+ }
48
+
49
+ void
50
+ initiate_lookup_in_all_replicas_operation(std::shared_ptr<cluster> core,
51
+ const std::string& bucket_name,
52
+ const std::string& scope_name,
53
+ const std::string& collection_name,
54
+ std::string document_key,
55
+ const std::vector<subdoc::command>& specs,
56
+ std::optional<std::chrono::milliseconds> timeout,
57
+ movable_lookup_in_all_replicas_handler&& handler)
58
+ {
59
+ auto request = std::make_shared<couchbase::core::impl::lookup_in_all_replicas_request>(
60
+ bucket_name, scope_name, collection_name, std::move(document_key), specs, timeout);
61
+ core->with_bucket_configuration(
62
+ bucket_name,
63
+ [core, r = std::move(request), h = std::move(handler)](std::error_code ec, const core::topology::configuration& config) mutable {
64
+ if (!config.supports_subdoc_read_replica()) {
65
+ ec = errc::common::feature_not_available;
66
+ }
67
+
68
+ if (ec) {
69
+ std::optional<std::string> first_error_path{};
70
+ std::optional<std::size_t> first_error_index{};
71
+ return h(
72
+ make_subdocument_error_context(make_key_value_error_context(ec, r->id()), ec, first_error_path, first_error_index, false),
73
+ lookup_in_all_replicas_result{});
74
+ }
75
+ struct replica_context {
76
+ replica_context(movable_lookup_in_all_replicas_handler handler, std::uint32_t expected_responses)
77
+ : handler_(std::move(handler))
78
+ , expected_responses_(expected_responses)
79
+ {
80
+ }
81
+
82
+ movable_lookup_in_all_replicas_handler handler_;
83
+ std::uint32_t expected_responses_;
84
+ bool done_{ false };
85
+ std::mutex mutex_{};
86
+ lookup_in_all_replicas_result result_{};
87
+ };
88
+ auto ctx = std::make_shared<replica_context>(std::move(h), config.num_replicas.value_or(0U) + 1U);
89
+
90
+ for (std::size_t idx = 1U; idx <= config.num_replicas.value_or(0U); ++idx) {
91
+ document_id replica_id{ r->id() };
92
+ replica_id.node_index(idx);
93
+ core->execute(
94
+ impl::lookup_in_replica_request{ std::move(replica_id), r->specs(), r->timeout() },
95
+ [ctx](impl::lookup_in_replica_response&& resp) {
96
+ movable_lookup_in_all_replicas_handler local_handler{};
97
+ {
98
+ std::scoped_lock lock(ctx->mutex_);
99
+ if (ctx->done_) {
100
+ return;
101
+ }
102
+ --ctx->expected_responses_;
103
+ if (resp.ctx.ec()) {
104
+ if (ctx->expected_responses_ > 0) {
105
+ // just ignore the response
106
+ return;
107
+ }
108
+ } else {
109
+ std::vector<lookup_in_replica_result::entry> entries{};
110
+ for (auto& field : resp.fields) {
111
+ lookup_in_replica_result::entry lookup_in_entry{};
112
+ lookup_in_entry.path = field.path;
113
+ lookup_in_entry.value = field.value;
114
+ lookup_in_entry.exists = field.exists;
115
+ lookup_in_entry.original_index = field.original_index;
116
+ entries.emplace_back(lookup_in_entry);
117
+ }
118
+ ctx->result_.emplace_back(lookup_in_replica_result{ resp.cas, entries, resp.deleted, true /* replica */ });
119
+ }
120
+ if (ctx->expected_responses_ == 0) {
121
+ ctx->done_ = true;
122
+ std::swap(local_handler, ctx->handler_);
123
+ }
124
+ }
125
+ if (local_handler) {
126
+ if (!ctx->result_.empty()) {
127
+ resp.ctx.override_ec({});
128
+ }
129
+ return local_handler(std::move(resp.ctx), std::move(ctx->result_));
130
+ }
131
+ });
132
+ }
133
+
134
+ core::operations::lookup_in_request active{ document_id{ r->id() } };
135
+ active.specs = r->specs();
136
+ active.timeout = r->timeout();
137
+ core->execute(active, [ctx](core::operations::lookup_in_response&& resp) {
138
+ movable_lookup_in_all_replicas_handler local_handler{};
139
+ {
140
+ std::scoped_lock lock(ctx->mutex_);
141
+ if (ctx->done_) {
142
+ return;
143
+ }
144
+ --ctx->expected_responses_;
145
+ if (resp.ctx.ec()) {
146
+ if (ctx->expected_responses_ > 0) {
147
+ // just ignore the response
148
+ return;
149
+ }
150
+ } else {
151
+ std::vector<lookup_in_replica_result::entry> entries{};
152
+ for (auto& field : resp.fields) {
153
+ lookup_in_replica_result::entry lookup_in_entry{};
154
+ lookup_in_entry.path = field.path;
155
+ lookup_in_entry.value = field.value;
156
+ lookup_in_entry.exists = field.exists;
157
+ lookup_in_entry.original_index = field.original_index;
158
+ entries.emplace_back(lookup_in_entry);
159
+ }
160
+ ctx->result_.emplace_back(lookup_in_replica_result{ resp.cas, entries, resp.deleted, false /* active */ });
161
+ }
162
+ if (ctx->expected_responses_ == 0) {
163
+ ctx->done_ = true;
164
+ std::swap(local_handler, ctx->handler_);
165
+ }
166
+ }
167
+ if (local_handler) {
168
+ if (!ctx->result_.empty()) {
169
+ resp.ctx.override_ec({});
170
+ }
171
+ return local_handler(std::move(resp.ctx), std::move(ctx->result_));
172
+ }
173
+ });
174
+ });
175
+ }
176
+ } // namespace couchbase::core::impl
@@ -0,0 +1,80 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2020-Present Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #pragma once
19
+
20
+ #include <couchbase/lookup_in_all_replicas_options.hxx>
21
+ #include <couchbase/lookup_in_replica_result.hxx>
22
+
23
+ #include "core/document_id.hxx"
24
+ #include "core/error_context/key_value.hxx"
25
+ #include "core/utils/movable_function.hxx"
26
+
27
+ #include <vector>
28
+
29
+ namespace couchbase::core::impl
30
+ {
31
+
32
+ class lookup_in_all_replicas_request
33
+ {
34
+ public:
35
+ explicit lookup_in_all_replicas_request(std::string bucket_name,
36
+ std::string scope_name,
37
+ std::string collection_name,
38
+ std::string document_key,
39
+ std::vector<couchbase::core::impl::subdoc::command> specs,
40
+ std::optional<std::chrono::milliseconds> timeout)
41
+ : id_{ std::move(bucket_name), std::move(scope_name), std::move(collection_name), std::move(document_key) }
42
+ , specs_{ std::move(specs) }
43
+ , timeout_{ timeout }
44
+ {
45
+ }
46
+
47
+ [[nodiscard]] const auto& id() const
48
+ {
49
+ return id_;
50
+ }
51
+
52
+ [[nodiscard]] const auto& specs() const
53
+ {
54
+ return specs_;
55
+ }
56
+
57
+ [[nodiscard]] const auto& timeout() const
58
+ {
59
+ return timeout_;
60
+ }
61
+
62
+ private:
63
+ core::document_id id_;
64
+ std::vector<couchbase::core::impl::subdoc::command> specs_;
65
+ std::optional<std::chrono::milliseconds> timeout_{};
66
+ };
67
+
68
+ using movable_lookup_in_all_replicas_handler =
69
+ utils::movable_function<void(couchbase::subdocument_error_context, lookup_in_all_replicas_result)>;
70
+
71
+ void
72
+ initiate_lookup_in_all_replicas_operation(std::shared_ptr<cluster> core,
73
+ const std::string& bucket_name,
74
+ const std::string& scope_name,
75
+ const std::string& collection_name,
76
+ std::string document_key,
77
+ const std::vector<subdoc::command>& specs,
78
+ std::optional<std::chrono::milliseconds> timeout,
79
+ movable_lookup_in_all_replicas_handler&& handler);
80
+ } // namespace couchbase::core::impl
@@ -0,0 +1,167 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2020-Present Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include "lookup_in_any_replica.hxx"
19
+ #include "lookup_in_replica.hxx"
20
+
21
+ #include "core/cluster.hxx"
22
+ #include "core/error_context/key_value.hxx"
23
+ #include "core/operations/document_lookup_in.hxx"
24
+ #include "core/topology/configuration.hxx"
25
+
26
+ namespace couchbase::core::impl
27
+ {
28
+ void
29
+ initiate_lookup_in_any_replica_operation(std::shared_ptr<cluster> core,
30
+ const std::string& bucket_name,
31
+ const std::string& scope_name,
32
+ const std::string& collection_name,
33
+ std::string document_key,
34
+ const std::vector<subdoc::command>& specs,
35
+ lookup_in_any_replica_options::built options,
36
+ lookup_in_any_replica_handler&& handler)
37
+ {
38
+ return initiate_lookup_in_any_replica_operation(std::move(core),
39
+ bucket_name,
40
+ scope_name,
41
+ collection_name,
42
+ std::move(document_key),
43
+ specs,
44
+ options.timeout,
45
+ movable_lookup_in_any_replica_handler{ std::move(handler) });
46
+ }
47
+
48
+ void
49
+ initiate_lookup_in_any_replica_operation(std::shared_ptr<cluster> core,
50
+ const std::string& bucket_name,
51
+ const std::string& scope_name,
52
+ const std::string& collection_name,
53
+ std::string document_key,
54
+ const std::vector<subdoc::command>& specs,
55
+ std::optional<std::chrono::milliseconds> timeout,
56
+ movable_lookup_in_any_replica_handler&& handler)
57
+ {
58
+ auto request = std::make_shared<couchbase::core::impl::lookup_in_any_replica_request>(
59
+ bucket_name, scope_name, collection_name, std::move(document_key), specs, timeout);
60
+ core->with_bucket_configuration(
61
+ bucket_name,
62
+ [core, r = std::move(request), h = std::move(handler)](std::error_code ec, const core::topology::configuration& config) mutable {
63
+ if (!config.supports_subdoc_read_replica()) {
64
+ ec = errc::common::feature_not_available;
65
+ }
66
+ if (r->specs().size() > 16) {
67
+ ec = errc::common::invalid_argument;
68
+ }
69
+ if (ec) {
70
+ std::optional<std::string> first_error_path{};
71
+ std::optional<std::size_t> first_error_index{};
72
+ return h(
73
+ make_subdocument_error_context(make_key_value_error_context(ec, r->id()), ec, first_error_path, first_error_index, false),
74
+ lookup_in_replica_result{});
75
+ }
76
+ struct replica_context {
77
+ replica_context(movable_lookup_in_any_replica_handler handler, std::uint32_t expected_responses)
78
+ : handler_(std::move(handler))
79
+ , expected_responses_(expected_responses)
80
+ {
81
+ }
82
+
83
+ movable_lookup_in_any_replica_handler handler_;
84
+ std::uint32_t expected_responses_;
85
+ bool done_{ false };
86
+ std::mutex mutex_{};
87
+ };
88
+ auto ctx = std::make_shared<replica_context>(std::move(h), config.num_replicas.value_or(0U) + 1U);
89
+
90
+ for (std::size_t idx = 1U; idx <= config.num_replicas.value_or(0U); ++idx) {
91
+ document_id replica_id{ r->id() };
92
+ replica_id.node_index(idx);
93
+ core->execute(impl::lookup_in_replica_request{ std::move(replica_id), r->specs(), r->timeout() },
94
+ [ctx](impl::lookup_in_replica_response&& resp) {
95
+ movable_lookup_in_any_replica_handler local_handler;
96
+ {
97
+ std::scoped_lock lock(ctx->mutex_);
98
+ if (ctx->done_) {
99
+ return;
100
+ }
101
+ --ctx->expected_responses_;
102
+ if (resp.ctx.ec()) {
103
+ if (ctx->expected_responses_ > 0) {
104
+ // just ignore the response
105
+ return;
106
+ }
107
+ // consider document irretrievable and give up
108
+ resp.ctx.override_ec(errc::key_value::document_irretrievable);
109
+ }
110
+ ctx->done_ = true;
111
+ std::swap(local_handler, ctx->handler_);
112
+ }
113
+ if (local_handler) {
114
+ std::vector<lookup_in_replica_result::entry> entries;
115
+ for (auto& field : resp.fields) {
116
+ lookup_in_replica_result::entry entry{};
117
+ entry.path = field.path;
118
+ entry.original_index = field.original_index;
119
+ entry.exists = field.exists;
120
+ entry.value = field.value;
121
+ entries.emplace_back(entry);
122
+ }
123
+ return local_handler(std::move(resp.ctx),
124
+ lookup_in_replica_result{ resp.cas, entries, resp.deleted, true /* replica */ });
125
+ }
126
+ });
127
+ }
128
+
129
+ core::operations::lookup_in_request active{ document_id{ r->id() } };
130
+ active.specs = r->specs();
131
+ active.timeout = r->timeout();
132
+ core->execute(active, [ctx](core::operations::lookup_in_response&& resp) {
133
+ movable_lookup_in_any_replica_handler local_handler{};
134
+ {
135
+ std::scoped_lock lock(ctx->mutex_);
136
+ if (ctx->done_) {
137
+ return;
138
+ }
139
+ --ctx->expected_responses_;
140
+ if (resp.ctx.ec()) {
141
+ if (ctx->expected_responses_ > 0) {
142
+ // just ignore the response
143
+ return;
144
+ }
145
+ // consider document irretrievable and give up
146
+ resp.ctx.override_ec(errc::key_value::document_irretrievable);
147
+ }
148
+ ctx->done_ = true;
149
+ std::swap(local_handler, ctx->handler_);
150
+ }
151
+ if (local_handler) {
152
+ std::vector<lookup_in_replica_result::entry> entries;
153
+ for (auto& field : resp.fields) {
154
+ lookup_in_replica_result::entry entry{};
155
+ entry.path = field.path;
156
+ entry.original_index = field.original_index;
157
+ entry.exists = field.exists;
158
+ entry.value = field.value;
159
+ entries.emplace_back(entry);
160
+ }
161
+ return local_handler(std::move(resp.ctx),
162
+ lookup_in_replica_result{ resp.cas, entries, resp.deleted, false /* active */ });
163
+ }
164
+ });
165
+ });
166
+ }
167
+ } // namespace couchbase::core::impl
@@ -0,0 +1,75 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2020-Present Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #pragma once
19
+
20
+ #include <couchbase/lookup_in_any_replica_options.hxx>
21
+ #include <couchbase/lookup_in_replica_result.hxx>
22
+
23
+ #include "core/document_id.hxx"
24
+ #include "core/utils/movable_function.hxx"
25
+
26
+ namespace couchbase::core::impl
27
+ {
28
+ class lookup_in_any_replica_request
29
+ {
30
+ public:
31
+ explicit lookup_in_any_replica_request(std::string bucket_name,
32
+ std::string scope_name,
33
+ std::string collection_name,
34
+ std::string document_key,
35
+ std::vector<couchbase::core::impl::subdoc::command> specs,
36
+ std::optional<std::chrono::milliseconds> timeout)
37
+ : id_{ std::move(bucket_name), std::move(scope_name), std::move(collection_name), std::move(document_key) }
38
+ , specs_{ std::move(specs) }
39
+ , timeout_{ timeout }
40
+ {
41
+ }
42
+
43
+ [[nodiscard]] const auto& id() const
44
+ {
45
+ return id_;
46
+ }
47
+
48
+ [[nodiscard]] const auto& specs() const
49
+ {
50
+ return specs_;
51
+ }
52
+
53
+ [[nodiscard]] const auto& timeout() const
54
+ {
55
+ return timeout_;
56
+ }
57
+
58
+ private:
59
+ core::document_id id_;
60
+ std::vector<couchbase::core::impl::subdoc::command> specs_;
61
+ std::optional<std::chrono::milliseconds> timeout_{};
62
+ };
63
+
64
+ using movable_lookup_in_any_replica_handler = utils::movable_function<void(couchbase::subdocument_error_context, lookup_in_replica_result)>;
65
+
66
+ void
67
+ initiate_lookup_in_any_replica_operation(std::shared_ptr<cluster> core,
68
+ const std::string& bucket_name,
69
+ const std::string& scope_name,
70
+ const std::string& collection_name,
71
+ std::string document_key,
72
+ const std::vector<subdoc::command>& specs,
73
+ std::optional<std::chrono::milliseconds> timeout,
74
+ movable_lookup_in_any_replica_handler&& handler);
75
+ } // namespace couchbase::core::impl