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
|
@@ -65,7 +65,7 @@ map_collection(std::string scope_name,
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
auto
|
|
68
|
-
map_scope_specs(core::topology::collections_manifest& manifest)
|
|
68
|
+
map_scope_specs(const core::topology::collections_manifest& manifest)
|
|
69
69
|
-> std::vector<couchbase::management::bucket::scope_spec>
|
|
70
70
|
{
|
|
71
71
|
std::vector<couchbase::management::bucket::scope_spec> scope_specs{};
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
#include "core/io/dns_client.hxx"
|
|
22
22
|
#include "core/io/dns_config.hxx"
|
|
23
23
|
#include "core/logger/logger.hxx"
|
|
24
|
+
#include "core/logger/redaction.hxx"
|
|
24
25
|
#include "core/origin.hxx"
|
|
25
26
|
#include "core/topology/configuration.hxx"
|
|
26
|
-
#include "core/utils/join_strings.hxx"
|
|
27
27
|
#include "core/utils/movable_function.hxx"
|
|
28
28
|
|
|
29
29
|
#include <couchbase/error_codes.hxx>
|
|
@@ -44,6 +44,27 @@
|
|
|
44
44
|
|
|
45
45
|
namespace couchbase::core::impl
|
|
46
46
|
{
|
|
47
|
+
namespace
|
|
48
|
+
{
|
|
49
|
+
auto
|
|
50
|
+
nameserver_address(const io::dns::dns_config& config) -> std::string
|
|
51
|
+
{
|
|
52
|
+
return fmt::format(
|
|
53
|
+
"{}:{}", config.nameserver().empty() ? "(system)" : config.nameserver(), config.port());
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
auto
|
|
57
|
+
node_addresses(const origin::node_list& nodes) -> std::vector<std::string>
|
|
58
|
+
{
|
|
59
|
+
std::vector<std::string> addresses;
|
|
60
|
+
addresses.reserve(nodes.size());
|
|
61
|
+
for (const auto& [host, port] : nodes) {
|
|
62
|
+
addresses.emplace_back(fmt::format("{}:{}", host, port));
|
|
63
|
+
}
|
|
64
|
+
return addresses;
|
|
65
|
+
}
|
|
66
|
+
} // namespace
|
|
67
|
+
|
|
47
68
|
dns_srv_tracker::dns_srv_tracker(asio::io_context& ctx,
|
|
48
69
|
std::string address,
|
|
49
70
|
io::dns::dns_config config,
|
|
@@ -61,26 +82,37 @@ void
|
|
|
61
82
|
dns_srv_tracker::get_srv_nodes(
|
|
62
83
|
utils::movable_function<void(origin::node_list, std::error_code)> callback)
|
|
63
84
|
{
|
|
64
|
-
CB_LOG_DEBUG("Query DNS-SRV:
|
|
65
|
-
address_,
|
|
85
|
+
CB_LOG_DEBUG("Query DNS-SRV: name=\"{}._tcp.{}\", nameserver=\"{}\"",
|
|
66
86
|
service_,
|
|
67
|
-
|
|
68
|
-
config_
|
|
87
|
+
logger::system_data(address_),
|
|
88
|
+
logger::system_data(nameserver_address(config_)));
|
|
69
89
|
dns_client_.query_srv(address_,
|
|
70
90
|
service_,
|
|
71
91
|
config_,
|
|
72
92
|
[self = shared_from_this(), callback = std::move(callback)](
|
|
73
|
-
couchbase::core::io::dns::dns_srv_response&& resp) mutable {
|
|
93
|
+
couchbase::core::io::dns::dns_srv_response&& resp) mutable -> void {
|
|
74
94
|
origin::node_list nodes;
|
|
75
95
|
if (resp.ec) {
|
|
76
96
|
CB_LOG_WARNING("failed to fetch DNS SRV records for \"{}\" ({}), "
|
|
77
97
|
"assuming that cluster is listening this address",
|
|
78
|
-
self->address_,
|
|
98
|
+
logger::system_data(self->address_),
|
|
79
99
|
resp.ec.message());
|
|
80
100
|
} else if (resp.targets.empty() && self->address_ != "localhost") {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
101
|
+
if (self->config_.nameserver().empty()) {
|
|
102
|
+
CB_LOG_DEBUG("DNS SRV query returned 0 records for \"{}\", assuming "
|
|
103
|
+
"that cluster is listening this address",
|
|
104
|
+
logger::system_data(self->address_));
|
|
105
|
+
} else {
|
|
106
|
+
CB_LOG_WARNING(
|
|
107
|
+
"DNS SRV query for \"{}._tcp.{}\" returned 0 records from "
|
|
108
|
+
"nameserver \"{}\". The DNS server may not have SRV records "
|
|
109
|
+
"for this hostname, or may not support SRV lookups. "
|
|
110
|
+
"Falling back to direct connection to \"{}\".",
|
|
111
|
+
self->service_,
|
|
112
|
+
logger::system_data(self->address_),
|
|
113
|
+
logger::system_data(nameserver_address(self->config_)),
|
|
114
|
+
logger::system_data(self->address_));
|
|
115
|
+
}
|
|
84
116
|
} else {
|
|
85
117
|
nodes.reserve(resp.targets.size());
|
|
86
118
|
for (const auto& address : resp.targets) {
|
|
@@ -115,14 +147,9 @@ dns_srv_tracker::do_dns_refresh()
|
|
|
115
147
|
|
|
116
148
|
if (!listeners.empty()) {
|
|
117
149
|
auto config = topology::make_blank_configuration(nodes, self->use_tls_, true);
|
|
118
|
-
std::vector<std::string> endpoints;
|
|
119
|
-
endpoints.reserve(nodes.size());
|
|
120
|
-
for (const auto& [host, port] : nodes) {
|
|
121
|
-
endpoints.emplace_back(fmt::format("\"{}:{}\"", host, port));
|
|
122
|
-
}
|
|
123
150
|
CB_LOG_DEBUG("generated configuration from DNS-SRV response \"{}\": [{}]",
|
|
124
|
-
self->address_,
|
|
125
|
-
|
|
151
|
+
logger::system_data(self->address_),
|
|
152
|
+
logger::system_data_list(node_addresses(nodes), logger::list_entries::quoted));
|
|
126
153
|
for (const auto& listener : listeners) {
|
|
127
154
|
listener->update_config(config);
|
|
128
155
|
}
|
|
@@ -152,7 +179,7 @@ dns_srv_tracker::report_bootstrap_error(const std::string& endpoint, std::error_
|
|
|
152
179
|
CB_LOG_DEBUG(
|
|
153
180
|
"all nodes failed to bootstrap, triggering DNS-SRV refresh, ec={}, last endpoint=\"{}\"",
|
|
154
181
|
ec.message(),
|
|
155
|
-
endpoint);
|
|
182
|
+
logger::system_data(endpoint));
|
|
156
183
|
return asio::post(asio::bind_executor(ctx_, [self = shared_from_this()]() mutable {
|
|
157
184
|
self->do_dns_refresh();
|
|
158
185
|
}));
|
|
@@ -86,6 +86,19 @@ error::error(std::error_code ec,
|
|
|
86
86
|
{
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
error::error(std::error_code ec,
|
|
90
|
+
std::string message,
|
|
91
|
+
couchbase::error_context ctx,
|
|
92
|
+
couchbase::error cause,
|
|
93
|
+
couchbase::node_id node_id)
|
|
94
|
+
: ec_{ ec }
|
|
95
|
+
, message_{ std::move(message) }
|
|
96
|
+
, ctx_{ std::move(ctx) }
|
|
97
|
+
, cause_{ std::make_shared<error>(std::move(cause)) }
|
|
98
|
+
, node_id_{ std::move(node_id) }
|
|
99
|
+
{
|
|
100
|
+
}
|
|
101
|
+
|
|
89
102
|
auto
|
|
90
103
|
error::ec() const -> std::error_code
|
|
91
104
|
{
|
|
@@ -120,7 +133,8 @@ error::node_id() const -> const couchbase::node_id&
|
|
|
120
133
|
return node_id_;
|
|
121
134
|
}
|
|
122
135
|
|
|
123
|
-
error::
|
|
136
|
+
error::
|
|
137
|
+
operator bool() const
|
|
124
138
|
{
|
|
125
139
|
return ec_.value() != 0;
|
|
126
140
|
}
|
|
@@ -222,11 +236,17 @@ make_error(const core::transactions::op_exception& exc) -> couchbase::error
|
|
|
222
236
|
}
|
|
223
237
|
|
|
224
238
|
if (cause.has_value()) {
|
|
239
|
+
// Propagate node_id from the inner cause to the outer error. Without
|
|
240
|
+
// this, a transaction-wrapped KV failure would have outer.node_id() ==
|
|
241
|
+
// {} while cause().value().node_id() carries the real attribution —
|
|
242
|
+
// surprising for callers reading error.node_id() at the top level.
|
|
243
|
+
auto node_id = cause->node_id();
|
|
225
244
|
return couchbase::error{
|
|
226
245
|
transaction_op_errc_from_external_exception(exc.cause()),
|
|
227
246
|
exc.what(),
|
|
228
247
|
{},
|
|
229
|
-
cause
|
|
248
|
+
std::move(*cause),
|
|
249
|
+
std::move(node_id),
|
|
230
250
|
};
|
|
231
251
|
}
|
|
232
252
|
|
|
@@ -0,0 +1,111 @@
|
|
|
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 <couchbase/analytics_meta_data.hxx>
|
|
21
|
+
#include <couchbase/analytics_stream_result.hxx>
|
|
22
|
+
#include <couchbase/error_codes.hxx>
|
|
23
|
+
|
|
24
|
+
#include "core/analytics_stream.hxx"
|
|
25
|
+
|
|
26
|
+
#include "core/error_context/analytics.hxx"
|
|
27
|
+
#include <atomic>
|
|
28
|
+
#include <future>
|
|
29
|
+
|
|
30
|
+
#include <memory>
|
|
31
|
+
#include <mutex>
|
|
32
|
+
#include <optional>
|
|
33
|
+
#include <system_error>
|
|
34
|
+
#include <utility>
|
|
35
|
+
#include <vector>
|
|
36
|
+
|
|
37
|
+
namespace couchbase::core::impl
|
|
38
|
+
{
|
|
39
|
+
class observability_recorder;
|
|
40
|
+
} // namespace couchbase::core::impl
|
|
41
|
+
|
|
42
|
+
namespace couchbase
|
|
43
|
+
{
|
|
44
|
+
class internal_analytics_stream_result
|
|
45
|
+
: public std::enable_shared_from_this<internal_analytics_stream_result>
|
|
46
|
+
{
|
|
47
|
+
public:
|
|
48
|
+
internal_analytics_stream_result(core::analytics_stream stream,
|
|
49
|
+
std::unique_ptr<core::impl::observability_recorder> obs_rec,
|
|
50
|
+
core::error_context::analytics ctx);
|
|
51
|
+
// Non-copyable and non-movable: holds a std::mutex and is only ever owned via shared_ptr.
|
|
52
|
+
internal_analytics_stream_result(const internal_analytics_stream_result&) = delete;
|
|
53
|
+
internal_analytics_stream_result(internal_analytics_stream_result&&) = delete;
|
|
54
|
+
auto operator=(const internal_analytics_stream_result&)
|
|
55
|
+
-> internal_analytics_stream_result& = delete;
|
|
56
|
+
auto operator=(internal_analytics_stream_result&&) -> internal_analytics_stream_result& = delete;
|
|
57
|
+
|
|
58
|
+
~internal_analytics_stream_result();
|
|
59
|
+
|
|
60
|
+
void next(analytics_row_handler&& handler);
|
|
61
|
+
void cancel();
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Returns the analytics signature captured from the response metadata.
|
|
65
|
+
*/
|
|
66
|
+
[[nodiscard]] auto signature() const -> std::optional<codec::binary>;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Returns a future that resolves to analytics metadata once the stream reaches its terminal
|
|
70
|
+
* state (all rows consumed or an error). If the terminal has already been reached, returns a
|
|
71
|
+
* ready future built from the stored value.
|
|
72
|
+
*/
|
|
73
|
+
auto meta_data() -> std::future<std::pair<error, analytics_meta_data>>;
|
|
74
|
+
|
|
75
|
+
private:
|
|
76
|
+
/**
|
|
77
|
+
* Called when next_row reports the terminal condition (nullopt row).
|
|
78
|
+
* Resolves the meta_data promise from the core stream.
|
|
79
|
+
*
|
|
80
|
+
* @param ec error code from the terminal next_row call (falsy = clean end)
|
|
81
|
+
*/
|
|
82
|
+
void resolve_meta_data(std::error_code ec);
|
|
83
|
+
|
|
84
|
+
core::analytics_stream stream_;
|
|
85
|
+
|
|
86
|
+
// The request's error context as of a successfully started stream (statement, parameters, HTTP
|
|
87
|
+
// status, endpoint). A terminal error is reported against a copy of this with the trailer's
|
|
88
|
+
// diagnostics stamped on, so a mid-stream failure is as diagnosable as one that failed to start.
|
|
89
|
+
core::error_context::analytics ctx_;
|
|
90
|
+
|
|
91
|
+
// Observability recorder for the whole streaming operation. Its operation span already parents
|
|
92
|
+
// the request; finish() is called exactly once from resolve_meta_data() (the single terminal
|
|
93
|
+
// hook, reached on drain/error/cancel/destruction), recording the operation latency metric and
|
|
94
|
+
// ending the span — the same instrumentation buffered analytics_query() emits via its recorder.
|
|
95
|
+
std::unique_ptr<core::impl::observability_recorder> obs_rec_;
|
|
96
|
+
|
|
97
|
+
// Guards the "only one outstanding next()" contract. Set while a pull is in flight and cleared
|
|
98
|
+
// when its handler runs; a concurrent/overlapping next() is rejected with invalid_argument
|
|
99
|
+
// rather than racing the single-consumer channel. Shared across handle copies (they alias one
|
|
100
|
+
// stream), so copies cannot smuggle in a second concurrent pull either.
|
|
101
|
+
std::atomic_bool pull_in_flight_{ false };
|
|
102
|
+
|
|
103
|
+
mutable std::mutex meta_mutex_{};
|
|
104
|
+
bool terminal_reached_{ false };
|
|
105
|
+
std::pair<error, analytics_meta_data> terminal_value_{};
|
|
106
|
+
// meta_data() may be called any number of times before the stream terminates; each call parks a
|
|
107
|
+
// promise here and they are all satisfied together at the terminal. (A single shared promise
|
|
108
|
+
// would throw future_already_retrieved on the second call.)
|
|
109
|
+
std::vector<std::promise<std::pair<error, analytics_meta_data>>> pending_meta_promises_{};
|
|
110
|
+
};
|
|
111
|
+
} // namespace couchbase
|
|
@@ -0,0 +1,110 @@
|
|
|
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 <couchbase/error_codes.hxx>
|
|
21
|
+
#include <couchbase/query_meta_data.hxx>
|
|
22
|
+
#include <couchbase/query_stream_result.hxx>
|
|
23
|
+
|
|
24
|
+
#include "core/query_stream.hxx"
|
|
25
|
+
|
|
26
|
+
#include "core/error_context/query.hxx"
|
|
27
|
+
#include <atomic>
|
|
28
|
+
#include <future>
|
|
29
|
+
|
|
30
|
+
#include <memory>
|
|
31
|
+
#include <mutex>
|
|
32
|
+
#include <optional>
|
|
33
|
+
#include <system_error>
|
|
34
|
+
#include <utility>
|
|
35
|
+
#include <vector>
|
|
36
|
+
|
|
37
|
+
namespace couchbase::core::impl
|
|
38
|
+
{
|
|
39
|
+
class observability_recorder;
|
|
40
|
+
} // namespace couchbase::core::impl
|
|
41
|
+
|
|
42
|
+
namespace couchbase
|
|
43
|
+
{
|
|
44
|
+
class internal_query_stream_result
|
|
45
|
+
: public std::enable_shared_from_this<internal_query_stream_result>
|
|
46
|
+
{
|
|
47
|
+
public:
|
|
48
|
+
internal_query_stream_result(core::query_stream stream,
|
|
49
|
+
std::unique_ptr<core::impl::observability_recorder> obs_rec,
|
|
50
|
+
core::error_context::query ctx);
|
|
51
|
+
// Non-copyable and non-movable: holds a std::mutex and is only ever owned via shared_ptr.
|
|
52
|
+
internal_query_stream_result(const internal_query_stream_result&) = delete;
|
|
53
|
+
internal_query_stream_result(internal_query_stream_result&&) = delete;
|
|
54
|
+
auto operator=(const internal_query_stream_result&) -> internal_query_stream_result& = delete;
|
|
55
|
+
auto operator=(internal_query_stream_result&&) -> internal_query_stream_result& = delete;
|
|
56
|
+
|
|
57
|
+
~internal_query_stream_result();
|
|
58
|
+
|
|
59
|
+
void next(query_row_handler&& handler);
|
|
60
|
+
void cancel();
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Returns the query signature captured from the response metadata.
|
|
64
|
+
*/
|
|
65
|
+
[[nodiscard]] auto signature() const -> std::optional<codec::binary>;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Returns a future that resolves to query metadata once the stream reaches its terminal state
|
|
69
|
+
* (all rows consumed or an error). If the terminal has already been reached, returns a
|
|
70
|
+
* ready future built from the stored value.
|
|
71
|
+
*/
|
|
72
|
+
auto meta_data() -> std::future<std::pair<error, query_meta_data>>;
|
|
73
|
+
|
|
74
|
+
private:
|
|
75
|
+
/**
|
|
76
|
+
* Called when next_row reports the terminal condition (nullopt row).
|
|
77
|
+
* Resolves the meta_data promise from the core stream.
|
|
78
|
+
*
|
|
79
|
+
* @param ec error code from the terminal next_row call (falsy = clean end)
|
|
80
|
+
*/
|
|
81
|
+
void resolve_meta_data(std::error_code ec);
|
|
82
|
+
|
|
83
|
+
core::query_stream stream_;
|
|
84
|
+
|
|
85
|
+
// The request's error context as of a successfully started stream (statement, parameters, HTTP
|
|
86
|
+
// status, endpoint). A terminal error is reported against a copy of this with the trailer's
|
|
87
|
+
// diagnostics stamped on, so a mid-stream failure is as diagnosable as one that failed to start.
|
|
88
|
+
core::error_context::query ctx_;
|
|
89
|
+
|
|
90
|
+
// Observability recorder for the whole streaming operation. Its operation span already parents
|
|
91
|
+
// the request; finish() is called exactly once from resolve_meta_data() (the single terminal
|
|
92
|
+
// hook, reached on drain/error/cancel/destruction), recording the operation latency metric and
|
|
93
|
+
// ending the span — the same instrumentation the buffered query() emits via its recorder.
|
|
94
|
+
std::unique_ptr<core::impl::observability_recorder> obs_rec_;
|
|
95
|
+
|
|
96
|
+
// Guards the "only one outstanding next()" contract. Set while a pull is in flight and cleared
|
|
97
|
+
// when its handler runs; a concurrent/overlapping next() is rejected with invalid_argument
|
|
98
|
+
// rather than racing the single-consumer channel. Shared across handle copies (they alias one
|
|
99
|
+
// stream), so copies cannot smuggle in a second concurrent pull either.
|
|
100
|
+
std::atomic_bool pull_in_flight_{ false };
|
|
101
|
+
|
|
102
|
+
mutable std::mutex meta_mutex_{};
|
|
103
|
+
bool terminal_reached_{ false };
|
|
104
|
+
std::pair<error, query_meta_data> terminal_value_{};
|
|
105
|
+
// meta_data() may be called any number of times before the stream terminates; each call parks a
|
|
106
|
+
// promise here and they are all satisfied together at the terminal. (A single shared promise
|
|
107
|
+
// would throw future_already_retrieved on the second call.)
|
|
108
|
+
std::vector<std::promise<std::pair<error, query_meta_data>>> pending_meta_promises_{};
|
|
109
|
+
};
|
|
110
|
+
} // namespace couchbase
|
|
@@ -30,15 +30,23 @@ namespace couchbase::core::impl
|
|
|
30
30
|
* allocation a type-erasing wrapper would introduce for the sole purpose of
|
|
31
31
|
* setting node_id - that extra allocation was the source of the 18
|
|
32
32
|
* "Potential memory leak" reports clang-static-analyzer flagged against the
|
|
33
|
-
* previous wrap_with_node_id helper.
|
|
34
|
-
*
|
|
35
|
-
*
|
|
33
|
+
* previous wrap_with_node_id helper.
|
|
34
|
+
*
|
|
35
|
+
* Parameters are taken by forwarding reference and perfect-forwarded to the
|
|
36
|
+
* invocation. Callers at the SDK boundary always pass rvalues (the result
|
|
37
|
+
* and error are constructed in-place at the response decoder), so this
|
|
38
|
+
* pattern eliminates the intermediate parameter-slot move and the
|
|
39
|
+
* @c invoke_with_node_id helper's overhead actually approaches zero — what
|
|
40
|
+
* the commit message claimed but the original (by-value) signatures did
|
|
41
|
+
* not quite deliver.
|
|
36
42
|
*/
|
|
37
|
-
template<typename Handler, typename Result>
|
|
43
|
+
template<typename Handler, typename Error, typename Result>
|
|
38
44
|
void
|
|
39
|
-
invoke_with_node_id(Handler&& handler,
|
|
45
|
+
invoke_with_node_id(Handler&& handler, Error&& err, Result&& result)
|
|
40
46
|
{
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
// Read node_id() BEFORE we move err, otherwise the read would see a
|
|
48
|
+
// moved-from string and yield a default node_id.
|
|
49
|
+
result.set_node_id_internal(err.node_id());
|
|
50
|
+
std::forward<Handler>(handler)(std::forward<Error>(err), std::forward<Result>(result));
|
|
43
51
|
}
|
|
44
52
|
} // namespace couchbase::core::impl
|
|
@@ -90,6 +90,12 @@ struct key_value_error_category : std::error_category {
|
|
|
90
90
|
return "mutation_token_outdated (133)";
|
|
91
91
|
case errc::key_value::range_scan_completed:
|
|
92
92
|
return "range_scan_completed (134)";
|
|
93
|
+
case errc::key_value::document_not_found_on_replica:
|
|
94
|
+
return "document_not_found_on_replica (135)";
|
|
95
|
+
case errc::key_value::replica_index_out_of_bounds:
|
|
96
|
+
return "replica_index_out_of_bounds (136)";
|
|
97
|
+
case errc::key_value::replica_index_currently_unavailable:
|
|
98
|
+
return "replica_index_currently_unavailable (137)";
|
|
93
99
|
}
|
|
94
100
|
return "FIXME: unknown error code (recompile with newer library): couchbase.key_value." +
|
|
95
101
|
std::to_string(ev);
|
|
@@ -59,7 +59,6 @@ lookup_in_replica_request::make_response(key_value_error_context&& ctx,
|
|
|
59
59
|
bool deleted = false;
|
|
60
60
|
couchbase::cas cas{};
|
|
61
61
|
std::vector<lookup_in_replica_response::entry> fields{};
|
|
62
|
-
std::error_code ec = ctx.ec();
|
|
63
62
|
std::optional<std::size_t> first_error_index{};
|
|
64
63
|
std::optional<std::string> first_error_path{};
|
|
65
64
|
|
|
@@ -83,13 +82,14 @@ lookup_in_replica_request::make_response(key_value_error_context&& ctx,
|
|
|
83
82
|
static_cast<std::uint16_t>(res_entry.status));
|
|
84
83
|
if (fields[i].opcode == protocol::subdoc_opcode::exists &&
|
|
85
84
|
fields[i].ec == errc::key_value::path_not_found) {
|
|
85
|
+
// exists treats path_not_found as success ("false"); suppress the error so the
|
|
86
|
+
// exists flag below carries the result instead.
|
|
86
87
|
fields[i].ec.clear();
|
|
87
88
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
first_error_index = i;
|
|
89
|
+
// Use original_index, not wire-order i: XATTR specs are reordered during encode_to(),
|
|
90
|
+
// so i != original_index (was the CXXCBC-788 bug).
|
|
91
|
+
if (!first_error_index && fields[i].ec) {
|
|
92
|
+
first_error_index = fields[i].original_index;
|
|
93
93
|
first_error_path = fields[i].path;
|
|
94
94
|
}
|
|
95
95
|
fields[i].exists = res_entry.status == key_value_status_code::success ||
|
|
@@ -100,16 +100,16 @@ lookup_in_replica_request::make_response(key_value_error_context&& ctx,
|
|
|
100
100
|
fields[i].value = utils::to_binary(res_entry.value);
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
// Always assign CAS; previously guarded by a local ec that was polluted by per-path
|
|
104
|
+
// errors, zeroing CAS whenever any path failed (CXXCBC-788).
|
|
105
|
+
cas = encoded.cas();
|
|
106
106
|
std::sort(fields.begin(), fields.end(), [](const auto& lhs, const auto& rhs) {
|
|
107
107
|
return lhs.original_index < rhs.original_index;
|
|
108
108
|
});
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
return lookup_in_replica_response{
|
|
112
|
-
make_subdocument_error_context(ctx, ec, first_error_path, first_error_index, deleted),
|
|
112
|
+
make_subdocument_error_context(ctx, ctx.ec(), first_error_path, first_error_index, deleted),
|
|
113
113
|
cas,
|
|
114
114
|
std::move(fields),
|
|
115
115
|
deleted,
|
|
@@ -35,10 +35,10 @@ struct lookup_in_replica_response {
|
|
|
35
35
|
struct entry {
|
|
36
36
|
std::string path;
|
|
37
37
|
couchbase::codec::binary value;
|
|
38
|
-
std::size_t original_index;
|
|
39
|
-
bool exists;
|
|
40
|
-
protocol::subdoc_opcode opcode;
|
|
41
|
-
key_value_status_code status;
|
|
38
|
+
std::size_t original_index{};
|
|
39
|
+
bool exists{};
|
|
40
|
+
protocol::subdoc_opcode opcode{};
|
|
41
|
+
key_value_status_code status{};
|
|
42
42
|
std::error_code ec{};
|
|
43
43
|
};
|
|
44
44
|
subdocument_error_context ctx{};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
2
|
/*
|
|
3
|
-
* Copyright
|
|
3
|
+
* Copyright 2026-Present Couchbase, Inc.
|
|
4
4
|
*
|
|
5
5
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
6
|
* you may not use this file except in compliance with the License.
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
|
|
20
20
|
#include "core/utils/crc32.hxx"
|
|
21
21
|
|
|
22
|
-
#include <
|
|
23
|
-
|
|
22
|
+
#include <array>
|
|
24
23
|
#include <cstdint>
|
|
25
24
|
#include <string>
|
|
25
|
+
#include <utility>
|
|
26
26
|
|
|
27
27
|
namespace couchbase
|
|
28
28
|
{
|
|
@@ -39,9 +39,19 @@ namespace
|
|
|
39
39
|
auto
|
|
40
40
|
derive_fallback_id(const std::string& hostname, std::uint16_t port) -> std::string
|
|
41
41
|
{
|
|
42
|
-
auto input =
|
|
42
|
+
auto input = hostname + ':' + std::to_string(port);
|
|
43
43
|
auto crc = core::utils::hash_crc32(input.data(), input.size());
|
|
44
|
-
|
|
44
|
+
|
|
45
|
+
// Format as 8 lowercase hex chars, zero-padded — avoids a heavy fmt include
|
|
46
|
+
// for what amounts to a two-line hex conversion.
|
|
47
|
+
static constexpr std::array<char, 16> hex_digits{ '0', '1', '2', '3', '4', '5', '6', '7',
|
|
48
|
+
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
|
49
|
+
std::string out;
|
|
50
|
+
out.reserve(8);
|
|
51
|
+
for (int shift = 28; shift >= 0; shift -= 4) {
|
|
52
|
+
out.push_back(hex_digits[(crc >> shift) & 0xFU]);
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
45
55
|
}
|
|
46
56
|
} // namespace
|
|
47
57
|
|
|
@@ -54,56 +64,82 @@ node_id::node_id(std::string node_uuid, std::string hostname, std::uint16_t port
|
|
|
54
64
|
}
|
|
55
65
|
|
|
56
66
|
auto
|
|
57
|
-
node_id::id() const -> const std::string&
|
|
67
|
+
node_id::id() const noexcept -> const std::string&
|
|
58
68
|
{
|
|
59
69
|
return id_;
|
|
60
70
|
}
|
|
61
71
|
|
|
62
72
|
auto
|
|
63
|
-
node_id::node_uuid() const -> const std::string&
|
|
73
|
+
node_id::node_uuid() const noexcept -> const std::string&
|
|
64
74
|
{
|
|
65
75
|
return node_uuid_;
|
|
66
76
|
}
|
|
67
77
|
|
|
68
78
|
auto
|
|
69
|
-
node_id::hostname() const -> const std::string&
|
|
79
|
+
node_id::hostname() const noexcept -> const std::string&
|
|
70
80
|
{
|
|
71
81
|
return hostname_;
|
|
72
82
|
}
|
|
73
83
|
|
|
74
84
|
auto
|
|
75
|
-
node_id::port() const -> std::uint16_t
|
|
85
|
+
node_id::port() const noexcept -> std::uint16_t
|
|
76
86
|
{
|
|
77
87
|
return port_;
|
|
78
88
|
}
|
|
79
89
|
|
|
80
90
|
node_id::
|
|
81
|
-
operator bool() const
|
|
91
|
+
operator bool() const noexcept
|
|
82
92
|
{
|
|
83
93
|
return !id_.empty();
|
|
84
94
|
}
|
|
85
95
|
|
|
86
96
|
auto
|
|
87
|
-
node_id::operator==(const node_id& other) const -> bool
|
|
97
|
+
node_id::operator==(const node_id& other) const noexcept -> bool
|
|
88
98
|
{
|
|
89
99
|
return id_ == other.id_;
|
|
90
100
|
}
|
|
91
101
|
|
|
92
102
|
auto
|
|
93
|
-
node_id::operator!=(const node_id& other) const -> bool
|
|
103
|
+
node_id::operator!=(const node_id& other) const noexcept -> bool
|
|
94
104
|
{
|
|
95
105
|
return !(*this == other);
|
|
96
106
|
}
|
|
97
107
|
|
|
98
108
|
auto
|
|
99
|
-
node_id::operator<(const node_id& other) const -> bool
|
|
109
|
+
node_id::operator<(const node_id& other) const noexcept -> bool
|
|
100
110
|
{
|
|
101
111
|
return id_ < other.id_;
|
|
102
112
|
}
|
|
103
113
|
|
|
114
|
+
auto
|
|
115
|
+
node_id::operator<=(const node_id& other) const noexcept -> bool
|
|
116
|
+
{
|
|
117
|
+
return !(other < *this);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
auto
|
|
121
|
+
node_id::operator>(const node_id& other) const noexcept -> bool
|
|
122
|
+
{
|
|
123
|
+
return other < *this;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
auto
|
|
127
|
+
node_id::operator>=(const node_id& other) const noexcept -> bool
|
|
128
|
+
{
|
|
129
|
+
return !(*this < other);
|
|
130
|
+
}
|
|
131
|
+
|
|
104
132
|
auto
|
|
105
133
|
internal_node_id::build(std::string node_uuid, std::string hostname, std::uint16_t port) -> node_id
|
|
106
134
|
{
|
|
135
|
+
// Preserve the "falsy = unknown" contract: a node that has neither a
|
|
136
|
+
// server-assigned UUID nor a usable hostname+port pair cannot be uniquely
|
|
137
|
+
// identified. Returning a default-constructed node_id keeps such an input
|
|
138
|
+
// falsy so request- and response-side identity construction agree on the
|
|
139
|
+
// same "empty" answer for not-yet-bound or KV-less topology entries.
|
|
140
|
+
if (node_uuid.empty() && (hostname.empty() || port == 0)) {
|
|
141
|
+
return {};
|
|
142
|
+
}
|
|
107
143
|
return { std::move(node_uuid), std::move(hostname), port };
|
|
108
144
|
}
|
|
109
145
|
|
|
@@ -45,8 +45,18 @@ observability_recorder::operation_span() -> const std::shared_ptr<couchbase::tra
|
|
|
45
45
|
void
|
|
46
46
|
observability_recorder::finish(const std::error_code ec)
|
|
47
47
|
{
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
// Precompute the standardized error type once here, so the recorder-cache lookup keyed on it does
|
|
49
|
+
// not build a string per comparison.
|
|
50
|
+
metric_attributes_.error_type = metrics::standardized_error_type(ec);
|
|
51
|
+
// meter_ is a weak_ptr. On the buffered path finish() always runs inside the io-thread execute
|
|
52
|
+
// completion, so the meter (owned by the cluster) is alive. The streaming path defers finish() to
|
|
53
|
+
// a user-controlled terminal — a stream handle dropped via its destructor/cancel() — which may
|
|
54
|
+
// run after the owning cluster, and its meter, is gone. Guard the lock so a late finish records
|
|
55
|
+
// nothing instead of dereferencing an expired weak_ptr. span_ holds a strong ref, so ending it is
|
|
56
|
+
// always safe.
|
|
57
|
+
if (const auto meter = meter_.lock()) {
|
|
58
|
+
meter->record_value(std::move(metric_attributes_), start_time_);
|
|
59
|
+
}
|
|
50
60
|
span_->end();
|
|
51
61
|
}
|
|
52
62
|
|