couchbase 4.2.6 → 4.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/deps/couchbase-cxx-client/.github/workflows/windows.yml +0 -3
  2. package/deps/couchbase-cxx-client/CMakeLists.txt +4 -0
  3. package/deps/couchbase-cxx-client/bin/build-tests.rb +1 -1
  4. package/deps/couchbase-cxx-client/core/impl/lookup_in.cxx +1 -0
  5. package/deps/couchbase-cxx-client/core/impl/lookup_in_all_replicas.cxx +176 -0
  6. package/deps/couchbase-cxx-client/core/impl/lookup_in_all_replicas.hxx +80 -0
  7. package/deps/couchbase-cxx-client/core/impl/lookup_in_any_replica.cxx +167 -0
  8. package/deps/couchbase-cxx-client/core/impl/lookup_in_any_replica.hxx +75 -0
  9. package/deps/couchbase-cxx-client/core/impl/lookup_in_replica.cxx +97 -0
  10. package/deps/couchbase-cxx-client/core/impl/lookup_in_replica.hxx +67 -0
  11. package/deps/couchbase-cxx-client/core/meta/features.hxx +13 -0
  12. package/deps/couchbase-cxx-client/core/operations/document_lookup_in_all_replicas.hxx +192 -0
  13. package/deps/couchbase-cxx-client/core/operations/document_lookup_in_any_replica.hxx +188 -0
  14. package/deps/couchbase-cxx-client/core/operations.hxx +2 -0
  15. package/deps/couchbase-cxx-client/core/protocol/cmd_hello.hxx +1 -0
  16. package/deps/couchbase-cxx-client/core/protocol/cmd_lookup_in_replica.cxx +107 -0
  17. package/deps/couchbase-cxx-client/core/protocol/cmd_lookup_in_replica.hxx +137 -0
  18. package/deps/couchbase-cxx-client/core/protocol/hello_feature.hxx +6 -0
  19. package/deps/couchbase-cxx-client/core/protocol/hello_feature_fmt.hxx +3 -0
  20. package/deps/couchbase-cxx-client/core/topology/capabilities.hxx +1 -0
  21. package/deps/couchbase-cxx-client/core/topology/capabilities_fmt.hxx +3 -0
  22. package/deps/couchbase-cxx-client/core/topology/configuration.hxx +5 -0
  23. package/deps/couchbase-cxx-client/core/topology/configuration_json.hxx +2 -1
  24. package/deps/couchbase-cxx-client/couchbase/collection.hxx +111 -0
  25. package/deps/couchbase-cxx-client/couchbase/get_and_lock_options.hxx +2 -2
  26. package/deps/couchbase-cxx-client/couchbase/get_and_touch_options.hxx +2 -2
  27. package/deps/couchbase-cxx-client/couchbase/get_options.hxx +2 -2
  28. package/deps/couchbase-cxx-client/couchbase/insert_options.hxx +3 -3
  29. package/deps/couchbase-cxx-client/couchbase/lookup_in_all_replicas_options.hxx +109 -0
  30. package/deps/couchbase-cxx-client/couchbase/lookup_in_any_replica_options.hxx +101 -0
  31. package/deps/couchbase-cxx-client/couchbase/lookup_in_options.hxx +2 -2
  32. package/deps/couchbase-cxx-client/couchbase/lookup_in_replica_result.hxx +74 -0
  33. package/deps/couchbase-cxx-client/couchbase/lookup_in_result.hxx +26 -0
  34. package/deps/couchbase-cxx-client/couchbase/mutate_in_options.hxx +2 -2
  35. package/deps/couchbase-cxx-client/couchbase/remove_options.hxx +2 -2
  36. package/deps/couchbase-cxx-client/couchbase/replace_options.hxx +3 -3
  37. package/deps/couchbase-cxx-client/couchbase/touch_options.hxx +2 -2
  38. package/deps/couchbase-cxx-client/couchbase/unlock_options.hxx +2 -2
  39. package/deps/couchbase-cxx-client/couchbase/upsert_options.hxx +3 -3
  40. package/deps/couchbase-cxx-client/test/test_integration_subdoc.cxx +655 -0
  41. package/dist/binding.d.ts +45 -0
  42. package/dist/collection.d.ts +53 -1
  43. package/dist/collection.js +139 -1
  44. package/dist/crudoptypes.d.ts +24 -0
  45. package/dist/crudoptypes.js +14 -1
  46. package/package.json +13 -13
  47. package/src/connection.cpp +4 -0
  48. package/src/connection.hpp +2 -0
  49. package/src/connection_autogen.cpp +28 -0
  50. package/src/jstocbpp_autogen.hpp +262 -0
