couchbase 4.2.5 → 4.2.6-dev.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. package/deps/couchbase-cxx-client/CMakeLists.txt +9 -1
  2. package/deps/couchbase-cxx-client/bin/api.rb +234 -0
  3. package/deps/couchbase-cxx-client/bin/create-search-index +18 -135
  4. package/deps/couchbase-cxx-client/bin/init-cluster +17 -139
  5. package/deps/couchbase-cxx-client/bin/load-sample-buckets +54 -0
  6. package/deps/couchbase-cxx-client/core/cluster.hxx +33 -12
  7. package/deps/couchbase-cxx-client/core/cluster_options.hxx +3 -0
  8. package/deps/couchbase-cxx-client/core/crud_component.cxx +51 -22
  9. package/deps/couchbase-cxx-client/core/impl/build_deferred_query_indexes.cxx +115 -50
  10. package/deps/couchbase-cxx-client/core/impl/cluster.cxx +6 -0
  11. package/deps/couchbase-cxx-client/core/impl/create_bucket.cxx +155 -0
  12. package/deps/couchbase-cxx-client/core/impl/create_query_index.cxx +172 -59
  13. package/deps/couchbase-cxx-client/core/impl/dns_srv_tracker.cxx +2 -1
  14. package/deps/couchbase-cxx-client/core/impl/drop_bucket.cxx +66 -0
  15. package/deps/couchbase-cxx-client/core/impl/drop_query_index.cxx +138 -59
  16. package/deps/couchbase-cxx-client/core/impl/flush_bucket.cxx +66 -0
  17. package/deps/couchbase-cxx-client/core/impl/get_all_buckets.cxx +163 -0
  18. package/deps/couchbase-cxx-client/core/impl/get_all_query_indexes.cxx +67 -37
  19. package/deps/couchbase-cxx-client/core/impl/get_bucket.cxx +153 -0
  20. package/deps/couchbase-cxx-client/core/impl/internal_manager_error_context.cxx +113 -0
  21. package/deps/couchbase-cxx-client/core/impl/internal_manager_error_context.hxx +60 -0
  22. package/deps/couchbase-cxx-client/core/impl/key_value_error_category.cxx +2 -4
  23. package/deps/couchbase-cxx-client/core/impl/manager_error_context.cxx +100 -0
  24. package/deps/couchbase-cxx-client/core/impl/query.cxx +1 -0
  25. package/deps/couchbase-cxx-client/core/impl/update_bucket.cxx +130 -0
  26. package/deps/couchbase-cxx-client/core/impl/watch_query_indexes.cxx +53 -29
  27. package/deps/couchbase-cxx-client/core/io/dns_client.cxx +71 -38
  28. package/deps/couchbase-cxx-client/core/io/dns_config.cxx +5 -4
  29. package/deps/couchbase-cxx-client/core/io/mcbp_session.cxx +5 -6
  30. package/deps/couchbase-cxx-client/core/meta/features.hxx +6 -0
  31. package/deps/couchbase-cxx-client/core/operations/document_query.cxx +11 -0
  32. package/deps/couchbase-cxx-client/core/operations/document_query.hxx +1 -0
  33. package/deps/couchbase-cxx-client/core/origin.cxx +270 -0
  34. package/deps/couchbase-cxx-client/core/origin.hxx +2 -0
  35. package/deps/couchbase-cxx-client/core/protocol/status.cxx +2 -2
  36. package/deps/couchbase-cxx-client/core/range_scan_options.cxx +3 -27
  37. package/deps/couchbase-cxx-client/core/range_scan_options.hxx +13 -17
  38. package/deps/couchbase-cxx-client/core/range_scan_orchestrator.cxx +367 -170
  39. package/deps/couchbase-cxx-client/core/range_scan_orchestrator.hxx +13 -2
  40. package/deps/couchbase-cxx-client/core/range_scan_orchestrator_options.hxx +5 -3
  41. package/deps/couchbase-cxx-client/core/scan_options.hxx +0 -19
  42. package/deps/couchbase-cxx-client/core/scan_result.cxx +19 -5
  43. package/deps/couchbase-cxx-client/core/scan_result.hxx +5 -2
  44. package/deps/couchbase-cxx-client/core/timeout_defaults.hxx +2 -3
  45. package/deps/couchbase-cxx-client/core/topology/capabilities.hxx +1 -0
  46. package/deps/couchbase-cxx-client/core/topology/capabilities_fmt.hxx +2 -0
  47. package/deps/couchbase-cxx-client/core/topology/collections_manifest_fmt.hxx +1 -1
  48. package/deps/couchbase-cxx-client/core/topology/configuration.hxx +5 -0
  49. package/deps/couchbase-cxx-client/core/topology/configuration_json.hxx +2 -0
  50. package/deps/couchbase-cxx-client/core/utils/connection_string.cxx +4 -0
  51. package/deps/couchbase-cxx-client/couchbase/behavior_options.hxx +19 -2
  52. package/deps/couchbase-cxx-client/couchbase/bucket_manager.hxx +135 -0
  53. package/deps/couchbase-cxx-client/couchbase/build_query_index_options.hxx +0 -30
  54. package/deps/couchbase-cxx-client/couchbase/cluster.hxx +14 -0
  55. package/deps/couchbase-cxx-client/couchbase/collection_query_index_manager.hxx +7 -48
  56. package/deps/couchbase-cxx-client/couchbase/create_bucket_options.hxx +41 -0
  57. package/deps/couchbase-cxx-client/couchbase/create_primary_query_index_options.hxx +0 -29
  58. package/deps/couchbase-cxx-client/couchbase/create_query_index_options.hxx +0 -33
  59. package/deps/couchbase-cxx-client/couchbase/drop_bucket_options.hxx +41 -0
  60. package/deps/couchbase-cxx-client/couchbase/drop_primary_query_index_options.hxx +0 -30
  61. package/deps/couchbase-cxx-client/couchbase/drop_query_index_options.hxx +0 -31
  62. package/deps/couchbase-cxx-client/couchbase/error_codes.hxx +1 -2
  63. package/deps/couchbase-cxx-client/couchbase/flush_bucket_options.hxx +41 -0
  64. package/deps/couchbase-cxx-client/couchbase/get_all_buckets_options.hxx +44 -0
  65. package/deps/couchbase-cxx-client/couchbase/get_all_query_indexes_options.hxx +0 -30
  66. package/deps/couchbase-cxx-client/couchbase/get_bucket_options.hxx +43 -0
  67. package/deps/couchbase-cxx-client/couchbase/management/bucket_settings.hxx +116 -0
  68. package/deps/couchbase-cxx-client/couchbase/manager_error_context.hxx +29 -53
  69. package/deps/couchbase-cxx-client/couchbase/query_index_manager.hxx +16 -83
  70. package/deps/couchbase-cxx-client/couchbase/query_options.hxx +18 -0
  71. package/deps/couchbase-cxx-client/couchbase/security_options.hxx +15 -0
  72. package/deps/couchbase-cxx-client/couchbase/update_bucket_options.hxx +41 -0
  73. package/deps/couchbase-cxx-client/couchbase/watch_query_indexes_options.hxx +0 -31
  74. package/deps/couchbase-cxx-client/docs/cbc-analytics.md +1 -0
  75. package/deps/couchbase-cxx-client/docs/cbc-get.md +1 -0
  76. package/deps/couchbase-cxx-client/docs/cbc-pillowfight.md +1 -0
  77. package/deps/couchbase-cxx-client/docs/cbc-query.md +1 -0
  78. package/deps/couchbase-cxx-client/docs/cbc.md +10 -0
  79. package/deps/couchbase-cxx-client/test/CMakeLists.txt +1 -0
  80. package/deps/couchbase-cxx-client/test/test_integration_collections.cxx +6 -0
  81. package/deps/couchbase-cxx-client/test/test_integration_crud.cxx +5 -0
  82. package/deps/couchbase-cxx-client/test/test_integration_examples.cxx +137 -1
  83. package/deps/couchbase-cxx-client/test/test_integration_management.cxx +709 -266
  84. package/deps/couchbase-cxx-client/test/test_integration_query.cxx +19 -7
  85. package/deps/couchbase-cxx-client/test/test_integration_range_scan.cxx +351 -112
  86. package/deps/couchbase-cxx-client/test/test_integration_search.cxx +10 -1
  87. package/deps/couchbase-cxx-client/test/test_transaction_public_async_api.cxx +13 -12
  88. package/deps/couchbase-cxx-client/test/test_transaction_public_blocking_api.cxx +27 -21
  89. package/deps/couchbase-cxx-client/test/test_unit_query.cxx +75 -0
  90. package/deps/couchbase-cxx-client/test/utils/server_version.hxx +5 -0
  91. package/deps/couchbase-cxx-client/test/utils/wait_until.cxx +29 -10
  92. package/deps/couchbase-cxx-client/test/utils/wait_until.hxx +3 -1
  93. package/deps/couchbase-cxx-client/tools/utils.cxx +4 -1
  94. package/dist/binding.d.ts +21 -16
  95. package/dist/binding.js +1 -4
  96. package/dist/bindingutilities.d.ts +6 -1
  97. package/dist/bindingutilities.js +36 -1
  98. package/dist/collection.d.ts +65 -3
  99. package/dist/collection.js +107 -0
  100. package/dist/crudoptypes.d.ts +34 -0
  101. package/dist/crudoptypes.js +18 -1
  102. package/dist/queryexecutor.js +1 -0
  103. package/dist/querytypes.d.ts +7 -0
  104. package/dist/rangeScan.d.ts +107 -0
  105. package/dist/rangeScan.js +91 -0
  106. package/dist/streamablepromises.d.ts +6 -0
  107. package/dist/streamablepromises.js +25 -1
  108. package/package.json +13 -13
  109. package/src/addondata.hpp +1 -0
  110. package/src/binding.cpp +5 -2
  111. package/src/connection.cpp +108 -2
  112. package/src/connection.hpp +1 -0
  113. package/src/constants.cpp +2 -12
  114. package/src/jstocbpp_autogen.hpp +49 -22
  115. package/src/jstocbpp_basic.hpp +2 -8
  116. package/src/mutationtoken.cpp +13 -0
  117. package/src/scan_iterator.cpp +90 -0
  118. package/src/scan_iterator.hpp +30 -0
  119. package/tools/gen-bindings-json.py +9 -8
  120. package/deps/couchbase-cxx-client/core/impl/collection_query_index_manager.cxx +0 -93
