couchbase 4.2.10 → 4.2.11
Sign up to get free protection for your applications and to get access to all the features.
- package/deps/couchbase-cxx-client/CMakeLists.txt +1 -0
- package/deps/couchbase-cxx-client/cmake/ThirdPartyDependencies.cmake +2 -0
- package/deps/couchbase-cxx-client/core/bucket.cxx +25 -10
- package/deps/couchbase-cxx-client/core/bucket.hxx +1 -0
- package/deps/couchbase-cxx-client/core/cluster.cxx +29 -3
- package/deps/couchbase-cxx-client/core/impl/collection.cxx +2 -2
- package/deps/couchbase-cxx-client/core/impl/query_index_manager.cxx +6 -6
- package/deps/couchbase-cxx-client/core/io/http_session_manager.hxx +7 -1
- package/deps/couchbase-cxx-client/core/io/mcbp_command.hxx +10 -0
- package/deps/couchbase-cxx-client/core/io/mcbp_session.cxx +35 -1
- package/deps/couchbase-cxx-client/core/io/mcbp_session.hxx +2 -0
- package/deps/couchbase-cxx-client/core/management/design_document.hxx +1 -1
- package/deps/couchbase-cxx-client/core/meta/features.hxx +16 -1
- package/deps/couchbase-cxx-client/core/operations/document_lookup_in_all_replicas.hxx +1 -1
- package/deps/couchbase-cxx-client/core/operations/document_lookup_in_any_replica.hxx +1 -1
- package/deps/couchbase-cxx-client/core/operations/document_query.cxx +2 -2
- package/deps/couchbase-cxx-client/core/operations/document_search.cxx +10 -10
- package/deps/couchbase-cxx-client/core/operations/document_view.cxx +3 -0
- package/deps/couchbase-cxx-client/core/operations/document_view.hxx +1 -0
- package/deps/couchbase-cxx-client/core/operations/management/query_index_create.cxx +24 -13
- package/deps/couchbase-cxx-client/core/operations/management/query_index_create.hxx +1 -1
- package/deps/couchbase-cxx-client/core/origin.cxx +14 -0
- package/deps/couchbase-cxx-client/core/origin.hxx +6 -0
- package/deps/couchbase-cxx-client/core/protocol/status.cxx +2 -0
- package/deps/couchbase-cxx-client/core/protocol/status.hxx +1 -0
- package/deps/couchbase-cxx-client/core/range_scan_load_balancer.cxx +141 -0
- package/deps/couchbase-cxx-client/core/range_scan_load_balancer.hxx +64 -0
- package/deps/couchbase-cxx-client/core/range_scan_orchestrator.cxx +224 -336
- package/deps/couchbase-cxx-client/core/range_scan_orchestrator.hxx +5 -6
- package/deps/couchbase-cxx-client/core/range_scan_orchestrator_options.hxx +6 -4
- package/deps/couchbase-cxx-client/core/scan_result.hxx +1 -11
- package/deps/couchbase-cxx-client/core/topology/capabilities.hxx +70 -1
- package/deps/couchbase-cxx-client/core/topology/capabilities_fmt.hxx +30 -2
- package/deps/couchbase-cxx-client/core/topology/configuration.hxx +1 -34
- package/deps/couchbase-cxx-client/core/topology/configuration_fmt.hxx +2 -2
- package/deps/couchbase-cxx-client/core/topology/configuration_json.hxx +43 -20
- package/deps/couchbase-cxx-client/core/transactions/internal/exceptions_internal.hxx +5 -0
- package/deps/couchbase-cxx-client/couchbase/bucket.hxx +2 -2
- package/deps/couchbase-cxx-client/couchbase/cluster.hxx +1 -1
- package/deps/couchbase-cxx-client/couchbase/collection.hxx +1 -0
- package/deps/couchbase-cxx-client/couchbase/collection_query_index_manager.hxx +80 -11
- package/deps/couchbase-cxx-client/couchbase/error_context.hxx +1 -0
- package/deps/couchbase-cxx-client/couchbase/fmt/key_value_status_code.hxx +3 -1
- package/deps/couchbase-cxx-client/couchbase/get_links_analytics_options.hxx +2 -2
- package/deps/couchbase-cxx-client/couchbase/key_value_status_code.hxx +1 -0
- package/deps/couchbase-cxx-client/couchbase/query_index_manager.hxx +6 -8
- package/deps/couchbase-cxx-client/couchbase/scope.hxx +1 -1
- package/deps/couchbase-cxx-client/couchbase/search_options.hxx +2 -2
- package/deps/couchbase-cxx-client/couchbase/search_result.hxx +1 -1
- package/deps/couchbase-cxx-client/couchbase/subdocument_error_context.hxx +1 -0
- package/deps/couchbase-cxx-client/couchbase/transactions/transaction_options.hxx +1 -1
- package/deps/couchbase-cxx-client/couchbase-sdk-cxx-black-duck-manifest.yaml +1 -0
- package/dist/binding.d.ts +24 -2
- package/dist/bindingutilities.d.ts +11 -3
- package/dist/bindingutilities.js +33 -7
- package/dist/couchbase.d.ts +1 -0
- package/dist/couchbase.js +1 -0
- package/dist/queryindexmanager.d.ts +4 -4
- package/dist/queryindexmanager.js +7 -7
- package/dist/scope.d.ts +21 -0
- package/dist/scope.js +34 -0
- package/dist/scopesearchindexmanager.d.ts +116 -0
- package/dist/scopesearchindexmanager.js +406 -0
- package/dist/sdspecs.js +10 -9
- package/dist/sdutils.d.ts +1 -0
- package/dist/sdutils.js +4 -0
- package/dist/searchexecutor.d.ts +3 -1
- package/dist/searchexecutor.js +9 -2
- package/dist/searchindexmanager.d.ts +58 -3
- package/dist/searchindexmanager.js +188 -104
- package/dist/viewexecutor.js +13 -9
- package/dist/viewindexmanager.d.ts +70 -7
- package/dist/viewindexmanager.js +236 -103
- package/dist/viewtypes.d.ts +26 -0
- package/dist/viewtypes.js +17 -1
- package/package.json +7 -7
- package/src/constants.cpp +1 -0
- package/src/jstocbpp_autogen.hpp +89 -7
- package/deps/couchbase-cxx-client/core/scan_options.hxx +0 -44
@@ -360,6 +360,7 @@ set(couchbase_cxx_client_FILES
|
|
360
360
|
core/protocol/cmd_upsert.cxx
|
361
361
|
core/protocol/frame_info_utils.cxx
|
362
362
|
core/protocol/status.cxx
|
363
|
+
core/range_scan_load_balancer.cxx
|
363
364
|
core/range_scan_options.cxx
|
364
365
|
core/range_scan_orchestrator.cxx
|
365
366
|
core/retry_orchestrator.cxx
|
@@ -426,7 +426,7 @@ class bucket_impl
|
|
426
426
|
}
|
427
427
|
self->update_config(cfg);
|
428
428
|
self->drain_deferred_queue();
|
429
|
-
self->
|
429
|
+
self->poll_config({});
|
430
430
|
}
|
431
431
|
asio::post(asio::bind_executor(self->ctx_, [h = std::move(h), ec, cfg = std::move(cfg)]() mutable { h(ec, cfg); }));
|
432
432
|
});
|
@@ -482,15 +482,11 @@ class bucket_impl
|
|
482
482
|
}
|
483
483
|
}
|
484
484
|
|
485
|
-
void fetch_config(
|
485
|
+
void fetch_config()
|
486
486
|
{
|
487
|
-
if (
|
488
|
-
return;
|
489
|
-
}
|
490
|
-
if (heartbeat_timer_.expiry() > std::chrono::steady_clock::now()) {
|
487
|
+
if (closed_) {
|
491
488
|
return;
|
492
489
|
}
|
493
|
-
|
494
490
|
std::optional<io::mcbp_session> session{};
|
495
491
|
{
|
496
492
|
std::scoped_lock lock(sessions_mutex_);
|
@@ -499,7 +495,7 @@ class bucket_impl
|
|
499
495
|
std::size_t i = start;
|
500
496
|
do {
|
501
497
|
auto ptr = sessions_.find(i % sessions_.size());
|
502
|
-
if (ptr != sessions_.end() && ptr->second.supports_gcccp()) {
|
498
|
+
if (ptr != sessions_.end() && ptr->second.is_bootstrapped() && ptr->second.supports_gcccp()) {
|
503
499
|
session = ptr->second;
|
504
500
|
}
|
505
501
|
i = heartbeat_next_index_.fetch_add(1);
|
@@ -510,14 +506,27 @@ class bucket_impl
|
|
510
506
|
req.opaque(session->next_opaque());
|
511
507
|
session->write_and_flush(req.data());
|
512
508
|
} else {
|
513
|
-
CB_LOG_WARNING(R"({} unable to find session with GCCCP support, retry in {})", log_prefix_, heartbeat_interval_);
|
509
|
+
CB_LOG_WARNING(R"({} unable to find connected session with GCCCP support, retry in {})", log_prefix_, heartbeat_interval_);
|
514
510
|
}
|
511
|
+
}
|
512
|
+
|
513
|
+
void poll_config(std::error_code ec)
|
514
|
+
{
|
515
|
+
if (ec == asio::error::operation_aborted || closed_) {
|
516
|
+
return;
|
517
|
+
}
|
518
|
+
if (heartbeat_timer_.expiry() > std::chrono::steady_clock::now()) {
|
519
|
+
return;
|
520
|
+
}
|
521
|
+
|
522
|
+
fetch_config();
|
523
|
+
|
515
524
|
heartbeat_timer_.expires_after(heartbeat_interval_);
|
516
525
|
return heartbeat_timer_.async_wait([self = shared_from_this()](std::error_code e) {
|
517
526
|
if (e == asio::error::operation_aborted) {
|
518
527
|
return;
|
519
528
|
}
|
520
|
-
self->
|
529
|
+
self->poll_config(e);
|
521
530
|
});
|
522
531
|
}
|
523
532
|
|
@@ -880,6 +889,12 @@ bucket::ping(std::shared_ptr<diag::ping_collector> collector, std::optional<std:
|
|
880
889
|
return impl_->ping(std::move(collector), std::move(timeout));
|
881
890
|
}
|
882
891
|
|
892
|
+
void
|
893
|
+
bucket::fetch_config()
|
894
|
+
{
|
895
|
+
return impl_->fetch_config();
|
896
|
+
}
|
897
|
+
|
883
898
|
void
|
884
899
|
bucket::update_config(topology::configuration config)
|
885
900
|
{
|
@@ -177,6 +177,7 @@ class bucket
|
|
177
177
|
});
|
178
178
|
}
|
179
179
|
|
180
|
+
void fetch_config();
|
180
181
|
void update_config(topology::configuration config) override;
|
181
182
|
void bootstrap(utils::movable_function<void(std::error_code, topology::configuration)>&& handler);
|
182
183
|
void with_configuration(utils::movable_function<void(std::error_code, topology::configuration)>&& handler);
|
@@ -114,6 +114,26 @@ class ping_collector_impl
|
|
114
114
|
}
|
115
115
|
};
|
116
116
|
|
117
|
+
template<typename Request>
|
118
|
+
constexpr bool
|
119
|
+
is_feature_supported(const Request& /* request */, const configuration_capabilities& /* capabilities */)
|
120
|
+
{
|
121
|
+
return true;
|
122
|
+
}
|
123
|
+
|
124
|
+
constexpr bool
|
125
|
+
is_feature_supported(const operations::search_request& request, const configuration_capabilities& capabilities)
|
126
|
+
{
|
127
|
+
if (request.scope_name && !capabilities.supports_scoped_search_indexes()) {
|
128
|
+
return false;
|
129
|
+
}
|
130
|
+
if (request.vector_search && !capabilities.supports_vector_search()) {
|
131
|
+
return false;
|
132
|
+
}
|
133
|
+
|
134
|
+
return true;
|
135
|
+
}
|
136
|
+
|
117
137
|
class cluster_impl : public std::enable_shared_from_this<cluster_impl>
|
118
138
|
{
|
119
139
|
public:
|
@@ -238,10 +258,14 @@ class cluster_impl : public std::enable_shared_from_this<cluster_impl>
|
|
238
258
|
auto ptr = buckets_.find(bucket_name);
|
239
259
|
if (ptr == buckets_.end()) {
|
240
260
|
std::vector<protocol::hello_feature> known_features;
|
261
|
+
|
262
|
+
auto origin = origin_;
|
241
263
|
if (session_ && session_->has_config()) {
|
242
264
|
known_features = session_->supported_features();
|
265
|
+
origin = { origin_, session_->config().value() };
|
243
266
|
}
|
244
|
-
|
267
|
+
|
268
|
+
b = std::make_shared<bucket>(id_, ctx_, tls_, tracer_, meter_, bucket_name, origin, known_features, dns_srv_tracker_);
|
245
269
|
buckets_.try_emplace(bucket_name, b);
|
246
270
|
}
|
247
271
|
}
|
@@ -326,6 +350,9 @@ class cluster_impl : public std::enable_shared_from_this<cluster_impl>
|
|
326
350
|
if (stopped_) {
|
327
351
|
return handler(request.make_response({ errc::network::cluster_closed }, response_type{}));
|
328
352
|
}
|
353
|
+
if (!is_feature_supported(request, session_manager_->configuration_capabilities())) {
|
354
|
+
return handler(request.make_response({ errc::common::feature_not_available }, response_type{}));
|
355
|
+
}
|
329
356
|
if constexpr (operations::is_compound_operation_v<Request>) {
|
330
357
|
return request.execute(shared_from_this(), std::forward<Handler>(handler));
|
331
358
|
} else {
|
@@ -355,8 +382,7 @@ class cluster_impl : public std::enable_shared_from_this<cluster_impl>
|
|
355
382
|
handler(request.make_response({ ec }, {}));
|
356
383
|
return;
|
357
384
|
}
|
358
|
-
|
359
|
-
if (bucket_caps.find(cap) == bucket_caps.end()) {
|
385
|
+
if (!config.capabilities.has_bucket_capability(cap)) {
|
360
386
|
handler(request.make_response({ errc::common::feature_not_available }, {}));
|
361
387
|
return;
|
362
388
|
}
|
@@ -479,7 +479,7 @@ class collection_impl : public std::enable_shared_from_this<collection_impl>
|
|
479
479
|
bucket_name_,
|
480
480
|
[core = core_, r = std::move(request), h = std::move(handler)](std::error_code ec,
|
481
481
|
const core::topology::configuration& config) mutable {
|
482
|
-
if (!config.supports_subdoc_read_replica()) {
|
482
|
+
if (!config.capabilities.supports_subdoc_read_replica()) {
|
483
483
|
ec = errc::common::feature_not_available;
|
484
484
|
}
|
485
485
|
|
@@ -601,7 +601,7 @@ class collection_impl : public std::enable_shared_from_this<collection_impl>
|
|
601
601
|
bucket_name_,
|
602
602
|
[core = core_, r = std::move(request), h = std::move(handler)](std::error_code ec,
|
603
603
|
const core::topology::configuration& config) mutable {
|
604
|
-
if (!config.supports_subdoc_read_replica()) {
|
604
|
+
if (!config.capabilities.supports_subdoc_read_replica()) {
|
605
605
|
ec = errc::common::feature_not_available;
|
606
606
|
}
|
607
607
|
if (r->specs().size() > 16) {
|
@@ -215,7 +215,7 @@ class query_index_manager_impl : public std::enable_shared_from_this<query_index
|
|
215
215
|
const std::string& scope_name,
|
216
216
|
const std::string& collection_name,
|
217
217
|
std::string index_name,
|
218
|
-
std::vector<std::string>
|
218
|
+
std::vector<std::string> keys,
|
219
219
|
const create_query_index_options::built& options,
|
220
220
|
create_query_index_handler&& handler) const
|
221
221
|
{
|
@@ -225,7 +225,7 @@ class query_index_manager_impl : public std::enable_shared_from_this<query_index
|
|
225
225
|
scope_name,
|
226
226
|
collection_name,
|
227
227
|
std::move(index_name),
|
228
|
-
std::move(
|
228
|
+
std::move(keys),
|
229
229
|
{},
|
230
230
|
false /* is_primary */,
|
231
231
|
options.ignore_if_exists,
|
@@ -521,22 +521,22 @@ collection_query_index_manager::get_all_indexes(const get_all_query_indexes_opti
|
|
521
521
|
|
522
522
|
void
|
523
523
|
collection_query_index_manager::create_index(std::string index_name,
|
524
|
-
std::vector<std::string>
|
524
|
+
std::vector<std::string> keys,
|
525
525
|
const create_query_index_options& options,
|
526
526
|
create_query_index_handler&& handler) const
|
527
527
|
{
|
528
528
|
return impl_->create_index(
|
529
|
-
bucket_name_, scope_name_, collection_name_, std::move(index_name), std::move(
|
529
|
+
bucket_name_, scope_name_, collection_name_, std::move(index_name), std::move(keys), options.build(), std::move(handler));
|
530
530
|
}
|
531
531
|
|
532
532
|
auto
|
533
533
|
collection_query_index_manager::create_index(std::string index_name,
|
534
|
-
std::vector<std::string>
|
534
|
+
std::vector<std::string> keys,
|
535
535
|
const create_query_index_options& options) const -> std::future<manager_error_context>
|
536
536
|
{
|
537
537
|
auto barrier = std::make_shared<std::promise<manager_error_context>>();
|
538
538
|
auto future = barrier->get_future();
|
539
|
-
create_index(std::move(index_name), std::move(
|
539
|
+
create_index(std::move(index_name), std::move(keys), options, [barrier](auto ctx) { barrier->set_value(std::move(ctx)); });
|
540
540
|
return future;
|
541
541
|
}
|
542
542
|
|
@@ -58,6 +58,12 @@ class http_session_manager
|
|
58
58
|
meter_ = std::move(meter);
|
59
59
|
}
|
60
60
|
|
61
|
+
auto configuration_capabilities() const -> configuration_capabilities
|
62
|
+
{
|
63
|
+
std::scoped_lock config_lock(config_mutex_);
|
64
|
+
return config_.capabilities;
|
65
|
+
}
|
66
|
+
|
61
67
|
void update_config(topology::configuration config) override
|
62
68
|
{
|
63
69
|
std::scoped_lock config_lock(config_mutex_, sessions_mutex_);
|
@@ -387,7 +393,7 @@ class http_session_manager
|
|
387
393
|
cluster_options options_{};
|
388
394
|
|
389
395
|
topology::configuration config_{};
|
390
|
-
std::mutex config_mutex_{};
|
396
|
+
mutable std::mutex config_mutex_{};
|
391
397
|
std::map<service_type, std::list<std::shared_ptr<http_session>>> busy_sessions_{};
|
392
398
|
std::map<service_type, std::list<std::shared_ptr<http_session>>> idle_sessions_{};
|
393
399
|
std::size_t next_index_{ 0 };
|
@@ -289,6 +289,16 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
|
|
289
289
|
if (status == key_value_status_code::unknown_collection) {
|
290
290
|
return self->handle_unknown_collection();
|
291
291
|
}
|
292
|
+
if (status == key_value_status_code::config_only) {
|
293
|
+
CB_LOG_DEBUG(
|
294
|
+
"{} server returned status 0x{:02x} ({}) meaning that the node does not serve data operations, requesting new "
|
295
|
+
"configuration and retrying",
|
296
|
+
self->session_->log_prefix(),
|
297
|
+
msg.header.status(),
|
298
|
+
status);
|
299
|
+
self->manager_->fetch_config();
|
300
|
+
return io::retry_orchestrator::maybe_retry(self->manager_, self, retry_reason::service_response_code_indicated, ec);
|
301
|
+
}
|
292
302
|
if (error_code && error_code.value().has_retry_attribute()) {
|
293
303
|
reason = retry_reason::key_value_error_map_retry_indicated;
|
294
304
|
} else {
|
@@ -455,6 +455,16 @@ class mcbp_session_impl
|
|
455
455
|
case protocol::client_opcode::get_cluster_config: {
|
456
456
|
protocol::cmd_info info{ session_->connection_endpoints_.remote_address,
|
457
457
|
session_->connection_endpoints_.remote.port() };
|
458
|
+
if (session_->origin_.options().dump_configuration) {
|
459
|
+
std::string_view config_text{ reinterpret_cast<const char*>(msg.body.data()), msg.body.size() };
|
460
|
+
CB_LOG_TRACE(
|
461
|
+
"{} configuration from get_cluster_config request (bootstrap, size={}, endpoint=\"{}:{}\"), {}",
|
462
|
+
session_->log_prefix_,
|
463
|
+
config_text.size(),
|
464
|
+
info.endpoint_address,
|
465
|
+
info.endpoint_port,
|
466
|
+
config_text);
|
467
|
+
}
|
458
468
|
protocol::client_response<protocol::get_cluster_config_response_body> resp(std::move(msg), info);
|
459
469
|
if (resp.status() == key_value_status_code::success) {
|
460
470
|
session_->update_configuration(resp.body().config());
|
@@ -860,6 +870,8 @@ class mcbp_session_impl
|
|
860
870
|
if (stopped_) {
|
861
871
|
return;
|
862
872
|
}
|
873
|
+
bootstrapped_ = false;
|
874
|
+
bootstrap_handler_ = nullptr;
|
863
875
|
state_ = diag::endpoint_state::connecting;
|
864
876
|
if (stream_->is_open()) {
|
865
877
|
std::string old_id = stream_->id();
|
@@ -908,6 +920,11 @@ class mcbp_session_impl
|
|
908
920
|
return stopped_;
|
909
921
|
}
|
910
922
|
|
923
|
+
[[nodiscard]] bool is_bootstrapped() const
|
924
|
+
{
|
925
|
+
return bootstrapped_;
|
926
|
+
}
|
927
|
+
|
911
928
|
void on_stop(utils::movable_function<void()> handler)
|
912
929
|
{
|
913
930
|
on_stop_handler_ = std::move(handler);
|
@@ -1139,6 +1156,11 @@ class mcbp_session_impl
|
|
1139
1156
|
return supports_gcccp_;
|
1140
1157
|
}
|
1141
1158
|
|
1159
|
+
std::optional<topology::configuration> config() const
|
1160
|
+
{
|
1161
|
+
return config_;
|
1162
|
+
}
|
1163
|
+
|
1142
1164
|
[[nodiscard]] bool has_config() const
|
1143
1165
|
{
|
1144
1166
|
return configured_;
|
@@ -1539,7 +1561,7 @@ class mcbp_session_impl
|
|
1539
1561
|
CB_LOG_TRACE("{} MCBP recv {}", self->log_prefix_, mcbp_header_view(msg.header_data()));
|
1540
1562
|
if (self->bootstrapped_) {
|
1541
1563
|
self->handler_->handle(std::move(msg));
|
1542
|
-
} else {
|
1564
|
+
} else if (self->bootstrap_handler_) {
|
1543
1565
|
self->bootstrap_handler_->handle(std::move(msg));
|
1544
1566
|
}
|
1545
1567
|
if (self->stopped_) {
|
@@ -1722,6 +1744,12 @@ mcbp_session::is_stopped() const
|
|
1722
1744
|
return impl_->is_stopped();
|
1723
1745
|
}
|
1724
1746
|
|
1747
|
+
bool
|
1748
|
+
mcbp_session::is_bootstrapped() const
|
1749
|
+
{
|
1750
|
+
return impl_->is_bootstrapped();
|
1751
|
+
}
|
1752
|
+
|
1725
1753
|
std::uint32_t
|
1726
1754
|
mcbp_session::next_opaque()
|
1727
1755
|
{
|
@@ -1818,6 +1846,12 @@ mcbp_session::index() const
|
|
1818
1846
|
return impl_->index();
|
1819
1847
|
}
|
1820
1848
|
|
1849
|
+
std::optional<topology::configuration>
|
1850
|
+
mcbp_session::config() const
|
1851
|
+
{
|
1852
|
+
return impl_->config();
|
1853
|
+
}
|
1854
|
+
|
1821
1855
|
bool
|
1822
1856
|
mcbp_session::has_config() const
|
1823
1857
|
{
|
@@ -97,6 +97,7 @@ class mcbp_session
|
|
97
97
|
[[nodiscard]] const std::string& log_prefix() const;
|
98
98
|
[[nodiscard]] bool cancel(std::uint32_t opaque, std::error_code ec, retry_reason reason);
|
99
99
|
[[nodiscard]] bool is_stopped() const;
|
100
|
+
[[nodiscard]] bool is_bootstrapped() const;
|
100
101
|
[[nodiscard]] std::uint32_t next_opaque();
|
101
102
|
[[nodiscard]] std::optional<std::uint32_t> get_collection_uid(const std::string& collection_path);
|
102
103
|
[[nodiscard]] mcbp_context context() const;
|
@@ -118,6 +119,7 @@ class mcbp_session
|
|
118
119
|
void stop(retry_reason reason);
|
119
120
|
[[nodiscard]] std::size_t index() const;
|
120
121
|
[[nodiscard]] bool has_config() const;
|
122
|
+
[[nodiscard]] std::optional<topology::configuration> config() const;
|
121
123
|
[[nodiscard]] diag::endpoint_diag_info diag_info() const;
|
122
124
|
void on_configuration_update(std::shared_ptr<config_listener> handler);
|
123
125
|
void ping(std::shared_ptr<diag::ping_reporter> handler, std::optional<std::chrono::milliseconds> = {}) const;
|
@@ -72,7 +72,7 @@
|
|
72
72
|
*/
|
73
73
|
#define COUCHBASE_CXX_CLIENT_HAS_COLLECTION_QUERY_INDEX_MANAGEMENT 1
|
74
74
|
|
75
|
-
#define COUCHBASE_CXX_CLIENT_TRANSACTIONS_EXT_PARALLEL_UNSTAGING
|
75
|
+
#define COUCHBASE_CXX_CLIENT_TRANSACTIONS_EXT_PARALLEL_UNSTAGING 1
|
76
76
|
|
77
77
|
/**
|
78
78
|
* core cluster implementation has been hidden and not accessible through the public API
|
@@ -111,3 +111,18 @@
|
|
111
111
|
* Scope level search index management is supported via couchbase::scope::search_indexes()
|
112
112
|
*/
|
113
113
|
#define COUCHBASE_CXX_CLIENT_HAS_SCOPE_SEARCH_INDEX_MANAGEMENT 1
|
114
|
+
|
115
|
+
/**
|
116
|
+
* Support for couchbase::codec::raw_json_transcoder
|
117
|
+
*/
|
118
|
+
#define COUCHBASE_CXX_CLIENT_HAS_RAW_JSON_TRANSCODER 1
|
119
|
+
|
120
|
+
/**
|
121
|
+
* Support for couchbase::codec::raw_string_transcoder
|
122
|
+
*/
|
123
|
+
#define COUCHBASE_CXX_CLIENT_HAS_RAW_STRING_TRANSCODER 1
|
124
|
+
|
125
|
+
/**
|
126
|
+
* Transaction's transaction_operation_failed has a public getter for its final_error
|
127
|
+
*/
|
128
|
+
#define COUCHBASE_CXX_CLIENT_TRANSACTIONS_CAN_FETCH_TO_RAISE 1
|
@@ -69,7 +69,7 @@ struct lookup_in_all_replicas_request {
|
|
69
69
|
id.bucket(),
|
70
70
|
[core, id = id, timeout = timeout, specs = specs, parent_span = parent_span, h = std::forward<Handler>(handler)](
|
71
71
|
std::error_code ec, const topology::configuration& config) mutable {
|
72
|
-
if (!config.supports_subdoc_read_replica()) {
|
72
|
+
if (!config.capabilities.supports_subdoc_read_replica()) {
|
73
73
|
ec = errc::common::feature_not_available;
|
74
74
|
}
|
75
75
|
|
@@ -66,7 +66,7 @@ struct lookup_in_any_replica_request {
|
|
66
66
|
id.bucket(),
|
67
67
|
[core, id = id, timeout = timeout, specs = specs, parent_span = parent_span, h = std::forward<Handler>(handler)](
|
68
68
|
std::error_code ec, const topology::configuration& config) mutable {
|
69
|
-
if (!config.supports_subdoc_read_replica()) {
|
69
|
+
if (!config.capabilities.supports_subdoc_read_replica()) {
|
70
70
|
ec = errc::common::feature_not_available;
|
71
71
|
}
|
72
72
|
if (specs.size() > 16) {
|
@@ -47,7 +47,7 @@ query_request::encode_to(query_request::encoded_request_type& encoded, http_cont
|
|
47
47
|
}
|
48
48
|
} else {
|
49
49
|
body["statement"] = "PREPARE " + statement;
|
50
|
-
if (context.config.supports_enhanced_prepared_statements()) {
|
50
|
+
if (context.config.capabilities.supports_enhanced_prepared_statements()) {
|
51
51
|
body["auto_execute"] = true;
|
52
52
|
} else {
|
53
53
|
extract_encoded_plan_ = true;
|
@@ -87,7 +87,7 @@ query_request::encode_to(query_request::encoded_request_type& encoded, http_cont
|
|
87
87
|
break;
|
88
88
|
}
|
89
89
|
if (use_replica.has_value()) {
|
90
|
-
if (context.config.supports_read_from_replica()) {
|
90
|
+
if (context.config.capabilities.supports_read_from_replica()) {
|
91
91
|
if (use_replica.value()) {
|
92
92
|
body["use_replica"] = "on";
|
93
93
|
} else {
|
@@ -36,20 +36,20 @@ search_request::encode_to(search_request::encoded_request_type& encoded, http_co
|
|
36
36
|
};
|
37
37
|
|
38
38
|
if (show_request.has_value()) {
|
39
|
-
body["showrequest"] = show_request.value()
|
39
|
+
body["showrequest"] = show_request.value();
|
40
40
|
}
|
41
41
|
|
42
42
|
if (vector_search.has_value()) {
|
43
43
|
body["knn"] = utils::json::parse(vector_search.value());
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
44
|
+
if (vector_query_combination.has_value()) {
|
45
|
+
switch (*vector_query_combination) {
|
46
|
+
case couchbase::core::vector_query_combination::combination_or:
|
47
|
+
body["knn_operator"] = "or";
|
48
|
+
break;
|
49
|
+
case couchbase::core::vector_query_combination::combination_and:
|
50
|
+
body["knn_operator"] = "and";
|
51
|
+
break;
|
52
|
+
}
|
53
53
|
}
|
54
54
|
}
|
55
55
|
|
@@ -77,6 +77,9 @@ document_view_request::encode_to(document_view_request::encoded_request_type& en
|
|
77
77
|
if (group_level) {
|
78
78
|
query_string.emplace_back(fmt::format("group_level={}", *group_level));
|
79
79
|
}
|
80
|
+
if (full_set) {
|
81
|
+
query_string.emplace_back(fmt::format("full_set={}", full_set.value() ? "true" : "false"));
|
82
|
+
}
|
80
83
|
if (order) {
|
81
84
|
switch (*order) {
|
82
85
|
case couchbase::core::view_sort_order::descending:
|
@@ -86,6 +86,7 @@ struct document_view_request {
|
|
86
86
|
std::optional<std::uint32_t> group_level;
|
87
87
|
bool debug{ false };
|
88
88
|
std::map<std::string, std::string> raw{};
|
89
|
+
std::optional<bool> full_set;
|
89
90
|
|
90
91
|
std::optional<couchbase::core::view_sort_order> order;
|
91
92
|
std::optional<couchbase::core::view_on_error> on_error;
|
@@ -17,7 +17,6 @@
|
|
17
17
|
|
18
18
|
#include "query_index_create.hxx"
|
19
19
|
|
20
|
-
#include "core/utils/join_strings.hxx"
|
21
20
|
#include "core/utils/json.hxx"
|
22
21
|
#include "core/utils/keyspace.hxx"
|
23
22
|
#include "error_utils.hxx"
|
@@ -49,19 +48,31 @@ query_index_create_request::encode_to(encoded_request_type& encoded, http_contex
|
|
49
48
|
if (with) {
|
50
49
|
with_clause = fmt::format("WITH {}", utils::json::generate(with));
|
51
50
|
}
|
51
|
+
std::string encoded_keys{};
|
52
|
+
for (std::size_t i = 0; i < keys.size(); i++) {
|
53
|
+
if (i != 0) {
|
54
|
+
encoded_keys += ", ";
|
55
|
+
}
|
56
|
+
auto key = keys.at(i);
|
57
|
+
|
58
|
+
// Add backticks around the key unless they are already present
|
59
|
+
if (key.at(0) == '`' && key.at(key.size() - 1) == '`') {
|
60
|
+
encoded_keys += key;
|
61
|
+
} else {
|
62
|
+
encoded_keys += fmt::format("`{}`", key);
|
63
|
+
}
|
64
|
+
}
|
52
65
|
std::string keyspace = utils::build_keyspace(*this);
|
53
|
-
tao::json::value body{
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
with_clause) },
|
64
|
-
{ "client_context_id", encoded.client_context_id } };
|
66
|
+
tao::json::value body{
|
67
|
+
{ "statement",
|
68
|
+
is_primary ? fmt::format(R"(CREATE PRIMARY INDEX {} ON {} USING GSI {})",
|
69
|
+
index_name.empty() ? "" : fmt::format("`{}`", index_name),
|
70
|
+
keyspace,
|
71
|
+
with_clause)
|
72
|
+
: fmt::format(
|
73
|
+
R"(CREATE INDEX `{}` ON {}({}) {} USING GSI {})", index_name, keyspace, encoded_keys, where_clause, with_clause) },
|
74
|
+
{ "client_context_id", encoded.client_context_id }
|
75
|
+
};
|
65
76
|
if (query_ctx.has_value()) {
|
66
77
|
body["query_context"] = query_ctx.value();
|
67
78
|
}
|
@@ -49,7 +49,7 @@ struct query_index_create_request {
|
|
49
49
|
std::string scope_name;
|
50
50
|
std::string collection_name;
|
51
51
|
std::string index_name{};
|
52
|
-
std::vector<std::string>
|
52
|
+
std::vector<std::string> keys;
|
53
53
|
query_context query_ctx;
|
54
54
|
bool is_primary{ false };
|
55
55
|
bool ignore_if_exists{ false };
|
@@ -18,6 +18,7 @@
|
|
18
18
|
#include "origin.hxx"
|
19
19
|
|
20
20
|
#include "core/utils/connection_string.hxx"
|
21
|
+
#include "topology/configuration.hxx"
|
21
22
|
|
22
23
|
#include <fmt/chrono.h>
|
23
24
|
#include <fmt/core.h>
|
@@ -281,6 +282,19 @@ couchbase::core::origin::origin(const couchbase::core::origin& other)
|
|
281
282
|
, next_node_(nodes_.begin())
|
282
283
|
{
|
283
284
|
}
|
285
|
+
|
286
|
+
couchbase::core::origin::origin(const origin& other, const topology::configuration& config)
|
287
|
+
: origin(other)
|
288
|
+
{
|
289
|
+
nodes_.clear();
|
290
|
+
for (const auto& node : config.nodes) {
|
291
|
+
if (auto port = options_.enable_tls ? node.services_tls.key_value : node.services_plain.key_value; port.has_value()) {
|
292
|
+
nodes_.emplace_back(node.hostname, std::to_string(port.value()));
|
293
|
+
}
|
294
|
+
}
|
295
|
+
next_node_ = nodes_.begin();
|
296
|
+
}
|
297
|
+
|
284
298
|
couchbase::core::origin::origin(couchbase::core::cluster_credentials auth,
|
285
299
|
const std::string& hostname,
|
286
300
|
std::uint16_t port,
|
@@ -40,6 +40,11 @@ struct cluster_credentials {
|
|
40
40
|
[[nodiscard]] bool uses_certificate() const;
|
41
41
|
};
|
42
42
|
|
43
|
+
namespace topology
|
44
|
+
{
|
45
|
+
struct configuration;
|
46
|
+
}
|
47
|
+
|
43
48
|
struct origin {
|
44
49
|
using node_entry = std::pair<std::string, std::string>;
|
45
50
|
using node_list = std::vector<node_entry>;
|
@@ -49,6 +54,7 @@ struct origin {
|
|
49
54
|
|
50
55
|
origin(origin&& other) = default;
|
51
56
|
origin(const origin& other);
|
57
|
+
origin(const origin& other, const topology::configuration& config);
|
52
58
|
origin(cluster_credentials auth, const std::string& hostname, std::uint16_t port, cluster_options options);
|
53
59
|
origin(cluster_credentials auth, const std::string& hostname, const std::string& port, cluster_options options);
|
54
60
|
origin(cluster_credentials auth, const utils::connection_string& connstr);
|
@@ -103,6 +103,7 @@ is_valid_status(std::uint16_t code)
|
|
103
103
|
case key_value_status_code::range_scan_more:
|
104
104
|
case key_value_status_code::range_scan_complete:
|
105
105
|
case key_value_status_code::range_scan_vb_uuid_not_equal:
|
106
|
+
case key_value_status_code::config_only:
|
106
107
|
return true;
|
107
108
|
case key_value_status_code::unknown:
|
108
109
|
return false;
|