couchbase 4.2.11 → 4.3.0

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 (62) hide show
  1. package/deps/couchbase-cxx-cache/mozilla-ca-bundle.crt +49 -2
  2. package/deps/couchbase-cxx-cache/mozilla-ca-bundle.sha256 +1 -1
  3. package/deps/couchbase-cxx-client/core/impl/cluster.cxx +51 -5
  4. package/deps/couchbase-cxx-client/core/impl/collection.cxx +224 -209
  5. package/deps/couchbase-cxx-client/core/impl/query_error_context.cxx +2 -2
  6. package/deps/couchbase-cxx-client/core/impl/query_index_manager.cxx +1 -0
  7. package/deps/couchbase-cxx-client/core/io/dns_client.cxx +4 -0
  8. package/deps/couchbase-cxx-client/core/io/dns_config.cxx +15 -4
  9. package/deps/couchbase-cxx-client/core/io/dns_config.hxx +1 -1
  10. package/deps/couchbase-cxx-client/core/io/mcbp_session.cxx +84 -53
  11. package/deps/couchbase-cxx-client/core/mcbp/operation_queue.cxx +1 -0
  12. package/deps/couchbase-cxx-client/core/meta/features.hxx +5 -0
  13. package/deps/couchbase-cxx-client/core/operations/document_lookup_in_all_replicas.hxx +116 -105
  14. package/deps/couchbase-cxx-client/core/operations/document_lookup_in_any_replica.hxx +116 -108
  15. package/deps/couchbase-cxx-client/core/operations/document_search.cxx +97 -81
  16. package/deps/couchbase-cxx-client/core/operations/document_search.hxx +5 -0
  17. package/deps/couchbase-cxx-client/core/range_scan_orchestrator_options.hxx +2 -1
  18. package/deps/couchbase-cxx-client/core/transactions/atr_cleanup_entry.cxx +16 -7
  19. package/deps/couchbase-cxx-client/core/transactions/attempt_context_impl.cxx +578 -483
  20. package/deps/couchbase-cxx-client/core/transactions/attempt_context_testing_hooks.cxx +51 -50
  21. package/deps/couchbase-cxx-client/core/transactions/attempt_context_testing_hooks.hxx +4 -2
  22. package/deps/couchbase-cxx-client/core/transactions/cleanup_testing_hooks.cxx +6 -6
  23. package/deps/couchbase-cxx-client/core/transactions/cleanup_testing_hooks.hxx +3 -2
  24. package/deps/couchbase-cxx-client/core/transactions/internal/transactions_cleanup.hxx +2 -0
  25. package/deps/couchbase-cxx-client/core/transactions/internal/utils.hxx +5 -1
  26. package/deps/couchbase-cxx-client/core/transactions/staged_mutation.cxx +222 -179
  27. package/deps/couchbase-cxx-client/core/transactions/staged_mutation.hxx +23 -12
  28. package/deps/couchbase-cxx-client/core/transactions/transactions.cxx +61 -24
  29. package/deps/couchbase-cxx-client/core/transactions/transactions_cleanup.cxx +36 -16
  30. package/deps/couchbase-cxx-client/core/transactions/utils.cxx +9 -0
  31. package/deps/couchbase-cxx-client/core/transactions.hxx +40 -7
  32. package/deps/couchbase-cxx-client/couchbase/cluster.hxx +19 -0
  33. package/deps/couchbase-cxx-client/couchbase/fork_event.hxx +39 -0
  34. package/dist/binding.d.ts +8 -0
  35. package/dist/bindingutilities.d.ts +6 -1
  36. package/dist/bindingutilities.js +15 -1
  37. package/dist/bucketmanager.d.ts +0 -12
  38. package/dist/cluster.d.ts +0 -2
  39. package/dist/cluster.js +0 -2
  40. package/dist/collection.d.ts +3 -3
  41. package/dist/collection.js +3 -1
  42. package/dist/querytypes.d.ts +0 -2
  43. package/dist/rangeScan.d.ts +0 -8
  44. package/dist/rangeScan.js +0 -8
  45. package/dist/scope.d.ts +0 -5
  46. package/dist/scope.js +0 -5
  47. package/dist/scopesearchindexmanager.d.ts +0 -2
  48. package/dist/scopesearchindexmanager.js +0 -2
  49. package/dist/searchexecutor.js +3 -1
  50. package/dist/searchtypes.d.ts +16 -6
  51. package/dist/searchtypes.js +2 -6
  52. package/dist/transactions.d.ts +23 -0
  53. package/dist/transactions.js +16 -10
  54. package/dist/vectorsearch.d.ts +8 -8
  55. package/dist/vectorsearch.js +7 -7
  56. package/package.json +7 -7
  57. package/src/instance.cpp +11 -1
  58. package/src/instance.hpp +1 -0
  59. package/src/jstocbpp_autogen.hpp +8 -0
  60. package/src/jstocbpp_transactions.hpp +40 -3
  61. package/src/transactions.cpp +12 -1
  62. package/tools/gen-bindings-json.py +0 -1