@@ -24,16 +24,6 @@
24
24
 
25
25
  namespace couchbase::core::impl
26
26
  {
27
-
28
- template<typename Response>
29
- static manager_error_context
30
- build_context(Response& resp, std::optional<std::error_code> ec = {})
31
- {
32
- return { ec ? ec.value() : resp.ctx.ec, resp.ctx.last_dispatched_to, resp.ctx.last_dispatched_from,
33
- resp.ctx.retry_attempts, std::move(resp.ctx.retry_reasons), std::move(resp.ctx.client_context_id),
34
- resp.ctx.http_status, std::move(resp.ctx.http_body), std::move(resp.ctx.path) };
35
- }
36
-
37
27
  class watch_context : public std::enable_shared_from_this<watch_context>
38
28
  {
39
29
 
@@ -50,9 +40,18 @@ class watch_context : public std::enable_shared_from_this<watch_context>
50
40
  std::chrono::milliseconds timeout_{ options_.timeout.value_or(core_->origin().second.options().query_timeout) };
51
41
  std::atomic<size_t> attempts_{ 0 };
52
42
 
53
- void finish(manager_error_context error_ctx)
43
+ template<typename Response>
44
+ void finish(Response& resp, std::optional<std::error_code> ec = {})
54
45
  {
55
- handler_(error_ctx);
46
+ handler_({ manager_error_context(internal_manager_error_context{ ec ? ec.value() : resp.ctx.ec,
47
+ resp.ctx.last_dispatched_to,
48
+ resp.ctx.last_dispatched_from,
49
+ resp.ctx.retry_attempts,
50
+ std::move(resp.ctx.retry_reasons),
51
+ std::move(resp.ctx.client_context_id),
52
+ resp.ctx.http_status,
53
+ std::move(resp.ctx.http_body),
54
+ std::move(resp.ctx.path) }) });
56
55
  timer_.cancel();
57
56
  }
58
57
  std::chrono::milliseconds remaining()
@@ -79,9 +78,9 @@ class watch_context : public std::enable_shared_from_this<watch_context>
79
78
  complete &= it != resp.indexes.end() && it->state == "online";
80
79
  }
81
80
  if (complete || resp.ctx.ec == couchbase::errc::common::ambiguous_timeout) {
82
- finish(build_context(resp));
81
+ finish(resp);
83
82
  } else if (remaining().count() <= 0) {
84
- finish(build_context(resp, couchbase::errc::common::ambiguous_timeout));
83
+ finish(resp, couchbase::errc::common::ambiguous_timeout);
85
84
  complete = true;
86
85
  }
87
86
  return complete;
@@ -141,28 +140,53 @@ class watch_context : public std::enable_shared_from_this<watch_context>
141
140
  core_->execute(req, resp_fn);
142
141
  }
