couchbase 3.5.7 → 3.6.0

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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/ext/cache/extconf_include.rb +3 -3
  4. data/ext/cache/mozilla-ca-bundle.crt +3 -165
  5. data/ext/cache/mozilla-ca-bundle.sha256 +1 -1
  6. data/ext/cache/snappy/{585305c8dbb8f762f2c2e17f937f1cf3ac6cbc9c → 3cde171792b3607f75c14e5011eaf69da4857bd8}/snappy/CMakeLists.txt +14 -10
  7. data/ext/cache/snappy/{585305c8dbb8f762f2c2e17f937f1cf3ac6cbc9c → 3cde171792b3607f75c14e5011eaf69da4857bd8}/snappy/snappy.cc +7 -4
  8. data/ext/couchbase/CMakeLists.txt +12 -1
  9. data/ext/couchbase/cmake/Profiler.cmake +15 -0
  10. data/ext/couchbase/cmake/ThirdPartyDependencies.cmake +2 -2
  11. data/ext/couchbase/cmake/couchbase_cxx_client.pc.in +1 -1
  12. data/ext/couchbase/core/app_telemetry_address.cxx +55 -0
  13. data/ext/couchbase/core/app_telemetry_address.hxx +39 -0
  14. data/ext/couchbase/core/app_telemetry_meter.cxx +753 -0
  15. data/ext/couchbase/core/app_telemetry_meter.hxx +198 -0
  16. data/ext/couchbase/core/app_telemetry_reporter.cxx +895 -0
  17. data/ext/couchbase/core/app_telemetry_reporter.hxx +59 -0
  18. data/ext/couchbase/core/bucket.cxx +77 -35
  19. data/ext/couchbase/core/bucket.hxx +17 -10
  20. data/ext/couchbase/core/cluster.cxx +54 -16
  21. data/ext/couchbase/core/cluster_credentials.cxx +27 -0
  22. data/ext/couchbase/core/cluster_credentials.hxx +36 -0
  23. data/ext/couchbase/core/cluster_options.hxx +12 -0
  24. data/ext/couchbase/core/collections_component.cxx +7 -5
  25. data/ext/couchbase/core/http_component.cxx +6 -0
  26. data/ext/couchbase/core/impl/binary_collection.cxx +4 -0
  27. data/ext/couchbase/core/impl/bucket_manager.cxx +2 -0
  28. data/ext/couchbase/core/impl/cluster.cxx +9 -0
  29. data/ext/couchbase/core/impl/collection.cxx +2 -0
  30. data/ext/couchbase/core/impl/error.cxx +1 -0
  31. data/ext/couchbase/core/impl/logger.cxx +51 -0
  32. data/ext/couchbase/core/impl/replica_utils.cxx +1 -1
  33. data/ext/couchbase/core/impl/transaction_get_multi_replicas_from_preferred_server_group_spec.cxx +32 -0
  34. data/ext/couchbase/core/impl/transaction_get_multi_spec.cxx +30 -0
  35. data/ext/couchbase/core/impl/transaction_op_error_category.cxx +2 -0
  36. data/ext/couchbase/core/io/config_tracker.cxx +6 -6
  37. data/ext/couchbase/core/io/http_command.hxx +35 -11
  38. data/ext/couchbase/core/io/http_session.cxx +10 -0
  39. data/ext/couchbase/core/io/http_session.hxx +4 -0
  40. data/ext/couchbase/core/io/http_session_manager.hxx +83 -34
  41. data/ext/couchbase/core/io/mcbp_command.hxx +41 -2
  42. data/ext/couchbase/core/io/mcbp_session.cxx +52 -19
  43. data/ext/couchbase/core/io/mcbp_session.hxx +3 -0
  44. data/ext/couchbase/core/logger/logger.cxx +46 -0
  45. data/ext/couchbase/core/logger/logger.hxx +41 -1
  46. data/ext/couchbase/core/management/bucket_settings.hxx +1 -0
  47. data/ext/couchbase/core/management/bucket_settings_json.hxx +4 -0
  48. data/ext/couchbase/core/meta/features.hxx +32 -0
  49. data/ext/couchbase/core/operations/document_analytics.cxx +9 -9
  50. data/ext/couchbase/core/operations/document_append.cxx +1 -0
  51. data/ext/couchbase/core/operations/document_append.hxx +1 -0
  52. data/ext/couchbase/core/operations/document_get_all_replicas.hxx +10 -2
  53. data/ext/couchbase/core/operations/document_lookup_in.cxx +4 -0
  54. data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +14 -2
  55. data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +4 -0
  56. data/ext/couchbase/core/operations/document_mutate_in.cxx +4 -0
  57. data/ext/couchbase/core/operations/document_mutate_in.hxx +1 -0
  58. data/ext/couchbase/core/operations/document_prepend.cxx +1 -0
  59. data/ext/couchbase/core/operations/document_prepend.hxx +1 -0
  60. data/ext/couchbase/core/operations/document_query.cxx +12 -10
  61. data/ext/couchbase/core/operations/http_noop.cxx +1 -0
  62. data/ext/couchbase/core/operations/management/bucket_create.cxx +3 -0
  63. data/ext/couchbase/core/operations/management/bucket_update.cxx +3 -0
  64. data/ext/couchbase/core/origin.cxx +0 -5
  65. data/ext/couchbase/core/origin.hxx +2 -11
  66. data/ext/couchbase/core/platform/random.cc +6 -3
  67. data/ext/couchbase/core/platform/random.h +2 -2
  68. data/ext/couchbase/core/protocol/cmd_mutate_in.hxx +9 -0
  69. data/ext/couchbase/core/timeout_defaults.hxx +4 -0
  70. data/ext/couchbase/core/topology/configuration.cxx +10 -13
  71. data/ext/couchbase/core/topology/configuration.hxx +14 -15
  72. data/ext/couchbase/core/topology/configuration_json.hxx +6 -0
  73. data/ext/couchbase/core/transactions/async_attempt_context.hxx +22 -2
  74. data/ext/couchbase/core/transactions/attempt_context.hxx +25 -7
  75. data/ext/couchbase/core/transactions/attempt_context_impl.cxx +688 -238
  76. data/ext/couchbase/core/transactions/attempt_context_impl.hxx +91 -12
  77. data/ext/couchbase/core/transactions/exceptions.cxx +5 -0
  78. data/ext/couchbase/core/transactions/exceptions.hxx +20 -0
  79. data/ext/couchbase/core/transactions/exceptions_fmt.hxx +3 -0
  80. data/ext/couchbase/core/transactions/forward_compat.cxx +71 -6
  81. data/ext/couchbase/core/transactions/forward_compat.hxx +45 -59
  82. data/ext/couchbase/core/transactions/get_multi_orchestrator.cxx +616 -0
  83. data/ext/couchbase/core/transactions/get_multi_orchestrator.hxx +61 -0
  84. data/ext/couchbase/core/transactions/internal/doc_record.cxx +8 -0
  85. data/ext/couchbase/core/transactions/internal/doc_record.hxx +16 -5
  86. data/ext/couchbase/core/transactions/internal/exceptions_internal.hxx +12 -0
  87. data/ext/couchbase/core/transactions/internal/transaction_context.hxx +13 -0
  88. data/ext/couchbase/core/transactions/internal/transaction_fields.hxx +1 -0
  89. data/ext/couchbase/core/transactions/staged_mutation.cxx +277 -96
  90. data/ext/couchbase/core/transactions/staged_mutation.hxx +28 -76
  91. data/ext/couchbase/core/transactions/transaction_context.cxx +33 -0
  92. data/ext/couchbase/core/transactions/transaction_get_multi_mode.hxx +28 -0
  93. data/ext/couchbase/core/transactions/transaction_get_multi_replicas_from_preferred_server_group_mode.hxx +27 -0
  94. data/ext/couchbase/core/transactions/transaction_get_multi_replicas_from_preferred_server_group_result.hxx +71 -0
  95. data/ext/couchbase/core/transactions/transaction_get_multi_result.hxx +66 -0
  96. data/ext/couchbase/core/transactions/transaction_links.hxx +10 -0
  97. data/ext/couchbase/core/transactions/transactions.cxx +8 -3
  98. data/ext/couchbase/core/utils/connection_string.cxx +4 -0
  99. data/ext/couchbase/core/utils/url_codec.cxx +26 -0
  100. data/ext/couchbase/core/utils/url_codec.hxx +11 -0
  101. data/ext/couchbase/core/websocket_codec.cxx +647 -0
  102. data/ext/couchbase/core/websocket_codec.hxx +77 -0
  103. data/ext/couchbase/couchbase/analytics_options.hxx +70 -6
  104. data/ext/couchbase/couchbase/application_telemetry_options.hxx +124 -0
  105. data/ext/couchbase/couchbase/cluster_options.hxx +17 -0
  106. data/ext/couchbase/couchbase/error_codes.hxx +1 -0
  107. data/ext/couchbase/couchbase/logger.hxx +16 -0
  108. data/ext/couchbase/couchbase/management/bucket_settings.hxx +1 -0
  109. data/ext/couchbase/couchbase/query_options.hxx +70 -6
  110. data/ext/couchbase/couchbase/transactions/async_attempt_context.hxx +29 -5
  111. data/ext/couchbase/couchbase/transactions/attempt_context.hxx +24 -7
  112. data/ext/couchbase/couchbase/transactions/transaction_get_multi_mode.hxx +47 -0
  113. data/ext/couchbase/couchbase/transactions/transaction_get_multi_options.hxx +44 -0
  114. data/ext/couchbase/couchbase/transactions/transaction_get_multi_replicas_from_preferred_server_group_mode.hxx +46 -0
  115. data/ext/couchbase/couchbase/transactions/transaction_get_multi_replicas_from_preferred_server_group_options.hxx +48 -0
  116. data/ext/couchbase/couchbase/transactions/transaction_get_multi_replicas_from_preferred_server_group_result.hxx +109 -0
  117. data/ext/couchbase/couchbase/transactions/transaction_get_multi_replicas_from_preferred_server_group_spec.hxx +47 -0
  118. data/ext/couchbase/couchbase/transactions/transaction_get_multi_result.hxx +102 -0
  119. data/ext/couchbase/couchbase/transactions/transaction_get_multi_spec.hxx +45 -0
  120. data/ext/rcb_buckets.cxx +26 -0
  121. data/lib/active_support/cache/couchbase_store.rb +1 -1
  122. data/lib/couchbase/cluster.rb +1 -1
  123. data/lib/couchbase/collection.rb +1 -1
  124. data/lib/couchbase/collection_options.rb +2 -2
  125. data/lib/couchbase/management/analytics_index_manager.rb +4 -4
  126. data/lib/couchbase/management/bucket_manager.rb +8 -2
  127. data/lib/couchbase/protostellar/cluster.rb +2 -2
  128. data/lib/couchbase/protostellar/collection.rb +1 -1
  129. data/lib/couchbase/protostellar/management/collection_query_index_manager.rb +1 -1
  130. data/lib/couchbase/protostellar/request_generator/admin/bucket.rb +4 -4
  131. data/lib/couchbase/protostellar/request_generator/admin/collection.rb +6 -6
  132. data/lib/couchbase/protostellar/request_generator/admin/query.rb +13 -13
  133. data/lib/couchbase/protostellar/request_generator/kv.rb +25 -25
  134. data/lib/couchbase/protostellar/request_generator/query.rb +4 -4
  135. data/lib/couchbase/protostellar/request_generator/search.rb +25 -25
  136. data/lib/couchbase/protostellar/response_converter/search.rb +1 -1
  137. data/lib/couchbase/protostellar/retry/reason.rb +1 -1
  138. data/lib/couchbase/protostellar/timeouts.rb +1 -1
  139. data/lib/couchbase/scope.rb +1 -1
  140. data/lib/couchbase/transcoder_flags.rb +1 -1
  141. data/lib/couchbase/utils/stdlib_logger_adapter.rb +1 -1
  142. data/lib/couchbase/version.rb +1 -1
  143. metadata +47 -19
  144. /data/ext/cache/snappy/{585305c8dbb8f762f2c2e17f937f1cf3ac6cbc9c → 3cde171792b3607f75c14e5011eaf69da4857bd8}/snappy/COPYING +0 -0
  145. /data/ext/cache/snappy/{585305c8dbb8f762f2c2e17f937f1cf3ac6cbc9c → 3cde171792b3607f75c14e5011eaf69da4857bd8}/snappy/cmake/SnappyConfig.cmake.in +0 -0
  146. /data/ext/cache/snappy/{585305c8dbb8f762f2c2e17f937f1cf3ac6cbc9c → 3cde171792b3607f75c14e5011eaf69da4857bd8}/snappy/cmake/config.h.in +0 -0
  147. /data/ext/cache/snappy/{585305c8dbb8f762f2c2e17f937f1cf3ac6cbc9c → 3cde171792b3607f75c14e5011eaf69da4857bd8}/snappy/snappy-c.cc +0 -0
  148. /data/ext/cache/snappy/{585305c8dbb8f762f2c2e17f937f1cf3ac6cbc9c → 3cde171792b3607f75c14e5011eaf69da4857bd8}/snappy/snappy-c.h +0 -0
  149. /data/ext/cache/snappy/{585305c8dbb8f762f2c2e17f937f1cf3ac6cbc9c → 3cde171792b3607f75c14e5011eaf69da4857bd8}/snappy/snappy-internal.h +0 -0
  150. /data/ext/cache/snappy/{585305c8dbb8f762f2c2e17f937f1cf3ac6cbc9c → 3cde171792b3607f75c14e5011eaf69da4857bd8}/snappy/snappy-sinksource.cc +0 -0
  151. /data/ext/cache/snappy/{585305c8dbb8f762f2c2e17f937f1cf3ac6cbc9c → 3cde171792b3607f75c14e5011eaf69da4857bd8}/snappy/snappy-sinksource.h +0 -0
  152. /data/ext/cache/snappy/{585305c8dbb8f762f2c2e17f937f1cf3ac6cbc9c → 3cde171792b3607f75c14e5011eaf69da4857bd8}/snappy/snappy-stubs-internal.cc +0 -0
  153. /data/ext/cache/snappy/{585305c8dbb8f762f2c2e17f937f1cf3ac6cbc9c → 3cde171792b3607f75c14e5011eaf69da4857bd8}/snappy/snappy-stubs-internal.h +0 -0
  154. /data/ext/cache/snappy/{585305c8dbb8f762f2c2e17f937f1cf3ac6cbc9c → 3cde171792b3607f75c14e5011eaf69da4857bd8}/snappy/snappy-stubs-public.h.in +0 -0
  155. /data/ext/cache/snappy/{585305c8dbb8f762f2c2e17f937f1cf3ac6cbc9c → 3cde171792b3607f75c14e5011eaf69da4857bd8}/snappy/snappy.h +0 -0
