couchbase 3.0.0.alpha.1-universal-darwin-19 → 3.0.0.alpha.2-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-6.0.3.yml +49 -0
- data/.github/workflows/tests.yml +47 -0
- data/.gitmodules +3 -0
- data/.idea/dictionaries/gem_terms.xml +5 -0
- data/.idea/inspectionProfiles/Project_Default.xml +1 -0
- data/.idea/vcs.xml +1 -0
- data/Gemfile +1 -0
- data/README.md +55 -2
- data/Rakefile +18 -0
- data/bin/init-cluster +62 -0
- data/bin/setup +1 -0
- data/couchbase.gemspec +3 -2
- data/examples/crud.rb +1 -2
- data/examples/managing_buckets.rb +47 -0
- data/examples/managing_collections.rb +58 -0
- data/examples/managing_query_indexes.rb +63 -0
- data/examples/query.rb +3 -2
- data/examples/query_with_consistency.rb +76 -0
- data/examples/subdocument.rb +23 -1
- data/ext/.clang-format +1 -1
- data/ext/.idea/dictionaries/couchbase_terms.xml +2 -0
- data/ext/.idea/vcs.xml +1 -0
- data/ext/CMakeLists.txt +30 -12
- data/ext/build_version.hxx.in +26 -0
- data/ext/couchbase/bucket.hxx +69 -8
- data/ext/couchbase/cluster.hxx +70 -54
- data/ext/couchbase/collections_manifest.hxx +3 -3
- data/ext/couchbase/configuration.hxx +14 -0
- data/ext/couchbase/couchbase.cxx +2044 -383
- data/ext/couchbase/{operations/document_id.hxx → document_id.hxx} +5 -4
- data/ext/couchbase/io/http_message.hxx +5 -1
- data/ext/couchbase/io/http_parser.hxx +2 -1
- data/ext/couchbase/io/http_session.hxx +6 -3
- data/ext/couchbase/io/{binary_message.hxx → mcbp_message.hxx} +15 -12
- data/ext/couchbase/io/mcbp_parser.hxx +99 -0
- data/ext/couchbase/io/{key_value_session.hxx → mcbp_session.hxx} +200 -95
- data/ext/couchbase/io/session_manager.hxx +37 -22
- data/ext/couchbase/mutation_token.hxx +2 -1
- data/ext/couchbase/operations.hxx +38 -8
- data/ext/couchbase/operations/bucket_create.hxx +138 -0
- data/ext/couchbase/operations/bucket_drop.hxx +65 -0
- data/ext/couchbase/operations/bucket_flush.hxx +65 -0
- data/ext/couchbase/operations/bucket_get.hxx +69 -0
- data/ext/couchbase/operations/bucket_get_all.hxx +62 -0
- data/ext/couchbase/operations/bucket_settings.hxx +111 -0
- data/ext/couchbase/operations/bucket_update.hxx +115 -0
- data/ext/couchbase/operations/cluster_developer_preview_enable.hxx +60 -0
- data/ext/couchbase/operations/collection_create.hxx +86 -0
- data/ext/couchbase/operations/collection_drop.hxx +82 -0
- data/ext/couchbase/operations/command.hxx +10 -10
- data/ext/couchbase/operations/document_decrement.hxx +80 -0
- data/ext/couchbase/operations/document_exists.hxx +80 -0
- data/ext/couchbase/operations/{get.hxx → document_get.hxx} +4 -2
- data/ext/couchbase/operations/document_get_and_lock.hxx +64 -0
- data/ext/couchbase/operations/document_get_and_touch.hxx +64 -0
- data/ext/couchbase/operations/document_increment.hxx +80 -0
- data/ext/couchbase/operations/document_insert.hxx +74 -0
- data/ext/couchbase/operations/{lookup_in.hxx → document_lookup_in.hxx} +2 -2
- data/ext/couchbase/operations/{mutate_in.hxx → document_mutate_in.hxx} +11 -2
- data/ext/couchbase/operations/{query.hxx → document_query.hxx} +101 -6
- data/ext/couchbase/operations/document_remove.hxx +67 -0
- data/ext/couchbase/operations/document_replace.hxx +76 -0
- data/ext/couchbase/operations/{upsert.hxx → document_touch.hxx} +14 -14
- data/ext/couchbase/operations/{remove.hxx → document_unlock.hxx} +12 -10
- data/ext/couchbase/operations/document_upsert.hxx +74 -0
- data/ext/couchbase/operations/query_index_build_deferred.hxx +85 -0
- data/ext/couchbase/operations/query_index_create.hxx +134 -0
- data/ext/couchbase/operations/query_index_drop.hxx +108 -0
- data/ext/couchbase/operations/query_index_get_all.hxx +106 -0
- data/ext/couchbase/operations/scope_create.hxx +81 -0
- data/ext/couchbase/operations/scope_drop.hxx +79 -0
- data/ext/couchbase/operations/scope_get_all.hxx +72 -0
- data/ext/couchbase/protocol/client_opcode.hxx +35 -0
- data/ext/couchbase/protocol/client_request.hxx +56 -9
- data/ext/couchbase/protocol/client_response.hxx +52 -15
- data/ext/couchbase/protocol/cmd_cluster_map_change_notification.hxx +81 -0
- data/ext/couchbase/protocol/cmd_decrement.hxx +187 -0
- data/ext/couchbase/protocol/cmd_exists.hxx +171 -0
- data/ext/couchbase/protocol/cmd_get.hxx +31 -8
- data/ext/couchbase/protocol/cmd_get_and_lock.hxx +142 -0
- data/ext/couchbase/protocol/cmd_get_and_touch.hxx +142 -0
- data/ext/couchbase/protocol/cmd_get_cluster_config.hxx +16 -3
- data/ext/couchbase/protocol/cmd_get_collections_manifest.hxx +16 -3
- data/ext/couchbase/protocol/cmd_get_error_map.hxx +16 -3
- data/ext/couchbase/protocol/cmd_hello.hxx +24 -8
- data/ext/couchbase/protocol/cmd_increment.hxx +187 -0
- data/ext/couchbase/protocol/cmd_info.hxx +1 -0
- data/ext/couchbase/protocol/cmd_insert.hxx +172 -0
- data/ext/couchbase/protocol/cmd_lookup_in.hxx +28 -13
- data/ext/couchbase/protocol/cmd_mutate_in.hxx +65 -13
- data/ext/couchbase/protocol/cmd_remove.hxx +59 -4
- data/ext/couchbase/protocol/cmd_replace.hxx +172 -0
- data/ext/couchbase/protocol/cmd_sasl_auth.hxx +15 -3
- data/ext/couchbase/protocol/cmd_sasl_list_mechs.hxx +15 -3
- data/ext/couchbase/protocol/cmd_sasl_step.hxx +15 -3
- data/ext/couchbase/protocol/cmd_select_bucket.hxx +14 -2
- data/ext/couchbase/protocol/cmd_touch.hxx +102 -0
- data/ext/couchbase/protocol/cmd_unlock.hxx +95 -0
- data/ext/couchbase/protocol/cmd_upsert.hxx +50 -14
- data/ext/couchbase/protocol/durability_level.hxx +67 -0
- data/ext/couchbase/protocol/frame_info_id.hxx +187 -0
- data/ext/couchbase/protocol/hello_feature.hxx +137 -0
- data/ext/couchbase/protocol/server_opcode.hxx +57 -0
- data/ext/couchbase/protocol/server_request.hxx +122 -0
- data/ext/couchbase/protocol/unsigned_leb128.h +15 -15
- data/ext/couchbase/utils/byteswap.hxx +1 -2
- data/ext/couchbase/utils/url_codec.hxx +225 -0
- data/ext/couchbase/version.hxx +3 -1
- data/ext/extconf.rb +4 -1
- data/ext/test/main.cxx +37 -113
- data/ext/third_party/snappy/.appveyor.yml +36 -0
- data/ext/third_party/snappy/.gitignore +8 -0
- data/ext/third_party/snappy/.travis.yml +98 -0
- data/ext/third_party/snappy/AUTHORS +1 -0
- data/ext/third_party/snappy/CMakeLists.txt +345 -0
- data/ext/third_party/snappy/CONTRIBUTING.md +26 -0
- data/ext/third_party/snappy/COPYING +54 -0
- data/ext/third_party/snappy/NEWS +188 -0
- data/ext/third_party/snappy/README.md +148 -0
- data/ext/third_party/snappy/cmake/SnappyConfig.cmake.in +33 -0
- data/ext/third_party/snappy/cmake/config.h.in +59 -0
- data/ext/third_party/snappy/docs/README.md +72 -0
- data/ext/third_party/snappy/format_description.txt +110 -0
- data/ext/third_party/snappy/framing_format.txt +135 -0
- data/ext/third_party/snappy/snappy-c.cc +90 -0
- data/ext/third_party/snappy/snappy-c.h +138 -0
- data/ext/third_party/snappy/snappy-internal.h +315 -0
- data/ext/third_party/snappy/snappy-sinksource.cc +121 -0
- data/ext/third_party/snappy/snappy-sinksource.h +182 -0
- data/ext/third_party/snappy/snappy-stubs-internal.cc +42 -0
- data/ext/third_party/snappy/snappy-stubs-internal.h +493 -0
- data/ext/third_party/snappy/snappy-stubs-public.h.in +63 -0
- data/ext/third_party/snappy/snappy-test.cc +613 -0
- data/ext/third_party/snappy/snappy-test.h +526 -0
- data/ext/third_party/snappy/snappy.cc +1770 -0
- data/ext/third_party/snappy/snappy.h +209 -0
- data/ext/third_party/snappy/snappy_compress_fuzzer.cc +60 -0
- data/ext/third_party/snappy/snappy_uncompress_fuzzer.cc +58 -0
- data/ext/third_party/snappy/snappy_unittest.cc +1512 -0
- data/ext/third_party/snappy/testdata/alice29.txt +3609 -0
- data/ext/third_party/snappy/testdata/asyoulik.txt +4122 -0
- data/ext/third_party/snappy/testdata/baddata1.snappy +0 -0
- data/ext/third_party/snappy/testdata/baddata2.snappy +0 -0
- data/ext/third_party/snappy/testdata/baddata3.snappy +0 -0
- data/ext/third_party/snappy/testdata/fireworks.jpeg +0 -0
- data/ext/third_party/snappy/testdata/geo.protodata +0 -0
- data/ext/third_party/snappy/testdata/html +1 -0
- data/ext/third_party/snappy/testdata/html_x_4 +1 -0
- data/ext/third_party/snappy/testdata/kppkn.gtb +0 -0
- data/ext/third_party/snappy/testdata/lcet10.txt +7519 -0
- data/ext/third_party/snappy/testdata/paper-100k.pdf +600 -2
- data/ext/third_party/snappy/testdata/plrabn12.txt +10699 -0
- data/ext/third_party/snappy/testdata/urls.10K +10000 -0
- data/lib/couchbase/binary_collection.rb +33 -76
- data/lib/couchbase/binary_collection_options.rb +94 -0
- data/lib/couchbase/bucket.rb +9 -3
- data/lib/couchbase/cluster.rb +161 -23
- data/lib/couchbase/collection.rb +108 -191
- data/lib/couchbase/collection_options.rb +430 -0
- data/lib/couchbase/errors.rb +136 -134
- data/lib/couchbase/json_transcoder.rb +32 -0
- data/lib/couchbase/management/analytics_index_manager.rb +185 -9
- data/lib/couchbase/management/bucket_manager.rb +84 -33
- data/lib/couchbase/management/collection_manager.rb +166 -1
- data/lib/couchbase/management/query_index_manager.rb +261 -0
- data/lib/couchbase/management/search_index_manager.rb +291 -0
- data/lib/couchbase/management/user_manager.rb +12 -10
- data/lib/couchbase/management/view_index_manager.rb +151 -1
- data/lib/couchbase/mutation_state.rb +11 -1
- data/lib/couchbase/scope.rb +4 -4
- data/lib/couchbase/version.rb +1 -1
- metadata +113 -18
- data/.travis.yml +0 -7
- data/ext/couchbase/io/binary_parser.hxx +0 -64
- data/lib/couchbase/results.rb +0 -307
@@ -17,19 +17,20 @@
|
|
17
17
|
|
18
18
|
#pragma once
|
19
19
|
|
20
|
-
namespace couchbase
|
20
|
+
namespace couchbase
|
21
21
|
{
|
22
22
|
struct document_id {
|
23
23
|
std::string bucket;
|
24
24
|
std::string collection;
|
25
25
|
std::string key;
|
26
|
+
std::optional<std::uint32_t> collection_uid; // filled with resolved UID during request lifetime
|
26
27
|
};
|
27
|
-
} // namespace couchbase
|
28
|
+
} // namespace couchbase
|
28
29
|
|
29
30
|
template<>
|
30
|
-
struct fmt::formatter<couchbase::
|
31
|
+
struct fmt::formatter<couchbase::document_id> : formatter<std::string> {
|
31
32
|
template<typename FormatContext>
|
32
|
-
auto format(const couchbase::
|
33
|
+
auto format(const couchbase::document_id& id, FormatContext& ctx)
|
33
34
|
{
|
34
35
|
format_to(ctx.out(), "{}/{}/{}", id.bucket, id.collection, id.key);
|
35
36
|
return formatter<std::string>::format("", ctx);
|
@@ -17,9 +17,12 @@
|
|
17
17
|
|
18
18
|
#pragma once
|
19
19
|
|
20
|
+
#include <service_type.hxx>
|
21
|
+
|
20
22
|
namespace couchbase::io
|
21
23
|
{
|
22
24
|
struct http_request {
|
25
|
+
service_type type;
|
23
26
|
std::string method;
|
24
27
|
std::string path;
|
25
28
|
std::map<std::string, std::string> headers;
|
@@ -27,7 +30,8 @@ struct http_request {
|
|
27
30
|
};
|
28
31
|
|
29
32
|
struct http_response {
|
30
|
-
|
33
|
+
uint32_t status_code;
|
34
|
+
std::string status_message;
|
31
35
|
std::map<std::string, std::string> headers;
|
32
36
|
std::string body;
|
33
37
|
};
|
@@ -148,7 +148,7 @@ class http_session : public std::enable_shared_from_this
|
|
148
148
|
}
|
149
149
|
endpoints_ = endpoints;
|
150
150
|
do_connect(endpoints_.begin());
|
151
|
-
deadline_timer_.async_wait(std::bind(&http_session::check_deadline, this));
|
151
|
+
deadline_timer_.async_wait(std::bind(&http_session::check_deadline, this, std::placeholders::_1));
|
152
152
|
}
|
153
153
|
|
154
154
|
void do_connect(asio::ip::tcp::resolver::results_type::iterator it)
|
@@ -180,8 +180,11 @@ class http_session : public std::enable_shared_from_this
|
|
180
180
|
}
|
181
181
|
}
|
182
182
|
|
183
|
-
void check_deadline()
|
183
|
+
void check_deadline(std::error_code ec)
|
184
184
|
{
|
185
|
+
if (ec == asio::error::operation_aborted) {
|
186
|
+
return;
|
187
|
+
}
|
185
188
|
if (stopped_) {
|
186
189
|
return;
|
187
190
|
}
|
@@ -189,7 +192,7 @@ class http_session : public std::enable_shared_from_this
|
|
189
192
|
socket_.close();
|
190
193
|
deadline_timer_.expires_at(asio::steady_timer::time_point::max());
|
191
194
|
}
|
192
|
-
deadline_timer_.async_wait(std::bind(&http_session::check_deadline, this));
|
195
|
+
deadline_timer_.async_wait(std::bind(&http_session::check_deadline, this, std::placeholders::_1));
|
193
196
|
}
|
194
197
|
|
195
198
|
void do_read()
|
@@ -17,22 +17,25 @@
|
|
17
17
|
|
18
18
|
#pragma once
|
19
19
|
|
20
|
+
#include <cstdint>
|
21
|
+
#include <vector>
|
22
|
+
|
20
23
|
namespace couchbase::io
|
21
24
|
{
|
22
25
|
struct binary_header {
|
23
|
-
uint8_t magic;
|
24
|
-
uint8_t opcode;
|
25
|
-
uint16_t keylen;
|
26
|
-
uint8_t extlen;
|
27
|
-
uint8_t datatype;
|
28
|
-
uint16_t specific;
|
29
|
-
uint32_t bodylen;
|
30
|
-
uint32_t opaque;
|
31
|
-
uint64_t cas;
|
26
|
+
std::uint8_t magic;
|
27
|
+
std::uint8_t opcode;
|
28
|
+
std::uint16_t keylen;
|
29
|
+
std::uint8_t extlen;
|
30
|
+
std::uint8_t datatype;
|
31
|
+
std::uint16_t specific;
|
32
|
+
std::uint32_t bodylen;
|
33
|
+
std::uint32_t opaque;
|
34
|
+
std::uint64_t cas;
|
32
35
|
};
|
33
36
|
|
34
|
-
struct
|
37
|
+
struct mcbp_message {
|
35
38
|
binary_header header;
|
36
|
-
std::vector<uint8_t> body;
|
39
|
+
std::vector<std::uint8_t> body;
|
37
40
|
};
|
38
|
-
} // namespace couchbase::io
|
41
|
+
} // namespace couchbase::io
|
@@ -0,0 +1,99 @@
|
|
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 <snappy.h>
|
21
|
+
|
22
|
+
#include <gsl/gsl_assert>
|
23
|
+
#include <protocol/magic.hxx>
|
24
|
+
#include <protocol/datatype.hxx>
|
25
|
+
|
26
|
+
#include <spdlog/fmt/bin_to_hex.h>
|
27
|
+
|
28
|
+
namespace couchbase::io
|
29
|
+
{
|
30
|
+
struct mcbp_parser {
|
31
|
+
enum result { ok, need_data, failure };
|
32
|
+
|
33
|
+
template<typename Iterator>
|
34
|
+
void feed(Iterator begin, Iterator end)
|
35
|
+
{
|
36
|
+
buf.reserve(buf.size() + static_cast<size_t>(std::distance(begin, end)));
|
37
|
+
std::copy(begin, end, std::back_inserter(buf));
|
38
|
+
}
|
39
|
+
|
40
|
+
void reset()
|
41
|
+
{
|
42
|
+
buf.clear();
|
43
|
+
}
|
44
|
+
|
45
|
+
result next(mcbp_message& msg)
|
46
|
+
{
|
47
|
+
static const size_t header_size = 24;
|
48
|
+
if (buf.size() < header_size) {
|
49
|
+
return need_data;
|
50
|
+
}
|
51
|
+
std::memcpy(&msg.header, buf.data(), header_size);
|
52
|
+
uint32_t body_size = ntohl(msg.header.bodylen);
|
53
|
+
if (body_size > 0 && buf.size() - header_size < body_size) {
|
54
|
+
return need_data;
|
55
|
+
}
|
56
|
+
msg.body.clear();
|
57
|
+
msg.body.reserve(body_size);
|
58
|
+
uint32_t key_size = ntohs(msg.header.keylen);
|
59
|
+
uint32_t prefix_size = uint32_t(msg.header.extlen) + key_size;
|
60
|
+
if (msg.header.magic == static_cast<uint8_t>(protocol::magic::alt_client_response)) {
|
61
|
+
uint8_t framing_extras_size = msg.header.keylen & 0xfU;
|
62
|
+
key_size = (msg.header.keylen & 0xf0U) >> 8U;
|
63
|
+
prefix_size = uint32_t(framing_extras_size) + uint32_t(msg.header.extlen) + key_size;
|
64
|
+
}
|
65
|
+
std::copy(buf.begin() + header_size, buf.begin() + header_size + prefix_size, std::back_inserter(msg.body));
|
66
|
+
|
67
|
+
bool is_compressed = (msg.header.datatype & static_cast<uint8_t>(protocol::datatype::snappy)) != 0;
|
68
|
+
bool use_raw_value = true;
|
69
|
+
if (is_compressed) {
|
70
|
+
std::string uncompressed;
|
71
|
+
size_t offset = header_size + prefix_size;
|
72
|
+
bool success = snappy::Uncompress(reinterpret_cast<const char*>(buf.data() + offset), body_size - prefix_size, &uncompressed);
|
73
|
+
if (success) {
|
74
|
+
std::copy(uncompressed.begin(), uncompressed.end(), std::back_inserter(msg.body));
|
75
|
+
use_raw_value = false;
|
76
|
+
}
|
77
|
+
}
|
78
|
+
if (use_raw_value) {
|
79
|
+
std::copy(buf.begin() + header_size + prefix_size, buf.begin() + header_size + body_size, std::back_inserter(msg.body));
|
80
|
+
}
|
81
|
+
buf.erase(buf.begin(), buf.begin() + header_size + body_size);
|
82
|
+
if (!protocol::is_valid_magic(buf[0])) {
|
83
|
+
spdlog::warn("parsed frame for magic={:x}, opcode={:x}, opaque={}, body_len={}. Invalid magic of the next frame: {:x}, {} "
|
84
|
+
"bytes to parse{}",
|
85
|
+
msg.header.magic,
|
86
|
+
msg.header.opcode,
|
87
|
+
msg.header.opaque,
|
88
|
+
body_size,
|
89
|
+
buf[0],
|
90
|
+
buf.size(),
|
91
|
+
spdlog::to_hex(buf));
|
92
|
+
reset();
|
93
|
+
}
|
94
|
+
return ok;
|
95
|
+
}
|
96
|
+
|
97
|
+
std::vector<std::uint8_t> buf;
|
98
|
+
};
|
99
|
+
} // namespace couchbase::io
|
@@ -25,12 +25,13 @@
|
|
25
25
|
|
26
26
|
#include <platform/uuid.h>
|
27
27
|
|
28
|
-
#include <io/
|
29
|
-
#include <io/
|
28
|
+
#include <io/mcbp_message.hxx>
|
29
|
+
#include <io/mcbp_parser.hxx>
|
30
30
|
|
31
31
|
#include <protocol/hello_feature.hxx>
|
32
32
|
#include <protocol/client_request.hxx>
|
33
33
|
#include <protocol/client_response.hxx>
|
34
|
+
#include <protocol/server_request.hxx>
|
34
35
|
#include <protocol/cmd_hello.hxx>
|
35
36
|
#include <protocol/cmd_sasl_list_mechs.hxx>
|
36
37
|
#include <protocol/cmd_sasl_auth.hxx>
|
@@ -40,6 +41,7 @@
|
|
40
41
|
#include <protocol/cmd_get_error_map.hxx>
|
41
42
|
#include <protocol/cmd_get_collections_manifest.hxx>
|
42
43
|
#include <protocol/cmd_get.hxx>
|
44
|
+
#include <protocol/cmd_cluster_map_change_notification.hxx>
|
43
45
|
|
44
46
|
#include <cbsasl/client.h>
|
45
47
|
|
@@ -51,12 +53,12 @@
|
|
51
53
|
namespace couchbase::io
|
52
54
|
{
|
53
55
|
|
54
|
-
class
|
56
|
+
class mcbp_session : public std::enable_shared_from_this<mcbp_session>
|
55
57
|
{
|
56
58
|
class message_handler
|
57
59
|
{
|
58
60
|
public:
|
59
|
-
virtual void handle(
|
61
|
+
virtual void handle(mcbp_message&& msg) = 0;
|
60
62
|
|
61
63
|
virtual ~message_handler() = default;
|
62
64
|
|
@@ -68,14 +70,23 @@ class key_value_session : public std::enable_shared_from_this
|
|
68
70
|
class bootstrap_handler : public message_handler
|
69
71
|
{
|
70
72
|
private:
|
71
|
-
std::shared_ptr<
|
73
|
+
std::shared_ptr<mcbp_session> session_;
|
72
74
|
sasl::ClientContext sasl_;
|
75
|
+
std::atomic_bool stopped_{ false };
|
73
76
|
|
74
77
|
public:
|
75
|
-
bootstrap_handler(
|
76
|
-
~bootstrap_handler() = default;
|
78
|
+
~bootstrap_handler() override = default;
|
77
79
|
|
78
|
-
|
80
|
+
void stop() override
|
81
|
+
{
|
82
|
+
if (stopped_) {
|
83
|
+
return;
|
84
|
+
}
|
85
|
+
stopped_ = true;
|
86
|
+
session_.reset();
|
87
|
+
}
|
88
|
+
|
89
|
+
explicit bootstrap_handler(std::shared_ptr<mcbp_session> session)
|
79
90
|
: session_(session)
|
80
91
|
, sasl_([this]() -> std::string { return session_->username_; },
|
81
92
|
[this]() -> std::string { return session_->password_; },
|
@@ -116,7 +127,6 @@ class key_value_session : public std::enable_shared_from_this
|
|
116
127
|
|
117
128
|
void auth_success()
|
118
129
|
{
|
119
|
-
spdlog::debug("{} authentication successful", sasl_.get_name());
|
120
130
|
session_->authenticated_ = true;
|
121
131
|
if (session_->supports_feature(protocol::hello_feature::xerror)) {
|
122
132
|
protocol::client_request<protocol::get_error_map_request_body> errmap_req;
|
@@ -139,8 +149,11 @@ class key_value_session : public std::enable_shared_from_this
|
|
139
149
|
session_->flush();
|
140
150
|
}
|
141
151
|
|
142
|
-
void handle(
|
152
|
+
void handle(mcbp_message&& msg) override
|
143
153
|
{
|
154
|
+
if (stopped_ || !session_) {
|
155
|
+
return;
|
156
|
+
}
|
144
157
|
Expects(protocol::is_valid_client_opcode(msg.header.opcode));
|
145
158
|
auto opcode = static_cast<protocol::client_opcode>(msg.header.opcode);
|
146
159
|
switch (opcode) {
|
@@ -183,7 +196,7 @@ class key_value_session : public std::enable_shared_from_this
|
|
183
196
|
return complete(std::make_error_code(error::common_errc::authentication_failure));
|
184
197
|
}
|
185
198
|
} else {
|
186
|
-
spdlog::warn("unexpected message status during bootstrap: {}", resp.error_message());
|
199
|
+
spdlog::warn("unexpected message status during bootstrap: {} (opcode={})", resp.error_message(), opcode);
|
187
200
|
return complete(std::make_error_code(error::common_errc::authentication_failure));
|
188
201
|
}
|
189
202
|
} break;
|
@@ -199,7 +212,7 @@ class key_value_session : public std::enable_shared_from_this
|
|
199
212
|
if (resp.status() == protocol::status::success) {
|
200
213
|
session_->errmap_.emplace(resp.body().errmap());
|
201
214
|
} else {
|
202
|
-
spdlog::warn("unexpected message status during bootstrap: {}", resp.error_message());
|
215
|
+
spdlog::warn("unexpected message status during bootstrap: {} (opcode={})", resp.error_message(), opcode);
|
203
216
|
return complete(std::make_error_code(error::network_errc::protocol_error));
|
204
217
|
}
|
205
218
|
} break;
|
@@ -214,7 +227,7 @@ class key_value_session : public std::enable_shared_from_this
|
|
214
227
|
session_->bucket_name_.value_or(""),
|
215
228
|
resp.error_message());
|
216
229
|
} else {
|
217
|
-
spdlog::warn("unexpected message status during bootstrap: {}", resp.error_message());
|
230
|
+
spdlog::warn("unexpected message status during bootstrap: {} (opcode={})", resp.error_message(), opcode);
|
218
231
|
return complete(std::make_error_code(error::network_errc::protocol_error));
|
219
232
|
}
|
220
233
|
} break;
|
@@ -237,15 +250,21 @@ class key_value_session : public std::enable_shared_from_this
|
|
237
250
|
protocol::client_response<protocol::get_cluster_config_response_body> resp(msg);
|
238
251
|
if (resp.status() == protocol::status::success) {
|
239
252
|
session_->update_configuration(resp.body().config());
|
240
|
-
|
253
|
+
complete({});
|
254
|
+
} else if (resp.status() == protocol::status::no_bucket && !session_->bucket_name_) {
|
255
|
+
// bucket-less session, but the server wants bucket
|
256
|
+
session_->supports_gcccp_ = false;
|
257
|
+
spdlog::warn("this server does not support GCCCP, open bucket before making any cluster-level command");
|
258
|
+
session_->update_configuration(
|
259
|
+
make_blank_configuration(session_->endpoint_.address().to_string(), session_->endpoint_.port(), 0));
|
241
260
|
complete({});
|
242
261
|
} else {
|
243
|
-
spdlog::warn("unexpected message status during bootstrap: {}", resp.error_message());
|
262
|
+
spdlog::warn("unexpected message status during bootstrap: {} (opcode={})", resp.error_message(), opcode);
|
244
263
|
return complete(std::make_error_code(error::network_errc::protocol_error));
|
245
264
|
}
|
246
265
|
} break;
|
247
266
|
default:
|
248
|
-
spdlog::
|
267
|
+
spdlog::warn("unexpected message during bootstrap: {}", opcode);
|
249
268
|
return complete(std::make_error_code(error::network_errc::protocol_error));
|
250
269
|
}
|
251
270
|
}
|
@@ -254,75 +273,124 @@ class key_value_session : public std::enable_shared_from_this
|
|
254
273
|
class normal_handler : public message_handler
|
255
274
|
{
|
256
275
|
private:
|
257
|
-
std::shared_ptr<
|
276
|
+
std::shared_ptr<mcbp_session> session_;
|
258
277
|
asio::steady_timer heartbeat_timer_;
|
278
|
+
std::atomic_bool stopped_{ false };
|
259
279
|
|
260
280
|
public:
|
261
|
-
normal_handler(
|
262
|
-
~normal_handler() = default;
|
281
|
+
~normal_handler() override = default;
|
263
282
|
|
264
|
-
explicit normal_handler(std::shared_ptr<
|
283
|
+
explicit normal_handler(std::shared_ptr<mcbp_session> session)
|
265
284
|
: session_(session)
|
266
285
|
, heartbeat_timer_(session_->ctx_)
|
267
286
|
{
|
268
|
-
|
287
|
+
if (session_->supports_gcccp_) {
|
288
|
+
fetch_config({});
|
289
|
+
}
|
269
290
|
}
|
270
291
|
|
271
292
|
void stop() override
|
272
293
|
{
|
294
|
+
if (stopped_) {
|
295
|
+
return;
|
296
|
+
}
|
297
|
+
stopped_ = true;
|
273
298
|
heartbeat_timer_.cancel();
|
299
|
+
session_.reset();
|
274
300
|
}
|
275
301
|
|
276
|
-
void handle(
|
302
|
+
void handle(mcbp_message&& msg) override
|
277
303
|
{
|
278
|
-
if (session_
|
304
|
+
if (stopped_ || !session_) {
|
279
305
|
return;
|
280
306
|
}
|
281
|
-
Expects(protocol::
|
282
|
-
switch (auto
|
283
|
-
case protocol::
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
307
|
+
Expects(protocol::is_valid_magic(msg.header.magic));
|
308
|
+
switch (auto magic = static_cast<protocol::magic>(msg.header.magic)) {
|
309
|
+
case protocol::magic::client_response:
|
310
|
+
case protocol::magic::alt_client_response:
|
311
|
+
Expects(protocol::is_valid_client_opcode(msg.header.opcode));
|
312
|
+
switch (auto opcode = static_cast<protocol::client_opcode>(msg.header.opcode)) {
|
313
|
+
case protocol::client_opcode::get_cluster_config: {
|
314
|
+
protocol::client_response<protocol::get_cluster_config_response_body> resp(msg);
|
315
|
+
if (resp.status() == protocol::status::success) {
|
316
|
+
if (session_) {
|
317
|
+
session_->update_configuration(resp.body().config());
|
318
|
+
}
|
319
|
+
} else {
|
320
|
+
spdlog::warn("unexpected message status: {}", resp.error_message());
|
321
|
+
}
|
322
|
+
} break;
|
323
|
+
case protocol::client_opcode::get:
|
324
|
+
case protocol::client_opcode::get_and_lock:
|
325
|
+
case protocol::client_opcode::get_and_touch:
|
326
|
+
case protocol::client_opcode::touch:
|
327
|
+
case protocol::client_opcode::insert:
|
328
|
+
case protocol::client_opcode::replace:
|
329
|
+
case protocol::client_opcode::upsert:
|
330
|
+
case protocol::client_opcode::remove:
|
331
|
+
case protocol::client_opcode::observe:
|
332
|
+
case protocol::client_opcode::unlock:
|
333
|
+
case protocol::client_opcode::increment:
|
334
|
+
case protocol::client_opcode::decrement:
|
335
|
+
case protocol::client_opcode::subdoc_multi_lookup:
|
336
|
+
case protocol::client_opcode::subdoc_multi_mutation: {
|
337
|
+
std::uint32_t opaque = msg.header.opaque;
|
338
|
+
std::uint16_t status = ntohs(msg.header.specific);
|
339
|
+
auto handler = session_->command_handlers_.find(opaque);
|
340
|
+
if (handler != session_->command_handlers_.end()) {
|
341
|
+
handler->second(session_->map_status_code(opcode, status), std::move(msg));
|
342
|
+
session_->command_handlers_.erase(handler);
|
343
|
+
} else {
|
344
|
+
spdlog::debug("unexpected orphan response opcode={}, opaque={}", msg.header.opcode, msg.header.opaque);
|
345
|
+
}
|
346
|
+
} break;
|
347
|
+
default:
|
348
|
+
spdlog::warn("unexpected client response: {}", opcode);
|
289
349
|
}
|
290
|
-
|
291
|
-
case protocol::
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
350
|
+
break;
|
351
|
+
case protocol::magic::server_request:
|
352
|
+
Expects(protocol::is_valid_server_request_opcode(msg.header.opcode));
|
353
|
+
switch (auto opcode = static_cast<protocol::server_opcode>(msg.header.opcode)) {
|
354
|
+
case protocol::server_opcode::cluster_map_change_notification: {
|
355
|
+
protocol::server_request<protocol::cluster_map_change_notification_request_body> req(msg);
|
356
|
+
if (session_) {
|
357
|
+
if ((!req.body().config().bucket.has_value() && req.body().bucket().empty()) ||
|
358
|
+
(session_->bucket_name_.has_value() && !req.body().bucket().empty() &&
|
359
|
+
session_->bucket_name_.value() == req.body().bucket())) {
|
360
|
+
session_->update_configuration(req.body().config());
|
361
|
+
}
|
362
|
+
}
|
363
|
+
} break;
|
364
|
+
default:
|
365
|
+
spdlog::warn("unexpected server request: {}", opcode);
|
304
366
|
}
|
305
|
-
|
306
|
-
|
307
|
-
|
367
|
+
break;
|
368
|
+
case protocol::magic::client_request:
|
369
|
+
case protocol::magic::alt_client_request:
|
370
|
+
case protocol::magic::server_response:
|
371
|
+
spdlog::warn("unexpected magic: {}, opcode={}, opaque={}", magic, msg.header.opcode, msg.header.opaque);
|
372
|
+
break;
|
308
373
|
}
|
309
374
|
}
|
310
375
|
|
311
|
-
void fetch_config()
|
376
|
+
void fetch_config(std::error_code ec)
|
312
377
|
{
|
313
|
-
if (
|
378
|
+
if (ec == asio::error::operation_aborted) {
|
379
|
+
return;
|
380
|
+
}
|
381
|
+
if (stopped_ || !session_) {
|
314
382
|
return;
|
315
383
|
}
|
316
384
|
protocol::client_request<protocol::get_cluster_config_request_body> req;
|
317
385
|
req.opaque(session_->next_opaque());
|
318
386
|
session_->write_and_flush(req.data());
|
319
387
|
heartbeat_timer_.expires_after(std::chrono::milliseconds(2500));
|
320
|
-
heartbeat_timer_.async_wait(std::bind(&normal_handler::fetch_config, this));
|
388
|
+
heartbeat_timer_.async_wait(std::bind(&normal_handler::fetch_config, this, std::placeholders::_1));
|
321
389
|
}
|
322
390
|
};
|
323
391
|
|
324
392
|
public:
|
325
|
-
|
393
|
+
mcbp_session(uuid::uuid_t client_id, asio::io_context& ctx, std::optional<std::string> bucket_name = {})
|
326
394
|
: client_id_(client_id)
|
327
395
|
, id_(uuid::random())
|
328
396
|
, ctx_(ctx)
|
@@ -334,7 +402,7 @@ class key_value_session : public std::enable_shared_from_this
|
|
334
402
|
{
|
335
403
|
}
|
336
404
|
|
337
|
-
~
|
405
|
+
~mcbp_session()
|
338
406
|
{
|
339
407
|
stop();
|
340
408
|
}
|
@@ -343,13 +411,13 @@ class key_value_session : public std::enable_shared_from_this
|
|
343
411
|
const std::string& service,
|
344
412
|
const std::string& username,
|
345
413
|
const std::string& password,
|
346
|
-
std::function<void(std::error_code)>&& handler)
|
414
|
+
std::function<void(std::error_code, configuration)>&& handler)
|
347
415
|
{
|
348
416
|
username_ = username;
|
349
417
|
password_ = password;
|
350
418
|
bootstrap_handler_ = std::move(handler);
|
351
419
|
resolver_.async_resolve(
|
352
|
-
hostname, service, std::bind(&
|
420
|
+
hostname, service, std::bind(&mcbp_session::on_resolve, this, std::placeholders::_1, std::placeholders::_2));
|
353
421
|
}
|
354
422
|
|
355
423
|
[[nodiscard]] std::string id()
|
@@ -359,19 +427,18 @@ class key_value_session : public std::enable_shared_from_this
|
|
359
427
|
|
360
428
|
void stop()
|
361
429
|
{
|
362
|
-
stopped_
|
363
|
-
|
364
|
-
handler_->stop();
|
430
|
+
if (stopped_) {
|
431
|
+
return;
|
365
432
|
}
|
433
|
+
stopped_ = true;
|
434
|
+
deadline_timer_.cancel();
|
435
|
+
resolver_.cancel();
|
366
436
|
if (socket_.is_open()) {
|
367
437
|
socket_.close();
|
368
438
|
}
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
bool is_stopped()
|
373
|
-
{
|
374
|
-
return stopped_;
|
439
|
+
if (handler_) {
|
440
|
+
handler_->stop();
|
441
|
+
}
|
375
442
|
}
|
376
443
|
|
377
444
|
void write(const std::vector<uint8_t>& buf)
|
@@ -401,13 +468,22 @@ class key_value_session : public std::enable_shared_from_this
|
|
401
468
|
|
402
469
|
void write_and_subscribe(uint32_t opaque,
|
403
470
|
std::vector<std::uint8_t>& data,
|
404
|
-
std::function<void(std::error_code, io::
|
471
|
+
std::function<void(std::error_code, io::mcbp_message&&)> handler)
|
405
472
|
{
|
406
473
|
if (stopped_) {
|
407
474
|
return;
|
408
475
|
}
|
409
476
|
command_handlers_.emplace(opaque, std::move(handler));
|
410
|
-
|
477
|
+
if (bootstrapped_ && socket_.is_open()) {
|
478
|
+
write_and_flush(data);
|
479
|
+
} else {
|
480
|
+
pending_buffer_.push_back(data);
|
481
|
+
}
|
482
|
+
}
|
483
|
+
|
484
|
+
[[nodiscard]] std::optional<collections_manifest> manifest()
|
485
|
+
{
|
486
|
+
return manifest_;
|
411
487
|
}
|
412
488
|
|
413
489
|
bool supports_feature(protocol::hello_feature feature)
|
@@ -415,6 +491,11 @@ class key_value_session : public std::enable_shared_from_this
|
|
415
491
|
return std::find(supported_features_.begin(), supported_features_.end(), feature) != supported_features_.end();
|
416
492
|
}
|
417
493
|
|
494
|
+
bool supports_gcccp()
|
495
|
+
{
|
496
|
+
return supports_gcccp_;
|
497
|
+
}
|
498
|
+
|
418
499
|
[[nodiscard]] bool has_config() const
|
419
500
|
{
|
420
501
|
return config_.has_value();
|
@@ -570,23 +651,15 @@ class key_value_session : public std::enable_shared_from_this
|
|
570
651
|
break;
|
571
652
|
}
|
572
653
|
// FIXME: use error map here
|
654
|
+
spdlog::warn("unknown status code: {} (opcode={})", status, opcode);
|
573
655
|
return std::make_error_code(error::network_errc::protocol_error);
|
574
656
|
}
|
575
657
|
|
576
|
-
template<typename Handler>
|
577
|
-
void subscribe_to_configuration_updates(Handler&& handler)
|
578
|
-
{
|
579
|
-
configuration_listeners_.emplace_back(std::forward<Handler>(handler));
|
580
|
-
}
|
581
|
-
|
582
658
|
void update_configuration(configuration&& config)
|
583
659
|
{
|
584
660
|
if (!config_ || config.rev > config_->rev) {
|
585
661
|
config_.emplace(config);
|
586
662
|
spdlog::trace("received new configuration: {}", config_.value());
|
587
|
-
for (auto& listener : configuration_listeners_) {
|
588
|
-
listener(config_.value());
|
589
|
-
}
|
590
663
|
}
|
591
664
|
}
|
592
665
|
|
@@ -594,32 +667,45 @@ class key_value_session : public std::enable_shared_from_this
|
|
594
667
|
void invoke_bootstrap_handler(std::error_code ec)
|
595
668
|
{
|
596
669
|
if (!bootstrapped_ && bootstrap_handler_) {
|
597
|
-
bootstrap_handler_(ec);
|
670
|
+
bootstrap_handler_(ec, config_.value_or(configuration{}));
|
598
671
|
bootstrap_handler_ = nullptr;
|
599
672
|
}
|
600
673
|
bootstrapped_ = true;
|
601
674
|
if (ec) {
|
602
675
|
stop();
|
603
676
|
}
|
677
|
+
if (!pending_buffer_.empty()) {
|
678
|
+
for (const auto& buf : pending_buffer_) {
|
679
|
+
write(buf);
|
680
|
+
}
|
681
|
+
pending_buffer_.clear();
|
682
|
+
flush();
|
683
|
+
}
|
604
684
|
}
|
605
685
|
|
606
686
|
void on_resolve(std::error_code ec, const asio::ip::tcp::resolver::results_type& endpoints)
|
607
687
|
{
|
688
|
+
if (stopped_) {
|
689
|
+
return;
|
690
|
+
}
|
608
691
|
if (ec) {
|
609
692
|
spdlog::error("error on resolve: {}", ec.message());
|
610
693
|
return invoke_bootstrap_handler(std::make_error_code(error::network_errc::resolve_failure));
|
611
694
|
}
|
612
695
|
endpoints_ = endpoints;
|
613
696
|
do_connect(endpoints_.begin());
|
614
|
-
deadline_timer_.async_wait(std::bind(&
|
697
|
+
deadline_timer_.async_wait(std::bind(&mcbp_session::check_deadline, this, std::placeholders::_1));
|
615
698
|
}
|
616
699
|
|
617
700
|
void do_connect(asio::ip::tcp::resolver::results_type::iterator it)
|
618
701
|
{
|
702
|
+
if (stopped_) {
|
703
|
+
return;
|
704
|
+
}
|
619
705
|
if (it != endpoints_.end()) {
|
620
706
|
spdlog::trace("connecting to {}:{}", it->endpoint().address().to_string(), it->endpoint().port());
|
621
707
|
deadline_timer_.expires_after(std::chrono::seconds(10));
|
622
|
-
socket_.async_connect(it->endpoint(), std::bind(&
|
708
|
+
socket_.async_connect(it->endpoint(), std::bind(&mcbp_session::on_connect, this, std::placeholders::_1, it));
|
623
709
|
} else {
|
624
710
|
spdlog::error("no more endpoints left to connect");
|
625
711
|
invoke_bootstrap_handler(std::make_error_code(error::network_errc::no_endpoints_left));
|
@@ -635,6 +721,8 @@ class key_value_session : public std::enable_shared_from_this
|
|
635
721
|
if (!socket_.is_open() || ec) {
|
636
722
|
do_connect(++it);
|
637
723
|
} else {
|
724
|
+
socket_.set_option(asio::ip::tcp::no_delay{ true });
|
725
|
+
socket_.set_option(asio::socket_base::keep_alive{ true });
|
638
726
|
endpoint_ = it->endpoint();
|
639
727
|
spdlog::trace("connected to {}:{}", endpoint_.address().to_string(), it->endpoint().port());
|
640
728
|
handler_ = std::make_unique<bootstrap_handler>(shared_from_this());
|
@@ -643,8 +731,11 @@ class key_value_session : public std::enable_shared_from_this
|
|
643
731
|
}
|
644
732
|
}
|
645
733
|
|
646
|
-
void check_deadline()
|
734
|
+
void check_deadline(std::error_code ec)
|
647
735
|
{
|
736
|
+
if (ec == asio::error::operation_aborted) {
|
737
|
+
return;
|
738
|
+
}
|
648
739
|
if (stopped_) {
|
649
740
|
return;
|
650
741
|
}
|
@@ -652,7 +743,7 @@ class key_value_session : public std::enable_shared_from_this
|
|
652
743
|
socket_.close();
|
653
744
|
deadline_timer_.expires_at(asio::steady_timer::time_point::max());
|
654
745
|
}
|
655
|
-
deadline_timer_.async_wait(std::bind(&
|
746
|
+
deadline_timer_.async_wait(std::bind(&mcbp_session::check_deadline, this, std::placeholders::_1));
|
656
747
|
}
|
657
748
|
|
658
749
|
void do_read()
|
@@ -660,27 +751,35 @@ class key_value_session : public std::enable_shared_from_this
|
|
660
751
|
if (stopped_) {
|
661
752
|
return;
|
662
753
|
}
|
754
|
+
if (reading_) {
|
755
|
+
return;
|
756
|
+
}
|
757
|
+
reading_ = true;
|
663
758
|
socket_.async_read_some(asio::buffer(input_buffer_),
|
664
759
|
[self = shared_from_this()](std::error_code ec, std::size_t bytes_transferred) {
|
665
|
-
if (self->stopped_) {
|
760
|
+
if (ec == asio::error::operation_aborted || self->stopped_) {
|
666
761
|
return;
|
667
762
|
}
|
668
|
-
if (ec
|
669
|
-
spdlog::error("IO error while reading from the socket: {}",
|
763
|
+
if (ec) {
|
764
|
+
spdlog::error("[{}] [{}] IO error while reading from the socket: {}",
|
765
|
+
uuid::to_string(self->id_),
|
766
|
+
self->endpoint_.address().to_string(),
|
767
|
+
ec.message());
|
670
768
|
return self->stop();
|
671
769
|
}
|
672
770
|
self->parser_.feed(self->input_buffer_.data(), self->input_buffer_.data() + ssize_t(bytes_transferred));
|
673
771
|
|
674
772
|
for (;;) {
|
675
|
-
|
773
|
+
mcbp_message msg{};
|
676
774
|
switch (self->parser_.next(msg)) {
|
677
|
-
case
|
775
|
+
case mcbp_parser::ok:
|
678
776
|
self->handler_->handle(std::move(msg));
|
679
777
|
break;
|
680
|
-
case
|
778
|
+
case mcbp_parser::need_data:
|
779
|
+
self->reading_ = false;
|
681
780
|
return self->do_read();
|
682
|
-
case
|
683
|
-
ec = std::make_error_code(
|
781
|
+
case mcbp_parser::failure:
|
782
|
+
ec = std::make_error_code(error::common_errc::parsing_failure);
|
684
783
|
return self->stop();
|
685
784
|
}
|
686
785
|
}
|
@@ -706,7 +805,10 @@ class key_value_session : public std::enable_shared_from_this
|
|
706
805
|
return;
|
707
806
|
}
|
708
807
|
if (ec) {
|
709
|
-
spdlog::error("IO error while writing to the socket: {}",
|
808
|
+
spdlog::error("[{}] [{}] IO error while writing to the socket: {}",
|
809
|
+
uuid::to_string(self->id_),
|
810
|
+
self->endpoint_.address().to_string(),
|
811
|
+
ec.message());
|
710
812
|
return self->stop();
|
711
813
|
}
|
712
814
|
self->writing_buffer_.clear();
|
@@ -725,24 +827,25 @@ class key_value_session : public std::enable_shared_from_this
|
|
725
827
|
asio::ip::tcp::socket socket_;
|
726
828
|
asio::steady_timer deadline_timer_;
|
727
829
|
std::optional<std::string> bucket_name_;
|
728
|
-
|
830
|
+
mcbp_parser parser_;
|
729
831
|
std::unique_ptr<message_handler> handler_;
|
730
|
-
std::function<void(std::error_code)> bootstrap_handler_;
|
731
|
-
std::map<uint32_t, std::function<void(std::error_code, io::
|
832
|
+
std::function<void(std::error_code, configuration)> bootstrap_handler_;
|
833
|
+
std::map<uint32_t, std::function<void(std::error_code, io::mcbp_message&&)>> command_handlers_{};
|
732
834
|
|
733
835
|
bool bootstrapped_{ false };
|
734
|
-
|
836
|
+
std::atomic_bool stopped_{ false };
|
735
837
|
bool authenticated_{ false };
|
736
838
|
bool bucket_selected_{ false };
|
839
|
+
bool supports_gcccp_{ true };
|
737
840
|
|
738
841
|
std::atomic<std::uint32_t> opaque_{ 0 };
|
739
842
|
|
740
843
|
std::string username_;
|
741
844
|
std::string password_;
|
742
845
|
|
743
|
-
std::list<std::function<void(const configuration&)>> configuration_listeners_;
|
744
846
|
std::array<std::uint8_t, 16384> input_buffer_{};
|
745
847
|
std::vector<std::vector<std::uint8_t>> output_buffer_{};
|
848
|
+
std::vector<std::vector<std::uint8_t>> pending_buffer_{};
|
746
849
|
std::vector<std::vector<std::uint8_t>> writing_buffer_{};
|
747
850
|
asio::ip::tcp::endpoint endpoint_{}; // connected endpoint
|
748
851
|
asio::ip::tcp::resolver::results_type endpoints_;
|
@@ -750,5 +853,7 @@ class key_value_session : public std::enable_shared_from_this
|
|
750
853
|
std::optional<configuration> config_;
|
751
854
|
std::optional<error_map> errmap_;
|
752
855
|
std::optional<collections_manifest> manifest_;
|
856
|
+
|
857
|
+
std::atomic_bool reading_{ false };
|
753
858
|
};
|
754
|
-
} // namespace couchbase::io
|
859
|
+
} // namespace couchbase::io
|