couchbase 3.4.0 → 3.4.2
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/README.md +2 -2
- data/ext/couchbase/CMakeLists.txt +10 -3
- data/ext/couchbase/cmake/CompilerWarnings.cmake +12 -4
- data/ext/couchbase/cmake/Documentation.cmake +4 -3
- data/ext/couchbase/cmake/OpenSSL.cmake +52 -7
- data/ext/couchbase/cmake/ThirdPartyDependencies.cmake +4 -0
- data/ext/couchbase/cmake/VersionInfo.cmake +39 -3
- data/ext/couchbase/cmake/test_openssl.cxx +7 -0
- data/ext/couchbase/core/cluster_options.hxx +0 -1
- data/ext/couchbase/core/config_profile.cxx +23 -1
- data/ext/couchbase/core/config_profile.hxx +2 -12
- data/ext/couchbase/core/crypto/CMakeLists.txt +5 -1
- data/ext/couchbase/core/impl/analytics.cxx +236 -0
- data/ext/couchbase/core/impl/cluster.cxx +0 -1
- data/ext/couchbase/core/impl/collection_query_index_manager.cxx +3 -3
- data/ext/couchbase/core/impl/dns_srv_tracker.cxx +5 -3
- data/ext/couchbase/core/impl/get_all_query_indexes.cxx +3 -3
- data/ext/couchbase/core/impl/query.cxx +5 -5
- data/ext/couchbase/core/impl/transaction_get_result.cxx +54 -0
- data/ext/couchbase/core/io/dns_client.cxx +225 -0
- data/ext/couchbase/core/io/dns_client.hxx +19 -188
- data/ext/couchbase/core/meta/CMakeLists.txt +7 -5
- data/ext/couchbase/core/meta/version.cxx +19 -0
- data/ext/couchbase/core/operations/document_search.cxx +5 -2
- data/ext/couchbase/core/operations/document_search.hxx +0 -1
- data/ext/couchbase/core/transactions/active_transaction_record.hxx +2 -2
- data/ext/couchbase/core/transactions/atr_cleanup_entry.cxx +1 -0
- data/ext/couchbase/core/transactions/attempt_context_impl.cxx +65 -31
- data/ext/couchbase/core/transactions/attempt_context_impl.hxx +44 -23
- data/ext/couchbase/core/transactions/forward_compat.hxx +2 -2
- data/ext/couchbase/core/transactions/internal/transaction_context.hxx +13 -13
- data/ext/couchbase/core/transactions/internal/transaction_fields.hxx +1 -0
- data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +7 -1
- data/ext/couchbase/core/transactions/staged_mutation.cxx +1 -1
- data/ext/couchbase/core/transactions/staged_mutation.hxx +12 -2
- data/ext/couchbase/core/transactions/transaction_context.cxx +9 -11
- data/ext/couchbase/core/transactions/transaction_get_result.cxx +41 -31
- data/ext/couchbase/core/transactions/transaction_get_result.hxx +7 -3
- data/ext/couchbase/core/transactions/transaction_links.hxx +13 -1
- data/ext/couchbase/core/transactions/transactions_cleanup.cxx +144 -155
- data/ext/couchbase/core/transactions/waitable_op_list.hxx +1 -0
- data/ext/couchbase/core/utils/connection_string.cxx +10 -3
- data/ext/couchbase/core/utils/connection_string.hxx +3 -3
- data/ext/couchbase/couchbase/analytics_error_context.hxx +143 -0
- data/ext/couchbase/couchbase/analytics_meta_data.hxx +155 -0
- data/ext/couchbase/couchbase/analytics_metrics.hxx +163 -0
- data/ext/couchbase/couchbase/analytics_options.hxx +359 -0
- data/ext/couchbase/couchbase/analytics_result.hxx +102 -0
- data/ext/couchbase/couchbase/analytics_scan_consistency.hxx +46 -0
- data/ext/couchbase/couchbase/analytics_status.hxx +41 -0
- data/ext/couchbase/couchbase/analytics_warning.hxx +85 -0
- data/ext/couchbase/couchbase/cluster.hxx +35 -2
- data/ext/couchbase/couchbase/cluster_options.hxx +10 -10
- data/ext/couchbase/couchbase/collection.hxx +22 -17
- data/ext/couchbase/couchbase/collection_query_index_manager.hxx +1 -1
- data/ext/couchbase/couchbase/common_options.hxx +1 -1
- data/ext/couchbase/couchbase/configuration_profile.hxx +1 -1
- data/ext/couchbase/couchbase/configuration_profiles_registry.hxx +0 -1
- data/ext/couchbase/couchbase/create_primary_query_index_options.hxx +1 -1
- data/ext/couchbase/couchbase/drop_primary_query_index_options.hxx +1 -1
- data/ext/couchbase/couchbase/drop_query_index_options.hxx +1 -1
- data/ext/couchbase/couchbase/fmt/analytics_status.hxx +76 -0
- data/ext/couchbase/couchbase/fmt/cas.hxx +12 -0
- data/ext/couchbase/couchbase/fmt/durability_level.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/key_value_extended_error_info.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/key_value_status_code.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/mutation_token.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/query_scan_consistency.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/query_status.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/retry_reason.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/tls_verify_mode.hxx +6 -0
- data/ext/couchbase/couchbase/get_all_query_indexes_options.hxx +5 -4
- data/ext/couchbase/couchbase/query_index_manager.hxx +4 -2
- data/ext/couchbase/couchbase/query_options.hxx +0 -1
- data/ext/couchbase/couchbase/scope.hxx +34 -1
- data/ext/couchbase/couchbase/subdoc/array_add_unique.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/array_append.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/array_insert.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/array_prepend.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/count.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/counter.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/exists.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/get.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/insert.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/remove.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/replace.hxx +3 -1
- data/ext/couchbase/couchbase/subdoc/upsert.hxx +2 -0
- data/ext/couchbase/couchbase/transaction_op_error_context.hxx +4 -4
- data/ext/couchbase/couchbase/transactions/attempt_context.hxx +1 -1
- data/ext/couchbase/couchbase/transactions/transaction_get_result.hxx +36 -51
- data/ext/couchbase/couchbase/transactions/transactions_config.hxx +1 -1
- data/ext/couchbase/test/CMakeLists.txt +3 -2
- data/ext/couchbase/test/test_helper.hxx +1 -1
- data/ext/couchbase/test/test_integration_analytics.cxx +289 -13
- data/ext/couchbase/test/test_integration_crud.cxx +8 -1
- data/ext/couchbase/test/test_integration_examples.cxx +182 -0
- data/ext/couchbase/test/test_integration_management.cxx +15 -3
- data/ext/couchbase/test/test_integration_search.cxx +601 -0
- data/ext/couchbase/test/test_transaction_transaction_simple.cxx +73 -0
- data/ext/couchbase/test/test_unit_config_profiles.cxx +12 -12
- data/ext/couchbase/test/test_unit_connection_string.cxx +35 -0
- data/ext/couchbase/test/test_unit_transaction_utils.cxx +76 -19
- data/ext/couchbase/third_party/snappy/CMakeLists.txt +150 -27
- data/ext/couchbase/third_party/snappy/cmake/config.h.in +28 -24
- data/ext/couchbase/third_party/snappy/snappy-internal.h +189 -25
- data/ext/couchbase/third_party/snappy/snappy-sinksource.cc +26 -9
- data/ext/couchbase/third_party/snappy/snappy-sinksource.h +11 -11
- data/ext/couchbase/third_party/snappy/snappy-stubs-internal.cc +1 -1
- data/ext/couchbase/third_party/snappy/snappy-stubs-internal.h +227 -308
- data/ext/couchbase/third_party/snappy/snappy-stubs-public.h.in +0 -11
- data/ext/couchbase/third_party/snappy/snappy.cc +1176 -410
- data/ext/couchbase/third_party/snappy/snappy.h +19 -4
- data/ext/couchbase.cxx +506 -26
- data/ext/extconf.rb +2 -1
- data/ext/revisions.rb +3 -2
- data/lib/couchbase/binary_collection.rb +4 -4
- data/lib/couchbase/cluster.rb +13 -9
- data/lib/couchbase/cluster_registry.rb +7 -2
- data/lib/couchbase/collection.rb +5 -0
- data/lib/couchbase/configuration.rb +3 -4
- data/lib/couchbase/errors.rb +10 -0
- data/lib/couchbase/management/collection_query_index_manager.rb +183 -0
- data/lib/couchbase/management/query_index_manager.rb +35 -3
- data/lib/couchbase/management.rb +1 -0
- data/lib/couchbase/options.rb +87 -5
- data/lib/couchbase/search_options.rb +158 -240
- data/lib/couchbase/version.rb +1 -1
- metadata +21 -6
- data/ext/couchbase/core/CMakeLists.txt +0 -0
|
@@ -45,7 +45,7 @@ initiate_get_all_query_indexes(std::shared_ptr<couchbase::core::cluster> core,
|
|
|
45
45
|
couchbase::get_all_query_indexes_options::built options,
|
|
46
46
|
query_context query_ctx,
|
|
47
47
|
std::string collection_name,
|
|
48
|
-
|
|
48
|
+
get_all_query_indexes_handler&& handler)
|
|
49
49
|
{
|
|
50
50
|
core->execute(
|
|
51
51
|
operations::management::query_index_get_all_request{
|
|
@@ -68,9 +68,9 @@ void
|
|
|
68
68
|
initiate_get_all_query_indexes(std::shared_ptr<couchbase::core::cluster> core,
|
|
69
69
|
std::string bucket_name,
|
|
70
70
|
couchbase::get_all_query_indexes_options::built options,
|
|
71
|
-
|
|
71
|
+
get_all_query_indexes_handler&& handler)
|
|
72
72
|
{
|
|
73
73
|
initiate_get_all_query_indexes(core, std::move(bucket_name), options, {}, "", std::move(handler));
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
} // namespace couchbase::core::impl
|
|
76
|
+
} // namespace couchbase::core::impl
|
|
@@ -152,10 +152,10 @@ build_result(operations::query_response& resp)
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
static core::operations::query_request
|
|
155
|
-
build_query_request(query_options::built options)
|
|
155
|
+
build_query_request(std::string statement, query_options::built options)
|
|
156
156
|
{
|
|
157
157
|
operations::query_request request{
|
|
158
|
-
|
|
158
|
+
std::move(statement),
|
|
159
159
|
options.adhoc,
|
|
160
160
|
options.metrics,
|
|
161
161
|
options.readonly,
|
|
@@ -222,8 +222,9 @@ build_transaction_query_result(operations::query_response resp, std::error_code
|
|
|
222
222
|
core::operations::query_request
|
|
223
223
|
build_transaction_query_request(query_options::built opts)
|
|
224
224
|
{
|
|
225
|
-
return build_query_request(opts);
|
|
225
|
+
return build_query_request("", opts);
|
|
226
226
|
}
|
|
227
|
+
|
|
227
228
|
void
|
|
228
229
|
initiate_query_operation(std::shared_ptr<couchbase::core::cluster> core,
|
|
229
230
|
std::string statement,
|
|
@@ -231,8 +232,7 @@ initiate_query_operation(std::shared_ptr<couchbase::core::cluster> core,
|
|
|
231
232
|
query_options::built options,
|
|
232
233
|
query_handler&& handler)
|
|
233
234
|
{
|
|
234
|
-
auto request = build_query_request(options);
|
|
235
|
-
request.statement = std::move(statement);
|
|
235
|
+
auto request = build_query_request(std::move(statement), options);
|
|
236
236
|
if (query_context) {
|
|
237
237
|
request.query_context = std::move(query_context);
|
|
238
238
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
#include <core/transactions/transaction_get_result.hxx>
|
|
4
|
+
#include <couchbase/transactions/transaction_get_result.hxx>
|
|
5
|
+
|
|
6
|
+
namespace couchbase::transactions
|
|
7
|
+
{
|
|
8
|
+
|
|
9
|
+
transaction_get_result::transaction_get_result()
|
|
10
|
+
: base_(std::make_shared<couchbase::core::transactions::transaction_get_result>())
|
|
11
|
+
{
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const std::vector<std::byte>&
|
|
15
|
+
transaction_get_result::content() const
|
|
16
|
+
{
|
|
17
|
+
return base_->content();
|
|
18
|
+
}
|
|
19
|
+
void
|
|
20
|
+
transaction_get_result::content(std::vector<std::byte> content)
|
|
21
|
+
{
|
|
22
|
+
return base_->content(content);
|
|
23
|
+
}
|
|
24
|
+
void
|
|
25
|
+
transaction_get_result::content(std::vector<std::byte>&& content)
|
|
26
|
+
{
|
|
27
|
+
return base_->content(content);
|
|
28
|
+
}
|
|
29
|
+
const std::string
|
|
30
|
+
transaction_get_result::key() const
|
|
31
|
+
{
|
|
32
|
+
return base_->key();
|
|
33
|
+
}
|
|
34
|
+
const std::string
|
|
35
|
+
transaction_get_result::bucket() const
|
|
36
|
+
{
|
|
37
|
+
return base_->bucket();
|
|
38
|
+
}
|
|
39
|
+
const std::string
|
|
40
|
+
transaction_get_result::scope() const
|
|
41
|
+
{
|
|
42
|
+
return base_->scope();
|
|
43
|
+
}
|
|
44
|
+
const std::string
|
|
45
|
+
transaction_get_result::collection() const
|
|
46
|
+
{
|
|
47
|
+
return base_->collection();
|
|
48
|
+
}
|
|
49
|
+
const couchbase::cas
|
|
50
|
+
transaction_get_result::cas() const
|
|
51
|
+
{
|
|
52
|
+
return base_->cas();
|
|
53
|
+
}
|
|
54
|
+
} // namespace couchbase::transactions
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2020-Present Couchbase, Inc.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#include "dns_client.hxx"
|
|
19
|
+
|
|
20
|
+
#include "core/logger/logger.hxx"
|
|
21
|
+
#include "core/utils/join_strings.hxx"
|
|
22
|
+
#include "dns_codec.hxx"
|
|
23
|
+
#include "dns_config.hxx"
|
|
24
|
+
|
|
25
|
+
#include <couchbase/error_codes.hxx>
|
|
26
|
+
|
|
27
|
+
#include <asio/ip/tcp.hpp>
|
|
28
|
+
#include <asio/read.hpp>
|
|
29
|
+
#include <asio/write.hpp>
|
|
30
|
+
|
|
31
|
+
#include <memory>
|
|
32
|
+
#include <sstream>
|
|
33
|
+
|
|
34
|
+
namespace couchbase::core::io::dns
|
|
35
|
+
{
|
|
36
|
+
class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
|
|
37
|
+
{
|
|
38
|
+
public:
|
|
39
|
+
dns_srv_command(asio::io_context& ctx,
|
|
40
|
+
const std::string& name,
|
|
41
|
+
const std::string& service,
|
|
42
|
+
const asio::ip::address& address,
|
|
43
|
+
std::uint16_t port,
|
|
44
|
+
utils::movable_function<void(couchbase::core::io::dns::dns_srv_response&& resp)> handler)
|
|
45
|
+
: deadline_(ctx)
|
|
46
|
+
, udp_deadline_(ctx)
|
|
47
|
+
, udp_(ctx)
|
|
48
|
+
, tcp_(ctx)
|
|
49
|
+
, address_(address)
|
|
50
|
+
, port_(port)
|
|
51
|
+
, handler_(std::move(handler))
|
|
52
|
+
{
|
|
53
|
+
static std::string protocol{ "_tcp" };
|
|
54
|
+
dns_message request{};
|
|
55
|
+
question_record qr;
|
|
56
|
+
qr.klass = resource_class::in;
|
|
57
|
+
qr.type = resource_type::srv;
|
|
58
|
+
qr.name.labels.push_back(service);
|
|
59
|
+
qr.name.labels.push_back(protocol);
|
|
60
|
+
std::string label;
|
|
61
|
+
std::istringstream name_stream(name);
|
|
62
|
+
while (std::getline(name_stream, label, '.')) {
|
|
63
|
+
qr.name.labels.push_back(label);
|
|
64
|
+
}
|
|
65
|
+
request.questions.emplace_back(qr);
|
|
66
|
+
send_buf_ = dns_codec::encode(request);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
void execute(std::chrono::milliseconds total_timeout, std::chrono::milliseconds udp_timeout)
|
|
70
|
+
{
|
|
71
|
+
asio::ip::udp::endpoint endpoint(address_, port_);
|
|
72
|
+
udp_.open(endpoint.protocol());
|
|
73
|
+
udp_.async_send_to(
|
|
74
|
+
asio::buffer(send_buf_), endpoint, [self = shared_from_this()](std::error_code ec1, std::size_t /* bytes_transferred */) mutable {
|
|
75
|
+
if (ec1) {
|
|
76
|
+
self->udp_deadline_.cancel();
|
|
77
|
+
CB_LOG_DEBUG("DNS UDP write operation has got error {}, retrying with TCP", ec1.message());
|
|
78
|
+
return self->retry_with_tcp();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
self->recv_buf_.resize(512);
|
|
82
|
+
self->udp_.async_receive_from(
|
|
83
|
+
asio::buffer(self->recv_buf_), self->udp_sender_, [self](std::error_code ec2, std::size_t bytes_transferred) mutable {
|
|
84
|
+
self->udp_deadline_.cancel();
|
|
85
|
+
if (ec2) {
|
|
86
|
+
CB_LOG_DEBUG("DNS UDP read operation has got error {}, retrying with TCP", ec2.message());
|
|
87
|
+
return self->retry_with_tcp();
|
|
88
|
+
}
|
|
89
|
+
self->recv_buf_.resize(bytes_transferred);
|
|
90
|
+
const dns_message message = dns_codec::decode(self->recv_buf_);
|
|
91
|
+
if (message.header.flags.tc == truncation::yes) {
|
|
92
|
+
self->udp_.close();
|
|
93
|
+
CB_LOG_DEBUG("DNS UDP read operation returned truncated response, retrying with TCP");
|
|
94
|
+
return self->retry_with_tcp();
|
|
95
|
+
}
|
|
96
|
+
self->deadline_.cancel();
|
|
97
|
+
dns_srv_response resp{ ec2 };
|
|
98
|
+
resp.targets.reserve(message.answers.size());
|
|
99
|
+
for (const auto& answer : message.answers) {
|
|
100
|
+
resp.targets.emplace_back(dns_srv_response::address{ utils::join_strings(answer.target.labels, "."), answer.port });
|
|
101
|
+
}
|
|
102
|
+
CB_LOG_DEBUG("DNS UDP returned {} records", resp.targets.size());
|
|
103
|
+
return self->handler_(std::move(resp));
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
udp_deadline_.expires_after(udp_timeout);
|
|
107
|
+
deadline_.async_wait([self = shared_from_this()](std::error_code ec) {
|
|
108
|
+
if (ec == asio::error::operation_aborted) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
CB_LOG_DEBUG("DNS UDP deadline has been reached, cancelling UDP operation and fall back to TCP");
|
|
112
|
+
self->udp_.cancel();
|
|
113
|
+
return self->retry_with_tcp();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
deadline_.expires_after(total_timeout);
|
|
117
|
+
deadline_.async_wait([self = shared_from_this()](std::error_code ec) {
|
|
118
|
+
if (ec == asio::error::operation_aborted) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
CB_LOG_DEBUG("DNS deadline has been reached, cancelling in-flight operations (tcp.is_open={})", self->tcp_.is_open());
|
|
122
|
+
self->udp_.cancel();
|
|
123
|
+
if (self->tcp_.is_open()) {
|
|
124
|
+
self->tcp_.cancel();
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private:
|
|
130
|
+
void retry_with_tcp()
|
|
131
|
+
{
|
|
132
|
+
if (bool expected_state{ false }; !retrying_with_tcp_.compare_exchange_strong(expected_state, true)) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const asio::ip::tcp::no_delay no_delay(true);
|
|
137
|
+
std::error_code ignore_ec;
|
|
138
|
+
tcp_.set_option(no_delay, ignore_ec);
|
|
139
|
+
const asio::ip::tcp::endpoint endpoint(address_, port_);
|
|
140
|
+
tcp_.async_connect(endpoint, [self = shared_from_this()](std::error_code ec1) mutable {
|
|
141
|
+
if (ec1) {
|
|
142
|
+
self->deadline_.cancel();
|
|
143
|
+
CB_LOG_DEBUG("DNS TCP connection has been aborted, {}", ec1.message());
|
|
144
|
+
return self->handler_({ ec1 });
|
|
145
|
+
}
|
|
146
|
+
auto send_size = static_cast<std::uint16_t>(self->send_buf_.size());
|
|
147
|
+
self->send_buf_.insert(self->send_buf_.begin(), static_cast<std::uint8_t>(send_size & 0xffU));
|
|
148
|
+
self->send_buf_.insert(self->send_buf_.begin(), static_cast<std::uint8_t>(send_size >> 8U));
|
|
149
|
+
asio::async_write(
|
|
150
|
+
self->tcp_, asio::buffer(self->send_buf_), [self](std::error_code ec2, std::size_t /* bytes_transferred */) mutable {
|
|
151
|
+
if (ec2) {
|
|
152
|
+
CB_LOG_DEBUG("DNS TCP write operation has been aborted, {}", ec2.message());
|
|
153
|
+
self->deadline_.cancel();
|
|
154
|
+
if (ec2 == asio::error::operation_aborted) {
|
|
155
|
+
ec2 = errc::common::unambiguous_timeout;
|
|
156
|
+
}
|
|
157
|
+
return self->handler_({ ec2 });
|
|
158
|
+
}
|
|
159
|
+
asio::async_read(self->tcp_,
|
|
160
|
+
asio::buffer(&self->recv_buf_size_, sizeof(std::uint16_t)),
|
|
161
|
+
[self](std::error_code ec3, std::size_t /* bytes_transferred */) mutable {
|
|
162
|
+
if (ec3) {
|
|
163
|
+
CB_LOG_DEBUG("DNS TCP buf size read operation has been aborted, {}", ec3.message());
|
|
164
|
+
self->deadline_.cancel();
|
|
165
|
+
return self->handler_({ ec3 });
|
|
166
|
+
}
|
|
167
|
+
self->recv_buf_size_ = utils::byte_swap(self->recv_buf_size_);
|
|
168
|
+
self->recv_buf_.resize(self->recv_buf_size_);
|
|
169
|
+
CB_LOG_DEBUG("DNS TCP schedule read of {} bytes", self->recv_buf_size_);
|
|
170
|
+
asio::async_read(self->tcp_,
|
|
171
|
+
asio::buffer(self->recv_buf_),
|
|
172
|
+
[self](std::error_code ec4, std::size_t bytes_transferred) mutable {
|
|
173
|
+
self->deadline_.cancel();
|
|
174
|
+
if (ec4) {
|
|
175
|
+
CB_LOG_DEBUG("DNS TCP read operation has been aborted, {}", ec4.message());
|
|
176
|
+
return self->handler_({ ec4 });
|
|
177
|
+
}
|
|
178
|
+
self->recv_buf_.resize(bytes_transferred);
|
|
179
|
+
const dns_message message = dns_codec::decode(self->recv_buf_);
|
|
180
|
+
dns_srv_response resp{ ec4 };
|
|
181
|
+
resp.targets.reserve(message.answers.size());
|
|
182
|
+
for (const auto& answer : message.answers) {
|
|
183
|
+
resp.targets.emplace_back(dns_srv_response::address{
|
|
184
|
+
utils::join_strings(answer.target.labels, "."), answer.port });
|
|
185
|
+
}
|
|
186
|
+
CB_LOG_DEBUG("DNS TCP returned {} records", resp.targets.size());
|
|
187
|
+
return self->handler_(std::move(resp));
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
asio::steady_timer deadline_;
|
|
195
|
+
asio::steady_timer udp_deadline_;
|
|
196
|
+
asio::ip::udp::socket udp_;
|
|
197
|
+
asio::ip::udp::endpoint udp_sender_{};
|
|
198
|
+
asio::ip::tcp::socket tcp_;
|
|
199
|
+
|
|
200
|
+
asio::ip::address address_;
|
|
201
|
+
std::uint16_t port_;
|
|
202
|
+
utils::movable_function<void(couchbase::core::io::dns::dns_srv_response&& resp)> handler_;
|
|
203
|
+
|
|
204
|
+
std::vector<std::uint8_t> send_buf_{};
|
|
205
|
+
std::uint16_t recv_buf_size_{ 0 };
|
|
206
|
+
std::vector<std::uint8_t> recv_buf_{};
|
|
207
|
+
|
|
208
|
+
std::atomic_bool retrying_with_tcp_{ false };
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
void
|
|
212
|
+
dns_client::query_srv(const std::string& name,
|
|
213
|
+
const std::string& service,
|
|
214
|
+
const dns_config& config,
|
|
215
|
+
utils::movable_function<void(dns_srv_response&&)>&& handler)
|
|
216
|
+
{
|
|
217
|
+
std::error_code ec;
|
|
218
|
+
auto address = asio::ip::address::from_string(config.nameserver(), ec);
|
|
219
|
+
if (ec) {
|
|
220
|
+
return handler({ ec });
|
|
221
|
+
}
|
|
222
|
+
auto cmd = std::make_shared<dns_srv_command>(ctx_, name, service, address, config.port(), std::move(handler));
|
|
223
|
+
return cmd->execute(config.timeout(), config.timeout() / 2);
|
|
224
|
+
}
|
|
225
|
+
} // namespace couchbase::core::io::dns
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
2
|
/*
|
|
3
|
-
* Copyright 2020-
|
|
3
|
+
* Copyright 2020-Present Couchbase, Inc.
|
|
4
4
|
*
|
|
5
5
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
6
|
* you may not use this file except in compliance with the License.
|
|
@@ -17,207 +17,38 @@
|
|
|
17
17
|
|
|
18
18
|
#pragma once
|
|
19
19
|
|
|
20
|
-
#include "core/utils/
|
|
21
|
-
#include "dns_codec.hxx"
|
|
20
|
+
#include "core/utils/movable_function.hxx"
|
|
22
21
|
#include "dns_config.hxx"
|
|
23
22
|
|
|
24
|
-
#include <
|
|
23
|
+
#include <asio/io_context.hpp>
|
|
25
24
|
|
|
26
|
-
#include <
|
|
27
|
-
#include <
|
|
28
|
-
#include <
|
|
29
|
-
|
|
30
|
-
#include <memory>
|
|
31
|
-
#include <sstream>
|
|
25
|
+
#include <cinttypes>
|
|
26
|
+
#include <string>
|
|
27
|
+
#include <vector>
|
|
32
28
|
|
|
33
29
|
namespace couchbase::core::io::dns
|
|
34
30
|
{
|
|
31
|
+
struct dns_srv_response {
|
|
32
|
+
struct address {
|
|
33
|
+
std::string hostname;
|
|
34
|
+
std::uint16_t port;
|
|
35
|
+
};
|
|
36
|
+
std::error_code ec;
|
|
37
|
+
std::vector<address> targets{};
|
|
38
|
+
};
|
|
39
|
+
|
|
35
40
|
class dns_client
|
|
36
41
|
{
|
|
37
42
|
public:
|
|
38
|
-
struct dns_srv_response {
|
|
39
|
-
struct address {
|
|
40
|
-
std::string hostname;
|
|
41
|
-
std::uint16_t port;
|
|
42
|
-
};
|
|
43
|
-
std::error_code ec;
|
|
44
|
-
std::vector<address> targets{};
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
|
|
48
|
-
{
|
|
49
|
-
public:
|
|
50
|
-
dns_srv_command(asio::io_context& ctx,
|
|
51
|
-
const std::string& name,
|
|
52
|
-
const std::string& service,
|
|
53
|
-
const asio::ip::address& address,
|
|
54
|
-
std::uint16_t port)
|
|
55
|
-
: deadline_(ctx)
|
|
56
|
-
, udp_(ctx)
|
|
57
|
-
, tcp_(ctx)
|
|
58
|
-
, address_(address)
|
|
59
|
-
, port_(port)
|
|
60
|
-
{
|
|
61
|
-
static std::string protocol{ "_tcp" };
|
|
62
|
-
dns_message request{};
|
|
63
|
-
question_record qr;
|
|
64
|
-
qr.klass = resource_class::in;
|
|
65
|
-
qr.type = resource_type::srv;
|
|
66
|
-
qr.name.labels.push_back(service);
|
|
67
|
-
qr.name.labels.push_back(protocol);
|
|
68
|
-
std::string label;
|
|
69
|
-
std::istringstream name_stream(name);
|
|
70
|
-
while (std::getline(name_stream, label, '.')) {
|
|
71
|
-
qr.name.labels.push_back(label);
|
|
72
|
-
}
|
|
73
|
-
request.questions.emplace_back(qr);
|
|
74
|
-
send_buf_ = dns_codec::encode(request);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
template<class Handler>
|
|
78
|
-
void execute(std::chrono::milliseconds timeout, Handler&& handler)
|
|
79
|
-
{
|
|
80
|
-
asio::ip::udp::endpoint endpoint(address_, port_);
|
|
81
|
-
udp_.open(endpoint.protocol());
|
|
82
|
-
udp_.async_send_to(asio::buffer(send_buf_),
|
|
83
|
-
endpoint,
|
|
84
|
-
[self = shared_from_this(), handler = std::forward<Handler>(handler)](
|
|
85
|
-
std::error_code ec1, std::size_t /* bytes_transferred */) mutable {
|
|
86
|
-
if (ec1 == asio::error::operation_aborted) {
|
|
87
|
-
self->deadline_.cancel();
|
|
88
|
-
return handler({ errc::common::unambiguous_timeout });
|
|
89
|
-
}
|
|
90
|
-
if (ec1) {
|
|
91
|
-
self->deadline_.cancel();
|
|
92
|
-
return handler({ ec1 });
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
self->recv_buf_.resize(512);
|
|
96
|
-
self->udp_.async_receive_from(asio::buffer(self->recv_buf_),
|
|
97
|
-
self->udp_sender_,
|
|
98
|
-
[self, handler = std::forward<Handler>(handler)](
|
|
99
|
-
std::error_code ec2, std::size_t bytes_transferred) mutable {
|
|
100
|
-
self->deadline_.cancel();
|
|
101
|
-
if (ec2) {
|
|
102
|
-
return handler({ ec2 });
|
|
103
|
-
}
|
|
104
|
-
self->recv_buf_.resize(bytes_transferred);
|
|
105
|
-
dns_message message = dns_codec::decode(self->recv_buf_);
|
|
106
|
-
if (message.header.flags.tc == truncation::yes) {
|
|
107
|
-
self->udp_.close();
|
|
108
|
-
return self->retry_with_tcp(std::forward<Handler>(handler));
|
|
109
|
-
}
|
|
110
|
-
dns_srv_response resp{ ec2 };
|
|
111
|
-
resp.targets.reserve(message.answers.size());
|
|
112
|
-
for (const auto& answer : message.answers) {
|
|
113
|
-
resp.targets.emplace_back(dns_srv_response::address{
|
|
114
|
-
utils::join_strings(answer.target.labels, "."), answer.port });
|
|
115
|
-
}
|
|
116
|
-
return handler(std::move(resp));
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
deadline_.expires_after(timeout);
|
|
120
|
-
deadline_.async_wait([self = shared_from_this()](std::error_code ec) {
|
|
121
|
-
if (ec == asio::error::operation_aborted) {
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
self->udp_.cancel();
|
|
125
|
-
if (self->tcp_.is_open()) {
|
|
126
|
-
self->tcp_.cancel();
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
private:
|
|
132
|
-
template<class Handler>
|
|
133
|
-
void retry_with_tcp(Handler&& handler)
|
|
134
|
-
{
|
|
135
|
-
asio::ip::tcp::no_delay no_delay(true);
|
|
136
|
-
std::error_code ignore_ec;
|
|
137
|
-
tcp_.set_option(no_delay, ignore_ec);
|
|
138
|
-
asio::ip::tcp::endpoint endpoint(address_, port_);
|
|
139
|
-
tcp_.async_connect(
|
|
140
|
-
endpoint, [self = shared_from_this(), handler = std::forward<Handler>(handler)](std::error_code ec1) mutable {
|
|
141
|
-
if (ec1) {
|
|
142
|
-
self->deadline_.cancel();
|
|
143
|
-
return handler({ ec1 });
|
|
144
|
-
}
|
|
145
|
-
auto send_size = static_cast<std::uint16_t>(self->send_buf_.size());
|
|
146
|
-
self->send_buf_.insert(self->send_buf_.begin(), std::uint8_t(send_size & 0xffU));
|
|
147
|
-
self->send_buf_.insert(self->send_buf_.begin(), std::uint8_t(send_size >> 8U));
|
|
148
|
-
asio::async_write(
|
|
149
|
-
self->tcp_,
|
|
150
|
-
asio::buffer(self->send_buf_),
|
|
151
|
-
[self, handler = std::forward<Handler>(handler)](std::error_code ec2, std::size_t /* bytes_transferred */) mutable {
|
|
152
|
-
if (ec2) {
|
|
153
|
-
self->deadline_.cancel();
|
|
154
|
-
if (ec2 == asio::error::operation_aborted) {
|
|
155
|
-
ec2 = errc::common::unambiguous_timeout;
|
|
156
|
-
}
|
|
157
|
-
return handler({ ec2 });
|
|
158
|
-
}
|
|
159
|
-
asio::async_read(self->tcp_,
|
|
160
|
-
asio::buffer(&self->recv_buf_size_, sizeof(std::uint16_t)),
|
|
161
|
-
[self, handler = std::forward<Handler>(handler)](std::error_code ec3,
|
|
162
|
-
std::size_t /* bytes_transferred */) mutable {
|
|
163
|
-
if (ec3) {
|
|
164
|
-
self->deadline_.cancel();
|
|
165
|
-
return handler({ ec3 });
|
|
166
|
-
}
|
|
167
|
-
self->recv_buf_size_ = utils::byte_swap(self->recv_buf_size_);
|
|
168
|
-
self->recv_buf_.resize(self->recv_buf_size_);
|
|
169
|
-
asio::async_read(self->tcp_,
|
|
170
|
-
asio::buffer(self->recv_buf_),
|
|
171
|
-
[self, handler = std::forward<Handler>(handler)](
|
|
172
|
-
std::error_code ec4, std::size_t bytes_transferred) mutable {
|
|
173
|
-
self->deadline_.cancel();
|
|
174
|
-
if (ec4) {
|
|
175
|
-
return handler({ ec4 });
|
|
176
|
-
}
|
|
177
|
-
self->recv_buf_.resize(bytes_transferred);
|
|
178
|
-
dns_message message = dns_codec::decode(self->recv_buf_);
|
|
179
|
-
dns_srv_response resp{ ec4 };
|
|
180
|
-
resp.targets.reserve(message.answers.size());
|
|
181
|
-
for (const auto& answer : message.answers) {
|
|
182
|
-
resp.targets.emplace_back(dns_srv_response::address{
|
|
183
|
-
utils::join_strings(answer.target.labels, "."), answer.port });
|
|
184
|
-
}
|
|
185
|
-
return handler(std::move(resp));
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
asio::steady_timer deadline_;
|
|
193
|
-
asio::ip::udp::socket udp_;
|
|
194
|
-
asio::ip::udp::endpoint udp_sender_{};
|
|
195
|
-
asio::ip::tcp::socket tcp_;
|
|
196
|
-
|
|
197
|
-
asio::ip::address address_;
|
|
198
|
-
std::uint16_t port_;
|
|
199
|
-
|
|
200
|
-
std::vector<std::uint8_t> send_buf_{};
|
|
201
|
-
std::uint16_t recv_buf_size_{ 0 };
|
|
202
|
-
std::vector<std::uint8_t> recv_buf_{};
|
|
203
|
-
};
|
|
204
|
-
|
|
205
43
|
explicit dns_client(asio::io_context& ctx)
|
|
206
44
|
: ctx_(ctx)
|
|
207
45
|
{
|
|
208
46
|
}
|
|
209
47
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
auto address = asio::ip::address::from_string(config.nameserver(), ec);
|
|
215
|
-
if (ec) {
|
|
216
|
-
return handler({ ec });
|
|
217
|
-
}
|
|
218
|
-
auto cmd = std::make_shared<dns_srv_command>(ctx_, name, service, address, config.port());
|
|
219
|
-
cmd->execute(config.timeout(), std::forward<Handler>(handler));
|
|
220
|
-
}
|
|
48
|
+
void query_srv(const std::string& name,
|
|
49
|
+
const std::string& service,
|
|
50
|
+
const dns_config& config,
|
|
51
|
+
utils::movable_function<void(couchbase::core::io::dns::dns_srv_response&& resp)>&& handler);
|
|
221
52
|
|
|
222
53
|
asio::io_context& ctx_;
|
|
223
54
|
};
|
|
@@ -7,11 +7,13 @@ target_link_libraries(
|
|
|
7
7
|
snappy
|
|
8
8
|
fmt::fmt
|
|
9
9
|
spdlog::spdlog)
|
|
10
|
-
target_include_directories(couchbase_meta PRIVATE
|
|
11
|
-
|
|
12
|
-
${PROJECT_SOURCE_DIR}
|
|
13
|
-
${PROJECT_SOURCE_DIR}/third_party/http_parser)
|
|
10
|
+
target_include_directories(couchbase_meta PRIVATE ${PROJECT_BINARY_DIR}/generated ${PROJECT_SOURCE_DIR}
|
|
11
|
+
${PROJECT_SOURCE_DIR}/third_party/http_parser)
|
|
14
12
|
|
|
15
13
|
if(NOT COUCHBASE_CXX_CLIENT_POST_LINKED_OPENSSL)
|
|
16
|
-
|
|
14
|
+
if (TARGET PkgConfig::PKG_CONFIG_OPENSSL)
|
|
15
|
+
target_link_libraries(couchbase_meta PUBLIC PkgConfig::PKG_CONFIG_OPENSSL)
|
|
16
|
+
else()
|
|
17
|
+
target_link_libraries(couchbase_meta PUBLIC OpenSSL::SSL OpenSSL::Crypto)
|
|
18
|
+
endif()
|
|
17
19
|
endif()
|
|
@@ -100,9 +100,28 @@ sdk_build_info()
|
|
|
100
100
|
info["openssl_runtime"] = OpenSSL_version(OPENSSL_VERSION);
|
|
101
101
|
#elif defined(SSLEAY_VERSION)
|
|
102
102
|
info["openssl_runtime"] = SSLeay_version(SSLEAY_VERSION);
|
|
103
|
+
#endif
|
|
104
|
+
#if defined(OPENSSL_INFO_CONFIG_DIR)
|
|
105
|
+
info["openssl_config_dir"] = OPENSSL_info(OPENSSL_INFO_CONFIG_DIR);
|
|
106
|
+
#elif defined(OPENSSL_DIR)
|
|
107
|
+
if (std::string config_dir(OpenSSL_version(OPENSSL_DIR)); !config_dir.empty()) {
|
|
108
|
+
if (auto quote = config_dir.find('"'); quote != std::string::npos && quote + 2 < config_dir.size()) {
|
|
109
|
+
info["openssl_config_dir"] = config_dir.substr(quote + 1, config_dir.size() - quote - 2);
|
|
110
|
+
} else {
|
|
111
|
+
info["openssl_config_dir"] = config_dir;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
103
114
|
#endif
|
|
104
115
|
info["openssl_default_cert_dir"] = X509_get_default_cert_dir();
|
|
105
116
|
info["openssl_default_cert_file"] = X509_get_default_cert_file();
|
|
117
|
+
info["openssl_ssl_interface_include_directories"] = OPENSSL_SSL_INTERFACE_INCLUDE_DIRECTORIES;
|
|
118
|
+
info["openssl_ssl_interface_link_libraries"] = OPENSSL_SSL_INTERFACE_LINK_LIBRARIES;
|
|
119
|
+
info["openssl_ssl_imported_location"] = OPENSSL_SSL_IMPORTED_LOCATION;
|
|
120
|
+
info["openssl_crypto_interface_imported_location"] = OPENSSL_CRYPTO_IMPORTED_LOCATION;
|
|
121
|
+
info["openssl_crypto_interface_include_directories"] = OPENSSL_CRYPTO_INTERFACE_INCLUDE_DIRECTORIES;
|
|
122
|
+
info["openssl_crypto_interface_link_libraries"] = OPENSSL_CRYPTO_INTERFACE_LINK_LIBRARIES;
|
|
123
|
+
info["openssl_pkg_config_interface_include_directories"] = OPENSSL_PKG_CONFIG_INTERFACE_INCLUDE_DIRECTORIES;
|
|
124
|
+
info["openssl_pkg_config_interface_link_libraries"] = OPENSSL_PKG_CONFIG_INTERFACE_LINK_LIBRARIES;
|
|
106
125
|
info["__cplusplus"] = fmt::format("{}", __cplusplus);
|
|
107
126
|
#if defined(_MSC_VER)
|
|
108
127
|
info["_MSC_VER"] = fmt::format("{}", _MSC_VER);
|
|
@@ -92,11 +92,14 @@ search_request::encode_to(search_request::encoded_request_type& encoded, http_co
|
|
|
92
92
|
{ "vectors", { { index_name, scan_vectors } } },
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
|
-
if (
|
|
96
|
-
body["scope"] = scope_name.value();
|
|
95
|
+
if (!collections.empty()) {
|
|
97
96
|
body["collections"] = collections;
|
|
98
97
|
}
|
|
99
98
|
|
|
99
|
+
for (const auto& [key, value] : raw) {
|
|
100
|
+
body[key] = utils::json::parse(value);
|
|
101
|
+
}
|
|
102
|
+
|
|
100
103
|
encoded.type = type;
|
|
101
104
|
encoded.headers["content-type"] = "application/json";
|
|
102
105
|
encoded.method = "POST";
|
|
@@ -130,7 +130,6 @@ struct search_request {
|
|
|
130
130
|
std::optional<couchbase::core::search_highlight_style> highlight_style{};
|
|
131
131
|
std::vector<std::string> highlight_fields{};
|
|
132
132
|
std::vector<std::string> fields{};
|
|
133
|
-
std::optional<std::string> scope_name{};
|
|
134
133
|
std::vector<std::string> collections{};
|
|
135
134
|
|
|
136
135
|
std::optional<couchbase::core::search_scan_consistency> scan_consistency{};
|
|
@@ -153,7 +153,7 @@ class active_transaction_record
|
|
|
153
153
|
if (const auto* compat = val.find(ATR_FIELD_FORWARD_COMPAT); compat != nullptr) {
|
|
154
154
|
forward_compat = *compat;
|
|
155
155
|
}
|
|
156
|
-
|
|
156
|
+
std::optional<uint32_t> expires_after_msec = std::max(val.optional<int32_t>(ATR_FIELD_EXPIRES_AFTER_MSECS).value_or(0), 0);
|
|
157
157
|
entries.emplace_back(resp.ctx.bucket(),
|
|
158
158
|
resp.ctx.id(),
|
|
159
159
|
key,
|
|
@@ -163,7 +163,7 @@ class active_transaction_record
|
|
|
163
163
|
parse_mutation_cas(val.optional<std::string>(ATR_FIELD_TIMESTAMP_COMPLETE).value_or("")),
|
|
164
164
|
parse_mutation_cas(val.optional<std::string>(ATR_FIELD_TIMESTAMP_ROLLBACK_START).value_or("")),
|
|
165
165
|
parse_mutation_cas(val.optional<std::string>(ATR_FIELD_TIMESTAMP_ROLLBACK_COMPLETE).value_or("")),
|
|
166
|
-
|
|
166
|
+
expires_after_msec,
|
|
167
167
|
process_document_ids(val, ATR_FIELD_DOCS_INSERTED),
|
|
168
168
|
process_document_ids(val, ATR_FIELD_DOCS_REPLACED),
|
|
169
169
|
process_document_ids(val, ATR_FIELD_DOCS_REMOVED),
|