couchbase 3.4.3 → 3.4.5

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 (179) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/couchbase/CMakeLists.txt +22 -1
  4. data/ext/couchbase/core/bucket.cxx +183 -152
  5. data/ext/couchbase/core/bucket.hxx +17 -4
  6. data/ext/couchbase/core/cluster.hxx +41 -13
  7. data/ext/couchbase/core/cluster_options.hxx +3 -0
  8. data/ext/couchbase/core/crud_component.cxx +51 -22
  9. data/ext/couchbase/core/error_context/key_value.cxx +2 -1
  10. data/ext/couchbase/core/error_context/key_value.hxx +10 -12
  11. data/ext/couchbase/core/impl/build_deferred_query_indexes.cxx +115 -50
  12. data/ext/couchbase/core/impl/cluster.cxx +6 -0
  13. data/ext/couchbase/core/impl/create_bucket.cxx +158 -0
  14. data/ext/couchbase/core/impl/create_collection.cxx +83 -0
  15. data/ext/couchbase/core/impl/create_query_index.cxx +172 -59
  16. data/ext/couchbase/core/impl/create_scope.cxx +69 -0
  17. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +2 -1
  18. data/ext/couchbase/core/impl/drop_bucket.cxx +66 -0
  19. data/ext/couchbase/core/impl/drop_collection.cxx +76 -0
  20. data/ext/couchbase/core/impl/drop_query_index.cxx +138 -59
  21. data/ext/couchbase/core/impl/drop_scope.cxx +68 -0
  22. data/ext/couchbase/core/impl/flush_bucket.cxx +66 -0
  23. data/ext/couchbase/core/impl/get_all_buckets.cxx +178 -0
  24. data/ext/couchbase/core/impl/get_all_query_indexes.cxx +67 -37
  25. data/ext/couchbase/core/impl/get_all_scopes.cxx +94 -0
  26. data/ext/couchbase/core/impl/get_bucket.cxx +168 -0
  27. data/ext/couchbase/core/impl/internal_manager_error_context.cxx +113 -0
  28. data/ext/couchbase/core/impl/internal_manager_error_context.hxx +60 -0
  29. data/ext/couchbase/core/impl/key_value_error_category.cxx +2 -4
  30. data/ext/couchbase/core/impl/key_value_error_context.cxx +98 -0
  31. data/ext/couchbase/core/impl/lookup_in.cxx +1 -0
  32. data/ext/couchbase/core/impl/lookup_in_all_replicas.cxx +178 -0
  33. data/ext/couchbase/core/impl/lookup_in_all_replicas.hxx +80 -0
  34. data/ext/couchbase/core/impl/lookup_in_any_replica.cxx +169 -0
  35. data/ext/couchbase/core/impl/lookup_in_any_replica.hxx +75 -0
  36. data/ext/couchbase/core/impl/lookup_in_replica.cxx +104 -0
  37. data/ext/couchbase/core/impl/lookup_in_replica.hxx +67 -0
  38. data/ext/couchbase/core/impl/manager_error_context.cxx +100 -0
  39. data/ext/couchbase/core/impl/query.cxx +1 -0
  40. data/ext/couchbase/core/impl/query_error_context.cxx +75 -0
  41. data/ext/couchbase/core/impl/update_bucket.cxx +133 -0
  42. data/ext/couchbase/core/impl/update_collection.cxx +83 -0
  43. data/ext/couchbase/core/impl/watch_query_indexes.cxx +53 -29
  44. data/ext/couchbase/core/io/dns_client.cxx +111 -40
  45. data/ext/couchbase/core/io/dns_config.cxx +5 -4
  46. data/ext/couchbase/core/io/http_session.hxx +24 -1
  47. data/ext/couchbase/core/io/mcbp_command.hxx +9 -2
  48. data/ext/couchbase/core/io/mcbp_session.cxx +80 -43
  49. data/ext/couchbase/core/io/mcbp_session.hxx +4 -3
  50. data/ext/couchbase/core/logger/custom_rotating_file_sink.cxx +1 -1
  51. data/ext/couchbase/core/logger/logger.cxx +80 -20
  52. data/ext/couchbase/core/logger/logger.hxx +31 -0
  53. data/ext/couchbase/core/management/bucket_settings.hxx +8 -5
  54. data/ext/couchbase/core/management/bucket_settings_json.hxx +12 -2
  55. data/ext/couchbase/core/meta/features.hxx +42 -0
  56. data/ext/couchbase/core/operations/document_lookup_in.cxx +8 -1
  57. data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +192 -0
  58. data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +188 -0
  59. data/ext/couchbase/core/operations/document_query.cxx +11 -0
  60. data/ext/couchbase/core/operations/document_query.hxx +1 -0
  61. data/ext/couchbase/core/operations/management/CMakeLists.txt +1 -0
  62. data/ext/couchbase/core/operations/management/bucket_create.cxx +30 -9
  63. data/ext/couchbase/core/operations/management/bucket_update.cxx +27 -6
  64. data/ext/couchbase/core/operations/management/collection_create.cxx +5 -1
  65. data/ext/couchbase/core/operations/management/collection_create.hxx +1 -0
  66. data/ext/couchbase/core/operations/management/collection_update.cxx +87 -0
  67. data/ext/couchbase/core/operations/management/collection_update.hxx +54 -0
  68. data/ext/couchbase/core/operations/management/collections.hxx +1 -0
  69. data/ext/couchbase/core/operations.hxx +2 -0
  70. data/ext/couchbase/core/origin.cxx +270 -0
  71. data/ext/couchbase/core/origin.hxx +2 -0
  72. data/ext/couchbase/core/protocol/client_response.hxx +1 -0
  73. data/ext/couchbase/core/protocol/cmd_hello.hxx +1 -0
  74. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.cxx +107 -0
  75. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.hxx +137 -0
  76. data/ext/couchbase/core/protocol/hello_feature.hxx +6 -0
  77. data/ext/couchbase/core/protocol/hello_feature_fmt.hxx +3 -0
  78. data/ext/couchbase/core/protocol/status.cxx +2 -2
  79. data/ext/couchbase/core/range_scan_options.cxx +3 -27
  80. data/ext/couchbase/core/range_scan_options.hxx +13 -17
  81. data/ext/couchbase/core/range_scan_orchestrator.cxx +388 -170
  82. data/ext/couchbase/core/range_scan_orchestrator.hxx +13 -2
  83. data/ext/couchbase/core/range_scan_orchestrator_options.hxx +5 -3
  84. data/ext/couchbase/core/scan_options.hxx +0 -19
  85. data/ext/couchbase/core/scan_result.cxx +19 -5
  86. data/ext/couchbase/core/scan_result.hxx +5 -2
  87. data/ext/couchbase/core/timeout_defaults.hxx +3 -4
  88. data/ext/couchbase/core/topology/capabilities.hxx +4 -0
  89. data/ext/couchbase/core/topology/capabilities_fmt.hxx +11 -0
  90. data/ext/couchbase/core/topology/collections_manifest.hxx +2 -0
  91. data/ext/couchbase/core/topology/collections_manifest_fmt.hxx +1 -1
  92. data/ext/couchbase/core/topology/collections_manifest_json.hxx +3 -0
  93. data/ext/couchbase/core/topology/configuration.hxx +20 -0
  94. data/ext/couchbase/core/topology/configuration_json.hxx +8 -1
  95. data/ext/couchbase/core/utils/connection_string.cxx +62 -47
  96. data/ext/couchbase/core/utils/connection_string.hxx +1 -0
  97. data/ext/couchbase/couchbase/analytics_error_context.hxx +1 -1
  98. data/ext/couchbase/couchbase/behavior_options.hxx +19 -2
  99. data/ext/couchbase/couchbase/bucket.hxx +14 -0
  100. data/ext/couchbase/couchbase/bucket_manager.hxx +135 -0
  101. data/ext/couchbase/couchbase/build_query_index_options.hxx +0 -30
  102. data/ext/couchbase/couchbase/cluster.hxx +14 -0
  103. data/ext/couchbase/couchbase/collection.hxx +111 -0
  104. data/ext/couchbase/couchbase/collection_manager.hxx +160 -0
  105. data/ext/couchbase/couchbase/collection_query_index_manager.hxx +7 -48
  106. data/ext/couchbase/couchbase/create_bucket_options.hxx +41 -0
  107. data/ext/couchbase/couchbase/create_collection_options.hxx +44 -0
  108. data/ext/couchbase/couchbase/create_primary_query_index_options.hxx +0 -29
  109. data/ext/couchbase/couchbase/create_query_index_options.hxx +0 -33
  110. data/ext/couchbase/couchbase/create_scope_options.hxx +41 -0
  111. data/ext/couchbase/couchbase/drop_bucket_options.hxx +41 -0
  112. data/ext/couchbase/couchbase/drop_collection_options.hxx +41 -0
  113. data/ext/couchbase/couchbase/drop_primary_query_index_options.hxx +0 -30
  114. data/ext/couchbase/couchbase/drop_query_index_options.hxx +0 -31
  115. data/ext/couchbase/couchbase/drop_scope_options.hxx +41 -0
  116. data/ext/couchbase/couchbase/error_codes.hxx +1 -2
  117. data/ext/couchbase/couchbase/error_context.hxx +10 -2
  118. data/ext/couchbase/couchbase/flush_bucket_options.hxx +41 -0
  119. data/ext/couchbase/{core/topology/error_map_fmt.hxx → couchbase/fmt/key_value_error_map_attribute.hxx} +21 -21
  120. data/ext/couchbase/couchbase/get_all_buckets_options.hxx +44 -0
  121. data/ext/couchbase/couchbase/get_all_query_indexes_options.hxx +0 -30
  122. data/ext/couchbase/couchbase/get_all_scopes_options.hxx +44 -0
  123. data/ext/couchbase/couchbase/get_and_lock_options.hxx +2 -2
  124. data/ext/couchbase/couchbase/get_and_touch_options.hxx +2 -2
  125. data/ext/couchbase/couchbase/get_bucket_options.hxx +43 -0
  126. data/ext/couchbase/couchbase/get_options.hxx +2 -2
  127. data/ext/couchbase/couchbase/insert_options.hxx +3 -3
  128. data/ext/couchbase/couchbase/key_value_error_context.hxx +7 -2
  129. data/ext/couchbase/couchbase/lookup_in_all_replicas_options.hxx +109 -0
  130. data/ext/couchbase/couchbase/lookup_in_any_replica_options.hxx +101 -0
  131. data/ext/couchbase/couchbase/lookup_in_options.hxx +2 -2
  132. data/ext/couchbase/couchbase/lookup_in_replica_result.hxx +74 -0
  133. data/ext/couchbase/couchbase/lookup_in_result.hxx +26 -0
  134. data/ext/couchbase/couchbase/management/bucket_settings.hxx +119 -0
  135. data/ext/couchbase/couchbase/management/collection_spec.hxx +29 -0
  136. data/ext/couchbase/couchbase/management/scope_spec.hxx +29 -0
  137. data/ext/couchbase/couchbase/manager_error_context.hxx +29 -53
  138. data/ext/couchbase/couchbase/mutate_in_options.hxx +2 -2
  139. data/ext/couchbase/couchbase/query_error_context.hxx +3 -1
  140. data/ext/couchbase/couchbase/query_index_manager.hxx +16 -83
  141. data/ext/couchbase/couchbase/query_options.hxx +18 -0
  142. data/ext/couchbase/couchbase/remove_options.hxx +2 -2
  143. data/ext/couchbase/couchbase/replace_options.hxx +3 -3
  144. data/ext/couchbase/couchbase/security_options.hxx +15 -0
  145. data/ext/couchbase/couchbase/subdocument_error_context.hxx +4 -2
  146. data/ext/couchbase/couchbase/touch_options.hxx +2 -2
  147. data/ext/couchbase/couchbase/unlock_options.hxx +2 -2
  148. data/ext/couchbase/couchbase/update_bucket_options.hxx +41 -0
  149. data/ext/couchbase/couchbase/update_collection_options.hxx +44 -0
  150. data/ext/couchbase/couchbase/upsert_options.hxx +3 -3
  151. data/ext/couchbase/couchbase/watch_query_indexes_options.hxx +0 -31
  152. data/ext/couchbase/test/CMakeLists.txt +1 -0
  153. data/ext/couchbase/test/test_integration_collections.cxx +6 -0
  154. data/ext/couchbase/test/test_integration_crud.cxx +5 -0
  155. data/ext/couchbase/test/test_integration_examples.cxx +137 -1
  156. data/ext/couchbase/test/test_integration_management.cxx +1009 -309
  157. data/ext/couchbase/test/test_integration_query.cxx +19 -7
  158. data/ext/couchbase/test/test_integration_range_scan.cxx +351 -112
  159. data/ext/couchbase/test/test_integration_search.cxx +10 -1
  160. data/ext/couchbase/test/test_integration_subdoc.cxx +721 -7
  161. data/ext/couchbase/test/test_transaction_public_async_api.cxx +13 -12
  162. data/ext/couchbase/test/test_transaction_public_blocking_api.cxx +27 -21
  163. data/ext/couchbase/test/test_unit_connection_string.cxx +29 -0
  164. data/ext/couchbase/test/test_unit_query.cxx +75 -0
  165. data/ext/couchbase.cxx +735 -60
  166. data/ext/revisions.rb +3 -3
  167. data/lib/couchbase/cluster.rb +1 -1
  168. data/lib/couchbase/collection.rb +108 -0
  169. data/lib/couchbase/collection_options.rb +100 -1
  170. data/lib/couchbase/errors.rb +5 -0
  171. data/lib/couchbase/key_value_scan.rb +125 -0
  172. data/lib/couchbase/management/bucket_manager.rb +22 -15
  173. data/lib/couchbase/management/collection_manager.rb +158 -9
  174. data/lib/couchbase/options.rb +151 -0
  175. data/lib/couchbase/scope.rb +1 -1
  176. data/lib/couchbase/utils/time.rb +14 -1
  177. data/lib/couchbase/version.rb +1 -1
  178. metadata +59 -8
  179. data/ext/couchbase/core/impl/collection_query_index_manager.cxx +0 -93
