couchbase 3.0.0.alpha.2-universal-darwin-19 → 3.0.0.alpha.3-universal-darwin-19
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/tests-dev-preview.yml +52 -0
- data/.gitmodules +3 -0
- data/.idea/vcs.xml +1 -0
- data/.yardopts +1 -0
- data/README.md +1 -1
- data/Rakefile +5 -1
- data/bin/init-cluster +13 -5
- data/couchbase.gemspec +2 -1
- data/examples/managing_query_indexes.rb +1 -1
- data/examples/managing_search_indexes.rb +62 -0
- data/examples/search.rb +187 -0
- data/ext/.clang-tidy +1 -0
- data/ext/build_version.hxx.in +1 -1
- data/ext/couchbase/bucket.hxx +0 -40
- data/ext/couchbase/couchbase.cxx +2578 -1368
- data/ext/couchbase/io/http_session.hxx +27 -7
- data/ext/couchbase/io/mcbp_parser.hxx +2 -0
- data/ext/couchbase/io/mcbp_session.hxx +53 -24
- data/ext/couchbase/io/session_manager.hxx +6 -1
- data/ext/couchbase/operations.hxx +13 -0
- data/ext/couchbase/operations/bucket_create.hxx +1 -0
- data/ext/couchbase/operations/bucket_drop.hxx +1 -0
- data/ext/couchbase/operations/bucket_flush.hxx +1 -0
- data/ext/couchbase/operations/bucket_get.hxx +1 -0
- data/ext/couchbase/operations/bucket_get_all.hxx +1 -0
- data/ext/couchbase/operations/bucket_update.hxx +1 -0
- data/ext/couchbase/operations/cluster_developer_preview_enable.hxx +1 -0
- data/ext/couchbase/operations/collection_create.hxx +6 -1
- data/ext/couchbase/operations/collection_drop.hxx +1 -0
- data/ext/couchbase/operations/command.hxx +86 -11
- data/ext/couchbase/operations/document_decrement.hxx +1 -0
- data/ext/couchbase/operations/document_exists.hxx +1 -0
- data/ext/couchbase/operations/document_get.hxx +1 -0
- data/ext/couchbase/operations/document_get_and_lock.hxx +1 -0
- data/ext/couchbase/operations/document_get_and_touch.hxx +1 -0
- data/ext/couchbase/operations/document_get_projected.hxx +243 -0
- data/ext/couchbase/operations/document_increment.hxx +4 -1
- data/ext/couchbase/operations/document_insert.hxx +1 -0
- data/ext/couchbase/operations/document_lookup_in.hxx +1 -0
- data/ext/couchbase/operations/document_mutate_in.hxx +1 -0
- data/ext/couchbase/operations/document_query.hxx +13 -2
- data/ext/couchbase/operations/document_remove.hxx +1 -0
- data/ext/couchbase/operations/document_replace.hxx +1 -0
- data/ext/couchbase/operations/document_search.hxx +337 -0
- data/ext/couchbase/operations/document_touch.hxx +1 -0
- data/ext/couchbase/operations/document_unlock.hxx +1 -0
- data/ext/couchbase/operations/document_upsert.hxx +1 -0
- data/ext/couchbase/operations/query_index_build_deferred.hxx +1 -0
- data/ext/couchbase/operations/query_index_create.hxx +1 -0
- data/ext/couchbase/operations/query_index_drop.hxx +1 -0
- data/ext/couchbase/operations/query_index_get_all.hxx +1 -0
- data/ext/couchbase/operations/scope_create.hxx +1 -0
- data/ext/couchbase/operations/scope_drop.hxx +1 -0
- data/ext/couchbase/operations/scope_get_all.hxx +2 -0
- data/ext/couchbase/operations/search_index.hxx +62 -0
- data/ext/couchbase/operations/search_index_analyze_document.hxx +92 -0
- data/ext/couchbase/operations/search_index_control_ingest.hxx +78 -0
- data/ext/couchbase/operations/search_index_control_plan_freeze.hxx +80 -0
- data/ext/couchbase/operations/search_index_control_query.hxx +80 -0
- data/ext/couchbase/operations/search_index_drop.hxx +77 -0
- data/ext/couchbase/operations/search_index_get.hxx +80 -0
- data/ext/couchbase/operations/search_index_get_all.hxx +82 -0
- data/ext/couchbase/operations/search_index_get_documents_count.hxx +81 -0
- data/ext/couchbase/operations/search_index_upsert.hxx +106 -0
- data/ext/couchbase/protocol/client_opcode.hxx +10 -0
- data/ext/couchbase/protocol/cmd_get_collection_id.hxx +117 -0
- data/ext/couchbase/timeout_defaults.hxx +32 -0
- data/ext/couchbase/version.hxx +1 -1
- data/ext/test/main.cxx +5 -5
- data/lib/couchbase/binary_collection.rb +16 -12
- data/lib/couchbase/binary_collection_options.rb +4 -0
- data/lib/couchbase/cluster.rb +88 -8
- data/lib/couchbase/collection.rb +39 -15
- data/lib/couchbase/collection_options.rb +19 -2
- data/lib/couchbase/json_transcoder.rb +2 -2
- data/lib/couchbase/management/bucket_manager.rb +37 -23
- data/lib/couchbase/management/collection_manager.rb +15 -6
- data/lib/couchbase/management/query_index_manager.rb +16 -6
- data/lib/couchbase/management/search_index_manager.rb +61 -14
- data/lib/couchbase/search_options.rb +1492 -0
- data/lib/couchbase/version.rb +1 -1
- metadata +22 -2
@@ -33,6 +33,7 @@
|
|
33
33
|
#include <io/http_parser.hxx>
|
34
34
|
#include <io/http_message.hxx>
|
35
35
|
#include <platform/base64.h>
|
36
|
+
#include <timeout_defaults.hxx>
|
36
37
|
|
37
38
|
namespace couchbase::io
|
38
39
|
{
|
@@ -73,9 +74,14 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
73
74
|
stop();
|
74
75
|
}
|
75
76
|
|
76
|
-
[[nodiscard]]
|
77
|
+
[[nodiscard]] uuid::uuid_t id()
|
77
78
|
{
|
78
|
-
return
|
79
|
+
return id_;
|
80
|
+
}
|
81
|
+
|
82
|
+
void on_stop(std::function<void()> handler)
|
83
|
+
{
|
84
|
+
on_stop_handler_ = std::move(handler);
|
79
85
|
}
|
80
86
|
|
81
87
|
void stop()
|
@@ -85,6 +91,16 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
85
91
|
socket_.close();
|
86
92
|
}
|
87
93
|
deadline_timer_.cancel();
|
94
|
+
|
95
|
+
for (auto& handler : command_handlers_) {
|
96
|
+
handler(std::make_error_code(error::common_errc::ambiguous_timeout), {});
|
97
|
+
}
|
98
|
+
command_handlers_.clear();
|
99
|
+
|
100
|
+
if (on_stop_handler_) {
|
101
|
+
on_stop_handler_();
|
102
|
+
on_stop_handler_ = nullptr;
|
103
|
+
}
|
88
104
|
}
|
89
105
|
|
90
106
|
bool is_stopped()
|
@@ -105,7 +121,7 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
105
121
|
if (stopped_) {
|
106
122
|
return;
|
107
123
|
}
|
108
|
-
output_buffer_.emplace_back(buf.begin(), buf.end());
|
124
|
+
output_buffer_.emplace_back(std::vector<uint8_t>{ buf.begin(), buf.end() });
|
109
125
|
}
|
110
126
|
|
111
127
|
void flush()
|
@@ -155,7 +171,7 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
155
171
|
{
|
156
172
|
if (it != endpoints_.end()) {
|
157
173
|
spdlog::trace("connecting to {}:{}", it->endpoint().address().to_string(), it->endpoint().port());
|
158
|
-
deadline_timer_.expires_after(
|
174
|
+
deadline_timer_.expires_after(timeout_defaults::connect_timeout);
|
159
175
|
socket_.async_connect(it->endpoint(), std::bind(&http_session::on_connect, this, std::placeholders::_1, it));
|
160
176
|
} else {
|
161
177
|
spdlog::error("no more endpoints left to connect");
|
@@ -213,9 +229,11 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
213
229
|
switch (self->parser_.feed(reinterpret_cast<const char*>(self->input_buffer_.data()), bytes_transferred)) {
|
214
230
|
case http_parser::status::ok:
|
215
231
|
if (self->parser_.complete) {
|
216
|
-
|
217
|
-
|
218
|
-
|
232
|
+
if (!self->command_handlers_.empty()) {
|
233
|
+
auto handler = self->command_handlers_.front();
|
234
|
+
self->command_handlers_.pop_front();
|
235
|
+
handler({}, std::move(self->parser_.response));
|
236
|
+
}
|
219
237
|
self->parser_.reset();
|
220
238
|
return;
|
221
239
|
}
|
@@ -273,6 +291,8 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
273
291
|
bool stopped_{ false };
|
274
292
|
bool connected_{ false };
|
275
293
|
|
294
|
+
std::function<void()> on_stop_handler_{ nullptr };
|
295
|
+
|
276
296
|
std::list<std::function<void(std::error_code, io::http_response&&)>> command_handlers_{};
|
277
297
|
http_parser parser_{};
|
278
298
|
std::array<std::uint8_t, 16384> input_buffer_{};
|
@@ -73,6 +73,8 @@ struct mcbp_parser {
|
|
73
73
|
if (success) {
|
74
74
|
std::copy(uncompressed.begin(), uncompressed.end(), std::back_inserter(msg.body));
|
75
75
|
use_raw_value = false;
|
76
|
+
// patch header with new body size
|
77
|
+
msg.header.bodylen = htonl(static_cast<std::uint32_t>(prefix_size + uncompressed.size()));
|
76
78
|
}
|
77
79
|
}
|
78
80
|
if (use_raw_value) {
|
@@ -28,6 +28,8 @@
|
|
28
28
|
#include <io/mcbp_message.hxx>
|
29
29
|
#include <io/mcbp_parser.hxx>
|
30
30
|
|
31
|
+
#include <timeout_defaults.hxx>
|
32
|
+
|
31
33
|
#include <protocol/hello_feature.hxx>
|
32
34
|
#include <protocol/client_request.hxx>
|
33
35
|
#include <protocol/client_response.hxx>
|
@@ -39,7 +41,6 @@
|
|
39
41
|
#include <protocol/cmd_select_bucket.hxx>
|
40
42
|
#include <protocol/cmd_get_cluster_config.hxx>
|
41
43
|
#include <protocol/cmd_get_error_map.hxx>
|
42
|
-
#include <protocol/cmd_get_collections_manifest.hxx>
|
43
44
|
#include <protocol/cmd_get.hxx>
|
44
45
|
#include <protocol/cmd_cluster_map_change_notification.hxx>
|
45
46
|
|
@@ -55,6 +56,35 @@ namespace couchbase::io
|
|
55
56
|
|
56
57
|
class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
57
58
|
{
|
59
|
+
class collection_cache
|
60
|
+
{
|
61
|
+
private:
|
62
|
+
std::map<std::string, std::uint32_t> cid_map_{ { "_default._default", 0 } };
|
63
|
+
|
64
|
+
public:
|
65
|
+
[[nodiscard]] std::optional<std::uint32_t> get(const std::string& path)
|
66
|
+
{
|
67
|
+
Expects(!path.empty());
|
68
|
+
auto ptr = cid_map_.find(path);
|
69
|
+
if (ptr != cid_map_.end()) {
|
70
|
+
return ptr->second;
|
71
|
+
}
|
72
|
+
return {};
|
73
|
+
}
|
74
|
+
|
75
|
+
void update(const std::string& path, std::uint32_t id)
|
76
|
+
{
|
77
|
+
Expects(!path.empty());
|
78
|
+
cid_map_[path] = id;
|
79
|
+
}
|
80
|
+
|
81
|
+
void reset()
|
82
|
+
{
|
83
|
+
cid_map_.clear();
|
84
|
+
cid_map_["_default._default"] = 0;
|
85
|
+
}
|
86
|
+
};
|
87
|
+
|
58
88
|
class message_handler
|
59
89
|
{
|
60
90
|
public:
|
@@ -138,10 +168,6 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
138
168
|
sb_req.opaque(session_->next_opaque());
|
139
169
|
sb_req.body().bucket_name(session_->bucket_name_.value());
|
140
170
|
session_->write(sb_req.data());
|
141
|
-
|
142
|
-
protocol::client_request<protocol::get_collections_manifest_request_body> gcm_req;
|
143
|
-
gcm_req.opaque(session_->next_opaque());
|
144
|
-
session_->write(gcm_req.data());
|
145
171
|
}
|
146
172
|
protocol::client_request<protocol::get_cluster_config_request_body> cfg_req;
|
147
173
|
cfg_req.opaque(session_->next_opaque());
|
@@ -216,21 +242,6 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
216
242
|
return complete(std::make_error_code(error::network_errc::protocol_error));
|
217
243
|
}
|
218
244
|
} break;
|
219
|
-
case protocol::client_opcode::get_collections_manifest: {
|
220
|
-
protocol::client_response<protocol::get_collections_manifest_response_body> resp(msg);
|
221
|
-
if (resp.status() == protocol::status::success) {
|
222
|
-
session_->manifest_.emplace(resp.body().manifest());
|
223
|
-
spdlog::trace(
|
224
|
-
"collections manifest for bucket \"{}\": {}", session_->bucket_name_.value_or(""), *session_->manifest_);
|
225
|
-
} else if (resp.status() == protocol::status::no_collections_manifest) {
|
226
|
-
spdlog::trace("collection manifest is not available for bucket \"{}\": {}",
|
227
|
-
session_->bucket_name_.value_or(""),
|
228
|
-
resp.error_message());
|
229
|
-
} else {
|
230
|
-
spdlog::warn("unexpected message status during bootstrap: {} (opcode={})", resp.error_message(), opcode);
|
231
|
-
return complete(std::make_error_code(error::network_errc::protocol_error));
|
232
|
-
}
|
233
|
-
} break;
|
234
245
|
case protocol::client_opcode::select_bucket: {
|
235
246
|
protocol::client_response<protocol::select_bucket_response_body> resp(msg);
|
236
247
|
if (resp.status() == protocol::status::success) {
|
@@ -320,6 +331,7 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
320
331
|
spdlog::warn("unexpected message status: {}", resp.error_message());
|
321
332
|
}
|
322
333
|
} break;
|
334
|
+
case protocol::client_opcode::get_collection_id:
|
323
335
|
case protocol::client_opcode::get:
|
324
336
|
case protocol::client_opcode::get_and_lock:
|
325
337
|
case protocol::client_opcode::get_and_touch:
|
@@ -481,9 +493,16 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
481
493
|
}
|
482
494
|
}
|
483
495
|
|
484
|
-
|
496
|
+
void cancel(uint32_t opaque, std::error_code ec)
|
485
497
|
{
|
486
|
-
|
498
|
+
if (stopped_) {
|
499
|
+
return;
|
500
|
+
}
|
501
|
+
auto handler = command_handlers_.find(opaque);
|
502
|
+
if (handler != command_handlers_.end()) {
|
503
|
+
handler->second(ec, {});
|
504
|
+
command_handlers_.erase(handler);
|
505
|
+
}
|
487
506
|
}
|
488
507
|
|
489
508
|
bool supports_feature(protocol::hello_feature feature)
|
@@ -663,6 +682,16 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
663
682
|
}
|
664
683
|
}
|
665
684
|
|
685
|
+
std::optional<std::uint32_t> get_collection_uid(const std::string& collection_path)
|
686
|
+
{
|
687
|
+
return collection_cache_.get(collection_path);
|
688
|
+
}
|
689
|
+
|
690
|
+
void update_collection_uid(const std::string& path, std::uint32_t uid)
|
691
|
+
{
|
692
|
+
collection_cache_.update(path, uid);
|
693
|
+
}
|
694
|
+
|
666
695
|
private:
|
667
696
|
void invoke_bootstrap_handler(std::error_code ec)
|
668
697
|
{
|
@@ -704,7 +733,7 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
704
733
|
}
|
705
734
|
if (it != endpoints_.end()) {
|
706
735
|
spdlog::trace("connecting to {}:{}", it->endpoint().address().to_string(), it->endpoint().port());
|
707
|
-
deadline_timer_.expires_after(
|
736
|
+
deadline_timer_.expires_after(timeout_defaults::connect_timeout);
|
708
737
|
socket_.async_connect(it->endpoint(), std::bind(&mcbp_session::on_connect, this, std::placeholders::_1, it));
|
709
738
|
} else {
|
710
739
|
spdlog::error("no more endpoints left to connect");
|
@@ -852,7 +881,7 @@ class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
|
852
881
|
std::vector<protocol::hello_feature> supported_features_;
|
853
882
|
std::optional<configuration> config_;
|
854
883
|
std::optional<error_map> errmap_;
|
855
|
-
|
884
|
+
collection_cache collection_cache_;
|
856
885
|
|
857
886
|
std::atomic_bool reading_{ false };
|
858
887
|
};
|
@@ -25,7 +25,7 @@
|
|
25
25
|
namespace couchbase::io
|
26
26
|
{
|
27
27
|
|
28
|
-
class session_manager
|
28
|
+
class session_manager : public std::enable_shared_from_this<session_manager>
|
29
29
|
{
|
30
30
|
public:
|
31
31
|
session_manager(uuid::uuid_t client_id, asio::io_context& ctx)
|
@@ -57,11 +57,16 @@ class session_manager
|
|
57
57
|
}
|
58
58
|
config_.nodes.size();
|
59
59
|
auto session = std::make_shared<http_session>(client_id_, ctx_, username, password, hostname, std::to_string(port));
|
60
|
+
session->on_stop([type, id = session->id(), self = this->shared_from_this()]() {
|
61
|
+
self->busy_sessions_[type].remove_if([id](const auto& s) -> bool { return s->id() == id; });
|
62
|
+
self->idle_sessions_[type].remove_if([id](const auto& s) -> bool { return s->id() == id; });
|
63
|
+
});
|
60
64
|
busy_sessions_[type].push_back(session);
|
61
65
|
return session;
|
62
66
|
}
|
63
67
|
auto session = idle_sessions_[type].front();
|
64
68
|
idle_sessions_[type].pop_front();
|
69
|
+
busy_sessions_[type].push_back(session);
|
65
70
|
return session;
|
66
71
|
}
|
67
72
|
|
@@ -18,6 +18,7 @@
|
|
18
18
|
#pragma once
|
19
19
|
|
20
20
|
#include <document_id.hxx>
|
21
|
+
#include <timeout_defaults.hxx>
|
21
22
|
|
22
23
|
#include <operations/document_get.hxx>
|
23
24
|
#include <operations/document_get_and_lock.hxx>
|
@@ -33,8 +34,10 @@
|
|
33
34
|
#include <operations/document_unlock.hxx>
|
34
35
|
#include <operations/document_increment.hxx>
|
35
36
|
#include <operations/document_decrement.hxx>
|
37
|
+
#include <operations/document_get_projected.hxx>
|
36
38
|
|
37
39
|
#include <operations/document_query.hxx>
|
40
|
+
#include <operations/document_search.hxx>
|
38
41
|
|
39
42
|
#include <operations/bucket_get_all.hxx>
|
40
43
|
#include <operations/bucket_get.hxx>
|
@@ -56,4 +59,14 @@
|
|
56
59
|
#include <operations/query_index_create.hxx>
|
57
60
|
#include <operations/query_index_build_deferred.hxx>
|
58
61
|
|
62
|
+
#include <operations/search_index_get_all.hxx>
|
63
|
+
#include <operations/search_index_get.hxx>
|
64
|
+
#include <operations/search_index_get_documents_count.hxx>
|
65
|
+
#include <operations/search_index_upsert.hxx>
|
66
|
+
#include <operations/search_index_drop.hxx>
|
67
|
+
#include <operations/search_index_control_ingest.hxx>
|
68
|
+
#include <operations/search_index_control_query.hxx>
|
69
|
+
#include <operations/search_index_control_plan_freeze.hxx>
|
70
|
+
#include <operations/search_index_analyze_document.hxx>
|
71
|
+
|
59
72
|
#include <operations/command.hxx>
|
@@ -39,6 +39,7 @@ struct bucket_create_request {
|
|
39
39
|
static const inline service_type type = service_type::management;
|
40
40
|
|
41
41
|
bucket_settings bucket{};
|
42
|
+
std::chrono::milliseconds timeout{ timeout_defaults::management_timeout };
|
42
43
|
|
43
44
|
void encode_to(encoded_request_type& encoded)
|
44
45
|
{
|
@@ -36,6 +36,7 @@ struct bucket_get_all_request {
|
|
36
36
|
using encoded_response_type = io::http_response;
|
37
37
|
|
38
38
|
static const inline service_type type = service_type::management;
|
39
|
+
std::chrono::milliseconds timeout{ timeout_defaults::management_timeout };
|
39
40
|
|
40
41
|
void encode_to(encoded_request_type& encoded)
|
41
42
|
{
|
@@ -38,6 +38,7 @@ struct bucket_update_request {
|
|
38
38
|
using encoded_response_type = io::http_response;
|
39
39
|
|
40
40
|
static const inline service_type type = service_type::management;
|
41
|
+
std::chrono::milliseconds timeout{ timeout_defaults::management_timeout };
|
41
42
|
|
42
43
|
bucket_settings bucket{};
|
43
44
|
|
@@ -35,6 +35,7 @@ struct cluster_developer_preview_enable_request {
|
|
35
35
|
using encoded_response_type = io::http_response;
|
36
36
|
|
37
37
|
static const inline service_type type = service_type::management;
|
38
|
+
std::chrono::milliseconds timeout{ timeout_defaults::management_timeout };
|
38
39
|
|
39
40
|
void encode_to(encoded_request_type& encoded)
|
40
41
|
{
|
@@ -42,6 +42,7 @@ struct collection_create_request {
|
|
42
42
|
std::string scope_name;
|
43
43
|
std::string collection_name;
|
44
44
|
std::uint32_t max_expiry{ 0 };
|
45
|
+
std::chrono::milliseconds timeout{ timeout_defaults::management_timeout };
|
45
46
|
|
46
47
|
void encode_to(encoded_request_type& encoded)
|
47
48
|
{
|
@@ -62,7 +63,11 @@ make_response(std::error_code ec, collection_create_request&, collection_create_
|
|
62
63
|
if (!ec) {
|
63
64
|
switch (encoded.status_code) {
|
64
65
|
case 400:
|
65
|
-
|
66
|
+
if (encoded.body.find("Collection with this name already exists") != std::string::npos) {
|
67
|
+
response.ec = std::make_error_code(error::management_errc::collection_exists);
|
68
|
+
} else {
|
69
|
+
response.ec = std::make_error_code(error::common_errc::invalid_argument);
|
70
|
+
}
|
66
71
|
break;
|
67
72
|
case 404:
|
68
73
|
if (encoded.body.find("Scope with this name is not found") != std::string::npos) {
|
@@ -19,6 +19,7 @@
|
|
19
19
|
|
20
20
|
#include <io/mcbp_session.hxx>
|
21
21
|
#include <io/http_session.hxx>
|
22
|
+
#include <protocol/cmd_get_collection_id.hxx>
|
22
23
|
|
23
24
|
namespace couchbase::operations
|
24
25
|
{
|
@@ -28,30 +29,103 @@ struct command : public std::enable_shared_from_this<command<Request>> {
|
|
28
29
|
using encoded_request_type = typename Request::encoded_request_type;
|
29
30
|
using encoded_response_type = typename Request::encoded_response_type;
|
30
31
|
asio::steady_timer deadline;
|
32
|
+
asio::steady_timer retry_backoff;
|
31
33
|
Request request;
|
32
34
|
encoded_request_type encoded;
|
33
35
|
|
34
36
|
command(asio::io_context& ctx, Request&& req)
|
35
37
|
: deadline(ctx)
|
38
|
+
, retry_backoff(ctx)
|
36
39
|
, request(req)
|
37
40
|
{
|
38
41
|
}
|
39
42
|
|
43
|
+
template<typename Handler>
|
44
|
+
void request_collection_id(std::shared_ptr<io::mcbp_session> session, Handler&& handler)
|
45
|
+
{
|
46
|
+
protocol::client_request<protocol::get_collection_id_request_body> req;
|
47
|
+
req.opaque(session->next_opaque());
|
48
|
+
req.body().collection_path(request.id.collection);
|
49
|
+
session->write_and_subscribe(req.opaque(),
|
50
|
+
req.data(session->supports_feature(protocol::hello_feature::snappy)),
|
51
|
+
[self = this->shared_from_this(), session, handler = std::forward<Handler>(handler)](
|
52
|
+
std::error_code ec, io::mcbp_message&& msg) mutable {
|
53
|
+
if (ec == std::make_error_code(error::common_errc::collection_not_found)) {
|
54
|
+
if (self->request.id.collection_uid) {
|
55
|
+
return self->handle_unknown_collection(session, std::forward<Handler>(handler));
|
56
|
+
}
|
57
|
+
return handler(make_response(ec, self->request, {}));
|
58
|
+
}
|
59
|
+
if (ec) {
|
60
|
+
return handler(make_response(ec, self->request, {}));
|
61
|
+
}
|
62
|
+
protocol::client_response<protocol::get_collection_id_response_body> resp(msg);
|
63
|
+
session->update_collection_uid(self->request.id.collection, resp.body().collection_uid());
|
64
|
+
self->request.id.collection_uid = resp.body().collection_uid();
|
65
|
+
return self->send_to(session, std::forward<Handler>(handler));
|
66
|
+
});
|
67
|
+
}
|
68
|
+
|
69
|
+
template<typename Handler>
|
70
|
+
void handle_unknown_collection(std::shared_ptr<io::mcbp_session> session, Handler&& handler)
|
71
|
+
{
|
72
|
+
auto backoff = std::chrono::milliseconds(500);
|
73
|
+
if (std::chrono::steady_clock::now() + backoff > deadline.expiry()) {
|
74
|
+
return handler(make_response(std::make_error_code(error::common_errc::ambiguous_timeout), request, {}));
|
75
|
+
}
|
76
|
+
retry_backoff.expires_after(backoff);
|
77
|
+
retry_backoff.async_wait(
|
78
|
+
[self = this->shared_from_this(), session, handler = std::forward<Handler>(handler)](std::error_code ec) mutable {
|
79
|
+
if (ec == asio::error::operation_aborted) {
|
80
|
+
return handler(make_response(std::make_error_code(error::common_errc::ambiguous_timeout), self->request, {}));
|
81
|
+
}
|
82
|
+
self->request_collection_id(session, std::forward<Handler>(handler));
|
83
|
+
});
|
84
|
+
}
|
85
|
+
|
40
86
|
template<typename Handler>
|
41
87
|
void send_to(std::shared_ptr<io::mcbp_session> session, Handler&& handler)
|
42
88
|
{
|
43
|
-
|
89
|
+
auto opaque = session->next_opaque();
|
90
|
+
request.opaque = opaque;
|
91
|
+
if (!request.id.collection_uid) {
|
92
|
+
if (session->supports_feature(protocol::hello_feature::collections)) {
|
93
|
+
auto collection_id = session->get_collection_uid(request.id.collection);
|
94
|
+
if (collection_id) {
|
95
|
+
request.id.collection_uid = *collection_id;
|
96
|
+
} else {
|
97
|
+
return request_collection_id(session, std::forward<Handler>(handler));
|
98
|
+
}
|
99
|
+
} else {
|
100
|
+
if (!request.id.collection.empty() && request.id.collection != "_default._default") {
|
101
|
+
return handler(make_response(std::make_error_code(error::common_errc::unsupported_operation), request, {}));
|
102
|
+
}
|
103
|
+
}
|
104
|
+
}
|
44
105
|
request.encode_to(encoded);
|
45
106
|
session->write_and_subscribe(
|
46
107
|
request.opaque,
|
47
108
|
encoded.data(session->supports_feature(protocol::hello_feature::snappy)),
|
48
|
-
[self = this->shared_from_this(), handler = std::forward<Handler>(handler)](std::error_code ec,
|
49
|
-
|
109
|
+
[self = this->shared_from_this(), session, handler = std::forward<Handler>(handler)](std::error_code ec,
|
110
|
+
io::mcbp_message&& msg) mutable {
|
111
|
+
if (ec == asio::error::operation_aborted) {
|
112
|
+
return handler(make_response(std::make_error_code(error::common_errc::ambiguous_timeout), self->request, {}));
|
113
|
+
}
|
50
114
|
self->deadline.cancel();
|
115
|
+
self->retry_backoff.cancel();
|
116
|
+
encoded_response_type resp(msg);
|
117
|
+
if (resp.status() == protocol::status::unknown_collection) {
|
118
|
+
return self->handle_unknown_collection(session, std::forward<Handler>(handler));
|
119
|
+
}
|
51
120
|
handler(make_response(ec, self->request, resp));
|
52
121
|
});
|
53
|
-
deadline.expires_after(
|
54
|
-
deadline.async_wait(std::
|
122
|
+
deadline.expires_after(request.timeout);
|
123
|
+
deadline.async_wait([session, opaque](std::error_code ec) {
|
124
|
+
if (ec == asio::error::operation_aborted) {
|
125
|
+
return;
|
126
|
+
}
|
127
|
+
session->cancel(opaque, asio::error::operation_aborted);
|
128
|
+
});
|
55
129
|
}
|
56
130
|
|
57
131
|
template<typename Handler>
|
@@ -65,12 +139,13 @@ struct command : public std::enable_shared_from_this<command<Request>> {
|
|
65
139
|
self->deadline.cancel();
|
66
140
|
handler(make_response(ec, self->request, resp));
|
67
141
|
});
|
68
|
-
deadline.expires_after(
|
69
|
-
deadline.async_wait(std::
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
142
|
+
deadline.expires_after(request.timeout);
|
143
|
+
deadline.async_wait([session](std::error_code ec) {
|
144
|
+
if (ec == asio::error::operation_aborted) {
|
145
|
+
return;
|
146
|
+
}
|
147
|
+
session->stop();
|
148
|
+
});
|
74
149
|
}
|
75
150
|
};
|
76
151
|
|