@@ -25,6 +25,8 @@
25
25
 
26
26
  #pragma once
27
27
 
28
+ #include <functional>
29
+
28
30
  #include "level.hxx"
29
31
 
30
32
  #include <spdlog/fmt/bundled/core.h>
@@ -36,8 +38,17 @@
36
38
 
37
39
  namespace couchbase::core::logger
38
40
  {
41
+
39
42
  struct configuration;
40
43
 
44
+ struct log_location {
45
+ std::string file;
46
+ std::string function;
47
+ int line;
48
+ };
49
+
50
+ using log_callback = std::function<void(std::string_view, level, log_location)>;
51
+
41
52
  auto
42
53
  level_from_str(const std::string& str) -> level;
43
54
 
@@ -113,6 +124,12 @@ get() -> spdlog::logger*;
113
124
  void
114
125
  reset();
115
126
 
127
+ void
128
+ register_log_callback(log_callback callback);
129
+
130
+ void
131
+ unregister_log_callback();
132
+
116
133
  /**
117
134
  * Engines that create their own instances of an spdlog::logger should register the logger here to
118
135
  * ensure that the verbosity of the logger is updated when memcached receives a request to update
@@ -179,6 +196,13 @@ log(const char* file, int line, const char* function, level lvl, std::string_vie
179
196
 
180
197
  void
181
198
  log_protocol(const char* file, int line, const char* function, std::string_view msg);
199
+
200
+ void
201
+ log_custom_logger(const char* file,
202
+ int line,
203
+ const char* function,
204
+ level lvl,
205
+ std::string_view msg);
182
206
  } // namespace detail
183
207
 
184
208
  /**
@@ -199,6 +223,19 @@ log(const char* file,
199
223
  detail::log(file, line, function, lvl, fmt::format(msg, std::forward<Args>(args)...));
200
224
  }
201
225
 
226
+ template<typename... Args>
227
+ inline void
228
+ log_custom_logger(const char* file,
229
+ int line,
230
+ const char* function,
231
+ level lvl,
232
+ fmt::format_string<Args...> msg,
233
+ Args&&... args)
234
+ {
235
+ detail::log_custom_logger(
236
+ file, line, function, lvl, fmt::format(msg, std::forward<Args>(args)...));
237
+ }
238
+
202
239
  template<typename... Args>
203
240
  inline void
204
241
  log_protocol(const char* file,
@@ -228,7 +265,6 @@ shutdown();
228
265
  */
229
266
  auto
230
267
  is_initialized() -> bool;
231
-
232
268
  } // namespace couchbase::core::logger
