couchbase 3.4.0 → 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.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/ext/couchbase/CMakeLists.txt +10 -3
- data/ext/couchbase/cmake/CompilerWarnings.cmake +12 -4
- data/ext/couchbase/cmake/Documentation.cmake +4 -3
- data/ext/couchbase/cmake/OpenSSL.cmake +52 -7
- data/ext/couchbase/cmake/ThirdPartyDependencies.cmake +4 -0
- data/ext/couchbase/cmake/VersionInfo.cmake +39 -3
- data/ext/couchbase/cmake/test_openssl.cxx +7 -0
- data/ext/couchbase/core/cluster_options.hxx +0 -1
- data/ext/couchbase/core/config_profile.cxx +23 -1
- data/ext/couchbase/core/config_profile.hxx +2 -12
- data/ext/couchbase/core/crypto/CMakeLists.txt +5 -1
- data/ext/couchbase/core/impl/analytics.cxx +236 -0
- data/ext/couchbase/core/impl/cluster.cxx +0 -1
- data/ext/couchbase/core/impl/collection_query_index_manager.cxx +3 -3
- data/ext/couchbase/core/impl/dns_srv_tracker.cxx +5 -3
- data/ext/couchbase/core/impl/get_all_query_indexes.cxx +3 -3
- data/ext/couchbase/core/impl/query.cxx +5 -5
- data/ext/couchbase/core/impl/transaction_get_result.cxx +54 -0
- data/ext/couchbase/core/io/dns_client.cxx +225 -0
- data/ext/couchbase/core/io/dns_client.hxx +19 -188
- data/ext/couchbase/core/meta/CMakeLists.txt +7 -5
- data/ext/couchbase/core/meta/version.cxx +19 -0
- data/ext/couchbase/core/operations/document_search.cxx +5 -2
- data/ext/couchbase/core/operations/document_search.hxx +0 -1
- data/ext/couchbase/core/transactions/active_transaction_record.hxx +2 -2
- data/ext/couchbase/core/transactions/atr_cleanup_entry.cxx +1 -0
- data/ext/couchbase/core/transactions/attempt_context_impl.cxx +65 -31
- data/ext/couchbase/core/transactions/attempt_context_impl.hxx +44 -23
- data/ext/couchbase/core/transactions/forward_compat.hxx +2 -2
- data/ext/couchbase/core/transactions/internal/transaction_context.hxx +13 -13
- data/ext/couchbase/core/transactions/internal/transaction_fields.hxx +1 -0
- data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +7 -1
- data/ext/couchbase/core/transactions/staged_mutation.cxx +1 -1
- data/ext/couchbase/core/transactions/staged_mutation.hxx +12 -2
- data/ext/couchbase/core/transactions/transaction_context.cxx +9 -11
- data/ext/couchbase/core/transactions/transaction_get_result.cxx +41 -31
- data/ext/couchbase/core/transactions/transaction_get_result.hxx +7 -3
- data/ext/couchbase/core/transactions/transaction_links.hxx +13 -1
- data/ext/couchbase/core/transactions/transactions_cleanup.cxx +144 -155
- data/ext/couchbase/core/transactions/waitable_op_list.hxx +1 -0
- data/ext/couchbase/core/utils/connection_string.cxx +10 -3
- data/ext/couchbase/core/utils/connection_string.hxx +3 -3
- data/ext/couchbase/couchbase/analytics_error_context.hxx +143 -0
- data/ext/couchbase/couchbase/analytics_meta_data.hxx +155 -0
- data/ext/couchbase/couchbase/analytics_metrics.hxx +163 -0
- data/ext/couchbase/couchbase/analytics_options.hxx +359 -0
- data/ext/couchbase/couchbase/analytics_result.hxx +102 -0
- data/ext/couchbase/couchbase/analytics_scan_consistency.hxx +46 -0
- data/ext/couchbase/couchbase/analytics_status.hxx +41 -0
- data/ext/couchbase/couchbase/analytics_warning.hxx +85 -0
- data/ext/couchbase/couchbase/cluster.hxx +35 -2
- data/ext/couchbase/couchbase/cluster_options.hxx +10 -10
- data/ext/couchbase/couchbase/collection.hxx +22 -17
- data/ext/couchbase/couchbase/collection_query_index_manager.hxx +1 -1
- data/ext/couchbase/couchbase/common_options.hxx +1 -1
- data/ext/couchbase/couchbase/configuration_profile.hxx +1 -1
- data/ext/couchbase/couchbase/configuration_profiles_registry.hxx +0 -1
- data/ext/couchbase/couchbase/create_primary_query_index_options.hxx +1 -1
- data/ext/couchbase/couchbase/drop_primary_query_index_options.hxx +1 -1
- data/ext/couchbase/couchbase/drop_query_index_options.hxx +1 -1
- data/ext/couchbase/couchbase/fmt/analytics_status.hxx +76 -0
- data/ext/couchbase/couchbase/fmt/cas.hxx +12 -0
- data/ext/couchbase/couchbase/fmt/durability_level.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/key_value_extended_error_info.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/key_value_status_code.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/mutation_token.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/query_scan_consistency.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/query_status.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/retry_reason.hxx +6 -0
- data/ext/couchbase/couchbase/fmt/tls_verify_mode.hxx +6 -0
- data/ext/couchbase/couchbase/get_all_query_indexes_options.hxx +5 -4
- data/ext/couchbase/couchbase/query_index_manager.hxx +4 -2
- data/ext/couchbase/couchbase/query_options.hxx +0 -1
- data/ext/couchbase/couchbase/scope.hxx +34 -1
- data/ext/couchbase/couchbase/subdoc/array_add_unique.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/array_append.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/array_insert.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/array_prepend.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/count.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/counter.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/exists.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/get.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/insert.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/remove.hxx +2 -0
- data/ext/couchbase/couchbase/subdoc/replace.hxx +3 -1
- data/ext/couchbase/couchbase/subdoc/upsert.hxx +2 -0
- data/ext/couchbase/couchbase/transaction_op_error_context.hxx +4 -4
- data/ext/couchbase/couchbase/transactions/attempt_context.hxx +1 -1
- data/ext/couchbase/couchbase/transactions/transaction_get_result.hxx +36 -51
- data/ext/couchbase/couchbase/transactions/transactions_config.hxx +1 -1
- data/ext/couchbase/test/CMakeLists.txt +3 -2
- data/ext/couchbase/test/test_helper.hxx +1 -1
- data/ext/couchbase/test/test_integration_analytics.cxx +289 -13
- data/ext/couchbase/test/test_integration_crud.cxx +8 -1
- data/ext/couchbase/test/test_integration_examples.cxx +182 -0
- data/ext/couchbase/test/test_integration_management.cxx +15 -3
- data/ext/couchbase/test/test_integration_search.cxx +601 -0
- data/ext/couchbase/test/test_transaction_transaction_simple.cxx +73 -0
- data/ext/couchbase/test/test_unit_config_profiles.cxx +12 -12
- data/ext/couchbase/test/test_unit_connection_string.cxx +35 -0
- data/ext/couchbase/test/test_unit_transaction_utils.cxx +76 -19
- data/ext/couchbase/third_party/snappy/CMakeLists.txt +150 -27
- data/ext/couchbase/third_party/snappy/cmake/config.h.in +28 -24
- data/ext/couchbase/third_party/snappy/snappy-internal.h +189 -25
- data/ext/couchbase/third_party/snappy/snappy-sinksource.cc +26 -9
- data/ext/couchbase/third_party/snappy/snappy-sinksource.h +11 -11
- data/ext/couchbase/third_party/snappy/snappy-stubs-internal.cc +1 -1
- data/ext/couchbase/third_party/snappy/snappy-stubs-internal.h +227 -308
- data/ext/couchbase/third_party/snappy/snappy-stubs-public.h.in +0 -11
- data/ext/couchbase/third_party/snappy/snappy.cc +1176 -410
- data/ext/couchbase/third_party/snappy/snappy.h +19 -4
- data/ext/couchbase.cxx +506 -26
- data/ext/extconf.rb +2 -1
- data/ext/revisions.rb +3 -2
- data/lib/couchbase/binary_collection.rb +4 -4
- data/lib/couchbase/cluster.rb +13 -9
- data/lib/couchbase/cluster_registry.rb +7 -2
- data/lib/couchbase/collection.rb +5 -0
- data/lib/couchbase/configuration.rb +3 -4
- data/lib/couchbase/errors.rb +10 -0
- data/lib/couchbase/management/collection_query_index_manager.rb +183 -0
- data/lib/couchbase/management/query_index_manager.rb +35 -3
- data/lib/couchbase/management.rb +1 -0
- data/lib/couchbase/options.rb +87 -5
- data/lib/couchbase/search_options.rb +158 -240
- data/lib/couchbase/version.rb +1 -1
- metadata +21 -6
- data/ext/couchbase/core/CMakeLists.txt +0 -0
|
@@ -174,6 +174,7 @@ atr_cleanup_entry::do_per_doc(std::vector<doc_record> docs,
|
|
|
174
174
|
lookup_in_specs::get(ATR_ID).xattr(),
|
|
175
175
|
lookup_in_specs::get(TRANSACTION_ID).xattr(),
|
|
176
176
|
lookup_in_specs::get(ATTEMPT_ID).xattr(),
|
|
177
|
+
lookup_in_specs::get(OPERATION_ID).xattr(),
|
|
177
178
|
lookup_in_specs::get(STAGED_DATA).xattr(),
|
|
178
179
|
lookup_in_specs::get(ATR_BUCKET_NAME).xattr(),
|
|
179
180
|
lookup_in_specs::get(ATR_SCOPE_NAME).xattr(),
|
|
@@ -243,6 +243,7 @@ core::operations::mutate_in_request
|
|
|
243
243
|
attempt_context_impl::create_staging_request(const core::document_id& id,
|
|
244
244
|
const transaction_get_result* document,
|
|
245
245
|
const std::string type,
|
|
246
|
+
const std::string op_id,
|
|
246
247
|
std::optional<std::vector<std::byte>> content)
|
|
247
248
|
{
|
|
248
249
|
core::operations::mutate_in_request req{ id };
|
|
@@ -250,6 +251,7 @@ attempt_context_impl::create_staging_request(const core::document_id& id,
|
|
|
250
251
|
txn["id"] = tao::json::empty_object;
|
|
251
252
|
txn["id"]["txn"] = transaction_id();
|
|
252
253
|
txn["id"]["atmpt"] = this->id();
|
|
254
|
+
txn["id"]["op"] = op_id;
|
|
253
255
|
txn["atr"] = tao::json::empty_object;
|
|
254
256
|
txn["atr"]["id"] = atr_id();
|
|
255
257
|
txn["atr"]["bkt"] = atr_id_->bucket();
|
|
@@ -296,6 +298,7 @@ attempt_context_impl::replace_raw(const transaction_get_result& document, const
|
|
|
296
298
|
return op_completed_with_error(std::move(cb), transaction_operation_failed(FAIL_OTHER, ec.message()));
|
|
297
299
|
}
|
|
298
300
|
try {
|
|
301
|
+
auto op_id = uid_generator::next();
|
|
299
302
|
// a get can return a 'empty' doc, so check for that and short-circuit the eventual error that will occur...
|
|
300
303
|
if (document.key().empty() || document.bucket().empty()) {
|
|
301
304
|
return op_completed_with_error(std::move(cb),
|
|
@@ -321,7 +324,7 @@ attempt_context_impl::replace_raw(const transaction_get_result& document, const
|
|
|
321
324
|
check_and_handle_blocking_transactions(
|
|
322
325
|
document,
|
|
323
326
|
forward_compat_stage::WWC_REPLACING,
|
|
324
|
-
[this, existing_sm = std::move(existing_sm), document = std::move(document), cb = std::move(cb), content](
|
|
327
|
+
[this, existing_sm = std::move(existing_sm), document = std::move(document), cb = std::move(cb), op_id, content](
|
|
325
328
|
std::optional<transaction_operation_failed> e1) mutable {
|
|
326
329
|
if (e1) {
|
|
327
330
|
return op_completed_with_error(std::move(cb), *e1);
|
|
@@ -330,7 +333,7 @@ attempt_context_impl::replace_raw(const transaction_get_result& document, const
|
|
|
330
333
|
document_id{ document.id().bucket(), document.id().scope(), document.id().collection(), document.id().key() };
|
|
331
334
|
select_atr_if_needed_unlocked(
|
|
332
335
|
tmp_doc,
|
|
333
|
-
[this, existing_sm = std::move(existing_sm), document = std::move(document), cb = std::move(cb), content](
|
|
336
|
+
[this, existing_sm = std::move(existing_sm), document = std::move(document), cb = std::move(cb), op_id, content](
|
|
334
337
|
std::optional<transaction_operation_failed> e2) mutable {
|
|
335
338
|
if (e2) {
|
|
336
339
|
return op_completed_with_error(std::move(cb), *e2);
|
|
@@ -339,10 +342,10 @@ attempt_context_impl::replace_raw(const transaction_get_result& document, const
|
|
|
339
342
|
CB_ATTEMPT_CTX_LOG_DEBUG(this, "found existing INSERT of {} while replacing", document);
|
|
340
343
|
exp_delay delay(
|
|
341
344
|
std::chrono::milliseconds(5), std::chrono::milliseconds(300), overall_.config().expiration_time);
|
|
342
|
-
create_staged_insert(document.id(), content, existing_sm->doc().cas().value(), delay, std::move(cb));
|
|
345
|
+
create_staged_insert(document.id(), content, existing_sm->doc().cas().value(), delay, op_id, std::move(cb));
|
|
343
346
|
return;
|
|
344
347
|
}
|
|
345
|
-
create_staged_replace(document, content, std::move(cb));
|
|
348
|
+
create_staged_replace(document, content, op_id, std::move(cb));
|
|
346
349
|
});
|
|
347
350
|
});
|
|
348
351
|
} catch (const client_error& e) {
|
|
@@ -361,9 +364,12 @@ attempt_context_impl::replace_raw(const transaction_get_result& document, const
|
|
|
361
364
|
|
|
362
365
|
template<typename Handler>
|
|
363
366
|
void
|
|
364
|
-
attempt_context_impl::create_staged_replace(const transaction_get_result& document,
|
|
367
|
+
attempt_context_impl::create_staged_replace(const transaction_get_result& document,
|
|
368
|
+
const std::vector<std::byte>& content,
|
|
369
|
+
const std::string& op_id,
|
|
370
|
+
Handler&& cb)
|
|
365
371
|
{
|
|
366
|
-
auto req = create_staging_request(document.id(), &document, "replace", content);
|
|
372
|
+
auto req = create_staging_request(document.id(), &document, "replace", op_id, content);
|
|
367
373
|
req.cas = document.cas();
|
|
368
374
|
req.access_deleted = true;
|
|
369
375
|
auto error_handler = [this](error_class ec, const std::string& msg, Handler&& cb) {
|
|
@@ -449,6 +455,7 @@ attempt_context_impl::insert_raw(const core::document_id& id, const std::vector<
|
|
|
449
455
|
}
|
|
450
456
|
try {
|
|
451
457
|
check_if_done(cb);
|
|
458
|
+
auto op_id = uid_generator::next();
|
|
452
459
|
staged_mutation* existing_sm = staged_mutations_->find_any(id);
|
|
453
460
|
if ((existing_sm != nullptr) &&
|
|
454
461
|
(existing_sm->type() == staged_mutation_type::INSERT || existing_sm->type() == staged_mutation_type::REPLACE)) {
|
|
@@ -462,17 +469,17 @@ attempt_context_impl::insert_raw(const core::document_id& id, const std::vector<
|
|
|
462
469
|
transaction_operation_failed(FAIL_EXPIRY, "transaction expired").expired());
|
|
463
470
|
}
|
|
464
471
|
select_atr_if_needed_unlocked(
|
|
465
|
-
id, [this, existing_sm, cb = std::move(cb), id, content](std::optional<transaction_operation_failed> err) mutable {
|
|
472
|
+
id, [this, existing_sm, cb = std::move(cb), id, op_id, content](std::optional<transaction_operation_failed> err) mutable {
|
|
466
473
|
if (err) {
|
|
467
474
|
return op_completed_with_error(std::move(cb), *err);
|
|
468
475
|
}
|
|
469
476
|
if (existing_sm != nullptr && existing_sm->type() == staged_mutation_type::REMOVE) {
|
|
470
477
|
CB_ATTEMPT_CTX_LOG_DEBUG(this, "found existing remove of {} while inserting", id);
|
|
471
|
-
return create_staged_replace(existing_sm->doc(), content, std::move(cb));
|
|
478
|
+
return create_staged_replace(existing_sm->doc(), content, op_id, std::move(cb));
|
|
472
479
|
}
|
|
473
480
|
uint64_t cas = 0;
|
|
474
481
|
exp_delay delay(std::chrono::milliseconds(5), std::chrono::milliseconds(300), overall_.config().expiration_time);
|
|
475
|
-
create_staged_insert(id, content, cas, delay, std::move(cb));
|
|
482
|
+
create_staged_insert(id, content, cas, delay, op_id, std::move(cb));
|
|
476
483
|
});
|
|
477
484
|
} catch (const std::exception& e) {
|
|
478
485
|
return op_completed_with_error(std::move(cb), transaction_operation_failed(FAIL_OTHER, e.what()));
|
|
@@ -599,6 +606,7 @@ attempt_context_impl::remove(const transaction_get_result& document, VoidCallbac
|
|
|
599
606
|
return error_handler(FAIL_EXPIRY, "transaction expired", std::move(cb));
|
|
600
607
|
}
|
|
601
608
|
CB_ATTEMPT_CTX_LOG_DEBUG(this, "removing {}", document);
|
|
609
|
+
auto op_id = uid_generator::next();
|
|
602
610
|
if (existing_sm != nullptr) {
|
|
603
611
|
if (existing_sm->type() == staged_mutation_type::REMOVE) {
|
|
604
612
|
CB_ATTEMPT_CTX_LOG_DEBUG(this, "found existing REMOVE of {} while removing", document);
|
|
@@ -616,7 +624,7 @@ attempt_context_impl::remove(const transaction_get_result& document, VoidCallbac
|
|
|
616
624
|
check_and_handle_blocking_transactions(
|
|
617
625
|
document,
|
|
618
626
|
forward_compat_stage::WWC_REMOVING,
|
|
619
|
-
[this, document = std::move(document), cb = std::move(cb), error_handler = std::move(error_handler)](
|
|
627
|
+
[this, document = std::move(document), cb = std::move(cb), op_id, error_handler = std::move(error_handler)](
|
|
620
628
|
std::optional<transaction_operation_failed> err1) mutable {
|
|
621
629
|
if (err1) {
|
|
622
630
|
return op_completed_with_error(std::move(cb), *err1);
|
|
@@ -625,7 +633,7 @@ attempt_context_impl::remove(const transaction_get_result& document, VoidCallbac
|
|
|
625
633
|
document_id{ document.id().bucket(), document.id().scope(), document.id().collection(), document.id().key() };
|
|
626
634
|
select_atr_if_needed_unlocked(
|
|
627
635
|
tmp_doc,
|
|
628
|
-
[document = std::move(document), cb = std::move(cb), this, error_handler = std::move(error_handler)](
|
|
636
|
+
[document = std::move(document), cb = std::move(cb), this, op_id, error_handler = std::move(error_handler)](
|
|
629
637
|
std::optional<transaction_operation_failed> err2) mutable {
|
|
630
638
|
if (err2) {
|
|
631
639
|
return op_completed_with_error(std::move(cb), *err2);
|
|
@@ -634,7 +642,7 @@ attempt_context_impl::remove(const transaction_get_result& document, VoidCallbac
|
|
|
634
642
|
return error_handler(*ec, "before_staged_remove hook raised error", std::move(cb));
|
|
635
643
|
}
|
|
636
644
|
CB_ATTEMPT_CTX_LOG_TRACE(this, "about to remove doc {} with cas {}", document.id(), document.cas().value());
|
|
637
|
-
auto req = create_staging_request(document.id(), &document, "remove");
|
|
645
|
+
auto req = create_staging_request(document.id(), &document, "remove", op_id);
|
|
638
646
|
req.cas = document.cas();
|
|
639
647
|
req.access_deleted = document.links().is_deleted();
|
|
640
648
|
overall_.cluster_ref()->execute(
|
|
@@ -1139,6 +1147,9 @@ attempt_context_impl::get_with_query(const core::document_id& id, bool optional,
|
|
|
1139
1147
|
// make a transaction_get_result from the row...
|
|
1140
1148
|
try {
|
|
1141
1149
|
if (resp.rows.empty()) {
|
|
1150
|
+
if (optional) {
|
|
1151
|
+
return op_completed_with_callback(std::move(cb), std::optional<transaction_get_result>());
|
|
1152
|
+
}
|
|
1142
1153
|
return op_completed_with_error(
|
|
1143
1154
|
std::move(cb), transaction_operation_failed(FAIL_DOC_NOT_FOUND, "document not found"));
|
|
1144
1155
|
}
|
|
@@ -1905,10 +1916,10 @@ attempt_context_impl::set_atr_pending_locked(const core::document_id& id, std::u
|
|
|
1905
1916
|
return fn(std::nullopt);
|
|
1906
1917
|
case FAIL_AMBIGUOUS:
|
|
1907
1918
|
// Retry just this
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1919
|
+
CB_ATTEMPT_CTX_LOG_DEBUG(this, "got FAIL_AMBIGUOUS, retrying set atr pending", ec);
|
|
1920
|
+
return overall_.after_delay(std::chrono::milliseconds(1), [this, doc_id, &lock, fn = std::move(fn)]() {
|
|
1921
|
+
set_atr_pending_locked(doc_id, std::move(lock), std::move(fn));
|
|
1922
|
+
});
|
|
1912
1923
|
case FAIL_TRANSIENT:
|
|
1913
1924
|
// Retry txn
|
|
1914
1925
|
return fn(err.retry());
|
|
@@ -1923,8 +1934,6 @@ attempt_context_impl::set_atr_pending_locked(const core::document_id& id, std::u
|
|
|
1923
1934
|
}
|
|
1924
1935
|
CB_ATTEMPT_CTX_LOG_DEBUG(this, "updating atr {}", atr_id_.value());
|
|
1925
1936
|
|
|
1926
|
-
// FIXME: do we need to capture "now" here?
|
|
1927
|
-
// std::chrono::time_point<std::chrono::steady_clock> now = std::chrono::steady_clock::now();
|
|
1928
1937
|
std::chrono::nanoseconds remaining = overall_.remaining();
|
|
1929
1938
|
// This bounds the value to [0-expirationTime]. It should always be in this range, this is just to protect
|
|
1930
1939
|
// against the application clock changing.
|
|
@@ -2153,6 +2162,7 @@ attempt_context_impl::get_doc(
|
|
|
2153
2162
|
lookup_in_specs::get(ATR_ID).xattr(),
|
|
2154
2163
|
lookup_in_specs::get(TRANSACTION_ID).xattr(),
|
|
2155
2164
|
lookup_in_specs::get(ATTEMPT_ID).xattr(),
|
|
2165
|
+
lookup_in_specs::get(OPERATION_ID).xattr(),
|
|
2156
2166
|
lookup_in_specs::get(STAGED_DATA).xattr(),
|
|
2157
2167
|
lookup_in_specs::get(ATR_BUCKET_NAME).xattr(),
|
|
2158
2168
|
lookup_in_specs::get(ATR_SCOPE_NAME).xattr(),
|
|
@@ -2193,6 +2203,7 @@ attempt_context_impl::create_staged_insert_error_handler(const core::document_id
|
|
|
2193
2203
|
const std::vector<std::byte>& content,
|
|
2194
2204
|
uint64_t cas,
|
|
2195
2205
|
Delay&& delay,
|
|
2206
|
+
const std::string& op_id,
|
|
2196
2207
|
Handler&& cb,
|
|
2197
2208
|
error_class ec,
|
|
2198
2209
|
const std::string& message)
|
|
@@ -2211,7 +2222,7 @@ attempt_context_impl::create_staged_insert_error_handler(const core::document_id
|
|
|
2211
2222
|
case FAIL_AMBIGUOUS:
|
|
2212
2223
|
CB_ATTEMPT_CTX_LOG_DEBUG(this, "FAIL_AMBIGUOUS in create_staged_insert, retrying");
|
|
2213
2224
|
delay();
|
|
2214
|
-
return create_staged_insert(id, content, cas, delay, std::forward<Handler>(cb));
|
|
2225
|
+
return create_staged_insert(id, content, cas, delay, op_id, std::forward<Handler>(cb));
|
|
2215
2226
|
case FAIL_OTHER:
|
|
2216
2227
|
return op_completed_with_error(std::forward<Handler>(cb), transaction_operation_failed(ec, "error in create_staged_insert"));
|
|
2217
2228
|
case FAIL_HARD:
|
|
@@ -2221,7 +2232,7 @@ attempt_context_impl::create_staged_insert_error_handler(const core::document_id
|
|
|
2221
2232
|
case FAIL_CAS_MISMATCH: {
|
|
2222
2233
|
// special handling for doc already existing
|
|
2223
2234
|
CB_ATTEMPT_CTX_LOG_DEBUG(this, "found existing doc {}, may still be able to insert", id);
|
|
2224
|
-
auto error_handler = [this, id, content](error_class ec2, const std::string& err_message, Handler&& cb) mutable {
|
|
2235
|
+
auto error_handler = [this, id, op_id, content](error_class ec2, const std::string& err_message, Handler&& cb) mutable {
|
|
2225
2236
|
CB_ATTEMPT_CTX_LOG_TRACE(
|
|
2226
2237
|
this, "after a CAS_MISMATCH or DOC_ALREADY_EXISTS, then got error {} in create_staged_insert", ec2);
|
|
2227
2238
|
if (expiry_overtime_mode_.load()) {
|
|
@@ -2247,7 +2258,7 @@ attempt_context_impl::create_staged_insert_error_handler(const core::document_id
|
|
|
2247
2258
|
}
|
|
2248
2259
|
return get_doc(
|
|
2249
2260
|
id,
|
|
2250
|
-
[this, id, content, cb = std::forward<Handler>(cb), error_handler, delay](
|
|
2261
|
+
[this, id, content, op_id, cb = std::forward<Handler>(cb), error_handler, delay](
|
|
2251
2262
|
std::optional<error_class> ec3, std::optional<std::string> err_message, std::optional<transaction_get_result> doc) mutable {
|
|
2252
2263
|
if (!ec3) {
|
|
2253
2264
|
if (doc) {
|
|
@@ -2266,7 +2277,7 @@ attempt_context_impl::create_staged_insert_error_handler(const core::document_id
|
|
|
2266
2277
|
CB_ATTEMPT_CTX_LOG_DEBUG(
|
|
2267
2278
|
this, "create staged insert found existing deleted doc, retrying with cas {}", doc->cas().value());
|
|
2268
2279
|
delay();
|
|
2269
|
-
return create_staged_insert(id, content, doc->cas().value(), delay, std::forward<Handler>(cb));
|
|
2280
|
+
return create_staged_insert(id, content, doc->cas().value(), delay, op_id, std::forward<Handler>(cb));
|
|
2270
2281
|
}
|
|
2271
2282
|
if (!doc->links().is_document_in_transaction()) {
|
|
2272
2283
|
// doc was inserted outside txn elsewhere
|
|
@@ -2275,6 +2286,18 @@ attempt_context_impl::create_staged_insert_error_handler(const core::document_id
|
|
|
2275
2286
|
std::forward<Handler>(cb),
|
|
2276
2287
|
document_exists({ couchbase::errc::transaction_op::document_exists_exception, key_value_error_context() }));
|
|
2277
2288
|
}
|
|
2289
|
+
if (doc->links().staged_attempt_id() == this->id()) {
|
|
2290
|
+
if (doc->links().staged_operation_id() == op_id) {
|
|
2291
|
+
// this is us dealing with resolving an ambiguity. So, lets just update the staged_mutation with the
|
|
2292
|
+
// correct cas and continue...
|
|
2293
|
+
staged_mutations_->add(staged_mutation(*doc, content, staged_mutation_type::INSERT));
|
|
2294
|
+
return op_completed_with_callback(std::forward<Handler>(cb), doc);
|
|
2295
|
+
}
|
|
2296
|
+
return op_completed_with_error(
|
|
2297
|
+
std::forward<Handler>(cb),
|
|
2298
|
+
transaction_operation_failed(FAIL_OTHER, "concurrent operations on a document are not allowed")
|
|
2299
|
+
.cause(CONCURRENT_OPERATIONS_DETECTED_ON_SAME_DOCUMENT));
|
|
2300
|
+
}
|
|
2278
2301
|
// CBD-3787 - Only a staged insert is ok to overwrite
|
|
2279
2302
|
if (doc->links().op() && *doc->links().op() != "insert") {
|
|
2280
2303
|
return op_completed_with_error(
|
|
@@ -2285,7 +2308,7 @@ attempt_context_impl::create_staged_insert_error_handler(const core::document_id
|
|
|
2285
2308
|
check_and_handle_blocking_transactions(
|
|
2286
2309
|
*doc,
|
|
2287
2310
|
forward_compat_stage::WWC_INSERTING,
|
|
2288
|
-
[this, id, content, doc, cb = std::forward<Handler>(cb), delay](
|
|
2311
|
+
[this, id, op_id, content, doc, cb = std::forward<Handler>(cb), delay](
|
|
2289
2312
|
std::optional<transaction_operation_failed> err) mutable {
|
|
2290
2313
|
if (err) {
|
|
2291
2314
|
return op_completed_with_error(std::move(cb), *err);
|
|
@@ -2293,7 +2316,7 @@ attempt_context_impl::create_staged_insert_error_handler(const core::document_id
|
|
|
2293
2316
|
CB_ATTEMPT_CTX_LOG_DEBUG(
|
|
2294
2317
|
this, "doc ok to overwrite, retrying create_staged_insert with cas {}", doc->cas().value());
|
|
2295
2318
|
delay();
|
|
2296
|
-
return create_staged_insert(id, content, doc->cas().value(), delay, std::forward<Handler>(cb));
|
|
2319
|
+
return create_staged_insert(id, content, doc->cas().value(), delay, op_id, std::forward<Handler>(cb));
|
|
2297
2320
|
});
|
|
2298
2321
|
} else {
|
|
2299
2322
|
// no doc now, just retry entire txn
|
|
@@ -2320,20 +2343,27 @@ attempt_context_impl::create_staged_insert(const core::document_id& id,
|
|
|
2320
2343
|
const std::vector<std::byte>& content,
|
|
2321
2344
|
uint64_t cas,
|
|
2322
2345
|
Delay&& delay,
|
|
2346
|
+
const std::string& op_id,
|
|
2323
2347
|
Handler&& cb)
|
|
2324
2348
|
{
|
|
2325
2349
|
|
|
2326
2350
|
if (auto ec = error_if_expired_and_not_in_overtime(STAGE_CREATE_STAGED_INSERT, id.key()); ec) {
|
|
2327
|
-
return create_staged_insert_error_handler(
|
|
2328
|
-
|
|
2351
|
+
return create_staged_insert_error_handler(id,
|
|
2352
|
+
content,
|
|
2353
|
+
cas,
|
|
2354
|
+
std::forward<Delay>(delay),
|
|
2355
|
+
op_id,
|
|
2356
|
+
std::forward<Handler>(cb),
|
|
2357
|
+
*ec,
|
|
2358
|
+
"create_staged_insert expired and not in overtime");
|
|
2329
2359
|
}
|
|
2330
2360
|
|
|
2331
2361
|
if (auto ec = hooks_.before_staged_insert(this, id.key()); ec) {
|
|
2332
2362
|
return create_staged_insert_error_handler(
|
|
2333
|
-
id, content, cas, std::forward<Delay>(delay), std::forward<Handler>(cb), *ec, "before_staged_insert hook threw error");
|
|
2363
|
+
id, content, cas, std::forward<Delay>(delay), op_id, std::forward<Handler>(cb), *ec, "before_staged_insert hook threw error");
|
|
2334
2364
|
}
|
|
2335
2365
|
CB_ATTEMPT_CTX_LOG_DEBUG(this, "about to insert staged doc {} with cas {}", id, cas);
|
|
2336
|
-
auto req = create_staging_request(id, nullptr, "insert", content);
|
|
2366
|
+
auto req = create_staging_request(id, nullptr, "insert", op_id, content);
|
|
2337
2367
|
req.access_deleted = true;
|
|
2338
2368
|
req.create_as_deleted = true;
|
|
2339
2369
|
req.cas = couchbase::cas(cas);
|
|
@@ -2341,11 +2371,13 @@ attempt_context_impl::create_staged_insert(const core::document_id& id,
|
|
|
2341
2371
|
wrap_durable_request(req, overall_.config());
|
|
2342
2372
|
overall_.cluster_ref()->execute(
|
|
2343
2373
|
req,
|
|
2344
|
-
[this, id, content, cas, cb = std::forward<Handler>(cb), delay = std::forward<Delay>(delay)](
|
|
2374
|
+
[this, id, content, cas, op_id, cb = std::forward<Handler>(cb), delay = std::forward<Delay>(delay)](
|
|
2345
2375
|
core::operations::mutate_in_response resp) mutable {
|
|
2346
|
-
|
|
2376
|
+
auto ec = resp.ctx.ec() ? error_class_from_response(resp) : hooks_.after_staged_insert_complete(this, id.key());
|
|
2377
|
+
if (ec) {
|
|
2378
|
+
auto msg = (resp.ctx.ec() ? resp.ctx.ec().message() : "after_staged_insert hook threw error");
|
|
2347
2379
|
return create_staged_insert_error_handler(
|
|
2348
|
-
id, content, cas, std::forward<Delay>(delay), std::forward<Handler>(cb), *ec,
|
|
2380
|
+
id, content, cas, std::forward<Delay>(delay), op_id, std::forward<Handler>(cb), *ec, msg);
|
|
2349
2381
|
}
|
|
2350
2382
|
if (!resp.ctx.ec()) {
|
|
2351
2383
|
CB_ATTEMPT_CTX_LOG_DEBUG(this, "inserted doc {} CAS={}, {}", id, resp.cas.value(), resp.ctx.ec().message());
|
|
@@ -2357,6 +2389,7 @@ attempt_context_impl::create_staged_insert(const core::document_id& id,
|
|
|
2357
2389
|
id.collection(),
|
|
2358
2390
|
overall_.transaction_id(),
|
|
2359
2391
|
this->id(),
|
|
2392
|
+
op_id,
|
|
2360
2393
|
content,
|
|
2361
2394
|
std::nullopt,
|
|
2362
2395
|
std::nullopt,
|
|
@@ -2373,6 +2406,7 @@ attempt_context_impl::create_staged_insert(const core::document_id& id,
|
|
|
2373
2406
|
content,
|
|
2374
2407
|
cas,
|
|
2375
2408
|
std::forward<Delay>(delay),
|
|
2409
|
+
op_id,
|
|
2376
2410
|
std::forward<Handler>(cb),
|
|
2377
2411
|
error_class_from_response(resp).value(),
|
|
2378
2412
|
resp.ctx.ec().message());
|
|
@@ -301,11 +301,23 @@ class attempt_context_impl
|
|
|
301
301
|
existing_error();
|
|
302
302
|
return func();
|
|
303
303
|
} catch (const async_operation_conflict& e) {
|
|
304
|
-
// can't do anything here but log and eat it.
|
|
305
304
|
CB_ATTEMPT_CTX_LOG_ERROR(this, "Attempted to perform txn operation after commit/rollback started: {}", e.what());
|
|
306
305
|
// you cannot call op_completed_with_error, as it tries to decrement
|
|
307
306
|
// the op count, however it didn't successfully increment it, so...
|
|
308
|
-
|
|
307
|
+
auto err = transaction_operation_failed(FAIL_OTHER, "async operation conflict");
|
|
308
|
+
switch (state()) {
|
|
309
|
+
case attempt_state::ABORTED:
|
|
310
|
+
case attempt_state::ROLLED_BACK:
|
|
311
|
+
err.cause(TRANSACTION_ALREADY_ABORTED);
|
|
312
|
+
break;
|
|
313
|
+
case attempt_state::COMMITTED:
|
|
314
|
+
case attempt_state::COMPLETED:
|
|
315
|
+
err.cause(TRANSACTION_ALREADY_COMMITTED);
|
|
316
|
+
break;
|
|
317
|
+
default:
|
|
318
|
+
err.cause(UNKNOWN);
|
|
319
|
+
}
|
|
320
|
+
op_completed_with_error_no_cache(std::move(cb), std::make_exception_ptr(err));
|
|
309
321
|
} catch (const transaction_operation_failed& e) {
|
|
310
322
|
// thrown only from call_func when previous error exists, so eat it, unless
|
|
311
323
|
// it has PREVIOUS_OP_FAILED cause
|
|
@@ -389,26 +401,25 @@ class attempt_context_impl
|
|
|
389
401
|
std::optional<std::string> query_context,
|
|
390
402
|
couchbase::transactions::async_query_handler&& handler) override
|
|
391
403
|
{
|
|
392
|
-
query(
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
404
|
+
query(statement,
|
|
405
|
+
opts,
|
|
406
|
+
query_context,
|
|
407
|
+
[handler = std::move(handler)](std::exception_ptr err, std::optional<core::operations::query_response> resp) {
|
|
408
|
+
if (err) {
|
|
409
|
+
try {
|
|
410
|
+
std::rethrow_exception(err);
|
|
411
|
+
} catch (const transaction_operation_failed& e) {
|
|
412
|
+
return handler(e.get_error_ctx(), {});
|
|
413
|
+
} catch (const op_exception& ex) {
|
|
414
|
+
return handler(ex.ctx(), {});
|
|
415
|
+
} catch (...) {
|
|
416
|
+
// just in case...
|
|
417
|
+
return handler(transaction_op_error_context(couchbase::errc::transaction_op::unknown), {});
|
|
418
|
+
}
|
|
407
419
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
});
|
|
420
|
+
auto [ctx, res] = core::impl::build_transaction_query_result(*resp);
|
|
421
|
+
handler(ctx, res);
|
|
422
|
+
});
|
|
412
423
|
}
|
|
413
424
|
|
|
414
425
|
void commit() override;
|
|
@@ -445,7 +456,7 @@ class attempt_context_impl
|
|
|
445
456
|
|
|
446
457
|
void state(attempt_state s)
|
|
447
458
|
{
|
|
448
|
-
overall_.
|
|
459
|
+
overall_.current_attempt_state(s);
|
|
449
460
|
}
|
|
450
461
|
|
|
451
462
|
[[nodiscard]] const std::string atr_id()
|
|
@@ -514,6 +525,7 @@ class attempt_context_impl
|
|
|
514
525
|
core::operations::mutate_in_request create_staging_request(const core::document_id& in,
|
|
515
526
|
const transaction_get_result* document,
|
|
516
527
|
const std::string type,
|
|
528
|
+
const std::string op_id,
|
|
517
529
|
std::optional<std::vector<std::byte>> content = std::nullopt);
|
|
518
530
|
|
|
519
531
|
template<typename Handler, typename Delay>
|
|
@@ -521,16 +533,21 @@ class attempt_context_impl
|
|
|
521
533
|
const std::vector<std::byte>& content,
|
|
522
534
|
uint64_t cas,
|
|
523
535
|
Delay&& delay,
|
|
536
|
+
const std::string& op_id,
|
|
524
537
|
Handler&& cb);
|
|
525
538
|
|
|
526
539
|
template<typename Handler>
|
|
527
|
-
void create_staged_replace(const transaction_get_result& document,
|
|
540
|
+
void create_staged_replace(const transaction_get_result& document,
|
|
541
|
+
const std::vector<std::byte>& content,
|
|
542
|
+
const std::string& op_id,
|
|
543
|
+
Handler&& cb);
|
|
528
544
|
|
|
529
545
|
template<typename Handler, typename Delay>
|
|
530
546
|
void create_staged_insert_error_handler(const core::document_id& id,
|
|
531
547
|
const std::vector<std::byte>& content,
|
|
532
548
|
uint64_t cas,
|
|
533
549
|
Delay&& delay,
|
|
550
|
+
const std::string& op_id,
|
|
534
551
|
Handler&& cb,
|
|
535
552
|
error_class ec,
|
|
536
553
|
const std::string& message);
|
|
@@ -601,6 +618,10 @@ class attempt_context_impl
|
|
|
601
618
|
|
|
602
619
|
void ensure_open_bucket(std::string bucket_name, std::function<void(std::error_code)>&& handler)
|
|
603
620
|
{
|
|
621
|
+
if (bucket_name.empty()) {
|
|
622
|
+
CB_LOG_DEBUG("ensure_open_bucket called with empty bucket_name");
|
|
623
|
+
return handler(couchbase::errc::common::bucket_not_found);
|
|
624
|
+
}
|
|
604
625
|
cluster_ref()->open_bucket(bucket_name, [handler = std::move(handler)](std::error_code ec) { handler(ec); });
|
|
605
626
|
}
|
|
606
627
|
};
|
|
@@ -122,8 +122,8 @@ struct forward_compat_behavior_full {
|
|
|
122
122
|
struct forward_compat_supported {
|
|
123
123
|
uint32_t protocol_major = 2;
|
|
124
124
|
uint32_t protocol_minor = 0;
|
|
125
|
-
std::list<std::string> extensions{ "TI", "MO", "BM",
|
|
126
|
-
"
|
|
125
|
+
std::list<std::string> extensions{ "TI", "MO", "BM", "QU", "SD", "BF3787", "BF3705", "BF3838", "RC",
|
|
126
|
+
"UA", "CO", "BF3791", "CM", "SI", "QC", "IX", "TS" };
|
|
127
127
|
};
|
|
128
128
|
|
|
129
129
|
struct forward_compat_requirement {
|
|
@@ -49,30 +49,29 @@ class transaction_context
|
|
|
49
49
|
|
|
50
50
|
[[nodiscard]] std::size_t num_attempts() const
|
|
51
51
|
{
|
|
52
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
52
53
|
return attempts_.size();
|
|
53
54
|
}
|
|
54
|
-
[[nodiscard]] const std::vector<transaction_attempt>& attempts() const
|
|
55
|
-
{
|
|
56
|
-
return attempts_;
|
|
57
|
-
}
|
|
58
|
-
[[nodiscard]] std::vector<transaction_attempt>& attempts()
|
|
59
|
-
{
|
|
60
|
-
return const_cast<std::vector<transaction_attempt>&>(const_cast<const transaction_context*>(this)->attempts());
|
|
61
|
-
}
|
|
62
55
|
[[nodiscard]] const transaction_attempt& current_attempt() const
|
|
63
56
|
{
|
|
57
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
64
58
|
if (attempts_.empty()) {
|
|
65
59
|
throw std::runtime_error("transaction context has no attempts yet");
|
|
66
60
|
}
|
|
67
61
|
return attempts_.back();
|
|
68
62
|
}
|
|
69
|
-
[[nodiscard]] transaction_attempt& current_attempt()
|
|
70
|
-
{
|
|
71
|
-
return const_cast<transaction_attempt&>(const_cast<const transaction_context*>(this)->current_attempt());
|
|
72
|
-
}
|
|
73
63
|
|
|
74
64
|
void add_attempt();
|
|
75
65
|
|
|
66
|
+
void current_attempt_state(attempt_state s)
|
|
67
|
+
{
|
|
68
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
69
|
+
if (attempts_.empty()) {
|
|
70
|
+
throw std::runtime_error("transaction_context has no attempts yet");
|
|
71
|
+
}
|
|
72
|
+
attempts_.back().state = s;
|
|
73
|
+
}
|
|
74
|
+
|
|
76
75
|
[[nodiscard]] std::shared_ptr<core::cluster> cluster_ref()
|
|
77
76
|
{
|
|
78
77
|
return transactions_.cluster_ref();
|
|
@@ -90,7 +89,7 @@ class transaction_context
|
|
|
90
89
|
|
|
91
90
|
[[nodiscard]] bool has_expired_client_side();
|
|
92
91
|
|
|
93
|
-
void
|
|
92
|
+
void after_delay(std::chrono::milliseconds delay, std::function<void()> fn);
|
|
94
93
|
|
|
95
94
|
[[nodiscard]] std::chrono::time_point<std::chrono::steady_clock> start_time_client() const
|
|
96
95
|
{
|
|
@@ -191,6 +190,7 @@ class transaction_context
|
|
|
191
190
|
std::string atr_collection_;
|
|
192
191
|
transactions_cleanup& cleanup_;
|
|
193
192
|
std::shared_ptr<attempt_context_impl> current_attempt_context_;
|
|
193
|
+
mutable std::mutex mutex_;
|
|
194
194
|
|
|
195
195
|
std::unique_ptr<exp_delay> delay_;
|
|
196
196
|
};
|
|
@@ -50,6 +50,7 @@ static const std::string TRANSACTION_RESTORE_PREFIX_ONLY = TRANSACTION_INTERFACE
|
|
|
50
50
|
static const std::string TRANSACTION_RESTORE_PREFIX = TRANSACTION_RESTORE_PREFIX_ONLY + ".";
|
|
51
51
|
static const std::string TRANSACTION_ID = TRANSACTION_INTERFACE_PREFIX + "id.txn";
|
|
52
52
|
static const std::string ATTEMPT_ID = TRANSACTION_INTERFACE_PREFIX + "id.atmpt";
|
|
53
|
+
static const std::string OPERATION_ID = TRANSACTION_INTERFACE_PREFIX + "id.op";
|
|
53
54
|
static const std::string ATR_ID = TRANSACTION_INTERFACE_PREFIX + "atr.id";
|
|
54
55
|
static const std::string ATR_BUCKET_NAME = TRANSACTION_INTERFACE_PREFIX + "atr.bkt";
|
|
55
56
|
|
|
@@ -145,6 +145,12 @@ class transactions_cleanup
|
|
|
145
145
|
|
|
146
146
|
void attempts_loop();
|
|
147
147
|
|
|
148
|
+
bool is_running()
|
|
149
|
+
{
|
|
150
|
+
std::unique_lock<std::mutex> lock(mutex_);
|
|
151
|
+
return running_;
|
|
152
|
+
}
|
|
153
|
+
|
|
148
154
|
template<class R, class P>
|
|
149
155
|
bool interruptable_wait(std::chrono::duration<R, P> time);
|
|
150
156
|
|
|
@@ -153,7 +159,7 @@ class transactions_cleanup
|
|
|
153
159
|
void create_client_record(const couchbase::transactions::transaction_keyspace& keyspace);
|
|
154
160
|
const atr_cleanup_stats handle_atr_cleanup(const core::document_id& atr_id,
|
|
155
161
|
std::vector<transactions_cleanup_attempt>* result = nullptr);
|
|
156
|
-
|
|
162
|
+
bool running_{ false };
|
|
157
163
|
};
|
|
158
164
|
} // namespace transactions
|
|
159
165
|
} // namespace couchbase::core
|
|
@@ -315,7 +315,7 @@ staged_mutation_queue::commit_doc(attempt_context_impl* ctx, staged_mutation& it
|
|
|
315
315
|
|
|
316
316
|
result res;
|
|
317
317
|
if (item.type() == staged_mutation_type::INSERT && !cas_zero_mode) {
|
|
318
|
-
core::operations::insert_request req{ item.doc().id(), item.
|
|
318
|
+
core::operations::insert_request req{ item.doc().id(), item.content() };
|
|
319
319
|
req.flags = couchbase::codec::codec_flags::json_common_flags;
|
|
320
320
|
wrap_durable_request(req, ctx->overall_.config());
|
|
321
321
|
auto barrier = std::make_shared<std::promise<result>>();
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
#pragma once
|
|
18
18
|
|
|
19
19
|
#include "attempt_context_impl.hxx"
|
|
20
|
-
|
|
21
20
|
#include "internal/utils.hxx"
|
|
22
21
|
#include "transaction_get_result.hxx"
|
|
22
|
+
#include "uid_generator.hxx"
|
|
23
23
|
|
|
24
24
|
#include <mutex>
|
|
25
25
|
#include <string>
|
|
@@ -35,13 +35,18 @@ class staged_mutation
|
|
|
35
35
|
transaction_get_result doc_;
|
|
36
36
|
staged_mutation_type type_;
|
|
37
37
|
std::vector<std::byte> content_;
|
|
38
|
+
std::string operation_id_;
|
|
38
39
|
|
|
39
40
|
public:
|
|
40
41
|
template<typename Content>
|
|
41
|
-
staged_mutation(transaction_get_result& doc,
|
|
42
|
+
staged_mutation(transaction_get_result& doc,
|
|
43
|
+
Content content,
|
|
44
|
+
staged_mutation_type type,
|
|
45
|
+
std::string operation_id = uid_generator::next())
|
|
42
46
|
: doc_(doc)
|
|
43
47
|
, type_(type)
|
|
44
48
|
, content_(std::move(content))
|
|
49
|
+
, operation_id_(std::move(operation_id))
|
|
45
50
|
{
|
|
46
51
|
}
|
|
47
52
|
|
|
@@ -97,6 +102,11 @@ class staged_mutation
|
|
|
97
102
|
}
|
|
98
103
|
throw std::runtime_error("unknown type of staged mutation");
|
|
99
104
|
}
|
|
105
|
+
|
|
106
|
+
[[nodiscard]] const std::string& operation_id() const
|
|
107
|
+
{
|
|
108
|
+
return operation_id_;
|
|
109
|
+
}
|
|
100
110
|
};
|
|
101
111
|
|
|
102
112
|
class staged_mutation_queue
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
#include "attempt_context_impl.hxx"
|
|
18
18
|
#include "uid_generator.hxx"
|
|
19
19
|
#include <asio/post.hpp>
|
|
20
|
-
#include <
|
|
20
|
+
#include <asio/steady_timer.hpp>
|
|
21
21
|
|
|
22
22
|
#include "internal/logging.hxx"
|
|
23
23
|
#include "internal/transaction_context.hxx"
|
|
@@ -45,6 +45,7 @@ void
|
|
|
45
45
|
transaction_context::add_attempt()
|
|
46
46
|
{
|
|
47
47
|
transaction_attempt attempt{};
|
|
48
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
48
49
|
attempts_.push_back(attempt);
|
|
49
50
|
}
|
|
50
51
|
|
|
@@ -78,17 +79,14 @@ transaction_context::has_expired_client_side()
|
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
void
|
|
81
|
-
transaction_context::
|
|
82
|
+
transaction_context::after_delay(std::chrono::milliseconds delay, std::function<void()> fn)
|
|
82
83
|
{
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
CB_ATTEMPT_CTX_LOG_TRACE(
|
|
90
|
-
current_attempt_context_, "about to sleep for {} ms", std::chrono::duration_cast<std::chrono::milliseconds>(delay).count());
|
|
91
|
-
std::this_thread::sleep_for(delay);
|
|
84
|
+
auto timer = std::make_shared<asio::steady_timer>(this->transactions_.cluster_ref()->io_context());
|
|
85
|
+
timer->expires_after(delay);
|
|
86
|
+
timer->async_wait([timer, fn](std::error_code) {
|
|
87
|
+
// have to always call the function, even if timer was canceled.
|
|
88
|
+
fn();
|
|
89
|
+
});
|
|
92
90
|
}
|
|
93
91
|
|
|
94
92
|
void
|