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