143
142
  };
143
+ } // namespace couchbase::core::impl
144
144
 
145
+ namespace couchbase
146
+ {
145
147
  void
146
- initiate_watch_query_indexes(std::shared_ptr<couchbase::core::cluster> core,
147
- std::string bucket_name,
148
- std::vector<std::string> index_names,
149
- couchbase::watch_query_indexes_options::built options,
150
- query_context query_ctx,
151
- std::string collection_name,
152
- watch_query_indexes_handler&& handler)
148
+ query_index_manager::watch_indexes(std::string bucket_name,
149
+ std::vector<std::string> index_names,
150
+ const couchbase::watch_query_indexes_options& options,
151
+ couchbase::watch_query_indexes_handler&& handler)
153
152
  {
154
- auto ctx = std::make_shared<watch_context>(core, bucket_name, index_names, options, query_ctx, collection_name, std::move(handler));
153
+ auto ctx = std::make_shared<couchbase::core::impl::watch_context>(
154
+ core_, std::move(bucket_name), std::move(index_names), options.build(), core::query_context{}, "", std::move(handler));
155
155
  ctx->execute();
156
156
  }
157
157
 
158
+ auto
159
+ query_index_manager::watch_indexes(std::string bucket_name,
160
+ std::vector<std::string> index_names,
161
+ const couchbase::watch_query_indexes_options& options) -> std::future<manager_error_context>
162
+ {
163
+ auto barrier = std::make_shared<std::promise<manager_error_context>>();
164
+ watch_indexes(
165
+ std::move(bucket_name), std::move(index_names), options, [barrier](auto ctx) mutable { barrier->set_value(std::move(ctx)); });
166
+ return barrier->get_future();
167
+ }
168
+
158
169
  void
159
- initiate_watch_query_indexes(std::shared_ptr<couchbase::core::cluster> core,
160
- std::string bucket_name,
161
- std::vector<std::string> index_names,
162
- couchbase::watch_query_indexes_options::built options,
163
- watch_query_indexes_handler&& handler)
170
+ collection_query_index_manager::watch_indexes(std::vector<std::string> index_names,
171
+ const watch_query_indexes_options& options,
172
+ watch_query_indexes_handler&& handler) const
164
173
  {
165
- initiate_watch_query_indexes(core, std::move(bucket_name), std::move(index_names), options, {}, "", std::move(handler));
174
+ auto ctx = std::make_shared<couchbase::core::impl::watch_context>(core_,
175
+ bucket_name_,
176
+ std::move(index_names),
177
+ options.build(),
178
+ core::query_context(bucket_name_, scope_name_),
179
+ collection_name_,
180
+ std::move(handler));
181
+ ctx->execute();
166
182
  }
167
183
 
168
- } // namespace couchbase::core::impl
184
+ auto
185
+ collection_query_index_manager::watch_indexes(std::vector<std::string> index_names, const couchbase::watch_query_indexes_options& options)
186
+ -> std::future<manager_error_context>
187
+ {
188
+ auto barrier = std::make_shared<std::promise<manager_error_context>>();
189
+ watch_indexes(std::move(index_names), options, [barrier](auto ctx) mutable { barrier->set_value(std::move(ctx)); });
190
+ return barrier->get_future();
191
+ }
192
+ } // namespace couchbase
@@ -28,6 +28,10 @@
28
28
  #include <asio/read.hpp>
