couchbase 3.8.2 → 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 +1 -1
- data/ext/CMakeLists.txt +16 -1
- data/ext/cache/cpm/{CPM_0.42.0.cmake → CPM_0.43.1.cmake} +18 -2
- data/ext/cache/extconf_include.rb +6 -6
- data/ext/cache/mozilla-ca-bundle.crt +121 -55
- data/ext/cache/mozilla-ca-bundle.sha256 +1 -1
- data/ext/couchbase/CMakeLists.txt +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 +229 -42
- data/ext/couchbase/core/impl/public_query_stream_result.cxx +380 -0
- data/ext/couchbase/core/impl/public_transaction_get_multi_replicas_from_preferred_server_group_result.cxx +42 -0
- data/ext/couchbase/core/impl/public_transaction_get_multi_result.cxx +42 -0
- data/ext/couchbase/core/impl/query.cxx +76 -7
- data/ext/couchbase/core/impl/query.hxx +36 -0
- data/ext/couchbase/core/impl/query_index_manager.cxx +54 -1
- data/ext/couchbase/core/impl/replica_utils.cxx +101 -0
- data/ext/couchbase/core/impl/replica_utils.hxx +64 -0
- data/ext/couchbase/core/impl/resolve_node_id.hxx +125 -0
- data/ext/couchbase/core/impl/scope.cxx +70 -0
- data/ext/couchbase/core/impl/search.cxx +31 -1
- data/ext/couchbase/core/impl/transactions.cxx +130 -0
- data/ext/couchbase/core/impl/wait_until_ready.cxx +439 -0
- data/ext/couchbase/core/impl/wait_until_ready.hxx +110 -0
- data/ext/couchbase/core/impl/with_bucket_config_or_timeout.hxx +180 -0
- data/ext/couchbase/core/impl/with_cancellation.hxx +11 -3
- data/ext/couchbase/core/io/configuration_belongs_to_session.hxx +1 -2
- data/ext/couchbase/core/io/dns_client.cxx +122 -45
- data/ext/couchbase/core/io/dns_codec.hxx +21 -21
- data/ext/couchbase/core/io/dns_config.cxx +21 -6
- data/ext/couchbase/core/io/http_command.hxx +149 -121
- data/ext/couchbase/core/io/http_error.hxx +107 -0
- data/ext/couchbase/core/io/http_parser.cxx +4 -0
- data/ext/couchbase/core/io/http_session.cxx +606 -154
- data/ext/couchbase/core/io/http_session.hxx +147 -30
- data/ext/couchbase/core/io/http_session_manager.hxx +329 -382
- data/ext/couchbase/core/io/http_streaming_parser.cxx +4 -0
- data/ext/couchbase/core/io/http_streaming_response.cxx +328 -43
- data/ext/couchbase/core/io/http_streaming_response.hxx +37 -3
- data/ext/couchbase/core/io/mcbp_buffer_pool.hxx +122 -0
- data/ext/couchbase/core/io/mcbp_command.hxx +150 -51
- data/ext/couchbase/core/io/mcbp_command_id.hxx +45 -0
- data/ext/couchbase/core/io/mcbp_message.cxx +9 -1
- data/ext/couchbase/core/io/mcbp_message.hxx +19 -0
- data/ext/couchbase/core/io/mcbp_output_queue.hxx +150 -0
- data/ext/couchbase/core/io/mcbp_parser.cxx +24 -7
- data/ext/couchbase/core/io/mcbp_session.cxx +309 -301
- data/ext/couchbase/core/io/mcbp_session.hxx +27 -18
- data/ext/couchbase/core/io/opaque_ring_table.hxx +145 -0
- data/ext/couchbase/core/io/retry_orchestrator.hxx +6 -5
- data/ext/couchbase/core/io/stream_deadline.hxx +50 -0
- data/ext/couchbase/core/io/streams.cxx +151 -21
- data/ext/couchbase/core/io/streams.hxx +48 -1
- data/ext/couchbase/core/logger/logger.cxx +36 -0
- data/ext/couchbase/core/logger/logger.hxx +46 -6
- data/ext/couchbase/core/logger/redaction.hxx +503 -0
- data/ext/couchbase/core/management/eventing_status.hxx +10 -0
- data/ext/couchbase/core/management/eventing_status_json.hxx +4 -0
- data/ext/couchbase/core/mcbp/big_endian.cxx +1 -1
- data/ext/couchbase/core/mcbp/codec.cxx +27 -18
- data/ext/couchbase/core/mcbp/operation_queue.cxx +2 -2
- data/ext/couchbase/core/mcbp/packet.hxx +2 -2
- data/ext/couchbase/core/mcbp/queue_request.cxx +23 -6
- data/ext/couchbase/core/mcbp/queue_request.hxx +21 -0
- data/ext/couchbase/core/meta/features.hxx +13 -0
- data/ext/couchbase/core/meta/version.cxx +6 -3
- data/ext/couchbase/core/metrics/logging_meter.cxx +5 -10
- data/ext/couchbase/core/metrics/meter_wrapper.cxx +63 -33
- data/ext/couchbase/core/metrics/meter_wrapper.hxx +55 -3
- data/ext/couchbase/core/operations/analytics_response_parsing.cxx +177 -0
- data/ext/couchbase/core/operations/analytics_response_parsing.hxx +55 -0
- data/ext/couchbase/core/operations/document_analytics.cxx +48 -130
- data/ext/couchbase/core/operations/document_analytics.hxx +14 -2
- data/ext/couchbase/core/operations/document_get_all_replicas.hxx +15 -7
- data/ext/couchbase/core/operations/document_get_any_replica.hxx +19 -8
- data/ext/couchbase/core/operations/document_get_projected.cxx +1 -1
- data/ext/couchbase/core/{impl/get_replica.cxx → operations/document_get_replica.cxx} +21 -3
- data/ext/couchbase/core/{impl/get_replica.hxx → operations/document_get_replica.hxx} +31 -4
- data/ext/couchbase/core/operations/document_lookup_in.cxx +10 -10
- data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +228 -198
- data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +215 -217
- data/ext/couchbase/core/operations/document_query.cxx +108 -221
- data/ext/couchbase/core/operations/document_query.hxx +18 -4
- data/ext/couchbase/core/operations/document_search.cxx +52 -8
- data/ext/couchbase/core/operations/document_search.hxx +3 -0
- data/ext/couchbase/core/operations/document_view.cxx +3 -3
- data/ext/couchbase/core/operations/management/analytics_dataset_create.cxx +15 -8
- data/ext/couchbase/core/operations/management/analytics_dataset_create.hxx +4 -0
- data/ext/couchbase/core/operations/management/analytics_dataset_drop.cxx +11 -6
- data/ext/couchbase/core/operations/management/analytics_dataset_get_all.cxx +3 -2
- data/ext/couchbase/core/operations/management/analytics_dataverse_create.cxx +10 -5
- data/ext/couchbase/core/operations/management/analytics_dataverse_drop.cxx +10 -5
- data/ext/couchbase/core/operations/management/analytics_get_pending_mutations.cxx +2 -1
- data/ext/couchbase/core/operations/management/analytics_index_create.cxx +33 -8
- data/ext/couchbase/core/operations/management/analytics_index_drop.cxx +12 -7
- data/ext/couchbase/core/operations/management/analytics_index_get_all.cxx +3 -2
- data/ext/couchbase/core/operations/management/analytics_link_connect.cxx +11 -6
- data/ext/couchbase/core/operations/management/analytics_link_create.cxx +3 -3
- data/ext/couchbase/core/operations/management/analytics_link_disconnect.cxx +10 -4
- data/ext/couchbase/core/operations/management/analytics_link_drop.cxx +6 -4
- data/ext/couchbase/core/operations/management/analytics_link_get_all.cxx +4 -3
- data/ext/couchbase/core/operations/management/analytics_link_replace.cxx +3 -3
- data/ext/couchbase/core/operations/management/analytics_link_utils.hxx +1 -1
- data/ext/couchbase/core/operations/management/change_password.cxx +2 -0
- data/ext/couchbase/core/operations/management/collection_drop.cxx +5 -1
- data/ext/couchbase/core/operations/management/error_utils.cxx +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 +108 -63
- data/ext/couchbase/core/transactions/attempt_context_impl.hxx +19 -2
- data/ext/couchbase/core/transactions/error_list.hxx +2 -2
- data/ext/couchbase/core/transactions/get_multi_fetch.hxx +160 -0
- data/ext/couchbase/core/transactions/get_multi_orchestrator.cxx +326 -125
- data/ext/couchbase/core/transactions/get_multi_transaction_id.hxx +62 -0
- data/ext/couchbase/core/transactions/internal/atr_entry.hxx +22 -2
- data/ext/couchbase/core/transactions/internal/transaction_context.hxx +2 -2
- data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +23 -1
- data/ext/couchbase/core/transactions/internal/utils.hxx +50 -14
- data/ext/couchbase/core/transactions/staged_mutation.cxx +23 -18
- data/ext/couchbase/core/transactions/staged_mutation.hxx +15 -4
- data/ext/couchbase/core/transactions/transaction_context.cxx +55 -40
- data/ext/couchbase/core/transactions/transaction_get_result.hxx +16 -0
- data/ext/couchbase/core/transactions/transactions.cxx +3 -55
- data/ext/couchbase/core/transactions/transactions_cleanup.cxx +165 -72
- data/ext/couchbase/core/transactions/transactions_config.cxx +0 -11
- data/ext/couchbase/core/transactions/utils.cxx +10 -0
- data/ext/couchbase/core/transactions/waitable_op_list.hxx +2 -2
- data/ext/couchbase/core/transactions.hxx +9 -9
- data/ext/couchbase/core/utils/byteswap.hxx +166 -9
- data/ext/couchbase/core/utils/connection_string.cxx +50 -85
- data/ext/couchbase/core/utils/connection_string.hxx +15 -0
- data/ext/couchbase/core/{columnar/backoff_calculator.hxx → utils/deadline.hxx} +13 -13
- data/ext/couchbase/core/utils/duration_parser.cxx +1 -1
- data/ext/couchbase/core/utils/json_streaming_lexer.cxx +48 -5
- data/ext/couchbase/core/utils/json_streaming_lexer.hxx +4 -1
- data/ext/couchbase/core/utils/movable_function.hxx +301 -52
- data/ext/couchbase/core/utils/name_codec.hxx +154 -11
- data/ext/couchbase/core/{columnar/retry_info.hxx → utils/process_id.hxx} +18 -13
- data/ext/couchbase/core/utils/url_codec.cxx +12 -51
- data/ext/couchbase/core/websocket_codec.cxx +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 +183 -5
- data/ext/couchbase/{core/columnar/security_options.hxx → couchbase/cluster_state.hxx} +18 -14
- data/ext/couchbase/couchbase/codec/lenient_json_transcoder.hxx +69 -0
- data/ext/couchbase/couchbase/collection.hxx +234 -14
- data/ext/couchbase/couchbase/common_durability_options.hxx +18 -3
- data/ext/couchbase/couchbase/conjunction_query.hxx +1 -1
- data/ext/couchbase/couchbase/create_dataset_analytics_options.hxx +6 -1
- data/ext/couchbase/couchbase/date_range_query.hxx +2 -2
- data/ext/couchbase/couchbase/decrement_options.hxx +1 -1
- data/ext/couchbase/couchbase/disjunction_query.hxx +1 -1
- data/ext/couchbase/couchbase/error.hxx +32 -0
- data/ext/couchbase/couchbase/error_codes.hxx +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 +17 -0
- data/lib/couchbase/collection.rb +36 -1
- data/lib/couchbase/errors.rb +18 -0
- data/lib/couchbase/fork_hooks.rb +16 -7
- data/lib/couchbase/get_replica_strategy.rb +89 -0
- data/lib/couchbase/logger.rb +1 -1
- data/lib/couchbase/management/analytics_index_manager.rb +15 -15
- data/lib/couchbase/management/bucket_manager.rb +6 -6
- data/lib/couchbase/management/collection_manager.rb +6 -6
- data/lib/couchbase/management/query_index_manager.rb +7 -7
- data/lib/couchbase/management/search_index_manager.rb +13 -13
- data/lib/couchbase/management/user_manager.rb +10 -10
- data/lib/couchbase/management/view_index_manager.rb +5 -5
- data/lib/couchbase/options.rb +174 -42
- data/lib/couchbase/protostellar/bucket.rb +4 -0
- data/lib/couchbase/protostellar/cluster.rb +4 -0
- data/lib/couchbase/protostellar/collection.rb +4 -0
- data/lib/couchbase/protostellar/error_handling.rb +2 -1
- data/lib/couchbase/protostellar/request.rb +1 -0
- data/lib/couchbase/protostellar/request_generator/kv.rb +16 -2
- data/lib/couchbase/protostellar/request_generator/search.rb +17 -1
- data/lib/couchbase/protostellar/retry/orchestrator.rb +3 -2
- data/lib/couchbase/protostellar/retry/strategies/fail_fast.rb +33 -0
- data/lib/couchbase/protostellar/retry/strategies.rb +1 -0
- data/lib/couchbase/search_options.rb +95 -6
- data/lib/couchbase/version.rb +1 -1
- metadata +91 -33
- data/ext/0001-fix-build-for-mingw-w64-ucrt-x86_64-toolchain.patch +0 -40
- data/ext/couchbase/core/columnar/agent.hxx +0 -71
- data/ext/couchbase/core/columnar/agent_config.hxx +0 -59
- data/ext/couchbase/core/columnar/background_bootstrap_listener.hxx +0 -42
- data/ext/couchbase/core/columnar/backoff_calculator.cxx +0 -62
- data/ext/couchbase/core/columnar/columnar_agent.cxx +0 -147
- data/ext/couchbase/core/columnar/columnar_agent_config.cxx +0 -48
- data/ext/couchbase/core/columnar/columnar_error.cxx +0 -51
- data/ext/couchbase/core/columnar/database_management_options.hxx +0 -56
- data/ext/couchbase/core/columnar/error.hxx +0 -51
- data/ext/couchbase/core/columnar/error_codes.cxx +0 -107
- data/ext/couchbase/core/columnar/error_codes.hxx +0 -75
- data/ext/couchbase/core/columnar/management_component.cxx +0 -300
- data/ext/couchbase/core/columnar/management_component.hxx +0 -56
- data/ext/couchbase/core/columnar/query_component.cxx +0 -523
- data/ext/couchbase/core/columnar/query_component.hxx +0 -57
- data/ext/couchbase/core/columnar/query_options.hxx +0 -59
- data/ext/couchbase/core/columnar/query_result.cxx +0 -130
- data/ext/couchbase/core/columnar/query_result.hxx +0 -78
- data/ext/couchbase/core/io/config_tracker.cxx +0 -687
- data/ext/couchbase/core/io/config_tracker.hxx +0 -123
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2024. Couchbase, Inc.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#pragma once
|
|
19
|
+
|
|
20
|
+
#include <array>
|
|
21
|
+
#include <cstddef>
|
|
22
|
+
#include <utility>
|
|
23
|
+
#include <vector>
|
|
24
|
+
|
|
25
|
+
namespace couchbase::core::io
|
|
26
|
+
{
|
|
27
|
+
/**
|
|
28
|
+
* A tiny free-list of byte buffers used to recycle mcbp response body buffers.
|
|
29
|
+
*
|
|
30
|
+
* A KV response's body is allocated when the frame is parsed and freed a moment later when the
|
|
31
|
+
* decoded response is destroyed. Recycling those buffers keeps their capacity warm, so a subsequent
|
|
32
|
+
* response of similar size reuses the storage instead of allocating (and, once the value crosses
|
|
33
|
+
* the allocator's mmap threshold, mmap/munmap-ing) a fresh block every operation.
|
|
34
|
+
*
|
|
35
|
+
* NOT thread-safe by design, and it performs no synchronization. It is intended to be used as a
|
|
36
|
+
* thread-local pool (see tls_response_body_pool()): acquire and release always happen on the
|
|
37
|
+
* calling thread's own pool, so a buffer acquired on one IO thread but released on another (for
|
|
38
|
+
* example when a replica response is handed to a command strand running on a different IO thread)
|
|
39
|
+
* is simply not recycled back to the acquiring thread — which is safe, because each thread only
|
|
40
|
+
* ever touches its own pool. Recycling is therefore best-effort.
|
|
41
|
+
*
|
|
42
|
+
* Two bounds keep memory in check: at most `max_buffers` buffers are retained, and buffers larger
|
|
43
|
+
* than `max_buffer_bytes` are never pooled (they are freed normally), so a single very large value
|
|
44
|
+
* cannot pin megabytes per thread.
|
|
45
|
+
*
|
|
46
|
+
* The free list is a fixed-size array of (initially empty) buffers, so constructing the pool
|
|
47
|
+
* allocates nothing. That matters because the pool is a lazily-initialized thread_local (see
|
|
48
|
+
* tls_response_body_pool()): the first use on a given thread may be a release() from a response
|
|
49
|
+
* destructor, and that first use triggers the thread_local's construction. Backing the free list
|
|
50
|
+
* with a std::vector would make that construction allocate (and, on failure, throw) inside the
|
|
51
|
+
* noexcept destructor path, where a throw calls std::terminate. A fixed array cannot.
|
|
52
|
+
*/
|
|
53
|
+
class mcbp_buffer_pool
|
|
54
|
+
{
|
|
55
|
+
public:
|
|
56
|
+
using buffer = std::vector<std::byte>;
|
|
57
|
+
|
|
58
|
+
static constexpr std::size_t max_buffers = 16;
|
|
59
|
+
static constexpr std::size_t default_max_buffer_bytes = std::size_t{ 1024 } * 1024;
|
|
60
|
+
|
|
61
|
+
explicit mcbp_buffer_pool(std::size_t retained_buffers = max_buffers,
|
|
62
|
+
std::size_t max_buffer_bytes = default_max_buffer_bytes)
|
|
63
|
+
: retained_buffers_{ retained_buffers < max_buffers ? retained_buffers : max_buffers }
|
|
64
|
+
, max_buffer_bytes_{ max_buffer_bytes }
|
|
65
|
+
{
|
|
66
|
+
// No allocation here by design (see the class comment): the free list is a fixed-size array of
|
|
67
|
+
// empty buffers, so neither this constructor nor the lazy thread_local init it drives can
|
|
68
|
+
// throw.
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Hand out a recycled buffer (cleared, capacity retained) or an empty one if the pool is empty.
|
|
73
|
+
*/
|
|
74
|
+
auto acquire() -> buffer
|
|
75
|
+
{
|
|
76
|
+
if (count_ == 0) {
|
|
77
|
+
return {};
|
|
78
|
+
}
|
|
79
|
+
// Move the buffer out, leaving an empty slot (the moved-from vector holds no storage).
|
|
80
|
+
return std::move(free_[--count_]);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Return a buffer for reuse. Empty buffers (nothing to recycle) and buffers above the size cap
|
|
85
|
+
* are dropped, as is any buffer beyond the retained-count bound.
|
|
86
|
+
*/
|
|
87
|
+
void release(buffer&& buf) noexcept
|
|
88
|
+
{
|
|
89
|
+
if (buf.capacity() == 0 || buf.capacity() > max_buffer_bytes_ || count_ >= retained_buffers_) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
buf.clear();
|
|
93
|
+
// Slots at index >= count_ are always empty, so this move-assignment frees nothing and
|
|
94
|
+
// allocates nothing; release() therefore never touches the allocator, as its noexcept contract
|
|
95
|
+
// requires.
|
|
96
|
+
free_[count_++] = std::move(buf);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
[[nodiscard]] auto size() const -> std::size_t
|
|
100
|
+
{
|
|
101
|
+
return count_;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private:
|
|
105
|
+
std::array<buffer, max_buffers> free_{};
|
|
106
|
+
std::size_t count_{ 0 };
|
|
107
|
+
std::size_t retained_buffers_;
|
|
108
|
+
std::size_t max_buffer_bytes_;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* The calling thread's response-body buffer pool. Shared by every mcbp connection served on that IO
|
|
113
|
+
* thread; because it is thread-local, acquire and release are always confined to a single thread
|
|
114
|
+
* and need no locking (see mcbp_buffer_pool).
|
|
115
|
+
*/
|
|
116
|
+
inline auto
|
|
117
|
+
tls_response_body_pool() -> mcbp_buffer_pool&
|
|
118
|
+
{
|
|
119
|
+
static thread_local mcbp_buffer_pool pool;
|
|
120
|
+
return pool;
|
|
121
|
+
}
|
|
122
|
+
} // namespace couchbase::core::io
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
#pragma once
|
|
19
19
|
|
|
20
20
|
#include "core/app_telemetry_meter.hxx"
|
|
21
|
-
#include "core/
|
|
21
|
+
#include "core/document_id_redaction.hxx"
|
|
22
22
|
#include "core/error_context/key_value_error_map_info.hxx"
|
|
23
|
+
#include "core/logger/redaction.hxx"
|
|
23
24
|
#include "core/metrics/meter_wrapper.hxx"
|
|
24
25
|
#include "core/operations/operation_traits.hxx"
|
|
25
|
-
#include "core/platform/uuid.h"
|
|
26
26
|
#include "core/protocol/client_request.hxx"
|
|
27
27
|
#include "core/protocol/client_response.hxx"
|
|
28
28
|
#include "core/protocol/cmd_get_collection_id.hxx"
|
|
@@ -30,17 +30,23 @@
|
|
|
30
30
|
#include "core/utils/movable_function.hxx"
|
|
31
31
|
#include "couchbase/metrics/meter.hxx"
|
|
32
32
|
#include "couchbase/tracing/request_tracer.hxx"
|
|
33
|
+
#include "mcbp_command_id.hxx"
|
|
33
34
|
#include "mcbp_session.hxx"
|
|
34
35
|
#include "mcbp_traits.hxx"
|
|
35
36
|
#include "retry_orchestrator.hxx"
|
|
36
37
|
|
|
38
|
+
#include <couchbase/build_config.hxx>
|
|
37
39
|
#include <couchbase/durability_level.hxx>
|
|
38
40
|
#include <couchbase/error_codes.hxx>
|
|
39
41
|
|
|
42
|
+
#include <asio/dispatch.hpp>
|
|
43
|
+
#include <asio/io_context.hpp>
|
|
40
44
|
#include <asio/steady_timer.hpp>
|
|
45
|
+
#include <asio/strand.hpp>
|
|
41
46
|
#include <spdlog/fmt/bundled/chrono.h>
|
|
42
47
|
|
|
43
48
|
#include <functional>
|
|
49
|
+
#include <type_traits>
|
|
44
50
|
#include <utility>
|
|
45
51
|
|
|
46
52
|
namespace couchbase::core::operations
|
|
@@ -51,12 +57,22 @@ using mcbp_command_handler =
|
|
|
51
57
|
|
|
52
58
|
template<typename Manager, typename Request>
|
|
53
59
|
struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager, Request>> {
|
|
54
|
-
static constexpr std::chrono::milliseconds durability_timeout_floor{ 1'500 };
|
|
55
|
-
|
|
56
60
|
using encoded_request_type = typename Request::encoded_request_type;
|
|
57
61
|
using encoded_response_type = typename Request::encoded_response_type;
|
|
58
62
|
asio::steady_timer deadline;
|
|
59
63
|
asio::steady_timer retry_backoff;
|
|
64
|
+
// Only cancellable operations (replica fan-out) need a strand: their dispatch
|
|
65
|
+
// path can run on the caller thread while a sibling's completion cancels them
|
|
66
|
+
// from an IO thread, so all access to session_/opaque_/handler_ is confined to
|
|
67
|
+
// it. Non-cancellable operations get an empty placeholder instead, so they pay
|
|
68
|
+
// neither the strand_impl allocation nor any access on the hot path; the strand
|
|
69
|
+
// is referenced only inside `if constexpr (is_cancellable_operation_v<...>)`.
|
|
70
|
+
struct unused_strand {
|
|
71
|
+
};
|
|
72
|
+
using command_strand = std::conditional_t<is_cancellable_operation_v<Request>,
|
|
73
|
+
asio::strand<asio::io_context::executor_type>,
|
|
74
|
+
unused_strand>;
|
|
75
|
+
command_strand strand_;
|
|
60
76
|
Request request;
|
|
61
77
|
encoded_request_type encoded;
|
|
62
78
|
std::optional<std::uint32_t> opaque_{};
|
|
@@ -64,9 +80,8 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
|
|
|
64
80
|
mcbp_command_handler handler_{};
|
|
65
81
|
std::shared_ptr<Manager> manager_{};
|
|
66
82
|
std::chrono::milliseconds timeout_{};
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
uuid::to_string(uuid::random())) };
|
|
83
|
+
// Built lazily by id(); empty until first requested. See id().
|
|
84
|
+
mutable std::string id_{};
|
|
70
85
|
#ifdef COUCHBASE_CXX_CLIENT_CREATE_OPERATION_SPAN_IN_CORE
|
|
71
86
|
std::shared_ptr<couchbase::tracing::request_span> span_{ nullptr };
|
|
72
87
|
#endif
|
|
@@ -76,29 +91,48 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
|
|
|
76
91
|
std::chrono::time_point<std::chrono::steady_clock> started_at_{};
|
|
77
92
|
std::vector<std::chrono::microseconds> server_durations_{};
|
|
78
93
|
|
|
94
|
+
static auto make_command_strand(asio::io_context& ctx) -> command_strand
|
|
95
|
+
{
|
|
96
|
+
if constexpr (is_cancellable_operation_v<Request>) {
|
|
97
|
+
return command_strand{ ctx.get_executor() };
|
|
98
|
+
} else {
|
|
99
|
+
return command_strand{};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
79
103
|
mcbp_command(asio::io_context& ctx,
|
|
80
104
|
std::shared_ptr<Manager> manager,
|
|
81
105
|
Request req,
|
|
82
106
|
std::chrono::milliseconds default_timeout)
|
|
83
107
|
: deadline(ctx)
|
|
84
108
|
, retry_backoff(ctx)
|
|
109
|
+
, strand_(make_command_strand(ctx))
|
|
85
110
|
, request(req)
|
|
86
111
|
, manager_(manager)
|
|
87
112
|
, timeout_(request.timeout.value_or(default_timeout))
|
|
88
113
|
, parent_span_(request.parent_span)
|
|
89
114
|
{
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// The diagnostic identifier ("<opcode>/<uuid>") is used only in log lines,
|
|
118
|
+
// retry traces, and the returned key_value error context — never on the wire.
|
|
119
|
+
// Build it lazily on first use and cache it, so it is materialized at most once
|
|
120
|
+
// per command instead of eagerly in every constructor, and repeated readers -- a
|
|
121
|
+
// retry log line and then the completion's error context -- share the one cached
|
|
122
|
+
// value. The completion path builds the error context, so a completed operation
|
|
123
|
+
// still materializes it once; the laziness only avoids the cost for commands that
|
|
124
|
+
// never reach a point that needs it. The cache is logically const (it does not
|
|
125
|
+
// change the command's observable value), hence the mutable member and const
|
|
126
|
+
// accessor. Access while the command is in flight
|
|
127
|
+
// is serialized -- non-cancellable operations run on their session's single io
|
|
128
|
+
// thread, and cancellable (replica) operations confine access to the command
|
|
129
|
+
// strand (see strand_) -- so the one-time memoizing write needs no synchronization.
|
|
130
|
+
[[nodiscard]] auto id() const -> const std::string&
|
|
131
|
+
{
|
|
132
|
+
if (id_.empty()) {
|
|
133
|
+
id_ = make_command_id(encoded_request_type::body_type::opcode);
|
|
101
134
|
}
|
|
135
|
+
return id_;
|
|
102
136
|
}
|
|
103
137
|
|
|
104
138
|
void start(mcbp_command_handler&& handler)
|
|
@@ -133,6 +167,16 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
|
|
|
133
167
|
|
|
134
168
|
void cancel(retry_reason reason, bool is_timeout = true)
|
|
135
169
|
{
|
|
170
|
+
if constexpr (is_cancellable_operation_v<Request>) {
|
|
171
|
+
// Confine cancellation to the command strand so it cannot race the
|
|
172
|
+
// dispatch path (map_and_send/send_to/send) of a replica sibling that is
|
|
173
|
+
// still being set up on another thread.
|
|
174
|
+
if (!strand_.running_in_this_thread()) {
|
|
175
|
+
return asio::dispatch(strand_, [self = this->shared_from_this(), reason, is_timeout]() {
|
|
176
|
+
self->cancel(reason, is_timeout);
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
136
180
|
if (opaque_ && session_) {
|
|
137
181
|
if (session_->cancel(opaque_.value(), asio::error::operation_aborted, reason)) {
|
|
138
182
|
handler_ = nullptr;
|
|
@@ -149,6 +193,36 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
|
|
|
149
193
|
}
|
|
150
194
|
}
|
|
151
195
|
|
|
196
|
+
// Re-dispatch a session completion handler onto the command strand for
|
|
197
|
+
// cancellable operations, so the response/timeout path (which mcbp_session
|
|
198
|
+
// invokes on its own IO thread) cannot run concurrently with a strand-confined
|
|
199
|
+
// cancel(). A no-op passthrough for non-cancellable operations.
|
|
200
|
+
template<typename Handler>
|
|
201
|
+
auto on_strand(Handler&& handler)
|
|
202
|
+
{
|
|
203
|
+
if constexpr (is_cancellable_operation_v<Request>) {
|
|
204
|
+
return [self = this->shared_from_this(), handler = std::forward<Handler>(handler)](
|
|
205
|
+
std::error_code ec,
|
|
206
|
+
retry_reason reason,
|
|
207
|
+
io::mcbp_message&& msg,
|
|
208
|
+
std::optional<key_value_error_map_info> error_info) mutable {
|
|
209
|
+
if (self->strand_.running_in_this_thread()) {
|
|
210
|
+
return handler(ec, reason, std::move(msg), std::move(error_info));
|
|
211
|
+
}
|
|
212
|
+
asio::dispatch(self->strand_,
|
|
213
|
+
[handler = std::move(handler),
|
|
214
|
+
ec,
|
|
215
|
+
reason,
|
|
216
|
+
msg = std::move(msg),
|
|
217
|
+
error_info = std::move(error_info)]() mutable {
|
|
218
|
+
handler(ec, reason, std::move(msg), std::move(error_info));
|
|
219
|
+
});
|
|
220
|
+
};
|
|
221
|
+
} else {
|
|
222
|
+
return std::forward<Handler>(handler);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
152
226
|
void invoke_handler(std::error_code ec, std::optional<io::mcbp_message>&& msg = {})
|
|
153
227
|
{
|
|
154
228
|
retry_backoff.cancel();
|
|
@@ -162,18 +236,19 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
|
|
|
162
236
|
}
|
|
163
237
|
#endif
|
|
164
238
|
if (handler) {
|
|
165
|
-
const auto& node_uuid = session_ ? session_->node_uuid() : "";
|
|
166
239
|
auto telemetry_recorder =
|
|
167
|
-
|
|
240
|
+
session_
|
|
241
|
+
? session_->app_telemetry_recorder(*manager_->app_telemetry_meter(), manager_->name())
|
|
242
|
+
: manager_->app_telemetry_meter()->value_recorder("", manager_->name());
|
|
168
243
|
telemetry_recorder->update_counter(app_telemetry_counter::kv_r_total);
|
|
169
244
|
if (ec == errc::common::unambiguous_timeout || ec == errc::common::ambiguous_timeout) {
|
|
170
245
|
telemetry_recorder->update_counter(app_telemetry_counter::kv_r_timedout);
|
|
171
246
|
auto time_left = deadline.expiry() - std::chrono::steady_clock::now();
|
|
172
247
|
CB_LOG_TRACE(R"([{}] timeout operation id="{}", {}, key="{}", partition={}, time_left={})",
|
|
173
248
|
session_ ? session_->log_prefix() : manager_->log_prefix(),
|
|
174
|
-
|
|
249
|
+
id(),
|
|
175
250
|
encoded_request_type::body_type::opcode,
|
|
176
|
-
request.id,
|
|
251
|
+
logger::document(request.id),
|
|
177
252
|
request.partition,
|
|
178
253
|
time_left);
|
|
179
254
|
} else if (ec == errc::common::request_canceled) {
|
|
@@ -185,6 +260,15 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
|
|
|
185
260
|
|
|
186
261
|
void request_collection_id()
|
|
187
262
|
{
|
|
263
|
+
if constexpr (is_cancellable_operation_v<Request>) {
|
|
264
|
+
// Reached from the unknown-collection retry timer on an arbitrary IO
|
|
265
|
+
// thread; hop onto the strand before touching session_/opaque_.
|
|
266
|
+
if (!strand_.running_in_this_thread()) {
|
|
267
|
+
return asio::dispatch(strand_, [self = this->shared_from_this()]() {
|
|
268
|
+
self->request_collection_id();
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
188
272
|
if (session_->is_stopped()) {
|
|
189
273
|
return manager_->map_and_send(this->shared_from_this());
|
|
190
274
|
}
|
|
@@ -194,11 +278,11 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
|
|
|
194
278
|
session_->write_and_subscribe(
|
|
195
279
|
req.opaque(),
|
|
196
280
|
req.data(session_->supports_feature(protocol::hello_feature::snappy)),
|
|
197
|
-
[self = this->shared_from_this()](
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
281
|
+
on_strand([self = this->shared_from_this()](
|
|
282
|
+
std::error_code ec,
|
|
283
|
+
retry_reason /* reason */,
|
|
284
|
+
io::mcbp_message&& msg,
|
|
285
|
+
std::optional<key_value_error_map_info> /* error_info */) mutable {
|
|
202
286
|
if (ec == asio::error::operation_aborted) {
|
|
203
287
|
return self->invoke_handler(errc::common::ambiguous_timeout);
|
|
204
288
|
}
|
|
@@ -216,7 +300,7 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
|
|
|
216
300
|
resp.body().collection_uid());
|
|
217
301
|
self->request.id.collection_uid(resp.body().collection_uid());
|
|
218
302
|
return self->send();
|
|
219
|
-
});
|
|
303
|
+
}));
|
|
220
304
|
}
|
|
221
305
|
|
|
222
306
|
void handle_unknown_collection()
|
|
@@ -225,9 +309,9 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
|
|
|
225
309
|
auto time_left = deadline.expiry() - std::chrono::steady_clock::now();
|
|
226
310
|
CB_LOG_DEBUG(R"({} unknown collection response for "{}", time_left={}ms, id="{}")",
|
|
227
311
|
session_->log_prefix(),
|
|
228
|
-
request.id,
|
|
312
|
+
logger::document(request.id),
|
|
229
313
|
std::chrono::duration_cast<std::chrono::milliseconds>(time_left).count(),
|
|
230
|
-
|
|
314
|
+
id());
|
|
231
315
|
request.retries.add_reason(retry_reason::key_value_collection_outdated);
|
|
232
316
|
if (time_left < backoff) {
|
|
233
317
|
return invoke_handler(make_error_code(request.retries.idempotent()
|
|
@@ -256,9 +340,9 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
|
|
|
256
340
|
CB_LOG_DEBUG(
|
|
257
341
|
R"({} no cache entry for collection, resolve collection id for "{}", timeout={}ms, id="{}")",
|
|
258
342
|
session_->log_prefix(),
|
|
259
|
-
request.id,
|
|
343
|
+
logger::document(request.id),
|
|
260
344
|
timeout_.count(),
|
|
261
|
-
|
|
345
|
+
id());
|
|
262
346
|
return request_collection_id();
|
|
263
347
|
}
|
|
264
348
|
} else {
|
|
@@ -283,13 +367,13 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
|
|
|
283
367
|
session_->write_and_subscribe(
|
|
284
368
|
request.opaque,
|
|
285
369
|
encoded.data(session_->supports_feature(protocol::hello_feature::snappy)),
|
|
286
|
-
[self = this->shared_from_this(),
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
370
|
+
on_strand([self = this->shared_from_this(),
|
|
371
|
+
start = std::chrono::steady_clock::now(),
|
|
372
|
+
dispatch_span = std::move(dispatch_span)](
|
|
373
|
+
std::error_code ec,
|
|
374
|
+
retry_reason reason,
|
|
375
|
+
io::mcbp_message&& msg,
|
|
376
|
+
std::optional<key_value_error_map_info> /* error_info */) mutable {
|
|
293
377
|
{
|
|
294
378
|
const auto server_duration_us =
|
|
295
379
|
static_cast<std::uint64_t>(protocol::parse_server_duration_us(msg));
|
|
@@ -320,17 +404,17 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
|
|
|
320
404
|
break;
|
|
321
405
|
}
|
|
322
406
|
|
|
323
|
-
auto telemetry_recorder = self->
|
|
324
|
-
self->
|
|
407
|
+
auto telemetry_recorder = self->session_->app_telemetry_recorder(
|
|
408
|
+
*self->manager_->app_telemetry_meter(), self->manager_->name());
|
|
325
409
|
telemetry_recorder->record_latency(category, latency);
|
|
326
410
|
}
|
|
327
411
|
|
|
328
412
|
#ifdef COUCHBASE_CXX_CLIENT_CREATE_OPERATION_SPAN_IN_CORE
|
|
329
413
|
{
|
|
330
414
|
metrics::metric_attributes attrs{
|
|
331
|
-
|
|
415
|
+
tracing::service::key_value,
|
|
332
416
|
self->request.observability_identifier,
|
|
333
|
-
ec,
|
|
417
|
+
metrics::standardized_error_type(ec),
|
|
334
418
|
self->request.id.bucket(),
|
|
335
419
|
self->request.id.scope(),
|
|
336
420
|
self->request.id.collection(),
|
|
@@ -411,7 +495,7 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
|
|
|
411
495
|
} else {
|
|
412
496
|
io::retry_orchestrator::maybe_retry(self->manager_, self, reason, ec);
|
|
413
497
|
}
|
|
414
|
-
});
|
|
498
|
+
}));
|
|
415
499
|
}
|
|
416
500
|
|
|
417
501
|
void send_to(io::mcbp_session session)
|
|
@@ -464,9 +548,17 @@ private:
|
|
|
464
548
|
#endif
|
|
465
549
|
if (dispatch_span->uses_tags()) {
|
|
466
550
|
dispatch_span->add_tag(tracing::attributes::dispatch::network_transport, "tcp");
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
dispatch_span->
|
|
551
|
+
// Prefer the typed capability so the opaque is not formatted to a string on the hot path;
|
|
552
|
+
// spans that do not support it (external tracers) fall back to the string tag.
|
|
553
|
+
if (!dispatch_span->try_set_dispatch_operation_id(request.opaque)) {
|
|
554
|
+
dispatch_span->add_tag(tracing::attributes::dispatch::operation_id,
|
|
555
|
+
fmt::format("0x{:x}", request.opaque));
|
|
556
|
+
}
|
|
557
|
+
// Prefer the typed capability so the local id is not string-tagged on the hot path; external
|
|
558
|
+
// tracers fall back to the string tag.
|
|
559
|
+
if (!dispatch_span->try_set_dispatch_local_id(session_->id())) {
|
|
560
|
+
dispatch_span->add_tag(tracing::attributes::dispatch::local_id, session_->id());
|
|
561
|
+
}
|
|
470
562
|
}
|
|
471
563
|
return dispatch_span;
|
|
472
564
|
}
|
|
@@ -475,14 +567,21 @@ private:
|
|
|
475
567
|
const std::uint64_t server_duration_us) const
|
|
476
568
|
{
|
|
477
569
|
if (dispatch_span->uses_tags()) {
|
|
478
|
-
|
|
570
|
+
// Prefer the typed capability so the server duration and peer socket are not string-tagged on
|
|
571
|
+
// the hot path; external tracers fall back to the string tags.
|
|
572
|
+
if (!dispatch_span->try_set_dispatch_result(
|
|
573
|
+
server_duration_us, session_->remote_hostname(), session_->remote_port())) {
|
|
574
|
+
dispatch_span->add_tag(tracing::attributes::dispatch::server_duration, server_duration_us);
|
|
575
|
+
dispatch_span->add_tag(tracing::attributes::dispatch::peer_address,
|
|
576
|
+
session_->remote_hostname());
|
|
577
|
+
dispatch_span->add_tag(tracing::attributes::dispatch::peer_port, session_->remote_port());
|
|
578
|
+
}
|
|
579
|
+
// The built-in span does not keep the server (canonical) address; only external tracers
|
|
580
|
+
// consume these, and their SSO-sized tag names do not allocate.
|
|
479
581
|
dispatch_span->add_tag(tracing::attributes::dispatch::server_address,
|
|
480
582
|
session_->canonical_hostname());
|
|
481
583
|
dispatch_span->add_tag(tracing::attributes::dispatch::server_port,
|
|
482
584
|
session_->canonical_port_number());
|
|
483
|
-
dispatch_span->add_tag(tracing::attributes::dispatch::peer_address,
|
|
484
|
-
session_->remote_hostname());
|
|
485
|
-
dispatch_span->add_tag(tracing::attributes::dispatch::peer_port, session_->remote_port());
|
|
486
585
|
}
|
|
487
586
|
dispatch_span->end();
|
|
488
587
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2020-2021 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/platform/uuid.h"
|
|
21
|
+
#include "core/protocol/client_opcode.hxx"
|
|
22
|
+
|
|
23
|
+
#include <spdlog/fmt/bundled/core.h>
|
|
24
|
+
|
|
25
|
+
#include <cstdint>
|
|
26
|
+
#include <string>
|
|
27
|
+
|
|
28
|
+
namespace couchbase::core::operations
|
|
29
|
+
{
|
|
30
|
+
/**
|
|
31
|
+
* Build the diagnostic identifier for an mcbp command: the opcode rendered as
|
|
32
|
+
* two lowercase hex digits, a slash, and a random v4 UUID
|
|
33
|
+
* (e.g. "01/3f2a1c9e-...-...", 39 chars).
|
|
34
|
+
*
|
|
35
|
+
* This identifier never travels on the wire; it appears only in log lines,
|
|
36
|
+
* retry traces, and the returned key_value error context. mcbp_command
|
|
37
|
+
* therefore builds it lazily on first use rather than for every operation.
|
|
38
|
+
*/
|
|
39
|
+
inline auto
|
|
40
|
+
make_command_id(protocol::client_opcode opcode) -> std::string
|
|
41
|
+
{
|
|
42
|
+
return fmt::format(
|
|
43
|
+
"{:02x}/{}", static_cast<std::uint8_t>(opcode), uuid::to_string(uuid::random()));
|
|
44
|
+
}
|
|
45
|
+
} // namespace couchbase::core::operations
|
|
@@ -26,7 +26,15 @@ namespace couchbase::core::io
|
|
|
26
26
|
auto
|
|
27
27
|
binary_header::status() const -> std::uint16_t
|
|
28
28
|
{
|
|
29
|
-
return utils::
|
|
29
|
+
return utils::network_to_host(specific);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
auto
|
|
33
|
+
binary_header::alt_sizes() const -> binary_header::alt_frame_sizes
|
|
34
|
+
{
|
|
35
|
+
std::array<std::byte, sizeof(keylen)> bytes{};
|
|
36
|
+
std::memcpy(bytes.data(), &keylen, sizeof(keylen));
|
|
37
|
+
return { std::to_integer<std::uint8_t>(bytes[0]), std::to_integer<std::uint8_t>(bytes[1]) };
|
|
30
38
|
}
|
|
31
39
|
|
|
32
40
|
auto
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
#pragma once
|
|
19
19
|
|
|
20
20
|
#include <array>
|
|
21
|
+
#include <cstddef>
|
|
21
22
|
#include <cstdint>
|
|
22
23
|
#include <vector>
|
|
23
24
|
|
|
@@ -42,12 +43,30 @@ struct binary_header {
|
|
|
42
43
|
std::uint32_t opaque;
|
|
43
44
|
std::uint64_t cas;
|
|
44
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Sizes of the framing extras and key regions of a flexible-framing ("alt") frame.
|
|
48
|
+
*
|
|
49
|
+
* Bytes 2 and 3 of an alt frame header are two independent 1-byte fields, not one 16-bit
|
|
50
|
+
* value. Reinterpreting `keylen` as an integer and shifting the two halves apart puts each
|
|
51
|
+
* byte into the wrong variable on one host order or the other, so read them out as bytes.
|
|
52
|
+
*/
|
|
53
|
+
struct alt_frame_sizes {
|
|
54
|
+
std::uint8_t framing_extras;
|
|
55
|
+
std::uint8_t key;
|
|
56
|
+
};
|
|
57
|
+
|
|
45
58
|
[[nodiscard]] auto status() const -> std::uint16_t;
|
|
59
|
+
[[nodiscard]] auto alt_sizes() const -> alt_frame_sizes;
|
|
46
60
|
};
|
|
47
61
|
|
|
48
62
|
struct mcbp_message {
|
|
49
63
|
binary_header header{};
|
|
50
64
|
std::vector<std::byte> body{};
|
|
65
|
+
// Set on every frame read from the socket, so the buffer that ends up holding `body` can be
|
|
66
|
+
// recycled to the reading thread's pool when the decoded response is destroyed. False only for a
|
|
67
|
+
// message that never passed through the read loop (e.g. a default-constructed one), whose `body`
|
|
68
|
+
// is freed normally.
|
|
69
|
+
bool recycle_body{ false };
|
|
51
70
|
|
|
52
71
|
mcbp_message() = default;
|
|
53
72
|
mcbp_message(const mcbp_message& other) = delete;
|