couchbase 3.8.2 → 3.9.1
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 +1 -1
- 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 +121 -55
- data/ext/cache/mozilla-ca-bundle.sha256 +1 -1
- data/ext/couchbase/CMakeLists.txt +136 -23
- 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 +82 -7
- 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 +1551 -397
- 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 +229 -42
- 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 +1 -2
- 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 +309 -301
- 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 +151 -21
- data/ext/couchbase/core/io/streams.hxx +48 -1
- 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/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 +60 -6
- 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 +108 -63
- data/ext/couchbase/core/transactions/attempt_context_impl.hxx +19 -2
- 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 +165 -72
- 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 +2 -2
- 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 +13 -37
- 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 +183 -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 +33 -1
- 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 +17 -0
- 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 +174 -42
- 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 +91 -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
|
@@ -17,8 +17,6 @@
|
|
|
17
17
|
|
|
18
18
|
#pragma once
|
|
19
19
|
|
|
20
|
-
#include <couchbase/build_config.hxx>
|
|
21
|
-
|
|
22
20
|
#include "core/cluster_credentials.hxx"
|
|
23
21
|
#include "core/protocol/hello_feature.hxx"
|
|
24
22
|
#include "core/response_handler.hxx"
|
|
@@ -45,18 +43,16 @@ class context;
|
|
|
45
43
|
} // namespace ssl
|
|
46
44
|
} // namespace asio
|
|
47
45
|
|
|
46
|
+
namespace couchbase::core::mcbp
|
|
47
|
+
{
|
|
48
|
+
class queue_request;
|
|
49
|
+
} // namespace couchbase::core::mcbp
|
|
50
|
+
|
|
48
51
|
namespace couchbase::core
|
|
49
52
|
{
|
|
50
53
|
struct origin;
|
|
51
54
|
class config_listener;
|
|
52
55
|
|
|
53
|
-
#ifdef COUCHBASE_CXX_CLIENT_COLUMNAR
|
|
54
|
-
namespace columnar
|
|
55
|
-
{
|
|
56
|
-
class background_bootstrap_listener;
|
|
57
|
-
} // namespace columnar
|
|
58
|
-
#endif
|
|
59
|
-
|
|
60
56
|
namespace topology
|
|
61
57
|
{
|
|
62
58
|
struct configuration;
|
|
@@ -74,6 +70,9 @@ struct bootstrap_error;
|
|
|
74
70
|
class bootstrap_state_listener;
|
|
75
71
|
} // namespace impl
|
|
76
72
|
|
|
73
|
+
class app_telemetry_meter;
|
|
74
|
+
class app_telemetry_value_recorder;
|
|
75
|
+
|
|
77
76
|
namespace io
|
|
78
77
|
{
|
|
79
78
|
class mcbp_session_impl;
|
|
@@ -108,7 +107,18 @@ public:
|
|
|
108
107
|
std::optional<std::string> bucket_name = {},
|
|
109
108
|
std::vector<protocol::hello_feature> known_features = {});
|
|
110
109
|
|
|
111
|
-
|
|
110
|
+
/**
|
|
111
|
+
* Constructs a session handle from an existing implementation pointer.
|
|
112
|
+
*
|
|
113
|
+
* Used internally by @ref mcbp_session_impl to create a lightweight snapshot of
|
|
114
|
+
* the session that can be passed to @ref response_handler::handle_response without
|
|
115
|
+
* transferring ownership of the live session. The snapshot shares the same
|
|
116
|
+
* @ref impl_ and therefore exposes the same connection metadata (remote/local
|
|
117
|
+
* address and port) at the time the response is delivered.
|
|
118
|
+
*/
|
|
119
|
+
explicit mcbp_session(std::shared_ptr<mcbp_session_impl> impl);
|
|
120
|
+
|
|
121
|
+
[[nodiscard]] auto log_prefix() const -> std::string;
|
|
112
122
|
[[nodiscard]] auto cancel(std::uint32_t opaque, std::error_code ec, retry_reason reason) -> bool;
|
|
113
123
|
[[nodiscard]] auto is_stopped() const -> bool;
|
|
114
124
|
[[nodiscard]] auto is_bootstrapped() const -> bool;
|
|
@@ -120,6 +130,11 @@ public:
|
|
|
120
130
|
[[nodiscard]] auto supported_features() const -> std::vector<protocol::hello_feature>;
|
|
121
131
|
[[nodiscard]] auto id() const -> const std::string&;
|
|
122
132
|
[[nodiscard]] auto node_uuid() const -> const std::string&;
|
|
133
|
+
// Resolve the app_telemetry recorder for this connection, cached per connection and re-resolved
|
|
134
|
+
// only when the meter's generation changes (see app_telemetry_recorder_cache).
|
|
135
|
+
[[nodiscard]] auto app_telemetry_recorder(app_telemetry_meter& meter,
|
|
136
|
+
const std::string& bucket_name) const
|
|
137
|
+
-> std::shared_ptr<app_telemetry_value_recorder>;
|
|
123
138
|
[[nodiscard]] auto remote_address() const -> std::string;
|
|
124
139
|
[[nodiscard]] auto remote_hostname() const -> std::string;
|
|
125
140
|
[[nodiscard]] auto remote_port() const -> std::uint16_t;
|
|
@@ -128,12 +143,10 @@ public:
|
|
|
128
143
|
[[nodiscard]] auto bootstrap_hostname() const -> const std::string&;
|
|
129
144
|
[[nodiscard]] auto bootstrap_port() const -> const std::string&;
|
|
130
145
|
[[nodiscard]] auto bootstrap_port_number() const -> std::uint16_t;
|
|
131
|
-
[[nodiscard]] auto last_bootstrap_error() && -> std::optional<impl::bootstrap_error>;
|
|
132
|
-
[[nodiscard]] auto last_bootstrap_error() const& -> const std::optional<impl::bootstrap_error>&;
|
|
133
146
|
[[nodiscard]] auto canonical_hostname() const -> const std::string&;
|
|
134
147
|
[[nodiscard]] auto canonical_port_number() const -> std::uint16_t;
|
|
135
148
|
void write_and_flush(std::vector<std::byte>&& buffer);
|
|
136
|
-
void write_and_subscribe(const std::shared_ptr<mcbp::queue_request
|
|
149
|
+
void write_and_subscribe(const std::shared_ptr<mcbp::queue_request>& request,
|
|
137
150
|
const std::shared_ptr<response_handler>& handler);
|
|
138
151
|
void write_and_subscribe(std::uint32_t opaque,
|
|
139
152
|
std::vector<std::byte>&& data,
|
|
@@ -150,16 +163,12 @@ public:
|
|
|
150
163
|
[[nodiscard]] auto diag_info() const -> diag::endpoint_diag_info;
|
|
151
164
|
void on_configuration_update(std::shared_ptr<config_listener> handler);
|
|
152
165
|
void ping(const std::shared_ptr<diag::ping_reporter>& handler,
|
|
153
|
-
std::optional<std::chrono::milliseconds> = {}) const;
|
|
166
|
+
std::optional<std::chrono::milliseconds> timeout = {}) const;
|
|
154
167
|
[[nodiscard]] auto supports_gcccp() const -> bool;
|
|
155
168
|
[[nodiscard]] auto decode_error_code(std::uint16_t code)
|
|
156
169
|
-> std::optional<key_value_error_map_info>;
|
|
157
170
|
void handle_not_my_vbucket(const io::mcbp_message& msg) const;
|
|
158
171
|
void update_collection_uid(const std::string& path, std::uint32_t uid);
|
|
159
|
-
#ifdef COUCHBASE_CXX_CLIENT_COLUMNAR
|
|
160
|
-
void add_background_bootstrap_listener(
|
|
161
|
-
std::shared_ptr<columnar::background_bootstrap_listener> listener);
|
|
162
|
-
#endif
|
|
163
172
|
|
|
164
173
|
private:
|
|
165
174
|
std::shared_ptr<mcbp_session_impl> impl_{ nullptr };
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2024. Couchbase, Inc.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#pragma once
|
|
19
|
+
|
|
20
|
+
#include <array>
|
|
21
|
+
#include <cstddef>
|
|
22
|
+
#include <cstdint>
|
|
23
|
+
#include <unordered_map>
|
|
24
|
+
#include <utility>
|
|
25
|
+
#include <vector>
|
|
26
|
+
|
|
27
|
+
namespace couchbase::core::io
|
|
28
|
+
{
|
|
29
|
+
/**
|
|
30
|
+
* Maps a monotonically increasing 32-bit opaque to an in-flight handler without a per-operation
|
|
31
|
+
* heap allocation.
|
|
32
|
+
*
|
|
33
|
+
* The common case uses a fixed ring indexed by `opaque & mask`. Because the opaque increases by one
|
|
34
|
+
* per operation, in-flight operations occupy distinct slots as long as the range between the oldest
|
|
35
|
+
* and newest in-flight opaque stays within the ring; when it does not (a slow operation held open
|
|
36
|
+
* across a full lap of the ring, or opaque wraparound), the colliding entries spill to an overflow
|
|
37
|
+
* map, so lookups stay correct for any number of in-flight operations.
|
|
38
|
+
*
|
|
39
|
+
* Precondition: an opaque is unique while it is in flight — a value is never registered again
|
|
40
|
+
* before its handler has been taken. The single caller guarantees this by allocating a fresh opaque
|
|
41
|
+
* per operation, which is what lets insert() store into a free ring slot without also consulting
|
|
42
|
+
* the overflow map.
|
|
43
|
+
*
|
|
44
|
+
* Not thread-safe: callers serialize access.
|
|
45
|
+
*/
|
|
46
|
+
template<typename Handler>
|
|
47
|
+
class opaque_ring_table
|
|
48
|
+
{
|
|
49
|
+
public:
|
|
50
|
+
// Register a handler for an opaque. Relies on the unique-in-flight precondition: because a fresh
|
|
51
|
+
// opaque is never already registered, it always finds either a free ring slot or (on a ring
|
|
52
|
+
// collision) a free overflow entry. If the target ring slot happens to already hold the same
|
|
53
|
+
// opaque, insert() keeps the existing handler -- but that is a cheap same-slot guard only; the
|
|
54
|
+
// overflow map is deliberately not consulted (that would add a lookup to every insert on the hot
|
|
55
|
+
// path). Re-registering an opaque that is still in flight therefore violates the precondition and
|
|
56
|
+
// is not a supported dedup: if the original spilled to overflow_ and its ring slot has since been
|
|
57
|
+
// reclaimed, a duplicate would land in the ring and strand the overflow copy.
|
|
58
|
+
//
|
|
59
|
+
// The handler is taken by rvalue reference and moved into storage exactly once (handlers are
|
|
60
|
+
// move-only and every call site passes an rvalue), avoiding the extra move a by-value parameter
|
|
61
|
+
// would add on the hot path.
|
|
62
|
+
void insert(std::uint32_t opaque, Handler&& handler);
|
|
63
|
+
|
|
64
|
+
// Remove and return the handler for an opaque, or a default-constructed (empty) handler if
|
|
65
|
+
// absent. The returned handler is the sole owner; dropping it strands the operation, hence
|
|
66
|
+
// [[nodiscard]].
|
|
67
|
+
[[nodiscard]] auto take(std::uint32_t opaque) -> Handler;
|
|
68
|
+
|
|
69
|
+
// Move out every registered (opaque, handler) pair and clear the table. The returned handlers are
|
|
70
|
+
// the sole remaining owners, hence [[nodiscard]].
|
|
71
|
+
[[nodiscard]] auto drain() -> std::vector<std::pair<std::uint32_t, Handler>>;
|
|
72
|
+
|
|
73
|
+
private:
|
|
74
|
+
static constexpr std::size_t ring_size = 512;
|
|
75
|
+
static constexpr std::uint32_t ring_mask = ring_size - 1;
|
|
76
|
+
// `opaque & ring_mask` is a valid modulo only when the size is a power of two.
|
|
77
|
+
static_assert((ring_size & (ring_size - 1)) == 0, "ring_size must be a power of two");
|
|
78
|
+
|
|
79
|
+
struct slot {
|
|
80
|
+
std::uint32_t opaque{ 0 };
|
|
81
|
+
bool occupied{ false };
|
|
82
|
+
Handler handler{};
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
std::array<slot, ring_size> ring_{};
|
|
86
|
+
std::unordered_map<std::uint32_t, Handler> overflow_{};
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
template<typename Handler>
|
|
90
|
+
void
|
|
91
|
+
opaque_ring_table<Handler>::insert(std::uint32_t opaque, Handler&& handler)
|
|
92
|
+
{
|
|
93
|
+
auto& s = ring_[opaque & ring_mask];
|
|
94
|
+
if (!s.occupied) {
|
|
95
|
+
s.opaque = opaque;
|
|
96
|
+
s.occupied = true;
|
|
97
|
+
s.handler = std::move(handler);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (s.opaque == opaque) {
|
|
101
|
+
return; // keep the existing handler (not expected under the unique-opaque precondition)
|
|
102
|
+
}
|
|
103
|
+
// the slot is held by a different in-flight opaque (ring collision) — spill to the overflow map
|
|
104
|
+
overflow_.try_emplace(opaque, std::move(handler));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
template<typename Handler>
|
|
108
|
+
auto
|
|
109
|
+
opaque_ring_table<Handler>::take(std::uint32_t opaque) -> Handler
|
|
110
|
+
{
|
|
111
|
+
auto& s = ring_[opaque & ring_mask];
|
|
112
|
+
if (s.occupied && s.opaque == opaque) {
|
|
113
|
+
Handler h = std::move(s.handler);
|
|
114
|
+
s.handler = Handler{};
|
|
115
|
+
s.occupied = false;
|
|
116
|
+
return h;
|
|
117
|
+
}
|
|
118
|
+
if (auto it = overflow_.find(opaque); it != overflow_.end()) {
|
|
119
|
+
Handler h = std::move(it->second);
|
|
120
|
+
overflow_.erase(it);
|
|
121
|
+
return h;
|
|
122
|
+
}
|
|
123
|
+
return Handler{};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
template<typename Handler>
|
|
127
|
+
auto
|
|
128
|
+
opaque_ring_table<Handler>::drain() -> std::vector<std::pair<std::uint32_t, Handler>>
|
|
129
|
+
{
|
|
130
|
+
std::vector<std::pair<std::uint32_t, Handler>> result;
|
|
131
|
+
result.reserve(ring_size + overflow_.size());
|
|
132
|
+
for (auto& s : ring_) {
|
|
133
|
+
if (s.occupied) {
|
|
134
|
+
result.emplace_back(s.opaque, std::move(s.handler));
|
|
135
|
+
s.handler = Handler{};
|
|
136
|
+
s.occupied = false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
for (auto& [opaque, h] : overflow_) {
|
|
140
|
+
result.emplace_back(opaque, std::move(h));
|
|
141
|
+
}
|
|
142
|
+
overflow_.clear();
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
} // namespace couchbase::core::io
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
#pragma once
|
|
19
19
|
|
|
20
20
|
#include "core/logger/logger.hxx"
|
|
21
|
+
#include "core/logger/redaction.hxx"
|
|
21
22
|
#include "core/protocol/client_opcode_fmt.hxx"
|
|
22
23
|
|
|
23
24
|
#include <couchbase/best_effort_retry_strategy.hxx>
|
|
@@ -33,8 +34,8 @@ namespace priv
|
|
|
33
34
|
{
|
|
34
35
|
template<class Command>
|
|
35
36
|
auto
|
|
36
|
-
cap_duration(std::chrono::milliseconds uncapped,
|
|
37
|
-
|
|
37
|
+
cap_duration(std::chrono::milliseconds uncapped, std::shared_ptr<Command> command)
|
|
38
|
+
-> std::chrono::milliseconds
|
|
38
39
|
{
|
|
39
40
|
auto theoretical_deadline = std::chrono::steady_clock::now() + uncapped;
|
|
40
41
|
auto absolute_deadline = command->deadline.expiry();
|
|
@@ -63,11 +64,11 @@ retry_with_duration(std::shared_ptr<Manager> manager,
|
|
|
63
64
|
manager->log_prefix(),
|
|
64
65
|
decltype(command->request)::encoded_request_type::body_type::opcode,
|
|
65
66
|
duration.count(),
|
|
66
|
-
command->
|
|
67
|
+
command->id(),
|
|
67
68
|
command->request.partition,
|
|
68
69
|
reason,
|
|
69
70
|
command->request.retries.retry_attempts(),
|
|
70
|
-
command->session_ ? command->session_->remote_address() : "");
|
|
71
|
+
logger::system_data(command->session_ ? command->session_->remote_address() : ""));
|
|
71
72
|
manager->schedule_for_retry(command, duration);
|
|
72
73
|
}
|
|
73
74
|
|
|
@@ -98,7 +99,7 @@ maybe_retry(std::shared_ptr<Manager> manager,
|
|
|
98
99
|
CB_LOG_TRACE(R"({} not retrying operation {} (id="{}", reason={}, attempts={}, ec={} ({})))",
|
|
99
100
|
manager->log_prefix(),
|
|
100
101
|
decltype(command->request)::encoded_request_type::body_type::opcode,
|
|
101
|
-
command->
|
|
102
|
+
command->id(),
|
|
102
103
|
reason,
|
|
103
104
|
command->request.retries.retry_attempts(),
|
|
104
105
|
ec.value(),
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2026-Present Couchbase, Inc.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#pragma once
|
|
19
|
+
|
|
20
|
+
#include <system_error>
|
|
21
|
+
|
|
22
|
+
namespace couchbase::core::io
|
|
23
|
+
{
|
|
24
|
+
// Which timeout a whole-stream deadline reports when it fires. The two are not interchangeable: a
|
|
25
|
+
// retry layer may replay a request that definitely did not apply, and must not replay one that may
|
|
26
|
+
// have partially executed. A deadline has no other terminal, so no other value exists.
|
|
27
|
+
enum class deadline_terminal {
|
|
28
|
+
// The request is read-only, so the server cannot have applied it.
|
|
29
|
+
unambiguous,
|
|
30
|
+
// The request may have mutated state before the deadline closed the body.
|
|
31
|
+
ambiguous,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Whether a set_deadline call installed anything.
|
|
35
|
+
enum class deadline_state {
|
|
36
|
+
// Installed. The body closes at the deadline unless something ends it first.
|
|
37
|
+
armed,
|
|
38
|
+
// Nothing was installed, and nothing needs to be: the body has already ended, by expiry, by
|
|
39
|
+
// cancellation, or by having been read to completion. A replayed buffered response starts here.
|
|
40
|
+
//
|
|
41
|
+
// This is not end-of-stream. A consumer pulling rows reaches it before its last row, because
|
|
42
|
+
// the body ends when its bytes are read and the rows parsed from them are handed out
|
|
43
|
+
// afterwards. A caller arming per operation sees it for the final rows of every stream.
|
|
44
|
+
body_already_ended,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// The error_code `terminal` is reported as.
|
|
48
|
+
[[nodiscard]] auto
|
|
49
|
+
terminal_error_code(deadline_terminal terminal) -> std::error_code;
|
|
50
|
+
} // namespace couchbase::core::io
|
|
@@ -18,16 +18,22 @@
|
|
|
18
18
|
#include "streams.hxx"
|
|
19
19
|
|
|
20
20
|
#include "core/platform/uuid.h"
|
|
21
|
+
#include "core/utils/process_id.hxx"
|
|
21
22
|
|
|
22
23
|
#include <asio.hpp>
|
|
23
24
|
#include <asio/error.hpp>
|
|
24
25
|
#include <asio/ssl.hpp>
|
|
26
|
+
#include <asio/ssl/host_name_verification.hpp>
|
|
27
|
+
// ERR_get_error()/SSL_* come from the OpenSSL or BoringSSL headers pulled in by
|
|
28
|
+
// <asio/ssl.hpp>; do not include <openssl/*.h> directly so the static BoringSSL
|
|
29
|
+
// build (which ships its own headers) keeps working, matching core/io/mcbp_session.cxx.
|
|
25
30
|
|
|
31
|
+
#include <algorithm>
|
|
26
32
|
#include <cerrno>
|
|
33
|
+
#include <memory>
|
|
34
|
+
#include <mutex>
|
|
27
35
|
|
|
28
|
-
#if defined(_WIN32)
|
|
29
|
-
#include <process.h>
|
|
30
|
-
#else
|
|
36
|
+
#if !defined(_WIN32)
|
|
31
37
|
#include <unistd.h>
|
|
32
38
|
#endif
|
|
33
39
|
|
|
@@ -35,16 +41,6 @@ namespace couchbase::core::io
|
|
|
35
41
|
{
|
|
36
42
|
namespace
|
|
37
43
|
{
|
|
38
|
-
auto
|
|
39
|
-
current_process_id() -> long long
|
|
40
|
-
{
|
|
41
|
-
#if defined(_WIN32)
|
|
42
|
-
return static_cast<long long>(::_getpid());
|
|
43
|
-
#else
|
|
44
|
-
return static_cast<long long>(::getpid());
|
|
45
|
-
#endif
|
|
46
|
-
}
|
|
47
|
-
|
|
48
44
|
/**
|
|
49
45
|
* Release a socket this process inherited across fork(2), without disturbing the
|
|
50
46
|
* connection the parent is still using.
|
|
@@ -65,10 +61,12 @@ current_process_id() -> long long
|
|
|
65
61
|
* release() also completes any outstanding asynchronous operations on this socket
|
|
66
62
|
* with operation_aborted, which is what we want: those reads belong to the parent.
|
|
67
63
|
*/
|
|
68
|
-
// Takes the basic_socket base rather than
|
|
69
|
-
//
|
|
64
|
+
// Takes the basic_socket base rather than a concrete socket type, so the same code serves the
|
|
65
|
+
// plain socket, a TLS stream's lowest_layer(), whose type is that base, and the DNS client's
|
|
66
|
+
// sockets.
|
|
67
|
+
template<typename Protocol>
|
|
70
68
|
void
|
|
71
|
-
detach_inherited_socket(asio::basic_socket<
|
|
69
|
+
detach_inherited_socket(asio::basic_socket<Protocol>& socket, asio::error_code& ec)
|
|
72
70
|
{
|
|
73
71
|
if (!socket.is_open()) {
|
|
74
72
|
ec = asio::error::bad_descriptor;
|
|
@@ -140,11 +138,127 @@ configure_tls_handshake(asio::ssl::stream<asio::ip::tcp::socket>& stream,
|
|
|
140
138
|
return ec;
|
|
141
139
|
}
|
|
142
140
|
|
|
141
|
+
// The sockets of one io_context, each with the process that opened it. Held weakly: a socket also
|
|
142
|
+
// lives in the handlers that use it, such as a close posted before a fork, and is found there too.
|
|
143
|
+
class inherited_stream_registry : public asio::execution_context::service
|
|
144
|
+
{
|
|
145
|
+
public:
|
|
146
|
+
static inline asio::execution_context::id id{};
|
|
147
|
+
|
|
148
|
+
explicit inherited_stream_registry(asio::execution_context& ctx)
|
|
149
|
+
: asio::execution_context::service(ctx)
|
|
150
|
+
{
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
void add(const std::shared_ptr<asio::ip::tcp::socket>& socket)
|
|
154
|
+
{
|
|
155
|
+
const std::scoped_lock lock(mutex_);
|
|
156
|
+
prune();
|
|
157
|
+
plain_.push_back({ socket, utils::current_process_id() });
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
void add(const std::shared_ptr<asio::ssl::stream<asio::ip::tcp::socket>>& stream)
|
|
161
|
+
{
|
|
162
|
+
const std::scoped_lock lock(mutex_);
|
|
163
|
+
prune();
|
|
164
|
+
tls_.push_back({ stream, utils::current_process_id() });
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
void add(const std::shared_ptr<asio::ip::udp::socket>& socket)
|
|
168
|
+
{
|
|
169
|
+
const std::scoped_lock lock(mutex_);
|
|
170
|
+
prune();
|
|
171
|
+
udp_.push_back({ socket, utils::current_process_id() });
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// The detach result needs no handling. asio's reactive release() fails only on a socket that is
|
|
175
|
+
// not open, which is skipped here, and once it succeeds the socket is out of the reactor with its
|
|
176
|
+
// operations aborted, so a failed close(2) cannot let anything run on the parent's connection.
|
|
177
|
+
void detach_inherited()
|
|
178
|
+
{
|
|
179
|
+
const auto pid = utils::current_process_id();
|
|
180
|
+
const std::scoped_lock lock(mutex_);
|
|
181
|
+
for (const auto& [weak, owner_pid] : plain_) {
|
|
182
|
+
if (auto socket = weak.lock(); socket && owner_pid != pid && socket->is_open()) {
|
|
183
|
+
asio::error_code ec{};
|
|
184
|
+
detach_inherited_socket(*socket, ec);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
for (const auto& [weak, owner_pid] : tls_) {
|
|
188
|
+
if (auto stream = weak.lock();
|
|
189
|
+
stream && owner_pid != pid && stream->lowest_layer().is_open()) {
|
|
190
|
+
asio::error_code ec{};
|
|
191
|
+
detach_inherited_socket(stream->lowest_layer(), ec);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
for (const auto& [weak, owner_pid] : udp_) {
|
|
195
|
+
if (auto socket = weak.lock(); socket && owner_pid != pid && socket->is_open()) {
|
|
196
|
+
asio::error_code ec{};
|
|
197
|
+
detach_inherited_socket(*socket, ec);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
prune();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
private:
|
|
204
|
+
template<typename Stream>
|
|
205
|
+
struct entry {
|
|
206
|
+
std::weak_ptr<Stream> stream;
|
|
207
|
+
std::int64_t owner_pid;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
void shutdown() override
|
|
211
|
+
{
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
void prune()
|
|
215
|
+
{
|
|
216
|
+
const auto expired = [](const auto& e) {
|
|
217
|
+
return e.stream.expired();
|
|
218
|
+
};
|
|
219
|
+
plain_.erase(std::remove_if(plain_.begin(), plain_.end(), expired), plain_.end());
|
|
220
|
+
tls_.erase(std::remove_if(tls_.begin(), tls_.end(), expired), tls_.end());
|
|
221
|
+
udp_.erase(std::remove_if(udp_.begin(), udp_.end(), expired), udp_.end());
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
std::mutex mutex_{};
|
|
225
|
+
std::vector<entry<asio::ip::tcp::socket>> plain_{};
|
|
226
|
+
std::vector<entry<asio::ssl::stream<asio::ip::tcp::socket>>> tls_{};
|
|
227
|
+
std::vector<entry<asio::ip::udp::socket>> udp_{};
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
void
|
|
231
|
+
detach_inherited_sockets(asio::io_context& ctx)
|
|
232
|
+
{
|
|
233
|
+
if (asio::has_service<inherited_stream_registry>(ctx)) {
|
|
234
|
+
asio::use_service<inherited_stream_registry>(static_cast<asio::execution_context&>(ctx))
|
|
235
|
+
.detach_inherited();
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
void
|
|
240
|
+
register_inherited_socket(asio::io_context& ctx,
|
|
241
|
+
const std::shared_ptr<asio::ip::tcp::socket>& socket)
|
|
242
|
+
{
|
|
243
|
+
asio::use_service<inherited_stream_registry>(static_cast<asio::execution_context&>(ctx))
|
|
244
|
+
.add(socket);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
void
|
|
248
|
+
register_inherited_socket(asio::io_context& ctx,
|
|
249
|
+
const std::shared_ptr<asio::ip::udp::socket>& socket)
|
|
250
|
+
{
|
|
251
|
+
asio::use_service<inherited_stream_registry>(static_cast<asio::execution_context&>(ctx))
|
|
252
|
+
.add(socket);
|
|
253
|
+
}
|
|
254
|
+
|
|
143
255
|
stream_impl::stream_impl(asio::io_context& ctx, bool is_tls)
|
|
144
|
-
:
|
|
256
|
+
: inherited_(
|
|
257
|
+
asio::use_service<inherited_stream_registry>(static_cast<asio::execution_context&>(ctx)))
|
|
258
|
+
, strand_(asio::make_strand(ctx))
|
|
145
259
|
, tls_(is_tls)
|
|
146
260
|
, id_(uuid::to_string(uuid::random()))
|
|
147
|
-
, owner_pid_(current_process_id())
|
|
261
|
+
, owner_pid_(utils::current_process_id())
|
|
148
262
|
{
|
|
149
263
|
}
|
|
150
264
|
|
|
@@ -164,6 +278,7 @@ plain_stream_impl::plain_stream_impl(asio::io_context& ctx)
|
|
|
164
278
|
: stream_impl(ctx, false)
|
|
165
279
|
, stream_(std::make_shared<asio::ip::tcp::socket>(strand_))
|
|
166
280
|
{
|
|
281
|
+
inherited_.add(stream_);
|
|
167
282
|
}
|
|
168
283
|
|
|
169
284
|
auto
|
|
@@ -201,7 +316,7 @@ plain_stream_impl::close(utils::movable_function<void(std::error_code)>&& handle
|
|
|
201
316
|
// Decide here rather than when this was posted: io_.stop() at fork_prepare
|
|
202
317
|
// does not drain the queue, so a close queued before the fork runs in the
|
|
203
318
|
// child once the io_context is restarted, and there the answer differs.
|
|
204
|
-
if (owner_pid != current_process_id()) {
|
|
319
|
+
if (owner_pid != utils::current_process_id()) {
|
|
205
320
|
detach_inherited_socket(*stream, ec);
|
|
206
321
|
} else {
|
|
207
322
|
stream->shutdown(asio::socket_base::shutdown_both, ec);
|
|
@@ -225,11 +340,13 @@ plain_stream_impl::set_options()
|
|
|
225
340
|
void
|
|
226
341
|
plain_stream_impl::async_connect(
|
|
227
342
|
const asio::ip::tcp::resolver::results_type::endpoint_type& endpoint,
|
|
343
|
+
const std::string& /* hostname */,
|
|
228
344
|
utils::movable_function<void(std::error_code)>&& handler)
|
|
229
345
|
{
|
|
230
346
|
if (!stream_) {
|
|
231
347
|
id_ = uuid::to_string(uuid::random());
|
|
232
348
|
stream_ = std::make_shared<asio::ip::tcp::socket>(strand_);
|
|
349
|
+
inherited_.add(stream_);
|
|
233
350
|
}
|
|
234
351
|
return stream_->async_connect(endpoint,
|
|
235
352
|
[stream = stream_, handler = std::move(handler)](auto ec) {
|
|
@@ -271,6 +388,7 @@ tls_stream_impl::tls_stream_impl(asio::io_context& ctx, tls_context_provider& tl
|
|
|
271
388
|
std::make_shared<asio::ssl::stream<asio::ip::tcp::socket>>(asio::ip::tcp::socket(strand_),
|
|
272
389
|
*tls_.get_ctx()))
|
|
273
390
|
{
|
|
391
|
+
inherited_.add(stream_);
|
|
274
392
|
}
|
|
275
393
|
|
|
276
394
|
auto
|
|
@@ -307,7 +425,7 @@ tls_stream_impl::close(utils::movable_function<void(std::error_code)>&& handler)
|
|
|
307
425
|
asio::error_code ec{};
|
|
308
426
|
// See plain_stream_impl::close(): the inheritance test belongs here, not at
|
|
309
427
|
// post time.
|
|
310
|
-
if (owner_pid != current_process_id()) {
|
|
428
|
+
if (owner_pid != utils::current_process_id()) {
|
|
311
429
|
detach_inherited_socket(stream->lowest_layer(), ec);
|
|
312
430
|
} else {
|
|
313
431
|
stream->lowest_layer().shutdown(asio::socket_base::shutdown_both, ec);
|
|
@@ -330,21 +448,33 @@ tls_stream_impl::set_options()
|
|
|
330
448
|
|
|
331
449
|
void
|
|
332
450
|
tls_stream_impl::async_connect(const asio::ip::tcp::resolver::results_type::endpoint_type& endpoint,
|
|
451
|
+
const std::string& hostname,
|
|
333
452
|
utils::movable_function<void(std::error_code)>&& handler)
|
|
334
453
|
{
|
|
335
454
|
if (!stream_) {
|
|
336
455
|
id_ = uuid::to_string(uuid::random());
|
|
337
456
|
stream_ = std::make_shared<asio::ssl::stream<asio::ip::tcp::socket>>(
|
|
338
457
|
asio::ip::tcp::socket(strand_), *tls_.get_ctx());
|
|
458
|
+
inherited_.add(stream_);
|
|
339
459
|
}
|
|
340
460
|
return stream_->lowest_layer().async_connect(
|
|
341
|
-
endpoint,
|
|
461
|
+
endpoint,
|
|
462
|
+
// hostname is copied into the closure (owning std::string) so the async
|
|
463
|
+
// handler does not depend on the caller's argument lifetime.
|
|
464
|
+
[stream = stream_, hostname = hostname, handler = std::move(handler)](
|
|
465
|
+
std::error_code ec_connect) mutable {
|
|
342
466
|
if (ec_connect == asio::error::operation_aborted) {
|
|
343
467
|
return;
|
|
344
468
|
}
|
|
345
469
|
if (ec_connect) {
|
|
346
470
|
return handler(ec_connect);
|
|
347
471
|
}
|
|
472
|
+
// Verify the server's identity against `hostname` (SAN/CN) and set SNI
|
|
473
|
+
// before the handshake. Without this, verify_peer only checks that the
|
|
474
|
+
// certificate chains to a trusted CA, not that it identifies this host.
|
|
475
|
+
if (auto ec_identity = configure_tls_handshake(*stream, hostname); ec_identity) {
|
|
476
|
+
return handler(ec_identity);
|
|
477
|
+
}
|
|
348
478
|
stream->async_handshake(
|
|
349
479
|
asio::ssl::stream_base::client,
|
|
350
480
|
[stream, handler = std::move(handler)](std::error_code ec_handshake) mutable {
|