couchbase 3.0.0.alpha.5 → 3.0.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- 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/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_;
|