233
269
 
234
270
  #if defined(__GNUC__) || defined(__clang__)
@@ -243,6 +279,8 @@ is_initialized() -> bool;
243
279
  */
244
280
  #define COUCHBASE_LOG(file, line, function, severity, ...) \
245
281
  do { \
282
+ couchbase::core::logger::log_custom_logger(file, line, function, severity, __VA_ARGS__); \
283
+ \
246
284
  if (couchbase::core::logger::should_log(severity)) { \
247
285
  couchbase::core::logger::log(file, line, function, severity, __VA_ARGS__); \
248
286
  } \
@@ -305,6 +343,8 @@ is_initialized() -> bool;
305
343
  */
306
344
  #define COUCHBASE_LOG_RAW(file, line, function, severity, msg) \
307
345
  do { \
346
+ couchbase::core::logger::log_custom_logger(file, line, function, severity, msg); \
347
+ \
308
348
  if (couchbase::core::logger::should_log(severity)) { \
309
349
  couchbase::core::logger::detail::log(file, line, function, severity, msg); \
310
350
  } \
@@ -136,6 +136,7 @@ struct bucket_settings {
136
136
  std::optional<bool> history_retention_collection_default{};
137
137
  std::optional<std::uint32_t> history_retention_bytes{};
138
138
  std::optional<std::uint32_t> history_retention_duration{};
139
+ std::optional<std::uint16_t> num_vbuckets{};
139
140
 
140
141
  /**
141
142
  * UNCOMMITTED: This API may change in the future
@@ -56,6 +56,10 @@ struct traits<couchbase::core::management::cluster::bucket_settings> {
56
56
  history_retention_duration->template as<std::optional<std::uint32_t>>();
57
57
  }
58
58
 
59
+ if (auto* num_vbuckets = v.find("numVBuckets"); num_vbuckets != nullptr) {
60
+ result.num_vbuckets = num_vbuckets->template as<std::optional<std::uint16_t>>();
61
+ }
62
+
59
63
  if (auto& str = v.at("bucketType").get_string(); str == "couchbase" || str == "membase") {
60
64
  result.bucket_type = couchbase::core::management::cluster::bucket_type::couchbase;
61
65
  } else if (str == "ephemeral") {
@@ -207,7 +207,39 @@
207
207
  */
208
208
  #define COUCHBASE_CXX_CLIENT_PUBLIC_API_PARENT_SPAN 1
209
209
 
210
+ /**
211
+ * The library can be configured to use application telemetry (default is enabled)
212
+ * See couchbase::application_telemetry_options for available options
213
+ * to pass into couchbase::cluster_options
214
+ */
215
+ #define COUCHBASE_CXX_CLIENT_SUPPORTS_APP_TELEMETRY 1
216
+
210
217
  /**
211
218
  * core API like with_bucket_configuration() yields shared_ptr instead of configuration copy
212
219
  */
213
220
  #define COUCHBASE_CXX_CLIENT_CORE_RETURNS_POINTER_TO_CONFIG 1
221
+
222
+ /**
223
+ * bucket_settings in both the public and core management APIs have a num_vbuckets attribute
224
+ */
225
+ #define COUCHBASE_CXX_CLIENT_HAS_BUCKET_SETTINGS_NUM_VBUCKETS 1
226
+
227
+ /**
228
+ * couchbase::query_options and couchbase::analytics_options provide the methods:
229
+ * - add_positional_parameter
230
+ * - add_named_parameter
231
+ * - clear_positional_parameters
232
+ * - clear_named_parameters
233
+ */
234
+ #define COUCHBASE_CXX_CLIENT_QUERY_OPTIONS_HAVE_ADD_PARAMETER 1
235
+
236
+ /**
237
+ * couchbase::query_options and couchbase::analytics_options allow setting both positional and named
238
+ * parameters.
239
+ */
240
+ #define COUCHBASE_CXX_CLIENT_QUERY_SUPPORTS_BOTH_POSITIONAL_NAMED_PARAMETERS 1
241
+
242
+ /**
243
+ * get_multi API is implemented for transactions
244
+ */
245
+ #define COUCHBASE_CXX_CLIENT_HAS_TRANSACTIONS_GET_MULTI 1
@@ -35,16 +35,16 @@ analytics_request::encode_to(analytics_request::encoded_request_type& encoded,
35
35
  tao::json::value body{ { "statement", statement },
36
36
  { "client_context_id", encoded.client_context_id },
37
37
  { "timeout", fmt::format("{}ms", encoded.timeout.count()) } };
38
- if (positional_parameters.empty()) {
39
- for (const auto& [name, value] : named_parameters) {
40
- Expects(name.empty() == false);
41
- std::string key = name;
42
- if (key[0] != '$') {
43
- key.insert(key.begin(), '$');
44
- }
45
- body[key] = utils::json::parse(value);
38
+
39
+ for (const auto& [name, value] : named_parameters) {
40
+ Expects(name.empty() == false);
41
+ std::string key = name;
42
+ if (key[0] != '$') {
43
+ key.insert(key.begin(), '$');
46
44
  }
47
- } else {
45
+ body[key] = utils::json::parse(value);
46
+ }
47
+ if (!positional_parameters.empty()) {
48
48
  std::vector<tao::json::value> parameters;
49
49
  parameters.reserve(positional_parameters.size());
50
50
  for (const auto& value : positional_parameters) {
@@ -28,6 +28,7 @@ append_request::encode_to(protocol::client_request<protocol::append_request_body
28
28
  {
29
29
  encoded.opaque(opaque);
30
30
  encoded.partition(partition);
31
+ encoded.cas(cas);
31
32
  encoded.body().id(id);
32
33
  encoded.body().content(value);
33
34
  return {};
@@ -50,6 +50,7 @@ struct append_request {
50
50
  std::vector<std::byte> value;
51
51
  std::uint16_t partition{};
52
52
  std::uint32_t opaque{};
53
+ couchbase::cas cas{ 0 };
53
54
  couchbase::durability_level durability_level{ durability_level::none };
54
55
  std::optional<std::chrono::milliseconds> timeout{};
55
56
  io::retry_context<false> retries{};
@@ -131,7 +131,11 @@ struct get_all_replicas_request {
131
131
  }
132
132
  }
133
133
  if (local_handler) {
134
- return local_handler({ std::move(resp.ctx), std::move(ctx->result_) });
134
+ if (ctx->result_.empty()) {
135
+ // Return an error only when we have no results from any replica.
136
+ return local_handler({ std::move(resp.ctx), {} });
137
+ }
138
+ return local_handler({ {}, std::move(ctx->result_) });
135
139
  }
136
140
  });
137
141
  } else {
@@ -158,7 +162,11 @@ struct get_all_replicas_request {
158
162
  }
159
163
  }
160
164
  if (local_handler) {
161
- return local_handler({ std::move(resp.ctx), std::move(ctx->result_) });
165
+ if (ctx->result_.empty()) {
166
+ // Return an error only when we have no results from any replica.
167
+ return local_handler({ std::move(resp.ctx), {} });
168
+ }
169
+ return local_handler({ {}, std::move(ctx->result_) });
162
170
  }
163
171
  });
164
172
  }
@@ -31,6 +31,10 @@ auto
31
31
  lookup_in_request::encode_to(lookup_in_request::encoded_request_type& encoded,
32
32
  mcbp_context&& context) -> std::error_code
33
33
  {
34
+ if (specs.empty()) {
35
+ return errc::common::invalid_argument;
36
+ }
37
+
34
38
  for (std::size_t i = 0; i < specs.size(); ++i) {
35
39
  specs[i].original_index_ = i;
36
40
 
@@ -115,6 +115,10 @@ struct lookup_in_all_replicas_request {
115
115
  ec = errc::key_value::document_irretrievable;
116
116
  }
117
117
 
118
+ if (!ec && specs.empty()) {
119
+ ec = errc::common::invalid_argument;
120
+ }
121
+
118
122
  if (ec) {
119
123
  return h(response_type{ make_subdocument_error_context(
120
124
  make_key_value_error_context(ec, id), ec, {}, {}, false) });
@@ -183,7 +187,11 @@ struct lookup_in_all_replicas_request {
183
187
  }
184
188
  }
185
189
  if (local_handler) {
186
- return local_handler({ std::move(resp.ctx), std::move(ctx->result_) });
190
+ if (ctx->result_.empty()) {
191
+ // Return an error only when we have no results from any replica.
192
+ return local_handler({ std::move(resp.ctx), {} });
193
+ }
194
+ return local_handler({ {}, std::move(ctx->result_) });
187
195
  }
188
196
  });
189
197
  } else {
@@ -227,7 +235,11 @@ struct lookup_in_all_replicas_request {
227
235
  }
228
236
  }
229
237
  if (local_handler) {
230
- return local_handler({ std::move(resp.ctx), std::move(ctx->result_) });
238
+ if (ctx->result_.empty()) {
239
+ // Return an error only when we have no results from any replica.
240
+ return local_handler({ std::move(resp.ctx), {} });
241
+ }
242
+ return local_handler({ {}, std::move(ctx->result_) });
231
243
  }
232
244
  });
233
245
  }
