couchbase 4.4.2 → 4.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. package/CMakeLists.txt +2 -0
  2. package/deps/couchbase-cxx-client/CMakeLists.txt +17 -14
  3. package/deps/couchbase-cxx-client/README.md +2 -2
  4. package/deps/couchbase-cxx-client/cmake/Packaging.cmake +4 -0
  5. package/deps/couchbase-cxx-client/cmake/Testing.cmake +1 -1
  6. package/deps/couchbase-cxx-client/cmake/VersionInfo.cmake +24 -2
  7. package/deps/couchbase-cxx-client/cmake/couchbase-cxx-client.spec.in +43 -4
  8. package/deps/couchbase-cxx-client/core/agent_group.cxx +8 -0
  9. package/deps/couchbase-cxx-client/core/agent_group.hxx +4 -0
  10. package/deps/couchbase-cxx-client/core/bucket.cxx +16 -20
  11. package/deps/couchbase-cxx-client/core/bucket.hxx +12 -12
  12. package/deps/couchbase-cxx-client/core/cluster.cxx +44 -52
  13. package/deps/couchbase-cxx-client/core/cluster_agent.cxx +8 -0
  14. package/deps/couchbase-cxx-client/core/cluster_agent.hxx +4 -0
  15. package/deps/couchbase-cxx-client/core/collections_component.cxx +2 -2
  16. package/deps/couchbase-cxx-client/core/columnar/agent.cxx +2 -2
  17. package/deps/couchbase-cxx-client/core/columnar/agent.hxx +1 -1
  18. package/deps/couchbase-cxx-client/core/columnar/management_component.cxx +3 -3
  19. package/deps/couchbase-cxx-client/core/columnar/query_component.cxx +103 -45
  20. package/deps/couchbase-cxx-client/core/columnar/query_component.hxx +1 -0
  21. package/deps/couchbase-cxx-client/core/free_form_http_request.hxx +8 -0
  22. package/deps/couchbase-cxx-client/core/http_component.cxx +55 -24
  23. package/deps/couchbase-cxx-client/core/http_component.hxx +4 -0
  24. package/deps/couchbase-cxx-client/core/impl/analytics_index_manager.cxx +15 -15
  25. package/deps/couchbase-cxx-client/core/impl/bootstrap_error.hxx +10 -2
  26. package/deps/couchbase-cxx-client/core/impl/bucket.cxx +1 -1
  27. package/deps/couchbase-cxx-client/core/impl/bucket_manager.cxx +6 -6
  28. package/deps/couchbase-cxx-client/core/impl/cluster.cxx +36 -40
  29. package/deps/couchbase-cxx-client/core/impl/collection.cxx +2 -2
  30. package/deps/couchbase-cxx-client/core/impl/collection_manager.cxx +5 -5
  31. package/deps/couchbase-cxx-client/core/impl/observe_poll.cxx +13 -5
  32. package/deps/couchbase-cxx-client/core/impl/observe_poll.hxx +1 -3
  33. package/deps/couchbase-cxx-client/core/impl/query_index_manager.cxx +6 -6
  34. package/deps/couchbase-cxx-client/core/impl/scan_result.cxx +1 -1
  35. package/deps/couchbase-cxx-client/core/impl/search_index_manager.cxx +12 -12
  36. package/deps/couchbase-cxx-client/core/io/http_command.hxx +31 -20
  37. package/deps/couchbase-cxx-client/core/io/http_session.cxx +5 -0
  38. package/deps/couchbase-cxx-client/core/io/http_session.hxx +17 -4
  39. package/deps/couchbase-cxx-client/core/io/http_session_manager.hxx +97 -49
  40. package/deps/couchbase-cxx-client/core/io/mcbp_command.hxx +15 -14
  41. package/deps/couchbase-cxx-client/core/io/mcbp_session.cxx +48 -33
  42. package/deps/couchbase-cxx-client/core/io/streams.cxx +256 -0
  43. package/deps/couchbase-cxx-client/core/io/streams.hxx +31 -155
  44. package/deps/couchbase-cxx-client/core/logger/configuration.hxx +5 -0
  45. package/deps/couchbase-cxx-client/core/logger/custom_rotating_file_sink.cxx +2 -3
  46. package/deps/couchbase-cxx-client/core/logger/logger.cxx +39 -7
  47. package/deps/couchbase-cxx-client/core/logger/logger.hxx +7 -0
  48. package/deps/couchbase-cxx-client/core/metrics/meter_wrapper.cxx +188 -0
  49. package/deps/couchbase-cxx-client/core/metrics/meter_wrapper.hxx +73 -0
  50. package/deps/couchbase-cxx-client/core/operations/management/bucket_describe.cxx +2 -1
  51. package/deps/couchbase-cxx-client/core/operations/management/bucket_drop.cxx +3 -1
  52. package/deps/couchbase-cxx-client/core/operations/management/bucket_flush.cxx +3 -1
  53. package/deps/couchbase-cxx-client/core/operations/management/bucket_get.cxx +3 -1
  54. package/deps/couchbase-cxx-client/core/operations/management/bucket_update.cxx +3 -1
  55. package/deps/couchbase-cxx-client/core/operations/management/collection_create.cxx +3 -2
  56. package/deps/couchbase-cxx-client/core/operations/management/collection_drop.cxx +5 -2
  57. package/deps/couchbase-cxx-client/core/operations/management/collection_update.cxx +4 -2
  58. package/deps/couchbase-cxx-client/core/operations/management/group_upsert.cxx +3 -3
  59. package/deps/couchbase-cxx-client/core/operations/management/scope_create.cxx +2 -1
  60. package/deps/couchbase-cxx-client/core/operations/management/scope_drop.cxx +4 -1
  61. package/deps/couchbase-cxx-client/core/operations/management/scope_get_all.cxx +3 -1
  62. package/deps/couchbase-cxx-client/core/operations/management/search_index_analyze_document.cxx +3 -2
  63. package/deps/couchbase-cxx-client/core/operations/management/search_index_control_ingest.cxx +3 -2
  64. package/deps/couchbase-cxx-client/core/operations/management/search_index_control_plan_freeze.cxx +3 -2
  65. package/deps/couchbase-cxx-client/core/operations/management/search_index_control_query.cxx +3 -2
  66. package/deps/couchbase-cxx-client/core/operations/management/search_index_drop.cxx +5 -2
  67. package/deps/couchbase-cxx-client/core/operations/management/search_index_get.cxx +5 -2
  68. package/deps/couchbase-cxx-client/core/operations/management/search_index_get_all.cxx +4 -2
  69. package/deps/couchbase-cxx-client/core/operations/management/search_index_get_documents_count.cxx +3 -2
  70. package/deps/couchbase-cxx-client/core/operations/management/search_index_upsert.cxx +5 -2
  71. package/deps/couchbase-cxx-client/core/operations/management/view_index_drop.cxx +2 -1
  72. package/deps/couchbase-cxx-client/core/operations/management/view_index_get.cxx +2 -1
  73. package/deps/couchbase-cxx-client/core/operations/management/view_index_get_all.cxx +3 -1
  74. package/deps/couchbase-cxx-client/core/operations/management/view_index_upsert.cxx +2 -1
  75. package/deps/couchbase-cxx-client/core/origin.cxx +37 -17
  76. package/deps/couchbase-cxx-client/core/platform/base64.cc +1 -1
  77. package/deps/couchbase-cxx-client/core/platform/random.cc +2 -0
  78. package/deps/couchbase-cxx-client/core/platform/uuid.h +6 -6
  79. package/deps/couchbase-cxx-client/core/row_streamer.cxx +1 -1
  80. package/deps/couchbase-cxx-client/core/sasl/scram-sha/stringutils.cc +1 -1
  81. package/deps/couchbase-cxx-client/core/sasl/scram-sha/stringutils.h +4 -4
  82. package/deps/couchbase-cxx-client/core/topology/configuration.hxx +2 -0
  83. package/deps/couchbase-cxx-client/core/topology/configuration_json.hxx +8 -0
  84. package/deps/couchbase-cxx-client/core/tracing/constants.hxx +3 -0
  85. package/deps/couchbase-cxx-client/core/tracing/tracer_wrapper.cxx +87 -0
  86. package/deps/couchbase-cxx-client/core/tracing/tracer_wrapper.hxx +57 -0
  87. package/deps/couchbase-cxx-client/core/transactions/attempt_context_impl.cxx +16 -15
  88. package/deps/couchbase-cxx-client/core/transactions/attempt_context_impl.hxx +2 -2
  89. package/deps/couchbase-cxx-client/core/transactions/staged_mutation.cxx +2 -2
  90. package/deps/couchbase-cxx-client/core/transactions/transactions.cxx +2 -2
  91. package/deps/couchbase-cxx-client/core/utils/connection_string.cxx +128 -52
  92. package/deps/couchbase-cxx-client/couchbase/analytics_options.hxx +4 -3
  93. package/deps/couchbase-cxx-client/couchbase/codec/tao_json_serializer.hxx +1 -1
  94. package/deps/couchbase-cxx-client/couchbase/mutate_in_specs.hxx +2 -2
  95. package/deps/couchbase-cxx-client/couchbase/query_options.hxx +4 -3
  96. package/deps/couchbase-cxx-client/couchbase/search_options.hxx +1 -1
  97. package/package.json +8 -8
  98. package/src/binding.cpp +13 -13