@@ -0,0 +1,67 @@
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 "core/error_context/key_value.hxx"
21
+ #include "core/impl/subdoc/command.hxx"
22
+ #include "core/io/mcbp_context.hxx"
23
+ #include "core/io/retry_context.hxx"
24
+ #include "core/protocol/client_request.hxx"
25
+ #include "core/protocol/cmd_lookup_in_replica.hxx"
26
+ #include "core/public_fwd.hxx"
27
+ #include "core/timeout_defaults.hxx"
28
+
29
+ #include <couchbase/lookup_in_result.hxx>
30
+ #include <couchbase/subdocument_error_context.hxx>
31
+
32
+ namespace couchbase::core::impl
33
+ {
34
+ struct lookup_in_replica_response {
35
+ struct entry {
36
+ std::string path;
37
+ couchbase::codec::binary value;
38
+ std::size_t original_index;
39
+ bool exists;
40
+ protocol::subdoc_opcode opcode;
41
+ key_value_status_code status;
42
+ std::error_code ec{};
43
+ };
44
+ subdocument_error_context ctx{};
45
+ couchbase::cas cas{};
46
+ std::vector<entry> fields{};
47
+ bool deleted{ false };
48
+ };
49
+
50
+ struct lookup_in_replica_request {
51
+ using response_type = lookup_in_replica_response;
52
+ using encoded_request_type = protocol::client_request<protocol::lookup_in_replica_request_body>;
53
+ using encoded_response_type = protocol::client_response<protocol::lookup_in_replica_response_body>;
54
+
55
+ document_id id;
56
+ std::vector<couchbase::core::impl::subdoc::command> specs{};
57
+ std::optional<std::chrono::milliseconds> timeout{};
58
+ std::shared_ptr<couchbase::tracing::request_span> parent_span{ nullptr };
59
+ std::uint16_t partition{};
60
+ std::uint32_t opaque{};
61
+ io::retry_context<false> retries{};
62
+
63
+ [[nodiscard]] std::error_code encode_to(encoded_request_type& encoded, mcbp_context&& context);
64
+
65
+ [[nodiscard]] lookup_in_replica_response make_response(key_value_error_context&& ctx, const encoded_response_type& encoded) const;
66
+ };
67
+ } // namespace couchbase::core::impl
@@ -41,3 +41,16 @@
41
41
  * couchbase::core::range_scan_orchestrator and relevant options in the core API
42
42
  */
43
43
  #define COUCHBASE_CXX_CLIENT_CORE_HAS_RANGE_SCAN 1