@@ -112,6 +112,10 @@ struct lookup_in_any_replica_request {
112
112
  ec = errc::key_value::document_irretrievable;
113
113
  }
114
114
 
115
+ if (!ec && specs.empty()) {
116
+ ec = errc::common::invalid_argument;
117
+ }
118
+
115
119
  if (ec) {
116
120
  return h(response_type{ make_subdocument_error_context(
117
121
  make_key_value_error_context(ec, id), ec, {}, {}, false) });
@@ -36,6 +36,9 @@ mutate_in_request::encode_to(mutate_in_request::encoded_request_type& encoded,
36
36
  !context.supports_feature(protocol::hello_feature::subdoc_create_as_deleted)) {
37
37
  return errc::common::unsupported_operation;
38
38
  }
39
+ if (specs.empty()) {
40
+ return errc::common::invalid_argument;
41
+ }
39
42
  for (std::size_t i = 0; i < specs.size(); ++i) {
40
43
  auto& entry = specs[i];
41
44
  entry.original_index_ = i;
@@ -60,6 +63,7 @@ mutate_in_request::encode_to(mutate_in_request::encoded_request_type& encoded,
60
63
  }
61
64
  encoded.body().access_deleted(access_deleted);
62
65
  encoded.body().create_as_deleted(create_as_deleted);
66
+ encoded.body().revive_document(revive_document);
63
67
  encoded.body().store_semantics(store_semantics);
64
68
  encoded.body().specs(specs);
65
69
  if (preserve_expiry) {
@@ -63,6 +63,7 @@ struct mutate_in_request {
63
63
  couchbase::cas cas{ 0 };
64
64
  bool access_deleted{ false };
65
65
  bool create_as_deleted{ false };
66
+ bool revive_document{ false };
66
67
  std::optional<std::uint32_t> expiry{};
67
68
  couchbase::store_semantics store_semantics{ couchbase::store_semantics::replace };
68
69
  std::vector<couchbase::core::impl::subdoc::command> specs{};
@@ -28,6 +28,7 @@ prepend_request::encode_to(prepend_request::encoded_request_type& encoded,
28
28
  {
29
29
  encoded.opaque(opaque);
30
30
  encoded.partition(partition);
31
+ encoded.cas(cas);
31
32
  encoded.body().id(id);
32
33
  encoded.body().content(value);
33
34
  return {};
@@ -50,6 +50,7 @@ struct prepend_request {
50
50
  std::vector<std::byte> value;
51
51
  std::uint16_t partition{};
52
52
  std::uint32_t opaque{};
53
+ couchbase::cas cas{ 0 };
53
54
  couchbase::durability_level durability_level{ durability_level::none };
54
55
  std::optional<std::chrono::milliseconds> timeout{};
55
56
  io::retry_context<false> retries{};
@@ -64,16 +64,16 @@ query_request::encode_to(query_request::encoded_request_type& encoded,
64
64
  timeout_for_service -= std::chrono::milliseconds(500);
65
65
  }
66
66
  body["timeout"] = fmt::format("{}ms", timeout_for_service.count());
67
- if (positional_parameters.empty()) {
68
- for (const auto& [name, value] : named_parameters) {
69
- Expects(name.empty() == false);
70
- std::string key = name;
71
- if (key[0] != '$') {
72
- key.insert(key.begin(), '$');
73
- }
74
- body[key] = utils::json::parse(value);
67
+
68
+ for (const auto& [name, value] : named_parameters) {
69
+ Expects(name.empty() == false);
70
+ std::string key = name;
71
+ if (key[0] != '$') {
72
+ key.insert(key.begin(), '$');
75
73
  }
76
- } else {
74
+ body[key] = utils::json::parse(value);
75
+ }
76
+ if (!positional_parameters.empty()) {
77
77
  std::vector<tao::json::value> parameters;
78
78
  parameters.reserve(positional_parameters.size());
79
79
  for (const auto& value : positional_parameters) {
@@ -237,7 +237,9 @@ query_request::make_response(error_context::query&& ctx,
237
237
  response.ctx.ec = errc::common::parsing_failure;
238
238
  return response;
239
239
  }
240
- response.meta.request_id = payload.at("requestID").get_string();
240
+ if (const auto* i = payload.find("requestID"); i != nullptr) {
241
+ response.meta.request_id = i->get_string();
242
+ }
241
243
 
242
244
  if (const auto* i = payload.find("clientContextID"); i != nullptr) {
243
245
  response.meta.client_context_id = i->get_string();
@@ -25,6 +25,7 @@ auto
25
25
  http_noop_request::encode_to(http_noop_request::encoded_request_type& encoded,
26
26
  http_context& /* context */) -> std::error_code
27
27
  {
28
+ encoded.type = type;
28
29
  encoded.headers["connection"] = "keep-alive";
29
30
  encoded.method = "GET";
30
31
  encoded.path = "/";
@@ -86,6 +86,9 @@ bucket_create_request::encode_to(encoded_request_type& encoded,
86
86
  if (bucket.flush_enabled.has_value()) {
87
87
  encoded.body.append(fmt::format("&flushEnabled={}", bucket.flush_enabled.value() ? "1" : "0"));
88
88
  }
89
+ if (bucket.num_vbuckets.has_value()) {
90
+ encoded.body.append(fmt::format("&numVBuckets={}", bucket.num_vbuckets.value()));
91
+ }
89
92
 
90
93
  switch (bucket.eviction_policy) {
91
94
  case couchbase::core::management::cluster::bucket_eviction_policy::full:
@@ -69,6 +69,9 @@ bucket_update_request::encode_to(encoded_request_type& encoded,
69
69
  if (bucket.flush_enabled.has_value()) {
70
70
  encoded.body.append(fmt::format("&flushEnabled={}", bucket.flush_enabled.value() ? "1" : "0"));
71
71
  }
72
+ if (bucket.num_vbuckets.has_value()) {
73
+ encoded.body.append(fmt::format("&numVBuckets={}", bucket.num_vbuckets.value()));
74
+ }
72
75
 
73
76
  switch (bucket.eviction_policy) {
74
77
  case couchbase::core::management::cluster::bucket_eviction_policy::full:
@@ -298,11 +298,6 @@ origin::to_json() const -> std::string
298
298
  return tao::json::to_string(json);
299
299
  }
300
300
 
301
- auto
302
- cluster_credentials::uses_certificate() const -> bool
303
- {
304
- return !certificate_path.empty();
305
- }
306
301
  } // namespace couchbase::core
307
302
 
308
303
  couchbase::core::origin::origin(const couchbase::core::origin& other)
@@ -17,6 +17,7 @@
17
17
 
18
18
  #pragma once
19
19
 
20
+ #include "cluster_credentials.hxx"
20
21
  #include "cluster_options.hxx"
21
22
 
22
23
  #include <string>
@@ -30,20 +31,10 @@ namespace utils
30
31
  struct connection_string;
31
32
  } // namespace utils
32
33
 
33
- struct cluster_credentials {
34
- std::string username{};
35
- std::string password{};
36
- std::string certificate_path{};
37
- std::string key_path{};
38
- std::optional<std::vector<std::string>> allowed_sasl_mechanisms{};
39
-
40
- [[nodiscard]] bool uses_certificate() const;
41
- };
42
-
43
34
  namespace topology
44
35
  {
45
36
  struct configuration;
46
- }
37
+ } // namespace topology
47
38
 
48
39
  struct origin {
49
40
  using node_entry = std::pair<std::string, std::string>;
@@ -82,9 +82,12 @@ public:
82
82
  #ifdef WIN32
83
83
  return CryptGenRandom(handle, (DWORD)size, static_cast<BYTE*>(dest));
84
84
  #else
85
- // TODO(CXXCBC-549)
86
- // NOLINTNEXTLINE(clang-analyzer-unix.BlockInCriticalSection)
87
- return static_cast<std::size_t>(read(handle, dest, size)) == size;
85
+ #if defined(__clang__) && defined(__clang_analyzer__)
86
+ [[clang::suppress]]
87
+ #endif
88
+ // TODO(CXXCBC-549)
89
+ // NOLINTNEXTLINE(clang-analyzer-unix.BlockInCriticalSection)
90
+ return static_cast<std::size_t>(read(handle, dest, size)) == size;
88
91
  #endif
89
92
  }
90
93
 
@@ -32,8 +32,8 @@ class RandomGenerator
32
32
  public:
33
33
  RandomGenerator();
34
34
 
35
- std::uint64_t next();
35
+ auto next() -> std::uint64_t;
36
36
 
37
- static bool getBytes(void* dest, size_t size);
37
+ static auto getBytes(void* dest, size_t size) -> bool;
38
38
  };
39
39
  } // namespace couchbase::core
@@ -151,6 +151,15 @@ public:
151
151
  }
152
152
  }
153
153
 
154
+ void revive_document(bool value)
155
+ {
156
+ if (value) {
157
+ flags_ |= doc_flag_revive_document;
158
+ } else {
159
+ flags_ &= ~doc_flag_revive_document;
160
+ }
161
+ }
162
+
154
163
  void store_semantics(couchbase::store_semantics semantics)
155
164
  {
156
165
  flags_ &= std::byte{ 0b1111'1100U }; /* reset first two bits */
@@ -42,4 +42,8 @@ constexpr std::chrono::milliseconds config_poll_interval{ 2'500 };
42
42
  constexpr std::chrono::milliseconds config_poll_floor{ 50 };
43
43
  constexpr std::chrono::milliseconds config_idle_redial_timeout{ 5 * 60'000 };
44
44
  constexpr std::chrono::milliseconds idle_http_connection_timeout{ 1'000 };
45
+
46
+ constexpr std::chrono::milliseconds app_telemetry_ping_interval{ 30'000 };
47
+ constexpr std::chrono::milliseconds app_telemetry_ping_timeout{ 2'000 };
48
+ constexpr std::chrono::milliseconds app_telemetry_backoff_interval{ std::chrono::hours{ 1 } };
45
49
  } // namespace couchbase::core::timeout_defaults
@@ -29,9 +29,8 @@
29
29
  namespace couchbase::core::topology
30
30
  {
31
31
  auto
32
- configuration::node::port_or(service_type type,
33
- bool is_tls,
34
- std::uint16_t default_value) const -> std::uint16_t
32
+ configuration::node::port_or(service_type type, bool is_tls, std::uint16_t default_value) const
33
+ -> std::uint16_t
35
34
  {
36
35
  if (is_tls) {
37
36
  switch (type) {
@@ -90,7 +89,7 @@ configuration::node::hostname_for(const std::string& network) const -> const std
90
89
  }
91
90
  const auto& address = alt.find(network);
92
91
  if (address == alt.end()) {
93
- CB_LOG_WARNING(R"(requested network "{}" is not found, fallback to "default" host)", network);
92
+ CB_LOG_DEBUG(R"(requested network "{}" is not found, fallback to "default" host)", network);
94
93
  return hostname;
95
94
  }
96
95
  return address->second.hostname;
@@ -107,10 +106,9 @@ configuration::node::port_or(const std::string& network,
107
106
  }
108
107
  const auto& address = alt.find(network);
109
108
  if (address == alt.end()) {
110
- CB_LOG_WARNING(
111
- R"(requested network "{}" is not found, fallback to "default" port of {} service)",
112
- network,
113
- type);
109
+ CB_LOG_DEBUG(R"(requested network "{}" is not found, fallback to "default" port of {} service)",
110
+ network,
111
+ type);
114
112
  return port_or(type, is_tls, default_value);
115
113
  }
116
114
  if (is_tls) {
@@ -163,9 +161,8 @@ configuration::node::port_or(const std::string& network,
163
161
  }
164
162
 
165
163
  auto
166
- configuration::node::endpoint(const std::string& network,
167
- service_type type,
168
- bool is_tls) const -> std::optional<std::string>
164
+ configuration::node::endpoint(const std::string& network, service_type type, bool is_tls) const
165
+ -> std::optional<std::string>
169
166
  {
170
167
  auto p = port_or(type, is_tls, 0);
171
168
  if (p == 0) {
@@ -234,8 +231,8 @@ configuration::index_for_this_node() const -> std::size_t
234
231
  }
235
232
 
236
233
  auto
237
- configuration::server_by_vbucket(std::uint16_t vbucket,
238
- std::size_t index) const -> std::optional<std::size_t>
234
+ configuration::server_by_vbucket(std::uint16_t vbucket, std::size_t index) const
235
+ -> std::optional<std::size_t>
239
236
  {
240
237
  if (!vbmap.has_value() || vbucket >= vbmap->size()) {
241
238
  return {};
@@ -61,6 +61,8 @@ struct configuration {
61
61
  port_map services_tls{};
62
62
  std::map<std::string, alternate_address> alt{};
63
63
  std::string server_group{};
64
+ std::optional<std::string> app_telemetry_path{};
65
+ std::string node_uuid{};
64
66
 
65
67
  auto operator!=(const node& other) const -> bool
66
68
  {
@@ -69,9 +71,8 @@ struct configuration {
69
71
  services_tls.key_value != other.services_tls.key_value;
70
72
  }
71
73
 
72
- [[nodiscard]] auto port_or(service_type type,
73
- bool is_tls,
74
- std::uint16_t default_value) const -> std::uint16_t;
74
+ [[nodiscard]] auto port_or(service_type type, bool is_tls, std::uint16_t default_value) const
75
+ -> std::uint16_t;
75
76
 
76
77
  [[nodiscard]] auto port_or(const std::string& network,
77
78
  service_type type,
@@ -80,9 +81,8 @@ struct configuration {
80
81
 
81
82
  [[nodiscard]] auto hostname_for(const std::string& network) const -> const std::string&;
82
83
 
83
- [[nodiscard]] auto endpoint(const std::string& network,
84
- service_type type,
85
- bool is_tls) const -> std::optional<std::string>;
84
+ [[nodiscard]] auto endpoint(const std::string& network, service_type type, bool is_tls) const
85
+ -> std::optional<std::string>;
86
86
  };
87
87
 
88
88
  [[nodiscard]] auto select_network(const std::string& bootstrap_hostname) const -> std::string;
@@ -128,13 +128,13 @@ struct configuration {
128
128
  const std::string& hostname,
129
129
  const std::string& port) const -> bool;
130
130
 
131
- auto map_key(const std::string& key,
132
- std::size_t index) const -> std::pair<std::uint16_t, std::optional<std::size_t>>;
133
- auto map_key(const std::vector<std::byte>& key,
134
- std::size_t index) const -> std::pair<std::uint16_t, std::optional<std::size_t>>;
131
+ auto map_key(const std::string& key, std::size_t index) const
132
+ -> std::pair<std::uint16_t, std::optional<std::size_t>>;
133
+ auto map_key(const std::vector<std::byte>& key, std::size_t index) const
134
+ -> std::pair<std::uint16_t, std::optional<std::size_t>>;
135
135
 
136
- auto server_by_vbucket(std::uint16_t vbucket,
137
- std::size_t index) const -> std::optional<std::size_t>;
136
+ auto server_by_vbucket(std::uint16_t vbucket, std::size_t index) const
137
+ -> std::optional<std::size_t>;
138
138
  };
139
139
 
140
140
  using endpoint = std::pair<std::string, std::string>;
@@ -145,7 +145,6 @@ make_blank_configuration(const std::string& hostname,
145
145
  std::uint16_t tls_port) -> configuration;
146
146
 
147
147
  auto
148
- make_blank_configuration(const std::vector<endpoint>& endpoints,
149
- bool use_tls,
150
- bool force = false) -> configuration;
148
+ make_blank_configuration(const std::vector<endpoint>& endpoints, bool use_tls, bool force = false)
149
+ -> configuration;
151
150
  } // namespace couchbase::core::topology
@@ -61,6 +61,12 @@ struct traits<couchbase::core::topology::configuration> {
61
61
  if (const auto& group = o.find("serverGroup"); group != o.end()) {
62
62
  n.server_group = group->second.get_string();
63
63
  }
64
+ if (const auto& path = o.find("appTelemetryPath"); path != o.end()) {
65
+ n.app_telemetry_path = path->second.get_string();
66
+ }
67
+ if (const auto& uuid = o.find("nodeUUID"); uuid != o.end()) {
68
+ n.node_uuid = uuid->second.get_string();
69
+ }
64
70
  const auto& s = o.at("services");
65
71
  n.services_plain.key_value = s.template optional<std::uint16_t>("kv");
66
72
  n.services_plain.management = s.template optional<std::uint16_t>("mgmt");