@@ -24,10 +24,11 @@
24
24
  #include "core/columnar/bootstrap_notification_subscriber.hxx"
25
25
  #endif
26
26
  #include "core/logger/logger.hxx"
27
+ #include "core/metrics/meter_wrapper.hxx"
27
28
  #include "core/operations/http_noop.hxx"
28
29
  #include "core/service_type.hxx"
29
30
  #include "core/tracing/noop_tracer.hxx"
30
- #include "couchbase/metrics/meter.hxx"
31
+ #include "core/tracing/tracer_wrapper.hxx"
31
32
  #include "http_command.hxx"
32
33
  #include "http_context.hxx"
33
34
  #include "http_session.hxx"
@@ -63,12 +64,12 @@ public:
63
64
  {
64
65
  }
65
66
 
66
- void set_tracer(std::shared_ptr<couchbase::tracing::request_tracer> tracer)
67
+ void set_tracer(std::shared_ptr<tracing::tracer_wrapper> tracer)
67
68
  {
68
69
  tracer_ = std::move(tracer);
69
70
  }
70
71
 
71
- void set_meter(std::shared_ptr<couchbase::metrics::meter> meter)
72
+ void set_meter(std::shared_ptr<metrics::meter_wrapper> meter)
72
73
  {
73
74
  meter_ = std::move(meter);
74
75
  }
