couchbase 3.8.1 → 3.9.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.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/ext/CMakeLists.txt +16 -1
- data/ext/cache/cpm/{CPM_0.42.0.cmake → CPM_0.43.1.cmake} +18 -2
- data/ext/cache/extconf_include.rb +6 -6
- data/ext/cache/mozilla-ca-bundle.crt +214 -155
- data/ext/cache/mozilla-ca-bundle.sha256 +1 -1
- data/ext/couchbase/CMakeLists.txt +130 -21
- data/ext/couchbase/cmake/APKBUILD.in +25 -4
- data/ext/couchbase/cmake/Bundler.cmake +143 -34
- data/ext/couchbase/cmake/CPM.cmake +126 -12
- data/ext/couchbase/cmake/Cache.cmake +7 -1
- data/ext/couchbase/cmake/CompilerOptions.cmake +1 -1
- data/ext/couchbase/cmake/CompilerWarnings.cmake +17 -6
- data/ext/couchbase/cmake/GrpcProtobuf.cmake +481 -0
- data/ext/couchbase/cmake/OpenSSL.cmake +10 -3
- data/ext/couchbase/cmake/Packaging.cmake +519 -65
- data/ext/couchbase/cmake/Protostellar.cmake +250 -0
- data/ext/couchbase/cmake/Sanitizers.cmake +61 -50
- data/ext/couchbase/cmake/StaticAnalyzers.cmake +16 -5
- data/ext/couchbase/cmake/TestFramework.cmake +283 -0
- data/ext/couchbase/cmake/TestFrameworkAddTests.cmake +51 -0
- data/ext/couchbase/cmake/Testing.cmake +27 -9
- data/ext/couchbase/cmake/ThirdPartyDependencies.cmake +141 -8
- data/ext/couchbase/cmake/VersionInfo.cmake +50 -0
- data/ext/couchbase/cmake/build_config.hxx.in +2 -1
- data/ext/couchbase/cmake/couchbase-cxx-client.spec.in +101 -23
- data/ext/couchbase/cmake/couchbase_cxx_client_static-config.cmake.in +7 -0
- data/ext/couchbase/cmake/couchbase_cxx_client_static.pc.in +2 -0
- data/ext/couchbase/cmake/gRPC_Generate.cmake +58 -0
- data/ext/couchbase/cmake/protobuf_Generate.cmake +69 -0
- data/ext/couchbase/cmake/require-git-checkout.cmake +25 -0
- data/ext/couchbase/cmake/tarball_glob.txt +49 -0
- data/ext/couchbase/core/agent_group.cxx +0 -8
- data/ext/couchbase/core/agent_group.hxx +0 -4
- data/ext/couchbase/core/analytics_stream.cxx +314 -0
- data/ext/couchbase/core/analytics_stream.hxx +129 -0
- data/ext/couchbase/core/analytics_stream_component.cxx +245 -0
- data/ext/couchbase/core/analytics_stream_component.hxx +67 -0
- data/ext/couchbase/core/app_telemetry_meter.cxx +25 -3
- data/ext/couchbase/core/app_telemetry_meter.hxx +77 -0
- data/ext/couchbase/core/app_telemetry_reporter.cxx +7 -6
- data/ext/couchbase/core/bucket.cxx +381 -87
- data/ext/couchbase/core/bucket.hxx +105 -25
- data/ext/couchbase/core/bucket_unit_test_api.hxx +57 -0
- data/ext/couchbase/core/capella.hxx +91 -0
- data/ext/couchbase/core/cluster.cxx +1554 -398
- data/ext/couchbase/core/cluster.hxx +39 -8
- data/ext/couchbase/core/cluster_agent.cxx +0 -8
- data/ext/couchbase/core/cluster_agent.hxx +0 -4
- data/ext/couchbase/core/cluster_options.hxx +26 -3
- data/ext/couchbase/core/collections_component.cxx +39 -15
- data/ext/couchbase/core/config_profiles.cxx +1 -1
- data/ext/couchbase/core/crud_component.cxx +2 -2
- data/ext/couchbase/core/crud_options.hxx +34 -0
- data/ext/couchbase/core/crypto/cbcrypto.cc +18 -13
- data/ext/couchbase/core/document_id_redaction.hxx +81 -0
- data/ext/couchbase/core/error_context/base_error_context.hxx +7 -6
- data/ext/couchbase/core/error_context/key_value.cxx +25 -2
- data/ext/couchbase/core/error_context/key_value.hxx +60 -33
- data/ext/couchbase/core/error_context/key_value_error_context.hxx +16 -15
- data/ext/couchbase/core/error_context/search.hxx +5 -0
- data/ext/couchbase/core/error_context/search_json.hxx +3 -0
- data/ext/couchbase/core/error_context/subdocument_error_context.hxx +19 -18
- data/ext/couchbase/core/error_context/view.hxx +5 -0
- data/ext/couchbase/core/free_form_http_request.cxx +237 -4
- data/ext/couchbase/core/free_form_http_request.hxx +41 -8
- data/ext/couchbase/core/http_component.cxx +300 -284
- data/ext/couchbase/core/http_component.hxx +0 -4
- data/ext/couchbase/core/impl/analytics.cxx +38 -5
- data/ext/couchbase/core/impl/analytics.hxx +34 -0
- data/ext/couchbase/core/impl/bootstrap_error.hxx +0 -3
- data/ext/couchbase/core/impl/collection.cxx +215 -202
- data/ext/couchbase/core/impl/collection_manager.cxx +1 -1
- data/ext/couchbase/core/impl/dns_srv_tracker.cxx +45 -18
- data/ext/couchbase/core/impl/error.cxx +22 -2
- data/ext/couchbase/core/impl/internal_analytics_stream_result.hxx +111 -0
- data/ext/couchbase/core/impl/internal_query_stream_result.hxx +110 -0
- data/ext/couchbase/core/impl/invoke_with_node_id.hxx +15 -7
- data/ext/couchbase/core/impl/key_value_error_category.cxx +6 -0
- data/ext/couchbase/core/impl/lookup_in_replica.cxx +10 -10
- data/ext/couchbase/core/impl/lookup_in_replica.hxx +4 -4
- data/ext/couchbase/core/impl/node_id.cxx +49 -13
- data/ext/couchbase/core/impl/observability_recorder.cxx +12 -2
- data/ext/couchbase/core/impl/observe_poll.cxx +63 -23
- data/ext/couchbase/core/impl/public_analytics_stream_result.cxx +372 -0
- data/ext/couchbase/core/impl/public_bucket.cxx +48 -2
- data/ext/couchbase/core/impl/public_cluster.cxx +325 -25
- data/ext/couchbase/core/impl/public_query_stream_result.cxx +380 -0
- data/ext/couchbase/core/impl/public_transaction_get_multi_replicas_from_preferred_server_group_result.cxx +42 -0
- data/ext/couchbase/core/impl/public_transaction_get_multi_result.cxx +42 -0
- data/ext/couchbase/core/impl/query.cxx +76 -7
- data/ext/couchbase/core/impl/query.hxx +36 -0
- data/ext/couchbase/core/impl/query_index_manager.cxx +54 -1
- data/ext/couchbase/core/impl/replica_utils.cxx +101 -0
- data/ext/couchbase/core/impl/replica_utils.hxx +64 -0
- data/ext/couchbase/core/impl/resolve_node_id.hxx +125 -0
- data/ext/couchbase/core/impl/scope.cxx +70 -0
- data/ext/couchbase/core/impl/search.cxx +31 -1
- data/ext/couchbase/core/impl/transactions.cxx +130 -0
- data/ext/couchbase/core/impl/wait_until_ready.cxx +439 -0
- data/ext/couchbase/core/impl/wait_until_ready.hxx +110 -0
- data/ext/couchbase/core/impl/with_bucket_config_or_timeout.hxx +180 -0
- data/ext/couchbase/core/impl/with_cancellation.hxx +11 -3
- data/ext/couchbase/core/io/configuration_belongs_to_session.hxx +66 -0
- data/ext/couchbase/core/io/dns_client.cxx +122 -45
- data/ext/couchbase/core/io/dns_codec.hxx +21 -21
- data/ext/couchbase/core/io/dns_config.cxx +21 -6
- data/ext/couchbase/core/io/http_command.hxx +149 -121
- data/ext/couchbase/core/io/http_error.hxx +107 -0
- data/ext/couchbase/core/io/http_parser.cxx +4 -0
- data/ext/couchbase/core/io/http_session.cxx +606 -154
- data/ext/couchbase/core/io/http_session.hxx +147 -30
- data/ext/couchbase/core/io/http_session_manager.hxx +329 -382
- data/ext/couchbase/core/io/http_streaming_parser.cxx +4 -0
- data/ext/couchbase/core/io/http_streaming_response.cxx +328 -43
- data/ext/couchbase/core/io/http_streaming_response.hxx +37 -3
- data/ext/couchbase/core/io/mcbp_buffer_pool.hxx +122 -0
- data/ext/couchbase/core/io/mcbp_command.hxx +150 -51
- data/ext/couchbase/core/io/mcbp_command_id.hxx +45 -0
- data/ext/couchbase/core/io/mcbp_message.cxx +9 -1
- data/ext/couchbase/core/io/mcbp_message.hxx +19 -0
- data/ext/couchbase/core/io/mcbp_output_queue.hxx +150 -0
- data/ext/couchbase/core/io/mcbp_parser.cxx +24 -7
- data/ext/couchbase/core/io/mcbp_session.cxx +316 -317
- data/ext/couchbase/core/io/mcbp_session.hxx +27 -18
- data/ext/couchbase/core/io/opaque_ring_table.hxx +145 -0
- data/ext/couchbase/core/io/retry_orchestrator.hxx +6 -5
- data/ext/couchbase/core/io/stream_deadline.hxx +50 -0
- data/ext/couchbase/core/io/streams.cxx +275 -14
- data/ext/couchbase/core/io/streams.hxx +53 -0
- data/ext/couchbase/core/logger/logger.cxx +36 -0
- data/ext/couchbase/core/logger/logger.hxx +46 -6
- data/ext/couchbase/core/logger/redaction.hxx +503 -0
- data/ext/couchbase/core/management/eventing_status.hxx +10 -0
- data/ext/couchbase/core/management/eventing_status_json.hxx +4 -0
- data/ext/couchbase/core/mcbp/big_endian.cxx +1 -1
- data/ext/couchbase/core/mcbp/codec.cxx +27 -18
- data/ext/couchbase/core/mcbp/operation_queue.cxx +2 -2
- data/ext/couchbase/core/mcbp/packet.hxx +2 -2
- data/ext/couchbase/core/mcbp/queue_request.cxx +23 -6
- data/ext/couchbase/core/mcbp/queue_request.hxx +21 -0
- data/ext/couchbase/core/meta/features.hxx +13 -0
- data/ext/couchbase/core/meta/version.cxx +6 -3
- data/ext/couchbase/core/metrics/logging_meter.cxx +5 -10
- data/ext/couchbase/core/metrics/meter_wrapper.cxx +63 -33
- data/ext/couchbase/core/metrics/meter_wrapper.hxx +55 -3
- data/ext/couchbase/core/operations/analytics_response_parsing.cxx +177 -0
- data/ext/couchbase/core/operations/analytics_response_parsing.hxx +55 -0
- data/ext/couchbase/core/operations/document_analytics.cxx +48 -130
- data/ext/couchbase/core/operations/document_analytics.hxx +14 -2
- data/ext/couchbase/core/operations/document_get_all_replicas.hxx +15 -7
- data/ext/couchbase/core/operations/document_get_any_replica.hxx +19 -8
- data/ext/couchbase/core/operations/document_get_projected.cxx +1 -1
- data/ext/couchbase/core/{impl/get_replica.cxx → operations/document_get_replica.cxx} +21 -3
- data/ext/couchbase/core/{impl/get_replica.hxx → operations/document_get_replica.hxx} +31 -4
- data/ext/couchbase/core/operations/document_lookup_in.cxx +10 -10
- data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +228 -198
- data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +215 -217
- data/ext/couchbase/core/operations/document_query.cxx +108 -221
- data/ext/couchbase/core/operations/document_query.hxx +18 -4
- data/ext/couchbase/core/operations/document_search.cxx +52 -8
- data/ext/couchbase/core/operations/document_search.hxx +3 -0
- data/ext/couchbase/core/operations/document_view.cxx +3 -3
- data/ext/couchbase/core/operations/management/analytics_dataset_create.cxx +15 -8
- data/ext/couchbase/core/operations/management/analytics_dataset_create.hxx +4 -0
- data/ext/couchbase/core/operations/management/analytics_dataset_drop.cxx +11 -6
- data/ext/couchbase/core/operations/management/analytics_dataset_get_all.cxx +3 -2
- data/ext/couchbase/core/operations/management/analytics_dataverse_create.cxx +10 -5
- data/ext/couchbase/core/operations/management/analytics_dataverse_drop.cxx +10 -5
- data/ext/couchbase/core/operations/management/analytics_get_pending_mutations.cxx +2 -1
- data/ext/couchbase/core/operations/management/analytics_index_create.cxx +33 -8
- data/ext/couchbase/core/operations/management/analytics_index_drop.cxx +12 -7
- data/ext/couchbase/core/operations/management/analytics_index_get_all.cxx +3 -2
- data/ext/couchbase/core/operations/management/analytics_link_connect.cxx +11 -6
- data/ext/couchbase/core/operations/management/analytics_link_create.cxx +3 -3
- data/ext/couchbase/core/operations/management/analytics_link_disconnect.cxx +10 -4
- data/ext/couchbase/core/operations/management/analytics_link_drop.cxx +6 -4
- data/ext/couchbase/core/operations/management/analytics_link_get_all.cxx +4 -3
- data/ext/couchbase/core/operations/management/analytics_link_replace.cxx +3 -3
- data/ext/couchbase/core/operations/management/analytics_link_utils.hxx +1 -1
- data/ext/couchbase/core/operations/management/bucket_create.cxx +37 -38
- data/ext/couchbase/core/operations/management/bucket_update.cxx +26 -28
- data/ext/couchbase/core/operations/management/change_password.cxx +2 -0
- data/ext/couchbase/core/operations/management/collection_drop.cxx +5 -1
- data/ext/couchbase/core/operations/management/error_utils.cxx +59 -5
- data/ext/couchbase/core/operations/management/error_utils.hxx +29 -1
- data/ext/couchbase/core/operations/management/eventing_deploy_function.cxx +9 -3
- data/ext/couchbase/core/operations/management/eventing_drop_function.cxx +8 -3
- data/ext/couchbase/core/operations/management/eventing_get_all_functions.cxx +4 -2
- data/ext/couchbase/core/operations/management/eventing_get_function.cxx +5 -3
- data/ext/couchbase/core/operations/management/eventing_get_status.cxx +4 -2
- data/ext/couchbase/core/operations/management/eventing_pause_function.cxx +9 -3
- data/ext/couchbase/core/operations/management/eventing_resume_function.cxx +9 -3
- data/ext/couchbase/core/operations/management/eventing_undeploy_function.cxx +9 -3
- data/ext/couchbase/core/operations/management/eventing_upsert_function.cxx +9 -3
- data/ext/couchbase/core/operations/management/group_drop.cxx +3 -1
- data/ext/couchbase/core/operations/management/group_get.cxx +3 -1
- data/ext/couchbase/core/operations/management/group_upsert.cxx +11 -8
- data/ext/couchbase/core/operations/management/query_index_build.cxx +5 -2
- data/ext/couchbase/core/operations/management/query_index_create.cxx +9 -3
- data/ext/couchbase/core/operations/management/query_index_drop.cxx +11 -4
- data/ext/couchbase/core/operations/management/query_index_get_all.cxx +1 -1
- data/ext/couchbase/core/operations/management/query_index_get_all_deferred.cxx +1 -1
- data/ext/couchbase/core/operations/management/scope_drop.cxx +5 -1
- data/ext/couchbase/core/operations/management/scope_get_all.cxx +6 -1
- data/ext/couchbase/core/operations/management/search_get_stats.cxx +10 -0
- data/ext/couchbase/core/operations/management/search_index_analyze_document.cxx +3 -2
- data/ext/couchbase/core/operations/management/search_index_control_ingest.cxx +4 -3
- data/ext/couchbase/core/operations/management/search_index_control_plan_freeze.cxx +4 -3
- data/ext/couchbase/core/operations/management/search_index_control_query.cxx +4 -3
- data/ext/couchbase/core/operations/management/search_index_drop.cxx +2 -2
- data/ext/couchbase/core/operations/management/search_index_get.cxx +2 -2
- data/ext/couchbase/core/operations/management/search_index_get_documents_count.cxx +3 -2
- data/ext/couchbase/core/operations/management/search_index_get_stats.cxx +3 -1
- data/ext/couchbase/core/operations/management/search_index_upsert.cxx +2 -2
- data/ext/couchbase/core/operations/management/user_drop.cxx +3 -1
- data/ext/couchbase/core/operations/management/user_get.cxx +3 -1
- data/ext/couchbase/core/operations/management/user_upsert.cxx +12 -9
- data/ext/couchbase/core/operations/management/view_index_drop.cxx +1 -1
- data/ext/couchbase/core/operations/management/view_index_get.cxx +1 -1
- data/ext/couchbase/core/operations/management/view_index_upsert.cxx +1 -1
- data/ext/couchbase/core/operations/operation_traits.hxx +18 -0
- data/ext/couchbase/core/operations/query_response_parsing.cxx +211 -0
- data/ext/couchbase/core/operations/query_response_parsing.hxx +60 -0
- data/ext/couchbase/core/operations_fwd.hxx +3 -3
- data/ext/couchbase/core/origin.cxx +54 -26
- data/ext/couchbase/core/origin.hxx +12 -0
- data/ext/couchbase/core/orphan_reporter.cxx +2 -1
- data/ext/couchbase/core/platform/random.cc +7 -7
- data/ext/couchbase/core/protocol/client_request.cxx +2 -2
- data/ext/couchbase/core/protocol/client_request.hxx +38 -21
- data/ext/couchbase/core/protocol/client_response.cxx +11 -3
- data/ext/couchbase/core/protocol/client_response.hxx +27 -6
- data/ext/couchbase/core/protocol/cmd_append.cxx +2 -2
- data/ext/couchbase/core/protocol/cmd_cluster_map_change_notification.cxx +2 -2
- data/ext/couchbase/core/protocol/cmd_decrement.cxx +6 -6
- data/ext/couchbase/core/protocol/cmd_get.cxx +1 -1
- data/ext/couchbase/core/protocol/cmd_get_and_lock.cxx +2 -2
- data/ext/couchbase/core/protocol/cmd_get_and_touch.cxx +2 -2
- data/ext/couchbase/core/protocol/cmd_get_cluster_config.cxx +6 -4
- data/ext/couchbase/core/protocol/cmd_get_collection_id.cxx +2 -2
- data/ext/couchbase/core/protocol/cmd_get_error_map.cxx +1 -1
- data/ext/couchbase/core/protocol/cmd_get_meta.cxx +4 -4
- data/ext/couchbase/core/protocol/cmd_get_replica.cxx +1 -1
- data/ext/couchbase/core/protocol/cmd_hello.cxx +1 -1
- data/ext/couchbase/core/protocol/cmd_increment.cxx +6 -6
- data/ext/couchbase/core/protocol/cmd_insert.cxx +4 -4
- data/ext/couchbase/core/protocol/cmd_lookup_in.cxx +4 -3
- data/ext/couchbase/core/protocol/cmd_lookup_in_replica.cxx +4 -3
- data/ext/couchbase/core/protocol/cmd_mutate_in.cxx +10 -9
- data/ext/couchbase/core/protocol/cmd_mutate_in.hxx +10 -10
- data/ext/couchbase/core/protocol/cmd_observe_seqno.cxx +7 -7
- data/ext/couchbase/core/protocol/cmd_prepend.cxx +2 -2
- data/ext/couchbase/core/protocol/cmd_remove.cxx +2 -2
- data/ext/couchbase/core/protocol/cmd_replace.cxx +4 -4
- data/ext/couchbase/core/protocol/cmd_touch.cxx +1 -1
- data/ext/couchbase/core/protocol/cmd_upsert.cxx +4 -4
- data/ext/couchbase/core/protocol/datatype.hxx +118 -1
- data/ext/couchbase/core/protocol/frame_info_utils.cxx +1 -1
- data/ext/couchbase/core/protocol/magic.hxx +4 -0
- data/ext/couchbase/core/protocol/magic_fmt.hxx +3 -0
- data/ext/couchbase/core/protocol/server_request.hxx +3 -1
- data/ext/couchbase/core/protocol/status.cxx +1 -1
- data/ext/couchbase/core/protostellar/analytics_converter.hxx +171 -0
- data/ext/couchbase/core/protostellar/bucket_admin_converter.hxx +301 -0
- data/ext/couchbase/core/protostellar/collection_admin_converter.hxx +92 -0
- data/ext/couchbase/core/protostellar/component.cxx +2445 -0
- data/ext/couchbase/core/protostellar/component.hxx +391 -0
- data/ext/couchbase/core/{columnar/bootstrap_notification_subscriber.hxx → protostellar/compression_settings.hxx} +11 -10
- data/ext/couchbase/core/protostellar/credentials.cxx +233 -0
- data/ext/couchbase/core/protostellar/credentials.hxx +88 -0
- data/ext/couchbase/core/protostellar/dispatcher.cxx +57 -0
- data/ext/couchbase/core/protostellar/dispatcher.hxx +482 -0
- data/ext/couchbase/core/protostellar/error_utils.cxx +293 -0
- data/ext/couchbase/core/protostellar/error_utils.hxx +97 -0
- data/ext/couchbase/core/protostellar/json_payload.hxx +49 -0
- data/ext/couchbase/core/protostellar/kv_converter.cxx +70 -0
- data/ext/couchbase/core/protostellar/kv_converter.hxx +600 -0
- data/ext/couchbase/core/protostellar/query_converter.hxx +265 -0
- data/ext/couchbase/core/protostellar/query_index_admin_converter.hxx +291 -0
- data/ext/couchbase/core/protostellar/query_proto.hxx +73 -0
- data/ext/couchbase/core/protostellar/search_converter.hxx +244 -0
- data/ext/couchbase/core/protostellar/search_index_admin_converter.hxx +156 -0
- data/ext/couchbase/core/protostellar/view_converter.hxx +158 -0
- data/ext/couchbase/core/query_stream.cxx +447 -0
- data/ext/couchbase/core/query_stream.hxx +141 -0
- data/ext/couchbase/core/query_stream_component.cxx +243 -0
- data/ext/couchbase/core/query_stream_component.hxx +68 -0
- data/ext/couchbase/core/range_scan_load_balancer.cxx +15 -8
- data/ext/couchbase/core/range_scan_orchestrator.cxx +15 -3
- data/ext/couchbase/core/response_handler.hxx +41 -4
- data/ext/couchbase/core/row_streamer.cxx +332 -46
- data/ext/couchbase/core/row_streamer.hxx +31 -1
- data/ext/couchbase/core/row_streamer_options.hxx +55 -0
- data/ext/couchbase/core/sasl/client.h +3 -0
- data/ext/couchbase/core/search_scoring.hxx +66 -0
- data/ext/couchbase/core/stream_error_details.hxx +69 -0
- data/ext/couchbase/core/timeout_defaults.hxx +0 -1
- data/ext/couchbase/core/topology/capabilities.hxx +6 -0
- data/ext/couchbase/core/topology/capabilities_fmt.hxx +3 -0
- data/ext/couchbase/core/topology/configuration.cxx +21 -6
- data/ext/couchbase/core/topology/configuration.hxx +29 -8
- data/ext/couchbase/core/topology/configuration_json.hxx +3 -0
- data/ext/couchbase/core/topology/error_map_json.hxx +3 -1
- data/ext/couchbase/core/tracing/threshold_logging_tracer.cxx +70 -4
- data/ext/couchbase/core/tracing/threshold_logging_tracer.hxx +10 -0
- data/ext/couchbase/core/transactions/active_transaction_record.cxx +0 -34
- data/ext/couchbase/core/transactions/attempt_context_impl.cxx +362 -241
- data/ext/couchbase/core/transactions/attempt_context_impl.hxx +24 -3
- data/ext/couchbase/core/transactions/error_list.hxx +2 -2
- data/ext/couchbase/core/transactions/get_multi_fetch.hxx +160 -0
- data/ext/couchbase/core/transactions/get_multi_orchestrator.cxx +326 -125
- data/ext/couchbase/core/transactions/get_multi_transaction_id.hxx +62 -0
- data/ext/couchbase/core/transactions/internal/atr_entry.hxx +22 -2
- data/ext/couchbase/core/transactions/internal/transaction_context.hxx +2 -2
- data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +23 -1
- data/ext/couchbase/core/transactions/internal/utils.hxx +50 -14
- data/ext/couchbase/core/transactions/staged_mutation.cxx +23 -18
- data/ext/couchbase/core/transactions/staged_mutation.hxx +15 -4
- data/ext/couchbase/core/transactions/transaction_context.cxx +55 -40
- data/ext/couchbase/core/transactions/transaction_get_result.hxx +16 -0
- data/ext/couchbase/core/transactions/transactions.cxx +3 -55
- data/ext/couchbase/core/transactions/transactions_cleanup.cxx +194 -66
- data/ext/couchbase/core/transactions/transactions_config.cxx +0 -11
- data/ext/couchbase/core/transactions/utils.cxx +10 -0
- data/ext/couchbase/core/transactions/waitable_op_list.hxx +15 -4
- data/ext/couchbase/core/transactions.hxx +9 -9
- data/ext/couchbase/core/utils/byteswap.hxx +166 -9
- data/ext/couchbase/core/utils/connection_string.cxx +50 -85
- data/ext/couchbase/core/utils/connection_string.hxx +15 -0
- data/ext/couchbase/core/{columnar/backoff_calculator.hxx → utils/deadline.hxx} +13 -13
- data/ext/couchbase/core/utils/duration_parser.cxx +1 -1
- data/ext/couchbase/core/utils/json_streaming_lexer.cxx +48 -5
- data/ext/couchbase/core/utils/json_streaming_lexer.hxx +4 -1
- data/ext/couchbase/core/utils/movable_function.hxx +301 -52
- data/ext/couchbase/core/utils/name_codec.hxx +154 -11
- data/ext/couchbase/core/{columnar/retry_info.hxx → utils/process_id.hxx} +18 -13
- data/ext/couchbase/core/utils/url_codec.cxx +12 -51
- data/ext/couchbase/core/websocket_codec.cxx +3 -29
- data/ext/couchbase/couchbase/analytics_options.hxx +21 -10
- data/ext/couchbase/couchbase/analytics_row.hxx +105 -0
- data/ext/couchbase/couchbase/analytics_stream_result.hxx +266 -0
- data/ext/couchbase/couchbase/boolean_query.hxx +3 -3
- data/ext/couchbase/couchbase/bucket.hxx +57 -0
- data/ext/couchbase/couchbase/cluster.hxx +216 -5
- data/ext/couchbase/{core/columnar/security_options.hxx → couchbase/cluster_state.hxx} +18 -14
- data/ext/couchbase/couchbase/codec/lenient_json_transcoder.hxx +69 -0
- data/ext/couchbase/couchbase/collection.hxx +234 -14
- data/ext/couchbase/couchbase/common_durability_options.hxx +18 -3
- data/ext/couchbase/couchbase/conjunction_query.hxx +1 -1
- data/ext/couchbase/couchbase/create_dataset_analytics_options.hxx +6 -1
- data/ext/couchbase/couchbase/date_range_query.hxx +2 -2
- data/ext/couchbase/couchbase/decrement_options.hxx +1 -1
- data/ext/couchbase/couchbase/disjunction_query.hxx +1 -1
- data/ext/couchbase/couchbase/error.hxx +32 -0
- data/ext/couchbase/couchbase/error_codes.hxx +32 -0
- data/ext/couchbase/couchbase/geo_bounding_box_query.hxx +1 -1
- data/ext/couchbase/couchbase/geo_distance_query.hxx +1 -1
- data/ext/couchbase/couchbase/geo_polygon_query.hxx +1 -1
- data/ext/couchbase/couchbase/get_replica_options.hxx +68 -0
- data/ext/couchbase/couchbase/get_replica_result.hxx +5 -3
- data/ext/couchbase/couchbase/get_replica_strategy.hxx +161 -0
- data/ext/couchbase/couchbase/get_result.hxx +1 -0
- data/ext/couchbase/couchbase/increment_options.hxx +1 -1
- data/ext/couchbase/couchbase/insert_options.hxx +1 -1
- data/ext/couchbase/couchbase/match_phrase_query.hxx +1 -1
- data/ext/couchbase/couchbase/match_query.hxx +1 -1
- data/ext/couchbase/couchbase/mutate_in_options.hxx +3 -3
- data/ext/couchbase/couchbase/network_options.hxx +1 -1
- data/ext/couchbase/couchbase/node_id.hxx +42 -14
- data/ext/couchbase/couchbase/node_id_for_options.hxx +7 -1
- data/ext/couchbase/couchbase/node_ids_options.hxx +8 -2
- data/ext/couchbase/couchbase/numeric_range_query.hxx +1 -1
- data/ext/couchbase/couchbase/phrase_query.hxx +1 -1
- data/ext/couchbase/couchbase/prefix_query.hxx +1 -1
- data/ext/couchbase/couchbase/query_options.hxx +23 -12
- data/ext/couchbase/couchbase/query_row.hxx +111 -0
- data/ext/couchbase/couchbase/query_stream_result.hxx +302 -0
- data/ext/couchbase/couchbase/query_string_query.hxx +3 -3
- data/ext/couchbase/couchbase/regexp_query.hxx +1 -1
- data/ext/couchbase/couchbase/replace_options.hxx +3 -3
- data/ext/couchbase/couchbase/result.hxx +14 -3
- data/ext/couchbase/couchbase/scan_result_item.hxx +1 -0
- data/ext/couchbase/couchbase/scope.hxx +85 -2
- data/ext/couchbase/couchbase/search_options.hxx +58 -8
- data/ext/couchbase/couchbase/search_scoring.hxx +94 -0
- data/ext/couchbase/couchbase/search_scoring_none.hxx +51 -0
- data/ext/couchbase/couchbase/search_scoring_reciprocal_rank_fusion.hxx +88 -0
- data/ext/couchbase/couchbase/search_scoring_relative_score_fusion.hxx +70 -0
- data/ext/couchbase/couchbase/term_range_query.hxx +1 -1
- data/ext/couchbase/couchbase/tracing/request_span.hxx +46 -0
- data/ext/couchbase/couchbase/transactions/transaction_get_multi_replicas_from_preferred_server_group_result.hxx +23 -21
- data/ext/couchbase/couchbase/transactions/transaction_get_multi_result.hxx +24 -19
- data/ext/couchbase/couchbase/transactions/transaction_get_result.hxx +17 -3
- data/ext/couchbase/couchbase/transactions/transactions_config.hxx +4 -2
- data/ext/couchbase/couchbase/transactions.hxx +27 -18
- data/ext/couchbase/couchbase/upsert_options.hxx +3 -3
- data/ext/couchbase/couchbase/vector_query.hxx +1 -1
- data/ext/couchbase/couchbase/wait_until_ready_options.hxx +111 -0
- data/ext/couchbase/couchbase/wildcard_query.hxx +1 -1
- data/ext/extconf.rb +15 -10
- data/ext/rcb_analytics.cxx +82 -102
- data/ext/rcb_backend.cxx +42 -36
- data/ext/rcb_backend.hxx +2 -0
- data/ext/rcb_buckets.cxx +47 -59
- data/ext/rcb_collections.cxx +42 -52
- data/ext/rcb_crud.cxx +345 -224
- data/ext/rcb_diagnostics.cxx +117 -27
- data/ext/rcb_exceptions.cxx +152 -99
- data/ext/rcb_exceptions.hxx +25 -0
- data/ext/rcb_extras.cxx +18 -19
- data/ext/rcb_hdr_histogram.cxx +19 -4
- data/ext/rcb_logger.cxx +202 -27
- data/ext/rcb_logger.hxx +12 -0
- data/ext/rcb_multi.cxx +40 -40
- data/ext/rcb_observability.cxx +7 -5
- data/ext/rcb_query.cxx +99 -142
- data/ext/rcb_range_scan.cxx +41 -35
- data/ext/rcb_search.cxx +98 -99
- data/ext/rcb_users.cxx +36 -56
- data/ext/rcb_utils.cxx +100 -37
- data/ext/rcb_utils.hxx +287 -33
- data/ext/rcb_version.cxx +1 -1
- data/ext/rcb_views.cxx +55 -51
- data/lib/active_support/cache/couchbase_store.rb +77 -12
- data/lib/couchbase/bucket.rb +20 -0
- data/lib/couchbase/cluster.rb +33 -14
- data/lib/couchbase/collection.rb +36 -1
- data/lib/couchbase/errors.rb +18 -0
- data/lib/couchbase/fork_hooks.rb +16 -7
- data/lib/couchbase/get_replica_strategy.rb +89 -0
- data/lib/couchbase/logger.rb +1 -1
- data/lib/couchbase/management/analytics_index_manager.rb +15 -15
- data/lib/couchbase/management/bucket_manager.rb +6 -6
- data/lib/couchbase/management/collection_manager.rb +6 -6
- data/lib/couchbase/management/query_index_manager.rb +7 -7
- data/lib/couchbase/management/search_index_manager.rb +13 -13
- data/lib/couchbase/management/user_manager.rb +10 -10
- data/lib/couchbase/management/view_index_manager.rb +5 -5
- data/lib/couchbase/options.rb +181 -44
- data/lib/couchbase/protostellar/bucket.rb +4 -0
- data/lib/couchbase/protostellar/cluster.rb +4 -0
- data/lib/couchbase/protostellar/collection.rb +4 -0
- data/lib/couchbase/protostellar/error_handling.rb +2 -1
- data/lib/couchbase/protostellar/request.rb +1 -0
- data/lib/couchbase/protostellar/request_generator/kv.rb +16 -2
- data/lib/couchbase/protostellar/request_generator/search.rb +17 -1
- data/lib/couchbase/protostellar/retry/orchestrator.rb +3 -2
- data/lib/couchbase/protostellar/retry/strategies/fail_fast.rb +33 -0
- data/lib/couchbase/protostellar/retry/strategies.rb +1 -0
- data/lib/couchbase/search_options.rb +95 -6
- data/lib/couchbase/version.rb +1 -1
- metadata +92 -33
- data/ext/0001-fix-build-for-mingw-w64-ucrt-x86_64-toolchain.patch +0 -40
- data/ext/couchbase/core/columnar/agent.hxx +0 -71
- data/ext/couchbase/core/columnar/agent_config.hxx +0 -59
- data/ext/couchbase/core/columnar/background_bootstrap_listener.hxx +0 -42
- data/ext/couchbase/core/columnar/backoff_calculator.cxx +0 -62
- data/ext/couchbase/core/columnar/columnar_agent.cxx +0 -147
- data/ext/couchbase/core/columnar/columnar_agent_config.cxx +0 -48
- data/ext/couchbase/core/columnar/columnar_error.cxx +0 -51
- data/ext/couchbase/core/columnar/database_management_options.hxx +0 -56
- data/ext/couchbase/core/columnar/error.hxx +0 -51
- data/ext/couchbase/core/columnar/error_codes.cxx +0 -107
- data/ext/couchbase/core/columnar/error_codes.hxx +0 -75
- data/ext/couchbase/core/columnar/management_component.cxx +0 -300
- data/ext/couchbase/core/columnar/management_component.hxx +0 -56
- data/ext/couchbase/core/columnar/query_component.cxx +0 -523
- data/ext/couchbase/core/columnar/query_component.hxx +0 -57
- data/ext/couchbase/core/columnar/query_options.hxx +0 -59
- data/ext/couchbase/core/columnar/query_result.cxx +0 -130
- data/ext/couchbase/core/columnar/query_result.hxx +0 -78
- data/ext/couchbase/core/io/config_tracker.cxx +0 -687
- data/ext/couchbase/core/io/config_tracker.hxx +0 -123
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
#include "internal/utils.hxx"
|
|
43
43
|
#include "staged_mutation.hxx"
|
|
44
44
|
|
|
45
|
+
#include <cassert>
|
|
45
46
|
#include <optional>
|
|
46
47
|
|
|
47
48
|
namespace couchbase::core::transactions
|
|
@@ -200,11 +201,14 @@ attempt_context_impl::check_and_handle_blocking_transactions(
|
|
|
200
201
|
if (err) {
|
|
201
202
|
return cb(err);
|
|
202
203
|
}
|
|
203
|
-
return check_atr_entry_for_blocking_document(
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
204
|
+
return check_atr_entry_for_blocking_document(
|
|
205
|
+
doc,
|
|
206
|
+
std::make_shared<async_timed_exp_delay>(
|
|
207
|
+
std::make_shared<asio::steady_timer>(cluster_ref().io_context()),
|
|
208
|
+
std::chrono::milliseconds(50),
|
|
209
|
+
std::chrono::milliseconds(500),
|
|
210
|
+
std::chrono::seconds(1)),
|
|
211
|
+
std::move(cb));
|
|
208
212
|
}
|
|
209
213
|
CB_ATTEMPT_CTX_LOG_DEBUG(this,
|
|
210
214
|
"doc \"{}\" is in another transaction {}, but doesn't have enough "
|
|
@@ -233,10 +237,12 @@ attempt_context_impl::get(const core::document_id& id) -> transaction_get_result
|
|
|
233
237
|
void
|
|
234
238
|
attempt_context_impl::get(const core::document_id& id, Callback&& cb)
|
|
235
239
|
{
|
|
236
|
-
if (op_list_.get_mode().is_query()) {
|
|
237
|
-
return get_with_query(id, false, std::move(cb));
|
|
238
|
-
}
|
|
239
240
|
cache_error_async(cb, [self = shared_from_this(), id, cb]() mutable {
|
|
241
|
+
// Mode is read after cache_error_async incremented the op count, closing the
|
|
242
|
+
// race with set_query_mode() -- see the comment in insert() for the rationale.
|
|
243
|
+
if (self->op_list_.get_mode().is_query()) {
|
|
244
|
+
return self->get_with_query(id, false, std::move(cb));
|
|
245
|
+
}
|
|
240
246
|
self->check_if_done(cb);
|
|
241
247
|
self->do_get(
|
|
242
248
|
id,
|
|
@@ -323,10 +329,12 @@ void
|
|
|
323
329
|
attempt_context_impl::get_optional(const core::document_id& id, Callback&& cb)
|
|
324
330
|
{
|
|
325
331
|
|
|
326
|
-
if (op_list_.get_mode().is_query()) {
|
|
327
|
-
return get_with_query(id, true, std::move(cb));
|
|
328
|
-
}
|
|
329
332
|
cache_error_async(cb, [self = shared_from_this(), id, cb]() mutable {
|
|
333
|
+
// Mode is read after cache_error_async incremented the op count, closing the
|
|
334
|
+
// race with set_query_mode() -- see the comment in insert() for the rationale.
|
|
335
|
+
if (self->op_list_.get_mode().is_query()) {
|
|
336
|
+
return self->get_with_query(id, true, std::move(cb));
|
|
337
|
+
}
|
|
330
338
|
self->ensure_open_bucket(
|
|
331
339
|
id.bucket(), [self, id, cb = std::move(cb)](std::error_code ec) mutable {
|
|
332
340
|
if (ec) {
|
|
@@ -886,11 +894,13 @@ attempt_context_impl::replace(const transaction_get_result& document,
|
|
|
886
894
|
Callback&& cb)
|
|
887
895
|
{
|
|
888
896
|
|
|
889
|
-
if (op_list_.get_mode().is_query()) {
|
|
890
|
-
return replace_raw_with_query(document, std::move(content), std::move(cb));
|
|
891
|
-
}
|
|
892
897
|
return cache_error_async(
|
|
893
898
|
cb, [self = shared_from_this(), cb, document, content = std::move(content)]() mutable {
|
|
899
|
+
// Mode is read after cache_error_async incremented the op count, closing the
|
|
900
|
+
// race with set_query_mode() -- see the comment in insert() for the rationale.
|
|
901
|
+
if (self->op_list_.get_mode().is_query()) {
|
|
902
|
+
return self->replace_raw_with_query(document, std::move(content), std::move(cb));
|
|
903
|
+
}
|
|
894
904
|
self->ensure_open_bucket(
|
|
895
905
|
document.bucket(),
|
|
896
906
|
[self, cb = std::move(cb), document, content = std::move(content)](
|
|
@@ -912,7 +922,7 @@ attempt_context_impl::replace(const transaction_get_result& document,
|
|
|
912
922
|
CB_ATTEMPT_CTX_LOG_TRACE(
|
|
913
923
|
self, "replacing {} with {}", document, utils::to_string(content.data));
|
|
914
924
|
self->check_if_done(cb);
|
|
915
|
-
staged_mutation* existing_sm = self->staged_mutations_->find_any(document.id());
|
|
925
|
+
const staged_mutation* existing_sm = self->staged_mutations_->find_any(document.id());
|
|
916
926
|
if (existing_sm != nullptr && existing_sm->type() == staged_mutation_type::REMOVE) {
|
|
917
927
|
CB_ATTEMPT_CTX_LOG_DEBUG(
|
|
918
928
|
self, "found existing REMOVE of {} while replacing", document);
|
|
@@ -965,9 +975,7 @@ attempt_context_impl::replace(const transaction_get_result& document,
|
|
|
965
975
|
self->create_staged_insert(document.id(),
|
|
966
976
|
std::move(content),
|
|
967
977
|
document.cas().value(),
|
|
968
|
-
|
|
969
|
-
std::chrono::milliseconds(300),
|
|
970
|
-
self->overall()->config().timeout),
|
|
978
|
+
self->staged_insert_delay(),
|
|
971
979
|
op_id,
|
|
972
980
|
std::move(cb));
|
|
973
981
|
return;
|
|
@@ -1026,6 +1034,13 @@ attempt_context_impl::create_staged_replace(
|
|
|
1026
1034
|
const std::optional<document_metadata>& document_metadata,
|
|
1027
1035
|
Handler&& cb)
|
|
1028
1036
|
{
|
|
1037
|
+
// ExtThreadSafety invariant -- see create_staged_insert() for the full rationale and
|
|
1038
|
+
// the spec reference (couchbase-transactions-specs/transactions-extensions.md,
|
|
1039
|
+
// "ExtThreadSafety"). replace() reads the mode after this op is counted, so reaching
|
|
1040
|
+
// this staging point in query mode means that ordering has regressed.
|
|
1041
|
+
assert(!op_list_.query_mode_entered() &&
|
|
1042
|
+
"ExtThreadSafety: KV replace staged after query mode entered -- would be missing "
|
|
1043
|
+
"from BEGIN WORK and lost at commit");
|
|
1029
1044
|
operations::mutate_in_request req{ id };
|
|
1030
1045
|
const bool binary =
|
|
1031
1046
|
codec::codec_flags::has_common_flags(content.flags, codec::codec_flags::binary_common_flags);
|
|
@@ -1274,11 +1289,20 @@ attempt_context_impl::insert(const core::document_id& id,
|
|
|
1274
1289
|
codec::encoded_value content,
|
|
1275
1290
|
Callback&& cb)
|
|
1276
1291
|
{
|
|
1277
|
-
if (op_list_.get_mode().is_query()) {
|
|
1278
|
-
return insert_raw_with_query(id, std::move(content), std::move(cb));
|
|
1279
|
-
}
|
|
1280
1292
|
return cache_error_async(
|
|
1281
1293
|
cb, [self = shared_from_this(), id, cb, content = std::move(content)]() mutable {
|
|
1294
|
+
// The op count was incremented by cache_error_async before this lambda runs.
|
|
1295
|
+
// Reading the mode here -- after the increment -- closes a race with
|
|
1296
|
+
// set_query_mode(): a query switching to query mode first waits for all
|
|
1297
|
+
// in-flight KV ops to drain before issuing BEGIN WORK, so once this op is
|
|
1298
|
+
// counted, either we observe KV mode and our staged mutation is guaranteed to
|
|
1299
|
+
// be part of BEGIN WORK, or we observe query mode and route through query.
|
|
1300
|
+
// Checking the mode before the increment (as the code used to) left a window
|
|
1301
|
+
// where a query could flip the mode in the gap, after which this op would
|
|
1302
|
+
// stage a KV mutation that BEGIN WORK had already missed -- silently losing it.
|
|
1303
|
+
if (self->op_list_.get_mode().is_query()) {
|
|
1304
|
+
return self->insert_raw_with_query(id, std::move(content), std::move(cb));
|
|
1305
|
+
}
|
|
1282
1306
|
self->ensure_open_bucket(
|
|
1283
1307
|
id.bucket(),
|
|
1284
1308
|
[self, id, content = std::move(content), cb = std::move(cb)](std::error_code ec) mutable {
|
|
@@ -1289,7 +1313,7 @@ attempt_context_impl::insert(const core::document_id& id,
|
|
|
1289
1313
|
try {
|
|
1290
1314
|
self->check_if_done(cb);
|
|
1291
1315
|
auto op_id = uid_generator::next();
|
|
1292
|
-
staged_mutation* existing_sm = self->staged_mutations_->find_any(id);
|
|
1316
|
+
const staged_mutation* existing_sm = self->staged_mutations_->find_any(id);
|
|
1293
1317
|
if ((existing_sm != nullptr) &&
|
|
1294
1318
|
(existing_sm->type() == staged_mutation_type::INSERT ||
|
|
1295
1319
|
existing_sm->type() == staged_mutation_type::REPLACE)) {
|
|
@@ -1322,14 +1346,8 @@ attempt_context_impl::insert(const core::document_id& id,
|
|
|
1322
1346
|
std::move(cb));
|
|
1323
1347
|
}
|
|
1324
1348
|
const std::uint64_t cas = 0;
|
|
1325
|
-
self->create_staged_insert(
|
|
1326
|
-
|
|
1327
|
-
cas,
|
|
1328
|
-
exp_delay(std::chrono::milliseconds(5),
|
|
1329
|
-
std::chrono::milliseconds(300),
|
|
1330
|
-
self->overall()->config().timeout),
|
|
1331
|
-
op_id,
|
|
1332
|
-
std::move(cb));
|
|
1349
|
+
self->create_staged_insert(
|
|
1350
|
+
id, std::move(content), cas, self->staged_insert_delay(), op_id, std::move(cb));
|
|
1333
1351
|
});
|
|
1334
1352
|
} catch (const std::exception& e) {
|
|
1335
1353
|
return self->op_completed_with_error(
|
|
@@ -1378,19 +1396,24 @@ attempt_context_impl::select_atr_if_needed_unlocked(
|
|
|
1378
1396
|
CB_ATTEMPT_CTX_LOG_ERROR(this, "unexpected error \"{}\" during select atr if needed", e.what());
|
|
1379
1397
|
}
|
|
1380
1398
|
}
|
|
1381
|
-
template<typename Handler
|
|
1399
|
+
template<typename Handler>
|
|
1382
1400
|
void
|
|
1383
|
-
attempt_context_impl::check_atr_entry_for_blocking_document(
|
|
1384
|
-
|
|
1385
|
-
|
|
1401
|
+
attempt_context_impl::check_atr_entry_for_blocking_document(
|
|
1402
|
+
const transaction_get_result& doc,
|
|
1403
|
+
std::shared_ptr<async_timed_exp_delay> delay,
|
|
1404
|
+
Handler&& cb)
|
|
1386
1405
|
{
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1406
|
+
(*delay)([self = shared_from_this(), doc, delay, cb = std::forward<Handler>(cb)](
|
|
1407
|
+
const std::exception_ptr& delay_err) mutable {
|
|
1408
|
+
if (delay_err) {
|
|
1409
|
+
return cb(transaction_operation_failed(FAIL_WRITE_WRITE_CONFLICT,
|
|
1410
|
+
"document is in another transaction")
|
|
1411
|
+
.retry());
|
|
1412
|
+
}
|
|
1413
|
+
return self->hooks_.before_check_atr_entry_for_blocking_doc(
|
|
1414
|
+
self,
|
|
1391
1415
|
doc.id().key(),
|
|
1392
|
-
[self
|
|
1393
|
-
auto ec) mutable {
|
|
1416
|
+
[self, delay = std::move(delay), cb = std::move(cb), doc](auto ec) mutable {
|
|
1394
1417
|
if (ec) {
|
|
1395
1418
|
return cb(transaction_operation_failed(FAIL_WRITE_WRITE_CONFLICT,
|
|
1396
1419
|
"document is in another transaction")
|
|
@@ -1430,7 +1453,8 @@ attempt_context_impl::check_atr_entry_for_blocking_document(const transaction_ge
|
|
|
1430
1453
|
"existing atr entry found in state {}, retrying",
|
|
1431
1454
|
attempt_state_name(it->state()));
|
|
1432
1455
|
}
|
|
1433
|
-
return self->check_atr_entry_for_blocking_document(
|
|
1456
|
+
return self->check_atr_entry_for_blocking_document(
|
|
1457
|
+
doc, std::move(delay), std::move(cb));
|
|
1434
1458
|
}
|
|
1435
1459
|
}
|
|
1436
1460
|
CB_ATTEMPT_CTX_LOG_DEBUG(self, "no blocking atr entry");
|
|
@@ -1442,20 +1466,18 @@ attempt_context_impl::check_atr_entry_for_blocking_document(const transaction_ge
|
|
|
1442
1466
|
.retry());
|
|
1443
1467
|
});
|
|
1444
1468
|
});
|
|
1445
|
-
}
|
|
1446
|
-
return cb(
|
|
1447
|
-
transaction_operation_failed(FAIL_WRITE_WRITE_CONFLICT, "document is in another transaction")
|
|
1448
|
-
.retry());
|
|
1449
|
-
}
|
|
1469
|
+
});
|
|
1450
1470
|
}
|
|
1451
1471
|
void
|
|
1452
1472
|
attempt_context_impl::remove(const transaction_get_result& document, VoidCallback&& cb)
|
|
1453
1473
|
{
|
|
1454
1474
|
|
|
1455
|
-
if (op_list_.get_mode().is_query()) {
|
|
1456
|
-
return remove_with_query(document, std::move(cb));
|
|
1457
|
-
}
|
|
1458
1475
|
return cache_error_async(cb, [self = shared_from_this(), document, cb]() mutable {
|
|
1476
|
+
// Mode is read after cache_error_async incremented the op count, closing the
|
|
1477
|
+
// race with set_query_mode() -- see the comment in insert() for the rationale.
|
|
1478
|
+
if (self->op_list_.get_mode().is_query()) {
|
|
1479
|
+
return self->remove_with_query(document, std::move(cb));
|
|
1480
|
+
}
|
|
1459
1481
|
self->check_if_done(cb);
|
|
1460
1482
|
self->ensure_open_bucket(
|
|
1461
1483
|
document.bucket(), [self, document, cb = std::move(cb)](std::error_code ec) mutable {
|
|
@@ -1539,6 +1561,15 @@ attempt_context_impl::remove(const transaction_get_result& document, VoidCallbac
|
|
|
1539
1561
|
return error_handler(
|
|
1540
1562
|
*ec, "before_staged_remove hook raised error", std::move(cb));
|
|
1541
1563
|
}
|
|
1564
|
+
// ExtThreadSafety invariant -- see create_staged_insert() for the
|
|
1565
|
+
// full rationale and spec reference
|
|
1566
|
+
// (couchbase-transactions-specs/transactions-extensions.md,
|
|
1567
|
+
// "ExtThreadSafety"). remove() reads the mode after this op is
|
|
1568
|
+
// counted, so reaching this staging point in query mode means that
|
|
1569
|
+
// ordering has regressed.
|
|
1570
|
+
assert(!self->op_list_.query_mode_entered() &&
|
|
1571
|
+
"ExtThreadSafety: KV remove staged after query mode entered -- "
|
|
1572
|
+
"would be missing from BEGIN WORK and lost at commit");
|
|
1542
1573
|
CB_ATTEMPT_CTX_LOG_TRACE(self,
|
|
1543
1574
|
"about to remove doc {} with cas {}",
|
|
1544
1575
|
document.id(),
|
|
@@ -1959,11 +1990,11 @@ dump_request(const core::operations::query_request& req) -> std::string
|
|
|
1959
1990
|
std::string raw = "{";
|
|
1960
1991
|
for (const auto& x : req.raw) {
|
|
1961
1992
|
raw += x.first;
|
|
1962
|
-
raw +=
|
|
1993
|
+
raw += ':';
|
|
1963
1994
|
raw += x.second.str();
|
|
1964
|
-
raw +=
|
|
1995
|
+
raw += ',';
|
|
1965
1996
|
}
|
|
1966
|
-
raw +=
|
|
1997
|
+
raw += '}';
|
|
1967
1998
|
std::string params;
|
|
1968
1999
|
for (const auto& x : req.positional_parameters) {
|
|
1969
2000
|
params.append(x.str());
|
|
@@ -2015,6 +2046,7 @@ attempt_context_impl::wrap_query(
|
|
|
2015
2046
|
|
|
2016
2047
|
if (check_expiry) {
|
|
2017
2048
|
if (has_expired_client_side(hook_point, std::nullopt)) {
|
|
2049
|
+
query_check_expired_ = true;
|
|
2018
2050
|
auto err = std::make_exception_ptr(
|
|
2019
2051
|
transaction_operation_failed(FAIL_EXPIRY,
|
|
2020
2052
|
fmt::format("{} expired in stage {}", statement, hook_point))
|
|
@@ -2203,59 +2235,69 @@ make_kv_txdata(std::optional<transaction_get_result> doc = std::nullopt) -> tao:
|
|
|
2203
2235
|
void
|
|
2204
2236
|
attempt_context_impl::get_with_query(const core::document_id& id, bool optional, Callback&& cb)
|
|
2205
2237
|
{
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2238
|
+
// Called only from get()/get_optional(), already within their cache_error_async()
|
|
2239
|
+
// (op counted, existing_error() checked); see insert_raw_with_query() for why we do
|
|
2240
|
+
// not re-wrap.
|
|
2241
|
+
auto self = shared_from_this();
|
|
2242
|
+
couchbase::transactions::transaction_query_options opts;
|
|
2243
|
+
opts.readonly(true);
|
|
2244
|
+
return self->wrap_query(
|
|
2245
|
+
KV_GET,
|
|
2246
|
+
opts,
|
|
2247
|
+
make_params(id, {}),
|
|
2248
|
+
make_kv_txdata(),
|
|
2249
|
+
STAGE_QUERY_KV_GET,
|
|
2250
|
+
true,
|
|
2251
|
+
{},
|
|
2252
|
+
[self, id, optional, cb = std::move(cb)](std::exception_ptr err,
|
|
2253
|
+
core::operations::query_response resp) mutable {
|
|
2254
|
+
if (resp.ctx.ec == couchbase::errc::key_value::document_not_found) {
|
|
2255
|
+
// A non-optional get() must fail rather than report an empty result: its callback contract
|
|
2256
|
+
// (and the synchronous get() wrapper) dereferences the returned optional, so err==nullptr
|
|
2257
|
+
// with res==nullopt would be a null dereference. Mirror the rows-empty handling below and
|
|
2258
|
+
// the KV get() path.
|
|
2259
|
+
if (optional) {
|
|
2220
2260
|
return self->op_completed_with_callback(std::move(cb),
|
|
2221
2261
|
std::optional<transaction_get_result>());
|
|
2222
2262
|
}
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
return self->
|
|
2232
|
-
|
|
2233
|
-
transaction_operation_failed(FAIL_DOC_NOT_FOUND, "document not found"));
|
|
2263
|
+
return self->op_completed_with_error(
|
|
2264
|
+
std::move(cb), transaction_operation_failed(FAIL_DOC_NOT_FOUND, "document not found"));
|
|
2265
|
+
}
|
|
2266
|
+
if (!err) {
|
|
2267
|
+
// make a transaction_get_result from the row...
|
|
2268
|
+
try {
|
|
2269
|
+
if (resp.rows.empty()) {
|
|
2270
|
+
if (optional) {
|
|
2271
|
+
return self->op_completed_with_callback(std::move(cb),
|
|
2272
|
+
std::optional<transaction_get_result>());
|
|
2234
2273
|
}
|
|
2235
|
-
CB_ATTEMPT_CTX_LOG_TRACE(self, "get_with_query got: {}", resp.rows.front());
|
|
2236
|
-
transaction_get_result doc(id, core::utils::json::parse(resp.rows.front()));
|
|
2237
|
-
return self->op_completed_with_callback(std::move(cb),
|
|
2238
|
-
std::optional<transaction_get_result>(doc));
|
|
2239
|
-
} catch (const std::exception& e) {
|
|
2240
|
-
// TODO(SA): unsure what to do here, but this is pretty fatal, so
|
|
2241
2274
|
return self->op_completed_with_error(
|
|
2242
|
-
std::move(cb),
|
|
2275
|
+
std::move(cb),
|
|
2276
|
+
transaction_operation_failed(FAIL_DOC_NOT_FOUND, "document not found"));
|
|
2243
2277
|
}
|
|
2278
|
+
CB_ATTEMPT_CTX_LOG_TRACE(self, "get_with_query got: {}", resp.rows.front());
|
|
2279
|
+
transaction_get_result doc(id, core::utils::json::parse(resp.rows.front()));
|
|
2280
|
+
return self->op_completed_with_callback(std::move(cb),
|
|
2281
|
+
std::optional<transaction_get_result>(doc));
|
|
2282
|
+
} catch (const std::exception& e) {
|
|
2283
|
+
// Unexpected error here: fail with FAIL_OTHER so the transaction rolls back.
|
|
2284
|
+
return self->op_completed_with_error(std::move(cb),
|
|
2285
|
+
transaction_operation_failed(FAIL_OTHER, e.what()));
|
|
2244
2286
|
}
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2287
|
+
}
|
|
2288
|
+
// for get_optional. <sigh>
|
|
2289
|
+
if (optional) {
|
|
2290
|
+
try {
|
|
2291
|
+
std::rethrow_exception(err);
|
|
2292
|
+
} catch (const document_not_found&) {
|
|
2293
|
+
return self->op_completed_with_callback(std::move(cb),
|
|
2294
|
+
std::optional<transaction_get_result>());
|
|
2295
|
+
} catch (...) {
|
|
2296
|
+
return self->op_completed_with_error(std::move(cb), std::current_exception());
|
|
2255
2297
|
}
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2298
|
+
}
|
|
2299
|
+
return self->op_completed_with_error(std::move(cb), std::move(err));
|
|
2300
|
+
});
|
|
2259
2301
|
}
|
|
2260
2302
|
|
|
2261
2303
|
void
|
|
@@ -2263,46 +2305,55 @@ attempt_context_impl::insert_raw_with_query(const core::document_id& id,
|
|
|
2263
2305
|
codec::encoded_value content,
|
|
2264
2306
|
Callback&& cb)
|
|
2265
2307
|
{
|
|
2266
|
-
cache_error_async(
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
}
|
|
2308
|
+
// Called only from insert(), already within its cache_error_async(): the op has
|
|
2309
|
+
// been counted in the wait-group and existing_error() has been checked, so we must
|
|
2310
|
+
// not wrap again here -- double-counting would leave the op permanently in-flight
|
|
2311
|
+
// and deadlock the commit/rollback wait.
|
|
2312
|
+
auto self = shared_from_this();
|
|
2313
|
+
const couchbase::transactions::transaction_query_options opts;
|
|
2314
|
+
return self->wrap_query(
|
|
2315
|
+
KV_INSERT,
|
|
2316
|
+
opts,
|
|
2317
|
+
make_params(id, std::move(content)),
|
|
2318
|
+
make_kv_txdata(),
|
|
2319
|
+
STAGE_QUERY_KV_INSERT,
|
|
2320
|
+
true,
|
|
2321
|
+
{},
|
|
2322
|
+
[self, id, cb = std::move(cb)](const std::exception_ptr& err,
|
|
2323
|
+
core::operations::query_response resp) mutable {
|
|
2324
|
+
if (err) {
|
|
2325
|
+
try {
|
|
2326
|
+
std::rethrow_exception(err);
|
|
2327
|
+
} catch (const transaction_operation_failed& e) {
|
|
2328
|
+
return self->op_completed_with_error(std::move(cb), e);
|
|
2329
|
+
} catch (const op_exception& ex) {
|
|
2330
|
+
return self->op_completed_with_error(std::move(cb), ex);
|
|
2331
|
+
} catch (const std::exception& e) {
|
|
2332
|
+
return self->op_completed_with_error(std::move(cb),
|
|
2333
|
+
transaction_operation_failed(FAIL_OTHER, e.what()));
|
|
2334
|
+
} catch (...) {
|
|
2335
|
+
return self->op_completed_with_error(
|
|
2336
|
+
std::move(cb), transaction_operation_failed(FAIL_OTHER, "unexpected error"));
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
// make a transaction_get_result from the row...
|
|
2340
|
+
try {
|
|
2341
|
+
if (resp.rows.empty()) {
|
|
2342
|
+
// A successful insert query must return the staged document row; no rows is an
|
|
2343
|
+
// unexpected protocol condition. front() on an empty vector is UB, so guard explicitly.
|
|
2344
|
+
return self->op_completed_with_error(
|
|
2345
|
+
std::move(cb),
|
|
2346
|
+
transaction_operation_failed(FAIL_OTHER, "insert query returned no rows"));
|
|
2347
|
+
}
|
|
2348
|
+
CB_ATTEMPT_CTX_LOG_TRACE(self, "insert_raw_with_query got: {}", resp.rows.front());
|
|
2349
|
+
transaction_get_result doc(id, core::utils::json::parse(resp.rows.front()));
|
|
2350
|
+
return self->op_completed_with_callback(std::move(cb),
|
|
2351
|
+
std::optional<transaction_get_result>(doc));
|
|
2352
|
+
} catch (const std::exception& e) {
|
|
2353
|
+
// Unexpected error here: fail with FAIL_OTHER so the transaction rolls back.
|
|
2354
|
+
return self->op_completed_with_error(std::move(cb),
|
|
2355
|
+
transaction_operation_failed(FAIL_OTHER, e.what()));
|
|
2356
|
+
}
|
|
2306
2357
|
});
|
|
2307
2358
|
}
|
|
2308
2359
|
|
|
@@ -2311,91 +2362,103 @@ attempt_context_impl::replace_raw_with_query(const transaction_get_result& docum
|
|
|
2311
2362
|
codec::encoded_value content,
|
|
2312
2363
|
Callback&& cb)
|
|
2313
2364
|
{
|
|
2314
|
-
cache_error_async(
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
}
|
|
2365
|
+
// Called only from replace(), already within its cache_error_async() (op counted,
|
|
2366
|
+
// existing_error() checked); see insert_raw_with_query() for why we do not re-wrap.
|
|
2367
|
+
auto self = shared_from_this();
|
|
2368
|
+
const couchbase::transactions::transaction_query_options opts;
|
|
2369
|
+
return self->wrap_query(
|
|
2370
|
+
KV_REPLACE,
|
|
2371
|
+
opts,
|
|
2372
|
+
make_params(document.id(), std::move(content)),
|
|
2373
|
+
make_kv_txdata(document),
|
|
2374
|
+
STAGE_QUERY_KV_REPLACE,
|
|
2375
|
+
true,
|
|
2376
|
+
{},
|
|
2377
|
+
[self, id = document.id(), cb = std::move(cb)](const std::exception_ptr& err,
|
|
2378
|
+
core::operations::query_response resp) mutable {
|
|
2379
|
+
if (err) {
|
|
2380
|
+
try {
|
|
2381
|
+
std::rethrow_exception(err);
|
|
2382
|
+
} catch (const query_cas_mismatch& e) {
|
|
2383
|
+
return self->op_completed_with_error(
|
|
2384
|
+
std::move(cb), transaction_operation_failed(FAIL_CAS_MISMATCH, e.what()).retry());
|
|
2385
|
+
} catch (const document_not_found& e) {
|
|
2386
|
+
return self->op_completed_with_error(
|
|
2387
|
+
std::move(cb), transaction_operation_failed(FAIL_DOC_NOT_FOUND, e.what()).retry());
|
|
2388
|
+
} catch (const transaction_operation_failed& e) {
|
|
2389
|
+
return self->op_completed_with_error(std::move(cb), e);
|
|
2390
|
+
} catch (const op_exception& ex) {
|
|
2391
|
+
return self->op_completed_with_error(std::move(cb), ex);
|
|
2392
|
+
} catch (std::exception& e) {
|
|
2393
|
+
return self->op_completed_with_error(std::move(cb),
|
|
2394
|
+
transaction_operation_failed(FAIL_OTHER, e.what()));
|
|
2395
|
+
} catch (...) {
|
|
2396
|
+
return self->op_completed_with_error(
|
|
2397
|
+
std::move(cb), transaction_operation_failed(FAIL_OTHER, "unexpected exception"));
|
|
2398
|
+
}
|
|
2399
|
+
}
|
|
2400
|
+
// make a transaction_get_result from the row...
|
|
2401
|
+
try {
|
|
2402
|
+
if (resp.rows.empty()) {
|
|
2403
|
+
// A successful replace query must return the staged document row; no rows is an
|
|
2404
|
+
// unexpected protocol condition. front() on an empty vector is UB, so guard explicitly.
|
|
2405
|
+
return self->op_completed_with_error(
|
|
2406
|
+
std::move(cb),
|
|
2407
|
+
transaction_operation_failed(FAIL_OTHER, "replace query returned no rows"));
|
|
2408
|
+
}
|
|
2409
|
+
CB_ATTEMPT_CTX_LOG_TRACE(self, "replace_raw_with_query got: {}", resp.rows.front());
|
|
2410
|
+
transaction_get_result doc(id, core::utils::json::parse(resp.rows.front()));
|
|
2411
|
+
return self->op_completed_with_callback(std::move(cb),
|
|
2412
|
+
std::optional<transaction_get_result>(doc));
|
|
2413
|
+
} catch (const std::exception& e) {
|
|
2414
|
+
// Unexpected error here: fail with FAIL_OTHER so the transaction rolls back.
|
|
2415
|
+
return self->op_completed_with_error(std::move(cb),
|
|
2416
|
+
transaction_operation_failed(FAIL_OTHER, e.what()));
|
|
2417
|
+
}
|
|
2358
2418
|
});
|
|
2359
2419
|
}
|
|
2360
2420
|
|
|
2361
2421
|
void
|
|
2362
2422
|
attempt_context_impl::remove_with_query(const transaction_get_result& document, VoidCallback&& cb)
|
|
2363
2423
|
{
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2424
|
+
// Called only from remove(), already within its cache_error_async() (op counted,
|
|
2425
|
+
// existing_error() checked); see insert_raw_with_query() for why we do not re-wrap.
|
|
2426
|
+
auto self = shared_from_this();
|
|
2427
|
+
const couchbase::transactions::transaction_query_options opts;
|
|
2428
|
+
return self->wrap_query(
|
|
2429
|
+
KV_REMOVE,
|
|
2430
|
+
opts,
|
|
2431
|
+
make_params(document.id(), {}),
|
|
2432
|
+
make_kv_txdata(document),
|
|
2433
|
+
STAGE_QUERY_KV_REMOVE,
|
|
2434
|
+
true,
|
|
2435
|
+
{},
|
|
2436
|
+
[self, id = document.id(), cb = std::move(cb)](
|
|
2437
|
+
const std::exception_ptr& err, const core::operations::query_response& /* resp */) mutable {
|
|
2438
|
+
if (err) {
|
|
2439
|
+
try {
|
|
2440
|
+
std::rethrow_exception(err);
|
|
2441
|
+
} catch (const transaction_operation_failed& e) {
|
|
2442
|
+
return self->op_completed_with_error(std::move(cb), e);
|
|
2443
|
+
} catch (const document_not_found& e) {
|
|
2444
|
+
return self->op_completed_with_error(
|
|
2445
|
+
std::move(cb), transaction_operation_failed(FAIL_DOC_NOT_FOUND, e.what()).retry());
|
|
2446
|
+
} catch (const query_cas_mismatch& e) {
|
|
2447
|
+
return self->op_completed_with_error(
|
|
2448
|
+
std::move(cb), transaction_operation_failed(FAIL_CAS_MISMATCH, e.what()).retry());
|
|
2449
|
+
} catch (const op_exception& ex) {
|
|
2450
|
+
return self->op_completed_with_error(std::move(cb), ex);
|
|
2451
|
+
} catch (const std::exception& e) {
|
|
2452
|
+
return self->op_completed_with_error(std::move(cb),
|
|
2453
|
+
transaction_operation_failed(FAIL_OTHER, e.what()));
|
|
2454
|
+
} catch (...) {
|
|
2455
|
+
return self->op_completed_with_error(
|
|
2456
|
+
std::move(cb), transaction_operation_failed(FAIL_OTHER, "unexpected exception"));
|
|
2394
2457
|
}
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2458
|
+
}
|
|
2459
|
+
// make a transaction_get_result from the row...
|
|
2460
|
+
return self->op_completed_with_callback(std::move(cb));
|
|
2461
|
+
});
|
|
2399
2462
|
}
|
|
2400
2463
|
|
|
2401
2464
|
void
|
|
@@ -3176,10 +3239,10 @@ attempt_context_impl::set_atr_pending_locked(
|
|
|
3176
3239
|
// This bounds the value to [0-timeout]. It should always be in this
|
|
3177
3240
|
// range, this is just to protect against the application clock
|
|
3178
3241
|
// changing.
|
|
3179
|
-
const
|
|
3242
|
+
const auto remaining_bounded_nanos =
|
|
3180
3243
|
std::max(std::min(remaining.count(), self->overall()->config().timeout.count()),
|
|
3181
3244
|
static_cast<std::chrono::nanoseconds::rep>(0));
|
|
3182
|
-
const
|
|
3245
|
+
const auto remaining_bounded_msecs = remaining_bounded_nanos / 1'000'000;
|
|
3183
3246
|
|
|
3184
3247
|
core::operations::mutate_in_request req{ self->atr_id_.value() };
|
|
3185
3248
|
|
|
@@ -3338,6 +3401,7 @@ attempt_context_impl::do_get(const core::document_id& id,
|
|
|
3338
3401
|
return self->get_doc(
|
|
3339
3402
|
id,
|
|
3340
3403
|
allow_replica,
|
|
3404
|
+
std::nullopt,
|
|
3341
3405
|
[self,
|
|
3342
3406
|
id,
|
|
3343
3407
|
allow_replica,
|
|
@@ -3513,6 +3577,7 @@ execute_lookup(attempt_context_impl* ctx, LookupInRequest& req, Callback&& cb)
|
|
|
3513
3577
|
void
|
|
3514
3578
|
attempt_context_impl::get_doc(const core::document_id& id,
|
|
3515
3579
|
bool allow_replica,
|
|
3580
|
+
std::optional<std::chrono::milliseconds> timeout,
|
|
3516
3581
|
std::function<void(std::optional<error_class>,
|
|
3517
3582
|
std::optional<external_exception>,
|
|
3518
3583
|
std::optional<std::string>,
|
|
@@ -3536,27 +3601,21 @@ attempt_context_impl::get_doc(const core::document_id& id,
|
|
|
3536
3601
|
|
|
3537
3602
|
try {
|
|
3538
3603
|
if (allow_replica) {
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
}
|
|
3550
|
-
core::operations::lookup_in_any_replica_request req{ id };
|
|
3551
|
-
req.read_preference = couchbase::read_preference::selected_server_group_or_all_available;
|
|
3552
|
-
req.specs = specs;
|
|
3553
|
-
req.access_deleted = config->capabilities.supports_subdoc_access_deleted();
|
|
3554
|
-
execute_lookup(this, req, cb);
|
|
3555
|
-
});
|
|
3604
|
+
// Per the transactions spec ("Fetching an individual document") and MB-63241, a replica read
|
|
3605
|
+
// must not be combined with the accessDeleted flag; the reference SDKs omit it on the replica
|
|
3606
|
+
// path. We therefore always read replicas without accessDeleted (so tombstones are not
|
|
3607
|
+
// visible there) and need no bucket-config capability probe.
|
|
3608
|
+
core::operations::lookup_in_any_replica_request req{ id };
|
|
3609
|
+
req.read_preference = couchbase::read_preference::selected_server_group_or_all_available;
|
|
3610
|
+
req.specs = specs;
|
|
3611
|
+
req.access_deleted = false;
|
|
3612
|
+
req.timeout = timeout;
|
|
3613
|
+
execute_lookup(this, req, cb);
|
|
3556
3614
|
} else {
|
|
3557
3615
|
core::operations::lookup_in_request req{ id };
|
|
3558
3616
|
req.access_deleted = true;
|
|
3559
3617
|
req.specs = specs;
|
|
3618
|
+
req.timeout = timeout;
|
|
3560
3619
|
execute_lookup(this, req, cb);
|
|
3561
3620
|
}
|
|
3562
3621
|
} catch (const std::exception& e) {
|
|
@@ -3593,8 +3652,8 @@ attempt_context_impl::create_staged_insert_error_handler(const core::document_id
|
|
|
3593
3652
|
transaction_operation_failed(ec, "transient error in insert").retry());
|
|
3594
3653
|
case FAIL_AMBIGUOUS:
|
|
3595
3654
|
CB_ATTEMPT_CTX_LOG_DEBUG(this, "FAIL_AMBIGUOUS in create_staged_insert, retrying");
|
|
3596
|
-
|
|
3597
|
-
|
|
3655
|
+
return retry_create_staged_insert(
|
|
3656
|
+
id, content, cas, std::forward<Delay>(delay), op_id, std::forward<Handler>(cb));
|
|
3598
3657
|
case FAIL_OTHER:
|
|
3599
3658
|
return op_completed_with_error(
|
|
3600
3659
|
std::forward<Handler>(cb),
|
|
@@ -3655,6 +3714,7 @@ attempt_context_impl::create_staged_insert_error_handler(const core::document_id
|
|
|
3655
3714
|
return self->get_doc(
|
|
3656
3715
|
id,
|
|
3657
3716
|
false,
|
|
3717
|
+
std::nullopt,
|
|
3658
3718
|
[self, id, content, op_id, cb = std::forward<Handler>(cb), error_handler, delay](
|
|
3659
3719
|
std::optional<error_class> ec3,
|
|
3660
3720
|
std::optional<external_exception> /* cause */,
|
|
@@ -3682,8 +3742,7 @@ attempt_context_impl::create_staged_insert_error_handler(const core::document_id
|
|
|
3682
3742
|
"create staged insert found existing deleted doc, "
|
|
3683
3743
|
"retrying with cas {}",
|
|
3684
3744
|
doc->cas().value());
|
|
3685
|
-
|
|
3686
|
-
return self->create_staged_insert(
|
|
3745
|
+
return self->retry_create_staged_insert(
|
|
3687
3746
|
id, content, doc->cas().value(), delay, op_id, std::forward<Handler>(cb));
|
|
3688
3747
|
}
|
|
3689
3748
|
if (!doc->links().is_document_in_transaction()) {
|
|
@@ -3735,9 +3794,8 @@ attempt_context_impl::create_staged_insert_error_handler(const core::document_id
|
|
|
3735
3794
|
"doc ok to overwrite, retrying create_staged_insert "
|
|
3736
3795
|
"with cas {}",
|
|
3737
3796
|
doc->cas().value());
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
id, content, doc->cas().value(), delay, op_id, std::forward<Handler>(cb));
|
|
3797
|
+
return self->retry_create_staged_insert(
|
|
3798
|
+
id, content, doc->cas().value(), delay, op_id, std::move(cb));
|
|
3741
3799
|
});
|
|
3742
3800
|
} else {
|
|
3743
3801
|
// no doc now, just retry entire txn
|
|
@@ -3763,6 +3821,58 @@ attempt_context_impl::create_staged_insert_error_handler(const core::document_id
|
|
|
3763
3821
|
}
|
|
3764
3822
|
}
|
|
3765
3823
|
|
|
3824
|
+
auto
|
|
3825
|
+
attempt_context_impl::staged_insert_delay() const -> std::shared_ptr<async_timed_exp_delay>
|
|
3826
|
+
{
|
|
3827
|
+
auto delay = std::make_shared<async_timed_exp_delay>(
|
|
3828
|
+
std::make_shared<asio::steady_timer>(cluster_ref().io_context()),
|
|
3829
|
+
std::chrono::milliseconds(5),
|
|
3830
|
+
std::chrono::milliseconds(300),
|
|
3831
|
+
overall()->config().timeout);
|
|
3832
|
+
// The transaction expiry bounds the retries; a retry limit would fail a long transaction early.
|
|
3833
|
+
delay->max_retries = std::numeric_limits<std::size_t>::max();
|
|
3834
|
+
return delay;
|
|
3835
|
+
}
|
|
3836
|
+
|
|
3837
|
+
template<typename Handler, typename Delay>
|
|
3838
|
+
void
|
|
3839
|
+
attempt_context_impl::retry_create_staged_insert(const core::document_id& id,
|
|
3840
|
+
const codec::encoded_value& content,
|
|
3841
|
+
std::uint64_t cas,
|
|
3842
|
+
Delay&& delay,
|
|
3843
|
+
const std::string& op_id,
|
|
3844
|
+
Handler&& cb)
|
|
3845
|
+
{
|
|
3846
|
+
auto shared_delay = delay;
|
|
3847
|
+
(*shared_delay)([self = shared_from_this(),
|
|
3848
|
+
id,
|
|
3849
|
+
content = content,
|
|
3850
|
+
cas,
|
|
3851
|
+
delay = std::forward<Delay>(delay),
|
|
3852
|
+
op_id,
|
|
3853
|
+
cb = std::forward<Handler>(cb)](const std::exception_ptr& delay_err) mutable {
|
|
3854
|
+
if (delay_err) {
|
|
3855
|
+
try {
|
|
3856
|
+
std::rethrow_exception(delay_err);
|
|
3857
|
+
} catch (const retry_operation_timeout&) {
|
|
3858
|
+
return self->create_staged_insert_error_handler(id,
|
|
3859
|
+
content,
|
|
3860
|
+
cas,
|
|
3861
|
+
delay,
|
|
3862
|
+
op_id,
|
|
3863
|
+
std::move(cb),
|
|
3864
|
+
FAIL_EXPIRY,
|
|
3865
|
+
UNKNOWN,
|
|
3866
|
+
"create_staged_insert retries timed out");
|
|
3867
|
+
} catch (const std::exception& e) {
|
|
3868
|
+
return self->op_completed_with_error(std::move(cb),
|
|
3869
|
+
transaction_operation_failed(FAIL_OTHER, e.what()));
|
|
3870
|
+
}
|
|
3871
|
+
}
|
|
3872
|
+
return self->create_staged_insert(id, std::move(content), cas, delay, op_id, std::move(cb));
|
|
3873
|
+
});
|
|
3874
|
+
}
|
|
3875
|
+
|
|
3766
3876
|
template<typename Handler, typename Delay>
|
|
3767
3877
|
void
|
|
3768
3878
|
attempt_context_impl::create_staged_insert(const core::document_id& id,
|
|
@@ -3798,6 +3908,17 @@ attempt_context_impl::create_staged_insert(const core::document_id& id,
|
|
|
3798
3908
|
UNKNOWN,
|
|
3799
3909
|
"before_staged_insert hook threw error");
|
|
3800
3910
|
}
|
|
3911
|
+
// ExtThreadSafety invariant (couchbase-transactions-specs/transactions-extensions.md,
|
|
3912
|
+
// "ExtThreadSafety"): "no KV operations are staged but not sent in the BEGIN WORK" and
|
|
3913
|
+
// "no KV operations are performed regularly after queryMode is entered". insert()
|
|
3914
|
+
// reads the mode only after this op is counted in the wait-group, and set_query_mode()
|
|
3915
|
+
// drains all in-flight KV ops before issuing BEGIN WORK -- so reaching this staging
|
|
3916
|
+
// point with query mode already entered means that ordering has regressed and the
|
|
3917
|
+
// mutation would be silently lost at commit. Fires loudly in debug/FIT builds;
|
|
3918
|
+
// compiled out in release.
|
|
3919
|
+
assert(!op_list_.query_mode_entered() &&
|
|
3920
|
+
"ExtThreadSafety: KV insert staged after query mode entered -- would be missing "
|
|
3921
|
+
"from BEGIN WORK and lost at commit");
|
|
3801
3922
|
CB_ATTEMPT_CTX_LOG_DEBUG(this, "about to insert staged doc {} with cas {}", id, cas);
|
|
3802
3923
|
core::operations::mutate_in_request req{ id };
|
|
3803
3924
|
const bool binary =
|