couchbase 4.2.6 → 4.2.7

Sign up to get free protection for your applications and to get access to all the features.
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