44
+
45
+ /**
46
+ * Query with reads from replica is available:
47
+ * - use_replica field in couchbase::core::operations::query_request
48
+ * - couchbase::query_options::use_replica()
49
+ */
50
+ #define COUCHBASE_CXX_CLIENT_QUERY_READ_FROM_REPLICA 1
51
+
52
+ /**
53
+ * Subdoc read from replica is available in the core
54
+ * couchbase::core::lookup_in_replica support
55
+ */
56
+ #define COUCHBASE_CXX_CLIENT_CORE_HAS_SUBDOC_READ_REPLICA 1
@@ -0,0 +1,192 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2020-2021 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 "core/error_context/key_value.hxx"
21
+ #include "core/impl/lookup_in_replica.hxx"
22
+ #include "core/impl/subdoc/command.hxx"
23
+ #include "core/operations/document_lookup_in.hxx"
24
+ #include "core/operations/operation_traits.hxx"
25
+ #include "core/utils/movable_function.hxx"
26
+ #include "couchbase/codec/encoded_value.hxx"
27
+ #include "couchbase/error_codes.hxx"
28
+
29
+ #include <functional>
30
+ #include <memory>
31
+ #include <mutex>
32
+
33
+ namespace couchbase::core::operations
34
+ {
35
+ struct lookup_in_all_replicas_response {
36
+ struct entry {
37
+ struct lookup_in_entry {
38
+ std::string path;
39
+ codec::binary value;
40
+ std::size_t original_index;
41
+ bool exists;
42
+ protocol::subdoc_opcode opcode;
43
+ key_value_status_code status;
44
+ std::error_code ec{};
45
+ };
46
+ std::vector<lookup_in_entry> fields{};
47
+ couchbase::cas cas{};
48
+ bool deleted{ false };
49
+ bool is_replica{ true };
50
+ };
51
+ subdocument_error_context ctx{};
52
+ std::vector<entry> entries{};
53
+ };
54
+
55
+ struct lookup_in_all_replicas_request {
56
+ using response_type = lookup_in_all_replicas_response;
57
+ using encoded_request_type = core::protocol::client_request<core::protocol::lookup_in_replica_request_body>;
58
+ using encoded_response_type = core::protocol::client_response<core::protocol::lookup_in_replica_response_body>;
59
+
60
+ core::document_id id;
61
+ std::vector<couchbase::core::impl::subdoc::command> specs{};
62
+ std::optional<std::chrono::milliseconds> timeout{};
63
+ std::shared_ptr<couchbase::tracing::request_span> parent_span{ nullptr };
64
+
65
+ template<typename Core, typename Handler>
66
+ void execute(Core core, Handler handler)
67
+ {
68
+ core->with_bucket_configuration(
69
+ id.bucket(),
70
+ [core, id = id, timeout = timeout, specs = specs, parent_span = parent_span, h = std::forward<Handler>(handler)](
71
+ std::error_code ec, const topology::configuration& config) mutable {
72
+ if (!config.supports_subdoc_read_replica()) {
73
+ ec = errc::common::feature_not_available;
74
+ }
75
+
76
+ if (ec) {
77
+ std::optional<std::string> first_error_path{};
78
+ std::optional<std::size_t> first_error_index{};
79
+ return h(response_type{
80
+ make_subdocument_error_context(make_key_value_error_context(ec, id), ec, first_error_path, first_error_index, false) });
81
+ }
82
+ using handler_type = utils::movable_function<void(response_type)>;
83
+
84
+ struct replica_context {
85
+ replica_context(handler_type handler, std::uint32_t expected_responses)
86
+ : handler_(std::move(handler))
87
+ , expected_responses_(expected_responses)
88
+ {
89
+ }
90
+
91
+ handler_type handler_;
92
+ std::uint32_t expected_responses_;
93
+ bool done_{ false };
94
+ std::mutex mutex_{};
95
+ std::vector<lookup_in_all_replicas_response::entry> result_{};
96
+ };
97
+ auto ctx = std::make_shared<replica_context>(std::move(h), config.num_replicas.value_or(0U) + 1U);
98
+
99
+ for (std::size_t idx = 1U; idx <= config.num_replicas.value_or(0U); ++idx) {
100
+ document_id replica_id{ id };
101
+ replica_id.node_index(idx);
102
+ core->execute(impl::lookup_in_replica_request{ std::move(replica_id), specs, timeout, parent_span },
103
+ [ctx](impl::lookup_in_replica_response&& resp) {
104
+ handler_type local_handler{};
105
+ {
106
+ std::scoped_lock lock(ctx->mutex_);
107
+ if (ctx->done_) {
108
+ return;
109
+ }
110
+ --ctx->expected_responses_;
111
+ if (resp.ctx.ec()) {
112
+ if (ctx->expected_responses_ > 0) {
113
+ // just ignore the response
114
+ return;
115
+ }
116
+ } else {
117
+ lookup_in_all_replicas_response::entry top_entry{};
118
+ top_entry.cas = resp.cas;
119
+ top_entry.deleted = resp.deleted;
120
+ top_entry.is_replica = true;
121
+ for (auto& field : resp.fields) {
122
+ lookup_in_all_replicas_response::entry::lookup_in_entry lookup_in_entry{};
123
+ lookup_in_entry.path = field.path;
124
+ lookup_in_entry.value = field.value;
125
+ lookup_in_entry.status = field.status;
126
+ lookup_in_entry.ec = field.ec;
127
+ lookup_in_entry.exists = field.exists;
128
+ lookup_in_entry.original_index = field.original_index;
129
+ lookup_in_entry.opcode = field.opcode;
130
+ top_entry.fields.emplace_back(lookup_in_entry);
131
+ }
132
+ ctx->result_.emplace_back(lookup_in_all_replicas_response::entry{ top_entry });
133
+ }
134
+ if (ctx->expected_responses_ == 0) {
135
+ ctx->done_ = true;
136
+ std::swap(local_handler, ctx->handler_);
137
+ }
138
+ }
139
+ if (local_handler) {
140
+ return local_handler({ std::move(resp.ctx), std::move(ctx->result_) });
141
+ }
142
+ });
143
+ }
144
+
145
+ core->execute(lookup_in_request{ document_id{ id }, {}, {}, false, specs, timeout }, [ctx](lookup_in_response&& resp) {
146
+ handler_type local_handler{};
147
+ {
148
+ std::scoped_lock lock(ctx->mutex_);
149
+ if (ctx->done_) {
150
+ return;
151
+ }
152
+ --ctx->expected_responses_;
153
+ if (resp.ctx.ec()) {
154
+ if (ctx->expected_responses_ > 0) {
155
+ // just ignore the response
156
+ return;
157
+ }
158
+ } else {
159
+ lookup_in_all_replicas_response::entry top_entry{};
160
+ top_entry.cas = resp.cas;
161
+ top_entry.deleted = resp.deleted;
162
+ top_entry.is_replica = false;
163
+ for (auto& field : resp.fields) {
164
+ lookup_in_all_replicas_response::entry::lookup_in_entry lookup_in_entry{};
165
+ lookup_in_entry.path = field.path;
166
+ lookup_in_entry.value = field.value;
167
+ lookup_in_entry.status = field.status;
168
+ lookup_in_entry.ec = field.ec;
169
+ lookup_in_entry.exists = field.exists;
170
+ lookup_in_entry.original_index = field.original_index;
171
+ lookup_in_entry.opcode = field.opcode;
172
+ top_entry.fields.emplace_back(lookup_in_entry);
173
+ }
174
+ ctx->result_.emplace_back(lookup_in_all_replicas_response::entry{ top_entry });
175
+ }
176
+ if (ctx->expected_responses_ == 0) {
177
+ ctx->done_ = true;
178
+ std::swap(local_handler, ctx->handler_);
179
+ }
180
+ }
181
+ if (local_handler) {
182
+ return local_handler({ std::move(resp.ctx), std::move(ctx->result_) });
183
+ }
184
+ });
185
+ });
186
+ }
187
+ };
188
+
189
+ template<>
190
+ struct is_compound_operation<lookup_in_all_replicas_request> : public std::true_type {
191
+ };
192
+ } // namespace couchbase::core::operations
@@ -0,0 +1,188 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2020-2021 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 "core/error_context/key_value.hxx"
21
+ #include "core/impl/lookup_in_replica.hxx"
22
+ #include "core/impl/subdoc/command.hxx"
23
+ #include "core/operations/document_lookup_in.hxx"
24
+ #include "core/operations/operation_traits.hxx"
25
+ #include "core/utils/movable_function.hxx"
26
+ #include "couchbase/codec/encoded_value.hxx"
27
+ #include "couchbase/error_codes.hxx"
28
+
29
+ #include <functional>
30
+ #include <memory>
31
+ #include <mutex>
32
+
33
+ namespace couchbase::core::operations
34
+ {
35
+ struct lookup_in_any_replica_response {
36
+ struct entry {
37
+ std::string path;
38
+ codec::binary value;
39
+ std::size_t original_index;
40
+ bool exists;
41
+ protocol::subdoc_opcode opcode;
42
+ key_value_status_code status;
43
+ std::error_code ec{};
44
+ };
45
+ subdocument_error_context ctx{};
46
+ couchbase::cas cas{};
47
+ std::vector<entry> fields{};
48
+ bool deleted{ false };
49
+ bool is_replica{ true };
50
+ };
51
+
52
+ struct lookup_in_any_replica_request {
53
+ using response_type = lookup_in_any_replica_response;
54
+ using encoded_request_type = core::protocol::client_request<core::protocol::lookup_in_replica_request_body>;
55
+ using encoded_response_type = core::protocol::client_response<core::protocol::lookup_in_replica_response_body>;
56
+
57
+ core::document_id id;
58
+ std::vector<couchbase::core::impl::subdoc::command> specs{};
59
+ std::optional<std::chrono::milliseconds> timeout{};
60
+ std::shared_ptr<couchbase::tracing::request_span> parent_span{ nullptr };
61
+
62
+ template<typename Core, typename Handler>
63
+ void execute(Core core, Handler handler)
64
+ {
65
+ core->with_bucket_configuration(
66
+ id.bucket(),
67
+ [core, id = id, timeout = timeout, specs = specs, parent_span = parent_span, h = std::forward<Handler>(handler)](
68
+ std::error_code ec, const topology::configuration& config) mutable {
69
+ if (!config.supports_subdoc_read_replica()) {
70
+ ec = errc::common::feature_not_available;
71
+ }
72
+ if (specs.size() > 16) {
73
+ ec = errc::common::invalid_argument;
74
+ }
75
+
76
+ if (ec) {
77
+ std::optional<std::string> first_error_path{};
78
+ std::optional<std::size_t> first_error_index{};
79
+ return h(response_type{
80
+ make_subdocument_error_context(make_key_value_error_context(ec, id), ec, first_error_path, first_error_index, false) });
81
+ }
82
+ using handler_type = utils::movable_function<void(response_type)>;
83
+
84
+ struct replica_context {
85
+ replica_context(handler_type&& handler, std::uint32_t expected_responses)
86
+ : handler_(std::move(handler))
87
+ , expected_responses_(expected_responses)
88
+ {
89
+ }
90
+
91
+ handler_type handler_;
92
+ std::uint32_t expected_responses_;
93
+ bool done_{ false };
94
+ std::mutex mutex_{};
95
+ };
96
+ auto ctx = std::make_shared<replica_context>(std::move(h), config.num_replicas.value_or(0U) + 1U);
97
+
98
+ for (std::size_t idx = 1U; idx <= config.num_replicas.value_or(0U); ++idx) {
99
+ document_id replica_id{ id };
100
+ replica_id.node_index(idx);
101
+ core->execute(impl::lookup_in_replica_request{ std::move(replica_id), specs, timeout, parent_span },
102
+ [ctx](impl::lookup_in_replica_response&& resp) {
103
+ handler_type local_handler;
104
+ {
105
+ std::scoped_lock lock(ctx->mutex_);
106
+ if (ctx->done_) {
107
+ return;
108
+ }
109
+ --ctx->expected_responses_;
110
+ if (resp.ctx.ec()) {
111
+ if (ctx->expected_responses_ > 0) {
112
+ // just ignore the response
113
+ return;
114
+ }
115
+ // consider document irretrievable and give up
116
+ resp.ctx.override_ec(errc::key_value::document_irretrievable);
117
+ }
118
+ ctx->done_ = true;
119
+ std::swap(local_handler, ctx->handler_);
120
+ }
121
+ if (local_handler) {
122
+ response_type res{};
123
+ res.ctx = resp.ctx;
124
+ res.cas = resp.cas;
125
+ res.deleted = resp.deleted;
126
+ res.is_replica = true;
127
+ for (auto& field : resp.fields) {
128
+ auto lookup_in_entry = lookup_in_any_replica_response::entry{};
129
+ lookup_in_entry.path = field.path;
130
+ lookup_in_entry.value = field.value;
131
+ lookup_in_entry.status = field.status;
132
+ lookup_in_entry.ec = field.ec;
133
+ lookup_in_entry.exists = field.exists;
134
+ lookup_in_entry.original_index = field.original_index;
135
+ lookup_in_entry.opcode = field.opcode;
136
+ res.fields.emplace_back(lookup_in_entry);
137
+ }
138
+ return local_handler(res);
139
+ }
140
+ });
141
+ }
142
+ core->execute(lookup_in_request{ id, {}, {}, false, specs, timeout }, [ctx](lookup_in_response&& resp) {
143
+ handler_type local_handler{};
144
+ {
145
+ std::scoped_lock lock(ctx->mutex_);
146
+ if (ctx->done_) {
147
+ return;
148
+ }
149
+ --ctx->expected_responses_;
150
+ if (resp.ctx.ec()) {
151
+ if (ctx->expected_responses_ > 0) {
152
+ // just ignore the response
153
+ return;
154
+ }
155
+ // consider document irretrievable and give up
156
+ resp.ctx.override_ec(errc::key_value::document_irretrievable);
157
+ }
158
+ ctx->done_ = true;
159
+ std::swap(local_handler, ctx->handler_);
160
+ }
161
+ if (local_handler) {
162
+ auto res = response_type{};
163
+ res.ctx = resp.ctx;
164
+ res.cas = resp.cas;
165
+ res.deleted = resp.deleted;
166
+ res.is_replica = false;
167
+ for (auto& field : resp.fields) {
168
+ auto lookup_in_entry = lookup_in_any_replica_response::entry{};
169
+ lookup_in_entry.path = field.path;
170
+ lookup_in_entry.value = field.value;
171
+ lookup_in_entry.status = field.status;
172
+ lookup_in_entry.ec = field.ec;
173
+ lookup_in_entry.exists = field.exists;
174
+ lookup_in_entry.original_index = field.original_index;
175
+ lookup_in_entry.opcode = field.opcode;
176
+ res.fields.emplace_back(lookup_in_entry);
177
+ }
178
+ return local_handler(res);
179
+ }
180
+ });
181
+ });
182
+ }
183
+ };
184
+
185
+ template<>
186
+ struct is_compound_operation<lookup_in_any_replica_request> : public std::true_type {
187
+ };
188
+ } // namespace couchbase::core::operations
@@ -30,6 +30,8 @@
30
30
  #include "core/operations/document_increment.hxx"