@@ -79,6 +79,7 @@ class cluster : public std::enable_shared_from_this<cluster>
79
79
  }
80
80
 
81
81
  origin_ = std::move(origin);
82
+ CB_LOG_DEBUG(R"(open cluster, id: "{}", core version: "{}", {})", id_, couchbase::core::meta::sdk_semver(), origin_.to_json());
82
83
  // ignore the enable_tracing flag if a tracer was passed in
83
84
  if (nullptr != origin_.options().tracer) {
84
85
  tracer_ = origin_.options().tracer;
@@ -111,10 +112,7 @@ class cluster : public std::enable_shared_from_this<cluster>
111
112
  return self->dns_srv_tracker_->get_srv_nodes(
112
113
  [self, hostname = std::move(hostname), handler = std::forward<Handler>(handler)](origin::node_list nodes,
113
114
  std::error_code ec) mutable {
114
- if (ec) {
115
- return self->close([ec, handler = std::forward<Handler>(handler)]() mutable { handler(ec); });
116
- }
117
- if (!nodes.empty()) {
115
+ if (!ec && !nodes.empty()) {
118
116
  self->origin_.set_nodes(std::move(nodes));
119
117
  CB_LOG_INFO("replace list of bootstrap nodes with addresses from DNS SRV of \"{}\": [{}]",
120
118
  hostname,
@@ -338,9 +336,16 @@ class cluster : public std::enable_shared_from_this<cluster>
338
336
  template<typename Handler>
339
337
  void do_open(Handler&& handler)
340
338
  {
339
+ // Warn users if idle_http_connection_timeout is too close to server idle timeouts
340
+ if (origin_.options().idle_http_connection_timeout > std::chrono::milliseconds(4'500)) {
341
+ CB_LOG_INFO("[{}]: The SDK may produce trivial warnings due to the idle HTTP connection timeout being set above the idle"
342
+ "timeout of various services",
343
+ id_);
344
+ }
345
+
341
346
  // Warn users if they attempt to use Capella without TLS being enabled.
347
+ bool has_capella_host = false;
342
348
  {
343
- bool has_capella_host = false;
344
349
  bool has_non_capella_host = false;
345
350
  static std::string suffix = "cloud.couchbase.com";
346
351
  for (const auto& node : origin_.get_hostnames()) {
@@ -359,6 +364,7 @@ class cluster : public std::enable_shared_from_this<cluster>
359
364
 
360
365
  if (origin_.options().enable_tls /* TLS is enabled */
361
366
  && origin_.options().trust_certificate.empty() /* No CA certificate (or other SDK-specific trust source) is specified */
367
+ && origin_.options().trust_certificate_value.empty() /* and certificate value has not been specified */
362
368
  && origin_.options().tls_verify != tls_verify_mode::none /* The user did not disable all TLS verification */
363
369
  && has_non_capella_host /* The connection string has a hostname that does NOT end in ".cloud.couchbase.com" */) {
364
370
  CB_LOG_WARNING("[{}] When TLS is enabled, the cluster options must specify certificate(s) to trust or ensure that they are "
@@ -368,7 +374,17 @@ class cluster : public std::enable_shared_from_this<cluster>
368
374
  }
369
375
 
370
376
  if (origin_.options().enable_tls) {
371
- tls_.set_options(asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
377
+ long tls_options = asio::ssl::context::default_workarounds | // various bug workarounds that should be rather harmless
378
+ asio::ssl::context::no_sslv2 | // published: 1995, deprecated: 2011
379
+ asio::ssl::context::no_sslv3; // published: 1996, deprecated: 2015
380
+ if (origin_.options().tls_disable_deprecated_protocols) {
381
+ tls_options |= asio::ssl::context::no_tlsv1 | // published: 1999, deprecated: 2021
382
+ asio::ssl::context::no_tlsv1_1; // published: 2006, deprecated: 2021
383
+ }
384
+ if (origin_.options().tls_disable_v1_2 || has_capella_host) {
385
+ tls_options |= asio::ssl::context::no_tlsv1_2; // published: 2008, still in use
386
+ }
387
+ tls_.set_options(tls_options);
372
388
  switch (origin_.options().tls_verify) {
373
389
  case tls_verify_mode::none:
374
390
  tls_.set_verify_mode(asio::ssl::verify_none);
@@ -378,7 +394,8 @@ class cluster : public std::enable_shared_from_this<cluster>
378
394
  tls_.set_verify_mode(asio::ssl::verify_peer);
379
395
  break;
380
396
  }
381
- if (origin_.options().trust_certificate.empty()) { // trust certificate is not explicitly specified
397
+ if (origin_.options().trust_certificate.empty() &&
398
+ origin_.options().trust_certificate_value.empty()) { // trust certificate is not explicitly specified
382
399
  CB_LOG_DEBUG(R"([{}]: use default CA for TLS verify)", id_);
383
400
  std::error_code ec{};
384
401
 
@@ -414,11 +431,22 @@ class cluster : public std::enable_shared_from_this<cluster>
414
431
  std::error_code ec{};
415
432
  // load only the explicit certificate
416
433
  // system and default capella certificates are not loaded
417
- CB_LOG_DEBUG(R"([{}]: use TLS verify file: "{}")", id_, origin_.options().trust_certificate);
418
- tls_.load_verify_file(origin_.options().trust_certificate, ec);
419
- if (ec) {
420
- CB_LOG_ERROR("[{}]: unable to load verify file \"{}\": {}", id_, origin_.options().trust_certificate, ec.message());
421
- return close([ec, handler = std::forward<Handler>(handler)]() mutable { return handler(ec); });
434
+ if (!origin_.options().trust_certificate_value.empty()) {
435
+ CB_LOG_DEBUG(R"([{}]: use TLS certificate passed through via options object)", id_);
436
+ tls_.add_certificate_authority(asio::const_buffer(origin_.options().trust_certificate_value.data(),
437
+ origin_.options().trust_certificate_value.size()),
438
+ ec);
439
+ if (ec) {
440
+ CB_LOG_WARNING("[{}]: unable to load CA passed via options object: {}", id_, ec.message());
441
+ }
442
+ }
443
+ if (!origin_.options().trust_certificate.empty()) {
444
+ CB_LOG_DEBUG(R"([{}]: use TLS verify file: "{}")", id_, origin_.options().trust_certificate);
445
+ tls_.load_verify_file(origin_.options().trust_certificate, ec);
446
+ if (ec) {
447
+ CB_LOG_ERROR("[{}]: unable to load verify file \"{}\": {}", id_, origin_.options().trust_certificate, ec.message());
448
+ return close([ec, handler = std::forward<Handler>(handler)]() mutable { return handler(ec); });
449
+ }
422
450
  }
423
451
  }
424
452
  #ifdef COUCHBASE_CXX_CLIENT_TLS_KEY_LOG_FILE
@@ -483,7 +511,7 @@ class cluster : public std::enable_shared_from_this<cluster>
483
511
  }
484
512
  self->session_manager_->set_configuration(config, self->origin_.options());
485
513
  self->session_->on_configuration_update(self->session_manager_);
486
- self->session_->on_stop([self](retry_reason) {
514
+ self->session_->on_stop([self]() {
487
515
  if (self->session_) {
488
516
  self->session_.reset();
489
517
  }
@@ -50,7 +50,10 @@ struct cluster_options {
50
50
  std::chrono::milliseconds management_timeout = timeout_defaults::management_timeout;
51
51
 
52
52
  bool enable_tls{ false };
53
+ bool tls_disable_deprecated_protocols{ true };
54
+ bool tls_disable_v1_2{ false };
53
55
  std::string trust_certificate{};
56
+ std::string trust_certificate_value{};
54
57
  bool enable_mutation_tokens{ true };
55
58
  bool enable_tcp_keep_alive{ true };
56
59
  io::ip_protocol use_ip_protocol{ io::ip_protocol::any };
@@ -1,6 +1,6 @@
1
1
  /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
2
  /*
3
- * Copyright 2020-2021 Couchbase, Inc.
3
+ * Copyright 2020-2023 Couchbase, Inc.
4
4
  *
5
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
6
  * you may not use this file except in compliance with the License.
@@ -39,6 +39,8 @@
39
39
 
40
40
  #include <tl/expected.hpp>
41
41
 
42
+ #include <random>
43
+
42
44
  namespace couchbase::core
43
45
  {
44
46
  static std::pair<std::vector<std::byte>, std::error_code>
@@ -53,17 +55,40 @@ serialize_range_scan_create_options(const range_scan_create_options& options)
53
55
  body["collection"] = fmt::format("{:x}", options.collection_id);
54
56
  }
55
57
 
56
- if (std::holds_alternative<range_scan>(options.scan_type)) {
57
- const auto& range = std::get<range_scan>(options.scan_type);
58
+ if (std::holds_alternative<range_scan>(options.scan_type) || std::holds_alternative<prefix_scan>(options.scan_type)) {
59
+ const auto& range = (std::holds_alternative<range_scan>(options.scan_type))
60
+ ? std::get<range_scan>(options.scan_type)
61
+ : std::get<prefix_scan>(options.scan_type).to_range_scan();
62
+
63
+ const auto& from = range.from.value_or(scan_term{ "" });
64
+ const auto& to = range.to.value_or(scan_term{ "\xf4\x8f\xfb\xfb" });
65
+
58
66
  body["range"] = {
59
- { range.start_.exclusive ? "excl_start" : "start", base64::encode(range.start_.id) },
60
- { range.end_.exclusive ? "excl_end" : "end", base64::encode(range.end_.id) },
67
+ { from.exclusive ? "excl_start" : "start", base64::encode(from.term) },
68
+ { to.exclusive ? "excl_end" : "end", base64::encode(to.term) },
61
69
  };
62
70
  } else if (std::holds_alternative<sampling_scan>(options.scan_type)) {
63
71
  const auto& sampling = std::get<sampling_scan>(options.scan_type);
72
+
73
+ // The limit in sampling scan is required to be greater than 0
74
+ if (sampling.limit <= 0) {
75
+ return { {}, errc::common::invalid_argument };
76
+ }
77
+
78
+ std::uint64_t seed{};
79
+ if (sampling.seed.has_value()) {
80
+ seed = sampling.seed.value();
81
+ } else {
82
+ // Generate random uint64 as seed
83
+ std::random_device rd;
84
+ std::mt19937_64 gen(rd());
85
+ std::uniform_int_distribution<std::uint64_t> dis;
86
+ seed = dis(gen);
87
+ }
88
+
64
89
  body["sampling"] = {
65
90
  { "samples", sampling.limit },
66
- { "seed", sampling.seed.value_or(0) },
91
+ { "seed", seed },
67
92
  };
68
93
  } else {
69
94
  return { {}, errc::common::invalid_argument };
@@ -75,7 +100,7 @@ serialize_range_scan_create_options(const range_scan_create_options& options)
75
100
  { "vb_uuid", std::to_string(snapshot.vbucket_uuid) },
76
101
  { "seqno", snapshot.sequence_number },
77
102
  { "timeout_ms",
78
- (options.timeout == std::chrono::milliseconds::zero()) ? timeout_defaults::range_scan_timeout.count()
103
+ (options.timeout == std::chrono::milliseconds::zero()) ? timeout_defaults::key_value_scan_timeout.count()
79
104
  : options.timeout.count() },
80
105
  };
81
106
  if (snapshot.sequence_number_exists) {
@@ -98,7 +123,7 @@ parse_range_scan_keys(gsl::span<std::byte> data, range_scan_item_callback&& item
98
123
  if (remaining.size() < key_length) {
99
124
  return errc::network::protocol_error;
100
125
  }
101
- item_callback(range_scan_item{ { remaining.begin(), remaining.begin() + static_cast<std::ptrdiff_t>(key_length) } });
126
+ item_callback(range_scan_item{ { reinterpret_cast<const char*>(remaining.data()), key_length } });
102
127
  if (remaining.size() == key_length) {
103
128
  return {};
104
129
  }
@@ -130,13 +155,13 @@ parse_range_scan_documents(gsl::span<std::byte> data, range_scan_item_callback&&
130
155
  body.datatype = data[24];
131
156
  data = gsl::make_span(data.data() + header_offset, data.size() - header_offset);
132
157
 
133
- std::vector<std::byte> key{};
158
+ std::string key{};
134
159
  {
135
160
  auto [key_length, remaining] = utils::decode_unsigned_leb128<std::size_t>(data, core::utils::leb_128_no_throw{});
136
161
  if (remaining.size() < key_length) {
137
162
  return errc::network::protocol_error;
138
163
  }
139
- key = { remaining.begin(), remaining.begin() + static_cast<std::ptrdiff_t>(key_length) };
164
+ key = { reinterpret_cast<const char*>(remaining.data()), key_length };
140
165
  data = gsl::make_span(remaining.data() + key_length, remaining.size() - key_length);
141
166
  }
142
167
 
@@ -242,19 +267,10 @@ class crud_component_impl
242
267
  if (error) {
243
268
  return cb({}, error);
244
269
  }
245
- bool ids_only;
246
- switch (response->extras_.size()) {
247
- case 4:
248
- ids_only = mcbp::big_endian::read_uint32(response->extras_, 0) == 0;
249
- break;
250
-
251
- case 0:
252
- ids_only = options.ids_only; // support servers before MB-54267. TODO: remove after server GA
253
- break;
254
-
255
- default:
256
- return cb({}, errc::network::protocol_error);
270
+ if (response->extras_.size() != 4) {
271
+ return cb({}, errc::network::protocol_error);
257
272
  }
273
+ bool ids_only = mcbp::big_endian::read_uint32(response->extras_, 0) == 0;
258
274
 
259
275
  if (auto ec = parse_range_scan_data(response->value_, std::move(item_cb), ids_only); ec) {
260
276
  return cb({}, ec);
@@ -276,6 +292,19 @@ class crud_component_impl
276
292
 
277
293
  req->persistent_ = true;
278
294
  req->vbucket_ = vbucket_id;
295
+
296
+ if (options.timeout != std::chrono::milliseconds::zero()) {
297
+ auto timer = std::make_shared<asio::steady_timer>(io_);
298
+ timer->expires_after(options.timeout);
299
+ timer->async_wait([req](auto error) {
300
+ if (error == asio::error::operation_aborted) {
301
+ return;
302
+ }
303
+ req->cancel(couchbase::errc::common::unambiguous_timeout);
304
+ });
305
+ req->set_deadline(timer);
306
+ }
307
+
279
308
  mcbp::buffer_writer buf{ scan_uuid.size() + sizeof(std::uint32_t) * 3 };
280
309
  buf.write(scan_uuid);
281
310
  buf.write_uint32(options.batch_item_limit);
@@ -24,7 +24,7 @@ key_value_error_context
24
24
  make_key_value_error_context(std::error_code ec, const document_id& id)
25
25
  {
26
26
  return {
27
- ec, {}, {}, 0, {}, id.key(), id.bucket(), id.scope(), id.collection(), 0, {}, {}, {}, {},
27
+ {}, ec, {}, {}, 0, {}, id.key(), id.bucket(), id.scope(), id.collection(), 0, {}, {}, {}, {},
28
28
  };
29
29
  }
30
30
 
@@ -36,6 +36,7 @@ make_subdocument_error_context(const key_value_error_context& ctx,
36
36
  bool deleted)
37
37
  {
38
38
  return {
39
+ ctx.operation_id(),
39
40
  ec,
40
41
  ctx.last_dispatched_to(),
41
42
  ctx.last_dispatched_from(),
@@ -43,23 +43,21 @@ make_key_value_error_context(std::error_code ec, std::uint16_t status_code, cons
43
43
  const auto& scope = command->request.id.scope();
44
44
  const auto& bucket = command->request.id.bucket();
45
45
  std::uint32_t opaque = (ec && response.opaque() == 0) ? command->request.opaque : response.opaque();
46
- auto status = response.status();
47
- auto retry_attempts = command->request.retries.retry_attempts();
48
- auto retry_reasons = command->request.retries.retry_reasons();
49
- std::optional<std::string> last_dispatched_from{};
50
- std::optional<std::string> last_dispatched_to{};
46
+ std::optional<key_value_status_code> status{};
51
47
  std::optional<key_value_error_map_info> error_map_info{};
52
- if (command->session_) {
53
- last_dispatched_from = command->session_->local_address();
54
- last_dispatched_to = command->session_->remote_address();
55
- if (status_code) {
48
+ if (status_code != 0xffffU) {
49
+ status = response.status();
50
+ if (command->session_ && status_code > 0) {
56
51
  error_map_info = command->session_->decode_error_code(status_code);
57
52
  }
58
53
  }
54
+ auto retry_attempts = command->request.retries.retry_attempts();
55
+ auto retry_reasons = command->request.retries.retry_reasons();
59
56
 
60
- return { ec,
61
- std::move(last_dispatched_from),
62
- std::move(last_dispatched_to),
57
+ return { command->id_,
58
+ ec,
59
+ command->last_dispatched_to_,
60
+ command->last_dispatched_from_,
63
61
  retry_attempts,
64
62
  std::move(retry_reasons),
65
63
  key,
@@ -20,44 +20,116 @@
20
20
 
21
21
  #include "core/cluster.hxx"
22
22
  #include "core/operations/management/query_index_build.hxx"
23
- #include "core/operations/management/query_index_get_all_deferred.hxx"
24
- #include "core/utils/json.hxx"
23
+ #include "core/operations/management/query_index_build_deferred.hxx"
25
24
 
26
- namespace couchbase::core::impl
25
+ namespace couchbase
27
26
  {
28
27
  template<typename Response>
29
28
  static manager_error_context
30
29
  build_context(Response& resp)
31
30
  {
32
- return { resp.ctx.ec,
33
- resp.ctx.last_dispatched_to,
34
- resp.ctx.last_dispatched_from,
35
- resp.ctx.retry_attempts,
36
- std::move(resp.ctx.retry_reasons),
37
- std::move(resp.ctx.client_context_id),
38
- resp.ctx.http_status,
39
- std::move(resp.ctx.http_body),
40
- std::move(resp.ctx.path) };
31
+ return manager_error_context(internal_manager_error_context{ resp.ctx.ec,
32
+ resp.ctx.last_dispatched_to,
33
+ resp.ctx.last_dispatched_from,
34
+ resp.ctx.retry_attempts,
35
+ std::move(resp.ctx.retry_reasons),
36
+ std::move(resp.ctx.client_context_id),
37
+ resp.ctx.http_status,
38
+ std::move(resp.ctx.http_body),
39
+ std::move(resp.ctx.path) });
41
40
  }
41
+
42
+ static core::operations::management::query_index_build_request
43
+ build_build_index_request(std::string bucket_name,
44
+ core::operations::management::query_index_get_all_deferred_response list_resp,
45
+ const build_query_index_options::built& options)
46
+ {
47
+ core::operations::management::query_index_build_request request{
48
+ std::move(bucket_name), {}, {}, {}, std::move(list_resp.index_names), {}, options.timeout
49
+ };
50
+ return request;
51
+ }
52
+
53
+ static core::operations::management::query_index_get_all_deferred_request
54
+ build_get_all_request(std::string bucket_name, const build_query_index_options::built& options)
55
+ {
56
+ core::operations::management::query_index_get_all_deferred_request request{ std::move(bucket_name), {}, {}, {}, {}, options.timeout };
57
+ return request;
58
+ }
59
+
60
+ static core::operations::management::query_index_build_request
61
+ build_build_index_request(std::string bucket_name,
62
+ std::string scope_name,
63
+ std::string collection_name,
64
+ core::operations::management::query_index_get_all_deferred_response list_resp,
65
+ const build_query_index_options::built& options)
66
+ {
67
+ core::operations::management::query_index_build_request request{ "",
68
+ "",
69
+ std::move(collection_name),
70
+ core::query_context{ std::move(bucket_name), std::move(scope_name) },
71
+ std::move(list_resp.index_names),
72
+ {},
73
+ options.timeout };
74
+ return request;
75
+ }
76
+
77
+ static core::operations::management::query_index_get_all_deferred_request
78
+ build_get_all_request(std::string bucket_name,
79
+ std::string scope_name,
80
+ std::string collection_name,
81
+ const build_query_index_options::built& options)
82
+ {
83
+ core::operations::management::query_index_get_all_deferred_request request{
84
+ "", "", std::move(collection_name), core::query_context{ std::move(bucket_name), std::move(scope_name) }, {}, options.timeout
85
+ };
86
+ return request;
87
+ }
88
+
42
89
  void
43
- initiate_build_deferred_indexes(std::shared_ptr<couchbase::core::cluster> core,
44
- std::string bucket_name,
45
- build_query_index_options::built options,
46
- query_context query_ctx,
47
- std::string collection_name,
48
- build_deferred_query_indexes_handler&& handler)
90
+ query_index_manager::build_deferred_indexes(std::string bucket_name,
91
+ const couchbase::build_query_index_options& options,
92
+ couchbase::build_deferred_query_indexes_handler&& handler) const
93
+ {
94
+
95
+ auto get_all_request = build_get_all_request(bucket_name, options.build());
96
+ core_->execute(std::move(get_all_request),
97
+ [handler = std::move(handler), this, bucket_name, options](
98
+ core::operations::management::query_index_get_all_deferred_response resp1) mutable {
99
+ auto list_resp = std::move(resp1);
100
+ if (list_resp.ctx.ec) {
101
+ return handler(build_context(list_resp));
102
+ }
103
+ if (list_resp.index_names.empty()) {
104
+ return handler(build_context(list_resp));
105
+ }
106
+ auto build_request = build_build_index_request(std::move(bucket_name), list_resp, options.build());
107
+ core_->execute(
108
+ std::move(build_request),
109
+ [handler = std::move(handler)](core::operations::management::query_index_build_response resp2) mutable {
110
+ auto build_resp = std::move(resp2);
111
+ return handler(build_context(build_resp));
112
+ });
113
+ });
114
+ }
115
+
116
+ auto
117
+ query_index_manager::build_deferred_indexes(std::string bucket_name, const couchbase::build_query_index_options& options) const
118
+ -> std::future<manager_error_context>
49
119
  {
50
- core->execute(
51
- operations::management::query_index_get_all_deferred_request{
52
- bucket_name,
53
- "",
54
- collection_name,
55
- query_ctx,
56
- {},
57
- options.timeout,
58
- },
59
- [core, bucket_name, collection_name, options = std::move(options), query_ctx, handler = std::move(handler)](
60
- operations::management::query_index_get_all_deferred_response resp1) mutable {
120
+ auto barrier = std::make_shared<std::promise<manager_error_context>>();
121
+ build_deferred_indexes(std::move(bucket_name), options, [barrier](auto ctx) mutable { barrier->set_value(std::move(ctx)); });
122
+ return barrier->get_future();
123
+ }
124
+
125
+ void
126
+ collection_query_index_manager::build_deferred_indexes(const build_query_index_options& options,
127
+ build_deferred_query_indexes_handler&& handler) const
128
+ {
129
+ auto get_all_request = build_get_all_request(bucket_name_, scope_name_, collection_name_, options.build());
130
+ core_->execute(
131
+ std::move(get_all_request),
132
+ [handler = std::move(handler), this, options](core::operations::management::query_index_get_all_deferred_response resp1) mutable {
61
133
  auto list_resp = std::move(resp1);
62
134
  if (list_resp.ctx.ec) {
63
135
  return handler(build_context(list_resp));
@@ -65,28 +137,21 @@ initiate_build_deferred_indexes(std::shared_ptr<couchbase::core::cluster> core,
65
137
  if (list_resp.index_names.empty()) {
66
138
  return handler(build_context(list_resp));
67
139
  }
68
- core->execute(
69
- operations::management::query_index_build_request{
70
- std::move(bucket_name),
71
- "",
72
- collection_name,
73
- query_ctx,
74
- std::move(list_resp.index_names),
75
- {},
76
- options.timeout,
77
- },
78
- [handler = std::move(handler)](operations::management::query_index_build_response resp2) {
79
- auto build_resp = std::move(resp2);
80
- return handler(build_context(build_resp));
81
- });
140
+ auto build_request = build_build_index_request(bucket_name_, scope_name_, collection_name_, list_resp, options.build());
141
+ core_->execute(std::move(build_request),
142
+ [handler = std::move(handler)](core::operations::management::query_index_build_response resp2) mutable {
143
+ auto build_resp = std::move(resp2);
144
+ return handler(build_context(build_resp));
145
+ });
82
146
  });
83
147
  }
84
- void
85
- initiate_build_deferred_indexes(std::shared_ptr<couchbase::core::cluster> core,
86
- std::string bucket_name,
87
- build_query_index_options::built options,
88
- build_deferred_query_indexes_handler&& handler)
148
+
149
+ auto
150
+ collection_query_index_manager::build_deferred_indexes(const couchbase::build_query_index_options& options) const
151
+ -> std::future<manager_error_context>
89
152
  {
90
- return initiate_build_deferred_indexes(core, std::move(bucket_name), options, {}, "", std::move(handler));
153
+ auto barrier = std::make_shared<std::promise<manager_error_context>>();
154
+ build_deferred_indexes(options, [barrier](auto ctx) mutable { barrier->set_value(std::move(ctx)); });
155
+ return barrier->get_future();
91
156
  }
92
- } // namespace couchbase::core::impl
157
+ } // namespace couchbase
@@ -82,6 +82,9 @@ options_to_origin(const std::string& connection_string, const couchbase::cluster
82
82
  if (opts.security.trust_certificate.has_value()) {
83
83
  user_options.trust_certificate = opts.security.trust_certificate.value();
84
84
  }
85
+ if (opts.security.trust_certificate_value.has_value()) {
86
+ user_options.trust_certificate_value = opts.security.trust_certificate_value.value();
87
+ }
85
88
  switch (opts.security.tls_verify) {
86
89
  case couchbase::tls_verify_mode::none:
87
90
  user_options.tls_verify = core::tls_verify_mode::none;
@@ -91,6 +94,8 @@ options_to_origin(const std::string& connection_string, const couchbase::cluster
91
94
  break;
92
95
  }
93
96
  user_options.disable_mozilla_ca_certificates = opts.security.disable_mozilla_ca_certificates;
97
+ user_options.tls_disable_deprecated_protocols = opts.security.disable_deprecated_protocols;
98
+ user_options.tls_disable_v1_2 = opts.security.disable_tls_v1_2;
94
99
  }
95
100
 
96
101
  if (opts.dns.nameserver) {
@@ -103,6 +108,7 @@ options_to_origin(const std::string& connection_string, const couchbase::cluster
103
108
  user_options.enable_mutation_tokens = opts.behavior.enable_mutation_tokens;
104
109
  user_options.enable_unordered_execution = opts.behavior.enable_unordered_execution;
105
110
  user_options.user_agent_extra = opts.behavior.user_agent_extra;
111
+ user_options.network = opts.behavior.network;
106
112
 
107
113
  user_options.enable_tcp_keep_alive = opts.network.enable_tcp_keep_alive;
108
114
  user_options.tcp_keep_alive_interval = opts.network.tcp_keep_alive_interval;