couchbase 4.2.11 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/deps/couchbase-cxx-cache/mozilla-ca-bundle.crt +49 -2
- package/deps/couchbase-cxx-cache/mozilla-ca-bundle.sha256 +1 -1
- package/deps/couchbase-cxx-client/core/impl/cluster.cxx +51 -5
- package/deps/couchbase-cxx-client/core/impl/collection.cxx +224 -209
- package/deps/couchbase-cxx-client/core/impl/query_error_context.cxx +2 -2
- package/deps/couchbase-cxx-client/core/impl/query_index_manager.cxx +1 -0
- package/deps/couchbase-cxx-client/core/io/dns_client.cxx +4 -0
- package/deps/couchbase-cxx-client/core/io/dns_config.cxx +15 -4
- package/deps/couchbase-cxx-client/core/io/dns_config.hxx +1 -1
- package/deps/couchbase-cxx-client/core/io/mcbp_session.cxx +84 -53
- package/deps/couchbase-cxx-client/core/mcbp/operation_queue.cxx +1 -0
- package/deps/couchbase-cxx-client/core/meta/features.hxx +5 -0
- package/deps/couchbase-cxx-client/core/operations/document_lookup_in_all_replicas.hxx +116 -105
- package/deps/couchbase-cxx-client/core/operations/document_lookup_in_any_replica.hxx +116 -108
- package/deps/couchbase-cxx-client/core/operations/document_search.cxx +97 -81
- package/deps/couchbase-cxx-client/core/operations/document_search.hxx +5 -0
- package/deps/couchbase-cxx-client/core/range_scan_orchestrator_options.hxx +2 -1
- package/deps/couchbase-cxx-client/core/transactions/atr_cleanup_entry.cxx +16 -7
- package/deps/couchbase-cxx-client/core/transactions/attempt_context_impl.cxx +578 -483
- package/deps/couchbase-cxx-client/core/transactions/attempt_context_testing_hooks.cxx +51 -50
- package/deps/couchbase-cxx-client/core/transactions/attempt_context_testing_hooks.hxx +4 -2
- package/deps/couchbase-cxx-client/core/transactions/cleanup_testing_hooks.cxx +6 -6
- package/deps/couchbase-cxx-client/core/transactions/cleanup_testing_hooks.hxx +3 -2
- package/deps/couchbase-cxx-client/core/transactions/internal/transactions_cleanup.hxx +2 -0
- package/deps/couchbase-cxx-client/core/transactions/internal/utils.hxx +5 -1
- package/deps/couchbase-cxx-client/core/transactions/staged_mutation.cxx +222 -179
- package/deps/couchbase-cxx-client/core/transactions/staged_mutation.hxx +23 -12
- package/deps/couchbase-cxx-client/core/transactions/transactions.cxx +61 -24
- package/deps/couchbase-cxx-client/core/transactions/transactions_cleanup.cxx +36 -16
- package/deps/couchbase-cxx-client/core/transactions/utils.cxx +9 -0
- package/deps/couchbase-cxx-client/core/transactions.hxx +40 -7
- package/deps/couchbase-cxx-client/couchbase/cluster.hxx +19 -0
- package/deps/couchbase-cxx-client/couchbase/fork_event.hxx +39 -0
- package/dist/binding.d.ts +8 -0
- package/dist/bindingutilities.d.ts +6 -1
- package/dist/bindingutilities.js +15 -1
- package/dist/bucketmanager.d.ts +0 -12
- package/dist/cluster.d.ts +0 -2
- package/dist/cluster.js +0 -2
- package/dist/collection.d.ts +3 -3
- package/dist/collection.js +3 -1
- package/dist/querytypes.d.ts +0 -2
- package/dist/rangeScan.d.ts +0 -8
- package/dist/rangeScan.js +0 -8
- package/dist/scope.d.ts +0 -5
- package/dist/scope.js +0 -5
- package/dist/scopesearchindexmanager.d.ts +0 -2
- package/dist/scopesearchindexmanager.js +0 -2
- package/dist/searchexecutor.js +3 -1
- package/dist/searchtypes.d.ts +16 -6
- package/dist/searchtypes.js +2 -6
- package/dist/transactions.d.ts +23 -0
- package/dist/transactions.js +16 -10
- package/dist/vectorsearch.d.ts +8 -8
- package/dist/vectorsearch.js +7 -7
- package/package.json +7 -7
- package/src/instance.cpp +11 -1
- package/src/instance.hpp +1 -0
- package/src/jstocbpp_autogen.hpp +8 -0
- package/src/jstocbpp_transactions.hpp +40 -3
- package/src/transactions.cpp +12 -1
- package/tools/gen-bindings-json.py +0 -1
@@ -38,8 +38,8 @@ query_error_context::to_json() const -> std::string
|
|
38
38
|
{ "retry_attempts", retry_attempts() },
|
39
39
|
{ "client_context_id", client_context_id_ },
|
40
40
|
{ "statement", statement_ },
|
41
|
-
{ "method",
|
42
|
-
{ "path",
|
41
|
+
{ "method", method_ },
|
42
|
+
{ "path", path_ },
|
43
43
|
{ "http_status", http_status_ },
|
44
44
|
{ "http_body", http_body_ },
|
45
45
|
{ "hostname", hostname_ },
|
@@ -285,6 +285,10 @@ dns_client::query_srv(const std::string& name,
|
|
285
285
|
const dns_config& config,
|
286
286
|
utils::movable_function<void(dns_srv_response&&)>&& handler)
|
287
287
|
{
|
288
|
+
if (config.nameserver().empty()) {
|
289
|
+
return handler({ {} });
|
290
|
+
}
|
291
|
+
|
288
292
|
std::error_code ec;
|
289
293
|
auto address = asio::ip::make_address(config.nameserver(), ec);
|
290
294
|
if (ec) {
|
@@ -53,6 +53,7 @@ load_resolv_conf()
|
|
53
53
|
fixed_info = (FIXED_INFO*)malloc(sizeof(FIXED_INFO));
|
54
54
|
if (fixed_info == NULL) {
|
55
55
|
CB_LOG_WARNING("Error allocating memory needed to call GetNetworkParams");
|
56
|
+
return {};
|
56
57
|
}
|
57
58
|
buf = sizeof(FIXED_INFO);
|
58
59
|
|
@@ -63,6 +64,7 @@ load_resolv_conf()
|
|
63
64
|
fixed_info = (FIXED_INFO*)malloc(buf);
|
64
65
|
if (fixed_info == NULL) {
|
65
66
|
CB_LOG_WARNING("Error allocating memory needed to call GetNetworkParams");
|
67
|
+
return {};
|
66
68
|
}
|
67
69
|
}
|
68
70
|
|
@@ -86,10 +88,12 @@ load_resolv_conf()
|
|
86
88
|
}
|
87
89
|
} else {
|
88
90
|
CB_LOG_WARNING("GetNetworkParams failed with error: {}", ret);
|
91
|
+
return {};
|
89
92
|
}
|
90
93
|
|
91
|
-
if (fixed_info)
|
94
|
+
if (fixed_info) {
|
92
95
|
free(fixed_info);
|
96
|
+
}
|
93
97
|
|
94
98
|
if (dns_servers.size() > 0) {
|
95
99
|
CB_LOG_DEBUG(
|
@@ -153,10 +157,17 @@ dns_config::system_config()
|
|
153
157
|
std::error_code ec;
|
154
158
|
asio::ip::make_address(nameserver, ec);
|
155
159
|
if (ec) {
|
156
|
-
|
157
|
-
|
160
|
+
std::string extra_info{};
|
161
|
+
#ifndef _WIN32
|
162
|
+
extra_info = fmt::format(" in \"{}\"", default_resolv_conf_path);
|
163
|
+
#endif
|
164
|
+
CB_LOG_WARNING("System DNS detection failed: unable to parse \"{}\" as a network address{}. DNS-SRV will not work "
|
165
|
+
"unless nameserver is specified explicitly in the options.",
|
166
|
+
nameserver,
|
167
|
+
extra_info);
|
168
|
+
} else {
|
169
|
+
instance.nameserver_ = nameserver;
|
158
170
|
}
|
159
|
-
instance.nameserver_ = nameserver;
|
160
171
|
});
|
161
172
|
|
162
173
|
return instance;
|
@@ -40,7 +40,7 @@ class dns_config
|
|
40
40
|
[[nodiscard]] std::chrono::milliseconds timeout() const;
|
41
41
|
|
42
42
|
private:
|
43
|
-
std::string nameserver_{
|
43
|
+
std::string nameserver_{};
|
44
44
|
std::uint16_t port_{ default_port };
|
45
45
|
std::chrono::milliseconds timeout_{ timeout_defaults::dns_srv_timeout };
|
46
46
|
};
|
@@ -210,6 +210,7 @@ class mcbp_session_impl
|
|
210
210
|
std::shared_ptr<mcbp_session_impl> session_;
|
211
211
|
sasl::ClientContext sasl_;
|
212
212
|
std::atomic_bool stopped_{ false };
|
213
|
+
std::string last_error_message_;
|
213
214
|
|
214
215
|
public:
|
215
216
|
~bootstrap_handler()
|
@@ -234,6 +235,16 @@ class mcbp_session_impl
|
|
234
235
|
return { "SCRAM-SHA512", "SCRAM-SHA256", "SCRAM-SHA1" };
|
235
236
|
}
|
236
237
|
|
238
|
+
std::string last_error_message() &&
|
239
|
+
{
|
240
|
+
return std::move(last_error_message_);
|
241
|
+
}
|
242
|
+
|
243
|
+
[[nodiscard]] const std::string& last_error_message() const&
|
244
|
+
{
|
245
|
+
return last_error_message_;
|
246
|
+
}
|
247
|
+
|
237
248
|
explicit bootstrap_handler(std::shared_ptr<mcbp_session_impl> session)
|
238
249
|
: session_(std::move(session))
|
239
250
|
, sasl_([origin = session_->origin_]() { return origin.username(); },
|
@@ -322,21 +333,21 @@ class mcbp_session_impl
|
|
322
333
|
case key_value_status_code::rate_limited_max_connections:
|
323
334
|
case key_value_status_code::rate_limited_network_egress:
|
324
335
|
case key_value_status_code::rate_limited_network_ingress:
|
325
|
-
|
326
|
-
"
|
327
|
-
session_->log_prefix_,
|
336
|
+
last_error_message_ = fmt::format(
|
337
|
+
"unable to bootstrap MCBP session (bucket={}, opcode={}, status={}), the user has reached rate limit",
|
328
338
|
session_->bucket_name_.value_or(""),
|
329
339
|
protocol::client_opcode(msg.header.opcode),
|
330
340
|
status);
|
341
|
+
CB_LOG_DEBUG("{} {}", session_->log_prefix_, last_error_message_);
|
331
342
|
return complete(errc::common::rate_limited);
|
332
343
|
|
333
344
|
case key_value_status_code::scope_size_limit_exceeded:
|
334
|
-
|
335
|
-
"
|
336
|
-
session_->log_prefix_,
|
345
|
+
last_error_message_ = fmt::format(
|
346
|
+
"unable to bootstrap MCBP session (bucket={}, opcode={}, status={}), the user has reached quota limit",
|
337
347
|
session_->bucket_name_.value_or(""),
|
338
348
|
protocol::client_opcode(msg.header.opcode),
|
339
349
|
status);
|
350
|
+
CB_LOG_DEBUG("{} {}", session_->log_prefix_, last_error_message_);
|
340
351
|
return complete(errc::common::quota_limited);
|
341
352
|
|
342
353
|
default:
|
@@ -356,20 +367,18 @@ class mcbp_session_impl
|
|
356
367
|
return auth_success();
|
357
368
|
}
|
358
369
|
} else {
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
resp.opaque());
|
370
|
+
last_error_message_ = fmt::format(
|
371
|
+
"unexpected message status during bootstrap: {} (opaque={})", resp.error_message(), resp.opaque());
|
372
|
+
CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
|
363
373
|
return complete(errc::network::handshake_failure);
|
364
374
|
}
|
365
375
|
} break;
|
366
376
|
case protocol::client_opcode::sasl_list_mechs: {
|
367
377
|
protocol::client_response<protocol::sasl_list_mechs_response_body> resp(std::move(msg));
|
368
378
|
if (resp.status() != key_value_status_code::success) {
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
resp.opaque());
|
379
|
+
last_error_message_ = fmt::format(
|
380
|
+
"unexpected message status during bootstrap: {} (opaque={})", resp.error_message(), resp.opaque());
|
381
|
+
CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
|
373
382
|
return complete(errc::common::authentication_failure);
|
374
383
|
}
|
375
384
|
} break;
|
@@ -390,17 +399,17 @@ class mcbp_session_impl
|
|
390
399
|
req.body().sasl_data(sasl_payload);
|
391
400
|
session_->write_and_flush(req.data());
|
392
401
|
} else {
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
resp.opaque());
|
402
|
+
last_error_message_ =
|
403
|
+
fmt::format("unable to authenticate: (sasl_code={}, opaque={})", sasl_code, resp.opaque());
|
404
|
+
CB_LOG_ERROR("{} {}", session_->log_prefix_, last_error_message_);
|
397
405
|
return complete(errc::common::authentication_failure);
|
398
406
|
}
|
399
407
|
} else {
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
408
|
+
last_error_message_ = fmt::format("{} unexpected message status during bootstrap: {} (opaque={})",
|
409
|
+
session_->log_prefix_,
|
410
|
+
resp.error_message(),
|
411
|
+
resp.opaque());
|
412
|
+
CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
|
404
413
|
return complete(errc::common::authentication_failure);
|
405
414
|
}
|
406
415
|
} break;
|
@@ -409,6 +418,9 @@ class mcbp_session_impl
|
|
409
418
|
if (resp.status() == key_value_status_code::success) {
|
410
419
|
return auth_success();
|
411
420
|
}
|
421
|
+
last_error_message_ =
|
422
|
+
fmt::format("unable to authenticate (opcode={}, status={}, opaque={})", opcode, resp.status(), resp.opaque());
|
423
|
+
CB_LOG_ERROR("{} {}", session_->log_prefix_, last_error_message_);
|
412
424
|
return complete(errc::common::authentication_failure);
|
413
425
|
}
|
414
426
|
case protocol::client_opcode::get_error_map: {
|
@@ -416,11 +428,11 @@ class mcbp_session_impl
|
|
416
428
|
if (resp.status() == key_value_status_code::success) {
|
417
429
|
session_->error_map_.emplace(resp.body().errmap());
|
418
430
|
} else {
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
431
|
+
last_error_message_ = fmt::format("unexpected message status during bootstrap: {} (opaque={}, {:n})",
|
432
|
+
resp.error_message(),
|
433
|
+
resp.opaque(),
|
434
|
+
spdlog::to_hex(resp.header()));
|
435
|
+
CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
|
424
436
|
return complete(errc::network::protocol_error);
|
425
437
|
}
|
426
438
|
} break;
|
@@ -430,25 +442,25 @@ class mcbp_session_impl
|
|
430
442
|
CB_LOG_DEBUG("{} selected bucket: {}", session_->log_prefix_, session_->bucket_name_.value_or(""));
|
431
443
|
session_->bucket_selected_ = true;
|
432
444
|
} else if (resp.status() == key_value_status_code::not_found) {
|
433
|
-
|
434
|
-
"
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
445
|
+
last_error_message_ =
|
446
|
+
fmt::format("kv_engine node does not have configuration propagated yet (opcode={}, status={}, opaque={})",
|
447
|
+
opcode,
|
448
|
+
resp.status(),
|
449
|
+
resp.opaque());
|
450
|
+
CB_LOG_DEBUG("{} {}", session_->log_prefix_, last_error_message_);
|
439
451
|
return complete(errc::network::configuration_not_available);
|
440
452
|
} else if (resp.status() == key_value_status_code::no_access) {
|
441
|
-
|
442
|
-
|
443
|
-
|
453
|
+
last_error_message_ = fmt::format("unable to select bucket: {}, probably the bucket does not exist",
|
454
|
+
session_->bucket_name_.value_or(""));
|
455
|
+
CB_LOG_DEBUG("{} {}", session_->log_prefix_, last_error_message_);
|
444
456
|
session_->bucket_selected_ = false;
|
445
457
|
return complete(errc::common::bucket_not_found);
|
446
458
|
} else {
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
459
|
+
last_error_message_ = fmt::format("unexpected message status during bootstrap: {} (opaque={}, {:n})",
|
460
|
+
resp.error_message(),
|
461
|
+
resp.opaque(),
|
462
|
+
spdlog::to_hex(resp.header()));
|
463
|
+
CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
|
452
464
|
return complete(errc::common::bucket_not_found);
|
453
465
|
}
|
454
466
|
} break;
|
@@ -470,12 +482,12 @@ class mcbp_session_impl
|
|
470
482
|
session_->update_configuration(resp.body().config());
|
471
483
|
complete({});
|
472
484
|
} else if (resp.status() == key_value_status_code::not_found) {
|
473
|
-
|
474
|
-
"
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
485
|
+
last_error_message_ =
|
486
|
+
fmt::format("kv_engine node does not have configuration propagated yet (opcode={}, status={}, opaque={})",
|
487
|
+
opcode,
|
488
|
+
resp.status(),
|
489
|
+
resp.opaque());
|
490
|
+
CB_LOG_DEBUG("{} {}", session_->log_prefix_, last_error_message_);
|
479
491
|
return complete(errc::network::configuration_not_available);
|
480
492
|
} else if (resp.status() == key_value_status_code::no_bucket && !session_->bucket_name_) {
|
481
493
|
// bucket-less session, but the server wants bucket
|
@@ -486,16 +498,17 @@ class mcbp_session_impl
|
|
486
498
|
session_->connection_endpoints_.remote_address, session_->connection_endpoints_.remote.port(), 0));
|
487
499
|
complete({});
|
488
500
|
} else {
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
501
|
+
last_error_message_ = fmt::format("unexpected message status during bootstrap: {} (opaque={}, {:n})",
|
502
|
+
resp.error_message(),
|
503
|
+
resp.opaque(),
|
504
|
+
spdlog::to_hex(resp.header()));
|
505
|
+
CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
|
494
506
|
return complete(errc::network::protocol_error);
|
495
507
|
}
|
496
508
|
} break;
|
497
509
|
default:
|
498
|
-
|
510
|
+
last_error_message_ = fmt::format("unexpected message during bootstrap: {}", opcode);
|
511
|
+
CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
|
499
512
|
return complete(errc::network::protocol_error);
|
500
513
|
}
|
501
514
|
break;
|
@@ -796,6 +809,20 @@ class mcbp_session_impl
|
|
796
809
|
|
797
810
|
void ping(std::shared_ptr<diag::ping_reporter> handler, std::optional<std::chrono::milliseconds> timeout)
|
798
811
|
{
|
812
|
+
if (!bootstrapped_) {
|
813
|
+
handler->report({
|
814
|
+
service_type::key_value,
|
815
|
+
id_,
|
816
|
+
std::chrono::microseconds(0),
|
817
|
+
remote_address(),
|
818
|
+
local_address(),
|
819
|
+
diag::ping_state::error,
|
820
|
+
bucket_name_,
|
821
|
+
last_bootstrap_error_message_.has_value() ? last_bootstrap_error_message_.value()
|
822
|
+
: "Bootstrap incomplete, cannot perform ping.",
|
823
|
+
});
|
824
|
+
return;
|
825
|
+
}
|
799
826
|
protocol::client_request<protocol::mcbp_noop_request_body> req;
|
800
827
|
req.opaque(next_opaque());
|
801
828
|
write_and_subscribe(req.opaque(),
|
@@ -871,6 +898,9 @@ class mcbp_session_impl
|
|
871
898
|
return;
|
872
899
|
}
|
873
900
|
bootstrapped_ = false;
|
901
|
+
if (bootstrap_handler_) {
|
902
|
+
last_bootstrap_error_message_ = std::move(bootstrap_handler_)->last_error_message();
|
903
|
+
}
|
874
904
|
bootstrap_handler_ = nullptr;
|
875
905
|
state_ = diag::endpoint_state::connecting;
|
876
906
|
if (stream_->is_open()) {
|
@@ -1644,6 +1674,7 @@ class mcbp_session_impl
|
|
1644
1674
|
std::optional<std::string> bucket_name_;
|
1645
1675
|
mcbp_parser parser_;
|
1646
1676
|
std::shared_ptr<bootstrap_handler> bootstrap_handler_{ nullptr };
|
1677
|
+
std::optional<std::string> last_bootstrap_error_message_;
|
1647
1678
|
std::shared_ptr<message_handler> handler_{ nullptr };
|
1648
1679
|
utils::movable_function<void(std::error_code, const topology::configuration&)> bootstrap_callback_{};
|
1649
1680
|
std::mutex command_handlers_mutex_{};
|
@@ -126,3 +126,8 @@
|
|
126
126
|
* Transaction's transaction_operation_failed has a public getter for its final_error
|
127
127
|
*/
|
128
128
|
#define COUCHBASE_CXX_CLIENT_TRANSACTIONS_CAN_FETCH_TO_RAISE 1
|
129
|
+
|
130
|
+
/**
|
131
|
+
* Hooks in the transactions core are asynchronous (they have a callback parameter)
|
132
|
+
*/
|
133
|
+
#define COUCHBASE_CXX_CLIENT_TRANSACTIONS_CORE_ASYNC_HOOKS
|
@@ -65,123 +65,134 @@ struct lookup_in_all_replicas_request {
|
|
65
65
|
template<typename Core, typename Handler>
|
66
66
|
void execute(Core core, Handler handler)
|
67
67
|
{
|
68
|
-
core->
|
68
|
+
core->open_bucket(
|
69
69
|
id.bucket(),
|
70
70
|
[core, id = id, timeout = timeout, specs = specs, parent_span = parent_span, h = std::forward<Handler>(handler)](
|
71
|
-
std::error_code ec
|
72
|
-
if (!config.capabilities.supports_subdoc_read_replica()) {
|
73
|
-
ec = errc::common::feature_not_available;
|
74
|
-
}
|
75
|
-
|
71
|
+
std::error_code ec) mutable {
|
76
72
|
if (ec) {
|
77
73
|
std::optional<std::string> first_error_path{};
|
78
74
|
std::optional<std::size_t> first_error_index{};
|
79
75
|
return h(response_type{
|
80
76
|
make_subdocument_error_context(make_key_value_error_context(ec, id), ec, first_error_path, first_error_index, false) });
|
81
77
|
}
|
82
|
-
|
78
|
+
core->with_bucket_configuration(
|
79
|
+
id.bucket(),
|
80
|
+
[core, id = id, timeout = timeout, specs = specs, parent_span = parent_span, h = std::forward<Handler>(h)](
|
81
|
+
std::error_code ec, const topology::configuration& config) mutable {
|
82
|
+
if (!config.capabilities.supports_subdoc_read_replica()) {
|
83
|
+
ec = errc::common::feature_not_available;
|
84
|
+
}
|
83
85
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
86
|
+
if (ec) {
|
87
|
+
std::optional<std::string> first_error_path{};
|
88
|
+
std::optional<std::size_t> first_error_index{};
|
89
|
+
return h(response_type{ make_subdocument_error_context(
|
90
|
+
make_key_value_error_context(ec, id), ec, first_error_path, first_error_index, false) });
|
91
|
+
}
|
92
|
+
using handler_type = utils::movable_function<void(response_type)>;
|
90
93
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
auto ctx = std::make_shared<replica_context>(std::move(h), config.num_replicas.value_or(0U) + 1U);
|
94
|
+
struct replica_context {
|
95
|
+
replica_context(handler_type handler, std::uint32_t expected_responses)
|
96
|
+
: handler_(std::move(handler))
|
97
|
+
, expected_responses_(expected_responses)
|
98
|
+
{
|
99
|
+
}
|
98
100
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
101
|
+
handler_type handler_;
|
102
|
+
std::uint32_t expected_responses_;
|
103
|
+
bool done_{ false };
|
104
|
+
std::mutex mutex_{};
|
105
|
+
std::vector<lookup_in_all_replicas_response::entry> result_{};
|
106
|
+
};
|
107
|
+
auto ctx = std::make_shared<replica_context>(std::move(h), config.num_replicas.value_or(0U) + 1U);
|
108
|
+
|
109
|
+
for (std::size_t idx = 1U; idx <= config.num_replicas.value_or(0U); ++idx) {
|
110
|
+
document_id replica_id{ id };
|
111
|
+
replica_id.node_index(idx);
|
112
|
+
core->execute(impl::lookup_in_replica_request{ std::move(replica_id), specs, timeout, parent_span },
|
113
|
+
[ctx](impl::lookup_in_replica_response&& resp) {
|
114
|
+
handler_type local_handler{};
|
115
|
+
{
|
116
|
+
std::scoped_lock lock(ctx->mutex_);
|
117
|
+
if (ctx->done_) {
|
118
|
+
return;
|
119
|
+
}
|
120
|
+
--ctx->expected_responses_;
|
121
|
+
if (resp.ctx.ec()) {
|
122
|
+
if (ctx->expected_responses_ > 0) {
|
123
|
+
// just ignore the response
|
124
|
+
return;
|
125
|
+
}
|
126
|
+
} else {
|
127
|
+
lookup_in_all_replicas_response::entry top_entry{};
|
128
|
+
top_entry.cas = resp.cas;
|
129
|
+
top_entry.deleted = resp.deleted;
|
130
|
+
top_entry.is_replica = true;
|
131
|
+
for (auto& field : resp.fields) {
|
132
|
+
lookup_in_all_replicas_response::entry::lookup_in_entry lookup_in_entry{};
|
133
|
+
lookup_in_entry.path = field.path;
|
134
|
+
lookup_in_entry.value = field.value;
|
135
|
+
lookup_in_entry.status = field.status;
|
136
|
+
lookup_in_entry.ec = field.ec;
|
137
|
+
lookup_in_entry.exists = field.exists;
|
138
|
+
lookup_in_entry.original_index = field.original_index;
|
139
|
+
lookup_in_entry.opcode = field.opcode;
|
140
|
+
top_entry.fields.emplace_back(lookup_in_entry);
|
141
|
+
}
|
142
|
+
ctx->result_.emplace_back(lookup_in_all_replicas_response::entry{ top_entry });
|
143
|
+
}
|
144
|
+
if (ctx->expected_responses_ == 0) {
|
145
|
+
ctx->done_ = true;
|
146
|
+
std::swap(local_handler, ctx->handler_);
|
147
|
+
}
|
148
|
+
}
|
149
|
+
if (local_handler) {
|
150
|
+
return local_handler({ std::move(resp.ctx), std::move(ctx->result_) });
|
151
|
+
}
|
152
|
+
});
|
153
|
+
}
|
144
154
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
155
|
+
core->execute(lookup_in_request{ document_id{ id }, {}, {}, false, specs, timeout }, [ctx](lookup_in_response&& resp) {
|
156
|
+
handler_type local_handler{};
|
157
|
+
{
|
158
|
+
std::scoped_lock lock(ctx->mutex_);
|
159
|
+
if (ctx->done_) {
|
160
|
+
return;
|
161
|
+
}
|
162
|
+
--ctx->expected_responses_;
|
163
|
+
if (resp.ctx.ec()) {
|
164
|
+
if (ctx->expected_responses_ > 0) {
|
165
|
+
// just ignore the response
|
166
|
+
return;
|
167
|
+
}
|
168
|
+
} else {
|
169
|
+
lookup_in_all_replicas_response::entry top_entry{};
|
170
|
+
top_entry.cas = resp.cas;
|
171
|
+
top_entry.deleted = resp.deleted;
|
172
|
+
top_entry.is_replica = false;
|
173
|
+
for (auto& field : resp.fields) {
|
174
|
+
lookup_in_all_replicas_response::entry::lookup_in_entry lookup_in_entry{};
|
175
|
+
lookup_in_entry.path = field.path;
|
176
|
+
lookup_in_entry.value = field.value;
|
177
|
+
lookup_in_entry.status = field.status;
|
178
|
+
lookup_in_entry.ec = field.ec;
|
179
|
+
lookup_in_entry.exists = field.exists;
|
180
|
+
lookup_in_entry.original_index = field.original_index;
|
181
|
+
lookup_in_entry.opcode = field.opcode;
|
182
|
+
top_entry.fields.emplace_back(lookup_in_entry);
|
183
|
+
}
|
184
|
+
ctx->result_.emplace_back(lookup_in_all_replicas_response::entry{ top_entry });
|
185
|
+
}
|
186
|
+
if (ctx->expected_responses_ == 0) {
|
187
|
+
ctx->done_ = true;
|
188
|
+
std::swap(local_handler, ctx->handler_);
|
189
|
+
}
|
190
|
+
}
|
191
|
+
if (local_handler) {
|
192
|
+
return local_handler({ std::move(resp.ctx), std::move(ctx->result_) });
|
193
|
+
}
|
194
|
+
});
|
195
|
+
});
|
185
196
|
});
|
186
197
|
}
|
187
198
|
};
|