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
|
@@ -18,17 +18,247 @@
|
|
|
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.
|
|
30
|
+
|
|
31
|
+
#include <algorithm>
|
|
32
|
+
#include <cerrno>
|
|
33
|
+
#include <memory>
|
|
34
|
+
#include <mutex>
|
|
35
|
+
|
|
36
|
+
#if !defined(_WIN32)
|
|
37
|
+
#include <unistd.h>
|
|
38
|
+
#endif
|
|
25
39
|
|
|
26
40
|
namespace couchbase::core::io
|
|
27
41
|
{
|
|
42
|
+
namespace
|
|
43
|
+
{
|
|
44
|
+
/**
|
|
45
|
+
* Release a socket this process inherited across fork(2), without disturbing the
|
|
46
|
+
* connection the parent is still using.
|
|
47
|
+
*
|
|
48
|
+
* Two things differ from the ordinary close path, and both matter:
|
|
49
|
+
*
|
|
50
|
+
* * No shutdown(2). It acts on the open file description, which fork(2) shares,
|
|
51
|
+
* so it would send FIN and break the parent's connection. close(2) drops only
|
|
52
|
+
* our own descriptor; the peer sees nothing.
|
|
53
|
+
* * release() before closing, rather than asio's close(). asio's close() skips
|
|
54
|
+
* EPOLL_CTL_DEL on the assumption that closing a descriptor removes its epoll
|
|
55
|
+
* registration. Per epoll(7) that happens only once *every* descriptor
|
|
56
|
+
* referring to the description is closed -- and the parent still holds one --
|
|
57
|
+
* so the registration would outlive the descriptor_state asio recycles, which
|
|
58
|
+
* is precisely the stale-pointer shape the reactor faults on. release() emits
|
|
59
|
+
* the EPOLL_CTL_DEL explicitly and hands back the raw descriptor to close.
|
|
60
|
+
*
|
|
61
|
+
* release() also completes any outstanding asynchronous operations on this socket
|
|
62
|
+
* with operation_aborted, which is what we want: those reads belong to the parent.
|
|
63
|
+
*/
|
|
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>
|
|
68
|
+
void
|
|
69
|
+
detach_inherited_socket(asio::basic_socket<Protocol>& socket, asio::error_code& ec)
|
|
70
|
+
{
|
|
71
|
+
if (!socket.is_open()) {
|
|
72
|
+
ec = asio::error::bad_descriptor;
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const auto handle = socket.release(ec);
|
|
77
|
+
if (ec) {
|
|
78
|
+
// Report it. Do not reach for asio's close() here: that is the very call
|
|
79
|
+
// whose epoll behaviour makes it unsafe on an inherited descriptor, and the
|
|
80
|
+
// descriptor goes away when this process exits anyway.
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
#if defined(_WIN32)
|
|
85
|
+
// Unreachable: without fork(2) no socket is ever inherited, so the owner pid
|
|
86
|
+
// always matches and close() never takes this path.
|
|
87
|
+
(void)handle;
|
|
88
|
+
ec = asio::error::operation_not_supported;
|
|
89
|
+
#else
|
|
90
|
+
if (::close(handle) != 0) {
|
|
91
|
+
ec.assign(errno, asio::error::get_system_category());
|
|
92
|
+
}
|
|
93
|
+
#endif
|
|
94
|
+
}
|
|
95
|
+
} // namespace
|
|
96
|
+
|
|
97
|
+
auto
|
|
98
|
+
configure_tls_handshake(asio::ssl::stream<asio::ip::tcp::socket>& stream,
|
|
99
|
+
const std::string& hostname) -> std::error_code
|
|
100
|
+
{
|
|
101
|
+
if (hostname.empty()) {
|
|
102
|
+
// Fail closed: a TLS client connection must have a hostname to verify the
|
|
103
|
+
// server's identity against. Returning success here would silently fall back
|
|
104
|
+
// to CA-only validation -- the CWE-297 problem this function exists to prevent.
|
|
105
|
+
return asio::error::make_error_code(asio::error::invalid_argument);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Send SNI so that name-based / multi-tenant TLS endpoints present the correct
|
|
109
|
+
// certificate for this hostname.
|
|
110
|
+
{
|
|
111
|
+
// SSL_set_tlsext_host_name() is a macro that expands to an internal C-style
|
|
112
|
+
// cast to void*, which trips -Wold-style-cast; suppress it locally.
|
|
113
|
+
#if defined(__GNUC__) || defined(__clang__)
|
|
114
|
+
#pragma GCC diagnostic push
|
|
115
|
+
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
|
116
|
+
#endif
|
|
117
|
+
ERR_clear_error();
|
|
118
|
+
const auto sni_result = SSL_set_tlsext_host_name(stream.native_handle(), hostname.c_str());
|
|
119
|
+
#if defined(__GNUC__) || defined(__clang__)
|
|
120
|
+
#pragma GCC diagnostic pop
|
|
121
|
+
#endif
|
|
122
|
+
if (sni_result != 1) {
|
|
123
|
+
// Prefer the underlying SSL reason (if any) so failures are diagnosable,
|
|
124
|
+
// and fall back to a generic error when the SSL error queue is empty.
|
|
125
|
+
if (const auto reason = ERR_get_error(); reason != 0) {
|
|
126
|
+
return { static_cast<int>(reason), asio::error::get_ssl_category() };
|
|
127
|
+
}
|
|
128
|
+
return asio::error::make_error_code(asio::error::invalid_argument);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Verify that the presented certificate actually identifies `hostname`
|
|
133
|
+
// (SAN/CN). asio::ssl::verify_peer on its own only validates the certificate
|
|
134
|
+
// chain, not the name. In verify_none mode OpenSSL ignores the callback
|
|
135
|
+
// result, so this has no effect there.
|
|
136
|
+
std::error_code ec{};
|
|
137
|
+
stream.set_verify_callback(asio::ssl::host_name_verification(hostname), ec);
|
|
138
|
+
return ec;
|
|
139
|
+
}
|
|
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
|
+
|
|
28
255
|
stream_impl::stream_impl(asio::io_context& ctx, bool is_tls)
|
|
29
|
-
:
|
|
256
|
+
: inherited_(
|
|
257
|
+
asio::use_service<inherited_stream_registry>(static_cast<asio::execution_context&>(ctx)))
|
|
258
|
+
, strand_(asio::make_strand(ctx))
|
|
30
259
|
, tls_(is_tls)
|
|
31
260
|
, id_(uuid::to_string(uuid::random()))
|
|
261
|
+
, owner_pid_(utils::current_process_id())
|
|
32
262
|
{
|
|
33
263
|
}
|
|
34
264
|
|
|
@@ -48,6 +278,7 @@ plain_stream_impl::plain_stream_impl(asio::io_context& ctx)
|
|
|
48
278
|
: stream_impl(ctx, false)
|
|
49
279
|
, stream_(std::make_shared<asio::ip::tcp::socket>(strand_))
|
|
50
280
|
{
|
|
281
|
+
inherited_.add(stream_);
|
|
51
282
|
}
|
|
52
283
|
|
|
53
284
|
auto
|
|
@@ -79,12 +310,20 @@ plain_stream_impl::close(utils::movable_function<void(std::error_code)>&& handle
|
|
|
79
310
|
if (!stream_) {
|
|
80
311
|
return handler(asio::error::bad_descriptor);
|
|
81
312
|
}
|
|
82
|
-
return asio::post(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
313
|
+
return asio::post(
|
|
314
|
+
strand_, [stream = std::move(stream_), owner_pid = owner_pid_, handler = std::move(handler)]() {
|
|
315
|
+
asio::error_code ec{};
|
|
316
|
+
// Decide here rather than when this was posted: io_.stop() at fork_prepare
|
|
317
|
+
// does not drain the queue, so a close queued before the fork runs in the
|
|
318
|
+
// child once the io_context is restarted, and there the answer differs.
|
|
319
|
+
if (owner_pid != utils::current_process_id()) {
|
|
320
|
+
detach_inherited_socket(*stream, ec);
|
|
321
|
+
} else {
|
|
322
|
+
stream->shutdown(asio::socket_base::shutdown_both, ec);
|
|
323
|
+
stream->close(ec);
|
|
324
|
+
}
|
|
325
|
+
handler(ec);
|
|
326
|
+
});
|
|
88
327
|
}
|
|
89
328
|
|
|
90
329
|
void
|
|
@@ -101,11 +340,13 @@ plain_stream_impl::set_options()
|
|
|
101
340
|
void
|
|
102
341
|
plain_stream_impl::async_connect(
|
|
103
342
|
const asio::ip::tcp::resolver::results_type::endpoint_type& endpoint,
|
|
343
|
+
const std::string& /* hostname */,
|
|
104
344
|
utils::movable_function<void(std::error_code)>&& handler)
|
|
105
345
|
{
|
|
106
346
|
if (!stream_) {
|
|
107
347
|
id_ = uuid::to_string(uuid::random());
|
|
108
348
|
stream_ = std::make_shared<asio::ip::tcp::socket>(strand_);
|
|
349
|
+
inherited_.add(stream_);
|
|
109
350
|
}
|
|
110
351
|
return stream_->async_connect(endpoint,
|
|
111
352
|
[stream = stream_, handler = std::move(handler)](auto ec) {
|
|
@@ -147,6 +388,7 @@ tls_stream_impl::tls_stream_impl(asio::io_context& ctx, tls_context_provider& tl
|
|
|
147
388
|
std::make_shared<asio::ssl::stream<asio::ip::tcp::socket>>(asio::ip::tcp::socket(strand_),
|
|
148
389
|
*tls_.get_ctx()))
|
|
149
390
|
{
|
|
391
|
+
inherited_.add(stream_);
|
|
150
392
|
}
|
|
151
393
|
|
|
152
394
|
auto
|
|
@@ -178,12 +420,19 @@ tls_stream_impl::close(utils::movable_function<void(std::error_code)>&& handler)
|
|
|
178
420
|
if (!stream_) {
|
|
179
421
|
return handler(asio::error::bad_descriptor);
|
|
180
422
|
}
|
|
181
|
-
return asio::post(
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
423
|
+
return asio::post(
|
|
424
|
+
strand_, [stream = std::move(stream_), owner_pid = owner_pid_, handler = std::move(handler)]() {
|
|
425
|
+
asio::error_code ec{};
|
|
426
|
+
// See plain_stream_impl::close(): the inheritance test belongs here, not at
|
|
427
|
+
// post time.
|
|
428
|
+
if (owner_pid != utils::current_process_id()) {
|
|
429
|
+
detach_inherited_socket(stream->lowest_layer(), ec);
|
|
430
|
+
} else {
|
|
431
|
+
stream->lowest_layer().shutdown(asio::socket_base::shutdown_both, ec);
|
|
432
|
+
stream->lowest_layer().close(ec);
|
|
433
|
+
}
|
|
434
|
+
handler(ec);
|
|
435
|
+
});
|
|
187
436
|
}
|
|
188
437
|
|
|
189
438
|
void
|
|
@@ -199,21 +448,33 @@ tls_stream_impl::set_options()
|
|
|
199
448
|
|
|
200
449
|
void
|
|
201
450
|
tls_stream_impl::async_connect(const asio::ip::tcp::resolver::results_type::endpoint_type& endpoint,
|
|
451
|
+
const std::string& hostname,
|
|
202
452
|
utils::movable_function<void(std::error_code)>&& handler)
|
|
203
453
|
{
|
|
204
454
|
if (!stream_) {
|
|
205
455
|
id_ = uuid::to_string(uuid::random());
|
|
206
456
|
stream_ = std::make_shared<asio::ssl::stream<asio::ip::tcp::socket>>(
|
|
207
457
|
asio::ip::tcp::socket(strand_), *tls_.get_ctx());
|
|
458
|
+
inherited_.add(stream_);
|
|
208
459
|
}
|
|
209
460
|
return stream_->lowest_layer().async_connect(
|
|
210
|
-
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 {
|
|
211
466
|
if (ec_connect == asio::error::operation_aborted) {
|
|
212
467
|
return;
|
|
213
468
|
}
|
|
214
469
|
if (ec_connect) {
|
|
215
470
|
return handler(ec_connect);
|
|
216
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
|
+
}
|
|
217
478
|
stream->async_handshake(
|
|
218
479
|
asio::ssl::stream_base::client,
|
|
219
480
|
[stream, handler = std::move(handler)](std::error_code ec_handshake) mutable {
|
|
@@ -24,10 +24,12 @@
|
|
|
24
24
|
#include <asio/error.hpp>
|
|
25
25
|
#include <asio/io_context.hpp>
|
|
26
26
|
#include <asio/ip/tcp.hpp>
|
|
27
|
+
#include <asio/ip/udp.hpp>
|
|
27
28
|
#include <asio/ssl/context.hpp>
|
|
28
29
|
#include <asio/ssl/stream.hpp>
|
|
29
30
|
#include <asio/strand.hpp>
|
|
30
31
|
|
|
32
|
+
#include <cstdint>
|
|
31
33
|
#include <string>
|
|
32
34
|
#include <vector>
|
|
33
35
|
|
|
@@ -59,12 +61,58 @@ async_resolve(ip_protocol protocol,
|
|
|
59
61
|
return resolver.async_resolve(hostname, service, std::forward<Handler>(handler));
|
|
60
62
|
}
|
|
61
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Configure server-identity verification on a client TLS stream prior to the
|
|
66
|
+
* handshake: install a hostname (SAN/CN) verification callback and set the SNI
|
|
67
|
+
* server name. When the underlying context is in verify_none mode the callback
|
|
68
|
+
* has no effect, but SNI is still set.
|
|
69
|
+
*
|
|
70
|
+
* Without this, asio::ssl::verify_peer only validates that the certificate
|
|
71
|
+
* chains to a trusted CA -- it does NOT check that the certificate identifies
|
|
72
|
+
* the host being contacted (CWE-297).
|
|
73
|
+
*
|
|
74
|
+
* @param stream the client TLS stream that has connected but not yet handshaken
|
|
75
|
+
* @param hostname the canonical hostname the caller intended to reach; must not
|
|
76
|
+
* be empty (an empty hostname is rejected to avoid silently falling back to
|
|
77
|
+
* CA-only validation)
|
|
78
|
+
* @return a non-empty error_code if the hostname is empty, SNI could not be set,
|
|
79
|
+
* or the hostname-verification callback could not be installed; empty on success
|
|
80
|
+
*/
|
|
81
|
+
[[nodiscard]] auto
|
|
82
|
+
configure_tls_handshake(asio::ssl::stream<asio::ip::tcp::socket>& stream,
|
|
83
|
+
const std::string& hostname) -> std::error_code;
|
|
84
|
+
|
|
85
|
+
class inherited_stream_registry;
|
|
86
|
+
|
|
87
|
+
// For a forked child, after io_context::notify_fork(fork_child) and before anything runs on ctx:
|
|
88
|
+
// releases and closes every registered stream and socket on ctx that another process opened,
|
|
89
|
+
// without shutdown(2). No pending operation on them can then read or write a connection the
|
|
90
|
+
// parent is still using. The DNS client registers its sockets through register_inherited_socket().
|
|
91
|
+
void
|
|
92
|
+
detach_inherited_sockets(asio::io_context& ctx);
|
|
93
|
+
|
|
94
|
+
// Records a socket on ctx that is not a stream, so that detach_inherited_sockets() in a forked
|
|
95
|
+
// child releases it. Held weakly: the registry does not keep the socket alive.
|
|
96
|
+
void
|
|
97
|
+
register_inherited_socket(asio::io_context& ctx,
|
|
98
|
+
const std::shared_ptr<asio::ip::tcp::socket>& socket);
|
|
99
|
+
void
|
|
100
|
+
register_inherited_socket(asio::io_context& ctx,
|
|
101
|
+
const std::shared_ptr<asio::ip::udp::socket>& socket);
|
|
102
|
+
|
|
62
103
|
class stream_impl
|
|
63
104
|
{
|
|
64
105
|
protected:
|
|
106
|
+
inherited_stream_registry& inherited_;
|
|
65
107
|
asio::strand<asio::io_context::executor_type> strand_;
|
|
66
108
|
bool tls_;
|
|
67
109
|
std::string id_{};
|
|
110
|
+
// Identifies the process that opened this socket. close() compares it against
|
|
111
|
+
// the process running at that moment to tell a socket inherited across fork(2)
|
|
112
|
+
// apart from one this process opened itself, because an inherited socket must not
|
|
113
|
+
// be shut down: shutdown(2) acts on the open file description, which fork(2)
|
|
114
|
+
// shares, so it would tear down a connection the parent is still using.
|
|
115
|
+
std::int64_t owner_pid_;
|
|
68
116
|
|
|
69
117
|
public:
|
|
70
118
|
stream_impl(asio::io_context& ctx, bool is_tls);
|
|
@@ -88,7 +136,10 @@ public:
|
|
|
88
136
|
|
|
89
137
|
virtual void set_options() = 0;
|
|
90
138
|
|
|
139
|
+
// `hostname` is the canonical name the caller intends to reach; TLS streams use
|
|
140
|
+
// it to verify the server certificate's identity (SAN/CN) and to set SNI.
|
|
91
141
|
virtual void async_connect(const asio::ip::tcp::resolver::results_type::endpoint_type& endpoint,
|
|
142
|
+
const std::string& hostname,
|
|
92
143
|
utils::movable_function<void(std::error_code)>&& handler) = 0;
|
|
93
144
|
|
|
94
145
|
virtual void async_write(
|
|
@@ -117,6 +168,7 @@ public:
|
|
|
117
168
|
void set_options() override;
|
|
118
169
|
|
|
119
170
|
void async_connect(const asio::ip::tcp::resolver::results_type::endpoint_type& endpoint,
|
|
171
|
+
const std::string& hostname,
|
|
120
172
|
utils::movable_function<void(std::error_code)>&& handler) override;
|
|
121
173
|
|
|
122
174
|
void async_write(std::vector<asio::const_buffer>& buffers,
|
|
@@ -145,6 +197,7 @@ public:
|
|
|
145
197
|
void set_options() override;
|
|
146
198
|
|
|
147
199
|
void async_connect(const asio::ip::tcp::resolver::results_type::endpoint_type& endpoint,
|
|
200
|
+
const std::string& hostname,
|
|
148
201
|
utils::movable_function<void(std::error_code)>&& handler) override;
|
|
149
202
|
|
|
150
203
|
void async_write(std::vector<asio::const_buffer>& buffers,
|
|
@@ -62,6 +62,10 @@ std::atomic_int file_logger_version{ 0 };
|
|
|
62
62
|
std::shared_ptr<couchbase::core::logger::log_callback> log_callback{};
|
|
63
63
|
std::mutex log_callback_mutex;
|
|
64
64
|
std::atomic_int log_callback_version{ 0 };
|
|
65
|
+
// Mirrors "is log_callback set?" so the hot-path predicate can be answered with a single atomic
|
|
66
|
+
// load, without copying the owning shared_ptr. Updated under log_callback_mutex alongside
|
|
67
|
+
// log_callback.
|
|
68
|
+
std::atomic<bool> log_callback_present{ false };
|
|
65
69
|
|
|
66
70
|
auto
|
|
67
71
|
get_file_logger() -> std::shared_ptr<spdlog::logger>
|
|
@@ -94,6 +98,7 @@ update_callback_logger(const std::shared_ptr<couchbase::core::logger::log_callba
|
|
|
94
98
|
{
|
|
95
99
|
const std::scoped_lock lock(log_callback_mutex);
|
|
96
100
|
log_callback = new_callback;
|
|
101
|
+
log_callback_present.store(new_callback != nullptr, std::memory_order_relaxed);
|
|
97
102
|
++log_callback_version;
|
|
98
103
|
}
|
|
99
104
|
|
|
@@ -196,6 +201,14 @@ should_log(level lvl) -> bool
|
|
|
196
201
|
return false;
|
|
197
202
|
}
|
|
198
203
|
|
|
204
|
+
auto
|
|
205
|
+
has_custom_callback() -> bool
|
|
206
|
+
{
|
|
207
|
+
// A log macro asks this on every call; answer it with a single atomic load rather than copying
|
|
208
|
+
// the owning shared_ptr that get_custom_callback() returns.
|
|
209
|
+
return log_callback_present.load(std::memory_order_relaxed);
|
|
210
|
+
}
|
|
211
|
+
|
|
199
212
|
namespace detail
|
|
200
213
|
{
|
|
201
214
|
void
|
|
@@ -252,6 +265,29 @@ is_initialized() -> bool
|
|
|
252
265
|
return get_file_logger() != nullptr;
|
|
253
266
|
}
|
|
254
267
|
|
|
268
|
+
namespace
|
|
269
|
+
{
|
|
270
|
+
std::atomic<bool> log_redaction_enabled{ false };
|
|
271
|
+
} // namespace
|
|
272
|
+
|
|
273
|
+
void
|
|
274
|
+
set_log_redaction(bool enable)
|
|
275
|
+
{
|
|
276
|
+
const auto was_enabled = log_redaction_enabled.exchange(enable, std::memory_order_relaxed);
|
|
277
|
+
if (enable && !was_enabled) {
|
|
278
|
+
CB_LOG_INFO_RAW(
|
|
279
|
+
"Log redaction enabled: sensitive values are wrapped in redaction tags. This log still "
|
|
280
|
+
"contains identifying information until those tags are processed. Once redacted, diagnosis "
|
|
281
|
+
"and support of issues may be challenging or not possible");
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
auto
|
|
286
|
+
is_log_redaction_enabled() -> bool
|
|
287
|
+
{
|
|
288
|
+
return log_redaction_enabled.load(std::memory_order_relaxed);
|
|
289
|
+
}
|
|
290
|
+
|
|
255
291
|
auto
|
|
256
292
|
create_file_logger_impl(const std::string& logger_name, const configuration& logger_settings)
|
|
257
293
|
-> std::pair<std::optional<std::string>, std::shared_ptr<spdlog::logger>>
|
|
@@ -181,6 +181,14 @@ get_lowest_log_level() -> level;
|
|
|
181
181
|
auto
|
|
182
182
|
should_log(level lvl) -> bool;
|
|
183
183
|
|
|
184
|
+
/**
|
|
185
|
+
* @return true if a custom log callback is currently registered. Used to decide whether log
|
|
186
|
+
* arguments need to be formatted at all, independently of the severity level (the callback does
|
|
187
|
+
* its own level filtering).
|
|
188
|
+
*/
|
|
189
|
+
auto
|
|
190
|
+
has_custom_callback() -> bool;
|
|
191
|
+
|
|
184
192
|
auto
|
|
185
193
|
should_log_protocol() -> bool;
|
|
186
194
|
|
|
@@ -265,6 +273,29 @@ shutdown();
|
|
|
265
273
|
*/
|
|
266
274
|
auto
|
|
267
275
|
is_initialized() -> bool;
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Enable or disable log redaction.
|
|
279
|
+
*
|
|
280
|
+
* Redaction state is process-wide. When enabled, values wrapped by the helpers in
|
|
281
|
+
* `core/logger/redaction.hxx` are surrounded by `<ud>`/`<md>`/`<sd>` tags so that an external tool
|
|
282
|
+
* can strip or hash them; the SDK never removes or obscures anything itself.
|
|
283
|
+
*
|
|
284
|
+
* Connection-context log prefixes bake their tags in at construction, so redaction must be enabled
|
|
285
|
+
* *before* connecting for those prefixes to be tagged. Enabling it later affects only prefixes
|
|
286
|
+
* built afterwards.
|
|
287
|
+
*
|
|
288
|
+
* Enabling emits a one-time breadcrumb recording that the log carries redaction tags and still
|
|
289
|
+
* needs processing. That breadcrumb is dropped if no logger has been initialized yet.
|
|
290
|
+
*/
|
|
291
|
+
void
|
|
292
|
+
set_log_redaction(bool enable);
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* @return whether log redaction is currently enabled
|
|
296
|
+
*/
|
|
297
|
+
auto
|
|
298
|
+
is_log_redaction_enabled() -> bool;
|
|
268
299
|
} // namespace couchbase::core::logger
|
|
269
300
|
|
|
270
301
|
#if defined(__GNUC__) || defined(__clang__)
|
|
@@ -279,10 +310,17 @@ is_initialized() -> bool;
|
|
|
279
310
|
*/
|
|
280
311
|
#define COUCHBASE_LOG(file, line, function, severity, ...) \
|
|
281
312
|
do { \
|
|
282
|
-
couchbase::core::logger::
|
|
283
|
-
|
|
284
|
-
if (
|
|
285
|
-
|
|
313
|
+
const bool cb_log_to_file_ = couchbase::core::logger::should_log(severity); \
|
|
314
|
+
const bool cb_log_to_custom_ = couchbase::core::logger::has_custom_callback(); \
|
|
315
|
+
if (cb_log_to_file_ || cb_log_to_custom_) { \
|
|
316
|
+
auto cb_log_message_ = ::fmt::format(__VA_ARGS__); \
|
|
317
|
+
if (cb_log_to_custom_) { \
|
|
318
|
+
couchbase::core::logger::detail::log_custom_logger( \
|
|
319
|
+
file, line, function, severity, cb_log_message_); \
|
|
320
|
+
} \
|
|
321
|
+
if (cb_log_to_file_) { \
|
|
322
|
+
couchbase::core::logger::detail::log(file, line, function, severity, cb_log_message_); \
|
|
323
|
+
} \
|
|
286
324
|
} \
|
|
287
325
|
} while (false)
|
|
288
326
|
|
|
@@ -343,8 +381,10 @@ is_initialized() -> bool;
|
|
|
343
381
|
*/
|
|
344
382
|
#define COUCHBASE_LOG_RAW(file, line, function, severity, msg) \
|
|
345
383
|
do { \
|
|
346
|
-
|
|
347
|
-
|
|
384
|
+
/* msg is already a string; deliver it directly (no fmt::format), gated like COUCHBASE_LOG. */ \
|
|
385
|
+
if (couchbase::core::logger::has_custom_callback()) { \
|
|
386
|
+
couchbase::core::logger::detail::log_custom_logger(file, line, function, severity, msg); \
|
|
387
|
+
} \
|
|
348
388
|
if (couchbase::core::logger::should_log(severity)) { \
|
|
349
389
|
couchbase::core::logger::detail::log(file, line, function, severity, msg); \
|
|
350
390
|
} \
|