29
29
  #include <asio/write.hpp>
30
30
 
31
+ #include <fmt/chrono.h>
32
+
33
+ #include <spdlog/fmt/bin_to_hex.h>
34
+
31
35
  #include <memory>
32
36
  #include <sstream>
33
37
 
@@ -68,13 +72,22 @@ class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
68
72
 
69
73
  void execute(std::chrono::milliseconds total_timeout, std::chrono::milliseconds udp_timeout)
70
74
  {
75
+ CB_LOG_TRACE("Query DNS-SRV (UDP) address=\"{}:{}\", udp_timeout={}, total_timeout={}{:a}",
76
+ address_.to_string(),
77
+ port_,
78
+ udp_timeout,
79
+ total_timeout,
80
+ spdlog::to_hex(send_buf_));
71
81
  asio::ip::udp::endpoint endpoint(address_, port_);
72
82
  udp_.open(endpoint.protocol());
73
83
  udp_.async_send_to(
74
84
  asio::buffer(send_buf_), endpoint, [self = shared_from_this()](std::error_code ec1, std::size_t /* bytes_transferred */) mutable {
75
85
  if (ec1) {
76
86
  self->udp_deadline_.cancel();
77
- CB_LOG_DEBUG("DNS UDP write operation has got error {}, retrying with TCP", ec1.message());
87
+ CB_LOG_DEBUG("DNS UDP write operation has got error, retrying with TCP, address=\"{}:{}\", ec={}",
88
+ self->address_.to_string(),
89
+ self->port_,
90
+ ec1.message());
78
91
  return self->retry_with_tcp();
79
92
  }
80
93
 
@@ -83,7 +96,10 @@ class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
83
96
  asio::buffer(self->recv_buf_), self->udp_sender_, [self](std::error_code ec2, std::size_t bytes_transferred) mutable {
84
97
  self->udp_deadline_.cancel();
85
98
  if (ec2) {
86
- CB_LOG_DEBUG("DNS UDP read operation has got error {}, retrying with TCP", ec2.message());
99
+ CB_LOG_DEBUG("DNS UDP read operation has got error, retrying with TCP, address=\"{}:{}\", ec={}",
100
+ self->address_.to_string(),
101
+ self->port_,
102
+ ec2.message());
87
103
  return self->retry_with_tcp();
88
104
  }
89
105
  self->recv_buf_.resize(bytes_transferred);
@@ -104,11 +120,13 @@ class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
104
120
  });
105
121
  });
106
122
  udp_deadline_.expires_after(udp_timeout);
