couchbase 4.2.6-dev.1 → 4.2.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|