couchbase 3.0.0.alpha.2-universal-darwin-19 → 3.0.0.alpha.3-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/.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
|
|