couchbase 4.2.11 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
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: