couchbase 3.4.1 → 3.4.2

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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/couchbase/CMakeLists.txt +2 -0
  4. data/ext/couchbase/cmake/ThirdPartyDependencies.cmake +4 -0
  5. data/ext/couchbase/core/cluster_options.hxx +0 -1
  6. data/ext/couchbase/core/config_profile.cxx +23 -1
  7. data/ext/couchbase/core/config_profile.hxx +2 -12
  8. data/ext/couchbase/core/impl/analytics.cxx +236 -0
  9. data/ext/couchbase/core/impl/cluster.cxx +0 -1
  10. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +5 -3
  11. data/ext/couchbase/core/impl/query.cxx +5 -5
  12. data/ext/couchbase/core/io/dns_client.cxx +225 -0
  13. data/ext/couchbase/core/io/dns_client.hxx +19 -188
  14. data/ext/couchbase/core/transactions/active_transaction_record.hxx +2 -2
  15. data/ext/couchbase/core/transactions/attempt_context_impl.cxx +3 -0
  16. data/ext/couchbase/core/transactions/attempt_context_impl.hxx +1 -1
  17. data/ext/couchbase/core/transactions/internal/transaction_context.hxx +12 -12
  18. data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +7 -1
  19. data/ext/couchbase/core/transactions/transaction_context.cxx +1 -0
  20. data/ext/couchbase/core/transactions/transactions_cleanup.cxx +144 -155
  21. data/ext/couchbase/core/utils/connection_string.cxx +10 -3
  22. data/ext/couchbase/core/utils/connection_string.hxx +3 -3
  23. data/ext/couchbase/couchbase/analytics_error_context.hxx +143 -0
  24. data/ext/couchbase/couchbase/analytics_meta_data.hxx +155 -0
  25. data/ext/couchbase/couchbase/analytics_metrics.hxx +163 -0
  26. data/ext/couchbase/couchbase/analytics_options.hxx +359 -0
  27. data/ext/couchbase/couchbase/analytics_result.hxx +102 -0
  28. data/ext/couchbase/couchbase/analytics_scan_consistency.hxx +46 -0
  29. data/ext/couchbase/couchbase/analytics_status.hxx +41 -0
  30. data/ext/couchbase/couchbase/analytics_warning.hxx +85 -0
  31. data/ext/couchbase/couchbase/cluster.hxx +33 -0
  32. data/ext/couchbase/couchbase/fmt/analytics_status.hxx +76 -0
  33. data/ext/couchbase/couchbase/query_options.hxx +0 -1
  34. data/ext/couchbase/couchbase/scope.hxx +33 -0
  35. data/ext/couchbase/couchbase/transactions/attempt_context.hxx +1 -1
  36. data/ext/couchbase/test/CMakeLists.txt +1 -2
  37. data/ext/couchbase/test/test_helper.hxx +1 -1
  38. data/ext/couchbase/test/test_integration_analytics.cxx +289 -13
  39. data/ext/couchbase/test/test_integration_crud.cxx +8 -1
  40. data/ext/couchbase/test/test_integration_examples.cxx +41 -0
  41. data/ext/couchbase/test/test_integration_management.cxx +15 -3
  42. data/ext/couchbase/test/test_integration_search.cxx +601 -0
  43. data/ext/couchbase/test/test_transaction_transaction_simple.cxx +73 -0
  44. data/ext/couchbase/test/test_unit_config_profiles.cxx +12 -12
  45. data/ext/couchbase/test/test_unit_connection_string.cxx +35 -0
  46. data/ext/couchbase/third_party/snappy/CMakeLists.txt +150 -27
  47. data/ext/couchbase/third_party/snappy/cmake/config.h.in +28 -24
  48. data/ext/couchbase/third_party/snappy/snappy-internal.h +189 -25
  49. data/ext/couchbase/third_party/snappy/snappy-sinksource.cc +26 -9
  50. data/ext/couchbase/third_party/snappy/snappy-sinksource.h +11 -11
  51. data/ext/couchbase/third_party/snappy/snappy-stubs-internal.cc +1 -1
  52. data/ext/couchbase/third_party/snappy/snappy-stubs-internal.h +227 -308
  53. data/ext/couchbase/third_party/snappy/snappy-stubs-public.h.in +0 -11
  54. data/ext/couchbase/third_party/snappy/snappy.cc +1176 -410
  55. data/ext/couchbase/third_party/snappy/snappy.h +19 -4
  56. data/ext/couchbase.cxx +27 -6
  57. data/ext/revisions.rb +3 -3
  58. data/lib/couchbase/cluster.rb +13 -9
  59. data/lib/couchbase/cluster_registry.rb +7 -2
  60. data/lib/couchbase/configuration.rb +3 -4
  61. data/lib/couchbase/options.rb +85 -2
  62. data/lib/couchbase/search_options.rb +158 -240
  63. data/lib/couchbase/version.rb +1 -1
  64. metadata +17 -6
  65. data/ext/couchbase/core/CMakeLists.txt +0 -0
@@ -46,9 +46,8 @@ transactions_cleanup::transactions_cleanup(std::shared_ptr<core::cluster> cluste
46
46
  : cluster_(cluster)
47
47
  , config_(config)
48
48
  , client_uuid_(uid_generator::next())
49
- , running_(false)
49
+ , running_(config.cleanup_config.cleanup_client_attempts || config.cleanup_config.cleanup_lost_attempts)
50
50
  {
51
- running_ = config.cleanup_config.cleanup_client_attempts || config.cleanup_config.cleanup_lost_attempts;
52
51
  if (config.cleanup_config.cleanup_client_attempts) {
53
52
  cleanup_thr_ = std::thread(std::bind(&transactions_cleanup::attempts_loop, this));
54
53
  }
@@ -61,14 +60,14 @@ transactions_cleanup::transactions_cleanup(std::shared_ptr<core::cluster> cluste
61
60
  }
62
61
  }
63
62
 
64
- static uint64_t
65
- byteswap64(uint64_t val)
63
+ static std::uint64_t
64
+ byteswap64(std::uint64_t val)
66
65
  {
67
- uint64_t ret = 0;
68
- for (std::size_t ii = 0; ii < sizeof(uint64_t); ii++) {
69
- ret <<= 8ull;
70
- ret |= val & 0xffull;
71
- val >>= 8ull;
66
+ std::uint64_t ret = 0;
67
+ for (std::size_t ii = 0; ii < sizeof(std::uint64_t); ii++) {
68
+ ret <<= 8ULL;
69
+ ret |= val & 0xffULL;
70
+ val >>= 8ULL;
72
71
  }
73
72
  return ret;
74
73
  }
@@ -86,7 +85,7 @@ byteswap64(uint64_t val)
86
85
  * Want: 0x155CD21DA7580000 (1539336197457313792 in base10, an epoch
87
86
  * time in millionths of a second)
88
87
  */
89
- static uint64_t
88
+ static std::uint64_t
90
89
  parse_mutation_cas(const std::string& cas)
91
90
  {
92
91
  if (cas.empty()) {
@@ -114,18 +113,18 @@ transactions_cleanup::interruptable_wait(std::chrono::duration<R, P> delay)
114
113
  {
115
114
  // wait for specified time, _or_ until the condition variable changes
116
115
  std::unique_lock<std::mutex> lock(mutex_);
117
- if (!running_.load()) {
116
+ if (!running_) {
118
117
  return false;
119
118
  }
120
- cv_.wait_for(lock, delay, [&]() { return !running_.load(); });
121
- return running_.load();
119
+ cv_.wait_for(lock, delay, [&]() { return !running_; });
120
+ return running_;
122
121
  }
123
122
 
124
123
  void
125
124
  transactions_cleanup::clean_collection(const couchbase::transactions::transaction_keyspace& keyspace)
126
125
  {
127
126
  // first make sure the collection is in the list
128
- while (running_.load()) {
127
+ while (is_running()) {
129
128
  {
130
129
  std::lock_guard<std::mutex> lock(mutex_);
131
130
  if (collections_.end() == std::find(collections_.begin(), collections_.end(), keyspace)) {
@@ -158,7 +157,7 @@ transactions_cleanup::clean_collection(const couchbase::transactions::transactio
158
157
  remaining_in_cleanup_window.count() / std::max<decltype(it)::difference_type>(1, atrs_left_for_this_client));
159
158
  // clean the ATR entry
160
159
  std::string atr_id = *it;
161
- if (!running_.load()) {
160
+ if (!is_running()) {
162
161
  CB_LOST_ATTEMPT_CLEANUP_LOG_DEBUG("cleanup of {} complete", keyspace);
163
162
  return;
164
163
  }
@@ -186,7 +185,9 @@ transactions_cleanup::clean_collection(const couchbase::transactions::transactio
186
185
  atr_left.count());*/
187
186
 
188
187
  if (atr_left.count() > 0 && atr_left.count() < 1000000000) { // safety check protects against bugs
189
- std::this_thread::sleep_for(atr_left);
188
+ if (!interruptable_wait(atr_left)) {
189
+ return;
190
+ }
190
191
  }
191
192
  }
192
193
  } catch (const std::exception& ex) {
@@ -212,16 +213,16 @@ transactions_cleanup::handle_atr_cleanup(const core::document_id& atr_id, std::v
212
213
  // check_if_expired to false.
213
214
  atr_cleanup_entry cleanup_entry(entry, atr_id, *this, results == nullptr);
214
215
  try {
215
- if (results) {
216
+ if (results != nullptr) {
216
217
  results->emplace_back(cleanup_entry);
217
218
  }
218
- cleanup_entry.clean(results ? &results->back() : nullptr);
219
- if (results) {
219
+ cleanup_entry.clean(results != nullptr ? &results->back() : nullptr);
220
+ if (results != nullptr) {
220
221
  results->back().success(true);
221
222
  }
222
223
  } catch (const std::exception& e) {
223
224
  CB_LOST_ATTEMPT_CLEANUP_LOG_ERROR("cleanup of {} failed: {}, moving on", cleanup_entry, e.what());
224
- if (results) {
225
+ if (results != nullptr) {
225
226
  results->back().success(false);
226
227
  }
227
228
  }
@@ -273,135 +274,127 @@ transactions_cleanup::create_client_record(const couchbase::transactions::transa
273
274
  const client_record_details
274
275
  transactions_cleanup::get_active_clients(const couchbase::transactions::transaction_keyspace& keyspace, const std::string& uuid)
275
276
  {
276
- std::chrono::milliseconds min_retry(1000);
277
- if (config_.cleanup_config.cleanup_window < min_retry) {
278
- min_retry = config_.cleanup_config.cleanup_window;
279
- }
280
- return retry_op_exponential_backoff_timeout<client_record_details>(
281
- min_retry, std::chrono::seconds(1), config_.cleanup_config.cleanup_window, [this, keyspace, uuid]() -> client_record_details {
282
- client_record_details details;
283
- // Write our client record, return details.
284
- try {
285
- auto id = document_id{ keyspace.bucket, keyspace.scope, keyspace.collection, CLIENT_RECORD_DOC_ID };
286
- core::operations::lookup_in_request req{ id };
287
- req.specs =
288
- lookup_in_specs{
289
- lookup_in_specs::get(FIELD_RECORDS).xattr(),
290
- lookup_in_specs::get(subdoc::lookup_in_macro::vbucket).xattr(),
291
- }
292
- .specs();
293
- wrap_request(req, config_);
294
- auto barrier = std::make_shared<std::promise<result>>();
295
- auto f = barrier->get_future();
296
- auto ec = config_.cleanup_hooks->client_record_before_get(keyspace.bucket);
297
- if (ec) {
298
- throw client_error(*ec, "client_record_before_get hook raised error");
299
- }
300
- cluster_->execute(req, [barrier](core::operations::lookup_in_response resp) {
301
- barrier->set_value(result::create_from_subdoc_response(resp));
302
- });
303
- auto res = wrap_operation_future(f);
304
- std::vector<std::string> active_client_uids;
305
- auto hlc = res.values[1].content_as();
306
- auto now_ms = now_ns_from_vbucket(hlc) / 1000000;
307
- details.override_enabled = false;
308
- details.override_expires = 0;
309
- if (res.values[0].status == subdoc_result::status_type::success) {
310
- auto records = res.values[0].content_as();
311
- CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("client records: {}", core::utils::json::generate(records));
312
- for (const auto& [key, value] : records.get_object()) {
313
- if (key == FIELD_OVERRIDE) {
314
- for (const auto& [override, param] : value.get_object()) {
315
- if (override == FIELD_OVERRIDE_ENABLED) {
316
- details.override_enabled = param.get_boolean();
317
- } else if (override == FIELD_OVERRIDE_EXPIRES) {
318
- details.override_expires = param.as<std::uint64_t>();
319
- }
320
- }
321
- } else if (key == FIELD_CLIENTS_ONLY) {
322
- for (const auto& [other_client_uuid, cl] : value.get_object()) {
323
- uint64_t heartbeat_ms = parse_mutation_cas(cl.at(FIELD_HEARTBEAT).get_string());
324
- auto expires_ms = cl.at(FIELD_EXPIRES).as<std::uint64_t>();
325
- auto expired_period = static_cast<int64_t>(now_ms) - static_cast<int64_t>(heartbeat_ms);
326
- bool has_expired = expired_period >= static_cast<int64_t>(expires_ms) && now_ms > heartbeat_ms;
327
- if (has_expired && other_client_uuid != uuid) {
328
- details.expired_client_ids.push_back(other_client_uuid);
329
- } else {
330
- active_client_uids.push_back(other_client_uuid);
331
- }
332
- }
333
- }
334
- }
335
- }
336
- if (std::find(active_client_uids.begin(), active_client_uids.end(), uuid) == active_client_uids.end()) {
337
- active_client_uids.push_back(uuid);
338
- }
339
- std::sort(active_client_uids.begin(), active_client_uids.end());
340
- auto this_idx =
341
- std::distance(active_client_uids.begin(), std::find(active_client_uids.begin(), active_client_uids.end(), uuid));
342
- details.num_active_clients = static_cast<std::uint32_t>(active_client_uids.size());
343
- details.index_of_this_client = static_cast<std::uint32_t>(this_idx);
344
- details.num_active_clients = static_cast<std::uint32_t>(active_client_uids.size());
345
- details.num_expired_clients = static_cast<std::uint32_t>(details.expired_client_ids.size());
346
- details.num_existing_clients = details.num_expired_clients + details.num_active_clients;
347
- details.client_uuid = uuid;
348
- details.cas_now_nanos = now_ms * 1000000;
349
- details.override_active = (details.override_enabled && details.override_expires > details.cas_now_nanos);
350
- CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("client details {}", details);
351
- if (details.override_active) {
352
- CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("override enabled, will not update record");
353
- return details;
354
- }
355
-
356
- // update client record, maybe cleanup some as well...
357
- core::operations::mutate_in_request mutate_req{ id };
358
- auto mut_specs = couchbase::mutate_in_specs{
359
- couchbase::mutate_in_specs::upsert(FIELD_CLIENTS + "." + uuid + "." + FIELD_HEARTBEAT, subdoc::mutate_in_macro::cas)
360
- .xattr()
361
- .create_path(),
362
- couchbase::mutate_in_specs::upsert(FIELD_CLIENTS + "." + uuid + "." + FIELD_EXPIRES,
363
- config_.cleanup_config.cleanup_window.count() / 2 + SAFETY_MARGIN_EXPIRY_MS)
364
- .xattr()
365
- .create_path(),
366
- couchbase::mutate_in_specs::upsert(FIELD_CLIENTS + "." + uuid + "." + FIELD_NUM_ATRS, atr_ids::all().size())
367
- .xattr()
368
- .create_path(),
369
- };
370
- for (std::size_t idx = 0; idx < std::min(details.expired_client_ids.size(), static_cast<std::size_t>(12)); idx++) {
371
- CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("adding {} to list of clients to be removed when updating this client",
372
- details.expired_client_ids[idx]);
373
- mut_specs.push_back(couchbase::mutate_in_specs::remove(FIELD_CLIENTS + "." + details.expired_client_ids[idx]).xattr());
374
- }
375
- mutate_req.specs = mut_specs.specs();
376
- ec = config_.cleanup_hooks->client_record_before_update(keyspace.bucket);
377
- if (ec) {
378
- throw client_error(*ec, "client_record_before_update hook raised error");
379
- }
380
- wrap_durable_request(mutate_req, config_);
381
- auto mutate_barrier = std::make_shared<std::promise<result>>();
382
- auto mutate_f = mutate_barrier->get_future();
383
- CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("updating record");
384
- cluster_->execute(mutate_req, [mutate_barrier](core::operations::mutate_in_response resp) {
385
- mutate_barrier->set_value(result::create_from_subdoc_response(resp));
386
- });
387
- res = wrap_operation_future(mutate_f);
388
-
389
- // just update the cas, and return the details
390
- details.cas_now_nanos = res.cas;
391
- CB_LOST_ATTEMPT_CLEANUP_LOG_DEBUG("get_active_clients found {}", details);
392
- return details;
393
- } catch (const client_error& e) {
394
- auto ec = e.ec();
395
- switch (ec) {
396
- case FAIL_DOC_NOT_FOUND:
397
- CB_LOST_ATTEMPT_CLEANUP_LOG_DEBUG("client record not found, creating new one");
398
- create_client_record(keyspace);
399
- throw retry_operation("Client record didn't exist. Creating and retrying");
400
- default:
401
- throw;
402
- }
277
+ client_record_details details;
278
+ // Write our client record, return details.
279
+ try {
280
+ auto id = document_id{ keyspace.bucket, keyspace.scope, keyspace.collection, CLIENT_RECORD_DOC_ID };
281
+ core::operations::lookup_in_request req{ id };
282
+ req.specs =
283
+ lookup_in_specs{
284
+ lookup_in_specs::get(FIELD_RECORDS).xattr(),
285
+ lookup_in_specs::get(subdoc::lookup_in_macro::vbucket).xattr(),
403
286
  }
404
- });
287
+ .specs();
288
+ wrap_request(req, config_);
289
+ auto barrier = std::make_shared<std::promise<result>>();
290
+ auto f = barrier->get_future();
291
+ auto ec = config_.cleanup_hooks->client_record_before_get(keyspace.bucket);
292
+ if (ec) {
293
+ throw client_error(*ec, "client_record_before_get hook raised error");
294
+ }
295
+ cluster_->execute(
296
+ req, [barrier](core::operations::lookup_in_response resp) { barrier->set_value(result::create_from_subdoc_response(resp)); });
297
+ auto res = wrap_operation_future(f);
298
+
299
+ std::vector<std::string> active_client_uids;
300
+ auto hlc = res.values[1].content_as();
301
+ auto now_ms = now_ns_from_vbucket(hlc) / 1000000;
302
+ details.override_enabled = false;
303
+ details.override_expires = 0;
304
+ if (res.values[0].status == subdoc_result::status_type::success) {
305
+ auto records = res.values[0].content_as();
306
+ CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("client records: {}", core::utils::json::generate(records));
307
+ for (const auto& [key, value] : records.get_object()) {
308
+ if (key == FIELD_OVERRIDE) {
309
+ for (const auto& [over_ride, param] : value.get_object()) {
310
+ if (over_ride == FIELD_OVERRIDE_ENABLED) {
311
+ details.override_enabled = param.get_boolean();
312
+ } else if (over_ride == FIELD_OVERRIDE_EXPIRES) {
313
+ details.override_expires = param.as<std::uint64_t>();
314
+ }
315
+ }
316
+ } else if (key == FIELD_CLIENTS_ONLY) {
317
+ for (const auto& [other_client_uuid, cl] : value.get_object()) {
318
+ std::uint64_t heartbeat_ms = parse_mutation_cas(cl.at(FIELD_HEARTBEAT).get_string());
319
+ auto expires_ms = cl.at(FIELD_EXPIRES).as<std::uint64_t>();
320
+ auto expired_period = static_cast<std::int64_t>(now_ms) - static_cast<std::int64_t>(heartbeat_ms);
321
+ bool has_expired = expired_period >= static_cast<std::int64_t>(expires_ms) && now_ms > heartbeat_ms;
322
+ if (has_expired && other_client_uuid != uuid) {
323
+ details.expired_client_ids.push_back(other_client_uuid);
324
+ } else {
325
+ active_client_uids.push_back(other_client_uuid);
326
+ }
327
+ }
328
+ }
329
+ }
330
+ }
331
+ if (std::find(active_client_uids.begin(), active_client_uids.end(), uuid) == active_client_uids.end()) {
332
+ active_client_uids.push_back(uuid);
333
+ }
334
+ std::sort(active_client_uids.begin(), active_client_uids.end());
335
+ auto this_idx = std::distance(active_client_uids.begin(), std::find(active_client_uids.begin(), active_client_uids.end(), uuid));
336
+ details.num_active_clients = static_cast<std::uint32_t>(active_client_uids.size());
337
+ details.index_of_this_client = static_cast<std::uint32_t>(this_idx);
338
+ details.num_active_clients = static_cast<std::uint32_t>(active_client_uids.size());
339
+ details.num_expired_clients = static_cast<std::uint32_t>(details.expired_client_ids.size());
340
+ details.num_existing_clients = details.num_expired_clients + details.num_active_clients;
341
+ details.client_uuid = uuid;
342
+ details.cas_now_nanos = now_ms * 1000000;
343
+ details.override_active = (details.override_enabled && details.override_expires > details.cas_now_nanos);
344
+ CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("client details {}", details);
345
+ if (details.override_active) {
346
+ CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("override enabled, will not update record");
347
+ return details;
348
+ }
349
+
350
+ // update client record, maybe cleanup some as well...
351
+ core::operations::mutate_in_request mutate_req{ id };
352
+ auto mut_specs = couchbase::mutate_in_specs{
353
+ couchbase::mutate_in_specs::upsert(FIELD_CLIENTS + "." + uuid + "." + FIELD_HEARTBEAT, subdoc::mutate_in_macro::cas)
354
+ .xattr()
355
+ .create_path(),
356
+ couchbase::mutate_in_specs::upsert(FIELD_CLIENTS + "." + uuid + "." + FIELD_EXPIRES,
357
+ config_.cleanup_config.cleanup_window.count() / 2 + SAFETY_MARGIN_EXPIRY_MS)
358
+ .xattr()
359
+ .create_path(),
360
+ couchbase::mutate_in_specs::upsert(FIELD_CLIENTS + "." + uuid + "." + FIELD_NUM_ATRS, atr_ids::all().size())
361
+ .xattr()
362
+ .create_path(),
363
+ };
364
+ for (std::size_t idx = 0; idx < std::min(details.expired_client_ids.size(), static_cast<std::size_t>(12)); idx++) {
365
+ CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("adding {} to list of clients to be removed when updating this client",
366
+ details.expired_client_ids[idx]);
367
+ mut_specs.push_back(couchbase::mutate_in_specs::remove(FIELD_CLIENTS + "." + details.expired_client_ids[idx]).xattr());
368
+ }
369
+ mutate_req.specs = mut_specs.specs();
370
+ ec = config_.cleanup_hooks->client_record_before_update(keyspace.bucket);
371
+ if (ec) {
372
+ throw client_error(*ec, "client_record_before_update hook raised error");
373
+ }
374
+ wrap_durable_request(mutate_req, config_);
375
+ auto mutate_barrier = std::make_shared<std::promise<result>>();
376
+ auto mutate_f = mutate_barrier->get_future();
377
+ CB_LOST_ATTEMPT_CLEANUP_LOG_TRACE("updating record");
378
+ cluster_->execute(mutate_req, [mutate_barrier](core::operations::mutate_in_response resp) {
379
+ mutate_barrier->set_value(result::create_from_subdoc_response(resp));
380
+ });
381
+ res = wrap_operation_future(mutate_f);
382
+
383
+ // just update the cas, and return the details
384
+ details.cas_now_nanos = res.cas;
385
+ CB_LOST_ATTEMPT_CLEANUP_LOG_DEBUG("get_active_clients found {}", details);
386
+ return details;
387
+ } catch (const client_error& e) {
388
+ auto ec = e.ec();
389
+ switch (ec) {
390
+ case FAIL_DOC_NOT_FOUND:
391
+ CB_LOST_ATTEMPT_CLEANUP_LOG_DEBUG("client record not found, creating new one");
392
+ create_client_record(keyspace);
393
+ return get_active_clients(keyspace, uuid);
394
+ default:
395
+ throw;
396
+ }
397
+ }
405
398
  }
406
399
 
407
400
  void
@@ -412,9 +405,7 @@ transactions_cleanup::remove_client_record_from_all_buckets(const std::string& u
412
405
  retry_op_exponential_backoff_timeout<void>(
413
406
  std::chrono::milliseconds(10), std::chrono::milliseconds(250), std::chrono::milliseconds(500), [this, keyspace, uuid]() {
414
407
  try {
415
- // insure a client record document exists...
416
- create_client_record(keyspace);
417
- // now, proceed to remove the client uuid if it exists
408
+ // proceed to remove the client uuid if it exists
418
409
  auto ec = config_.cleanup_hooks->client_record_before_remove_client(keyspace.bucket);
419
410
  if (ec) {
420
411
  throw client_error(*ec, "client_record_before_remove_client hook raised error");
@@ -502,7 +493,7 @@ transactions_cleanup::attempts_loop()
502
493
  CB_ATTEMPT_CLEANUP_LOG_DEBUG("cleanup attempts loop starting...");
503
494
  while (interruptable_wait(cleanup_loop_delay_)) {
504
495
  while (auto entry = atr_queue_.pop()) {
505
- if (!running_.load()) {
496
+ if (!is_running()) {
506
497
  CB_ATTEMPT_CLEANUP_LOG_DEBUG("loop stopping - {} entries on queue", atr_queue_.size());
507
498
  return;
508
499
  }
@@ -580,9 +571,7 @@ transactions_cleanup::close()
580
571
  }
581
572
  }
582
573
  CB_LOST_ATTEMPT_CLEANUP_LOG_DEBUG("all lost attempt cleanup threads closed");
583
- if (true) {
584
- remove_client_record_from_all_buckets(client_uuid_);
585
- }
574
+ remove_client_record_from_all_buckets(client_uuid_);
586
575
  }
587
576
 
588
577
  transactions_cleanup::~transactions_cleanup()
@@ -51,18 +51,22 @@ using opt_bucket_name = opt_must<one<'/'>, bucket_name>;
51
51
  using opt_params = opt_must<one<'?'>, list_must<param, one<'&'>>>;
52
52
  using opt_nodes = seq<list_must<node, one<',', ';'>>, opt_bucket_name>;
53
53
 
54
- using grammar = must<seq<uri::scheme, one<':'>, uri::dslash, opt_nodes, opt_params, tao::pegtl::eof>>;
54
+ struct scheme : seq<uri::scheme, one<':'>, uri::dslash> {
55
+ };
56
+ using opt_scheme = opt<scheme>;
57
+
58
+ using grammar = must<seq<opt_scheme, opt_nodes, opt_params, tao::pegtl::eof>>;
55
59
 
56
60
  template<typename Rule>
57
61
  struct action {
58
62
  };
59
63
 
60
64
  template<>
61
- struct action<uri::scheme> {
65
+ struct action<scheme> {
62
66
  template<typename ActionInput>
63
67
  static void apply(const ActionInput& in, connection_string& cs, connection_string::node& /* cur_node */)
64
68
  {
65
- cs.scheme = in.string();
69
+ cs.scheme = in.string().substr(0, in.string().rfind(':'));
66
70
  if (cs.scheme == "couchbase") {
67
71
  cs.default_port = 11210;
68
72
  cs.default_mode = connection_string::bootstrap_mode::gcccp;
@@ -79,6 +83,9 @@ struct action<uri::scheme> {
79
83
  cs.default_port = 18091;
80
84
  cs.default_mode = connection_string::bootstrap_mode::http;
81
85
  cs.tls = true;
86
+ } else {
87
+ cs.default_mode = connection_string::bootstrap_mode::unspecified;
88
+ cs.default_port = 0;
82
89
  }
83
90
  }
84
91
  };
@@ -57,7 +57,7 @@ struct connection_string {
57
57
  }
58
58
  };
59
59
 
60
- std::string scheme{};
60
+ std::string scheme{ "couchbase" };
61
61
  bool tls{ false };
62
62
  std::map<std::string, std::string> params{};
63
63
  cluster_options options{};
@@ -65,8 +65,8 @@ struct connection_string {
65
65
  std::vector<node> bootstrap_nodes{};
66
66
 
67
67
  std::optional<std::string> default_bucket_name{};
68
- bootstrap_mode default_mode{ bootstrap_mode::unspecified };
69
- std::uint16_t default_port{ 0 };
68
+ bootstrap_mode default_mode{ connection_string::bootstrap_mode::gcccp };
69
+ std::uint16_t default_port{ 11210 };
70
70
 
71
71
  std::optional<std::string> error{};
72
72
  };
@@ -0,0 +1,143 @@
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 <couchbase/error_context.hxx>
21
+
22
+ #include <cstdint>
23
+ #include <optional>
24
+
25
+ namespace couchbase
26
+ {
27
+ /**
28
+ * The error context returned with Query operations.
29
+ *
30
+ * @since 1.0.0
31
+ * @committed
32
+ */
33
+ class analytics_error_context : public error_context
34
+ {
35
+ public:
36
+ /**
37
+ * Creates empty error context
38
+ *
39
+ * @since 1.0.0
40
+ * @committed
41
+ */
42
+ analytics_error_context() = default;
43
+
44
+ analytics_error_context(std::error_code ec,
45
+ std::optional<std::string> last_dispatched_to,
46
+ std::optional<std::string> last_dispatched_from,
47
+ std::size_t retry_attempts,
48
+ std::set<retry_reason> retry_reasons,
49
+ std::uint64_t first_error_code,
50
+ std::string first_error_message,
51
+ std::string client_context_id,
52
+ std::string statement,
53
+ std::optional<std::string> parameters,
54
+ std::string method,
55
+ std::string path,
56
+ std::uint32_t http_status,
57
+ std::string http_body,
58
+ std::string hostname,
59
+ std::uint16_t port)
60
+ : error_context{ ec, std::move(last_dispatched_to), std::move(last_dispatched_from), retry_attempts, std::move(retry_reasons) }
61
+ , first_error_code_{ first_error_code }
62
+ , first_error_message_{ std::move(first_error_message) }
63
+ , client_context_id_{ std::move(client_context_id) }
64
+ , statement_{ std::move(statement) }
65
+ , parameters_{ std::move(parameters) }
66
+ , method_{ std::move(method) }
67
+ , path_{ std::move(path) }
68
+ , http_status_{ http_status }
69
+ , http_body_{ std::move(http_body) }
70
+ , hostname_{ std::move(hostname) }
71
+ , port_{ port }
72
+ {
73
+ }
74
+
75
+ [[nodiscard]] auto first_error_code() const -> std::uint64_t
76
+ {
77
+ return first_error_code_;
78
+ }
79
+
80
+ [[nodiscard]] auto first_error_message() const -> const std::string&
81
+ {
82
+ return first_error_message_;
83
+ }
84
+
85
+ [[nodiscard]] auto client_context_id() const -> const std::string&
86
+ {
87
+ return client_context_id_;
88
+ }
89
+
90
+ [[nodiscard]] auto statement() const -> const std::string&
91
+ {
92
+ return statement_;
93
+ }
94
+
95
+ [[nodiscard]] auto parameters() const -> const std::optional<std::string>&
96
+ {
97
+ return parameters_;
98
+ }
99
+
100
+ [[nodiscard]] auto method() const -> const std::string&
101
+ {
102
+ return method_;
103
+ }
104
+
105
+ [[nodiscard]] auto path() const -> const std::string&
106
+ {
107
+ return path_;
108
+ }
109
+
110
+ [[nodiscard]] auto http_status() const -> std::uint32_t
111
+ {
112
+ return http_status_;
113
+ }
114
+
115
+ [[nodiscard]] auto http_body() const -> const std::string&
116
+ {
117
+ return http_body_;
118
+ }
119
+
120
+ [[nodiscard]] auto hostname() const -> const std::string&
121
+ {
122
+ return hostname_;
123
+ }
124
+
125
+ [[nodiscard]] auto port() const -> std::uint16_t
126
+ {
127
+ return port_;
128
+ }
129
+
130
+ private:
131
+ std::uint64_t first_error_code_{};
132
+ std::string first_error_message_{};
133
+ std::string client_context_id_{};
134
+ std::string statement_{};
135
+ std::optional<std::string> parameters_{};
136
+ std::string method_{};
137
+ std::string path_{};
138
+ std::uint32_t http_status_{};
139
+ std::string http_body_{};
140
+ std::string hostname_{};
141
+ std::uint16_t port_{};
142
+ };
143
+ } // namespace couchbase