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
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
|
|
27
27
|
namespace
|
|
28
28
|
{
|
|
29
|
+
// NOLINTBEGIN(misc-const-correctness): these are llhttp callbacks whose signatures must match
|
|
30
|
+
// llhttp_data_cb / llhttp_cb exactly (int(llhttp_t*, ...)); the parser pointer cannot be const or
|
|
31
|
+
// the assignment to the llhttp_settings_t members below would be ill-formed.
|
|
29
32
|
inline auto
|
|
30
33
|
static_on_status(llhttp_t* parser, const char* at, std::size_t length) -> int
|
|
31
34
|
{
|
|
@@ -80,6 +83,7 @@ static_on_message_complete(llhttp_t* parser) -> int
|
|
|
80
83
|
wrapper->complete = true;
|
|
81
84
|
return 0;
|
|
82
85
|
}
|
|
86
|
+
// NOLINTEND(misc-const-correctness)
|
|
83
87
|
} // namespace
|
|
84
88
|
|
|
85
89
|
namespace couchbase::core::io
|
|
@@ -17,20 +17,38 @@
|
|
|
17
17
|
|
|
18
18
|
#include "http_streaming_response.hxx"
|
|
19
19
|
|
|
20
|
+
#include "core/logger/logger.hxx"
|
|
21
|
+
#include "core/logger/redaction.hxx"
|
|
20
22
|
#include "core/utils/movable_function.hxx"
|
|
21
23
|
#include "http_session.hxx"
|
|
22
24
|
|
|
23
25
|
#include <couchbase/error_codes.hxx>
|
|
24
26
|
|
|
27
|
+
#include <asio/post.hpp>
|
|
28
|
+
|
|
25
29
|
#include <cstdint>
|
|
26
30
|
#include <map>
|
|
27
31
|
#include <memory>
|
|
32
|
+
#include <mutex>
|
|
33
|
+
#include <optional>
|
|
28
34
|
#include <string>
|
|
29
35
|
#include <system_error>
|
|
30
36
|
#include <utility>
|
|
31
37
|
|
|
32
38
|
namespace couchbase::core::io
|
|
33
39
|
{
|
|
40
|
+
auto
|
|
41
|
+
terminal_error_code(deadline_terminal terminal) -> std::error_code
|
|
42
|
+
{
|
|
43
|
+
switch (terminal) {
|
|
44
|
+
case deadline_terminal::unambiguous:
|
|
45
|
+
return errc::common::unambiguous_timeout;
|
|
46
|
+
case deadline_terminal::ambiguous:
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
return errc::common::ambiguous_timeout;
|
|
50
|
+
}
|
|
51
|
+
|
|
34
52
|
class http_streaming_response_body_impl
|
|
35
53
|
: public std::enable_shared_from_this<http_streaming_response_body_impl>
|
|
36
54
|
{
|
|
@@ -38,85 +56,318 @@ public:
|
|
|
38
56
|
http_streaming_response_body_impl(asio::io_context& io,
|
|
39
57
|
std::shared_ptr<http_session> session,
|
|
40
58
|
std::string cached_data,
|
|
41
|
-
bool reading_complete
|
|
59
|
+
bool reading_complete,
|
|
60
|
+
std::size_t cached_chunk_size)
|
|
42
61
|
: session_{ std::move(session) }
|
|
62
|
+
, endpoint_{ session_ ? session_->hostname() + ":" + session_->port() : std::string{} }
|
|
43
63
|
, cached_data_{ std::move(cached_data) }
|
|
44
64
|
, deadline_{ io }
|
|
45
65
|
, reading_complete_{ reading_complete }
|
|
66
|
+
, cached_chunk_size_{ cached_chunk_size }
|
|
67
|
+
{
|
|
68
|
+
// A response complete before a single read_some is constructed with the session still held.
|
|
69
|
+
// http_session checks that connection in once the response handler returns, and nothing
|
|
70
|
+
// further belongs to this message, so a read from that session would park on a connection
|
|
71
|
+
// serving someone else. Release it here, which also establishes the invariant next(),
|
|
72
|
+
// close_impl() and set_deadline() each assume: reading_complete_ means no live session.
|
|
73
|
+
if (reading_complete_) {
|
|
74
|
+
session_ = nullptr;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// A pending read holds this body, so it is destroyed only with no pull in flight. An armed
|
|
79
|
+
// deadline does not hold it. A body dropped before its response was fully read leaves its
|
|
80
|
+
// connection mid-response, which otherwise only cluster close ends. Closing the body posts a stop
|
|
81
|
+
// of its session to the session strand.
|
|
82
|
+
~http_streaming_response_body_impl()
|
|
83
|
+
{
|
|
84
|
+
close_impl(errc::common::request_canceled, std::nullopt);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
void close(std::error_code ec)
|
|
46
88
|
{
|
|
89
|
+
close_impl(ec, std::nullopt);
|
|
47
90
|
}
|
|
48
91
|
|
|
49
|
-
|
|
92
|
+
// Closes only if `generation` is still current. The check and the terminal transition share one
|
|
93
|
+
// lock, so a re-arm or a clean completion cannot land between them.
|
|
94
|
+
void close_at_deadline(deadline_terminal on_expiry, std::uint64_t generation)
|
|
50
95
|
{
|
|
51
|
-
|
|
52
|
-
|
|
96
|
+
const auto ec = terminal_error_code(on_expiry);
|
|
97
|
+
if (close_impl(ec, generation)) {
|
|
98
|
+
CB_LOG_DEBUG("streaming response deadline expired, closing the body: terminal={}, "
|
|
99
|
+
"endpoint=\"{}\"",
|
|
100
|
+
ec.message(),
|
|
101
|
+
logger::system_data(endpoint_));
|
|
53
102
|
}
|
|
54
|
-
session_ = nullptr;
|
|
55
|
-
final_ec_ = ec;
|
|
56
103
|
}
|
|
57
104
|
|
|
58
|
-
|
|
105
|
+
// Returns whether this call closed the body; false when it was already closed, drained, or the
|
|
106
|
+
// generation was superseded.
|
|
107
|
+
auto close_impl(std::error_code ec, std::optional<std::uint64_t> expect_generation) -> bool
|
|
59
108
|
{
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
109
|
+
// session_ and final_ec_ are written here and on the session's read completion, which runs on
|
|
110
|
+
// the session strand. close() is reached off that strand: from row_streamer::cancel()'s post,
|
|
111
|
+
// the idle-timer completion and the deadline completion, and from the destructor on whatever
|
|
112
|
+
// thread drops the body. A mutex guards the shared teardown state. close() is
|
|
113
|
+
// idempotent, so a second teardown (a cancel racing a transport error) neither stops the
|
|
114
|
+
// session twice nor overwrites the first terminal error.
|
|
115
|
+
std::shared_ptr<http_session> to_stop;
|
|
116
|
+
{
|
|
117
|
+
const std::scoped_lock lock{ mutex_ };
|
|
118
|
+
if (expect_generation.has_value() && *expect_generation != deadline_generation_) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
if (closed_ || (reading_complete_ && cached_data_.empty())) {
|
|
122
|
+
// Drained is terminal too, the state set_deadline() also refuses. A clean end leaves
|
|
123
|
+
// closed_ false, so without this a later close() overwrites final_ec_ and a pull after
|
|
124
|
+
// end-of-stream reports request_canceled. Both clean-end paths disarm the timer, so
|
|
125
|
+
// returning here leaves none armed.
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
closed_ = true;
|
|
129
|
+
// Only stop the session when the response was abandoned mid-body: such a connection is left
|
|
130
|
+
// at an arbitrary offset and cannot be reused. A response that was already fully received
|
|
131
|
+
// (reading_complete_) leaves the connection at a message boundary, and http_session checks
|
|
132
|
+
// it back into the keep-alive pool via its stream-end handler
|
|
133
|
+
// (http_session_manager::check_in) — stopping it here would evict a live pooled connection
|
|
134
|
+
// and make the *next* unrelated request on it fail with request_canceled.
|
|
135
|
+
//
|
|
136
|
+
// reading_complete_ is what separates a connection this body may stop from one the pool
|
|
137
|
+
// owns. http_session::read_some runs the stream-end handler only after invoking this body's
|
|
138
|
+
// completion, so on one thread the flag is set by the time the connection is published.
|
|
139
|
+
// Across threads a clean end can still land between the claim below and the stop that
|
|
140
|
+
// executes it, which is what mark_stopping() covers.
|
|
141
|
+
//
|
|
142
|
+
// Hand the session out to be stopped below, then drop our reference. Written as two
|
|
143
|
+
// statements rather than std::exchange because cppcheck's flow analysis mis-models the
|
|
144
|
+
// std::exchange return value and wrongly reports the `if (to_stop)` guard as always-false.
|
|
145
|
+
//
|
|
146
|
+
// A session already stopped is skipped: the stop() call that set stopped_ runs the whole
|
|
147
|
+
// teardown, and a stop posted after the cluster closed would hold the session until the
|
|
148
|
+
// io_context is destroyed.
|
|
149
|
+
if (!reading_complete_ && session_ && !session_->is_stopped()) {
|
|
150
|
+
to_stop = session_;
|
|
151
|
+
// Claim the stop while this lock is held. The clean-end branch of the read completion
|
|
152
|
+
// clears closed_ and hands the connection to check_in, and it can run between the claim
|
|
153
|
+
// and the stop that executes it; the claim is what check_in tests, so the pool refuses a
|
|
154
|
+
// connection this body is about to stop.
|
|
155
|
+
to_stop->mark_stopping();
|
|
156
|
+
}
|
|
157
|
+
session_ = nullptr;
|
|
158
|
+
final_ec_ = ec;
|
|
159
|
+
// Disarm. cancel() does not stop a completion already queued, hence the generation bump.
|
|
160
|
+
deadline_.cancel();
|
|
161
|
+
++deadline_generation_;
|
|
162
|
+
// Reached on error, cancel or destruction (a clean end sets reading_complete_ instead), so
|
|
163
|
+
// any bytes still buffered from the initial parse are not handed out as data. Dropping them
|
|
164
|
+
// makes next() surface the terminal error, not stale body bytes.
|
|
165
|
+
cached_data_.clear();
|
|
66
166
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
167
|
+
// stop() runs inline -- it closes the stream, cancels the timers, cancels the current
|
|
168
|
+
// response and invokes on_stop_handler_ -- so it has to run on the session strand, alongside
|
|
169
|
+
// the read and write handlers it tears down. close() is reached off that strand from a
|
|
170
|
+
// deadline expiry, an idle-timer completion, row_streamer::cancel()'s post and the destructor,
|
|
171
|
+
// so the stop is posted there.
|
|
172
|
+
//
|
|
173
|
+
// The session is already claimed above, so the gap between deciding the stop and running it
|
|
174
|
+
// stays invisible to the pool.
|
|
175
|
+
if (to_stop) {
|
|
176
|
+
asio::post(to_stop->get_executor(), [to_stop]() {
|
|
177
|
+
to_stop->stop();
|
|
178
|
+
});
|
|
70
179
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
void next(utils::movable_function<void(std::string, bool, std::error_code)>&& callback)
|
|
184
|
+
{
|
|
185
|
+
// Decide what to do under the lock (the state it reads is mutated by close() and by the read
|
|
186
|
+
// completion below), then invoke the callback / start the read outside the lock so neither can
|
|
187
|
+
// re-enter next() while the mutex is held. deadline_ is touched under the lock: an asio timer
|
|
188
|
+
// is not thread-safe.
|
|
189
|
+
std::string data;
|
|
190
|
+
bool has_more = false;
|
|
191
|
+
std::error_code deliver_ec;
|
|
192
|
+
bool deliver_now = false;
|
|
193
|
+
std::shared_ptr<http_session> to_read;
|
|
194
|
+
{
|
|
195
|
+
const std::scoped_lock lock{ mutex_ };
|
|
196
|
+
if (closed_) {
|
|
197
|
+
// The body was closed on error/cancel: surface the recorded terminal error and stop,
|
|
198
|
+
// ahead of the cached-data branch, so a next() after close never delivers residual body
|
|
199
|
+
// bytes (with a falsy ec) that would make a cancelled/failed stream look like it is still
|
|
200
|
+
// producing rows.
|
|
201
|
+
deliver_ec = final_ec_;
|
|
202
|
+
deliver_now = true;
|
|
203
|
+
} else if (!cached_data_.empty()) {
|
|
204
|
+
// Hand back the data buffered during the initial parse. When a cached chunk size is set (a
|
|
205
|
+
// test seam that simulates a socket that dribbles the body out), deliver at most that many
|
|
206
|
+
// bytes per pull; otherwise hand back everything at once. There is more to come while
|
|
207
|
+
// cached data remains or the response was not already fully read (reading_complete_).
|
|
208
|
+
if (cached_chunk_size_ == 0 || cached_data_.size() <= cached_chunk_size_) {
|
|
209
|
+
std::swap(data, cached_data_);
|
|
210
|
+
} else {
|
|
211
|
+
data = cached_data_.substr(0, cached_chunk_size_);
|
|
212
|
+
cached_data_.erase(0, cached_chunk_size_);
|
|
79
213
|
}
|
|
80
|
-
|
|
81
|
-
|
|
214
|
+
has_more = !reading_complete_ || !cached_data_.empty();
|
|
215
|
+
deliver_now = true;
|
|
216
|
+
if (!has_more) {
|
|
217
|
+
deadline_.cancel();
|
|
218
|
+
++deadline_generation_;
|
|
219
|
+
}
|
|
220
|
+
} else if (session_) {
|
|
221
|
+
// A read is needed. session_ is non-null here: it is cleared alongside closed_ and
|
|
222
|
+
// alongside reading_complete_, so a live session means the body is still streaming.
|
|
223
|
+
to_read = session_;
|
|
224
|
+
} else {
|
|
225
|
+
// No cached data and no live session, and not closed: the body drained cleanly
|
|
226
|
+
// (reading_complete_), so report end-of-stream with a falsy error.
|
|
227
|
+
deliver_now = true;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (deliver_now) {
|
|
231
|
+
callback(std::move(data), has_more, deliver_ec);
|
|
82
232
|
return;
|
|
83
233
|
}
|
|
84
|
-
|
|
234
|
+
to_read->read_some([self = shared_from_this(), cb = std::move(callback)](
|
|
235
|
+
std::string data, bool has_more, std::error_code ec) mutable {
|
|
236
|
+
if (ec) {
|
|
237
|
+
// Error or cancellation: the connection is left mid-response and is not reusable, so stop
|
|
238
|
+
// it. close() records the terminal in final_ec_, which this callback and any later
|
|
239
|
+
// next() both report.
|
|
240
|
+
self->close(ec);
|
|
241
|
+
} else {
|
|
242
|
+
const std::scoped_lock lock{ self->mutex_ };
|
|
243
|
+
if (!has_more) {
|
|
244
|
+
// Clean end-of-stream. http_session::read_some hands the session back to the keep-alive
|
|
245
|
+
// pool via its stream-end handler (http_session_manager::check_in) once this completion
|
|
246
|
+
// returns, and that handler stops the connection only when it is not reusable
|
|
247
|
+
// (Connection: close, node gone, etc.). Calling stop() here would evict an
|
|
248
|
+
// otherwise-reusable connection and defeat
|
|
249
|
+
// keep-alive, adding avoidable connection churn, so just release our reference and mark
|
|
250
|
+
// the body drained; subsequent next() calls report end-of-stream via reading_complete_.
|
|
251
|
+
//
|
|
252
|
+
// Tested ahead of closed_, so a response whose last read succeeded is delivered even
|
|
253
|
+
// when a terminal was recorded while that read was in flight. This is the rule
|
|
254
|
+
// close_impl already applies, refusing a close once the body is drained; the read
|
|
255
|
+
// completion is where drained is established, so the two orders disagree only over the
|
|
256
|
+
// instant that establishes it. The bytes are the whole remainder of a response the
|
|
257
|
+
// server completed, and reporting a timeout for one held in hand tells a retry layer
|
|
258
|
+
// the request may not have applied when it did.
|
|
259
|
+
self->reading_complete_ = true;
|
|
260
|
+
self->session_ = nullptr;
|
|
261
|
+
self->deadline_.cancel();
|
|
262
|
+
++self->deadline_generation_;
|
|
263
|
+
// Drop the terminal a close recorded while this read was in flight. Delivering the read
|
|
264
|
+
// as a clean end and leaving that terminal in place would contradict it on the next
|
|
265
|
+
// pull, which tests closed_ first and would report the timeout the body has just
|
|
266
|
+
// decided against. The body is drained either way -- reading_complete_ with no cached
|
|
267
|
+
// bytes is the state close_impl and set_deadline already refuse -- so clearing this
|
|
268
|
+
// reopens nothing.
|
|
269
|
+
self->closed_ = false;
|
|
270
|
+
self->final_ec_ = {};
|
|
271
|
+
} else if (self->closed_) {
|
|
272
|
+
// Closed while a read that has more to come was completing. Report the recorded terminal
|
|
273
|
+
// and drop the bytes: they are a fragment of a response that has already ended, and
|
|
274
|
+
// handing them over with a falsy error_code would report a closed body as still
|
|
275
|
+
// producing data. row_streamer::cancel closes the row channel itself, so it is a
|
|
276
|
+
// deadline expiry that reaches here with a consumer still able to receive. The close
|
|
277
|
+
// has to land between the read completing and this lock, which needs a second thread
|
|
278
|
+
// running the io_context.
|
|
279
|
+
ec = self->final_ec_;
|
|
280
|
+
data.clear();
|
|
281
|
+
has_more = false;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
if (ec) {
|
|
285
|
+
// A failed read reports why the body closed, not what the read returned: an abort reports
|
|
286
|
+
// request_canceled whatever ended the body, and a transport error arriving after a close
|
|
287
|
+
// would otherwise mask the terminal.
|
|
288
|
+
ec = self->terminal_error();
|
|
289
|
+
}
|
|
290
|
+
cb(std::move(data), has_more, ec);
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Supersedes any armed deadline without ending the body. Taken under the same lock as arming
|
|
295
|
+
// and the terminal transition, so an expiry already queued when the lock is taken is discarded
|
|
296
|
+
// by the generation check rather than delivered. Lets a caller whose own teardown must be
|
|
297
|
+
// posted stop the deadline on the calling thread first, so a cancel cannot lose to an expiry
|
|
298
|
+
// landing in the gap.
|
|
299
|
+
void cancel_deadline()
|
|
300
|
+
{
|
|
301
|
+
const std::scoped_lock lock{ mutex_ };
|
|
302
|
+
deadline_.cancel();
|
|
303
|
+
++deadline_generation_;
|
|
85
304
|
}
|
|
86
305
|
|
|
87
|
-
|
|
306
|
+
auto set_deadline(std::chrono::time_point<std::chrono::steady_clock> deadline_tp,
|
|
307
|
+
deadline_terminal on_expiry) -> deadline_state
|
|
88
308
|
{
|
|
309
|
+
const std::scoped_lock lock{ mutex_ };
|
|
310
|
+
if (closed_ || (reading_complete_ && cached_data_.empty())) {
|
|
311
|
+
// Drained: nothing left to reclaim. reading_complete_ with cached_data_ still buffered is
|
|
312
|
+
// not drained, and does take a deadline.
|
|
313
|
+
return deadline_state::body_already_ended;
|
|
314
|
+
}
|
|
315
|
+
const auto generation = ++deadline_generation_;
|
|
89
316
|
deadline_.expires_at(deadline_tp);
|
|
90
|
-
|
|
317
|
+
// Weak: an armed deadline does not keep a dropped body, and through it the session, alive
|
|
318
|
+
// until expiry. The destructor closes a body dropped before its deadline.
|
|
319
|
+
deadline_.async_wait([weak = weak_from_this(), on_expiry, generation](auto ec) {
|
|
91
320
|
if (ec == asio::error::operation_aborted) {
|
|
92
321
|
return;
|
|
93
322
|
}
|
|
94
|
-
self
|
|
323
|
+
if (const auto self = weak.lock(); self) {
|
|
324
|
+
self->close_at_deadline(on_expiry, generation);
|
|
325
|
+
}
|
|
95
326
|
});
|
|
327
|
+
return deadline_state::armed;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
[[nodiscard]] auto terminal_error() -> std::error_code
|
|
331
|
+
{
|
|
332
|
+
const std::scoped_lock lock{ mutex_ };
|
|
333
|
+
return final_ec_;
|
|
96
334
|
}
|
|
97
335
|
|
|
98
336
|
private:
|
|
337
|
+
std::mutex mutex_{};
|
|
338
|
+
// Guarded by mutex_: written from the read completion (session strand) and from close()
|
|
339
|
+
// (off-strand). cached_data_/cached_chunk_size_ are logically single-consumer but are read under
|
|
340
|
+
// the same lock for uniformity. deadline_ is guarded because an asio timer may not be armed and
|
|
341
|
+
// cancelled concurrently; deadline_generation_ supersedes a queued completion.
|
|
99
342
|
std::shared_ptr<http_session> session_;
|
|
343
|
+
// hostname:port of the session the body was built with, kept for logging after session_ is
|
|
344
|
+
// released.
|
|
345
|
+
std::string endpoint_;
|
|
100
346
|
std::string cached_data_;
|
|
101
347
|
std::error_code final_ec_;
|
|
102
348
|
asio::steady_timer deadline_;
|
|
103
|
-
std::
|
|
349
|
+
std::uint64_t deadline_generation_{ 0 };
|
|
350
|
+
bool reading_complete_{ false };
|
|
351
|
+
bool closed_{ false };
|
|
352
|
+
std::size_t cached_chunk_size_{ 0 };
|
|
104
353
|
};
|
|
105
354
|
|
|
106
355
|
http_streaming_response_body::http_streaming_response_body(asio::io_context& io,
|
|
107
356
|
std::shared_ptr<http_session> session,
|
|
108
357
|
std::string cached_data,
|
|
109
|
-
bool reading_complete
|
|
358
|
+
bool reading_complete,
|
|
359
|
+
std::size_t cached_chunk_size)
|
|
110
360
|
: impl_{ std::make_shared<http_streaming_response_body_impl>(io,
|
|
111
361
|
std::move(session),
|
|
112
362
|
std::move(cached_data),
|
|
113
|
-
reading_complete
|
|
363
|
+
reading_complete,
|
|
364
|
+
cached_chunk_size) }
|
|
114
365
|
{
|
|
115
366
|
}
|
|
116
367
|
|
|
117
368
|
void
|
|
118
369
|
http_streaming_response_body::next(
|
|
119
|
-
utils::movable_function<void(std::string, std::error_code)>&& callback)
|
|
370
|
+
utils::movable_function<void(std::string, bool, std::error_code)>&& callback)
|
|
120
371
|
{
|
|
121
372
|
impl_->next(std::move(callback));
|
|
122
373
|
}
|
|
@@ -127,11 +378,18 @@ http_streaming_response_body::close(std::error_code ec)
|
|
|
127
378
|
impl_->close(ec);
|
|
128
379
|
}
|
|
129
380
|
|
|
130
|
-
|
|
381
|
+
auto
|
|
131
382
|
http_streaming_response_body::set_deadline(
|
|
132
|
-
std::chrono::time_point<std::chrono::steady_clock> deadline_tp
|
|
383
|
+
std::chrono::time_point<std::chrono::steady_clock> deadline_tp,
|
|
384
|
+
deadline_terminal on_expiry) -> deadline_state
|
|
133
385
|
{
|
|
134
|
-
impl_->set_deadline(deadline_tp);
|
|
386
|
+
return impl_->set_deadline(deadline_tp, on_expiry);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
void
|
|
390
|
+
http_streaming_response_body::cancel_deadline()
|
|
391
|
+
{
|
|
392
|
+
return impl_->cancel_deadline();
|
|
135
393
|
}
|
|
136
394
|
|
|
137
395
|
class http_streaming_response_impl
|
|
@@ -140,11 +398,13 @@ public:
|
|
|
140
398
|
http_streaming_response_impl(std::uint32_t status_code,
|
|
141
399
|
std::string status_message,
|
|
142
400
|
std::map<std::string, std::string> headers,
|
|
143
|
-
http_streaming_response_body body
|
|
401
|
+
http_streaming_response_body body,
|
|
402
|
+
http_dispatch_info dispatch_info)
|
|
144
403
|
: status_code_{ status_code }
|
|
145
404
|
, status_message_{ std::move(status_message) }
|
|
146
405
|
, headers_{ std::move(headers) }
|
|
147
406
|
, body_{ std::move(body) }
|
|
407
|
+
, dispatch_info_{ std::move(dispatch_info) }
|
|
148
408
|
{
|
|
149
409
|
}
|
|
150
410
|
|
|
@@ -176,23 +436,42 @@ public:
|
|
|
176
436
|
return false;
|
|
177
437
|
}
|
|
178
438
|
|
|
439
|
+
[[nodiscard]] auto dispatch_info() const -> const http_dispatch_info&
|
|
440
|
+
{
|
|
441
|
+
return dispatch_info_;
|
|
442
|
+
}
|
|
443
|
+
|
|
179
444
|
private:
|
|
180
445
|
std::uint32_t status_code_;
|
|
181
446
|
std::string status_message_;
|
|
182
447
|
std::map<std::string, std::string> headers_;
|
|
183
448
|
http_streaming_response_body body_;
|
|
449
|
+
http_dispatch_info dispatch_info_;
|
|
184
450
|
};
|
|
185
451
|
|
|
186
452
|
http_streaming_response::http_streaming_response(
|
|
187
453
|
asio::io_context& io,
|
|
188
454
|
const couchbase::core::io::http_streaming_parser& parser,
|
|
189
455
|
std::shared_ptr<http_session> session)
|
|
190
|
-
: impl_{
|
|
191
|
-
parser.status_code,
|
|
192
|
-
parser.status_message,
|
|
193
|
-
parser.headers,
|
|
194
|
-
http_streaming_response_body{ io, std::move(session), parser.body_chunk, parser.complete }) }
|
|
456
|
+
: impl_{ nullptr }
|
|
195
457
|
{
|
|
458
|
+
http_dispatch_info dispatch_info{};
|
|
459
|
+
if (session) {
|
|
460
|
+
// Taken from the session's http_context, the same source io::http_command stamps onto a
|
|
461
|
+
// buffered response, so both paths report the identical endpoint. The port is already a
|
|
462
|
+
// std::uint16_t there; http_session::port() is that same value rendered as a string for
|
|
463
|
+
// resolving and for the Host header, so parsing it back would only reintroduce a conversion.
|
|
464
|
+
dispatch_info.hostname = session->http_context().hostname;
|
|
465
|
+
dispatch_info.port = session->http_context().port;
|
|
466
|
+
dispatch_info.remote_address = session->remote_address();
|
|
467
|
+
dispatch_info.local_address = session->local_address();
|
|
468
|
+
}
|
|
469
|
+
impl_ = std::make_shared<http_streaming_response_impl>(
|
|
470
|
+
parser.status_code,
|
|
471
|
+
parser.status_message,
|
|
472
|
+
parser.headers,
|
|
473
|
+
http_streaming_response_body{ io, std::move(session), parser.body_chunk, parser.complete },
|
|
474
|
+
std::move(dispatch_info));
|
|
196
475
|
}
|
|
197
476
|
|
|
198
477
|
auto
|
|
@@ -224,4 +503,10 @@ http_streaming_response::must_close_connection() const -> bool
|
|
|
224
503
|
{
|
|
225
504
|
return impl_->must_close_connection();
|
|
226
505
|
}
|
|
506
|
+
|
|
507
|
+
auto
|
|
508
|
+
http_streaming_response::dispatch_info() const -> const http_dispatch_info&
|
|
509
|
+
{
|
|
510
|
+
return impl_->dispatch_info();
|
|
511
|
+
}
|
|
227
512
|
} // namespace couchbase::core::io
|
|
@@ -18,10 +18,12 @@
|
|
|
18
18
|
|
|
19
19
|
#include <couchbase/error_codes.hxx>
|
|
20
20
|
|
|
21
|
+
#include "core/io/stream_deadline.hxx"
|
|
21
22
|
#include "core/utils/movable_function.hxx"
|
|
22
23
|
|
|
23
24
|
#include <asio/steady_timer.hpp>
|
|
24
25
|
|
|
26
|
+
#include <cstddef>
|
|
25
27
|
#include <cstdint>
|
|
26
28
|
#include <map>
|
|
27
29
|
#include <memory>
|
|
@@ -30,6 +32,7 @@
|
|
|
30
32
|
|
|
31
33
|
namespace couchbase::core::io
|
|
32
34
|
{
|
|
35
|
+
|
|
33
36
|
class http_session;
|
|
34
37
|
struct http_streaming_parser;
|
|
35
38
|
class http_streaming_response_body_impl;
|
|
@@ -41,10 +44,30 @@ public:
|
|
|
41
44
|
http_streaming_response_body(asio::io_context& io,
|
|
42
45
|
std::shared_ptr<http_session> session,
|
|
43
46
|
std::string cached_data = {},
|
|
44
|
-
bool reading_complete = false
|
|
47
|
+
bool reading_complete = false,
|
|
48
|
+
std::size_t cached_chunk_size = 0);
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
// Closes the body with `on_expiry` at `deadline_tp`, whether or not a read is in flight. A
|
|
51
|
+
// deadline already in the past fires as soon as the io_context runs it. Re-arming before expiry
|
|
52
|
+
// replaces the previous deadline. Once the body has ended, by expiry or otherwise, a further
|
|
53
|
+
// call arms nothing and reports body_already_ended.
|
|
54
|
+
//
|
|
55
|
+
// Callable from any thread. Arming, cancelling and the terminal transition share one lock. An
|
|
56
|
+
// expiry already queued when that lock is taken is superseded, not delivered.
|
|
57
|
+
[[nodiscard]] auto set_deadline(std::chrono::time_point<std::chrono::steady_clock> deadline_tp,
|
|
58
|
+
deadline_terminal on_expiry) -> deadline_state;
|
|
59
|
+
// Supersedes an armed deadline without ending the body, under the same lock as set_deadline.
|
|
60
|
+
// For a caller that must post its own teardown: stopping the deadline here first keeps a cancel
|
|
61
|
+
// from losing to an expiry that lands before the posted work runs.
|
|
62
|
+
void cancel_deadline();
|
|
63
|
+
// Delivers the next body chunk. The bool argument is `has_more`: true while the response is
|
|
64
|
+
// still in progress (an empty chunk with has_more==true simply carried no body bytes, e.g. a
|
|
65
|
+
// read consumed by HTTP chunk framing), false once the stream has ended. Consumers must key
|
|
66
|
+
// end-of-stream off this flag, never off an empty data string.
|
|
67
|
+
//
|
|
68
|
+
// The error_code next() reports is the reason the body was closed, not the error the read
|
|
69
|
+
// returned: read_some reports request_canceled for every aborted read.
|
|
70
|
+
void next(utils::movable_function<void(std::string, bool, std::error_code)>&& callback);
|
|
48
71
|
void close(std::error_code ec = couchbase::errc::common::request_canceled);
|
|
49
72
|
|
|
50
73
|
private:
|
|
@@ -53,6 +76,16 @@ private:
|
|
|
53
76
|
|
|
54
77
|
class http_streaming_response_impl;
|
|
55
78
|
|
|
79
|
+
// Where a streaming response was dispatched, captured at construction rather than held as a session
|
|
80
|
+
// reference: an error context is built after the stream has been torn down, by which point the
|
|
81
|
+
// session may already be back in the keep-alive pool or gone.
|
|
82
|
+
struct http_dispatch_info {
|
|
83
|
+
std::string hostname{};
|
|
84
|
+
std::uint16_t port{};
|
|
85
|
+
std::string remote_address{};
|
|
86
|
+
std::string local_address{};
|
|
87
|
+
};
|
|
88
|
+
|
|
56
89
|
class http_streaming_response
|
|
57
90
|
{
|
|
58
91
|
public:
|
|
@@ -66,6 +99,7 @@ public:
|
|
|
66
99
|
[[nodiscard]] auto headers() const -> const std::map<std::string, std::string>&;
|
|
67
100
|
[[nodiscard]] auto body() -> http_streaming_response_body&;
|
|
68
101
|
[[nodiscard]] auto must_close_connection() const -> bool;
|
|
102
|
+
[[nodiscard]] auto dispatch_info() const -> const http_dispatch_info&;
|
|
69
103
|
|
|
70
104
|
private:
|
|
71
105
|
std::shared_ptr<http_streaming_response_impl> impl_;
|