@@ -17,6 +17,7 @@
17
17
  #include "staged_mutation.hxx"
18
18
 
19
19
  #include "attempt_context_impl.hxx"
20
+ #include "attempt_context_testing_hooks.hxx"
20
21
  #include "core/cluster.hxx"
21
22
 
22
23
  #include "internal/transaction_fields.hxx"
@@ -357,98 +358,94 @@ staged_mutation_queue::rollback(attempt_context_impl* ctx)
357
358
  void
358
359
  staged_mutation_queue::rollback_insert(attempt_context_impl* ctx,
359
360
  const staged_mutation& item,
360
- async_exp_delay delay,
361
+ async_exp_delay& delay,
361
362
  utils::movable_function<void(std::exception_ptr)> callback)
362
363
  {
363
364
  CB_ATTEMPT_CTX_LOG_TRACE(ctx, "rolling back staged insert for {} with cas {}", item.doc().id(), item.doc().cas().value());
364
365
 
365
366
  asio::post(asio::bind_executor(ctx->cluster_ref().io_context(), [this, callback = std::move(callback), ctx, &item, delay]() mutable {
366
- try {
367
- auto ec = ctx->error_if_expired_and_not_in_overtime(STAGE_DELETE_INSERTED, item.doc().id().key());
368
- if (ec) {
369
- throw client_error(*ec, "expired in rollback and not in overtime mode");
370
- }
371
- ec = ctx->hooks_.before_rollback_delete_inserted(ctx, item.doc().id().key());
372
- if (ec) {
373
- throw client_error(*ec, "before_rollback_delete_insert hook threw error");
367
+ auto handler = [this, callback = std::move(callback), ctx, &item, delay](const std::optional<client_error>& e) mutable {
368
+ if (e) {
369
+ return handle_rollback_insert_error(e.value(), ctx, item, delay, std::move(callback));
374
370
  }
375
- core::operations::mutate_in_request req{ item.doc().id() };
376
- req.specs =
377
- couchbase::mutate_in_specs{
378
- couchbase::mutate_in_specs::remove(TRANSACTION_INTERFACE_PREFIX_ONLY).xattr(),
379
- }
380
- .specs();
381
- req.access_deleted = true;
382
- req.cas = item.doc().cas();
383
- wrap_durable_request(req, ctx->overall().config());
384
- return ctx->cluster_ref().execute(
385
- req, [this, callback = std::move(callback), ctx, &item, delay](const core::operations::mutate_in_response& resp) mutable {
386
- CB_ATTEMPT_CTX_LOG_TRACE(ctx, "mutate_in for {} with cas {}", item.doc().id(), item.doc().cas().value());
387
-
388
- auto res = result::create_from_subdoc_response(resp);
389
- try {
390
- validate_rollback_insert_result(ctx, res, item);
391
- } catch (const client_error& e) {
392
- handle_rollback_insert_error(e, ctx, item, delay, std::move(callback));
393
- return;
394
- }
395
- callback({});
396
- });
397
- } catch (const client_error& e) {
398
- handle_rollback_insert_error(e, ctx, item, delay, std::move(callback));
399
- return;
371
+ return callback({});
372
+ };
373
+
374
+ auto ec = ctx->error_if_expired_and_not_in_overtime(STAGE_DELETE_INSERTED, item.doc().id().key());
375
+ if (ec) {
376
+ return handler(client_error(*ec, "expired in rollback and not in overtime mode"));
400
377
  }
378
+
379
+ return ctx->hooks_.before_rollback_delete_inserted(
380
+ ctx, item.doc().id().key(), [handler = std::move(handler), ctx, &item, delay](std::optional<error_class> ec) mutable {
381
+ if (ec) {
382
+ return handler(client_error(*ec, "before_rollback_delete_insert hook threw error"));
383
+ }
384
+ core::operations::mutate_in_request req{ item.doc().id() };
385
+ req.specs =
386
+ couchbase::mutate_in_specs{
387
+ couchbase::mutate_in_specs::remove(TRANSACTION_INTERFACE_PREFIX_ONLY).xattr(),
388
+ }
389
+ .specs();
390
+ req.access_deleted = true;
391
+ req.cas = item.doc().cas();
392
+ wrap_durable_request(req, ctx->overall().config());
393
+ return ctx->cluster_ref().execute(
394
+ req, [handler = std::move(handler), ctx, &item, delay](const core::operations::mutate_in_response& resp) mutable {
395
+ CB_ATTEMPT_CTX_LOG_TRACE(ctx, "mutate_in for {} with cas {}", item.doc().id(), item.doc().cas().value());
396
+
397
+ auto res = result::create_from_subdoc_response(resp);
398
+ return validate_rollback_insert_result(ctx, res, item, std::move(handler));
399
+ });
400
+ });
401
401
  }));
402
402
  }
403
403
 
404
404
  void
405
405
  staged_mutation_queue::rollback_remove_or_replace(attempt_context_impl* ctx,
406
406
  const staged_mutation& item,
407
- async_exp_delay delay,
407
+ async_exp_delay& delay,
408
408
  utils::movable_function<void(std::exception_ptr)> callback)
409
409
  {
410
410
  CB_ATTEMPT_CTX_LOG_TRACE(ctx, "rolling back staged remove/replace for {} with cas {}", item.doc().id(), item.doc().cas().value());
411
411
 
412
412
  asio::post(asio::bind_executor(ctx->cluster_ref().io_context(), [this, callback = std::move(callback), ctx, &item, delay]() mutable {
413
- try {
414
- auto ec = ctx->error_if_expired_and_not_in_overtime(STAGE_ROLLBACK_DOC, item.doc().id().key());
415
- if (ec) {
416
- throw client_error(*ec, "expired in rollback_remove_or_replace and not in expiry overtime");
413
+ auto handler = [this, callback = std::move(callback), ctx, &item, delay](const std::optional<client_error>& e) mutable {
414
+ if (e) {
415
+ return handle_rollback_remove_or_replace_error(e.value(), ctx, item, delay, std::move(callback));
417
416
  }
418
- ec = ctx->hooks_.before_doc_rolled_back(ctx, item.doc().id().key());
419
- if (ec) {
420
- throw client_error(*ec, "before_doc_rolled_back hook threw error");
421
- }
422
- core::operations::mutate_in_request req{ item.doc().id() };
423
- req.specs =
424
- couchbase::mutate_in_specs{
425
- couchbase::mutate_in_specs::remove(TRANSACTION_INTERFACE_PREFIX_ONLY).xattr(),
426
- }
427
- .specs();
428
- req.cas = item.doc().cas();
429
- wrap_durable_request(req, ctx->overall().config());
430
- return ctx->cluster_ref().execute(
431
- req, [this, callback = std::move(callback), ctx, &item, delay](const core::operations::mutate_in_response& resp) mutable {
432
- auto res = result::create_from_subdoc_response(resp);
433
- try {
434
- validate_rollback_remove_or_replace_result(ctx, res, item);
435
- } catch (const client_error& e) {
436
- handle_rollback_remove_or_replace_error(e, ctx, item, delay, std::move(callback));
437
- return;
438
- }
439
- callback({});
440
- });
441
- } catch (const client_error& e) {
442
- handle_rollback_remove_or_replace_error(e, ctx, item, delay, std::move(callback));
443
- return;
417
+ return callback({});
418
+ };
419
+ auto ec = ctx->error_if_expired_and_not_in_overtime(STAGE_ROLLBACK_DOC, item.doc().id().key());
420
+ if (ec) {
421
+ return handler(client_error(*ec, "expired in rollback_remove_or_replace and not in expiry overtime"));
444
422
  }
423
+ ctx->hooks_.before_doc_rolled_back(
424
+ ctx, item.doc().id().key(), [handler = std::move(handler), ctx, &item, delay](std::optional<error_class> ec) mutable {
425
+ if (ec) {
426
+ return handler(client_error(*ec, "before_doc_rolled_back hook threw error"));
427
+ }
428
+ core::operations::mutate_in_request req{ item.doc().id() };
429
+ req.specs =
430
+ couchbase::mutate_in_specs{
431
+ couchbase::mutate_in_specs::remove(TRANSACTION_INTERFACE_PREFIX_ONLY).xattr(),
432
+ }
433
+ .specs();
434
+ req.cas = item.doc().cas();
435
+ wrap_durable_request(req, ctx->overall().config());
436
+ return ctx->cluster_ref().execute(
437
+ req, [handler = std::move(handler), ctx, &item, delay](const core::operations::mutate_in_response& resp) mutable {
438
+ auto res = result::create_from_subdoc_response(resp);
439
+ return validate_rollback_remove_or_replace_result(ctx, res, item, std::move(handler));
440
+ });
441
+ });
445
442
  }));
446
443
  }
447
444
 
448
445
  void
449
446
  staged_mutation_queue::commit_doc(attempt_context_impl* ctx,
450
447
  staged_mutation& item,
451
- async_constant_delay delay,
448
+ async_constant_delay& delay,
452
449
  utils::movable_function<void(std::exception_ptr)> callback,
453
450
  bool ambiguity_resolution_mode,
454
451
  bool cas_zero_mode)
@@ -459,158 +456,204 @@ staged_mutation_queue::commit_doc(attempt_context_impl* ctx,
459
456
  asio::post(asio::bind_executor(
460
457
  ctx->cluster_ref().io_context(),
461
458
  [this, callback = std::move(callback), ctx, &item, delay, cas_zero_mode, ambiguity_resolution_mode]() mutable {
462
- try {
463
- ctx->check_expiry_during_commit_or_rollback(STAGE_COMMIT_DOC, std::optional<const std::string>(item.doc().id().key()));
464
- auto ec = ctx->hooks_.before_doc_committed(ctx, item.doc().id().key());
465
- if (ec) {
466
- throw client_error(*ec, "before_doc_committed hook threw error");
467
- }
459
+ ctx->check_expiry_during_commit_or_rollback(STAGE_COMMIT_DOC, std::optional<const std::string>(item.doc().id().key()));
468
460
 
469
- // move staged content into doc
470
- CB_ATTEMPT_CTX_LOG_TRACE(
471
- ctx, "commit doc id {}, content {}, cas {}", item.doc().id(), to_string(item.content()), item.doc().cas().value());
472
-
473
- if (item.type() == staged_mutation_type::INSERT && !cas_zero_mode) {
474
- core::operations::insert_request req{ item.doc().id(), item.content() };
475
- req.flags = couchbase::codec::codec_flags::json_common_flags;
476
- wrap_durable_request(req, ctx->overall().config());
477
- return ctx->cluster_ref().execute(
478
- req,
479
- [this, callback = std::move(callback), ctx, &item, delay, ambiguity_resolution_mode, cas_zero_mode](
480
- const core::operations::insert_response& resp) mutable {
481
- auto res = result::create_from_mutation_response(resp);
482
- try {
483
- validate_commit_doc_result(ctx, res, item);
484
- } catch (const client_error& e) {
485
- handle_commit_doc_error(e, ctx, item, delay, ambiguity_resolution_mode, cas_zero_mode, std::move(callback));
486
- return;
487
- }
488
- // Commit successful
489
- callback({});
490
- });
491
- } else {
492
- core::operations::mutate_in_request req{ item.doc().id() };
493
- req.specs =
494
- couchbase::mutate_in_specs{
495
- couchbase::mutate_in_specs::remove(TRANSACTION_INTERFACE_PREFIX_ONLY).xattr(),
496
- // subdoc::opcode::set_doc used in replace w/ empty path
497
- couchbase::mutate_in_specs::replace_raw("", item.content()),
498
- }
499
- .specs();
500
- req.store_semantics = couchbase::store_semantics::replace;
501
- req.cas = couchbase::cas(cas_zero_mode ? 0 : item.doc().cas().value());
502
- wrap_durable_request(req, ctx->overall().config());
503
- return ctx->cluster_ref().execute(
504
- req,
505
- [this, callback = std::move(callback), ctx, &item, delay, ambiguity_resolution_mode, cas_zero_mode](
506
- const core::operations::mutate_in_response resp) mutable {
507
- auto res = result::create_from_subdoc_response(resp);
508
- try {
509
- validate_commit_doc_result(ctx, res, item);
510
- } catch (const client_error& e) {
511
- handle_commit_doc_error(e, ctx, item, delay, ambiguity_resolution_mode, cas_zero_mode, std::move(callback));
512
- return;
513
- }
514
- // Commit successful
515
- callback({});
516
- });
461
+ auto handler = [this, callback = std::move(callback), ctx, &item, delay](
462
+ const std::optional<client_error>& e, bool ambiguity_resolution_mode, bool cas_zero_mode) mutable {
463
+ if (e) {
464
+ return handle_commit_doc_error(
465
+ e.value(), ctx, item, delay, ambiguity_resolution_mode, cas_zero_mode, std::move(callback));
517
466
  }
518
- } catch (const client_error& e) {
519
- handle_commit_doc_error(e, ctx, item, delay, ambiguity_resolution_mode, cas_zero_mode, std::move(callback));
520
- }
467
+ callback({});
468
+ };
469
+
470
+ ctx->hooks_.before_doc_committed(
471
+ ctx,
472
+ item.doc().id().key(),
473
+ [handler = std::move(handler), ctx, &item, delay, ambiguity_resolution_mode, cas_zero_mode](
474
+ std::optional<error_class> ec) mutable {
475
+ if (ec) {
476
+ return handler(client_error(*ec, "before_doc_committed hook threw error"), ambiguity_resolution_mode, cas_zero_mode);
477
+ }
478
+ // move staged content into doc
479
+ CB_ATTEMPT_CTX_LOG_TRACE(
480
+ ctx, "commit doc id {}, content {}, cas {}", item.doc().id(), to_string(item.content()), item.doc().cas().value());
481
+
482
+ if (item.type() == staged_mutation_type::INSERT && !cas_zero_mode) {
483
+ core::operations::insert_request req{ item.doc().id(), item.content() };
484
+ req.flags = couchbase::codec::codec_flags::json_common_flags;
485
+ wrap_durable_request(req, ctx->overall().config());
486
+ return ctx->cluster_ref().execute(
487
+ req,
488
+ [handler = std::move(handler), ctx, &item, delay, ambiguity_resolution_mode, cas_zero_mode](
489
+ const core::operations::insert_response& resp) mutable {
490
+ auto res = result::create_from_mutation_response(resp);
491
+ return validate_commit_doc_result(
492
+ ctx, res, item, [ambiguity_resolution_mode, cas_zero_mode, handler = std::move(handler)](auto e) mutable {
493
+ if (e) {
494
+ return handler(e, ambiguity_resolution_mode, cas_zero_mode);
495
+ }
496
+ // Commit successful
497
+ return handler({}, {}, {});
498
+ });
499
+ });
500
+ } else {
501
+ core::operations::mutate_in_request req{ item.doc().id() };
502
+ req.specs =
503
+ couchbase::mutate_in_specs{
504
+ couchbase::mutate_in_specs::remove(TRANSACTION_INTERFACE_PREFIX_ONLY).xattr(),
505
+ // subdoc::opcode::set_doc used in replace w/ empty path
506
+ couchbase::mutate_in_specs::replace_raw("", item.content()),
507
+ }
508
+ .specs();
509
+ req.store_semantics = couchbase::store_semantics::replace;
510
+ req.cas = couchbase::cas(cas_zero_mode ? 0 : item.doc().cas().value());
511
+ wrap_durable_request(req, ctx->overall().config());
512
+ return ctx->cluster_ref().execute(
513
+ req,
514
+ [handler = std::move(handler), ctx, &item, delay, ambiguity_resolution_mode, cas_zero_mode](
515
+ const core::operations::mutate_in_response resp) mutable {
516
+ auto res = result::create_from_subdoc_response(resp);
517
+ return validate_commit_doc_result(
518
+ ctx, res, item, [ambiguity_resolution_mode, cas_zero_mode, handler = std::move(handler)](auto e) mutable {
519
+ if (e) {
520
+ return handler(e, ambiguity_resolution_mode, cas_zero_mode);
521
+ }
522
+ // Commit successful
523
+ return handler({}, {}, {});
524
+ });
525
+ });
526
+ }
527
+ });
521
528
  }));
522
529
  }
523
530
 
524
531
  void
525
532
  staged_mutation_queue::remove_doc(attempt_context_impl* ctx,
526
533
  const staged_mutation& item,
527
- async_constant_delay delay,
534
+ async_constant_delay& delay,
528
535
  utils::movable_function<void(std::exception_ptr)> callback)
529
536
  {
530
537
  CB_ATTEMPT_CTX_LOG_TRACE(ctx, "remove doc {}", item.doc().id());
531
538
 
532
539
  asio::post(asio::bind_executor(ctx->cluster_ref().io_context(), [this, callback = std::move(callback), ctx, &item, delay]() mutable {
533
- try {
534
- ctx->check_expiry_during_commit_or_rollback(STAGE_REMOVE_DOC, std::optional<const std::string>(item.doc().id().key()));
535
- auto ec = ctx->hooks_.before_doc_removed(ctx, item.doc().id().key());
536
- if (ec) {
537
- throw client_error(*ec, "before_doc_removed hook threw error");
540
+ auto handler = [this, ctx, &item, delay, callback = std::move(callback)](const std::optional<client_error>& e) mutable {
541
+ if (e) {
542
+ return handle_remove_doc_error(e.value(), ctx, item, delay, std::move(callback));
538
543
  }
539
- core::operations::remove_request req{ item.doc().id() };
540
- wrap_durable_request(req, ctx->overall().config());
541
- return ctx->cluster_ref().execute(
542
- req, [this, callback = std::move(callback), ctx, &item, delay](core::operations::remove_response resp) mutable {
543
- auto res = result::create_from_mutation_response(resp);
544
- try {
545
- validate_remove_doc_result(ctx, res, item);
546
- } catch (const client_error& e) {
547
- handle_remove_doc_error(e, ctx, item, delay, std::move(callback));
548
- return;
549
- }
550
- callback({});
551
- });
552
- } catch (const client_error& e) {
553
- handle_remove_doc_error(e, ctx, item, delay, std::move(callback));
554
- }
544
+ return callback({});
545
+ };
546
+
547
+ ctx->check_expiry_during_commit_or_rollback(STAGE_REMOVE_DOC, std::optional<const std::string>(item.doc().id().key()));
548
+ return ctx->hooks_.before_doc_removed(
549
+ ctx, item.doc().id().key(), [ctx, &item, delay, handler = std::move(handler)](auto ec) mutable {
550
+ if (ec) {
551
+ return handler(client_error(*ec, "before_doc_removed hook threw error"));
552
+ }
553
+ core::operations::remove_request req{ item.doc().id() };
554
+ wrap_durable_request(req, ctx->overall().config());
555
+ return ctx->cluster_ref().execute(
556
+ req, [handler = std::move(handler), ctx, &item, delay](core::operations::remove_response resp) mutable {
557
+ auto res = result::create_from_mutation_response(resp);
558
+ return validate_remove_doc_result(ctx, res, item, std::move(handler));
559
+ });
560
+ });
555
561
  }));
556
562
  }
557
563
 
558
564
  void
559
- staged_mutation_queue::validate_commit_doc_result(attempt_context_impl* ctx, result& res, staged_mutation& item)
565
+ staged_mutation_queue::validate_commit_doc_result(attempt_context_impl* ctx,
566
+ result& res,
567
+ staged_mutation& item,
568
+ client_error_handler&& handler)
560
569
  {
561
- validate_operation_result(res);
570
+ try {
571
+ validate_operation_result(res);
572
+ } catch (const client_error& e) {
573
+ return handler(e);
574
+ }
562
575
  CB_ATTEMPT_CTX_LOG_TRACE(ctx, "commit doc result {}", res);
563
576
  // TODO: mutation tokens
564
- auto ec = ctx->hooks_.after_doc_committed_before_saving_cas(ctx, item.doc().id().key());
565
- if (ec) {
566
- throw client_error(*ec, "after_doc_committed_before_saving_cas threw error");
567
- }
568
- item.doc().cas(res.cas);
569
- ec = ctx->hooks_.after_doc_committed(ctx, item.doc().id().key());
570
- if (ec) {
571
- throw client_error(*ec, "after_doc_committed threw error");
572
- }
577
+ ctx->hooks_.after_doc_committed_before_saving_cas(
578
+ ctx, item.doc().id().key(), [ctx, res, item, handler = std::move(handler)](auto ec) mutable {
579
+ if (ec) {
580
+ return handler(client_error(*ec, "after_doc_committed_before_saving_cas threw error"));
581
+ }
582
+ item.doc().cas(res.cas);
583
+ return ctx->hooks_.after_doc_committed(ctx, item.doc().id().key(), [res, item, handler = std::move(handler)](auto ec) mutable {
584
+ if (ec) {
585
+ return handler(client_error(*ec, "after_doc_committed threw error"));
586
+ }
587
+ return handler({});
588
+ });
589
+ });
573
590
  }
574
591
 
575
592
  void
576
- staged_mutation_queue::validate_remove_doc_result(attempt_context_impl* ctx, result& res, const staged_mutation& item)
593
+ staged_mutation_queue::validate_remove_doc_result(attempt_context_impl* ctx,
594
+ result& res,
595
+ const staged_mutation& item,
596
+ client_error_handler&& handler)
577
597
  {
578
- validate_operation_result(res);
579
- CB_ATTEMPT_CTX_LOG_TRACE(ctx, "remove doc result {}", res);
580
- auto ec = ctx->hooks_.after_doc_removed_pre_retry(ctx, item.doc().id().key());
581
- CB_ATTEMPT_CTX_LOG_TRACE(ctx, "got hook ec");
582
- if (ec) {
583
- throw client_error(*ec, "after_doc_removed_pre_retry threw error");
598
+ try {
599
+ validate_operation_result(res);
600
+ } catch (const client_error& e) {
601
+ return handler(e);
584
602
  }
603
+ CB_ATTEMPT_CTX_LOG_TRACE(ctx, "remove doc result {}", res);
604
+ return ctx->hooks_.after_doc_removed_pre_retry(ctx, item.doc().id().key(), [handler = std::move(handler)](auto ec) {
605
+ if (ec) {
606
+ return handler(client_error(*ec, "after_doc_removed_pre_retry threw error"));
607
+ }
608
+ return handler({});
609
+ });
585
610
  }
586
611
 
587
612
  void
588
- staged_mutation_queue::validate_rollback_insert_result(attempt_context_impl* ctx, result& res, const staged_mutation& item)
613
+ staged_mutation_queue::validate_rollback_insert_result(attempt_context_impl* ctx,
614
+ result& res,
615
+ const staged_mutation& item,
616
+ client_error_handler&& handler)
589
617
  {
590
- validate_operation_result(res);
591
- CB_ATTEMPT_CTX_LOG_TRACE(ctx, "rollback insert result {}", res);
592
- auto ec = ctx->hooks_.after_rollback_delete_inserted(ctx, item.doc().id().key());
593
- if (ec) {
594
- throw client_error(*ec, "after_rollback_delete_insert hook threw error");
618
+ try {
619
+ validate_operation_result(res);
620
+ } catch (const client_error& e) {
621
+ return handler(e);
595
622
  }
623
+ CB_ATTEMPT_CTX_LOG_TRACE(ctx, "rollback insert result {}", res);
624
+ return ctx->hooks_.after_rollback_delete_inserted(ctx, item.doc().id().key(), [handler = std::move(handler)](auto ec) {
625
+ if (ec) {
626
+ return handler(client_error(*ec, "after_rollback_delete_insert hook threw error"));
627
+ }
628
+ return handler({});
629
+ });
596
630
  }
597
631
 
598
632
  void
599
- staged_mutation_queue::validate_rollback_remove_or_replace_result(attempt_context_impl* ctx, result& res, const staged_mutation& item)
633
+ staged_mutation_queue::validate_rollback_remove_or_replace_result(attempt_context_impl* ctx,
634
+ result& res,
635
+ const staged_mutation& item,
636
+ client_error_handler&& handler)
600
637
  {
601
- validate_operation_result(res);
602
- CB_ATTEMPT_CTX_LOG_TRACE(ctx, "rollback remove or replace result {}", res);
603
- auto ec = ctx->hooks_.after_rollback_replace_or_remove(ctx, item.doc().id().key());
604
- if (ec) {
605
- throw client_error(*ec, "after_rollback_replace_or_remove hook threw error");
638
+ try {
639
+ validate_operation_result(res);
640
+ } catch (const client_error& e) {
641
+ return handler(e);
606
642
  }
643
+ CB_ATTEMPT_CTX_LOG_TRACE(ctx, "rollback remove or replace result {}", res);
644
+ return ctx->hooks_.after_rollback_replace_or_remove(ctx, item.doc().id().key(), [handler = std::move(handler)](auto ec) {
645
+ if (ec) {
646
+ return handler(client_error(*ec, "after_rollback_replace_or_remove hook threw error"));
647
+ }
648
+ return handler({});
649
+ });
607
650
  }
608
651
 
609
652
  void
610
653
  staged_mutation_queue::handle_commit_doc_error(const client_error& e,
611
654
  attempt_context_impl* ctx,
612
655
  staged_mutation& item,
613
- async_constant_delay delay,
656
+ async_constant_delay& delay,
614
657
  bool ambiguity_resolution_mode,
615
658
  bool cas_zero_mode,
616
659
  utils::movable_function<void(std::exception_ptr)> callback)
@@ -656,7 +699,7 @@ void
656
699
  staged_mutation_queue::handle_remove_doc_error(const client_error& e,
657
700
  attempt_context_impl* ctx,
658
701
  const staged_mutation& item,
659
- async_constant_delay delay,
702
+ async_constant_delay& delay,
660
703
  utils::movable_function<void(std::exception_ptr)> callback)
661
704
  {
662
705
  auto ec = e.ec();
@@ -690,7 +733,7 @@ void
690
733
  staged_mutation_queue::handle_rollback_insert_error(const client_error& e,
691
734
  attempt_context_impl* ctx,
692
735
  const staged_mutation& item,
693
- async_exp_delay delay,
736
+ async_exp_delay& delay,
694
737
  utils::movable_function<void(std::exception_ptr)> callback)
695
738
  {
696
739
  auto ec = e.ec();
@@ -736,7 +779,7 @@ void
736
779
  staged_mutation_queue::handle_rollback_remove_or_replace_error(const client_error& e,
737
780
  attempt_context_impl* ctx,
738
781
  const staged_mutation& item,
739
- async_exp_delay delay,
782
+ async_exp_delay& delay,
740
783
  utils::movable_function<void(std::exception_ptr)> callback)
741
784
  {
742
785
  auto ec = e.ec();
@@ -129,51 +129,62 @@ class staged_mutation_queue
129
129
  std::mutex mutex_;
130
130
  std::vector<staged_mutation> queue_;
131
131
 
132
- static void validate_rollback_remove_or_replace_result(attempt_context_impl* ctx, result& res, const staged_mutation& item);
133
- static void validate_rollback_insert_result(attempt_context_impl* ctx, result& res, const staged_mutation& item);
134
- static void validate_commit_doc_result(attempt_context_impl* ctx, result& res, staged_mutation& item);
135
- static void validate_remove_doc_result(attempt_context_impl* ctx, result& res, const staged_mutation& item);
132
+ using client_error_handler = utils::movable_function<void(const std::optional<client_error>&)>;
133
+
134
+ static void validate_rollback_remove_or_replace_result(attempt_context_impl* ctx,
135
+ result& res,
136
+ const staged_mutation& item,
137
+ client_error_handler&& handler);
138
+ static void validate_rollback_insert_result(attempt_context_impl* ctx,
139
+ result& res,
140
+ const staged_mutation& item,
141
+ client_error_handler&& handler);
142
+ static void validate_commit_doc_result(attempt_context_impl* ctx, result& res, staged_mutation& item, client_error_handler&& handler);
143
+ static void validate_remove_doc_result(attempt_context_impl* ctx,
144
+ result& res,
145
+ const staged_mutation& item,
146
+ client_error_handler&& handler);
136
147
 
137
148
  void handle_commit_doc_error(const client_error& e,
138
149
  attempt_context_impl* ctx,
139
150
  staged_mutation& item,
140
- async_constant_delay delay,
151
+ async_constant_delay& delay,
141
152
  bool ambiguity_resolution_mode,
142
153
  bool cas_zero_mode,
143
154
  utils::movable_function<void(std::exception_ptr)> callback);
144
155
  void handle_remove_doc_error(const client_error& e,
145
156
  attempt_context_impl* ctx,
146
157
  const staged_mutation& item,
147
- async_constant_delay delay,
158
+ async_constant_delay& delay,
148
159
  utils::movable_function<void(std::exception_ptr)> callback);
149
160
  void handle_rollback_insert_error(const client_error& e,
150
161
  attempt_context_impl* ctx,
151
162
  const staged_mutation& item,
152
- async_exp_delay delay,
163
+ async_exp_delay& delay,
153
164
  utils::movable_function<void(std::exception_ptr)> callback);
154
165
  void handle_rollback_remove_or_replace_error(const client_error& e,
155
166
  attempt_context_impl* ctx,
156
167
  const staged_mutation& item,
157
- async_exp_delay delay,
168
+ async_exp_delay& delay,
158
169
  utils::movable_function<void(std::exception_ptr)> callback);
159
170
 
160
171
  void commit_doc(attempt_context_impl* ctx,
161
172
  staged_mutation& item,
162
- async_constant_delay delay,
173
+ async_constant_delay& delay,
163
174
  utils::movable_function<void(std::exception_ptr)> callback,
164
175
  bool ambiguity_resolution_mode = false,
165
176
  bool cas_zero_mode = false);
166
177
  void remove_doc(attempt_context_impl* ctx,
167
178
  const staged_mutation& item,
168
- async_constant_delay delay,
179
+ async_constant_delay& delay,
169
180
  utils::movable_function<void(std::exception_ptr)> callback);
170
181
  void rollback_insert(attempt_context_impl* ctx,
171
182
  const staged_mutation& item,
172
- async_exp_delay delay,
183
+ async_exp_delay& delay,
173
184
  utils::movable_function<void(std::exception_ptr)> callback);
174
185
  void rollback_remove_or_replace(attempt_context_impl* ctx,
175
186
  const staged_mutation& item,
176
- async_exp_delay delay,
187
+ async_exp_delay& delay,
177
188
  utils::movable_function<void(std::exception_ptr)> callback);
178
189
 
179
190
  public: