couchbase 3.0.0.beta.1-universal-darwin-19 → 3.0.0-universal-darwin-19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +227 -0
- data/.rubocop_todo.yml +47 -0
- data/CONTRIBUTING.md +110 -0
- data/Gemfile +4 -0
- data/README.md +3 -3
- data/Rakefile +1 -1
- data/couchbase.gemspec +40 -39
- data/examples/analytics.rb +123 -108
- data/examples/auth.rb +33 -0
- data/examples/crud.rb +16 -2
- data/examples/managing_analytics_indexes.rb +18 -4
- data/examples/managing_buckets.rb +17 -3
- data/examples/managing_collections.rb +22 -9
- data/examples/managing_query_indexes.rb +38 -18
- data/examples/managing_search_indexes.rb +21 -6
- data/examples/managing_view_indexes.rb +18 -4
- data/examples/query.rb +17 -3
- data/examples/query_with_consistency.rb +30 -20
- data/examples/search.rb +116 -101
- data/examples/search_with_consistency.rb +43 -30
- data/examples/subdocument.rb +42 -30
- data/examples/view.rb +19 -10
- data/ext/CMakeLists.txt +40 -2
- data/ext/build_version.hxx.in +1 -1
- data/ext/couchbase/bucket.hxx +190 -38
- data/ext/couchbase/cluster.hxx +22 -4
- data/ext/couchbase/configuration.hxx +14 -14
- data/ext/couchbase/couchbase.cxx +108 -12
- data/ext/couchbase/error_map.hxx +202 -2
- data/ext/couchbase/errors.hxx +8 -2
- data/ext/couchbase/io/dns_client.hxx +6 -6
- data/ext/couchbase/io/http_command.hxx +2 -2
- data/ext/couchbase/io/http_session.hxx +7 -11
- data/ext/couchbase/io/http_session_manager.hxx +3 -3
- data/ext/couchbase/io/mcbp_command.hxx +101 -44
- data/ext/couchbase/io/mcbp_session.hxx +144 -49
- data/ext/couchbase/io/retry_action.hxx +30 -0
- data/ext/couchbase/io/retry_context.hxx +39 -0
- data/ext/couchbase/io/retry_orchestrator.hxx +96 -0
- data/ext/couchbase/io/retry_reason.hxx +235 -0
- data/ext/couchbase/io/retry_strategy.hxx +156 -0
- data/ext/couchbase/operations/document_decrement.hxx +2 -0
- data/ext/couchbase/operations/document_exists.hxx +2 -0
- data/ext/couchbase/operations/document_get.hxx +2 -0
- data/ext/couchbase/operations/document_get_and_lock.hxx +2 -0
- data/ext/couchbase/operations/document_get_and_touch.hxx +2 -0
- data/ext/couchbase/operations/document_get_projected.hxx +2 -0
- data/ext/couchbase/operations/document_increment.hxx +2 -0
- data/ext/couchbase/operations/document_insert.hxx +2 -0
- data/ext/couchbase/operations/document_lookup_in.hxx +2 -0
- data/ext/couchbase/operations/document_mutate_in.hxx +3 -0
- data/ext/couchbase/operations/document_query.hxx +10 -0
- data/ext/couchbase/operations/document_remove.hxx +2 -0
- data/ext/couchbase/operations/document_replace.hxx +2 -0
- data/ext/couchbase/operations/document_search.hxx +8 -3
- data/ext/couchbase/operations/document_touch.hxx +2 -0
- data/ext/couchbase/operations/document_unlock.hxx +2 -0
- data/ext/couchbase/operations/document_upsert.hxx +2 -0
- data/ext/couchbase/operations/query_index_create.hxx +14 -4
- data/ext/couchbase/operations/query_index_drop.hxx +12 -2
- data/ext/couchbase/operations/query_index_get_all.hxx +11 -2
- data/ext/couchbase/origin.hxx +47 -17
- data/ext/couchbase/platform/backtrace.c +189 -0
- data/ext/couchbase/platform/backtrace.h +54 -0
- data/ext/couchbase/platform/terminate_handler.cc +122 -0
- data/ext/couchbase/platform/terminate_handler.h +36 -0
- data/ext/couchbase/protocol/cmd_get_cluster_config.hxx +6 -1
- data/ext/couchbase/protocol/status.hxx +14 -4
- data/ext/couchbase/version.hxx +2 -2
- data/ext/extconf.rb +39 -36
- data/ext/test/main.cxx +64 -16
- data/lib/couchbase.rb +0 -1
- data/lib/couchbase/analytics_options.rb +2 -4
- data/lib/couchbase/authenticator.rb +14 -0
- data/lib/couchbase/binary_collection.rb +9 -9
- data/lib/couchbase/binary_collection_options.rb +8 -6
- data/lib/couchbase/bucket.rb +18 -18
- data/lib/couchbase/cluster.rb +121 -90
- data/lib/couchbase/collection.rb +36 -38
- data/lib/couchbase/collection_options.rb +31 -17
- data/lib/couchbase/common_options.rb +1 -1
- data/lib/couchbase/datastructures/couchbase_list.rb +16 -16
- data/lib/couchbase/datastructures/couchbase_map.rb +18 -18
- data/lib/couchbase/datastructures/couchbase_queue.rb +13 -13
- data/lib/couchbase/datastructures/couchbase_set.rb +8 -7
- data/lib/couchbase/errors.rb +10 -3
- data/lib/couchbase/json_transcoder.rb +2 -2
- data/lib/couchbase/libcouchbase.bundle +0 -0
- data/lib/couchbase/management/analytics_index_manager.rb +37 -37
- data/lib/couchbase/management/bucket_manager.rb +25 -25
- data/lib/couchbase/management/collection_manager.rb +3 -3
- data/lib/couchbase/management/query_index_manager.rb +59 -14
- data/lib/couchbase/management/search_index_manager.rb +15 -12
- data/lib/couchbase/management/user_manager.rb +1 -1
- data/lib/couchbase/management/view_index_manager.rb +11 -5
- data/lib/couchbase/mutation_state.rb +12 -0
- data/lib/couchbase/query_options.rb +23 -9
- data/lib/couchbase/scope.rb +61 -1
- data/lib/couchbase/search_options.rb +40 -27
- data/lib/couchbase/subdoc.rb +31 -28
- data/lib/couchbase/version.rb +2 -2
- data/lib/couchbase/view_options.rb +0 -1
- metadata +20 -7
data/ext/couchbase/cluster.hxx
CHANGED
@@ -53,7 +53,8 @@ class cluster
|
|
53
53
|
{
|
54
54
|
origin_ = origin;
|
55
55
|
if (origin_.options().enable_dns_srv) {
|
56
|
-
return
|
56
|
+
return asio::post(asio::bind_executor(
|
57
|
+
ctx_, [this, handler = std::forward<Handler>(handler)]() mutable { return do_dns_srv(std::forward<Handler>(handler)); }));
|
57
58
|
}
|
58
59
|
do_open(std::forward<Handler>(handler));
|
59
60
|
}
|
@@ -63,7 +64,7 @@ class cluster
|
|
63
64
|
{
|
64
65
|
asio::post(asio::bind_executor(ctx_, [this, handler = std::forward<Handler>(handler)]() {
|
65
66
|
if (session_) {
|
66
|
-
session_->stop();
|
67
|
+
session_->stop(io::retry_reason::do_not_retry);
|
67
68
|
}
|
68
69
|
for (auto& bucket : buckets_) {
|
69
70
|
bucket.second->close();
|
@@ -103,7 +104,7 @@ class cluster
|
|
103
104
|
template<class Request, class Handler>
|
104
105
|
void execute_http(Request request, Handler&& handler)
|
105
106
|
{
|
106
|
-
auto session = session_manager_->check_out(Request::type, origin_.
|
107
|
+
auto session = session_manager_->check_out(Request::type, origin_.credentials());
|
107
108
|
if (!session) {
|
108
109
|
return handler(operations::make_response(std::make_error_code(error::common_errc::service_not_available), request, {}));
|
109
110
|
}
|
@@ -157,9 +158,11 @@ class cluster
|
|
157
158
|
tls_.set_options(asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
|
158
159
|
if (!origin_.options().trust_certificate.empty()) {
|
159
160
|
std::error_code ec{};
|
161
|
+
spdlog::debug(R"([{}]: use TLS certificate chain: "{}")", id_, origin_.options().trust_certificate);
|
160
162
|
tls_.use_certificate_chain_file(origin_.options().trust_certificate, ec);
|
161
163
|
if (ec) {
|
162
|
-
spdlog::error(
|
164
|
+
spdlog::error(
|
165
|
+
"[{}]: unable to load certificate chain \"{}\": {}", id_, origin_.options().trust_certificate, ec.message());
|
163
166
|
return handler(ec);
|
164
167
|
}
|
165
168
|
}
|
@@ -172,6 +175,21 @@ class cluster
|
|
172
175
|
"(https://wiki.wireshark.org/TLS). DO NOT USE THIS BUILD IN PRODUCTION",
|
173
176
|
TLS_KEY_LOG_FILE);
|
174
177
|
#endif
|
178
|
+
if (origin_.credentials().uses_certificate()) {
|
179
|
+
std::error_code ec{};
|
180
|
+
spdlog::debug(R"([{}]: use TLS certificate: "{}")", id_, origin_.certificate_path());
|
181
|
+
tls_.use_certificate_file(origin_.certificate_path(), asio::ssl::context::file_format::pem, ec);
|
182
|
+
if (ec) {
|
183
|
+
spdlog::error("[{}]: unable to load certificate \"{}\": {}", id_, origin_.certificate_path(), ec.message());
|
184
|
+
return handler(ec);
|
185
|
+
}
|
186
|
+
spdlog::debug(R"([{}]: use TLS private key: "{}")", id_, origin_.key_path());
|
187
|
+
tls_.use_private_key_file(origin_.key_path(), asio::ssl::context::file_format::pem, ec);
|
188
|
+
if (ec) {
|
189
|
+
spdlog::error("[{}]: unable to load private key \"{}\": {}", id_, origin_.key_path(), ec.message());
|
190
|
+
return handler(ec);
|
191
|
+
}
|
192
|
+
}
|
175
193
|
session_ = std::make_shared<io::mcbp_session>(id_, ctx_, tls_, origin_);
|
176
194
|
} else {
|
177
195
|
session_ = std::make_shared<io::mcbp_session>(id_, ctx_, origin_);
|
@@ -30,25 +30,25 @@ namespace couchbase
|
|
30
30
|
{
|
31
31
|
struct configuration {
|
32
32
|
struct port_map {
|
33
|
-
std::optional<std::uint16_t> key_value;
|
34
|
-
std::optional<std::uint16_t> management;
|
35
|
-
std::optional<std::uint16_t> analytics;
|
36
|
-
std::optional<std::uint16_t> search;
|
37
|
-
std::optional<std::uint16_t> views;
|
38
|
-
std::optional<std::uint16_t> query;
|
33
|
+
std::optional<std::uint16_t> key_value{};
|
34
|
+
std::optional<std::uint16_t> management{};
|
35
|
+
std::optional<std::uint16_t> analytics{};
|
36
|
+
std::optional<std::uint16_t> search{};
|
37
|
+
std::optional<std::uint16_t> views{};
|
38
|
+
std::optional<std::uint16_t> query{};
|
39
39
|
};
|
40
40
|
struct alternate_address {
|
41
|
-
std::string name;
|
42
|
-
std::string hostname;
|
41
|
+
std::string name{};
|
42
|
+
std::string hostname{};
|
43
43
|
port_map services_plain{};
|
44
44
|
port_map services_tls{};
|
45
45
|
};
|
46
46
|
struct node {
|
47
47
|
bool this_node{ false };
|
48
|
-
size_t index;
|
49
|
-
std::string hostname;
|
50
|
-
port_map services_plain;
|
51
|
-
port_map services_tls;
|
48
|
+
size_t index{};
|
49
|
+
std::string hostname{};
|
50
|
+
port_map services_plain{};
|
51
|
+
port_map services_tls{};
|
52
52
|
std::map<std::string, alternate_address> alt{};
|
53
53
|
|
54
54
|
[[nodiscard]] std::uint16_t port_or(service_type type, bool is_tls, std::uint16_t default_value) const
|
@@ -211,14 +211,14 @@ struct configuration {
|
|
211
211
|
throw std::runtime_error("no nodes marked as this_node");
|
212
212
|
}
|
213
213
|
|
214
|
-
std::pair<uint16_t,
|
214
|
+
std::pair<std::uint16_t, std::int16_t> map_key(const std::string& key)
|
215
215
|
{
|
216
216
|
if (!vbmap.has_value()) {
|
217
217
|
throw std::runtime_error("cannot map key: partition map is not available");
|
218
218
|
}
|
219
219
|
uint32_t crc = utils::hash_crc32(key.data(), key.size());
|
220
220
|
uint16_t vbucket = uint16_t(crc % vbmap->size());
|
221
|
-
return std::make_pair(vbucket,
|
221
|
+
return std::make_pair(vbucket, vbmap->at(vbucket)[0]);
|
222
222
|
}
|
223
223
|
};
|
224
224
|
|
data/ext/couchbase/couchbase.cxx
CHANGED
@@ -28,6 +28,8 @@
|
|
28
28
|
#include <snappy.h>
|
29
29
|
|
30
30
|
#include <version.hxx>
|
31
|
+
#include <platform/terminate_handler.h>
|
32
|
+
|
31
33
|
#include <cluster.hxx>
|
32
34
|
#include <operations.hxx>
|
33
35
|
|
@@ -165,6 +167,7 @@ cb_Backend_allocate(VALUE klass)
|
|
165
167
|
}
|
166
168
|
|
167
169
|
static VALUE eCouchbaseError;
|
170
|
+
static VALUE eTimeout;
|
168
171
|
static VALUE eAmbiguousTimeout;
|
169
172
|
static VALUE eAuthenticationFailure;
|
170
173
|
static VALUE eBucketExists;
|
@@ -197,6 +200,7 @@ static VALUE eGroupNotFound;
|
|
197
200
|
static VALUE eIndexExists;
|
198
201
|
static VALUE eIndexFailure;
|
199
202
|
static VALUE eIndexNotFound;
|
203
|
+
static VALUE eIndexNotReady;
|
200
204
|
static VALUE eInternalServerFailure;
|
201
205
|
static VALUE eInvalidArgument;
|
202
206
|
static VALUE eJobQueueFull;
|
@@ -235,7 +239,9 @@ init_exceptions(VALUE mCouchbase)
|
|
235
239
|
VALUE mError = rb_define_module_under(mCouchbase, "Error");
|
236
240
|
eCouchbaseError = rb_define_class_under(mError, "CouchbaseError", rb_eStandardError);
|
237
241
|
|
238
|
-
|
242
|
+
eTimeout = rb_define_class_under(mError, "Timeout", eCouchbaseError);
|
243
|
+
|
244
|
+
eAmbiguousTimeout = rb_define_class_under(mError, "AmbiguousTimeout", eTimeout);
|
239
245
|
eAuthenticationFailure = rb_define_class_under(mError, "AuthenticationFailure", eCouchbaseError);
|
240
246
|
eBucketExists = rb_define_class_under(mError, "BucketExists", eCouchbaseError);
|
241
247
|
eBucketNotFlushable = rb_define_class_under(mError, "BucketNotFlushable", eCouchbaseError);
|
@@ -267,6 +273,7 @@ init_exceptions(VALUE mCouchbase)
|
|
267
273
|
eIndexExists = rb_define_class_under(mError, "IndexExists", eCouchbaseError);
|
268
274
|
eIndexFailure = rb_define_class_under(mError, "IndexFailure", eCouchbaseError);
|
269
275
|
eIndexNotFound = rb_define_class_under(mError, "IndexNotFound", eCouchbaseError);
|
276
|
+
eIndexNotReady = rb_define_class_under(mError, "IndexNotReady", eCouchbaseError);
|
270
277
|
eInternalServerFailure = rb_define_class_under(mError, "InternalServerFailure", eCouchbaseError);
|
271
278
|
eInvalidArgument = rb_define_class_under(mError, "InvalidArgument", rb_eArgError);
|
272
279
|
eJobQueueFull = rb_define_class_under(mError, "JobQueueFull", eCouchbaseError);
|
@@ -286,7 +293,7 @@ init_exceptions(VALUE mCouchbase)
|
|
286
293
|
eScopeNotFound = rb_define_class_under(mError, "ScopeNotFound", eCouchbaseError);
|
287
294
|
eServiceNotAvailable = rb_define_class_under(mError, "ServiceNotAvailable", eCouchbaseError);
|
288
295
|
eTemporaryFailure = rb_define_class_under(mError, "TemporaryFailure", eCouchbaseError);
|
289
|
-
eUnambiguousTimeout = rb_define_class_under(mError, "UnambiguousTimeout",
|
296
|
+
eUnambiguousTimeout = rb_define_class_under(mError, "UnambiguousTimeout", eTimeout);
|
290
297
|
eUnsupportedOperation = rb_define_class_under(mError, "UnsupportedOperation", eCouchbaseError);
|
291
298
|
eUserNotFound = rb_define_class_under(mError, "UserNotFound", eCouchbaseError);
|
292
299
|
eUserExists = rb_define_class_under(mError, "UserExists", eCouchbaseError);
|
@@ -450,6 +457,11 @@ cb__map_error_code(std::error_code ec, const std::string& message)
|
|
450
457
|
case couchbase::error::query_errc::prepared_statement_failure:
|
451
458
|
return rb_exc_new_cstr(ePreparedStatementFailure, fmt::format("{}: {}", message, ec.message()).c_str());
|
452
459
|
}
|
460
|
+
} else if (ec.category() == couchbase::error::detail::get_search_category()) {
|
461
|
+
switch (static_cast<couchbase::error::search_errc>(ec.value())) {
|
462
|
+
case couchbase::error::search_errc::index_not_ready:
|
463
|
+
return rb_exc_new_cstr(eIndexNotReady, fmt::format("{}: {}", message, ec.message()).c_str());
|
464
|
+
}
|
453
465
|
} else if (ec.category() == couchbase::error::detail::get_view_category()) {
|
454
466
|
switch (static_cast<couchbase::error::view_errc>(ec.value())) {
|
455
467
|
case couchbase::error::view_errc::view_not_found:
|
@@ -510,7 +522,7 @@ cb__map_error_code(std::error_code ec, const std::string& message)
|
|
510
522
|
}
|
511
523
|
|
512
524
|
static VALUE
|
513
|
-
cb_Backend_open(VALUE self, VALUE connection_string, VALUE
|
525
|
+
cb_Backend_open(VALUE self, VALUE connection_string, VALUE credentials, VALUE options)
|
514
526
|
{
|
515
527
|
cb_backend_data* backend = nullptr;
|
516
528
|
TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
|
@@ -519,26 +531,52 @@ cb_Backend_open(VALUE self, VALUE connection_string, VALUE username, VALUE passw
|
|
519
531
|
rb_raise(rb_eArgError, "Cluster has been closed already");
|
520
532
|
}
|
521
533
|
Check_Type(connection_string, T_STRING);
|
522
|
-
Check_Type(
|
523
|
-
|
534
|
+
Check_Type(credentials, T_HASH);
|
535
|
+
|
536
|
+
VALUE username = Qnil;
|
537
|
+
VALUE password = Qnil;
|
538
|
+
|
539
|
+
VALUE certificate_path = rb_hash_aref(credentials, rb_id2sym(rb_intern("certificate_path")));
|
540
|
+
VALUE key_path = rb_hash_aref(credentials, rb_id2sym(rb_intern("key_path")));
|
541
|
+
if (NIL_P(certificate_path) || NIL_P(key_path)) {
|
542
|
+
username = rb_hash_aref(credentials, rb_id2sym(rb_intern("username")));
|
543
|
+
password = rb_hash_aref(credentials, rb_id2sym(rb_intern("password")));
|
544
|
+
Check_Type(username, T_STRING);
|
545
|
+
Check_Type(password, T_STRING);
|
546
|
+
} else {
|
547
|
+
Check_Type(certificate_path, T_STRING);
|
548
|
+
Check_Type(key_path, T_STRING);
|
549
|
+
}
|
524
550
|
if (!NIL_P(options)) {
|
525
551
|
Check_Type(options, T_HASH);
|
526
552
|
}
|
527
553
|
|
528
554
|
VALUE exc = Qnil;
|
529
|
-
{
|
555
|
+
do {
|
530
556
|
std::string input(RSTRING_PTR(connection_string), static_cast<size_t>(RSTRING_LEN(connection_string)));
|
531
557
|
auto connstr = couchbase::utils::parse_connection_string(input);
|
532
|
-
|
533
|
-
|
534
|
-
|
558
|
+
couchbase::cluster_credentials auth{};
|
559
|
+
if (NIL_P(certificate_path) || NIL_P(key_path)) {
|
560
|
+
auth.username.assign(RSTRING_PTR(username), static_cast<size_t>(RSTRING_LEN(username)));
|
561
|
+
auth.password.assign(RSTRING_PTR(password), static_cast<size_t>(RSTRING_LEN(password)));
|
562
|
+
} else {
|
563
|
+
if (!connstr.tls) {
|
564
|
+
exc = rb_exc_new_cstr(
|
565
|
+
eInvalidArgument,
|
566
|
+
fmt::format("Certificate authenticator requires TLS connection, check the schema of the connection string").c_str());
|
567
|
+
break;
|
568
|
+
}
|
569
|
+
auth.certificate_path.assign(RSTRING_PTR(certificate_path), static_cast<size_t>(RSTRING_LEN(certificate_path)));
|
570
|
+
auth.key_path.assign(RSTRING_PTR(key_path), static_cast<size_t>(RSTRING_LEN(key_path)));
|
571
|
+
}
|
572
|
+
couchbase::origin origin(auth, std::move(connstr));
|
535
573
|
auto barrier = std::make_shared<std::promise<std::error_code>>();
|
536
574
|
auto f = barrier->get_future();
|
537
575
|
backend->cluster->open(origin, [barrier](std::error_code ec) mutable { barrier->set_value(ec); });
|
538
576
|
if (auto ec = f.get()) {
|
539
577
|
exc = cb__map_error_code(ec, fmt::format("unable open cluster at {}", origin.next_address().first));
|
540
578
|
}
|
541
|
-
}
|
579
|
+
} while (false);
|
542
580
|
if (!NIL_P(exc)) {
|
543
581
|
rb_exc_raise(exc);
|
544
582
|
}
|
@@ -1958,6 +1996,22 @@ cb_Backend_document_query(VALUE self, VALUE statement, VALUE options)
|
|
1958
1996
|
if (!NIL_P(pipeline_batch)) {
|
1959
1997
|
req.pipeline_batch = NUM2ULONG(pipeline_batch);
|
1960
1998
|
}
|
1999
|
+
VALUE scope_qualifier = rb_hash_aref(options, rb_id2sym(rb_intern("scope_qualifier")));
|
2000
|
+
if (!NIL_P(scope_qualifier) && TYPE(scope_qualifier) == T_STRING) {
|
2001
|
+
req.scope_qualifier.emplace(std::string(RSTRING_PTR(scope_qualifier), static_cast<std::size_t>(RSTRING_LEN(scope_qualifier))));
|
2002
|
+
} else {
|
2003
|
+
VALUE scope_name = rb_hash_aref(options, rb_id2sym(rb_intern("scope_name")));
|
2004
|
+
if (!NIL_P(scope_name) && TYPE(scope_name) == T_STRING) {
|
2005
|
+
req.scope_name.emplace(std::string(RSTRING_PTR(scope_name), static_cast<std::size_t>(RSTRING_LEN(scope_name))));
|
2006
|
+
VALUE bucket_name = rb_hash_aref(options, rb_id2sym(rb_intern("bucket_name")));
|
2007
|
+
if (NIL_P(bucket_name)) {
|
2008
|
+
exc = rb_exc_new_cstr(
|
2009
|
+
eInvalidArgument, fmt::format("bucket must be specified for query in scope \"{}\"", req.scope_name.value()).c_str());
|
2010
|
+
break;
|
2011
|
+
}
|
2012
|
+
req.bucket_name.emplace(std::string(RSTRING_PTR(bucket_name), static_cast<std::size_t>(RSTRING_LEN(bucket_name))));
|
2013
|
+
}
|
2014
|
+
}
|
1961
2015
|
VALUE profile = rb_hash_aref(options, rb_id2sym(rb_intern("profile")));
|
1962
2016
|
if (!NIL_P(profile)) {
|
1963
2017
|
Check_Type(profile, T_SYMBOL);
|
@@ -2776,6 +2830,14 @@ cb_Backend_query_index_get_all(VALUE self, VALUE bucket_name, VALUE timeout)
|
|
2776
2830
|
rb_ary_push(index_key, rb_str_new(key.data(), static_cast<long>(key.size())));
|
2777
2831
|
}
|
2778
2832
|
rb_hash_aset(index, rb_id2sym(rb_intern("index_key")), index_key);
|
2833
|
+
if (idx.scope_id) {
|
2834
|
+
rb_hash_aset(
|
2835
|
+
index, rb_id2sym(rb_intern("scope_id")), rb_str_new(idx.scope_id->data(), static_cast<long>(idx.scope_id->size())));
|
2836
|
+
}
|
2837
|
+
if (idx.bucket_id) {
|
2838
|
+
rb_hash_aset(
|
2839
|
+
index, rb_id2sym(rb_intern("bucket_id")), rb_str_new(idx.bucket_id->data(), static_cast<long>(idx.bucket_id->size())));
|
2840
|
+
}
|
2779
2841
|
if (idx.condition) {
|
2780
2842
|
rb_hash_aset(
|
2781
2843
|
index, rb_id2sym(rb_intern("condition")), rb_str_new(idx.condition->data(), static_cast<long>(idx.condition->size())));
|
@@ -2840,6 +2902,14 @@ cb_Backend_query_index_create(VALUE self, VALUE bucket_name, VALUE index_name, V
|
|
2840
2902
|
if (!NIL_P(condition)) {
|
2841
2903
|
req.condition.emplace(std::string(RSTRING_PTR(condition), static_cast<std::size_t>(RSTRING_LEN(condition))));
|
2842
2904
|
} /* else use backend default */
|
2905
|
+
VALUE scope_name = rb_hash_aref(options, rb_id2sym(rb_intern("scope_name")));
|
2906
|
+
if (TYPE(scope_name) == T_STRING) {
|
2907
|
+
req.scope_name.assign(RSTRING_PTR(scope_name), static_cast<size_t>(RSTRING_LEN(scope_name)));
|
2908
|
+
}
|
2909
|
+
VALUE collection_name = rb_hash_aref(options, rb_id2sym(rb_intern("collection_name")));
|
2910
|
+
if (TYPE(scope_name) == T_STRING) {
|
2911
|
+
req.collection_name.assign(RSTRING_PTR(collection_name), static_cast<size_t>(RSTRING_LEN(collection_name)));
|
2912
|
+
}
|
2843
2913
|
}
|
2844
2914
|
|
2845
2915
|
auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_create_response>>();
|
@@ -2907,6 +2977,14 @@ cb_Backend_query_index_drop(VALUE self, VALUE bucket_name, VALUE index_name, VAL
|
|
2907
2977
|
} else if (ignore_if_does_not_exist == Qfalse) {
|
2908
2978
|
req.ignore_if_does_not_exist = false;
|
2909
2979
|
} /* else use backend default */
|
2980
|
+
VALUE scope_name = rb_hash_aref(options, rb_id2sym(rb_intern("scope_name")));
|
2981
|
+
if (TYPE(scope_name) == T_STRING) {
|
2982
|
+
req.scope_name.assign(RSTRING_PTR(scope_name), static_cast<size_t>(RSTRING_LEN(scope_name)));
|
2983
|
+
}
|
2984
|
+
VALUE collection_name = rb_hash_aref(options, rb_id2sym(rb_intern("collection_name")));
|
2985
|
+
if (TYPE(scope_name) == T_STRING) {
|
2986
|
+
req.collection_name.assign(RSTRING_PTR(collection_name), static_cast<size_t>(RSTRING_LEN(collection_name)));
|
2987
|
+
}
|
2910
2988
|
}
|
2911
2989
|
|
2912
2990
|
auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_drop_response>>();
|
@@ -2990,6 +3068,14 @@ cb_Backend_query_index_create_primary(VALUE self, VALUE bucket_name, VALUE optio
|
|
2990
3068
|
if (!NIL_P(index_name)) {
|
2991
3069
|
req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
|
2992
3070
|
} /* else use backend default */
|
3071
|
+
VALUE scope_name = rb_hash_aref(options, rb_id2sym(rb_intern("scope_name")));
|
3072
|
+
if (TYPE(scope_name) == T_STRING) {
|
3073
|
+
req.scope_name.assign(RSTRING_PTR(scope_name), static_cast<size_t>(RSTRING_LEN(scope_name)));
|
3074
|
+
}
|
3075
|
+
VALUE collection_name = rb_hash_aref(options, rb_id2sym(rb_intern("collection_name")));
|
3076
|
+
if (TYPE(scope_name) == T_STRING) {
|
3077
|
+
req.collection_name.assign(RSTRING_PTR(collection_name), static_cast<size_t>(RSTRING_LEN(collection_name)));
|
3078
|
+
}
|
2993
3079
|
}
|
2994
3080
|
|
2995
3081
|
auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_create_response>>();
|
@@ -3061,6 +3147,14 @@ cb_Backend_query_index_drop_primary(VALUE self, VALUE bucket_name, VALUE options
|
|
3061
3147
|
req.is_primary = false;
|
3062
3148
|
req.bucket_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
|
3063
3149
|
}
|
3150
|
+
VALUE scope_name = rb_hash_aref(options, rb_id2sym(rb_intern("scope_name")));
|
3151
|
+
if (TYPE(scope_name) == T_STRING) {
|
3152
|
+
req.scope_name.assign(RSTRING_PTR(scope_name), static_cast<size_t>(RSTRING_LEN(scope_name)));
|
3153
|
+
}
|
3154
|
+
VALUE collection_name = rb_hash_aref(options, rb_id2sym(rb_intern("collection_name")));
|
3155
|
+
if (TYPE(scope_name) == T_STRING) {
|
3156
|
+
req.collection_name.assign(RSTRING_PTR(collection_name), static_cast<size_t>(RSTRING_LEN(collection_name)));
|
3157
|
+
}
|
3064
3158
|
}
|
3065
3159
|
|
3066
3160
|
auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_drop_response>>();
|
@@ -5347,7 +5441,7 @@ init_backend(VALUE mCouchbase)
|
|
5347
5441
|
{
|
5348
5442
|
VALUE cBackend = rb_define_class_under(mCouchbase, "Backend", rb_cBasicObject);
|
5349
5443
|
rb_define_alloc_func(cBackend, cb_Backend_allocate);
|
5350
|
-
rb_define_method(cBackend, "open", VALUE_FUNC(cb_Backend_open),
|
5444
|
+
rb_define_method(cBackend, "open", VALUE_FUNC(cb_Backend_open), 3);
|
5351
5445
|
rb_define_method(cBackend, "close", VALUE_FUNC(cb_Backend_close), 0);
|
5352
5446
|
rb_define_method(cBackend, "open_bucket", VALUE_FUNC(cb_Backend_open_bucket), 2);
|
5353
5447
|
|
@@ -5435,11 +5529,13 @@ init_logger()
|
|
5435
5529
|
|
5436
5530
|
auto env_val = spdlog::details::os::getenv("COUCHBASE_BACKEND_LOG_LEVEL");
|
5437
5531
|
if (env_val.empty()) {
|
5438
|
-
spdlog::set_level(spdlog::level::
|
5532
|
+
spdlog::set_level(spdlog::level::warn);
|
5439
5533
|
} else {
|
5440
5534
|
auto levels = spdlog::cfg::helpers::extract_levels(env_val);
|
5441
5535
|
spdlog::details::registry::instance().update_levels(std::move(levels));
|
5442
5536
|
}
|
5537
|
+
|
5538
|
+
couchbase::platform::install_backtrace_terminate_handler();
|
5443
5539
|
}
|
5444
5540
|
|
5445
5541
|
extern "C" {
|
data/ext/couchbase/error_map.hxx
CHANGED
@@ -20,12 +20,112 @@
|
|
20
20
|
namespace couchbase
|
21
21
|
{
|
22
22
|
struct error_map {
|
23
|
+
enum class attribute {
|
24
|
+
/**
|
25
|
+
* The operation was successful for those situations where the error code is indicating successful (i.e. subdoc operations carried
|
26
|
+
* out on a deleted document)
|
27
|
+
*/
|
28
|
+
success,
|
29
|
+
|
30
|
+
/**
|
31
|
+
* This attribute means that the error is related to a constraint failure regarding the item itself, i.e. the item does not exist,
|
32
|
+
* already exists, or its current value makes the current operation impossible. Retrying the operation when the item's value or
|
33
|
+
* status has changed may succeed.
|
34
|
+
*/
|
35
|
+
item_only,
|
36
|
+
|
37
|
+
/**
|
38
|
+
* This attribute means that a user's input was invalid because it violates the semantics of the operation, or exceeds some
|
39
|
+
* predefined limit.
|
40
|
+
*/
|
41
|
+
invalid_input,
|
42
|
+
|
43
|
+
/**
|
44
|
+
* The client's cluster map may be outdated and requires updating. The client should obtain a newer configuration.
|
45
|
+
*/
|
46
|
+
fetch_config,
|
47
|
+
|
48
|
+
/**
|
49
|
+
* The current connection is no longer valid. The client must reconnect to the server. Note that the presence of other attributes
|
50
|
+
* may indicate an alternate remedy to fixing the connection without a disconnect, but without special remedial action a disconnect
|
51
|
+
* is needed.
|
52
|
+
*/
|
53
|
+
conn_state_invalidated,
|
54
|
+
|
55
|
+
/**
|
56
|
+
* The operation failed because the client failed to authenticate or is not authorized to perform this operation. Note that this
|
57
|
+
* error in itself does not mean the connection is invalid, unless conn-state-invalidated is also present.
|
58
|
+
*/
|
59
|
+
auth,
|
60
|
+
|
61
|
+
/**
|
62
|
+
* This error code must be handled specially. If it is not handled, the connection must be dropped.
|
63
|
+
*/
|
64
|
+
special_handling,
|
65
|
+
|
66
|
+
/**
|
67
|
+
* The operation is not supported, possibly because the of server version, bucket type, or current user.
|
68
|
+
*/
|
69
|
+
support,
|
70
|
+
|
71
|
+
/**
|
72
|
+
* This error is transient. Note that this does not mean the error is retriable.
|
73
|
+
*/
|
74
|
+
temp,
|
75
|
+
|
76
|
+
/**
|
77
|
+
* This is an internal error in the server.
|
78
|
+
*/
|
79
|
+
internal,
|
80
|
+
|
81
|
+
/**
|
82
|
+
* The operation may be retried immediately.
|
83
|
+
*/
|
84
|
+
retry_now,
|
85
|
+
|
86
|
+
/**
|
87
|
+
* The operation may be retried after some time.
|
88
|
+
*/
|
89
|
+
retry_later,
|
90
|
+
|
91
|
+
/**
|
92
|
+
* The error is related to the subdocument subsystem.
|
93
|
+
*/
|
94
|
+
subdoc,
|
95
|
+
|
96
|
+
/**
|
97
|
+
* The error is related to the DCP subsystem.
|
98
|
+
*/
|
99
|
+
dcp,
|
100
|
+
|
101
|
+
/**
|
102
|
+
* Use retry specifications from the server.
|
103
|
+
*/
|
104
|
+
auto_retry,
|
105
|
+
|
106
|
+
/**
|
107
|
+
* This attribute specifies that the requested item is currently locked.
|
108
|
+
*/
|
109
|
+
item_locked,
|
110
|
+
|
111
|
+
/**
|
112
|
+
* This attribute means that the error is related to operating on a soft-deleted document.
|
113
|
+
*/
|
114
|
+
item_deleted,
|
115
|
+
};
|
116
|
+
|
23
117
|
struct error_info {
|
24
118
|
std::uint16_t code;
|
25
119
|
std::string name;
|
26
120
|
std::string description;
|
27
|
-
std::set<
|
121
|
+
std::set<attribute> attributes;
|
122
|
+
|
123
|
+
bool has_retry_attribute()
|
124
|
+
{
|
125
|
+
return attributes.find(attribute::retry_now) != attributes.end() || attributes.find(attribute::retry_later) != attributes.end();
|
126
|
+
}
|
28
127
|
};
|
128
|
+
|
29
129
|
uuid::uuid_t id;
|
30
130
|
uint16_t version;
|
31
131
|
uint16_t revision;
|
@@ -51,7 +151,44 @@ struct traits<couchbase::error_map> {
|
|
51
151
|
ei.name = info.at("name").get_string();
|
52
152
|
ei.description = info.at("desc").get_string();
|
53
153
|
for (const auto& a : info.at("attrs").get_array()) {
|
54
|
-
|
154
|
+
const std::string& attr_val = a.get_string();
|
155
|
+
if (attr_val == "success") {
|
156
|
+
ei.attributes.insert(couchbase::error_map::attribute::success);
|
157
|
+
} else if (attr_val == "item-only") {
|
158
|
+
ei.attributes.insert(couchbase::error_map::attribute::item_only);
|
159
|
+
} else if (attr_val == "invalid-input") {
|
160
|
+
ei.attributes.insert(couchbase::error_map::attribute::invalid_input);
|
161
|
+
} else if (attr_val == "fetch-config") {
|
162
|
+
ei.attributes.insert(couchbase::error_map::attribute::fetch_config);
|
163
|
+
} else if (attr_val == "conn-state-invalidated") {
|
164
|
+
ei.attributes.insert(couchbase::error_map::attribute::conn_state_invalidated);
|
165
|
+
} else if (attr_val == "auth") {
|
166
|
+
ei.attributes.insert(couchbase::error_map::attribute::auth);
|
167
|
+
} else if (attr_val == "special-handling") {
|
168
|
+
ei.attributes.insert(couchbase::error_map::attribute::special_handling);
|
169
|
+
} else if (attr_val == "support") {
|
170
|
+
ei.attributes.insert(couchbase::error_map::attribute::support);
|
171
|
+
} else if (attr_val == "temp") {
|
172
|
+
ei.attributes.insert(couchbase::error_map::attribute::temp);
|
173
|
+
} else if (attr_val == "internal") {
|
174
|
+
ei.attributes.insert(couchbase::error_map::attribute::internal);
|
175
|
+
} else if (attr_val == "retry-now") {
|
176
|
+
ei.attributes.insert(couchbase::error_map::attribute::retry_now);
|
177
|
+
} else if (attr_val == "retry-later") {
|
178
|
+
ei.attributes.insert(couchbase::error_map::attribute::retry_later);
|
179
|
+
} else if (attr_val == "subdoc") {
|
180
|
+
ei.attributes.insert(couchbase::error_map::attribute::subdoc);
|
181
|
+
} else if (attr_val == "dcp") {
|
182
|
+
ei.attributes.insert(couchbase::error_map::attribute::dcp);
|
183
|
+
} else if (attr_val == "auto-retry") {
|
184
|
+
ei.attributes.insert(couchbase::error_map::attribute::auto_retry);
|
185
|
+
} else if (attr_val == "item-locked") {
|
186
|
+
ei.attributes.insert(couchbase::error_map::attribute::item_locked);
|
187
|
+
} else if (attr_val == "item-deleted") {
|
188
|
+
ei.attributes.insert(couchbase::error_map::attribute::item_deleted);
|
189
|
+
} else {
|
190
|
+
spdlog::warn(R"(skipping unknown attribute "{}" in error map for code={} and name="{}")", attr_val, ei.code, ei.name);
|
191
|
+
}
|
55
192
|
}
|
56
193
|
result.errors.emplace(ei.code, ei);
|
57
194
|
}
|
@@ -59,3 +196,66 @@ struct traits<couchbase::error_map> {
|
|
59
196
|
}
|
60
197
|
};
|
61
198
|
} // namespace tao::json
|
199
|
+
|
200
|
+
template<>
|
201
|
+
struct fmt::formatter<couchbase::error_map::attribute> : formatter<string_view> {
|
202
|
+
template<typename FormatContext>
|
203
|
+
auto format(couchbase::error_map::attribute attr, FormatContext& ctx)
|
204
|
+
{
|
205
|
+
string_view name = "unknown";
|
206
|
+
switch (attr) {
|
207
|
+
case couchbase::error_map::attribute::success:
|
208
|
+
name = "success";
|
209
|
+
break;
|
210
|
+
case couchbase::error_map::attribute::item_only:
|
211
|
+
name = "item-only";
|
212
|
+
break;
|
213
|
+
case couchbase::error_map::attribute::invalid_input:
|
214
|
+
name = "invalid-input";
|
215
|
+
break;
|
216
|
+
case couchbase::error_map::attribute::fetch_config:
|
217
|
+
name = "fetch-config";
|
218
|
+
break;
|
219
|
+
case couchbase::error_map::attribute::conn_state_invalidated:
|
220
|
+
name = "conn-state-invalidated";
|
221
|
+
break;
|
222
|
+
case couchbase::error_map::attribute::auth:
|
223
|
+
name = "auth";
|
224
|
+
break;
|
225
|
+
case couchbase::error_map::attribute::special_handling:
|
226
|
+
name = "special-handling";
|
227
|
+
break;
|
228
|
+
case couchbase::error_map::attribute::support:
|
229
|
+
name = "support";
|
230
|
+
break;
|
231
|
+
case couchbase::error_map::attribute::temp:
|
232
|
+
name = "temp";
|
233
|
+
break;
|
234
|
+
case couchbase::error_map::attribute::internal:
|
235
|
+
name = "internal";
|
236
|
+
break;
|
237
|
+
case couchbase::error_map::attribute::retry_now:
|
238
|
+
name = "retry-now";
|
239
|
+
break;
|
240
|
+
case couchbase::error_map::attribute::retry_later:
|
241
|
+
name = "retry-later";
|
242
|
+
break;
|
243
|
+
case couchbase::error_map::attribute::subdoc:
|
244
|
+
name = "subdoc";
|
245
|
+
break;
|
246
|
+
case couchbase::error_map::attribute::dcp:
|
247
|
+
name = "dcp";
|
248
|
+
break;
|
249
|
+
case couchbase::error_map::attribute::auto_retry:
|
250
|
+
name = "auto-retry";
|
251
|
+
break;
|
252
|
+
case couchbase::error_map::attribute::item_locked:
|
253
|
+
name = "item-locked";
|
254
|
+
break;
|
255
|
+
case couchbase::error_map::attribute::item_deleted:
|
256
|
+
name = "item-deleted";
|
257
|
+
break;
|
258
|
+
}
|
259
|
+
return formatter<string_view>::format(name, ctx);
|
260
|
+
}
|
261
|
+
};
|