@@ -91,6 +92,7 @@ public:
91
92
  if (allow_fast_fail_) {
92
93
  std::scoped_lock bootstrap_error_lock(last_bootstrap_error_mutex_);
93
94
  last_bootstrap_error_ = error;
95
+ drain_deferred_queue(last_bootstrap_error_.value());
94
96
  }
95
97
  }
96
98
 
@@ -222,14 +224,19 @@ public:
222
224
  ctx_, request, tracer_, meter_, options_.default_timeout_for(request.type));
223
225
  #endif
224
226
 
225
- cmd->start(
226
- [start = std::chrono::steady_clock::now(),
227
- self = shared_from_this(),
228
- type,
229
- cmd,
230
- handler = collector->build_reporter()](std::error_code ec, io::http_response&& msg) {
231
- diag::ping_state state = diag::ping_state::ok;
232
- std::optional<std::string> error{};
227
+ cmd->start([start = std::chrono::steady_clock::now(),
228
+ self = shared_from_this(),
229
+ type,
230
+ cmd,
231
+ #ifdef COUCHBASE_CXX_CLIENT_COLUMNAR
232
+ handler = collector->build_reporter()](error_union err,
233
+ io::http_response&& msg) {
234
+ diag::ping_state state = diag::ping_state::ok;
235
+ std::optional<std::string> error{};
236
+ if (!std::holds_alternative<std::monostate>(err)) {
237
+ auto ec = std::holds_alternative<impl::bootstrap_error>(err)
238
+ ? std::get<impl::bootstrap_error>(err).ec
239
+ : std::get<std::error_code>(err);
233
240
  if (ec) {
234
241
  if (ec == errc::common::unambiguous_timeout ||
235
242
  ec == errc::common::ambiguous_timeout) {
@@ -240,25 +247,42 @@ public:
240
247
  error.emplace(fmt::format(
241
248
  "code={}, message={}, http_code={}", ec.value(), ec.message(), msg.status_code));
242
249
  }
243
- auto remote_address = cmd->session_->remote_address();
244
- // If not connected, the remote address will be empty. Better to
245
- // give the user some context on the "attempted" remote address.
246
- if (remote_address.empty()) {
247
- remote_address =
248
- fmt::format("{}:{}", cmd->session_->hostname(), cmd->session_->port());
250
+ }
251
+ #else
252
+ handler = collector->build_reporter()](std::error_code ec,
253
+ io::http_response&& msg) {
254
+ diag::ping_state state = diag::ping_state::ok;
255
+ std::optional<std::string> error{};
256
+ if (ec) {
257
+ if (ec == errc::common::unambiguous_timeout ||
258
+ ec == errc::common::ambiguous_timeout) {
259
+ state = diag::ping_state::timeout;
260
+ } else {
261
+ state = diag::ping_state::error;
249
262
  }
250
- handler->report(
251
- diag::endpoint_ping_info{ type,
252
- cmd->session_->id(),
253
- std::chrono::duration_cast<std::chrono::microseconds>(
254
- std::chrono::steady_clock::now() - start),
255
- remote_address,
256
- cmd->session_->local_address(),
257
- state,
258
- {},
259
- error });
260
- self->check_in(type, cmd->session_);
261
- });
263
+ error.emplace(fmt::format(
264
+ "code={}, message={}, http_code={}", ec.value(), ec.message(), msg.status_code));
265
+ }
266
+ #endif
267
+ auto remote_address = cmd->session_->remote_address();
268
+ // If not connected, the remote address will be empty. Better to
269
+ // give the user some context on the "attempted" remote address.
270
+ if (remote_address.empty()) {
271
+ remote_address =
272
+ fmt::format("{}:{}", cmd->session_->hostname(), cmd->session_->port());
273
+ }
274
+ handler->report(
275
+ diag::endpoint_ping_info{ type,
276
+ cmd->session_->id(),
277
+ std::chrono::duration_cast<std::chrono::microseconds>(
278
+ std::chrono::steady_clock::now() - start),
279
+ remote_address,
280
+ cmd->session_->local_address(),
281
+ state,
282
+ {},
283
+ error });
284
+ self->check_in(type, cmd->session_);
285
+ });
262
286
  cmd->set_command_session(session);
263
287
  if (!session->is_connected()) {
264
288
  connect_then_send(session, cmd, {}, true);
@@ -450,18 +474,37 @@ public:
450
474
  meter_,
451
475
  options_.default_timeout_for(request.type),
452
476
  dispatch_timeout_);
477
+ cmd->start([self = shared_from_this(), cmd, handler = std::forward<Handler>(handler)](
478
+ error_union err, io::http_response&& msg) mutable {
453
479
  #else
454
480
  auto cmd = std::make_shared<operations::http_command<Request>>(
455
481
  ctx_, request, tracer_, meter_, options_.default_timeout_for(request.type));
456
- #endif
457
482
  cmd->start([self = shared_from_this(), cmd, handler = std::forward<Handler>(handler)](
458
483
  std::error_code ec, io::http_response&& msg) mutable {
484
+ #endif
459
485
  using command_type = typename decltype(cmd)::element_type;
460
486
  using encoded_response_type = typename command_type::encoded_response_type;
461
487
  using error_context_type = typename command_type::error_context_type;
462
488
  encoded_response_type resp{ std::move(msg) };
463
489
  error_context_type ctx{};
490
+ #ifdef COUCHBASE_CXX_CLIENT_COLUMNAR
491
+ if (!std::holds_alternative<std::monostate>(err)) {
492
+ if (std::holds_alternative<impl::bootstrap_error>(err)) {
493
+ auto bootstrap_error = std::get<impl::bootstrap_error>(err);
494
+ if (bootstrap_error.ec == errc::common::unambiguous_timeout) {
495
+ CB_LOG_DEBUG("Timeout caused by bootstrap error. code={}, ec_message={}, message={}.",
496
+ bootstrap_error.ec.value(),
497
+ bootstrap_error.ec.message(),
498
+ bootstrap_error.error_message);
499
+ }
500
+ ctx.ec = bootstrap_error.ec;
501
+ } else {
502
+ ctx.ec = std::get<std::error_code>(err);
503
+ }
504
+ }
505
+ #else
464
506
  ctx.ec = ec;
507
+ #endif
465
508
  ctx.client_context_id = cmd->client_context_id_;
466
509
  ctx.method = cmd->encoded.method;
467
510
  ctx.path = cmd->encoded.path;
@@ -584,7 +627,7 @@ public:
584
627
  }
585
628
 
586
629
  #ifdef COUCHBASE_CXX_CLIENT_COLUMNAR
587
- void add_to_deferred_queue(utils::movable_function<void(std::error_code)> command)
630
+ void add_to_deferred_queue(utils::movable_function<void(error_union)> command)
588
631
  {
589
632
  const std::scoped_lock lock_for_deferred_commands(deferred_commands_mutex_);
590
633
  deferred_commands_.emplace(std::move(command));
@@ -723,20 +766,25 @@ private:
723
766
  options_.default_timeout_for(request.type),
724
767
  dispatch_timeout_);
725
768
  cmd->start([self = shared_from_this(), cmd, handler = std::forward<Handler>(handler)](
726
- std::error_code ec, io::http_response&& msg) mutable {
769
+ error_union err, io::http_response&& msg) mutable {
727
770
  using command_type = typename decltype(cmd)::element_type;
728
771
  using encoded_response_type = typename command_type::encoded_response_type;
729
772
  using error_context_type = typename command_type::error_context_type;
730
773
  encoded_response_type resp{ std::move(msg) };
731
774
  error_context_type ctx{};
732
- if (self->last_bootstrap_error_.has_value() && ec == errc::common::unambiguous_timeout) {
733
- CB_LOG_DEBUG("Timeout caused by bootstrap error. code={}, ec_message={}, message={}.",
734
- self->last_bootstrap_error_.value().ec.value(),
735
- self->last_bootstrap_error_.value().ec.message(),
736
- self->last_bootstrap_error_.value().error_message);
737
- ctx.ec = self->last_bootstrap_error_.value().ec;
738
- } else {
739
- ctx.ec = ec;
775
+ if (!std::holds_alternative<std::monostate>(err)) {
776
+ if (std::holds_alternative<impl::bootstrap_error>(err)) {
777
+ auto bootstrap_error = std::get<impl::bootstrap_error>(err);
778
+ if (bootstrap_error.ec == errc::common::unambiguous_timeout) {
779
+ CB_LOG_DEBUG("Timeout caused by bootstrap error. code={}, ec_message={}, message={}.",
780
+ bootstrap_error.ec.value(),
781
+ bootstrap_error.ec.message(),
782
+ bootstrap_error.error_message);
783
+ }
784
+ ctx.ec = bootstrap_error.ec;
785
+ } else {
786
+ ctx.ec = std::get<std::error_code>(err);
787
+ }
740
788
  }
741
789
  ctx.client_context_id = cmd->client_context_id_;
742
790
  ctx.method = cmd->encoded.method;
@@ -756,10 +804,10 @@ private:
756
804
  cmd->request.type,
757
805
  cmd->client_context_id_);
758
806
  add_to_deferred_queue(
759
- [self = shared_from_this(), cmd, request, credentials](std::error_code ec) mutable {
760
- if (ec) {
807
+ [self = shared_from_this(), cmd, request, credentials](error_union err) mutable {
808
+ if (!std::holds_alternative<std::monostate>(err)) {
761
809
  using response_type = typename Request::encoded_response_type;
762
- return cmd->invoke_handler(ec, response_type{});
810
+ return cmd->invoke_handler(err, response_type{});
763
811
  }
764
812
 
765
813
  // don't do anything if the command wasn't dispatched or has already timed out
@@ -787,9 +835,9 @@ private:
787
835
  });
788
836
  }
789
837
 
790
- void drain_deferred_queue(std::error_code ec)
838
+ void drain_deferred_queue(error_union err)
791
839
  {
792
- std::queue<utils::movable_function<void(std::error_code)>> commands{};
840
+ std::queue<utils::movable_function<void(error_union)>> commands{};
793
841
  {
794
842
  const std::scoped_lock lock(deferred_commands_mutex_);
795
843
  std::swap(deferred_commands_, commands);
@@ -798,7 +846,7 @@ private:
798
846
  CB_LOG_TRACE("Draining deferred operation queue, size={}", commands.size());
799
847
  }
800
848
  while (!commands.empty()) {
801
- commands.front()(ec);
849
+ commands.front()(err);
802
850
  commands.pop();
803
851
  }
804
852
  }
@@ -881,8 +929,8 @@ private:
881
929
  std::string client_id_;
882
930
  asio::io_context& ctx_;
883
931
  asio::ssl::context& tls_;
884
- std::shared_ptr<couchbase::tracing::request_tracer> tracer_{ nullptr };
885
- std::shared_ptr<couchbase::metrics::meter> meter_{ nullptr };
932
+ std::shared_ptr<tracing::tracer_wrapper> tracer_{ nullptr };
933
+ std::shared_ptr<metrics::meter_wrapper> meter_{ nullptr };
886
934
  cluster_options options_{};
887
935
 
888
936
  topology::configuration config_{};
@@ -898,7 +946,7 @@ private:
898
946
  std::atomic_bool configured_{ false };
899
947
  std::chrono::milliseconds dispatch_timeout_{};
900
948
  std::atomic_bool allow_fast_fail_{ true };
901
- std::queue<utils::movable_function<void(std::error_code)>> deferred_commands_{};
949
+ std::queue<utils::movable_function<void(error_union)>> deferred_commands_{};
902
950
  std::mutex deferred_commands_mutex_{};
903
951
  std::optional<impl::bootstrap_error> last_bootstrap_error_;
904
952
  std::mutex last_bootstrap_error_mutex_{};
@@ -18,6 +18,8 @@
18
18
  #pragma once
19
19
 
20
20
  #include "core/document_id_fmt.hxx"
21
+ #include "core/error_context/key_value_error_map_info.hxx"
22
+ #include "core/metrics/meter_wrapper.hxx"
21
23
  #include "core/platform/uuid.h"
22
24
  #include "core/protocol/client_request.hxx"
23
25
  #include "core/protocol/client_response.hxx"
@@ -30,7 +32,6 @@
30
32
  #include "mcbp_traits.hxx"
31
33
  #include "retry_orchestrator.hxx"
32
34
 
33
- #include "core/error_context/key_value_error_map_info.hxx"
34
35
  #include <couchbase/durability_level.hxx>
35
36
  #include <couchbase/error_codes.hxx>
36
37
 
@@ -98,12 +99,12 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
98
99
 
99
100
  void start(mcbp_command_handler&& handler)
100
101
  {
101
- span_ = manager_->tracer()->start_span(
102
+ span_ = manager_->tracer()->create_span(
102
103
  tracing::span_name_for_mcbp_command(encoded_request_type::body_type::opcode), parent_span);
103
- if (span_->uses_tags())
104
+ if (span_->uses_tags()) {
104
105
  span_->add_tag(tracing::attributes::service, tracing::service::key_value);
105
- if (span_->uses_tags())
106
106
  span_->add_tag(tracing::attributes::instance, request.id.bucket());
107
+ }
107
108
 
108
109
  handler_ = std::move(handler);
109
110
  deadline.expires_after(timeout_);
@@ -223,8 +224,9 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
223
224
  {
224
225
  opaque_ = session_->next_opaque();
225
226
  request.opaque = *opaque_;
226
- if (span_->uses_tags())
227
+ if (span_->uses_tags()) {
227
228
  span_->add_tag(tracing::attributes::operation_id, fmt::format("0x{:x}", request.opaque));
229
+ }
228
230
  if (request.id.use_collections() && !request.id.is_collection_resolved()) {
229
231
  if (session_->supports_feature(protocol::hello_feature::collections)) {
230
232
  auto collection_id = session_->get_collection_uid(request.id.collection_path());
@@ -265,16 +267,15 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
265
267
  retry_reason reason,
266
268
  io::mcbp_message&& msg,
267
269
  std::optional<key_value_error_map_info> /* error_info */) mutable {
268
- static std::string meter_name = "db.couchbase.operations";
269
- static std::map<std::string, std::string> tags = {
270
- { "db.couchbase.service", "kv" },
271
- { "db.operation", fmt::format("{}", encoded_request_type::body_type::opcode) },
270
+ metrics::metric_attributes attrs{
271
+ service_type::key_value,
272
+ fmt::format("{}", encoded_request_type::body_type::opcode),
273
+ ec,
274
+ self->request.id.bucket(),
275
+ self->request.id.scope(),
276
+ self->request.id.collection(),
272
277
  };
273
- self->manager_->meter()
274
- ->get_value_recorder(meter_name, tags)
275
- ->record_value(std::chrono::duration_cast<std::chrono::microseconds>(
276
- std::chrono::steady_clock::now() - start)
277
- .count());
278
+ self->manager_->meter()->record_value(std::move(attrs), start);
278
279
 
279
280
  self->retry_backoff.cancel();
280
281
  if (ec == asio::error::operation_aborted) {
@@ -1084,20 +1084,20 @@ public:
1084
1084
  return;
1085
1085
  }
1086
1086
  bootstrapped_ = false;
1087
- if (bootstrap_handler_) {
1088
- last_bootstrap_error_ = std::move(bootstrap_handler_)->last_bootstrap_error();
1087
+ if (auto handler = std::move(bootstrap_handler_); handler) {
1088
+ last_bootstrap_error_ = handler->last_bootstrap_error();
1089
1089
  }
1090
- bootstrap_handler_ = nullptr;
1091
1090
  state_ = diag::endpoint_state::connecting;
1092
1091
  if (stream_->is_open()) {
1093
- std::string old_id = stream_->id();
1094
- stream_->reopen();
1095
- CB_LOG_TRACE(R"({} reopen socket connection "{}" -> "{}", host="{}", port={})",
1096
- log_prefix_,
1097
- old_id,
1098
- stream_->id(),
1099
- bootstrap_hostname_,
1100
- bootstrap_port_);
1092
+ return stream_->close([self = shared_from_this(), old_id = stream_->id()](std::error_code) {
1093
+ CB_LOG_DEBUG(R"({} reopened socket connection "{}" -> "{}", host="{}", port={})",
1094
+ self->log_prefix_,
1095
+ old_id,
1096
+ self->stream_->id(),
1097
+ self->bootstrap_hostname_,
1098
+ self->bootstrap_port_);
1099
+ return self->initiate_bootstrap();
1100
+ });
1101
1101
  }
1102
1102
  if (origin_.exhausted()) {
1103
1103
  #ifdef COUCHBASE_CXX_CLIENT_COLUMNAR
@@ -1174,6 +1174,20 @@ public:
1174
1174
  if (stopped_) {
1175
1175
  return;
1176
1176
  }
1177
+
1178
+ if (reason == retry_reason::socket_closed_while_in_flight && !bootstrapped_) {
1179
+ return stream_->close([self = shared_from_this(), old_id = stream_->id()](std::error_code) {
1180
+ CB_LOG_DEBUG(
1181
+ R"({} reopened socket connection due to IO error, "{}" -> "{}", host="{}", port={})",
1182
+ self->log_prefix_,
1183
+ old_id,
1184
+ self->stream_->id(),
1185
+ self->bootstrap_hostname_,
1186
+ self->bootstrap_port_);
1187
+ return self->initiate_bootstrap();
1188
+ });
1189
+ }
1190
+
1177
1191
  state_ = diag::endpoint_state::disconnecting;
1178
1192
  CB_LOG_DEBUG("{} stop MCBP connection, reason={}", log_prefix_, reason);
1179
1193
  stopped_ = true;
@@ -1653,6 +1667,7 @@ public:
1653
1667
  private:
1654
1668
  void invoke_bootstrap_handler(std::error_code ec)
1655
1669
  {
1670
+ connection_deadline_.cancel();
1656
1671
  retry_backoff_.cancel();
1657
1672
 
1658
1673
  if (ec && state_listener_) {
@@ -1716,6 +1731,7 @@ private:
1716
1731
  if (ec == asio::error::operation_aborted || stopped_) {
1717
1732
  return;
1718
1733
  }
1734
+ connection_deadline_.cancel();
1719
1735
  last_active_ = std::chrono::steady_clock::now();
1720
1736
  if (ec) {
1721
1737
  CB_LOG_ERROR("{} error on resolve: {} ({})", log_prefix_, ec.value(), ec.message());
@@ -1734,9 +1750,7 @@ private:
1734
1750
  if (timer_ec == asio::error::operation_aborted || self->stopped_) {
1735
1751
  return;
1736
1752
  }
1737
- return self->stream_->close([self](std::error_code) {
1738
- self->initiate_bootstrap();
1739
- });
1753
+ self->initiate_bootstrap();
1740
1754
  });
1741
1755
  }
1742
1756
 
@@ -1768,12 +1782,7 @@ private:
1768
1782
  port,
1769
1783
  self->bootstrap_hostname_,
1770
1784
  self->bootstrap_port_);
1771
- return self->stream_->close([self](std::error_code ec) {
1772
- self->last_bootstrap_error_ = {
1773
- ec, ec.message(), self->bootstrap_hostname_, self->bootstrap_port_
1774
- };
1775
- self->initiate_bootstrap();
1776
- });
1785
+ self->initiate_bootstrap();
1777
1786
  });
1778
1787
  stream_->async_connect(it->endpoint(), [capture0 = shared_from_this(), it](auto&& PH1) {
1779
1788
  capture0->on_connect(std::forward<decltype(PH1)>(PH1), it);
@@ -1801,6 +1810,7 @@ private:
1801
1810
  if (ec == asio::error::operation_aborted || stopped_) {
1802
1811
  return;
1803
1812
  }
1813
+ connection_deadline_.cancel();
1804
1814
  last_active_ = std::chrono::steady_clock::now();
1805
1815
  if (!stream_->is_open() || ec) {
1806
1816
  #ifdef COUCHBASE_CXX_CLIENT_STATIC_BORINGSSL
@@ -1853,23 +1863,26 @@ private:
1853
1863
  connection_endpoints_.remote_address,
1854
1864
  connection_endpoints_.remote.port());
1855
1865
  parser_.reset();
1866
+ {
1867
+ const std::scoped_lock lock(output_buffer_mutex_);
1868
+ output_buffer_.clear();
1869
+ }
1856
1870
  bootstrap_handler_ = std::make_shared<bootstrap_handler>(shared_from_this());
1857
- connection_deadline_.cancel();
1858
- }
1859
- }
1860
1871
 
1861
- void check_deadline(std::error_code ec)
1862
- {
1863
- if (ec == asio::error::operation_aborted || stopped_) {
1864
- return;
1865
- }
1866
- if (connection_deadline_.expiry() <= asio::steady_timer::clock_type::now()) {
1867
- stream_->close([](std::error_code) {
1872
+ connection_deadline_.expires_after(origin_.options().key_value_timeout);
1873
+ connection_deadline_.async_wait([self = shared_from_this()](const auto timer_ec) {
1874
+ if (timer_ec == asio::error::operation_aborted || self->stopped_) {
1875
+ return;
1876
+ }
1877
+ CB_LOG_DEBUG("{} unable to boostrap single node at {}:{} (\"{}:{}\") in time, reconnecting",
1878
+ self->log_prefix_,
1879
+ self->connection_endpoints_.remote_address,
1880
+ self->connection_endpoints_.remote.port(),
1881
+ self->bootstrap_hostname_,
1882
+ self->bootstrap_port_);
1883
+ return self->initiate_bootstrap();
1868
1884
  });
1869
1885
  }
1870
- connection_deadline_.async_wait([capture0 = shared_from_this()](auto&& PH1) {
1871
- capture0->check_deadline(std::forward<decltype(PH1)>(PH1));
1872
- });
1873
1886
  }
1874
1887
 
1875
1888
  void do_read()
@@ -1883,6 +1896,7 @@ private:
1883
1896
  [self = shared_from_this(), stream_id = stream_->id()](std::error_code ec,
1884
1897
  std::size_t bytes_transferred) {
1885
1898
  if (ec == asio::error::operation_aborted || self->stopped_) {
1899
+ self->reading_ = false;
1886
1900
  CB_LOG_PROTOCOL("[MCBP, IN] host=\"{}\", port={}, rc={}, bytes_received={}",
1887
1901
  self->connection_endpoints_.remote_address,
1888
1902
  self->connection_endpoints_.remote.port(),
@@ -1901,6 +1915,7 @@ private:
1901
1915
 
1902
1916
  self->last_active_ = std::chrono::steady_clock::now();
1903
1917
  if (ec) {
1918
+ self->reading_ = false;
1904
1919
  if (stream_id != self->stream_->id()) {
1905
1920
  CB_LOG_ERROR(
1906
1921
  R"({} ignore IO error while reading from the socket: {} ({}), old_id="{}", new_id="{}")",