107
- deadline_.async_wait([self = shared_from_this()](std::error_code ec) {
123
+ udp_deadline_.async_wait([self = shared_from_this()](std::error_code ec) {
108
124
  if (ec == asio::error::operation_aborted) {
109
125
  return;
110
126
  }
111
- CB_LOG_DEBUG("DNS UDP deadline has been reached, cancelling UDP operation and fall back to TCP");
127
+ CB_LOG_DEBUG("DNS UDP deadline has been reached, cancelling UDP operation and fall back to TCP, address=\"{}:{}\"",
128
+ self->address_.to_string(),
129
+ self->port_);
112
130
  self->udp_.cancel();
113
131
  return self->retry_with_tcp();
114
132
  });
@@ -118,7 +136,10 @@ class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
118
136
  if (ec == asio::error::operation_aborted) {
119
137
  return;
120
138
  }
121
- CB_LOG_DEBUG("DNS deadline has been reached, cancelling in-flight operations (tcp.is_open={})", self->tcp_.is_open());
139
+ CB_LOG_DEBUG("DNS deadline has been reached, cancelling in-flight operations (tcp.is_open={}, address=\"{}:{}\")",
140
+ self->tcp_.is_open(),
141
+ self->address_.to_string(),
142
+ self->port_);
122
143
  self->udp_.cancel();
123
144
  if (self->tcp_.is_open()) {
124
145
  self->tcp_.cancel();
@@ -140,53 +161,65 @@ class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
140
161
  tcp_.async_connect(endpoint, [self = shared_from_this()](std::error_code ec1) mutable {
141
162
  if (ec1) {
142
163
  self->deadline_.cancel();
143
- CB_LOG_DEBUG("DNS TCP connection has been aborted, {}", ec1.message());
164
+ CB_LOG_DEBUG(
165
+ "DNS TCP connection has been aborted, address=\"{}:{}\", ec={}", self->address_.to_string(), self->port_, ec1.message());
144
166
  return self->handler_({ ec1 });
145
167
  }
146
168
  auto send_size = static_cast<std::uint16_t>(self->send_buf_.size());
147
169
  self->send_buf_.insert(self->send_buf_.begin(), static_cast<std::uint8_t>(send_size & 0xffU));
148
170
  self->send_buf_.insert(self->send_buf_.begin(), static_cast<std::uint8_t>(send_size >> 8U));
171
+ CB_LOG_TRACE(
172
+ "Query DNS-SRV (TCP) address=\"{}:{}\"{:a}", self->address_.to_string(), self->port_, spdlog::to_hex(self->send_buf_));
149
173
  asio::async_write(
150
174
  self->tcp_, asio::buffer(self->send_buf_), [self](std::error_code ec2, std::size_t /* bytes_transferred */) mutable {
151
175
  if (ec2) {
152
- CB_LOG_DEBUG("DNS TCP write operation has been aborted, {}", ec2.message());
176
+ CB_LOG_DEBUG("DNS TCP write operation has been aborted, address=\"{}:{}\", ec={}",
177
+ self->address_.to_string(),
178
+ self->port_,
179
+ ec2.message());
153
180
  self->deadline_.cancel();
154
181
  if (ec2 == asio::error::operation_aborted) {
155
182
  ec2 = errc::common::unambiguous_timeout;
156
183
  }
157
184
  return self->handler_({ ec2 });
158
185
  }
159
- asio::async_read(self->tcp_,
160
- asio::buffer(&self->recv_buf_size_, sizeof(std::uint16_t)),
161
- [self](std::error_code ec3, std::size_t /* bytes_transferred */) mutable {
162
- if (ec3) {
163
- CB_LOG_DEBUG("DNS TCP buf size read operation has been aborted, {}", ec3.message());
164
- self->deadline_.cancel();
165
- return self->handler_({ ec3 });
166
- }
167
- self->recv_buf_size_ = utils::byte_swap(self->recv_buf_size_);
168
- self->recv_buf_.resize(self->recv_buf_size_);
169
- CB_LOG_DEBUG("DNS TCP schedule read of {} bytes", self->recv_buf_size_);
170
- asio::async_read(self->tcp_,
171
- asio::buffer(self->recv_buf_),
172
- [self](std::error_code ec4, std::size_t bytes_transferred) mutable {
173
- self->deadline_.cancel();
174
- if (ec4) {
175
- CB_LOG_DEBUG("DNS TCP read operation has been aborted, {}", ec4.message());
176
- return self->handler_({ ec4 });
177
- }
178
- self->recv_buf_.resize(bytes_transferred);
179
- const dns_message message = dns_codec::decode(self->recv_buf_);
180
- dns_srv_response resp{ ec4 };
181
- resp.targets.reserve(message.answers.size());
182
- for (const auto& answer : message.answers) {
183
- resp.targets.emplace_back(dns_srv_response::address{
184
- utils::join_strings(answer.target.labels, "."), answer.port });
185
- }
186
- CB_LOG_DEBUG("DNS TCP returned {} records", resp.targets.size());
187
- return self->handler_(std::move(resp));
188
- });
189
- });
186
+ asio::async_read(
187
+ self->tcp_,
188
+ asio::buffer(&self->recv_buf_size_, sizeof(std::uint16_t)),
189
+ [self](std::error_code ec3, std::size_t /* bytes_transferred */) mutable {
190
+ if (ec3) {
191
+ CB_LOG_DEBUG("DNS TCP buf size read operation has been aborted, address=\"{}:{}\", ec={}",
192
+ self->address_.to_string(),
193
+ self->port_,
194
+ ec3.message());
195
+ self->deadline_.cancel();
196
+ return self->handler_({ ec3 });
197
+ }
198
+ self->recv_buf_size_ = utils::byte_swap(self->recv_buf_size_);
199
+ self->recv_buf_.resize(self->recv_buf_size_);
200
+ CB_LOG_DEBUG("DNS TCP schedule read of {} bytes", self->recv_buf_size_);
201
+ asio::async_read(
202
+ self->tcp_, asio::buffer(self->recv_buf_), [self](std::error_code ec4, std::size_t bytes_transferred) mutable {
203
+ self->deadline_.cancel();
204
+ if (ec4) {
205
+ CB_LOG_DEBUG("DNS TCP read operation has been aborted, address=\"{}:{}\", ec={}",
206
+ self->address_.to_string(),
207
+ self->port_,
208
+ ec4.message());
209
+ return self->handler_({ ec4 });
210
+ }
211
+ self->recv_buf_.resize(bytes_transferred);
212
+ const dns_message message = dns_codec::decode(self->recv_buf_);
213
+ dns_srv_response resp{ ec4 };
214
+ resp.targets.reserve(message.answers.size());
215
+ for (const auto& answer : message.answers) {
216
+ resp.targets.emplace_back(
217
+ dns_srv_response::address{ utils::join_strings(answer.target.labels, "."), answer.port });
218
+ }
219
+ CB_LOG_DEBUG("DNS TCP returned {} records", resp.targets.size());
220
+ return self->handler_(std::move(resp));
221
+ });
222
+ });
190
223
  });
191
224
  });
192
225
  }
@@ -87,7 +87,7 @@ load_resolv_conf()
87
87
 
88
88
  if (dns_servers.size() > 0) {
89
89
  CB_LOG_DEBUG(
90
- "Found DNS Servers: [{}], using nameserver: {}", couchbase::core::utils::join_strings(dns_servers, ", "), dns_servers[0]);
90
+ "Found DNS Servers: [{}], selected nameserver: \"{}\"", couchbase::core::utils::join_strings(dns_servers, ", "), dns_servers[0]);
91
91
  return dns_servers[0];
92
92
  }
93
93
  CB_LOG_WARNING("Unable to find DNS nameserver");
@@ -118,13 +118,13 @@ load_resolv_conf(const char* conf_path)
118
118
  if (space == std::string::npos || space == offset || line.size() < space + 2) {
119
119
  continue;
120
120
  }
121
- if (std::string keyword = line.substr(offset, space); keyword != "nameserver") {
121
+ if (const auto keyword = line.substr(offset, space); keyword != "nameserver") {
122
122
  continue;
123
123
  }
124
124
  offset = space + 1;
125
125
  space = line.find(' ', offset);
126
- auto nameserver = line.substr(offset, space);
127
- CB_LOG_DEBUG("Using nameserver: {}", nameserver);
126
+ auto nameserver = (space == std::string::npos) ? line.substr(offset) : line.substr(offset, space - offset);
127
+ CB_LOG_DEBUG("Selected nameserver: \"{}\" from \"{}\"", nameserver, conf_path);
128
128
  return nameserver;
129
129
  }
130
130
  }
