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
@@ -0,0 +1,91 @@
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* Copyright 2020 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
|
+
#pragma once
|
19
|
+
|
20
|
+
#include <io/http_session.hxx>
|
21
|
+
|
22
|
+
namespace couchbase::operations
|
23
|
+
{
|
24
|
+
|
25
|
+
template<typename Request>
|
26
|
+
struct http_command : public std::enable_shared_from_this<http_command<Request>> {
|
27
|
+
using encoded_request_type = typename Request::encoded_request_type;
|
28
|
+
using encoded_response_type = typename Request::encoded_response_type;
|
29
|
+
asio::steady_timer deadline;
|
30
|
+
asio::steady_timer retry_backoff;
|
31
|
+
Request request;
|
32
|
+
encoded_request_type encoded;
|
33
|
+
|
34
|
+
http_command(asio::io_context& ctx, Request req)
|
35
|
+
: deadline(ctx)
|
36
|
+
, retry_backoff(ctx)
|
37
|
+
, request(req)
|
38
|
+
{
|
39
|
+
}
|
40
|
+
|
41
|
+
template<typename Handler>
|
42
|
+
void send_to(std::shared_ptr<io::http_session> session, Handler&& handler)
|
43
|
+
{
|
44
|
+
encoded.type = Request::type;
|
45
|
+
request.encode_to(encoded);
|
46
|
+
encoded.headers["client-context-id"] = request.client_context_id;
|
47
|
+
auto log_prefix = session->log_prefix();
|
48
|
+
spdlog::debug("{} HTTP request: {}, method={}, path={}, client_context_id={}, timeout={}ms",
|
49
|
+
log_prefix,
|
50
|
+
encoded.type,
|
51
|
+
encoded.method,
|
52
|
+
encoded.path,
|
53
|
+
request.client_context_id,
|
54
|
+
request.timeout.count());
|
55
|
+
SPDLOG_TRACE("{} HTTP request: {}, method={}, path={}, client_context_id={}, timeout={}ms{:a}",
|
56
|
+
log_prefix,
|
57
|
+
encoded.type,
|
58
|
+
encoded.method,
|
59
|
+
encoded.path,
|
60
|
+
request.client_context_id,
|
61
|
+
request.timeout.count(),
|
62
|
+
spdlog::to_hex(encoded.body));
|
63
|
+
session->write_and_subscribe(encoded,
|
64
|
+
[self = this->shared_from_this(), log_prefix, handler = std::forward<Handler>(handler)](
|
65
|
+
std::error_code ec, io::http_response&& msg) mutable {
|
66
|
+
self->deadline.cancel();
|
67
|
+
encoded_response_type resp(msg);
|
68
|
+
spdlog::debug("{} HTTP response: {}, client_context_id={}, status={}",
|
69
|
+
log_prefix,
|
70
|
+
self->request.type,
|
71
|
+
self->request.client_context_id,
|
72
|
+
resp.status_code);
|
73
|
+
SPDLOG_TRACE("{} HTTP response: {}, client_context_id={}, status={}{:a}",
|
74
|
+
log_prefix,
|
75
|
+
self->request.type,
|
76
|
+
self->request.client_context_id,
|
77
|
+
resp.status_code,
|
78
|
+
spdlog::to_hex(resp.body));
|
79
|
+
handler(make_response(ec, self->request, resp));
|
80
|
+
});
|
81
|
+
deadline.expires_after(request.timeout);
|
82
|
+
deadline.async_wait([session](std::error_code ec) {
|
83
|
+
if (ec == asio::error::operation_aborted) {
|
84
|
+
return;
|
85
|
+
}
|
86
|
+
session->stop();
|
87
|
+
});
|
88
|
+
}
|
89
|
+
};
|
90
|
+
|
91
|
+
} // namespace couchbase::operations
|
@@ -51,8 +51,7 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
51
51
|
, id_(uuid::to_string(uuid::random()))
|
52
52
|
, ctx_(ctx)
|
53
53
|
, resolver_(ctx_)
|
54
|
-
,
|
55
|
-
, socket_(strand_)
|
54
|
+
, stream_(std::make_unique<plain_stream_impl>(ctx_))
|
56
55
|
, deadline_timer_(ctx_)
|
57
56
|
, username_(username)
|
58
57
|
, password_(password)
|
@@ -66,10 +65,37 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
66
65
|
client_id_,
|
67
66
|
id_,
|
68
67
|
BACKEND_SYSTEM))
|
68
|
+
, log_prefix_(fmt::format("[{}/{}]", client_id_, id_))
|
69
|
+
{
|
70
|
+
}
|
71
|
+
|
72
|
+
http_session(const std::string& client_id,
|
73
|
+
asio::io_context& ctx,
|
74
|
+
asio::ssl::context& tls,
|
75
|
+
const std::string& username,
|
76
|
+
const std::string& password,
|
77
|
+
const std::string& hostname,
|
78
|
+
const std::string& service)
|
79
|
+
: client_id_(client_id)
|
80
|
+
, id_(uuid::to_string(uuid::random()))
|
81
|
+
, ctx_(ctx)
|
82
|
+
, resolver_(ctx_)
|
83
|
+
, stream_(std::make_unique<tls_stream_impl>(ctx_, tls))
|
84
|
+
, deadline_timer_(ctx_)
|
85
|
+
, username_(username)
|
86
|
+
, password_(password)
|
87
|
+
, hostname_(hostname)
|
88
|
+
, service_(service)
|
89
|
+
, user_agent_(fmt::format("ruby/{}.{}.{}/{}; client/{}; session/{}; {}",
|
90
|
+
BACKEND_VERSION_MAJOR,
|
91
|
+
BACKEND_VERSION_MINOR,
|
92
|
+
BACKEND_VERSION_PATCH,
|
93
|
+
BACKEND_GIT_REVISION,
|
94
|
+
client_id_,
|
95
|
+
id_,
|
96
|
+
BACKEND_SYSTEM))
|
97
|
+
, log_prefix_(fmt::format("[{}/{}]", client_id_, id_))
|
69
98
|
{
|
70
|
-
log_prefix_ = fmt::format("[{}/{}]", client_id_, id_);
|
71
|
-
resolver_.async_resolve(
|
72
|
-
hostname, service, std::bind(&http_session::on_resolve, this, std::placeholders::_1, std::placeholders::_2));
|
73
99
|
}
|
74
100
|
|
75
101
|
~http_session()
|
@@ -77,6 +103,12 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
77
103
|
stop();
|
78
104
|
}
|
79
105
|
|
106
|
+
void start()
|
107
|
+
{
|
108
|
+
resolver_.async_resolve(
|
109
|
+
hostname_, service_, std::bind(&http_session::on_resolve, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
|
110
|
+
}
|
111
|
+
|
80
112
|
[[nodiscard]] const std::string& log_prefix() const
|
81
113
|
{
|
82
114
|
return log_prefix_;
|
@@ -100,8 +132,8 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
100
132
|
void stop()
|
101
133
|
{
|
102
134
|
stopped_ = true;
|
103
|
-
if (
|
104
|
-
|
135
|
+
if (stream_->is_open()) {
|
136
|
+
stream_->close();
|
105
137
|
}
|
106
138
|
deadline_timer_.cancel();
|
107
139
|
|
@@ -116,6 +148,11 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
116
148
|
}
|
117
149
|
}
|
118
150
|
|
151
|
+
bool keep_alive()
|
152
|
+
{
|
153
|
+
return keep_alive_;
|
154
|
+
}
|
155
|
+
|
119
156
|
bool is_stopped()
|
120
157
|
{
|
121
158
|
return stopped_;
|
@@ -177,7 +214,7 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
177
214
|
}
|
178
215
|
endpoints_ = endpoints;
|
179
216
|
do_connect(endpoints_.begin());
|
180
|
-
deadline_timer_.async_wait(std::bind(&http_session::check_deadline,
|
217
|
+
deadline_timer_.async_wait(std::bind(&http_session::check_deadline, shared_from_this(), std::placeholders::_1));
|
181
218
|
}
|
182
219
|
|
183
220
|
void do_connect(asio::ip::tcp::resolver::results_type::iterator it)
|
@@ -185,7 +222,7 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
185
222
|
if (it != endpoints_.end()) {
|
186
223
|
spdlog::debug("{} connecting to {}:{}", log_prefix_, it->endpoint().address().to_string(), it->endpoint().port());
|
187
224
|
deadline_timer_.expires_after(timeout_defaults::connect_timeout);
|
188
|
-
|
225
|
+
stream_->async_connect(it->endpoint(), std::bind(&http_session::on_connect, shared_from_this(), std::placeholders::_1, it));
|
189
226
|
} else {
|
190
227
|
spdlog::error("{} no more endpoints left to connect", log_prefix_);
|
191
228
|
stop();
|
@@ -197,7 +234,9 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
197
234
|
if (stopped_) {
|
198
235
|
return;
|
199
236
|
}
|
200
|
-
if (!
|
237
|
+
if (!stream_->is_open() || ec) {
|
238
|
+
spdlog::warn(
|
239
|
+
"{} unable to connect to {}:{}: {}", log_prefix_, it->endpoint().address().to_string(), it->endpoint().port(), ec.message());
|
201
240
|
do_connect(++it);
|
202
241
|
} else {
|
203
242
|
connected_ = true;
|
@@ -219,10 +258,10 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
219
258
|
return;
|
220
259
|
}
|
221
260
|
if (deadline_timer_.expiry() <= asio::steady_timer::clock_type::now()) {
|
222
|
-
|
261
|
+
stream_->close();
|
223
262
|
deadline_timer_.expires_at(asio::steady_timer::time_point::max());
|
224
263
|
}
|
225
|
-
deadline_timer_.async_wait(std::bind(&http_session::check_deadline,
|
264
|
+
deadline_timer_.async_wait(std::bind(&http_session::check_deadline, shared_from_this(), std::placeholders::_1));
|
226
265
|
}
|
227
266
|
|
228
267
|
void do_read()
|
@@ -230,12 +269,12 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
230
269
|
if (stopped_) {
|
231
270
|
return;
|
232
271
|
}
|
233
|
-
|
272
|
+
stream_->async_read_some(
|
234
273
|
asio::buffer(input_buffer_), [self = shared_from_this()](std::error_code ec, std::size_t bytes_transferred) {
|
235
|
-
if (self->stopped_) {
|
274
|
+
if (ec == asio::error::operation_aborted || self->stopped_) {
|
236
275
|
return;
|
237
276
|
}
|
238
|
-
if (ec
|
277
|
+
if (ec) {
|
239
278
|
spdlog::error("{} IO error while reading from the socket: {}", self->log_prefix_, ec.message());
|
240
279
|
return self->stop();
|
241
280
|
}
|
@@ -273,8 +312,8 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
273
312
|
for (auto& buf : writing_buffer_) {
|
274
313
|
buffers.emplace_back(asio::buffer(buf));
|
275
314
|
}
|
276
|
-
|
277
|
-
if (self->stopped_) {
|
315
|
+
stream_->async_write(buffers, [self = shared_from_this()](std::error_code ec, std::size_t /* bytes_transferred */) {
|
316
|
+
if (ec == asio::error::operation_aborted || self->stopped_) {
|
278
317
|
return;
|
279
318
|
}
|
280
319
|
if (ec) {
|
@@ -293,8 +332,7 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
293
332
|
std::string id_;
|
294
333
|
asio::io_context& ctx_;
|
295
334
|
asio::ip::tcp::resolver resolver_;
|
296
|
-
|
297
|
-
asio::ip::tcp::socket socket_;
|
335
|
+
std::unique_ptr<stream_impl> stream_;
|
298
336
|
asio::steady_timer deadline_timer_;
|
299
337
|
|
300
338
|
std::string username_;
|
@@ -305,6 +343,7 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
305
343
|
|
306
344
|
bool stopped_{ false };
|
307
345
|
bool connected_{ false };
|
346
|
+
bool keep_alive_{ false };
|
308
347
|
|
309
348
|
std::function<void()> on_stop_handler_{ nullptr };
|
310
349
|
|
@@ -28,14 +28,16 @@ namespace couchbase::io
|
|
28
28
|
class http_session_manager : public std::enable_shared_from_this<http_session_manager>
|
29
29
|
{
|
30
30
|
public:
|
31
|
-
http_session_manager(const std::string& client_id, asio::io_context& ctx)
|
31
|
+
http_session_manager(const std::string& client_id, asio::io_context& ctx, asio::ssl::context& tls)
|
32
32
|
: client_id_(client_id)
|
33
33
|
, ctx_(ctx)
|
34
|
+
, tls_(tls)
|
34
35
|
{
|
35
36
|
}
|
36
37
|
|
37
|
-
void set_configuration(const configuration& config)
|
38
|
+
void set_configuration(const configuration& config, const cluster_options& options)
|
38
39
|
{
|
40
|
+
options_ = options;
|
39
41
|
config_ = config;
|
40
42
|
next_index_ = 0;
|
41
43
|
if (config_.nodes.size() > 1) {
|
@@ -48,6 +50,7 @@ class http_session_manager : public std::enable_shared_from_this<http_session_ma
|
|
48
50
|
|
49
51
|
std::shared_ptr<http_session> check_out(service_type type, const std::string& username, const std::string& password)
|
50
52
|
{
|
53
|
+
std::scoped_lock lock(sessions_mutex_);
|
51
54
|
if (idle_sessions_[type].empty()) {
|
52
55
|
std::string hostname;
|
53
56
|
std::uint16_t port = 0;
|
@@ -56,8 +59,15 @@ class http_session_manager : public std::enable_shared_from_this<http_session_ma
|
|
56
59
|
return nullptr;
|
57
60
|
}
|
58
61
|
config_.nodes.size();
|
59
|
-
|
62
|
+
std::shared_ptr<http_session> session;
|
63
|
+
if (options_.enable_tls) {
|
64
|
+
session = std::make_shared<http_session>(client_id_, ctx_, tls_, username, password, hostname, std::to_string(port));
|
65
|
+
} else {
|
66
|
+
session = std::make_shared<http_session>(client_id_, ctx_, username, password, hostname, std::to_string(port));
|
67
|
+
}
|
68
|
+
session->start();
|
60
69
|
session->on_stop([type, id = session->id(), self = this->shared_from_this()]() {
|
70
|
+
std::scoped_lock inner_lock(self->sessions_mutex_);
|
61
71
|
self->busy_sessions_[type].remove_if([id](const auto& s) -> bool { return s->id() == id; });
|
62
72
|
self->idle_sessions_[type].remove_if([id](const auto& s) -> bool { return s->id() == id; });
|
63
73
|
});
|
@@ -72,7 +82,14 @@ class http_session_manager : public std::enable_shared_from_this<http_session_ma
|
|
72
82
|
|
73
83
|
void check_in(service_type type, std::shared_ptr<http_session> session)
|
74
84
|
{
|
75
|
-
|
85
|
+
if (!session->keep_alive()) {
|
86
|
+
return session->stop();
|
87
|
+
}
|
88
|
+
if (!session->is_stopped()) {
|
89
|
+
std::scoped_lock lock(sessions_mutex_);
|
90
|
+
spdlog::debug("{} put HTTP session back to idle connections", session->log_prefix());
|
91
|
+
idle_sessions_[type].push_back(session);
|
92
|
+
}
|
76
93
|
}
|
77
94
|
|
78
95
|
private:
|
@@ -83,34 +100,9 @@ class http_session_manager : public std::enable_shared_from_this<http_session_ma
|
|
83
100
|
--candidates;
|
84
101
|
auto& node = config_.nodes[next_index_];
|
85
102
|
next_index_ = (next_index_ + 1) % config_.nodes.size();
|
86
|
-
std::uint16_t port = 0;
|
87
|
-
switch (type) {
|
88
|
-
case service_type::query:
|
89
|
-
port = node.services_plain.query.value_or(0);
|
90
|
-
break;
|
91
|
-
|
92
|
-
case service_type::analytics:
|
93
|
-
port = node.services_plain.analytics.value_or(0);
|
94
|
-
break;
|
95
|
-
|
96
|
-
case service_type::search:
|
97
|
-
port = node.services_plain.search.value_or(0);
|
98
|
-
break;
|
99
|
-
|
100
|
-
case service_type::views:
|
101
|
-
port = node.services_plain.views.value_or(0);
|
102
|
-
break;
|
103
|
-
|
104
|
-
case service_type::management:
|
105
|
-
port = node.services_plain.management.value_or(0);
|
106
|
-
break;
|
107
|
-
|
108
|
-
case service_type::kv:
|
109
|
-
port = node.services_plain.key_value.value_or(0);
|
110
|
-
break;
|
111
|
-
}
|
103
|
+
std::uint16_t port = node.port_or(options_.network, type, options_.enable_tls, 0);
|
112
104
|
if (port != 0) {
|
113
|
-
return { node.
|
105
|
+
return { node.hostname_for(options_.network), port };
|
114
106
|
}
|
115
107
|
}
|
116
108
|
return { "", 0 };
|
@@ -118,10 +110,13 @@ class http_session_manager : public std::enable_shared_from_this<http_session_ma
|
|
118
110
|
|
119
111
|
std::string client_id_;
|
120
112
|
asio::io_context& ctx_;
|
113
|
+
asio::ssl::context& tls_;
|
114
|
+
cluster_options options_;
|
121
115
|
|
122
116
|
configuration config_{};
|
123
117
|
std::map<service_type, std::list<std::shared_ptr<http_session>>> busy_sessions_{};
|
124
118
|
std::map<service_type, std::list<std::shared_ptr<http_session>>> idle_sessions_{};
|
125
119
|
std::size_t next_index_{ 0 };
|
120
|
+
std::mutex sessions_mutex_{};
|
126
121
|
};
|
127
122
|
} // namespace couchbase::io
|
@@ -0,0 +1,180 @@
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* Copyright 2020 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
|
+
#pragma once
|
19
|
+
|
20
|
+
#include <io/mcbp_session.hxx>
|
21
|
+
#include <protocol/cmd_get_collection_id.hxx>
|
22
|
+
#include <functional>
|
23
|
+
#include <utility>
|
24
|
+
|
25
|
+
namespace couchbase::operations
|
26
|
+
{
|
27
|
+
|
28
|
+
using mcbp_command_handler = std::function<void(std::error_code, std::optional<io::mcbp_message>)>;
|
29
|
+
|
30
|
+
template<typename Request>
|
31
|
+
struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Request>> {
|
32
|
+
using encoded_request_type = typename Request::encoded_request_type;
|
33
|
+
using encoded_response_type = typename Request::encoded_response_type;
|
34
|
+
asio::steady_timer deadline;
|
35
|
+
asio::steady_timer retry_backoff;
|
36
|
+
Request request;
|
37
|
+
encoded_request_type encoded;
|
38
|
+
std::optional<std::uint32_t> opaque_{};
|
39
|
+
std::shared_ptr<io::mcbp_session> session_{};
|
40
|
+
mcbp_command_handler handler_{};
|
41
|
+
|
42
|
+
mcbp_command(asio::io_context& ctx, Request req)
|
43
|
+
: deadline(ctx)
|
44
|
+
, retry_backoff(ctx)
|
45
|
+
, request(req)
|
46
|
+
{
|
47
|
+
}
|
48
|
+
|
49
|
+
void start(mcbp_command_handler&& handler)
|
50
|
+
{
|
51
|
+
handler_ = handler;
|
52
|
+
deadline.expires_after(request.timeout);
|
53
|
+
deadline.async_wait([self = this->shared_from_this()](std::error_code ec) {
|
54
|
+
if (ec == asio::error::operation_aborted) {
|
55
|
+
return;
|
56
|
+
}
|
57
|
+
self->cancel();
|
58
|
+
});
|
59
|
+
}
|
60
|
+
|
61
|
+
void cancel()
|
62
|
+
{
|
63
|
+
if (opaque_ && session_) {
|
64
|
+
session_->cancel(opaque_.value(), asio::error::operation_aborted);
|
65
|
+
}
|
66
|
+
handler_ = nullptr;
|
67
|
+
}
|
68
|
+
|
69
|
+
void invoke_handler(std::error_code ec, std::optional<io::mcbp_message> msg = {})
|
70
|
+
{
|
71
|
+
if (handler_) {
|
72
|
+
handler_(ec, std::move(msg));
|
73
|
+
}
|
74
|
+
handler_ = nullptr;
|
75
|
+
}
|
76
|
+
|
77
|
+
void request_collection_id()
|
78
|
+
{
|
79
|
+
protocol::client_request<protocol::get_collection_id_request_body> req;
|
80
|
+
req.opaque(session_->next_opaque());
|
81
|
+
req.body().collection_path(request.id.collection);
|
82
|
+
session_->write_and_subscribe(req.opaque(),
|
83
|
+
req.data(session_->supports_feature(protocol::hello_feature::snappy)),
|
84
|
+
[self = this->shared_from_this()](std::error_code ec, io::mcbp_message&& msg) mutable {
|
85
|
+
if (ec == asio::error::operation_aborted) {
|
86
|
+
return self->invoke_handler(std::make_error_code(error::common_errc::ambiguous_timeout));
|
87
|
+
}
|
88
|
+
if (ec == std::make_error_code(error::common_errc::collection_not_found)) {
|
89
|
+
if (self->request.id.collection_uid) {
|
90
|
+
return self->handle_unknown_collection();
|
91
|
+
}
|
92
|
+
return self->invoke_handler(ec);
|
93
|
+
}
|
94
|
+
if (ec) {
|
95
|
+
return self->invoke_handler(ec);
|
96
|
+
}
|
97
|
+
protocol::client_response<protocol::get_collection_id_response_body> resp(msg);
|
98
|
+
self->session_->update_collection_uid(self->request.id.collection, resp.body().collection_uid());
|
99
|
+
self->request.id.collection_uid = resp.body().collection_uid();
|
100
|
+
return self->send();
|
101
|
+
});
|
102
|
+
}
|
103
|
+
|
104
|
+
void handle_unknown_collection()
|
105
|
+
{
|
106
|
+
auto backoff = std::chrono::milliseconds(500);
|
107
|
+
auto time_left = deadline.expiry() - std::chrono::steady_clock::now();
|
108
|
+
spdlog::debug("{} unknown collection response for \"{}/{}/{}\", time_left={}ms",
|
109
|
+
session_->log_prefix(),
|
110
|
+
request.id.bucket,
|
111
|
+
request.id.collection,
|
112
|
+
request.id.key,
|
113
|
+
std::chrono::duration_cast<std::chrono::milliseconds>(time_left).count());
|
114
|
+
if (time_left < backoff) {
|
115
|
+
return invoke_handler(std::make_error_code(error::common_errc::ambiguous_timeout));
|
116
|
+
}
|
117
|
+
retry_backoff.expires_after(backoff);
|
118
|
+
retry_backoff.async_wait([self = this->shared_from_this()](std::error_code ec) mutable {
|
119
|
+
if (ec == asio::error::operation_aborted) {
|
120
|
+
return;
|
121
|
+
}
|
122
|
+
self->request_collection_id();
|
123
|
+
});
|
124
|
+
}
|
125
|
+
|
126
|
+
void send()
|
127
|
+
{
|
128
|
+
opaque_ = session_->next_opaque();
|
129
|
+
request.opaque = *opaque_;
|
130
|
+
if (!request.id.collection_uid) {
|
131
|
+
if (session_->supports_feature(protocol::hello_feature::collections)) {
|
132
|
+
auto collection_id = session_->get_collection_uid(request.id.collection);
|
133
|
+
if (collection_id) {
|
134
|
+
request.id.collection_uid = *collection_id;
|
135
|
+
} else {
|
136
|
+
spdlog::debug("{} no cache entry for collection, resolve collection id for \"{}/{}/{}\", timeout={}ms",
|
137
|
+
session_->log_prefix(),
|
138
|
+
request.id.bucket,
|
139
|
+
request.id.collection,
|
140
|
+
request.id.key,
|
141
|
+
request.timeout.count());
|
142
|
+
return request_collection_id();
|
143
|
+
}
|
144
|
+
} else {
|
145
|
+
if (!request.id.collection.empty() && request.id.collection != "_default._default") {
|
146
|
+
return invoke_handler(std::make_error_code(error::common_errc::unsupported_operation));
|
147
|
+
}
|
148
|
+
}
|
149
|
+
}
|
150
|
+
request.encode_to(encoded);
|
151
|
+
|
152
|
+
session_->write_and_subscribe(request.opaque,
|
153
|
+
encoded.data(session_->supports_feature(protocol::hello_feature::snappy)),
|
154
|
+
[self = this->shared_from_this()](std::error_code ec, io::mcbp_message&& msg) mutable {
|
155
|
+
self->retry_backoff.cancel();
|
156
|
+
if (ec == asio::error::operation_aborted) {
|
157
|
+
return self->invoke_handler(std::make_error_code(error::common_errc::ambiguous_timeout));
|
158
|
+
}
|
159
|
+
if (ec == std::make_error_code(error::common_errc::request_canceled)) {
|
160
|
+
return self->invoke_handler(ec);
|
161
|
+
}
|
162
|
+
if (msg.header.status() == static_cast<std::uint16_t>(protocol::status::unknown_collection)) {
|
163
|
+
return self->handle_unknown_collection();
|
164
|
+
}
|
165
|
+
self->deadline.cancel();
|
166
|
+
self->invoke_handler(ec, msg);
|
167
|
+
});
|
168
|
+
}
|
169
|
+
|
170
|
+
void send_to(std::shared_ptr<io::mcbp_session> session)
|
171
|
+
{
|
172
|
+
if (!handler_) {
|
173
|
+
return;
|
174
|
+
}
|
175
|
+
session_ = std::move(session);
|
176
|
+
send();
|
177
|
+
}
|
178
|
+
};
|
179
|
+
|
180
|
+
} // namespace couchbase::operations
|