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
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2026. Couchbase, Inc.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#include "analytics_stream.hxx"
|
|
19
|
+
|
|
20
|
+
#include <couchbase/error_codes.hxx>
|
|
21
|
+
|
|
22
|
+
#include "core/io/http_error.hxx"
|
|
23
|
+
#include "core/operations/analytics_response_parsing.hxx"
|
|
24
|
+
#include "free_form_http_request.hxx"
|
|
25
|
+
#include "logger/logger.hxx"
|
|
26
|
+
#include "row_streamer.hxx"
|
|
27
|
+
#include "utils/json.hxx"
|
|
28
|
+
#include "utils/movable_function.hxx"
|
|
29
|
+
|
|
30
|
+
#include <tao/json/value.hpp>
|
|
31
|
+
|
|
32
|
+
#include <chrono>
|
|
33
|
+
#include <memory>
|
|
34
|
+
#include <mutex>
|
|
35
|
+
#include <optional>
|
|
36
|
+
#include <string>
|
|
37
|
+
#include <system_error>
|
|
38
|
+
#include <utility>
|
|
39
|
+
|
|
40
|
+
namespace couchbase::core
|
|
41
|
+
{
|
|
42
|
+
namespace
|
|
43
|
+
{
|
|
44
|
+
constexpr auto ANALYTICS_RESULTS_POINTER = "/results/^";
|
|
45
|
+
|
|
46
|
+
// Normalize a bounded-lexer failure (malformed / oversized JSON) to errc::common::parsing_failure,
|
|
47
|
+
// matching the buffered analytics_query() path and row_streamer's own truncated-body terminal, so
|
|
48
|
+
// the public streaming error contract is consistent.
|
|
49
|
+
auto
|
|
50
|
+
normalize_stream_error(std::error_code ec) -> std::error_code
|
|
51
|
+
{
|
|
52
|
+
if (ec.category() == couchbase::core::impl::streaming_json_lexer_category()) {
|
|
53
|
+
return errc::common::parsing_failure;
|
|
54
|
+
}
|
|
55
|
+
return ec;
|
|
56
|
+
}
|
|
57
|
+
} // namespace
|
|
58
|
+
|
|
59
|
+
namespace
|
|
60
|
+
{
|
|
61
|
+
// Lift the service-reported diagnostics out of a parsed preamble/trailer. Called for both sections,
|
|
62
|
+
// so whichever one carried the failure is what the error context ends up describing.
|
|
63
|
+
auto
|
|
64
|
+
extract_error_details(const operations::analytics_response::analytics_meta_data& meta,
|
|
65
|
+
std::string raw) -> stream_error_details
|
|
66
|
+
{
|
|
67
|
+
stream_error_details details{};
|
|
68
|
+
details.client_context_id = meta.client_context_id;
|
|
69
|
+
// Retained whether or not the section reports an error: it becomes error_context::http_body,
|
|
70
|
+
// which the buffered path fills for every response, and even an error-free envelope names the
|
|
71
|
+
// request the service logged.
|
|
72
|
+
details.raw = std::move(raw);
|
|
73
|
+
if (!meta.errors.empty()) {
|
|
74
|
+
details.first_error_code = meta.errors.front().code;
|
|
75
|
+
details.first_error_message = meta.errors.front().message;
|
|
76
|
+
}
|
|
77
|
+
return details;
|
|
78
|
+
}
|
|
79
|
+
} // namespace
|
|
80
|
+
|
|
81
|
+
class analytics_stream_impl : public std::enable_shared_from_this<analytics_stream_impl>
|
|
82
|
+
{
|
|
83
|
+
public:
|
|
84
|
+
analytics_stream_impl(asio::io_context& io,
|
|
85
|
+
http_response_body body,
|
|
86
|
+
row_streamer_options options,
|
|
87
|
+
std::uint32_t http_status)
|
|
88
|
+
: streamer_{ io, std::move(body), ANALYTICS_RESULTS_POINTER, options }
|
|
89
|
+
, http_status_{ http_status }
|
|
90
|
+
{
|
|
91
|
+
}
|
|
92
|
+
analytics_stream_impl(const analytics_stream_impl&) = delete;
|
|
93
|
+
analytics_stream_impl(analytics_stream_impl&&) = delete;
|
|
94
|
+
auto operator=(const analytics_stream_impl&) -> analytics_stream_impl& = delete;
|
|
95
|
+
auto operator=(analytics_stream_impl&&) -> analytics_stream_impl& = delete;
|
|
96
|
+
|
|
97
|
+
// Runs with no handle left, no pull in flight and the preamble delivered: each pull, and start()
|
|
98
|
+
// until the preamble, holds this object.
|
|
99
|
+
//
|
|
100
|
+
// Cancels unless a pull delivered the terminal of a completed JSON document. Without the cancel,
|
|
101
|
+
// the read-ahead keeps the body and its session alive:
|
|
102
|
+
// - through a read in flight, until the idle timer fires or the cluster closes;
|
|
103
|
+
// - through a row send queued on a full channel, indefinitely.
|
|
104
|
+
// The cancel stops the connection only while the body is still being read. A body read to its
|
|
105
|
+
// end has already checked the connection in.
|
|
106
|
+
//
|
|
107
|
+
// After a completed document the read-ahead reads the trailing bytes and the connection is
|
|
108
|
+
// checked in, or the idle timer ends the body.
|
|
109
|
+
~analytics_stream_impl()
|
|
110
|
+
{
|
|
111
|
+
if (!document_completed_) {
|
|
112
|
+
streamer_.cancel();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
void start(utils::movable_function<void(std::error_code)>&& on_ready)
|
|
117
|
+
{
|
|
118
|
+
streamer_.start([self = shared_from_this(), on_ready = std::move(on_ready)](
|
|
119
|
+
std::string preamble, std::error_code ec) mutable {
|
|
120
|
+
if (ec) {
|
|
121
|
+
return on_ready(normalize_stream_error(
|
|
122
|
+
io::invalid_argument_for_undecodable_400(ec, self->http_status_, {})));
|
|
123
|
+
}
|
|
124
|
+
operations::analytics_response::analytics_meta_data meta{};
|
|
125
|
+
try {
|
|
126
|
+
meta = operations::parse_analytics_meta(utils::json::parse(preamble));
|
|
127
|
+
} catch (const std::exception&) {
|
|
128
|
+
{
|
|
129
|
+
// Keep the unparseable preamble: it is the only diagnostic there is for a malformed
|
|
130
|
+
// response, and the buffered path reports the raw body in the same situation.
|
|
131
|
+
const std::scoped_lock lock{ self->mutex_ };
|
|
132
|
+
self->error_details_.raw = std::move(preamble);
|
|
133
|
+
}
|
|
134
|
+
return on_ready(io::invalid_argument_for_undecodable_400(
|
|
135
|
+
errc::common::parsing_failure, self->http_status_, {}));
|
|
136
|
+
}
|
|
137
|
+
{
|
|
138
|
+
const std::scoped_lock lock{ self->mutex_ };
|
|
139
|
+
self->signature_ = meta.signature;
|
|
140
|
+
self->error_details_ = extract_error_details(meta, std::move(preamble));
|
|
141
|
+
}
|
|
142
|
+
// An upfront error is rare for the streaming path (status/errors usually arrive in the
|
|
143
|
+
// trailer). The preamble status is typically "running", so only surface an early error when
|
|
144
|
+
// the preamble already carries error entries.
|
|
145
|
+
std::error_code early_error{};
|
|
146
|
+
if (!meta.errors.empty()) {
|
|
147
|
+
early_error = operations::map_analytics_error(meta, self->http_status_);
|
|
148
|
+
}
|
|
149
|
+
on_ready(early_error);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
void next_row(
|
|
154
|
+
utils::movable_function<void(std::optional<std::string>, std::error_code)>&& handler)
|
|
155
|
+
{
|
|
156
|
+
// Terminal-sticky: once the stream has ended, re-deliver the stored terminal on every
|
|
157
|
+
// subsequent pull instead of issuing another receive that would park forever on the
|
|
158
|
+
// drained-but-open row channel. The public handle guards this too, but a core::-direct consumer
|
|
159
|
+
// (e.g. a wrapper) relies on this being safe.
|
|
160
|
+
std::optional<std::error_code> sticky_terminal;
|
|
161
|
+
{
|
|
162
|
+
const std::scoped_lock lock{ mutex_ };
|
|
163
|
+
if (terminal_reached_) {
|
|
164
|
+
sticky_terminal = terminal_ec_;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (sticky_terminal) {
|
|
168
|
+
// Deliver outside the lock: the handler typically issues the next pull, which re-enters
|
|
169
|
+
// next_row and would re-lock the non-recursive mutex_ and deadlock if invoked while held.
|
|
170
|
+
return handler(std::nullopt, *sticky_terminal);
|
|
171
|
+
}
|
|
172
|
+
streamer_.next_row([self = shared_from_this(),
|
|
173
|
+
handler = std::move(handler)](std::string row, std::error_code ec) mutable {
|
|
174
|
+
if (!row.empty()) {
|
|
175
|
+
return handler(std::move(row), {});
|
|
176
|
+
}
|
|
177
|
+
// Empty row marks the end of the stream. Classify the terminal, remember it (so later pulls
|
|
178
|
+
// are served the sticky terminal above), then deliver.
|
|
179
|
+
std::error_code terminal_ec{};
|
|
180
|
+
if (ec) {
|
|
181
|
+
// Normalize a mid-document lexer failure to parsing_failure, matching the buffered path.
|
|
182
|
+
terminal_ec = normalize_stream_error(
|
|
183
|
+
io::invalid_argument_for_undecodable_400(ec, self->http_status_, {}));
|
|
184
|
+
} else if (auto raw_meta = self->streamer_.metadata(); !raw_meta.has_value()) {
|
|
185
|
+
// A clean end without reconstructed metadata violates the row_streamer invariant; surface
|
|
186
|
+
// it rather than silently reporting success with no metadata.
|
|
187
|
+
CB_LOG_WARNING("analytics_stream: end reached but row_streamer returned no metadata");
|
|
188
|
+
terminal_ec = errc::common::internal_server_failure;
|
|
189
|
+
} else {
|
|
190
|
+
try {
|
|
191
|
+
auto meta = operations::parse_analytics_meta(utils::json::parse(raw_meta.value()));
|
|
192
|
+
terminal_ec = operations::map_analytics_error(meta, self->http_status_);
|
|
193
|
+
const std::scoped_lock lock{ self->mutex_ };
|
|
194
|
+
// The trailer is where a request that failed part-way reports itself, so its diagnostics
|
|
195
|
+
// supersede the preamble's for the terminal error.
|
|
196
|
+
self->error_details_ = extract_error_details(meta, std::move(raw_meta.value()));
|
|
197
|
+
self->meta_data_ = std::move(meta);
|
|
198
|
+
} catch (const std::exception&) {
|
|
199
|
+
terminal_ec = io::invalid_argument_for_undecodable_400(
|
|
200
|
+
errc::common::parsing_failure, self->http_status_, {});
|
|
201
|
+
const std::scoped_lock lock{ self->mutex_ };
|
|
202
|
+
self->error_details_.raw = std::move(raw_meta.value());
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
{
|
|
206
|
+
const std::scoped_lock lock{ self->mutex_ };
|
|
207
|
+
self->terminal_reached_ = true;
|
|
208
|
+
self->terminal_ec_ = terminal_ec;
|
|
209
|
+
self->document_completed_ = !ec;
|
|
210
|
+
}
|
|
211
|
+
handler(std::nullopt, terminal_ec);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
[[nodiscard]] auto signature() const -> std::optional<std::string>
|
|
216
|
+
{
|
|
217
|
+
const std::scoped_lock lock{ mutex_ };
|
|
218
|
+
return signature_;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
[[nodiscard]] auto meta_data() const
|
|
222
|
+
-> std::optional<operations::analytics_response::analytics_meta_data>
|
|
223
|
+
{
|
|
224
|
+
const std::scoped_lock lock{ mutex_ };
|
|
225
|
+
return meta_data_;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
[[nodiscard]] auto error_details() const -> stream_error_details
|
|
229
|
+
{
|
|
230
|
+
const std::scoped_lock lock{ mutex_ };
|
|
231
|
+
return error_details_;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
auto set_deadline(std::chrono::time_point<std::chrono::steady_clock> deadline_tp)
|
|
235
|
+
-> io::deadline_state
|
|
236
|
+
{
|
|
237
|
+
return streamer_.set_deadline(deadline_tp);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
void cancel()
|
|
241
|
+
{
|
|
242
|
+
streamer_.cancel();
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
private:
|
|
246
|
+
row_streamer streamer_;
|
|
247
|
+
std::uint32_t http_status_{};
|
|
248
|
+
mutable std::mutex mutex_{};
|
|
249
|
+
std::optional<std::string> signature_{};
|
|
250
|
+
std::optional<operations::analytics_response::analytics_meta_data> meta_data_{};
|
|
251
|
+
stream_error_details error_details_{};
|
|
252
|
+
// Terminal-sticky state (guarded by mutex_): once next_row reports the terminal, it is remembered
|
|
253
|
+
// so every later pull re-delivers it instead of parking on the drained channel.
|
|
254
|
+
bool terminal_reached_{ false };
|
|
255
|
+
std::error_code terminal_ec_{};
|
|
256
|
+
// Set when a pull delivers a terminal with no streamer error: the lexer completed the JSON
|
|
257
|
+
// document. Written under mutex_. The destructor reads it unlocked: the release of the last
|
|
258
|
+
// shared_ptr orders that read after every write.
|
|
259
|
+
bool document_completed_{ false };
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
analytics_stream::analytics_stream(asio::io_context& io,
|
|
263
|
+
http_response_body body,
|
|
264
|
+
row_streamer_options options,
|
|
265
|
+
std::uint32_t http_status)
|
|
266
|
+
: impl_{ std::make_shared<analytics_stream_impl>(io, std::move(body), options, http_status) }
|
|
267
|
+
{
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
void
|
|
271
|
+
analytics_stream::start(utils::movable_function<void(std::error_code)>&& on_ready)
|
|
272
|
+
{
|
|
273
|
+
impl_->start(std::move(on_ready));
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
void
|
|
277
|
+
analytics_stream::next_row(
|
|
278
|
+
utils::movable_function<void(std::optional<std::string>, std::error_code)>&& handler)
|
|
279
|
+
{
|
|
280
|
+
impl_->next_row(std::move(handler));
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
auto
|
|
284
|
+
analytics_stream::signature() const -> std::optional<std::string>
|
|
285
|
+
{
|
|
286
|
+
return impl_->signature();
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
auto
|
|
290
|
+
analytics_stream::error_details() const -> stream_error_details
|
|
291
|
+
{
|
|
292
|
+
return impl_->error_details();
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
auto
|
|
296
|
+
analytics_stream::meta_data() const
|
|
297
|
+
-> std::optional<operations::analytics_response::analytics_meta_data>
|
|
298
|
+
{
|
|
299
|
+
return impl_->meta_data();
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
auto
|
|
303
|
+
analytics_stream::set_deadline(std::chrono::time_point<std::chrono::steady_clock> deadline_tp)
|
|
304
|
+
-> io::deadline_state
|
|
305
|
+
{
|
|
306
|
+
return impl_->set_deadline(deadline_tp);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
void
|
|
310
|
+
analytics_stream::cancel()
|
|
311
|
+
{
|
|
312
|
+
impl_->cancel();
|
|
313
|
+
}
|
|
314
|
+
} // namespace couchbase::core
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2026. Couchbase, Inc.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#pragma once
|
|
19
|
+
|
|
20
|
+
#include "core/io/stream_deadline.hxx"
|
|
21
|
+
#include "core/operations/document_analytics.hxx"
|
|
22
|
+
#include "row_streamer.hxx"
|
|
23
|
+
#include "stream_error_details.hxx"
|
|
24
|
+
#include "utils/movable_function.hxx"
|
|
25
|
+
|
|
26
|
+
#include <chrono>
|
|
27
|
+
#include <cstdint>
|
|
28
|
+
#include <memory>
|
|
29
|
+
#include <optional>
|
|
30
|
+
#include <string>
|
|
31
|
+
#include <system_error>
|
|
32
|
+
|
|
33
|
+
namespace asio
|
|
34
|
+
{
|
|
35
|
+
class io_context;
|
|
36
|
+
} // namespace asio
|
|
37
|
+
|
|
38
|
+
namespace couchbase::core
|
|
39
|
+
{
|
|
40
|
+
class analytics_stream_impl;
|
|
41
|
+
class http_response_body;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* L3 streaming state machine for analytics responses.
|
|
45
|
+
*
|
|
46
|
+
* Mirrors query_stream but with analytics-specific semantics: it wraps a row_streamer (pointed at
|
|
47
|
+
* "/results/^", the same pointer the buffered analytics path uses) and adds preamble parsing
|
|
48
|
+
* (signature + upfront error detection), late trailer metadata, and terminal error classification
|
|
49
|
+
* via map_analytics_error.
|
|
50
|
+
*/
|
|
51
|
+
class analytics_stream
|
|
52
|
+
{
|
|
53
|
+
public:
|
|
54
|
+
/**
|
|
55
|
+
* Constructs an empty handle (no underlying stream). Used to carry the "no stream" outcome on
|
|
56
|
+
* the error path of the dispatch; none of the streaming methods may be called on it.
|
|
57
|
+
*/
|
|
58
|
+
analytics_stream() = default;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* http_status is the status of the response the body belongs to; an HTTP 400 that matches no
|
|
62
|
+
* specific error is reported as invalid_argument.
|
|
63
|
+
*/
|
|
64
|
+
analytics_stream(asio::io_context& io,
|
|
65
|
+
http_response_body body,
|
|
66
|
+
row_streamer_options options = {},
|
|
67
|
+
std::uint32_t http_status = 0);
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Starts the stream. Resolves once the preamble has been parsed. The early_error is set when
|
|
71
|
+
* the response carried an upfront error (or the preamble failed to parse).
|
|
72
|
+
*/
|
|
73
|
+
void start(utils::movable_function<void(std::error_code early_error)>&& on_ready);
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Service-reported diagnostics from the most recently parsed JSON section — the preamble after
|
|
77
|
+
* start(), the trailer once the terminal has been reached. The dispatch layer stamps these into
|
|
78
|
+
* the error context so a streaming failure reports the same detail as a buffered one.
|
|
79
|
+
*/
|
|
80
|
+
[[nodiscard]] auto error_details() const -> stream_error_details;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Retrieves the next row. A populated row is delivered with a falsy error_code. An empty row
|
|
84
|
+
* (std::nullopt) signals the end: a falsy error_code means a clean success end, a truthy
|
|
85
|
+
* error_code means a trailing analytics/transport error.
|
|
86
|
+
*/
|
|
87
|
+
void next_row(
|
|
88
|
+
utils::movable_function<void(std::optional<std::string> row, std::error_code)>&& handler);
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Signature captured from the preamble (available after start resolves).
|
|
92
|
+
*/
|
|
93
|
+
[[nodiscard]] auto signature() const -> std::optional<std::string>;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Trailer metadata. Valid only after the stream has reached its end.
|
|
97
|
+
*/
|
|
98
|
+
[[nodiscard]] auto meta_data() const
|
|
99
|
+
-> std::optional<operations::analytics_response::analytics_meta_data>;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Closes the HTTP body at `deadline_tp`, whether or not a row is being pulled, releasing the
|
|
103
|
+
* connection where one is still held. A response received in full holds none: once its bytes
|
|
104
|
+
* have also been parsed the call arms nothing and reports body_already_ended, and while bytes
|
|
105
|
+
* remain unparsed it ends the body, dropping those and reporting the timeout. Rows already
|
|
106
|
+
* parsed stay consumable either way. The inter-read idle timer is armed only while a socket
|
|
107
|
+
* read is in flight, and a consumer stopped above the high-water mark has none.
|
|
108
|
+
*
|
|
109
|
+
* The terminal reaches the consumer through a pull. A pull outstanding at expiry completes
|
|
110
|
+
* with the timeout. A read that completes the response is the exception: the whole response
|
|
111
|
+
* arrived, so those bytes are delivered as a clean end. Otherwise the next pull reports the
|
|
112
|
+
* terminal, after any rows already buffered.
|
|
113
|
+
*
|
|
114
|
+
* Optional. The terminal is unambiguous_timeout for a read-only request, ambiguous_timeout
|
|
115
|
+
* otherwise. Re-arming before expiry replaces the deadline. Once the stream has ended a
|
|
116
|
+
* further call arms nothing and reports body_already_ended. Callable from any thread.
|
|
117
|
+
*/
|
|
118
|
+
[[nodiscard]] auto set_deadline(std::chrono::time_point<std::chrono::steady_clock> deadline_tp)
|
|
119
|
+
-> io::deadline_state;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Cancels the stream & closes the HTTP connection.
|
|
123
|
+
*/
|
|
124
|
+
void cancel();
|
|
125
|
+
|
|
126
|
+
private:
|
|
127
|
+
std::shared_ptr<analytics_stream_impl> impl_;
|
|
128
|
+
};
|
|
129
|
+
} // namespace couchbase::core
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2026. Couchbase, Inc.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#include "analytics_stream_component.hxx"
|
|
19
|
+
|
|
20
|
+
#include "free_form_http_request.hxx"
|
|
21
|
+
#include "http_component.hxx"
|
|
22
|
+
#include "impl/bootstrap_error.hxx"
|
|
23
|
+
#include "operations/document_analytics.hxx"
|
|
24
|
+
#include "platform/uuid.h"
|
|
25
|
+
#include "service_type.hxx"
|
|
26
|
+
#include "utils/json.hxx"
|
|
27
|
+
|
|
28
|
+
#include <couchbase/error_codes.hxx>
|
|
29
|
+
|
|
30
|
+
#include <asio/io_context.hpp>
|
|
31
|
+
#include <spdlog/fmt/bundled/core.h>
|
|
32
|
+
#include <tao/json/value.hpp>
|
|
33
|
+
|
|
34
|
+
#include <chrono>
|
|
35
|
+
#include <memory>
|
|
36
|
+
#include <mutex>
|
|
37
|
+
#include <string>
|
|
38
|
+
#include <system_error>
|
|
39
|
+
#include <utility>
|
|
40
|
+
|
|
41
|
+
namespace couchbase::core
|
|
42
|
+
{
|
|
43
|
+
namespace
|
|
44
|
+
{
|
|
45
|
+
auto
|
|
46
|
+
to_error_code(std::error_code err) -> std::error_code
|
|
47
|
+
{
|
|
48
|
+
return err;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
auto
|
|
52
|
+
build_streaming_analytics_body(const operations::analytics_request& request,
|
|
53
|
+
const std::string& client_context_id,
|
|
54
|
+
std::chrono::milliseconds timeout) -> std::string
|
|
55
|
+
{
|
|
56
|
+
tao::json::value body{};
|
|
57
|
+
|
|
58
|
+
// The remaining options are identical to the buffered analytics path; share one encoder so the
|
|
59
|
+
// two stay byte-for-byte consistent. This runs first so the control fields set below always win
|
|
60
|
+
// over any same-named `raw` entry a caller may have supplied.
|
|
61
|
+
operations::encode_analytics_options(body, request);
|
|
62
|
+
|
|
63
|
+
body["client_context_id"] = client_context_id;
|
|
64
|
+
body["statement"] = request.statement;
|
|
65
|
+
// The server-side timeout is sent unmodified here — unlike the query path, which shaves 500ms so
|
|
66
|
+
// it observes the engine's timeout before its own. This mirrors the buffered analytics path
|
|
67
|
+
// (document_analytics), which likewise does not tighten the engine deadline; keep them
|
|
68
|
+
// consistent.
|
|
69
|
+
body["timeout"] = fmt::format("{}ms", timeout.count());
|
|
70
|
+
|
|
71
|
+
return utils::json::generate(body);
|
|
72
|
+
}
|
|
73
|
+
} // namespace
|
|
74
|
+
|
|
75
|
+
class analytics_stream_component_impl
|
|
76
|
+
: public std::enable_shared_from_this<analytics_stream_component_impl>
|
|
77
|
+
{
|
|
78
|
+
public:
|
|
79
|
+
analytics_stream_component_impl(asio::io_context& io,
|
|
80
|
+
http_component http,
|
|
81
|
+
std::chrono::milliseconds default_timeout,
|
|
82
|
+
row_streamer_options streaming_options)
|
|
83
|
+
: io_{ io }
|
|
84
|
+
, http_{ std::move(http) }
|
|
85
|
+
, default_timeout_{ default_timeout }
|
|
86
|
+
, streaming_options_{ streaming_options }
|
|
87
|
+
{
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
void execute(operations::analytics_request request,
|
|
91
|
+
analytics_stream_component::handler_type&& handler)
|
|
92
|
+
{
|
|
93
|
+
const std::string client_context_id =
|
|
94
|
+
request.client_context_id.value_or(uuid::to_string(uuid::random()));
|
|
95
|
+
const std::chrono::milliseconds timeout = request.timeout.value_or(default_timeout_);
|
|
96
|
+
|
|
97
|
+
http_request http_req{ service_type::analytics, "POST" };
|
|
98
|
+
http_req.path = "/query/service";
|
|
99
|
+
|
|
100
|
+
// Everything about the request that an error context reports, known before dispatch. The
|
|
101
|
+
// response-side fields (HTTP status, the service's first error, the endpoint) are filled in as
|
|
102
|
+
// they become available, so a failure at any stage carries as much detail as the buffered path.
|
|
103
|
+
// Held behind a shared_ptr, not by value: it carries the encoded request body in
|
|
104
|
+
// `parameters`, and both the dispatch callback and the synchronous dispatch-failure branch
|
|
105
|
+
// below need it, so sharing avoids deep-copying that body on every streaming request.
|
|
106
|
+
auto base_ctx = std::make_shared<error_context::analytics>();
|
|
107
|
+
base_ctx->client_context_id = client_context_id;
|
|
108
|
+
base_ctx->statement = request.statement;
|
|
109
|
+
base_ctx->method = http_req.method;
|
|
110
|
+
base_ctx->path = http_req.path;
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
http_req.body = build_streaming_analytics_body(request, client_context_id, timeout);
|
|
114
|
+
} catch (const std::exception&) {
|
|
115
|
+
// A caller-supplied raw/parameter value that is not valid JSON fails encoding; surface it as
|
|
116
|
+
// invalid_argument rather than letting the exception escape the public API.
|
|
117
|
+
base_ctx->ec = errc::common::invalid_argument;
|
|
118
|
+
return handler({}, std::move(*base_ctx));
|
|
119
|
+
}
|
|
120
|
+
base_ctx->parameters = http_req.body;
|
|
121
|
+
http_req.timeout = timeout;
|
|
122
|
+
http_req.client_context_id = client_context_id;
|
|
123
|
+
http_req.is_read_only = request.readonly;
|
|
124
|
+
http_req.headers["connection"] = "keep-alive";
|
|
125
|
+
http_req.headers["content-type"] = "application/json";
|
|
126
|
+
if (request.priority) {
|
|
127
|
+
http_req.headers["analytics-priority"] = "-1";
|
|
128
|
+
}
|
|
129
|
+
if (request.parent_span) {
|
|
130
|
+
http_req.parent_span = request.parent_span;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
auto callback_state = std::make_shared<callback_state_type>(std::move(handler));
|
|
134
|
+
|
|
135
|
+
using dispatch_error = std::error_code;
|
|
136
|
+
|
|
137
|
+
const bool read_only = request.readonly;
|
|
138
|
+
auto op = http_.do_http_request(
|
|
139
|
+
http_req,
|
|
140
|
+
[self = shared_from_this(), callback_state, timeout, read_only, base_ctx](
|
|
141
|
+
http_response resp, dispatch_error err) mutable {
|
|
142
|
+
if (auto ec = to_error_code(err)) {
|
|
143
|
+
base_ctx->ec = ec;
|
|
144
|
+
self->invoke(callback_state, {}, std::move(*base_ctx));
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
// The response is in hand, so the context can now name the endpoint and HTTP status.
|
|
148
|
+
base_ctx->http_status = resp.status_code();
|
|
149
|
+
const auto dispatch_info = resp.dispatch_info();
|
|
150
|
+
base_ctx->hostname = dispatch_info.hostname;
|
|
151
|
+
base_ctx->port = dispatch_info.port;
|
|
152
|
+
if (!dispatch_info.remote_address.empty()) {
|
|
153
|
+
base_ctx->last_dispatched_to = dispatch_info.remote_address;
|
|
154
|
+
}
|
|
155
|
+
if (!dispatch_info.local_address.empty()) {
|
|
156
|
+
base_ctx->last_dispatched_from = dispatch_info.local_address;
|
|
157
|
+
}
|
|
158
|
+
// Use the cluster's streaming tuning, but bound the server between reads with this
|
|
159
|
+
// request's timeout: if it stalls mid-body the stream times out rather than hanging next()
|
|
160
|
+
// forever (the request timeout is otherwise released once headers arrive).
|
|
161
|
+
auto options = self->streaming_options_;
|
|
162
|
+
options.idle_timeout = timeout;
|
|
163
|
+
options.is_read_only = read_only;
|
|
164
|
+
auto stream =
|
|
165
|
+
std::make_shared<analytics_stream>(self->io_, resp.body(), options, resp.status_code());
|
|
166
|
+
stream->start(
|
|
167
|
+
[self, callback_state, stream, base_ctx](std::error_code early_error) mutable {
|
|
168
|
+
if (early_error) {
|
|
169
|
+
// The preamble is what carried the failure, so stamp its diagnostics before tearing
|
|
170
|
+
// the stream down.
|
|
171
|
+
base_ctx->ec = early_error;
|
|
172
|
+
apply_error_details(*base_ctx, stream->error_details());
|
|
173
|
+
// No consumer will ever take ownership of this stream, so tear the underlying body
|
|
174
|
+
// (socket + timers) down now rather than when the last handle drops.
|
|
175
|
+
stream->cancel();
|
|
176
|
+
self->invoke(callback_state, {}, std::move(*base_ctx));
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
// Hand the base context to the consumer alongside the stream: a terminal error reached
|
|
180
|
+
// later is stamped onto it, so a mid-stream failure reports the same detail as this
|
|
181
|
+
// one.
|
|
182
|
+
self->invoke(callback_state, std::move(*stream), std::move(*base_ctx));
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
if (!op.has_value()) {
|
|
187
|
+
base_ctx->ec = to_error_code(op.error());
|
|
188
|
+
invoke(callback_state, {}, std::move(*base_ctx));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private:
|
|
193
|
+
struct callback_state_type {
|
|
194
|
+
explicit callback_state_type(analytics_stream_component::handler_type h)
|
|
195
|
+
: handler{ std::move(h) }
|
|
196
|
+
{
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
analytics_stream_component::handler_type handler;
|
|
200
|
+
std::mutex mutex{};
|
|
201
|
+
bool invoked{ false };
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
void invoke(const std::shared_ptr<callback_state_type>& state,
|
|
205
|
+
analytics_stream stream,
|
|
206
|
+
error_context::analytics ctx)
|
|
207
|
+
{
|
|
208
|
+
analytics_stream_component::handler_type handler;
|
|
209
|
+
{
|
|
210
|
+
const std::scoped_lock lock{ state->mutex };
|
|
211
|
+
if (state->invoked) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
state->invoked = true;
|
|
215
|
+
handler = std::move(state->handler);
|
|
216
|
+
}
|
|
217
|
+
if (handler) {
|
|
218
|
+
handler(std::move(stream), std::move(ctx));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
asio::io_context& io_;
|
|
223
|
+
http_component http_;
|
|
224
|
+
std::chrono::milliseconds default_timeout_;
|
|
225
|
+
row_streamer_options streaming_options_;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
analytics_stream_component::analytics_stream_component(asio::io_context& io,
|
|
229
|
+
http_component http,
|
|
230
|
+
std::chrono::milliseconds default_timeout,
|
|
231
|
+
row_streamer_options streaming_options)
|
|
232
|
+
: impl_{ std::make_shared<analytics_stream_component_impl>(io,
|
|
233
|
+
std::move(http),
|
|
234
|
+
default_timeout,
|
|
235
|
+
streaming_options) }
|
|
236
|
+
{
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
void
|
|
240
|
+
analytics_stream_component::execute(operations::analytics_request request,
|
|
241
|
+
handler_type&& handler) const
|
|
242
|
+
{
|
|
243
|
+
impl_->execute(std::move(request), std::move(handler));
|
|
244
|
+
}
|
|
245
|
+
} // namespace couchbase::core
|