@@ -147,6 +147,7 @@ dns_config::system_config()
147
147
  std::error_code ec;
148
148
  asio::ip::address::from_string(nameserver, ec);
149
149
  if (ec) {
150
+ CB_LOG_DEBUG("Unable to parse \"{}\" as a network address, fall back to \"{}\"", nameserver, default_nameserver);
150
151
  nameserver = default_nameserver;
151
152
  }
152
153
  instance.nameserver_ = nameserver;
@@ -1279,16 +1279,15 @@ class mcbp_session_impl
1279
1279
  }
1280
1280
  last_active_ = std::chrono::steady_clock::now();
1281
1281
  if (it != endpoints_.end()) {
1282
- CB_LOG_DEBUG("{} connecting to {}:{}, timeout={}ms",
1283
- log_prefix_,
1284
- it->endpoint().address().to_string(),
1285
- it->endpoint().port(),
1286
- origin_.options().connect_timeout.count());
1282
+ auto hostname = it->endpoint().address().to_string();
1283
+ auto port = it->endpoint().port();
1284
+ CB_LOG_DEBUG("{} connecting to {}:{}, timeout={}ms", log_prefix_, hostname, port, origin_.options().connect_timeout.count());
1287
1285
  connection_deadline_.expires_after(origin_.options().connect_timeout);
1288
- connection_deadline_.async_wait([self = shared_from_this()](const auto timer_ec) {
1286
+ connection_deadline_.async_wait([self = shared_from_this(), hostname, port](const auto timer_ec) {
1289
1287
  if (timer_ec == asio::error::operation_aborted || self->stopped_) {
1290
1288
  return;
1291
1289
  }
1290
+ CB_LOG_DEBUG("{} unable to connect to {}:{} in time, reconnecting", self->log_prefix_, hostname, port);
1292
1291
  return self->stream_->close([self](std::error_code) { self->initiate_bootstrap(); });
1293
1292
  });
1294
1293
  stream_->async_connect(it->endpoint(),
@@ -29,3 +29,9 @@
29
29
  * couchbase::core::meta::sdk_version() function is available
30
30
  */
31
31
  #define COUCHBASE_CXX_CLIENT_HAS_SDK_SEMVER 1
32
+
33
+ /**
34
+ * couchbase::core::cluster_options and couchbase::security_options support
35
+ * passing TLS trust certificate by value
36
+ */
37
+ #define COUCHBASE_CXX_CLIENT_CAN_PASS_TLS_TRUST_CERTIFICATE_BY_VALUE 1
@@ -85,6 +85,17 @@ query_request::encode_to(query_request::encoded_request_type& encoded, http_cont
85
85
  case couchbase::query_profile::off:
86
86
  break;
87
87
  }
88
+ if (use_replica.has_value()) {
89
+ if (context.config.supports_read_from_replica()) {
90
+ if (use_replica.value()) {
91
+ body["use_replica"] = "on";
92
+ } else {
93
+ body["use_replica"] = "off";
94
+ }
95
+ } else {
96
+ return errc::common::feature_not_available;
97
+ }
98
+ }
88
99
  if (max_parallelism) {
89
100
  body["max_parallelism"] = std::to_string(max_parallelism.value());
90
101
  }
@@ -91,6 +91,7 @@ struct query_request {
91
91
  bool flex_index{ false };
92
92
  bool preserve_expiry{ false };
93
93
 
94
+ std::optional<bool> use_replica{};
94
95
  std::optional<std::uint64_t> max_parallelism{};
95
96
  std::optional<std::uint64_t> scan_cap{};
96
97
  std::optional<std::chrono::milliseconds> scan_wait{};
@@ -0,0 +1,270 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2020-2021 Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include "origin.hxx"
19
+
20
+ #include <fmt/chrono.h>
21
+ #include <fmt/format.h>
22
+
23
+ #include <tao/json.hpp>
24
+
25
+ namespace tao::json
26
+ {
27
+
28
+ template<>
29
+ struct traits<std::chrono::milliseconds> {
30
+ template<template<typename...> class Traits>
31
+ static void assign(tao::json::basic_value<Traits>& v, const std::chrono::milliseconds& o)
32
+ {
33
+ v = fmt::format("{}", o);
34
+ }
35
+ };
36
+
37
+ template<>
38
+ struct traits<std::chrono::nanoseconds> {
39
+ template<template<typename...> class Traits>
40
+ static void assign(tao::json::basic_value<Traits>& v, const std::chrono::nanoseconds& o)
41
+ {
42
+ v = fmt::format("{}", o);
43
+ }
44
+ };
45
+
46
+ template<>
47
+ struct traits<couchbase::core::tls_verify_mode> {
48
+ template<template<typename...> class Traits>
49
+ static void assign(tao::json::basic_value<Traits>& v, const couchbase::core::tls_verify_mode& o)
50
+ {
51
+ switch (o) {
52
+ case couchbase::core::tls_verify_mode::none:
53
+ v = "none";
54
+ break;
55
+ case couchbase::core::tls_verify_mode::peer:
56
+ v = "peer";
57
+ break;
58
+ }
59
+ }
60
+ };
61
+
62
+ template<>
63
+ struct traits<couchbase::core::io::ip_protocol> {
64
+ template<template<typename...> class Traits>
65
+ static void assign(tao::json::basic_value<Traits>& v, const couchbase::core::io::ip_protocol& o)
66
+ {
67
+ switch (o) {
68
+ case couchbase::core::io::ip_protocol::any:
69
+ v = "any";
70
+ break;
71
+ case couchbase::core::io::ip_protocol::force_ipv4:
72
+ v = "force_ipv4";
73
+ break;
74
+ case couchbase::core::io::ip_protocol::force_ipv6:
75
+ v = "force_ipv6";
76
+ break;
77
+ }
78
+ }
79
+ };
80
+
81
+ template<>
82
+ struct traits<couchbase::core::io::dns::dns_config> {
83
+ template<template<typename...> class Traits>
84
+ static void assign(tao::json::basic_value<Traits>& v, const couchbase::core::io::dns::dns_config& o)
85
+ {
86
+ v = {
87
+ { "port", o.port() },
88
+ { "nameserver", o.nameserver() },
89
+ { "timeout", o.timeout() },
90
+ };
91
+ }
92
+ };
93
+
94
+ template<>
95
+ struct traits<couchbase::core::tracing::threshold_logging_options> {
96
+ template<template<typename...> class Traits>
97
+ static void assign(tao::json::basic_value<Traits>& v, const couchbase::core::tracing::threshold_logging_options& o)
98
+ {
99
+ v = {
100
+ { "orphaned_emit_interval", o.orphaned_emit_interval },
101
+ { "orphaned_sample_size", o.orphaned_sample_size },
102
+ { "threshold_emit_interval", o.threshold_emit_interval },
103
+ { "threshold_sample_size", o.threshold_sample_size },
104
+ { "key_value_threshold", o.key_value_threshold },
105
+ { "query_threshold", o.query_threshold },
106
+ { "view_threshold", o.view_threshold },
107
+ { "search_threshold", o.search_threshold },
108
+ { "analytics_threshold", o.analytics_threshold },
109
+ { "management_threshold", o.management_threshold },
110
+ };
111
+ }
112
+ };
113
+
114
+ template<>
115
+ struct traits<couchbase::core::metrics::logging_meter_options> {
116
+ template<template<typename...> class Traits>
117
+ static void assign(tao::json::basic_value<Traits>& v, const couchbase::core::metrics::logging_meter_options& o)
118
+ {
119
+ v = {
120
+ { "emit_interval", o.emit_interval },
121
+ };
122
+ }
123
+ };
124
+
125
+ template<>
126
+ struct traits<couchbase::durability_level> {
127
+ template<template<typename...> class Traits>
128
+ static void assign(tao::json::basic_value<Traits>& v, const couchbase::durability_level& o)
129
+ {
130
+ switch (o) {
131
+ case couchbase::durability_level::none:
132
+ v = "none";
133
+ break;
134
+ case couchbase::durability_level::majority:
135
+ v = "majority";
136
+ break;
137
+ case couchbase::durability_level::majority_and_persist_to_active:
138
+ v = "majority_and_persist_to_active";
139
+ break;
140
+ case couchbase::durability_level::persist_to_majority:
141
+ v = "persist_to_majority";
142
+ break;
143
+ }
144
+ }
145
+ };
146
+
147
+ template<>
148
+ struct traits<couchbase::query_scan_consistency> {
149
+ template<template<typename...> class Traits>
150
+ static void assign(tao::json::basic_value<Traits>& v, const couchbase::query_scan_consistency& o)
151
+ {
152
+ switch (o) {
153
+ case couchbase::query_scan_consistency::not_bounded:
154
+ v = "not_bounded";
155
+ break;
156
+ case couchbase::query_scan_consistency::request_plus:
157
+ v = "request_plus";
158
+ break;
159
+ }
160
+ }
161
+ };
162
+
163
+ template<>
164
+ struct traits<couchbase::transactions::transactions_config::built> {
165
+ template<template<typename...> class Traits>
166
+ static void assign(tao::json::basic_value<Traits>& v, const couchbase::transactions::transactions_config::built& o)
167
+ {
168
+ v = {
169
+ { "expiration_time", o.expiration_time },
170
+ { "durability_level", o.level },
171
+ {
172
+ "query_config",
173
+ {
174
+ { "scan_consistency", o.query_config.scan_consistency },
175
+ },
176
+ },
177
+ {
178
+ "cleanup_config",
179
+ {
180
+ { "cleanup_lost_attempts", o.cleanup_config.cleanup_lost_attempts },
181
+ { "cleanup_client_attempts", o.cleanup_config.cleanup_client_attempts },
182
+ { "cleanup_window", o.cleanup_config.cleanup_window },
183
+ { "collections", tao::json::empty_array },
184
+ },
185
+ },
186
+ };
187
+ if (const auto& p = o.kv_timeout; p.has_value()) {
188
+ v["key_value_timeout"] = p.value();
189
+ }
190
+ if (const auto& p = o.metadata_collection; p.has_value()) {
191
+ v["metadata_collection"] = {
192
+ { "bucket", p.value().bucket },
193
+ { "scope", p.value().scope },
194
+ { "collection", p.value().collection },
195
+ };
196
+ }
197
+ for (const auto& c : o.cleanup_config.collections) {
198
+ v["cleanup_config"]["collections"].emplace_back(tao::json::value{
199
+ { "bucket", c.bucket },
200
+ { "scope", c.scope },
201
+ { "collection", c.collection },
202
+ });
203
+ }
204
+ }
205
+ };
206
+
207
+ } // namespace tao::json
208
+
209
+ namespace couchbase::core
210
+ {
211
+ auto
212
+ origin::to_json() const -> std::string
213
+ {
214
+ tao::json::value json = {
215
+ {
216
+ "options",
217
+ {
218
+ { "bootstrap_timeout", options_.bootstrap_timeout },
219
+ { "resolve_timeout", options_.resolve_timeout },
220
+ { "connect_timeout", options_.connect_timeout },
221
+ { "key_value_timeout", options_.key_value_timeout },
222
+ { "key_value_durable_timeout", options_.key_value_durable_timeout },
223
+ { "view_timeout", options_.view_timeout },
224
+ { "query_timeout", options_.query_timeout },
225
+ { "analytics_timeout", options_.analytics_timeout },
226
+ { "search_timeout", options_.search_timeout },
227
+ { "management_timeout", options_.management_timeout },
228
+ { "enable_tls", options_.enable_tls },
229
+ { "trust_certificate", options_.trust_certificate },
230
+ { "enable_mutation_tokens", options_.enable_mutation_tokens },
231
+ { "enable_tcp_keep_alive", options_.enable_tcp_keep_alive },
232
+ { "use_ip_protocol", options_.use_ip_protocol },
233
+ { "enable_dns_srv", options_.enable_dns_srv },
234
+ { "dns_config", options_.dns_config },
235
+ { "show_queries", options_.show_queries },
236
+ { "enable_unordered_execution", options_.enable_unordered_execution },
237
+ { "enable_clustermap_notification", options_.enable_clustermap_notification },
238
+ { "enable_compression", options_.enable_compression },
239
+ { "enable_tracing", options_.enable_tracing },
240
+ { "enable_metrics", options_.enable_metrics },
241
+ { "tcp_keep_alive_interval", options_.tcp_keep_alive_interval },
242
+ { "config_poll_interval", options_.config_poll_interval },
243
+ { "config_poll_floor", options_.config_poll_floor },
244
+ { "config_idle_redial_timeout", options_.config_idle_redial_timeout },
245
+ { "max_http_connections", options_.max_http_connections },
246
+ { "idle_http_connection_timeout", options_.idle_http_connection_timeout },
247
+ { "user_agent_extra", options_.user_agent_extra },
248
+ { "dump_configuration", options_.dump_configuration },
249
+ { "disable_mozilla_ca_certificates", options_.disable_mozilla_ca_certificates },
250
+ { "metrics_options", options_.metrics_options },
251
+ { "network", options_.network },
252
+ { "tls_verify", options_.tls_verify },
253
+ { "tracing_options", options_.tracing_options },
254
+ { "transactions_options", options_.transactions },
255
+ },
256
+ },
257
+ };
258
+ {
259
+ tao::json::value nodes = tao::json::empty_array;
260
+ for (const auto& [hostname, port] : nodes_) {
261
+ nodes.emplace_back(tao::json::value{
262
+ { "hostname", hostname },
263
+ { "port", port },
264
+ });
265
+ }
266
+ json["bootstrap_nodes"] = nodes;
267
+ }
268
+ return tao::json::to_string(json);
269
+ }
270
+ } // namespace couchbase::core