31
31
  #include "core/operations/document_insert.hxx"
32
32
  #include "core/operations/document_lookup_in.hxx"
33
+ #include "core/operations/document_lookup_in_all_replicas.hxx"
34
+ #include "core/operations/document_lookup_in_any_replica.hxx"
33
35
  #include "core/operations/document_mutate_in.hxx"
34
36
  #include "core/operations/document_prepend.hxx"
35
37
  #include "core/operations/document_query.hxx"
@@ -71,6 +71,7 @@ class hello_request_body
71
71
  hello_feature::collections,
72
72
  hello_feature::subdoc_create_as_deleted,
73
73
  hello_feature::preserve_ttl,
74
+ hello_feature::subdoc_replica_read,
74
75
  };
75
76
  std::vector<std::byte> value_;
76
77
 
@@ -0,0 +1,107 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2020-2021 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 "cmd_lookup_in_replica.hxx"
19
+
20
+ #include "core/utils/byteswap.hxx"
21
+ #include "core/utils/unsigned_leb128.hxx"
22
+
23
+ #include <cstring>
24
+ #include <gsl/assert>
25
+
26
+ namespace couchbase::core::protocol
27
+ {
28
+ bool
29
+ lookup_in_replica_response_body::parse(key_value_status_code status,
30
+ const header_buffer& header,
31
+ std::uint8_t framing_extras_size,
32
+ std::uint16_t key_size,
33
+ std::uint8_t extras_size,
34
+ const std::vector<std::byte>& body,
35
+ const cmd_info& /* info */)
36
+ {
37
+ Expects(header[1] == static_cast<std::byte>(opcode));
38
+ if (status == key_value_status_code::success || status == key_value_status_code::subdoc_multi_path_failure ||
39
+ status == key_value_status_code::subdoc_success_deleted || status == key_value_status_code::subdoc_multi_path_failure_deleted) {
40
+ using offset_type = std::vector<std::byte>::difference_type;
41
+ offset_type offset = framing_extras_size + key_size + extras_size;
42
+ fields_.reserve(16); /* we won't have more than 16 entries anyway */
43
+ while (static_cast<std::size_t>(offset) < body.size()) {
44
+ lookup_in_field field;
45
+
46
+ std::uint16_t entry_status = 0;
47
+ memcpy(&entry_status, body.data() + offset, sizeof(entry_status));
48
+ entry_status = utils::byte_swap(entry_status);
49
+ Expects(is_valid_status(entry_status));
50
+ field.status = static_cast<key_value_status_code>(entry_status);
51
+ offset += static_cast<offset_type>(sizeof(entry_status));
52
+
53
+ std::uint32_t entry_size = 0;
54
+ memcpy(&entry_size, body.data() + offset, sizeof(entry_size));
55
+ entry_size = utils::byte_swap(entry_size);
56
+ Expects(entry_size < 20 * 1024 * 1024);
57
+ offset += static_cast<offset_type>(sizeof(entry_size));
58
+
59
+ field.value.resize(entry_size);
60
+ memcpy(field.value.data(), body.data() + offset, entry_size);
61
+ offset += static_cast<offset_type>(entry_size);
62
+
63
+ fields_.emplace_back(field);
64
+ }
65
+ return true;
66
+ }
67
+ return false;
68
+ }
69
+
70
+ void
71
+ lookup_in_replica_request_body::id(const document_id& id)
72
+ {
73
+ key_ = make_protocol_key(id);
74
+ }
75
+
76
+ void
77
+ lookup_in_replica_request_body::fill_extras()
78
+ {
79
+ if (flags_ != 0) {
80
+ extras_.resize(sizeof(flags_));
81
+ extras_[0] = std::byte{ flags_ };
82
+ }
83
+ }
84
+
85
+ void
86
+ lookup_in_replica_request_body::fill_value()
87
+ {
88
+ size_t value_size = 0;
89
+ for (const auto& spec : specs_) {
90
+ value_size += sizeof(spec.opcode_) + sizeof(std::uint8_t) + sizeof(std::uint16_t) + spec.path_.size();
91
+ }
92
+ Expects(value_size > 0);
93
+ value_.resize(value_size);
94
+ std::vector<std::byte>::size_type offset = 0;
95
+ for (const auto& spec : specs_) {
96
+ value_[offset] = static_cast<std::byte>(spec.opcode_);
97
+ ++offset;
98
+ value_[offset] = spec.flags_;
99
+ ++offset;
100
+ std::uint16_t path_size = utils::byte_swap(gsl::narrow_cast<std::uint16_t>(spec.path_.size()));
101
+ std::memcpy(value_.data() + offset, &path_size, sizeof(path_size));
102
+ offset += sizeof(path_size);
103
+ std::memcpy(value_.data() + offset, spec.path_.data(), spec.path_.size());
104
+ offset += spec.path_.size();
105
+ }
106
+ }
107
+ } // namespace couchbase::core::protocol