couchbase 4.2.6-dev.1 → 4.2.7
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.
- package/CONTRIBUTING.md +97 -0
- package/deps/couchbase-cxx-client/.github/workflows/windows.yml +0 -3
- package/deps/couchbase-cxx-client/CMakeLists.txt +4 -0
- package/deps/couchbase-cxx-client/bin/build-tests.rb +1 -1
- package/deps/couchbase-cxx-client/core/impl/lookup_in.cxx +1 -0
- package/deps/couchbase-cxx-client/core/impl/lookup_in_all_replicas.cxx +176 -0
- package/deps/couchbase-cxx-client/core/impl/lookup_in_all_replicas.hxx +80 -0
- package/deps/couchbase-cxx-client/core/impl/lookup_in_any_replica.cxx +167 -0
- package/deps/couchbase-cxx-client/core/impl/lookup_in_any_replica.hxx +75 -0
- package/deps/couchbase-cxx-client/core/impl/lookup_in_replica.cxx +97 -0
- package/deps/couchbase-cxx-client/core/impl/lookup_in_replica.hxx +67 -0
- package/deps/couchbase-cxx-client/core/io/dns_client.cxx +48 -10
- package/deps/couchbase-cxx-client/core/io/http_session.hxx +24 -1
- package/deps/couchbase-cxx-client/core/io/mcbp_session.cxx +22 -1
- package/deps/couchbase-cxx-client/core/logger/custom_rotating_file_sink.cxx +1 -1
- package/deps/couchbase-cxx-client/core/logger/logger.cxx +80 -20
- package/deps/couchbase-cxx-client/core/logger/logger.hxx +31 -0
- package/deps/couchbase-cxx-client/core/meta/features.hxx +19 -0
- package/deps/couchbase-cxx-client/core/operations/document_lookup_in_all_replicas.hxx +192 -0
- package/deps/couchbase-cxx-client/core/operations/document_lookup_in_any_replica.hxx +188 -0
- package/deps/couchbase-cxx-client/core/operations.hxx +2 -0
- package/deps/couchbase-cxx-client/core/protocol/cmd_hello.hxx +1 -0
- package/deps/couchbase-cxx-client/core/protocol/cmd_lookup_in_replica.cxx +107 -0
- package/deps/couchbase-cxx-client/core/protocol/cmd_lookup_in_replica.hxx +137 -0
- package/deps/couchbase-cxx-client/core/protocol/hello_feature.hxx +6 -0
- package/deps/couchbase-cxx-client/core/protocol/hello_feature_fmt.hxx +3 -0
- package/deps/couchbase-cxx-client/core/range_scan_orchestrator.cxx +22 -1
- package/deps/couchbase-cxx-client/core/topology/capabilities.hxx +2 -0
- package/deps/couchbase-cxx-client/core/topology/capabilities_fmt.hxx +6 -0
- package/deps/couchbase-cxx-client/core/topology/configuration.hxx +10 -0
- package/deps/couchbase-cxx-client/core/topology/configuration_json.hxx +4 -1
- package/deps/couchbase-cxx-client/couchbase/collection.hxx +111 -0
- package/deps/couchbase-cxx-client/couchbase/get_and_lock_options.hxx +2 -2
- package/deps/couchbase-cxx-client/couchbase/get_and_touch_options.hxx +2 -2
- package/deps/couchbase-cxx-client/couchbase/get_options.hxx +2 -2
- package/deps/couchbase-cxx-client/couchbase/insert_options.hxx +3 -3
- package/deps/couchbase-cxx-client/couchbase/lookup_in_all_replicas_options.hxx +109 -0
- package/deps/couchbase-cxx-client/couchbase/lookup_in_any_replica_options.hxx +101 -0
- package/deps/couchbase-cxx-client/couchbase/lookup_in_options.hxx +2 -2
- package/deps/couchbase-cxx-client/couchbase/lookup_in_replica_result.hxx +74 -0
- package/deps/couchbase-cxx-client/couchbase/lookup_in_result.hxx +26 -0
- package/deps/couchbase-cxx-client/couchbase/mutate_in_options.hxx +2 -2
- package/deps/couchbase-cxx-client/couchbase/remove_options.hxx +2 -2
- package/deps/couchbase-cxx-client/couchbase/replace_options.hxx +3 -3
- package/deps/couchbase-cxx-client/couchbase/touch_options.hxx +2 -2
- package/deps/couchbase-cxx-client/couchbase/unlock_options.hxx +2 -2
- package/deps/couchbase-cxx-client/couchbase/upsert_options.hxx +3 -3
- package/deps/couchbase-cxx-client/docs/cbc-analytics.md +3 -2
- package/deps/couchbase-cxx-client/docs/cbc-get.md +3 -2
- package/deps/couchbase-cxx-client/docs/cbc-pillowfight.md +3 -2
- package/deps/couchbase-cxx-client/docs/cbc-query.md +3 -2
- package/deps/couchbase-cxx-client/test/test_integration_subdoc.cxx +655 -0
- package/deps/couchbase-cxx-client/test/utils/logger.cxx +7 -0
- package/deps/couchbase-cxx-client/tools/utils.cxx +9 -2
- package/dist/binding.d.ts +47 -0
- package/dist/collection.d.ts +53 -1
- package/dist/collection.js +139 -1
- package/dist/couchbase.d.ts +15 -0
- package/dist/couchbase.js +22 -1
- package/dist/crudoptypes.d.ts +24 -0
- package/dist/crudoptypes.js +14 -1
- package/package.json +13 -13
- package/src/binding.cpp +28 -0
- package/src/connection.cpp +4 -0
- package/src/connection.hpp +2 -0
- package/src/connection_autogen.cpp +28 -0
- package/src/jstocbpp_autogen.hpp +262 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2020-Present 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
|
+
#include "lookup_in_replica.hxx"
|
|
19
|
+
#include "core/impl/subdoc/path_flags.hxx"
|
|
20
|
+
|
|
21
|
+
#include <couchbase/error_codes.hxx>
|
|
22
|
+
|
|
23
|
+
namespace couchbase::core::impl
|
|
24
|
+
{
|
|
25
|
+
std::error_code
|
|
26
|
+
lookup_in_replica_request::encode_to(lookup_in_replica_request::encoded_request_type& encoded, mcbp_context&& /* context */)
|
|
27
|
+
{
|
|
28
|
+
for (std::size_t i = 0; i < specs.size(); ++i) {
|
|
29
|
+
specs[i].original_index_ = i;
|
|
30
|
+
}
|
|
31
|
+
std::stable_sort(specs.begin(), specs.end(), [](const auto& lhs, const auto& rhs) {
|
|
32
|
+
/* move XATTRs to the beginning of the vector */
|
|
33
|
+
return core::impl::subdoc::has_xattr_path_flag(lhs.flags_) && !core::impl::subdoc::has_xattr_path_flag(rhs.flags_);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
encoded.opaque(opaque);
|
|
37
|
+
encoded.partition(partition);
|
|
38
|
+
encoded.body().id(id);
|
|
39
|
+
encoded.body().read_replica(true);
|
|
40
|
+
encoded.body().specs(specs);
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
lookup_in_replica_response
|
|
45
|
+
lookup_in_replica_request::make_response(key_value_error_context&& ctx, const encoded_response_type& encoded) const
|
|
46
|
+
{
|
|
47
|
+
|
|
48
|
+
bool deleted = false;
|
|
49
|
+
couchbase::cas cas{};
|
|
50
|
+
std::vector<lookup_in_replica_response::entry> fields{};
|
|
51
|
+
std::error_code ec = ctx.ec();
|
|
52
|
+
std::optional<std::size_t> first_error_index{};
|
|
53
|
+
std::optional<std::string> first_error_path{};
|
|
54
|
+
|
|
55
|
+
if (encoded.status() == key_value_status_code::subdoc_success_deleted ||
|
|
56
|
+
encoded.status() == key_value_status_code::subdoc_multi_path_failure_deleted) {
|
|
57
|
+
deleted = true;
|
|
58
|
+
}
|
|
59
|
+
if (!ctx.ec()) {
|
|
60
|
+
fields.resize(specs.size());
|
|
61
|
+
for (size_t i = 0; i < specs.size(); ++i) {
|
|
62
|
+
const auto& req_entry = specs[i];
|
|
63
|
+
fields[i].original_index = req_entry.original_index_;
|
|
64
|
+
fields[i].path = req_entry.path_;
|
|
65
|
+
fields[i].opcode = static_cast<protocol::subdoc_opcode>(req_entry.opcode_);
|
|
66
|
+
fields[i].status = key_value_status_code::success;
|
|
67
|
+
}
|
|
68
|
+
for (size_t i = 0; i < encoded.body().fields().size(); ++i) {
|
|
69
|
+
const auto& res_entry = encoded.body().fields()[i];
|
|
70
|
+
fields[i].status = res_entry.status;
|
|
71
|
+
fields[i].ec =
|
|
72
|
+
protocol::map_status_code(protocol::client_opcode::subdoc_multi_mutation, static_cast<std::uint16_t>(res_entry.status));
|
|
73
|
+
if (!fields[i].ec && !ctx.ec()) {
|
|
74
|
+
ec = fields[i].ec;
|
|
75
|
+
}
|
|
76
|
+
if (!first_error_index && !fields[i].ec) {
|
|
77
|
+
first_error_index = i;
|
|
78
|
+
first_error_path = fields[i].path;
|
|
79
|
+
}
|
|
80
|
+
fields[i].exists =
|
|
81
|
+
res_entry.status == key_value_status_code::success || res_entry.status == key_value_status_code::subdoc_success_deleted;
|
|
82
|
+
fields[i].value = utils::to_binary(res_entry.value);
|
|
83
|
+
}
|
|
84
|
+
if (!ec) {
|
|
85
|
+
cas = encoded.cas();
|
|
86
|
+
}
|
|
87
|
+
std::sort(fields.begin(), fields.end(), [](const auto& lhs, const auto& rhs) { return lhs.original_index < rhs.original_index; });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return lookup_in_replica_response{
|
|
91
|
+
make_subdocument_error_context(ctx, ec, first_error_path, first_error_index, deleted),
|
|
92
|
+
cas,
|
|
93
|
+
std::move(fields),
|
|
94
|
+
deleted,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
} // namespace couchbase::core::impl
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2020-Present 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 "core/error_context/key_value.hxx"
|
|
21
|
+
#include "core/impl/subdoc/command.hxx"
|
|
22
|
+
#include "core/io/mcbp_context.hxx"
|
|
23
|
+
#include "core/io/retry_context.hxx"
|
|
24
|
+
#include "core/protocol/client_request.hxx"
|
|
25
|
+
#include "core/protocol/cmd_lookup_in_replica.hxx"
|
|
26
|
+
#include "core/public_fwd.hxx"
|
|
27
|
+
#include "core/timeout_defaults.hxx"
|
|
28
|
+
|
|
29
|
+
#include <couchbase/lookup_in_result.hxx>
|
|
30
|
+
#include <couchbase/subdocument_error_context.hxx>
|
|
31
|
+
|
|
32
|
+
namespace couchbase::core::impl
|
|
33
|
+
{
|
|
34
|
+
struct lookup_in_replica_response {
|
|
35
|
+
struct entry {
|
|
36
|
+
std::string path;
|
|
37
|
+
couchbase::codec::binary value;
|
|
38
|
+
std::size_t original_index;
|
|
39
|
+
bool exists;
|
|
40
|
+
protocol::subdoc_opcode opcode;
|
|
41
|
+
key_value_status_code status;
|
|
42
|
+
std::error_code ec{};
|
|
43
|
+
};
|
|
44
|
+
subdocument_error_context ctx{};
|
|
45
|
+
couchbase::cas cas{};
|
|
46
|
+
std::vector<entry> fields{};
|
|
47
|
+
bool deleted{ false };
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
struct lookup_in_replica_request {
|
|
51
|
+
using response_type = lookup_in_replica_response;
|
|
52
|
+
using encoded_request_type = protocol::client_request<protocol::lookup_in_replica_request_body>;
|
|
53
|
+
using encoded_response_type = protocol::client_response<protocol::lookup_in_replica_response_body>;
|
|
54
|
+
|
|
55
|
+
document_id id;
|
|
56
|
+
std::vector<couchbase::core::impl::subdoc::command> specs{};
|
|
57
|
+
std::optional<std::chrono::milliseconds> timeout{};
|
|
58
|
+
std::shared_ptr<couchbase::tracing::request_span> parent_span{ nullptr };
|
|
59
|
+
std::uint16_t partition{};
|
|
60
|
+
std::uint32_t opaque{};
|
|
61
|
+
io::retry_context<false> retries{};
|
|
62
|
+
|
|
63
|
+
[[nodiscard]] std::error_code encode_to(encoded_request_type& encoded, mcbp_context&& context);
|
|
64
|
+
|
|
65
|
+
[[nodiscard]] lookup_in_replica_response make_response(key_value_error_context&& ctx, const encoded_response_type& encoded) const;
|
|
66
|
+
};
|
|
67
|
+
} // namespace couchbase::core::impl
|
|
@@ -72,16 +72,25 @@ class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
|
|
|
72
72
|
|
|
73
73
|
void execute(std::chrono::milliseconds total_timeout, std::chrono::milliseconds udp_timeout)
|
|
74
74
|
{
|
|
75
|
-
CB_LOG_TRACE("Query DNS-SRV (UDP) address=\"{}:{}\", udp_timeout={}, total_timeout={}
|
|
75
|
+
CB_LOG_TRACE("Query DNS-SRV (UDP) address=\"{}:{}\", udp_timeout={}, total_timeout={}",
|
|
76
76
|
address_.to_string(),
|
|
77
77
|
port_,
|
|
78
78
|
udp_timeout,
|
|
79
|
-
total_timeout
|
|
80
|
-
spdlog::to_hex(send_buf_));
|
|
79
|
+
total_timeout);
|
|
81
80
|
asio::ip::udp::endpoint endpoint(address_, port_);
|
|
82
81
|
udp_.open(endpoint.protocol());
|
|
82
|
+
CB_LOG_PROTOCOL("[DNS, UDP, OUT] host=\"{}\", port={}, buffer_size={}{:a}",
|
|
83
|
+
address_.to_string(),
|
|
84
|
+
port_,
|
|
85
|
+
send_buf_.size(),
|
|
86
|
+
spdlog::to_hex(send_buf_));
|
|
83
87
|
udp_.async_send_to(
|
|
84
|
-
asio::buffer(send_buf_), endpoint, [self = shared_from_this()](std::error_code ec1, std::size_t
|
|
88
|
+
asio::buffer(send_buf_), endpoint, [self = shared_from_this()](std::error_code ec1, std::size_t bytes_transferred1) mutable {
|
|
89
|
+
CB_LOG_PROTOCOL("[DNS, UDP, OUT] host=\"{}\", port={}, rc={}, bytes_sent={}",
|
|
90
|
+
self->address_.to_string(),
|
|
91
|
+
self->port_,
|
|
92
|
+
ec1 ? ec1.message() : "ok",
|
|
93
|
+
bytes_transferred1);
|
|
85
94
|
if (ec1) {
|
|
86
95
|
self->udp_deadline_.cancel();
|
|
87
96
|
CB_LOG_DEBUG("DNS UDP write operation has got error, retrying with TCP, address=\"{}:{}\", ec={}",
|
|
@@ -94,6 +103,13 @@ class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
|
|
|
94
103
|
self->recv_buf_.resize(512);
|
|
95
104
|
self->udp_.async_receive_from(
|
|
96
105
|
asio::buffer(self->recv_buf_), self->udp_sender_, [self](std::error_code ec2, std::size_t bytes_transferred) mutable {
|
|
106
|
+
CB_LOG_PROTOCOL("[DNS, UDP, IN] host=\"{}\", port={}, rc={}, bytes_received={}{:a}",
|
|
107
|
+
self->address_.to_string(),
|
|
108
|
+
self->port_,
|
|
109
|
+
ec2 ? ec2.message() : "ok",
|
|
110
|
+
bytes_transferred,
|
|
111
|
+
spdlog::to_hex(self->recv_buf_.data(), self->recv_buf_.data() + bytes_transferred));
|
|
112
|
+
|
|
97
113
|
self->udp_deadline_.cancel();
|
|
98
114
|
if (ec2) {
|
|
99
115
|
CB_LOG_DEBUG("DNS UDP read operation has got error, retrying with TCP, address=\"{}:{}\", ec={}",
|
|
@@ -168,10 +184,18 @@ class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
|
|
|
168
184
|
auto send_size = static_cast<std::uint16_t>(self->send_buf_.size());
|
|
169
185
|
self->send_buf_.insert(self->send_buf_.begin(), static_cast<std::uint8_t>(send_size & 0xffU));
|
|
170
186
|
self->send_buf_.insert(self->send_buf_.begin(), static_cast<std::uint8_t>(send_size >> 8U));
|
|
171
|
-
|
|
172
|
-
|
|
187
|
+
CB_LOG_PROTOCOL("[DNS, TCP, OUT] host=\"{}\", port={}, buffer_size={}{:a}",
|
|
188
|
+
self->address_.to_string(),
|
|
189
|
+
self->port_,
|
|
190
|
+
self->send_buf_.size(),
|
|
191
|
+
spdlog::to_hex(self->send_buf_));
|
|
173
192
|
asio::async_write(
|
|
174
|
-
self->tcp_, asio::buffer(self->send_buf_), [self](std::error_code ec2, std::size_t
|
|
193
|
+
self->tcp_, asio::buffer(self->send_buf_), [self](std::error_code ec2, std::size_t bytes_transferred2) mutable {
|
|
194
|
+
CB_LOG_PROTOCOL("[DNS, TCP, OUT] host=\"{}\", port={}, rc={}, bytes_sent={}",
|
|
195
|
+
self->address_.to_string(),
|
|
196
|
+
self->port_,
|
|
197
|
+
ec2 ? ec2.message() : "ok",
|
|
198
|
+
bytes_transferred2);
|
|
175
199
|
if (ec2) {
|
|
176
200
|
CB_LOG_DEBUG("DNS TCP write operation has been aborted, address=\"{}:{}\", ec={}",
|
|
177
201
|
self->address_.to_string(),
|
|
@@ -186,7 +210,14 @@ class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
|
|
|
186
210
|
asio::async_read(
|
|
187
211
|
self->tcp_,
|
|
188
212
|
asio::buffer(&self->recv_buf_size_, sizeof(std::uint16_t)),
|
|
189
|
-
[self](std::error_code ec3, std::size_t
|
|
213
|
+
[self](std::error_code ec3, std::size_t bytes_transferred3) mutable {
|
|
214
|
+
CB_LOG_PROTOCOL("[DNS, TCP, IN] host=\"{}\", port={}, rc={}, bytes_received={}{:a}",
|
|
215
|
+
self->address_.to_string(),
|
|
216
|
+
self->port_,
|
|
217
|
+
ec3 ? ec3.message() : "ok",
|
|
218
|
+
bytes_transferred3,
|
|
219
|
+
spdlog::to_hex(reinterpret_cast<std::uint8_t*>(&self->recv_buf_size_),
|
|
220
|
+
reinterpret_cast<std::uint8_t*>(&self->recv_buf_size_) + bytes_transferred3));
|
|
190
221
|
if (ec3) {
|
|
191
222
|
CB_LOG_DEBUG("DNS TCP buf size read operation has been aborted, address=\"{}:{}\", ec={}",
|
|
192
223
|
self->address_.to_string(),
|
|
@@ -199,8 +230,15 @@ class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
|
|
|
199
230
|
self->recv_buf_.resize(self->recv_buf_size_);
|
|
200
231
|
CB_LOG_DEBUG("DNS TCP schedule read of {} bytes", self->recv_buf_size_);
|
|
201
232
|
asio::async_read(
|
|
202
|
-
self->tcp_, asio::buffer(self->recv_buf_), [self](std::error_code ec4, std::size_t
|
|
233
|
+
self->tcp_, asio::buffer(self->recv_buf_), [self](std::error_code ec4, std::size_t bytes_transferred4) mutable {
|
|
203
234
|
self->deadline_.cancel();
|
|
235
|
+
CB_LOG_PROTOCOL("[DNS, TCP, IN] host=\"{}\", port={}, rc={}, bytes_received={}{:a}",
|
|
236
|
+
self->address_.to_string(),
|
|
237
|
+
self->port_,
|
|
238
|
+
ec4 ? ec4.message() : "ok",
|
|
239
|
+
bytes_transferred4,
|
|
240
|
+
spdlog::to_hex(self->recv_buf_.data(), self->recv_buf_.data() + bytes_transferred4));
|
|
241
|
+
|
|
204
242
|
if (ec4) {
|
|
205
243
|
CB_LOG_DEBUG("DNS TCP read operation has been aborted, address=\"{}:{}\", ec={}",
|
|
206
244
|
self->address_.to_string(),
|
|
@@ -208,7 +246,7 @@ class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
|
|
|
208
246
|
ec4.message());
|
|
209
247
|
return self->handler_({ ec4 });
|
|
210
248
|
}
|
|
211
|
-
self->recv_buf_.resize(
|
|
249
|
+
self->recv_buf_.resize(bytes_transferred4);
|
|
212
250
|
const dns_message message = dns_codec::decode(self->recv_buf_);
|
|
213
251
|
dns_srv_response resp{ ec4 };
|
|
214
252
|
resp.targets.reserve(message.answers.size());
|
|
@@ -31,7 +31,10 @@
|
|
|
31
31
|
|
|
32
32
|
#include <couchbase/error_codes.hxx>
|
|
33
33
|
|
|
34
|
+
#include <spdlog/fmt/bin_to_hex.h>
|
|
35
|
+
|
|
34
36
|
#include <asio.hpp>
|
|
37
|
+
|
|
35
38
|
#include <list>
|
|
36
39
|
#include <memory>
|
|
37
40
|
#include <utility>
|
|
@@ -448,7 +451,20 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
|
448
451
|
stream_->async_read_some(
|
|
449
452
|
asio::buffer(input_buffer_), [self = shared_from_this()](std::error_code ec, std::size_t bytes_transferred) {
|
|
450
453
|
if (ec == asio::error::operation_aborted || self->stopped_) {
|
|
454
|
+
CB_LOG_PROTOCOL("[HTTP, IN] type={}, host=\"{}\", rc={}, bytes_received={}",
|
|
455
|
+
self->type_,
|
|
456
|
+
self->info_.remote_address(),
|
|
457
|
+
ec ? ec.message() : "ok",
|
|
458
|
+
bytes_transferred);
|
|
451
459
|
return;
|
|
460
|
+
} else {
|
|
461
|
+
CB_LOG_PROTOCOL("[HTTP, IN] type={}, host=\"{}\", rc={}, bytes_received={}{:a}",
|
|
462
|
+
self->type_,
|
|
463
|
+
self->info_.remote_address(),
|
|
464
|
+
ec ? ec.message() : "ok",
|
|
465
|
+
bytes_transferred,
|
|
466
|
+
spdlog::to_hex(self->input_buffer_.data(),
|
|
467
|
+
self->input_buffer_.data() + static_cast<std::ptrdiff_t>(bytes_transferred)));
|
|
452
468
|
}
|
|
453
469
|
self->last_active_ = std::chrono::steady_clock::now();
|
|
454
470
|
if (ec) {
|
|
@@ -495,9 +511,16 @@ class http_session : public std::enable_shared_from_this<http_session>
|
|
|
495
511
|
std::vector<asio::const_buffer> buffers;
|
|
496
512
|
buffers.reserve(writing_buffer_.size());
|
|
497
513
|
for (auto& buf : writing_buffer_) {
|
|
514
|
+
CB_LOG_PROTOCOL(
|
|
515
|
+
"[HTTP, OUT] type={}, host=\"{}\", buffer_size={}{:a}", type_, info_.remote_address(), buf.size(), spdlog::to_hex(buf));
|
|
498
516
|
buffers.emplace_back(asio::buffer(buf));
|
|
499
517
|
}
|
|
500
|
-
stream_->async_write(buffers, [self = shared_from_this()](std::error_code ec, std::size_t
|
|
518
|
+
stream_->async_write(buffers, [self = shared_from_this()](std::error_code ec, std::size_t bytes_transferred) {
|
|
519
|
+
CB_LOG_PROTOCOL("[HTTP, OUT] type={}, host=\"{}\", rc={}, bytes_sent={}",
|
|
520
|
+
self->type_,
|
|
521
|
+
self->info_.remote_address(),
|
|
522
|
+
ec ? ec.message() : "ok",
|
|
523
|
+
bytes_transferred);
|
|
501
524
|
if (ec == asio::error::operation_aborted || self->stopped_) {
|
|
502
525
|
return;
|
|
503
526
|
}
|
|
@@ -1365,7 +1365,20 @@ class mcbp_session_impl
|
|
|
1365
1365
|
asio::buffer(input_buffer_),
|
|
1366
1366
|
[self = shared_from_this(), stream_id = stream_->id()](std::error_code ec, std::size_t bytes_transferred) {
|
|
1367
1367
|
if (ec == asio::error::operation_aborted || self->stopped_) {
|
|
1368
|
+
CB_LOG_PROTOCOL("[MCBP, IN] host=\"{}\", port={}, rc={}, bytes_received={}",
|
|
1369
|
+
self->endpoint_address_,
|
|
1370
|
+
self->endpoint_.port(),
|
|
1371
|
+
ec ? ec.message() : "ok",
|
|
1372
|
+
bytes_transferred);
|
|
1368
1373
|
return;
|
|
1374
|
+
} else {
|
|
1375
|
+
CB_LOG_PROTOCOL("[MCBP, IN] host=\"{}\", port={}, rc={}, bytes_received={}{:a}",
|
|
1376
|
+
self->endpoint_address_,
|
|
1377
|
+
self->endpoint_.port(),
|
|
1378
|
+
ec ? ec.message() : "ok",
|
|
1379
|
+
bytes_transferred,
|
|
1380
|
+
spdlog::to_hex(self->input_buffer_.data(),
|
|
1381
|
+
self->input_buffer_.data() + static_cast<std::ptrdiff_t>(bytes_transferred)));
|
|
1369
1382
|
}
|
|
1370
1383
|
self->last_active_ = std::chrono::steady_clock::now();
|
|
1371
1384
|
if (ec) {
|
|
@@ -1433,13 +1446,21 @@ class mcbp_session_impl
|
|
|
1433
1446
|
std::vector<asio::const_buffer> buffers;
|
|
1434
1447
|
buffers.reserve(writing_buffer_.size());
|
|
1435
1448
|
for (auto& buf : writing_buffer_) {
|
|
1449
|
+
CB_LOG_PROTOCOL(
|
|
1450
|
+
"[MCBP, OUT] host=\"{}\", port={}, buffer_size={}{:a}", endpoint_address_, endpoint_.port(), buf.size(), spdlog::to_hex(buf));
|
|
1436
1451
|
buffers.emplace_back(asio::buffer(buf));
|
|
1437
1452
|
}
|
|
1438
|
-
stream_->async_write(buffers, [self = shared_from_this()](std::error_code ec, std::size_t
|
|
1453
|
+
stream_->async_write(buffers, [self = shared_from_this()](std::error_code ec, std::size_t bytes_transferred) {
|
|
1454
|
+
CB_LOG_PROTOCOL("[MCBP, OUT] host=\"{}\", port={}, rc={}, bytes_sent={}",
|
|
1455
|
+
self->endpoint_address_,
|
|
1456
|
+
self->endpoint_.port(),
|
|
1457
|
+
ec ? ec.message() : "ok",
|
|
1458
|
+
bytes_transferred);
|
|
1439
1459
|
if (ec == asio::error::operation_aborted || self->stopped_) {
|
|
1440
1460
|
return;
|
|
1441
1461
|
}
|
|
1442
1462
|
self->last_active_ = std::chrono::steady_clock::now();
|
|
1463
|
+
|
|
1443
1464
|
if (ec) {
|
|
1444
1465
|
CB_LOG_ERROR(R"({} IO error while writing to the socket("{}"): {} ({}))",
|
|
1445
1466
|
self->log_prefix_,
|
|
@@ -127,7 +127,7 @@ custom_rotating_file_sink<Mutex>::add_hook(const std::string& hook)
|
|
|
127
127
|
|
|
128
128
|
// Payload shouldn't contain anything yet, overwrite it
|
|
129
129
|
Expects(msg.payload.size() == 0);
|
|
130
|
-
msg.payload =
|
|
130
|
+
msg.payload = hookToAdd;
|
|
131
131
|
|
|
132
132
|
spdlog::memory_buf_t formatted;
|
|
133
133
|
formatter->format(msg, formatted);
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
#include <spdlog/sinks/stdout_color_sinks.h>
|
|
23
23
|
#include <spdlog/spdlog.h>
|
|
24
24
|
|
|
25
|
-
static const std::string
|
|
25
|
+
static const std::string file_logger_name{ "couchbase_cxx_client_file_logger" };
|
|
26
|
+
static const std::string protocol_logger_name{ "couchbase_cxx_client_protocol_logger" };
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* Custom log pattern which the loggers will use.
|
|
@@ -39,7 +40,12 @@ static const std::string log_pattern{ "[%Y-%m-%d %T.%e] [%P,%t] [%^%l%$] %oms, %
|
|
|
39
40
|
* messages and send them to the sinks, which do the actual writing (to file,
|
|
40
41
|
* to stream etc.) or further processing.
|
|
41
42
|
*/
|
|
42
|
-
static std::shared_ptr<spdlog::logger> file_logger;
|
|
43
|
+
static std::shared_ptr<spdlog::logger> file_logger{};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Instance of the protocol logger.
|
|
47
|
+
*/
|
|
48
|
+
static std::shared_ptr<spdlog::logger> protocol_logger{};
|
|
43
49
|
|
|
44
50
|
namespace couchbase::core::logger
|
|
45
51
|
{
|
|
@@ -146,13 +152,11 @@ is_initialized()
|
|
|
146
152
|
return file_logger != nullptr;
|
|
147
153
|
}
|
|
148
154
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
* specified in a separate settings object.
|
|
152
|
-
*/
|
|
153
|
-
std::optional<std::string>
|
|
154
|
-
create_file_logger(const configuration& logger_settings)
|
|
155
|
+
std::pair<std::optional<std::string>, std::shared_ptr<spdlog::logger>>
|
|
156
|
+
create_file_logger_impl(const std::string logger_name, const configuration& logger_settings)
|
|
155
157
|
{
|
|
158
|
+
std::shared_ptr<spdlog::logger> logger{};
|
|
159
|
+
|
|
156
160
|
auto fname = logger_settings.filename;
|
|
157
161
|
auto buffersz = logger_settings.buffer_size;
|
|
158
162
|
auto cyclesz = logger_settings.cycle_size;
|
|
@@ -218,7 +222,7 @@ create_file_logger(const configuration& logger_settings)
|
|
|
218
222
|
spdlog::drop(logger_name);
|
|
219
223
|
|
|
220
224
|
if (logger_settings.unit_test) {
|
|
221
|
-
|
|
225
|
+
logger = std::make_shared<spdlog::logger>(logger_name, sink);
|
|
222
226
|
} else {
|
|
223
227
|
// Create the default thread pool for async logging
|
|
224
228
|
spdlog::init_thread_pool(buffersz, 1);
|
|
@@ -226,23 +230,71 @@ create_file_logger(const configuration& logger_settings)
|
|
|
226
230
|
// Get the thread pool so that we can actually construct the
|
|
227
231
|
// object with already created sinks...
|
|
228
232
|
auto tp = spdlog::thread_pool();
|
|
229
|
-
|
|
233
|
+
logger = std::make_shared<spdlog::async_logger>(logger_name, sink, tp, spdlog::async_overflow_policy::block);
|
|
230
234
|
}
|
|
231
235
|
|
|
232
|
-
|
|
233
|
-
|
|
236
|
+
logger->set_pattern(log_pattern);
|
|
237
|
+
logger->set_level(translate_level(logger_settings.log_level));
|
|
234
238
|
|
|
235
239
|
// Set the flushing interval policy
|
|
236
240
|
spdlog::flush_every(std::chrono::seconds(1));
|
|
237
241
|
|
|
238
|
-
spdlog::register_logger(
|
|
242
|
+
spdlog::register_logger(logger);
|
|
239
243
|
} catch (const spdlog::spdlog_ex& ex) {
|
|
240
244
|
std::string msg = std::string{ "Log initialization failed: " } + ex.what();
|
|
241
|
-
return
|
|
245
|
+
return { msg, {} };
|
|
246
|
+
}
|
|
247
|
+
return { {}, logger };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Initialises the loggers. Called if the logger configuration is
|
|
252
|
+
* specified in a separate settings object.
|
|
253
|
+
*/
|
|
254
|
+
std::optional<std::string>
|
|
255
|
+
create_file_logger(const configuration& logger_settings)
|
|
256
|
+
{
|
|
257
|
+
auto [error, logger] = create_file_logger_impl(file_logger_name, logger_settings);
|
|
258
|
+
if (error) {
|
|
259
|
+
return error;
|
|
260
|
+
}
|
|
261
|
+
file_logger = std::move(logger);
|
|
262
|
+
return {};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
std::optional<std::string>
|
|
266
|
+
create_protocol_logger(const configuration& logger_settings)
|
|
267
|
+
{
|
|
268
|
+
if (logger_settings.filename.empty()) {
|
|
269
|
+
return "File name is missing";
|
|
270
|
+
}
|
|
271
|
+
auto config = logger_settings;
|
|
272
|
+
config.log_level = couchbase::core::logger::level::trace;
|
|
273
|
+
auto [error, logger] = create_file_logger_impl(protocol_logger_name, config);
|
|
274
|
+
if (error) {
|
|
275
|
+
return error;
|
|
242
276
|
}
|
|
277
|
+
protocol_logger = std::move(logger);
|
|
243
278
|
return {};
|
|
244
279
|
}
|
|
245
280
|
|
|
281
|
+
bool
|
|
282
|
+
should_log_protocol()
|
|
283
|
+
{
|
|
284
|
+
return protocol_logger != nullptr;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
namespace detail
|
|
288
|
+
{
|
|
289
|
+
void
|
|
290
|
+
log_protocol(const char* file, int line, const char* function, std::string_view msg)
|
|
291
|
+
{
|
|
292
|
+
if (should_log_protocol()) {
|
|
293
|
+
return protocol_logger->log(spdlog::source_loc{ file, line, function }, spdlog::level::level_enum::trace, msg);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
} // namespace detail
|
|
297
|
+
|
|
246
298
|
spdlog::logger*
|
|
247
299
|
get()
|
|
248
300
|
{
|
|
@@ -252,17 +304,20 @@ get()
|
|
|
252
304
|
void
|
|
253
305
|
reset()
|
|
254
306
|
{
|
|
255
|
-
spdlog::drop(
|
|
307
|
+
spdlog::drop(file_logger_name);
|
|
256
308
|
file_logger.reset();
|
|
309
|
+
|
|
310
|
+
spdlog::drop(protocol_logger_name);
|
|
311
|
+
protocol_logger.reset();
|
|
257
312
|
}
|
|
258
313
|
|
|
259
314
|
void
|
|
260
315
|
create_blackhole_logger()
|
|
261
316
|
{
|
|
262
317
|
// delete if already exists
|
|
263
|
-
spdlog::drop(
|
|
318
|
+
spdlog::drop(file_logger_name);
|
|
264
319
|
|
|
265
|
-
file_logger = std::make_shared<spdlog::logger>(
|
|
320
|
+
file_logger = std::make_shared<spdlog::logger>(file_logger_name, std::make_shared<spdlog::sinks::null_sink_mt>());
|
|
266
321
|
|
|
267
322
|
file_logger->set_level(spdlog::level::off);
|
|
268
323
|
file_logger->set_pattern(log_pattern);
|
|
@@ -274,11 +329,11 @@ void
|
|
|
274
329
|
create_console_logger()
|
|
275
330
|
{
|
|
276
331
|
// delete if already exists
|
|
277
|
-
spdlog::drop(
|
|
332
|
+
spdlog::drop(file_logger_name);
|
|
278
333
|
|
|
279
334
|
auto stderrsink = std::make_shared<spdlog::sinks::stderr_color_sink_mt>();
|
|
280
335
|
|
|
281
|
-
file_logger = std::make_shared<spdlog::logger>(
|
|
336
|
+
file_logger = std::make_shared<spdlog::logger>(file_logger_name, stderrsink);
|
|
282
337
|
file_logger->set_level(spdlog::level::info);
|
|
283
338
|
file_logger->set_pattern(log_pattern);
|
|
284
339
|
|
|
@@ -322,8 +377,13 @@ void
|
|
|
322
377
|
set_log_levels(level lvl)
|
|
323
378
|
{
|
|
324
379
|
auto level = translate_level(lvl);
|
|
325
|
-
// Apply the function to each registered spdlog::logger
|
|
380
|
+
// Apply the function to each registered spdlog::logger except protocol logger
|
|
326
381
|
spdlog::apply_all([level](std::shared_ptr<spdlog::logger> l) {
|
|
382
|
+
if (l->name() == protocol_logger_name) {
|
|
383
|
+
l->set_level(spdlog::level::trace);
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
|
|
327
387
|
try {
|
|
328
388
|
l->set_level(level);
|
|
329
389
|
} catch (const spdlog::spdlog_ex& e) {
|
|
@@ -54,6 +54,17 @@ level_from_str(const std::string& str);
|
|
|
54
54
|
std::optional<std::string>
|
|
55
55
|
create_file_logger(const configuration& logger_settings);
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Protocol logger writes only communication logs with the nodes.
|
|
59
|
+
*
|
|
60
|
+
* It accepts the same settings as a file logger, and writes only to the filesystem.
|
|
61
|
+
*
|
|
62
|
+
* @param logger_settings
|
|
63
|
+
* @return
|
|
64
|
+
*/
|
|
65
|
+
std::optional<std::string>
|
|
66
|
+
create_protocol_logger(const configuration& logger_settings);
|
|
67
|
+
|
|
57
68
|
/**
|
|
58
69
|
* Initialize the logger with the blackhole logger object
|
|
59
70
|
*
|
|
@@ -144,6 +155,9 @@ set_log_levels(level lvl);
|
|
|
144
155
|
bool
|
|
145
156
|
should_log(level lvl);
|
|
146
157
|
|
|
158
|
+
bool
|
|
159
|
+
should_log_protocol();
|
|
160
|
+
|
|
147
161
|
namespace detail
|
|
148
162
|
{
|
|
149
163
|
/**
|
|
@@ -153,6 +167,9 @@ namespace detail
|
|
|
153
167
|
*/
|
|
154
168
|
void
|
|
155
169
|
log(const char* file, int line, const char* function, level lvl, std::string_view msg);
|
|
170
|
+
|
|
171
|
+
void
|
|
172
|
+
log_protocol(const char* file, int line, const char* function, std::string_view msg);
|
|
156
173
|
} // namespace detail
|
|
157
174
|
|
|
158
175
|
/**
|
|
@@ -168,6 +185,13 @@ log(const char* file, int line, const char* function, level lvl, const String& m
|
|
|
168
185
|
detail::log(file, line, function, lvl, fmt::format(msg, std::forward<Args>(args)...));
|
|
169
186
|
}
|
|
170
187
|
|
|
188
|
+
template<typename String, typename... Args>
|
|
189
|
+
inline void
|
|
190
|
+
log_protocol(const char* file, int line, const char* function, const String& msg, Args&&... args)
|
|
191
|
+
{
|
|
192
|
+
detail::log_protocol(file, line, function, fmt::format(msg, std::forward<Args>(args)...));
|
|
193
|
+
}
|
|
194
|
+
|
|
171
195
|
/**
|
|
172
196
|
* Tell the logger to flush its buffers
|
|
173
197
|
*/
|
|
@@ -214,6 +238,13 @@ is_initialized();
|
|
|
214
238
|
#define CB_LOG_CRITICAL(...) \
|
|
215
239
|
COUCHBASE_LOG(__FILE__, __LINE__, COUCHBASE_LOGGER_FUNCTION, couchbase::core::logger::level::critical, __VA_ARGS__)
|
|
216
240
|
|
|
241
|
+
#define CB_LOG_PROTOCOL(...) \
|
|
242
|
+
do { \
|
|
243
|
+
if (couchbase::core::logger::should_log_protocol()) { \
|
|
244
|
+
couchbase::core::logger::log_protocol(__FILE__, __LINE__, COUCHBASE_LOGGER_FUNCTION, __VA_ARGS__); \
|
|
245
|
+
} \
|
|
246
|
+
} while (false)
|
|
247
|
+
|
|
217
248
|
/**
|
|
218
249
|
* Convenience macros which log with the given level, and message, if the given
|
|
219
250
|
* level is currently enabled.
|
|
@@ -35,3 +35,22 @@
|
|
|
35
35
|
* passing TLS trust certificate by value
|
|
36
36
|
*/
|
|
37
37
|
#define COUCHBASE_CXX_CLIENT_CAN_PASS_TLS_TRUST_CERTIFICATE_BY_VALUE 1
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Range scan is available in the core
|
|
41
|
+
* couchbase::core::range_scan_orchestrator and relevant options in the core API
|
|
42
|
+
*/
|
|
43
|
+
#define COUCHBASE_CXX_CLIENT_CORE_HAS_RANGE_SCAN 1
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Query with reads from replica is available:
|
|
47
|
+
* - use_replica field in couchbase::core::operations::query_request
|
|
48
|
+
* - couchbase::query_options::use_replica()
|
|
49
|
+
*/
|
|
50
|
+
#define COUCHBASE_CXX_CLIENT_QUERY_READ_FROM_REPLICA 1
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Subdoc read from replica is available in the core
|
|
54
|
+
* couchbase::core::lookup_in_replica support
|
|
55
|
+
*/
|
|
56
|
+
#define COUCHBASE_CXX_CLIENT_CORE_HAS_SUBDOC_READ_REPLICA 1
|