couchbase 3.0.0.alpha.5-universal-darwin-19 → 3.0.0.beta.1-universal-darwin-19
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.
- checksums.yaml +4 -4
- data/Gemfile +12 -3
- data/README.md +4 -2
- data/Rakefile +1 -1
- data/couchbase.gemspec +17 -12
- data/ext/.idea/misc.xml +12 -0
- data/ext/CMakeLists.txt +10 -1
- data/ext/build_config.hxx.in +20 -0
- data/ext/build_version.hxx.in +1 -1
- data/ext/couchbase/bucket.hxx +90 -24
- data/ext/couchbase/cluster.hxx +125 -84
- data/ext/couchbase/cluster_options.hxx +53 -0
- data/ext/couchbase/configuration.hxx +220 -2
- data/ext/couchbase/couchbase.cxx +134 -127
- data/ext/couchbase/io/dns_client.hxx +3 -1
- data/ext/couchbase/io/http_command.hxx +91 -0
- data/ext/couchbase/io/http_session.hxx +58 -19
- data/ext/couchbase/io/http_session_manager.hxx +26 -31
- data/ext/couchbase/io/mcbp_command.hxx +180 -0
- data/ext/couchbase/io/mcbp_message.hxx +5 -0
- data/ext/couchbase/io/mcbp_session.hxx +213 -98
- data/ext/couchbase/io/streams.hxx +165 -0
- data/ext/couchbase/operations.hxx +1 -1
- data/ext/couchbase/operations/analytics_dataset_create.hxx +1 -1
- data/ext/couchbase/operations/bucket_create.hxx +4 -2
- data/ext/couchbase/operations/bucket_drop.hxx +4 -2
- data/ext/couchbase/operations/bucket_flush.hxx +4 -2
- data/ext/couchbase/operations/bucket_get.hxx +4 -2
- data/ext/couchbase/operations/bucket_get_all.hxx +4 -2
- data/ext/couchbase/operations/bucket_update.hxx +4 -2
- data/ext/couchbase/operations/cluster_developer_preview_enable.hxx +4 -2
- data/ext/couchbase/operations/collection_create.hxx +4 -2
- data/ext/couchbase/operations/collection_drop.hxx +4 -2
- data/ext/couchbase/operations/document_analytics.hxx +0 -4
- data/ext/couchbase/operations/document_decrement.hxx +6 -3
- data/ext/couchbase/operations/document_get.hxx +3 -0
- data/ext/couchbase/operations/document_get_and_lock.hxx +3 -0
- data/ext/couchbase/operations/document_get_and_touch.hxx +5 -2
- data/ext/couchbase/operations/document_get_projected.hxx +12 -9
- data/ext/couchbase/operations/document_increment.hxx +6 -3
- data/ext/couchbase/operations/document_insert.hxx +5 -2
- data/ext/couchbase/operations/document_lookup_in.hxx +3 -0
- data/ext/couchbase/operations/document_mutate_in.hxx +6 -3
- data/ext/couchbase/operations/document_remove.hxx +3 -0
- data/ext/couchbase/operations/document_replace.hxx +5 -2
- data/ext/couchbase/operations/document_search.hxx +6 -7
- data/ext/couchbase/operations/document_touch.hxx +5 -2
- data/ext/couchbase/operations/document_unlock.hxx +3 -0
- data/ext/couchbase/operations/document_upsert.hxx +5 -2
- data/ext/couchbase/operations/query_index_build_deferred.hxx +3 -3
- data/ext/couchbase/operations/query_index_create.hxx +3 -3
- data/ext/couchbase/operations/query_index_drop.hxx +3 -3
- data/ext/couchbase/operations/query_index_get_all.hxx +3 -3
- data/ext/couchbase/operations/scope_create.hxx +4 -2
- data/ext/couchbase/operations/scope_drop.hxx +4 -2
- data/ext/couchbase/operations/scope_get_all.hxx +4 -2
- data/ext/couchbase/operations/search_index_analyze_document.hxx +2 -2
- data/ext/couchbase/operations/search_index_control_ingest.hxx +2 -2
- data/ext/couchbase/operations/search_index_control_plan_freeze.hxx +2 -2
- data/ext/couchbase/operations/search_index_control_query.hxx +2 -2
- data/ext/couchbase/operations/search_index_drop.hxx +2 -2
- data/ext/couchbase/operations/search_index_get.hxx +2 -2
- data/ext/couchbase/operations/search_index_get_all.hxx +2 -2
- data/ext/couchbase/operations/search_index_get_documents_count.hxx +2 -2
- data/ext/couchbase/operations/search_index_upsert.hxx +2 -2
- data/ext/couchbase/origin.hxx +148 -0
- data/ext/couchbase/protocol/cmd_cluster_map_change_notification.hxx +1 -6
- data/ext/couchbase/protocol/cmd_decrement.hxx +5 -5
- data/ext/couchbase/protocol/cmd_get_and_touch.hxx +5 -5
- data/ext/couchbase/protocol/cmd_get_cluster_config.hxx +1 -6
- data/ext/couchbase/protocol/cmd_increment.hxx +5 -5
- data/ext/couchbase/protocol/cmd_info.hxx +0 -11
- data/ext/couchbase/protocol/cmd_insert.hxx +5 -5
- data/ext/couchbase/protocol/cmd_mutate_in.hxx +6 -6
- data/ext/couchbase/protocol/cmd_replace.hxx +5 -5
- data/ext/couchbase/protocol/cmd_touch.hxx +1 -1
- data/ext/couchbase/protocol/cmd_upsert.hxx +5 -5
- data/ext/couchbase/timeout_defaults.hxx +7 -0
- data/ext/couchbase/utils/connection_string.hxx +139 -0
- data/ext/extconf.rb +44 -11
- data/ext/test/main.cxx +93 -15
- data/ext/third_party/http_parser/Makefile +160 -0
- data/ext/third_party/json/Makefile +77 -0
- data/lib/couchbase/analytics_options.rb +18 -4
- data/lib/couchbase/binary_collection.rb +2 -2
- data/lib/couchbase/binary_collection_options.rb +2 -2
- data/lib/couchbase/bucket.rb +4 -4
- data/lib/couchbase/cluster.rb +60 -46
- data/lib/couchbase/collection.rb +13 -13
- data/lib/couchbase/collection_options.rb +15 -9
- data/{bin/console → lib/couchbase/datastructures.rb} +4 -7
- data/lib/couchbase/datastructures/couchbase_list.rb +171 -0
- data/lib/couchbase/datastructures/couchbase_map.rb +205 -0
- data/lib/couchbase/datastructures/couchbase_queue.rb +145 -0
- data/lib/couchbase/datastructures/couchbase_set.rb +138 -0
- data/lib/couchbase/errors.rb +66 -63
- data/lib/couchbase/libcouchbase.bundle +0 -0
- data/lib/couchbase/management/user_manager.rb +1 -1
- data/lib/couchbase/mutation_state.rb +1 -0
- data/lib/couchbase/query_options.rb +25 -2
- data/lib/couchbase/scope.rb +0 -7
- data/lib/couchbase/search_options.rb +7 -0
- data/lib/couchbase/version.rb +1 -1
- data/lib/couchbase/view_options.rb +4 -3
- metadata +20 -82
- data/.github/workflows/tests-6.0.3.yml +0 -52
- data/.github/workflows/tests-dev-preview.yml +0 -55
- data/.github/workflows/tests.yml +0 -50
- data/.gitignore +0 -20
- data/.gitmodules +0 -21
- data/.idea/.gitignore +0 -5
- data/.idea/dictionaries/gem_terms.xml +0 -18
- data/.idea/inspectionProfiles/Project_Default.xml +0 -8
- data/.idea/vcs.xml +0 -13
- data/bin/check-cluster +0 -31
- data/bin/fetch-stats +0 -19
- data/bin/init-cluster +0 -82
- data/bin/jenkins/build-extension +0 -35
- data/bin/jenkins/install-dependencies +0 -47
- data/bin/jenkins/test-with-cbdyncluster +0 -58
- data/bin/setup +0 -24
- data/ext/couchbase/configuration_monitor.hxx +0 -93
- data/ext/couchbase/operations/command.hxx +0 -163
- data/rbi/couchbase.rbi +0 -79
@@ -27,6 +27,7 @@
|
|
27
27
|
|
28
28
|
#include <io/mcbp_message.hxx>
|
29
29
|
#include <io/mcbp_parser.hxx>
|
30
|
+
#include <io/streams.hxx>
|
30
31
|
|
31
32
|
#include <timeout_defaults.hxx>
|
32
33
|
|
@@ -48,6 +49,7 @@
|
|
48
49
|
|
49
50
|
#include <spdlog/fmt/bin_to_hex.h>
|
50
51
|
|
52
|
+
#include <origin.hxx>
|
51
53
|
#include <errors.hxx>
|
52
54
|
#include <version.hxx>
|
53
55
|
|
@@ -118,8 +120,8 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
118
120
|
|
119
121
|
explicit bootstrap_handler(std::shared_ptr<mcbp_session> session)
|
120
122
|
: session_(session)
|
121
|
-
, sasl_([
|
122
|
-
[
|
123
|
+
, sasl_([origin = session_->origin_]() -> std::string { return origin.get_username(); },
|
124
|
+
[origin = session_->origin_]() -> std::string { return origin.get_password(); },
|
123
125
|
{ "SCRAM-SHA512", "SCRAM-SHA256", "SCRAM-SHA1", "PLAIN" })
|
124
126
|
{
|
125
127
|
tao::json::value user_agent{
|
@@ -155,10 +157,8 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
155
157
|
|
156
158
|
void complete(std::error_code ec)
|
157
159
|
{
|
160
|
+
stopped_ = true;
|
158
161
|
session_->invoke_bootstrap_handler(ec);
|
159
|
-
if (!ec) {
|
160
|
-
session_->handler_ = std::make_unique<normal_handler>(session_);
|
161
|
-
}
|
162
162
|
}
|
163
163
|
|
164
164
|
void auth_success()
|
@@ -282,7 +282,7 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
282
282
|
spdlog::warn("{} this server does not support GCCCP, open bucket before making any cluster-level command",
|
283
283
|
session_->log_prefix_);
|
284
284
|
session_->update_configuration(
|
285
|
-
make_blank_configuration(session_->
|
285
|
+
make_blank_configuration(session_->endpoint_address_, session_->endpoint_.port(), 0));
|
286
286
|
complete({});
|
287
287
|
} else {
|
288
288
|
spdlog::warn("{} unexpected message status during bootstrap: {} (opcode={})",
|
@@ -374,8 +374,9 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
374
374
|
opaque,
|
375
375
|
status,
|
376
376
|
ec.message());
|
377
|
-
handler->second
|
377
|
+
auto fun = handler->second;
|
378
378
|
session_->command_handlers_.erase(handler);
|
379
|
+
fun(ec, std::move(msg));
|
379
380
|
} else {
|
380
381
|
spdlog::debug("{} unexpected orphan response opcode={}, opaque={}",
|
381
382
|
session_->log_prefix_,
|
@@ -415,10 +416,7 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
415
416
|
|
416
417
|
void fetch_config(std::error_code ec)
|
417
418
|
{
|
418
|
-
if (ec == asio::error::operation_aborted) {
|
419
|
-
return;
|
420
|
-
}
|
421
|
-
if (stopped_ || !session_) {
|
419
|
+
if (ec == asio::error::operation_aborted || stopped_ || !session_) {
|
422
420
|
return;
|
423
421
|
}
|
424
422
|
protocol::client_request<protocol::get_cluster_config_request_body> req;
|
@@ -430,21 +428,46 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
430
428
|
};
|
431
429
|
|
432
430
|
public:
|
431
|
+
mcbp_session() = delete;
|
433
432
|
mcbp_session(const std::string& client_id,
|
434
433
|
asio::io_context& ctx,
|
434
|
+
const couchbase::origin& origin,
|
435
435
|
std::optional<std::string> bucket_name = {},
|
436
436
|
std::vector<protocol::hello_feature> known_features = {})
|
437
437
|
: client_id_(client_id)
|
438
438
|
, id_(uuid::to_string(uuid::random()))
|
439
439
|
, ctx_(ctx)
|
440
440
|
, resolver_(ctx_)
|
441
|
-
,
|
442
|
-
,
|
443
|
-
,
|
441
|
+
, stream_(std::make_unique<plain_stream_impl>(ctx_))
|
442
|
+
, bootstrap_deadline_(ctx_)
|
443
|
+
, connection_deadline_(ctx_)
|
444
|
+
, retry_backoff_(ctx_)
|
445
|
+
, origin_(origin)
|
444
446
|
, bucket_name_(std::move(bucket_name))
|
445
447
|
, supported_features_(known_features)
|
446
448
|
{
|
447
|
-
log_prefix_ = fmt::format("[{}/{}/{}]", client_id_, id_, bucket_name_.value_or("-"));
|
449
|
+
log_prefix_ = fmt::format("[{}/{}/{}/{}]", stream_->log_prefix(), client_id_, id_, bucket_name_.value_or("-"));
|
450
|
+
}
|
451
|
+
|
452
|
+
mcbp_session(const std::string& client_id,
|
453
|
+
asio::io_context& ctx,
|
454
|
+
asio::ssl::context& tls,
|
455
|
+
const couchbase::origin& origin,
|
456
|
+
std::optional<std::string> bucket_name = {},
|
457
|
+
std::vector<protocol::hello_feature> known_features = {})
|
458
|
+
: client_id_(client_id)
|
459
|
+
, id_(uuid::to_string(uuid::random()))
|
460
|
+
, ctx_(ctx)
|
461
|
+
, resolver_(ctx_)
|
462
|
+
, stream_(std::make_unique<tls_stream_impl>(ctx_, tls))
|
463
|
+
, bootstrap_deadline_(ctx_)
|
464
|
+
, connection_deadline_(ctx_)
|
465
|
+
, retry_backoff_(ctx_)
|
466
|
+
, origin_(origin)
|
467
|
+
, bucket_name_(std::move(bucket_name))
|
468
|
+
, supported_features_(known_features)
|
469
|
+
{
|
470
|
+
log_prefix_ = fmt::format("[{}/{}/{}/{}]", stream_->log_prefix(), client_id_, id_, bucket_name_.value_or("-"));
|
448
471
|
}
|
449
472
|
|
450
473
|
~mcbp_session()
|
@@ -452,17 +475,53 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
452
475
|
stop();
|
453
476
|
}
|
454
477
|
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
478
|
+
[[nodiscard]] const std::string& log_prefix() const
|
479
|
+
{
|
480
|
+
return log_prefix_;
|
481
|
+
}
|
482
|
+
|
483
|
+
void bootstrap(std::function<void(std::error_code, configuration)>&& handler)
|
460
484
|
{
|
461
|
-
username_ = username;
|
462
|
-
password_ = password;
|
463
485
|
bootstrap_handler_ = std::move(handler);
|
464
|
-
|
465
|
-
|
486
|
+
bootstrap_deadline_.expires_after(timeout_defaults::bootstrap_timeout);
|
487
|
+
bootstrap_deadline_.async_wait([self = shared_from_this()](std::error_code ec) {
|
488
|
+
if (ec == asio::error::operation_aborted || self->stopped_) {
|
489
|
+
return;
|
490
|
+
}
|
491
|
+
spdlog::warn("{} unable to bootstrap in time", self->log_prefix_);
|
492
|
+
self->bootstrap_handler_(std::make_error_code(error::common_errc::unambiguous_timeout), {});
|
493
|
+
self->bootstrap_handler_ = nullptr;
|
494
|
+
self->stop();
|
495
|
+
});
|
496
|
+
initiate_bootstrap();
|
497
|
+
}
|
498
|
+
|
499
|
+
void initiate_bootstrap()
|
500
|
+
{
|
501
|
+
if (stopped_) {
|
502
|
+
return;
|
503
|
+
}
|
504
|
+
if (origin_.exhausted()) {
|
505
|
+
auto backoff = std::chrono::milliseconds(500);
|
506
|
+
spdlog::debug("{} reached the end of list of bootstrap nodes, waiting for {}ms before restart", log_prefix_, backoff.count());
|
507
|
+
retry_backoff_.expires_after(backoff);
|
508
|
+
retry_backoff_.async_wait([self = shared_from_this()](std::error_code ec) mutable {
|
509
|
+
if (ec == asio::error::operation_aborted || self->stopped_) {
|
510
|
+
return;
|
511
|
+
}
|
512
|
+
self->origin_.restart();
|
513
|
+
self->initiate_bootstrap();
|
514
|
+
});
|
515
|
+
return;
|
516
|
+
}
|
517
|
+
std::string service;
|
518
|
+
std::tie(bootstrap_hostname_, service) = origin_.next_address();
|
519
|
+
log_prefix_ = fmt::format(
|
520
|
+
"[{}/{}/{}/{}] <{}:{}>", stream_->log_prefix(), client_id_, id_, bucket_name_.value_or("-"), bootstrap_hostname_, service);
|
521
|
+
spdlog::debug("{} attempt to establish MCBP connection", log_prefix_);
|
522
|
+
resolver_.async_resolve(bootstrap_hostname_,
|
523
|
+
service,
|
524
|
+
std::bind(&mcbp_session::on_resolve, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
|
466
525
|
}
|
467
526
|
|
468
527
|
[[nodiscard]] const std::string& id() const
|
@@ -476,14 +535,26 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
476
535
|
return;
|
477
536
|
}
|
478
537
|
stopped_ = true;
|
479
|
-
|
538
|
+
bootstrap_deadline_.cancel();
|
539
|
+
connection_deadline_.cancel();
|
540
|
+
retry_backoff_.cancel();
|
480
541
|
resolver_.cancel();
|
481
|
-
if (
|
482
|
-
|
542
|
+
if (stream_->is_open()) {
|
543
|
+
stream_->close();
|
544
|
+
}
|
545
|
+
auto ec = std::make_error_code(error::common_errc::request_canceled);
|
546
|
+
if (!bootstrapped_ && bootstrap_handler_) {
|
547
|
+
bootstrap_handler_(ec, {});
|
548
|
+
bootstrap_handler_ = nullptr;
|
483
549
|
}
|
484
550
|
if (handler_) {
|
485
551
|
handler_->stop();
|
486
552
|
}
|
553
|
+
for (auto& handler : command_handlers_) {
|
554
|
+
spdlog::debug("{} MCBP cancel operation during session close, opaque={}, ec={}", log_prefix_, handler.first, ec.message());
|
555
|
+
handler.second(ec, {});
|
556
|
+
}
|
557
|
+
command_handlers_.clear();
|
487
558
|
}
|
488
559
|
|
489
560
|
void write(const std::vector<uint8_t>& buf)
|
@@ -491,6 +562,11 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
491
562
|
if (stopped_) {
|
492
563
|
return;
|
493
564
|
}
|
565
|
+
std::uint32_t opaque{ 0 };
|
566
|
+
std::memcpy(&opaque, buf.data() + 12, sizeof(opaque));
|
567
|
+
spdlog::debug("{} MCBP send, opaque={}, {:n}", log_prefix_, opaque, spdlog::to_hex(buf.begin(), buf.begin() + 24));
|
568
|
+
SPDLOG_TRACE("{} MCBP send, opaque={}{:a}", log_prefix_, opaque, spdlog::to_hex(data));
|
569
|
+
std::scoped_lock lock(output_buffer_mutex_);
|
494
570
|
output_buffer_.push_back(buf);
|
495
571
|
}
|
496
572
|
|
@@ -516,14 +592,15 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
516
592
|
std::function<void(std::error_code, io::mcbp_message&&)> handler)
|
517
593
|
{
|
518
594
|
if (stopped_) {
|
595
|
+
spdlog::warn("{} MCBP cancel operation, while trying to write to closed session opaque={}", log_prefix_, opaque);
|
596
|
+
handler(std::make_error_code(error::common_errc::request_canceled), {});
|
519
597
|
return;
|
520
598
|
}
|
521
|
-
spdlog::trace(
|
522
|
-
"{} MCBP send, opaque={}{:a}", log_prefix_, endpoint_.address().to_string(), endpoint_.port(), opaque, spdlog::to_hex(data));
|
523
599
|
command_handlers_.emplace(opaque, std::move(handler));
|
524
|
-
if (bootstrapped_ &&
|
600
|
+
if (bootstrapped_ && stream_->is_open()) {
|
525
601
|
write_and_flush(data);
|
526
602
|
} else {
|
603
|
+
std::scoped_lock lock(pending_buffer_mutex_);
|
527
604
|
pending_buffer_.push_back(data);
|
528
605
|
}
|
529
606
|
}
|
@@ -572,6 +649,11 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
572
649
|
return config_->index_for_this_node();
|
573
650
|
}
|
574
651
|
|
652
|
+
[[nodiscard]] const std::string& bootstrap_hostname() const
|
653
|
+
{
|
654
|
+
return bootstrap_hostname_;
|
655
|
+
}
|
656
|
+
|
575
657
|
[[nodiscard]] uint32_t next_opaque()
|
576
658
|
{
|
577
659
|
return ++opaque_;
|
@@ -717,7 +799,15 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
717
799
|
|
718
800
|
void update_configuration(configuration&& config)
|
719
801
|
{
|
802
|
+
if (stopped_) {
|
803
|
+
return;
|
804
|
+
}
|
720
805
|
if (!config_ || config.rev > config_->rev) {
|
806
|
+
for (auto& node : config.nodes) {
|
807
|
+
if (node.this_node && node.hostname.empty()) {
|
808
|
+
node.hostname = endpoint_address_;
|
809
|
+
}
|
810
|
+
}
|
721
811
|
config_.emplace(config);
|
722
812
|
spdlog::debug("{} received new configuration: {}", log_prefix_, config_.value());
|
723
813
|
}
|
@@ -730,6 +820,9 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
730
820
|
|
731
821
|
void update_collection_uid(const std::string& path, std::uint32_t uid)
|
732
822
|
{
|
823
|
+
if (stopped_) {
|
824
|
+
return;
|
825
|
+
}
|
733
826
|
collection_cache_.update(path, uid);
|
734
827
|
}
|
735
828
|
|
@@ -737,13 +830,16 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
737
830
|
void invoke_bootstrap_handler(std::error_code ec)
|
738
831
|
{
|
739
832
|
if (!bootstrapped_ && bootstrap_handler_) {
|
833
|
+
bootstrap_deadline_.cancel();
|
740
834
|
bootstrap_handler_(ec, config_.value_or(configuration{}));
|
741
835
|
bootstrap_handler_ = nullptr;
|
742
836
|
}
|
743
|
-
bootstrapped_ = true;
|
744
837
|
if (ec) {
|
745
|
-
stop();
|
838
|
+
return stop();
|
746
839
|
}
|
840
|
+
bootstrapped_ = true;
|
841
|
+
handler_ = std::make_unique<normal_handler>(shared_from_this());
|
842
|
+
std::scoped_lock lock(pending_buffer_mutex_);
|
747
843
|
if (!pending_buffer_.empty()) {
|
748
844
|
for (const auto& buf : pending_buffer_) {
|
749
845
|
write(buf);
|
@@ -760,11 +856,12 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
760
856
|
}
|
761
857
|
if (ec) {
|
762
858
|
spdlog::error("{} error on resolve: {}", log_prefix_, ec.message());
|
763
|
-
return
|
859
|
+
return initiate_bootstrap();
|
764
860
|
}
|
765
861
|
endpoints_ = endpoints;
|
766
862
|
do_connect(endpoints_.begin());
|
767
|
-
|
863
|
+
connection_deadline_.expires_after(timeout_defaults::connect_timeout);
|
864
|
+
connection_deadline_.async_wait(std::bind(&mcbp_session::check_deadline, shared_from_this(), std::placeholders::_1));
|
768
865
|
}
|
769
866
|
|
770
867
|
void do_connect(asio::ip::tcp::resolver::results_type::iterator it)
|
@@ -774,12 +871,11 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
774
871
|
}
|
775
872
|
if (it != endpoints_.end()) {
|
776
873
|
spdlog::debug("{} connecting to {}:{}", log_prefix_, it->endpoint().address().to_string(), it->endpoint().port());
|
777
|
-
|
778
|
-
|
874
|
+
connection_deadline_.expires_after(timeout_defaults::connect_timeout);
|
875
|
+
stream_->async_connect(it->endpoint(), std::bind(&mcbp_session::on_connect, shared_from_this(), std::placeholders::_1, it));
|
779
876
|
} else {
|
780
|
-
spdlog::error("{} no more endpoints left to connect", log_prefix_);
|
781
|
-
|
782
|
-
stop();
|
877
|
+
spdlog::error("{} no more endpoints left to connect, will try another address", log_prefix_);
|
878
|
+
return initiate_bootstrap();
|
783
879
|
}
|
784
880
|
}
|
785
881
|
|
@@ -788,34 +884,39 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
788
884
|
if (stopped_) {
|
789
885
|
return;
|
790
886
|
}
|
791
|
-
if (!
|
887
|
+
if (!stream_->is_open() || ec) {
|
888
|
+
spdlog::warn(
|
889
|
+
"{} unable to connect to {}:{}: {}", log_prefix_, it->endpoint().address().to_string(), it->endpoint().port(), ec.message());
|
792
890
|
do_connect(++it);
|
793
891
|
} else {
|
794
|
-
|
795
|
-
socket_.set_option(asio::socket_base::keep_alive{ true });
|
892
|
+
stream_->set_options();
|
796
893
|
endpoint_ = it->endpoint();
|
797
|
-
|
798
|
-
log_prefix_
|
799
|
-
|
894
|
+
endpoint_address_ = endpoint_.address().to_string();
|
895
|
+
spdlog::debug("{} connected to {}:{}", log_prefix_, endpoint_address_, it->endpoint().port());
|
896
|
+
log_prefix_ = fmt::format("[{}/{}/{}/{}] <{}/{}:{}>",
|
897
|
+
stream_->log_prefix(),
|
898
|
+
client_id_,
|
899
|
+
id_,
|
900
|
+
bucket_name_.value_or("-"),
|
901
|
+
bootstrap_hostname_,
|
902
|
+
endpoint_address_,
|
903
|
+
endpoint_.port());
|
800
904
|
handler_ = std::make_unique<bootstrap_handler>(shared_from_this());
|
801
|
-
|
802
|
-
|
905
|
+
connection_deadline_.expires_at(asio::steady_timer::time_point::max());
|
906
|
+
connection_deadline_.cancel();
|
803
907
|
}
|
804
908
|
}
|
805
909
|
|
806
910
|
void check_deadline(std::error_code ec)
|
807
911
|
{
|
808
|
-
if (ec == asio::error::operation_aborted) {
|
809
|
-
return;
|
810
|
-
}
|
811
|
-
if (stopped_) {
|
912
|
+
if (ec == asio::error::operation_aborted || stopped_) {
|
812
913
|
return;
|
813
914
|
}
|
814
|
-
if (
|
815
|
-
|
816
|
-
|
915
|
+
if (connection_deadline_.expiry() <= asio::steady_timer::clock_type::now()) {
|
916
|
+
stream_->close();
|
917
|
+
connection_deadline_.expires_at(asio::steady_timer::time_point::max());
|
817
918
|
}
|
818
|
-
|
919
|
+
connection_deadline_.async_wait(std::bind(&mcbp_session::check_deadline, shared_from_this(), std::placeholders::_1));
|
819
920
|
}
|
820
921
|
|
821
922
|
void do_read()
|
@@ -827,36 +928,44 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
827
928
|
return;
|
828
929
|
}
|
829
930
|
reading_ = true;
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
931
|
+
stream_->async_read_some(
|
932
|
+
asio::buffer(input_buffer_), [self = shared_from_this()](std::error_code ec, std::size_t bytes_transferred) {
|
933
|
+
if (ec == asio::error::operation_aborted || self->stopped_) {
|
934
|
+
return;
|
935
|
+
}
|
936
|
+
if (ec) {
|
937
|
+
spdlog::error("{} IO error while reading from the socket: {}", self->log_prefix_, ec.message());
|
938
|
+
return self->stop();
|
939
|
+
}
|
940
|
+
self->parser_.feed(self->input_buffer_.data(), self->input_buffer_.data() + ssize_t(bytes_transferred));
|
941
|
+
|
942
|
+
for (;;) {
|
943
|
+
mcbp_message msg{};
|
944
|
+
switch (self->parser_.next(msg)) {
|
945
|
+
case mcbp_parser::ok:
|
946
|
+
spdlog::debug(
|
947
|
+
"{} MCBP recv, opaque={}, {:n}", self->log_prefix_, msg.header.opaque, spdlog::to_hex(msg.header_data()));
|
948
|
+
SPDLOG_TRACE("{} MCBP recv, opaque={}{:a}{:a}",
|
949
|
+
self->log_prefix_,
|
950
|
+
msg.header.opaque,
|
951
|
+
spdlog::to_hex(msg.header_data()),
|
952
|
+
spdlog::to_hex(msg.body));
|
953
|
+
self->handler_->handle(std::move(msg));
|
954
|
+
if (self->stopped_) {
|
955
|
+
return;
|
956
|
+
}
|
957
|
+
break;
|
958
|
+
case mcbp_parser::need_data:
|
959
|
+
self->reading_ = false;
|
960
|
+
if (!self->stopped_) {
|
961
|
+
self->do_read();
|
962
|
+
}
|
963
|
+
return;
|
964
|
+
case mcbp_parser::failure:
|
965
|
+
return self->stop();
|
966
|
+
}
|
967
|
+
}
|
968
|
+
});
|
860
969
|
}
|
861
970
|
|
862
971
|
void do_write()
|
@@ -864,7 +973,8 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
864
973
|
if (stopped_) {
|
865
974
|
return;
|
866
975
|
}
|
867
|
-
|
976
|
+
std::scoped_lock lock(writing_buffer_mutex_, output_buffer_mutex_);
|
977
|
+
if (!writing_buffer_.empty() || output_buffer_.empty()) {
|
868
978
|
return;
|
869
979
|
}
|
870
980
|
std::swap(writing_buffer_, output_buffer_);
|
@@ -873,18 +983,19 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
873
983
|
for (auto& buf : writing_buffer_) {
|
874
984
|
buffers.emplace_back(asio::buffer(buf));
|
875
985
|
}
|
876
|
-
|
877
|
-
if (self->stopped_) {
|
986
|
+
stream_->async_write(buffers, [self = shared_from_this()](std::error_code ec, std::size_t /*unused*/) {
|
987
|
+
if (ec == asio::error::operation_aborted || self->stopped_) {
|
878
988
|
return;
|
879
989
|
}
|
880
990
|
if (ec) {
|
881
991
|
spdlog::error("{} IO error while writing to the socket: {}", self->log_prefix_, ec.message());
|
882
992
|
return self->stop();
|
883
993
|
}
|
884
|
-
|
885
|
-
|
886
|
-
self->
|
994
|
+
{
|
995
|
+
std::scoped_lock inner_lock(self->writing_buffer_mutex_);
|
996
|
+
self->writing_buffer_.clear();
|
887
997
|
}
|
998
|
+
self->do_write();
|
888
999
|
self->do_read();
|
889
1000
|
});
|
890
1001
|
}
|
@@ -893,13 +1004,15 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
893
1004
|
std::string id_;
|
894
1005
|
asio::io_context& ctx_;
|
895
1006
|
asio::ip::tcp::resolver resolver_;
|
896
|
-
|
897
|
-
asio::
|
898
|
-
asio::steady_timer
|
1007
|
+
std::unique_ptr<stream_impl> stream_;
|
1008
|
+
asio::steady_timer bootstrap_deadline_;
|
1009
|
+
asio::steady_timer connection_deadline_;
|
1010
|
+
asio::steady_timer retry_backoff_;
|
1011
|
+
couchbase::origin origin_;
|
899
1012
|
std::optional<std::string> bucket_name_;
|
900
1013
|
mcbp_parser parser_;
|
901
1014
|
std::unique_ptr<message_handler> handler_;
|
902
|
-
std::function<void(std::error_code, configuration)> bootstrap_handler_;
|
1015
|
+
std::function<void(std::error_code, const configuration&)> bootstrap_handler_{};
|
903
1016
|
std::map<uint32_t, std::function<void(std::error_code, io::mcbp_message&&)>> command_handlers_{};
|
904
1017
|
|
905
1018
|
bool bootstrapped_{ false };
|
@@ -910,14 +1023,16 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
910
1023
|
|
911
1024
|
std::atomic<std::uint32_t> opaque_{ 0 };
|
912
1025
|
|
913
|
-
std::string username_;
|
914
|
-
std::string password_;
|
915
|
-
|
916
1026
|
std::array<std::uint8_t, 16384> input_buffer_{};
|
917
1027
|
std::vector<std::vector<std::uint8_t>> output_buffer_{};
|
918
1028
|
std::vector<std::vector<std::uint8_t>> pending_buffer_{};
|
919
1029
|
std::vector<std::vector<std::uint8_t>> writing_buffer_{};
|
1030
|
+
std::mutex output_buffer_mutex_{};
|
1031
|
+
std::mutex pending_buffer_mutex_{};
|
1032
|
+
std::mutex writing_buffer_mutex_{};
|
1033
|
+
std::string bootstrap_hostname_{};
|
920
1034
|
asio::ip::tcp::endpoint endpoint_{}; // connected endpoint
|
1035
|
+
std::string endpoint_address_{}; // cached string with endpoint address
|
921
1036
|
asio::ip::tcp::resolver::results_type endpoints_;
|
922
1037
|
std::vector<protocol::hello_feature> supported_features_;
|
923
1038
|
std::optional<configuration> config_;
|