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,2445 @@
|
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2026. Couchbase, Inc.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#include "core/protostellar/component.hxx"
|
|
19
|
+
|
|
20
|
+
#include "core/error_context/analytics.hxx"
|
|
21
|
+
#include "core/error_context/key_value.hxx"
|
|
22
|
+
#include "core/error_context/query.hxx"
|
|
23
|
+
#include "core/error_context/search.hxx"
|
|
24
|
+
#include "core/error_context/view.hxx"
|
|
25
|
+
#include "core/operations/analytics_response_parsing.hxx"
|
|
26
|
+
#include "core/operations/query_response_parsing.hxx"
|
|
27
|
+
#include "core/protostellar/analytics_converter.hxx"
|
|
28
|
+
#include "core/protostellar/bucket_admin_converter.hxx"
|
|
29
|
+
#include "core/protostellar/collection_admin_converter.hxx"
|
|
30
|
+
#include "core/protostellar/credentials.hxx"
|
|
31
|
+
#include "core/protostellar/error_utils.hxx"
|
|
32
|
+
#include "core/protostellar/kv_converter.hxx"
|
|
33
|
+
#include "core/protostellar/query_converter.hxx"
|
|
34
|
+
#include "core/protostellar/query_index_admin_converter.hxx"
|
|
35
|
+
#include "core/protostellar/search_converter.hxx"
|
|
36
|
+
#include "core/protostellar/search_index_admin_converter.hxx"
|
|
37
|
+
#include "core/protostellar/view_converter.hxx"
|
|
38
|
+
#include "core/utils/json_stream_control.hxx"
|
|
39
|
+
|
|
40
|
+
#include <couchbase/error_codes.hxx>
|
|
41
|
+
|
|
42
|
+
#include "core/protostellar/query_proto.hxx"
|
|
43
|
+
#include <couchbase/analytics/v1/analytics.grpc.pb.h>
|
|
44
|
+
|
|
45
|
+
#include <couchbase/admin/bucket/v1/bucket.grpc.pb.h>
|
|
46
|
+
#include <couchbase/admin/collection/v1/collection.grpc.pb.h>
|
|
47
|
+
#include <couchbase/admin/query/v1/query.grpc.pb.h>
|
|
48
|
+
#include <couchbase/admin/search/v1/search.grpc.pb.h>
|
|
49
|
+
#include <couchbase/kv/v1/kv.grpc.pb.h>
|
|
50
|
+
#include <couchbase/search/v1/search.grpc.pb.h>
|
|
51
|
+
#include <couchbase/view/v1/view.grpc.pb.h>
|
|
52
|
+
|
|
53
|
+
#include <asio/post.hpp>
|
|
54
|
+
|
|
55
|
+
#include <chrono>
|
|
56
|
+
#include <cstdint>
|
|
57
|
+
#include <limits>
|
|
58
|
+
#include <memory>
|
|
59
|
+
#include <string>
|
|
60
|
+
#include <system_error>
|
|
61
|
+
#include <utility>
|
|
62
|
+
#include <vector>
|
|
63
|
+
|
|
64
|
+
namespace couchbase::core::protostellar
|
|
65
|
+
{
|
|
66
|
+
namespace v1 = ::couchbase::kv::v1;
|
|
67
|
+
namespace query_v1 = ::couchbase::query::v1;
|
|
68
|
+
namespace analytics_v1 = ::couchbase::analytics::v1;
|
|
69
|
+
namespace search_v1 = ::couchbase::search::v1;
|
|
70
|
+
namespace view_v1 = ::couchbase::view::v1;
|
|
71
|
+
namespace bucket_admin_v1 = ::couchbase::admin::bucket::v1;
|
|
72
|
+
namespace collection_admin_v1 = ::couchbase::admin::collection::v1;
|
|
73
|
+
namespace query_admin_v1 = ::couchbase::admin::query::v1;
|
|
74
|
+
namespace search_admin_v1 = ::couchbase::admin::search::v1;
|
|
75
|
+
|
|
76
|
+
// Defined here rather than in the header so the generated gRPC types stay out of every consumer of
|
|
77
|
+
// component.hxx.
|
|
78
|
+
struct component::stubs {
|
|
79
|
+
std::unique_ptr<v1::KvService::Stub> kv;
|
|
80
|
+
std::unique_ptr<query_v1::QueryService::Stub> query;
|
|
81
|
+
std::unique_ptr<analytics_v1::AnalyticsService::Stub> analytics;
|
|
82
|
+
std::unique_ptr<search_v1::SearchService::Stub> search;
|
|
83
|
+
std::unique_ptr<view_v1::ViewService::Stub> view;
|
|
84
|
+
std::unique_ptr<bucket_admin_v1::BucketAdminService::Stub> bucket_admin;
|
|
85
|
+
std::unique_ptr<collection_admin_v1::CollectionAdminService::Stub> collection_admin;
|
|
86
|
+
std::unique_ptr<query_admin_v1::QueryAdminService::Stub> query_admin;
|
|
87
|
+
std::unique_ptr<search_admin_v1::SearchAdminService::Stub> search_admin;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
namespace
|
|
91
|
+
{
|
|
92
|
+
// A request whose time budget is already spent must not be dispatched. dispatcher::unary only sets
|
|
93
|
+
// a deadline when the timeout is positive, so handing it a non-positive one produces a call with no
|
|
94
|
+
// deadline at all -- an RPC that runs until the channel breaks, and that cluster::close() then
|
|
95
|
+
// blocks on. Turning "no time left" into "no limit" is the wrong direction for the mistake to go.
|
|
96
|
+
//
|
|
97
|
+
// This attempt sends nothing, but that does not make the operation unsent: the retry loop reaches
|
|
98
|
+
// here to end an operation whose earlier attempts were dispatched. The ambiguity ambiguous_timeout
|
|
99
|
+
// warns about is whether the server applied a write, so it is decided by whether anything was ever
|
|
100
|
+
// sent, not by whether this attempt was -- the same rule the MCBP path applies in
|
|
101
|
+
// mcbp_command::cancel(). An idempotent operation is safe to replay either way, and a first attempt
|
|
102
|
+
// (no retries recorded) provably reached nobody.
|
|
103
|
+
template<typename Request, typename Handler>
|
|
104
|
+
auto
|
|
105
|
+
fail_expired(asio::io_context& io, const Request& request, Handler& handler) -> pending_call
|
|
106
|
+
{
|
|
107
|
+
const auto ec =
|
|
108
|
+
(request.retries.idempotent() || request.retries.retry_attempts() == 0)
|
|
109
|
+
? errc::common::unambiguous_timeout // safe to retry, or never sent to the server
|
|
110
|
+
: errc::common::ambiguous_timeout; // non-idempotent and dispatched at least once
|
|
111
|
+
auto response = request.make_response(
|
|
112
|
+
make_key_value_error_context(
|
|
113
|
+
ec, request.id, request.retries.retry_attempts(), request.retries.retry_reasons()),
|
|
114
|
+
typename Request::encoded_response_type{});
|
|
115
|
+
// Delivered through the io_context, not inline on the caller's thread: "completions arrive on the
|
|
116
|
+
// SDK's execution context" is the contract every other path here honours, and a synchronous
|
|
117
|
+
// callback out of execute() would also re-enter the caller before it has its pending_call back.
|
|
118
|
+
asio::post(io, [handler = std::move(handler), response = std::move(response)]() mutable {
|
|
119
|
+
handler(std::move(response));
|
|
120
|
+
});
|
|
121
|
+
return {};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Shared state for a streaming query/analytics/search/view response consumed row by row
|
|
125
|
+
// (CXXCBC-910). `callback` is empty for the buffered path. `received_any` drives the CXXCBC-909
|
|
126
|
+
// rule: once the gateway has sent anything the statement has begun executing, so a later error must
|
|
127
|
+
// fail as request_canceled and never retry. It latches on arrival rather than on delivery to a
|
|
128
|
+
// consumer, because a buffered request (no row_callback) is just as unsafe to replay -- a
|
|
129
|
+
// `DELETE FROM ... WHERE ...` whose connection drops after the first result message would otherwise
|
|
130
|
+
// map to a retryable error and apply the mutation twice. `stopped` latches when the consumer
|
|
131
|
+
// returns stream_control::stop -- we keep reading to capture the terminal metadata (matching the
|
|
132
|
+
// HTTP row_callback contract) but stop invoking it.
|
|
133
|
+
struct row_stream_state {
|
|
134
|
+
std::function<utils::json::stream_control(std::string)> callback{};
|
|
135
|
+
bool stopped{ false };
|
|
136
|
+
bool received_any{ false };
|
|
137
|
+
|
|
138
|
+
// Feeds one row to the consumer. Returns true when the caller should buffer the row instead
|
|
139
|
+
// (no row_callback wired); in that case `row` is left untouched.
|
|
140
|
+
auto consume(std::string&& row) -> bool
|
|
141
|
+
{
|
|
142
|
+
received_any = true;
|
|
143
|
+
if (!callback) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
if (!stopped) {
|
|
147
|
+
if (callback(std::move(row)) == utils::json::stream_control::stop) {
|
|
148
|
+
stopped = true;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// Deliver a prepared response carrying ec without sending anything. Posted rather than invoked:
|
|
156
|
+
// completions arrive on the io context, never inline out of execute(), which would re-enter the
|
|
157
|
+
// caller before it holds its pending_call.
|
|
158
|
+
template<typename Response, typename Handler>
|
|
159
|
+
auto
|
|
160
|
+
fail_ctx(asio::io_context& io, Handler& handler, Response response, std::error_code ec)
|
|
161
|
+
-> pending_call
|
|
162
|
+
{
|
|
163
|
+
response.ctx.ec = ec;
|
|
164
|
+
asio::post(io, [handler = std::move(handler), response = std::move(response)]() mutable {
|
|
165
|
+
handler(std::move(response));
|
|
166
|
+
});
|
|
167
|
+
return {};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// The same rule for the services whose responses carry their own error context rather than a
|
|
171
|
+
// key_value one: they resolve a timeout exactly as the KV overloads do, so a non-positive one
|
|
172
|
+
// would reach the dispatcher and produce a call with no deadline there too. The response the
|
|
173
|
+
// overload would have built is stamped and delivered without anything being sent.
|
|
174
|
+
template<typename Response, typename Handler>
|
|
175
|
+
auto
|
|
176
|
+
fail_expired_ctx(asio::io_context& io, Handler& handler, Response response) -> pending_call
|
|
177
|
+
{
|
|
178
|
+
return fail_ctx(io, handler, std::move(response), errc::common::unambiguous_timeout);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// A management response carrying the caller's client_context_id, which is what correlates it with
|
|
182
|
+
// the request that produced it when several are in flight. The http error context has the field and
|
|
183
|
+
// the classic path fills it, so leaving it empty here would lose the identifier on the couchbase2
|
|
184
|
+
// path alone -- most visibly on the paths that send nothing, where there is no server response to
|
|
185
|
+
// correlate by either.
|
|
186
|
+
//
|
|
187
|
+
// Only what the caller supplied is echoed. The classic path substitutes a generated uuid for an
|
|
188
|
+
// absent one because it travels with the HTTP request and comes back in the server's own logs;
|
|
189
|
+
// couchbase2 sends no such field, so an id the caller never chose would identify nothing.
|
|
190
|
+
template<typename Request>
|
|
191
|
+
[[nodiscard]] auto
|
|
192
|
+
stamped_management(const Request& request) -> typename Request::response_type
|
|
193
|
+
{
|
|
194
|
+
typename Request::response_type response;
|
|
195
|
+
response.ctx.client_context_id = request.client_context_id.value_or(std::string{});
|
|
196
|
+
return response;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// FTS answers each of the search index management endpoints with {"status":"ok"} on success, and
|
|
200
|
+
// the classic path copies that string into the response, where core-API consumers read it.
|
|
201
|
+
// admin.search.v1 replies with empty messages, so a successful RPC is the same signal and carries
|
|
202
|
+
// the same meaning. A failed one leaves the field empty rather than inventing a status the server
|
|
203
|
+
// never reported; the error code is what describes it.
|
|
204
|
+
template<typename Response>
|
|
205
|
+
void
|
|
206
|
+
set_ok_status(Response& response)
|
|
207
|
+
{
|
|
208
|
+
if (!response.ctx.ec) {
|
|
209
|
+
response.status = "ok";
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} // namespace
|
|
213
|
+
|
|
214
|
+
component::component(asio::io_context& io, component_config config)
|
|
215
|
+
: io_{ io }
|
|
216
|
+
, stubs_{ std::make_unique<stubs>(
|
|
217
|
+
stubs{ v1::KvService::NewStub(config.channel),
|
|
218
|
+
query_v1::QueryService::NewStub(config.channel),
|
|
219
|
+
analytics_v1::AnalyticsService::NewStub(config.channel),
|
|
220
|
+
search_v1::SearchService::NewStub(config.channel),
|
|
221
|
+
view_v1::ViewService::NewStub(config.channel),
|
|
222
|
+
bucket_admin_v1::BucketAdminService::NewStub(config.channel),
|
|
223
|
+
collection_admin_v1::CollectionAdminService::NewStub(config.channel),
|
|
224
|
+
query_admin_v1::QueryAdminService::NewStub(config.channel),
|
|
225
|
+
search_admin_v1::SearchAdminService::NewStub(config.channel) }) }
|
|
226
|
+
, authorization_{ authorization_header(config.credentials) }
|
|
227
|
+
, timeouts_{ config.timeouts }
|
|
228
|
+
, compression_{ config.compression }
|
|
229
|
+
// Initialised last (see the declaration order in the header), so the channel can be moved in.
|
|
230
|
+
, dispatcher_{ io, std::move(config.channel) }
|
|
231
|
+
{
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
component::~component() = default;
|
|
235
|
+
|
|
236
|
+
auto
|
|
237
|
+
component::channel() const -> const std::shared_ptr<grpc::Channel>&
|
|
238
|
+
{
|
|
239
|
+
return dispatcher_.channel();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
auto
|
|
243
|
+
component::execute(const operations::get_request& request,
|
|
244
|
+
utils::movable_function<void(operations::get_response)>&& handler)
|
|
245
|
+
-> pending_call
|
|
246
|
+
{
|
|
247
|
+
const auto timeout = request.timeout.value_or(timeouts_.key_value);
|
|
248
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
249
|
+
return fail_expired(io_, request, handler);
|
|
250
|
+
}
|
|
251
|
+
auto proto = std::make_shared<v1::GetRequest>(kv::encode(request, compression_));
|
|
252
|
+
const auto id = request.id;
|
|
253
|
+
const auto retry_attempts = request.retries.retry_attempts();
|
|
254
|
+
const auto retry_reasons = request.retries.retry_reasons();
|
|
255
|
+
const auto auth = authorization_;
|
|
256
|
+
auto* stub = stubs_->kv.get();
|
|
257
|
+
return dispatcher_.unary<v1::GetResponse>(
|
|
258
|
+
timeout,
|
|
259
|
+
[stub, proto, auth](
|
|
260
|
+
grpc::ClientContext& ctx, v1::GetResponse& resp, std::function<void(grpc::Status)> cb) {
|
|
261
|
+
if (!auth.empty()) {
|
|
262
|
+
ctx.AddMetadata("authorization", auth);
|
|
263
|
+
}
|
|
264
|
+
stub->async()->Get(&ctx, proto.get(), &resp, std::move(cb));
|
|
265
|
+
},
|
|
266
|
+
// `proto` is captured here too so the request outlives the in-flight call.
|
|
267
|
+
[handler = std::move(handler), id, proto, retry_attempts, retry_reasons](
|
|
268
|
+
grpc::Status status, v1::GetResponse resp) mutable {
|
|
269
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
270
|
+
// A get reads and nothing more, so a deadline here is unambiguous: the document cannot have
|
|
271
|
+
// changed. kv::decode owns the compressed-content rule (it reports the decode failure rather
|
|
272
|
+
// than handing back an empty value with a success status).
|
|
273
|
+
auto ctx =
|
|
274
|
+
make_error_context(status, id, operation_kind::read_only, retry_attempts, retry_reasons);
|
|
275
|
+
handler(kv::decode(resp, std::move(ctx)));
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
auto
|
|
280
|
+
component::execute(const operations::get_projected_request& request,
|
|
281
|
+
utils::movable_function<void(operations::get_projected_response)>&& handler)
|
|
282
|
+
-> pending_call
|
|
283
|
+
{
|
|
284
|
+
auto proto = std::make_shared<v1::GetRequest>(kv::encode(request, compression_));
|
|
285
|
+
const auto id = request.id;
|
|
286
|
+
const auto retry_attempts = request.retries.retry_attempts();
|
|
287
|
+
const auto retry_reasons = request.retries.retry_reasons();
|
|
288
|
+
const auto timeout = request.timeout.value_or(timeouts_.key_value);
|
|
289
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
290
|
+
return fail_expired(io_, request, handler);
|
|
291
|
+
}
|
|
292
|
+
const auto auth = authorization_;
|
|
293
|
+
auto* stub = stubs_->kv.get();
|
|
294
|
+
return dispatcher_.unary<v1::GetResponse>(
|
|
295
|
+
timeout,
|
|
296
|
+
[stub, proto, auth](
|
|
297
|
+
grpc::ClientContext& ctx, v1::GetResponse& resp, std::function<void(grpc::Status)> cb) {
|
|
298
|
+
if (!auth.empty()) {
|
|
299
|
+
ctx.AddMetadata("authorization", auth);
|
|
300
|
+
}
|
|
301
|
+
stub->async()->Get(&ctx, proto.get(), &resp, std::move(cb));
|
|
302
|
+
},
|
|
303
|
+
[handler = std::move(handler), id, proto, request, retry_attempts, retry_reasons](
|
|
304
|
+
grpc::Status status, v1::GetResponse resp) mutable {
|
|
305
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
306
|
+
auto ctx =
|
|
307
|
+
make_error_context(status, id, operation_kind::read_only, retry_attempts, retry_reasons);
|
|
308
|
+
handler(kv::decode(resp, std::move(ctx), request));
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
auto
|
|
313
|
+
component::execute(const operations::upsert_request& request,
|
|
314
|
+
utils::movable_function<void(operations::upsert_response)>&& handler)
|
|
315
|
+
-> pending_call
|
|
316
|
+
{
|
|
317
|
+
const auto timeout = resolve_kv_timeout(request.timeout, request.durability_level, timeouts_);
|
|
318
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
319
|
+
return fail_expired(io_, request, handler);
|
|
320
|
+
}
|
|
321
|
+
auto proto = std::make_shared<v1::UpsertRequest>(kv::encode(request, compression_));
|
|
322
|
+
const auto id = request.id;
|
|
323
|
+
const auto retry_attempts = request.retries.retry_attempts();
|
|
324
|
+
const auto retry_reasons = request.retries.retry_reasons();
|
|
325
|
+
const auto auth = authorization_;
|
|
326
|
+
auto* stub = stubs_->kv.get();
|
|
327
|
+
return dispatcher_.unary<v1::UpsertResponse>(
|
|
328
|
+
timeout,
|
|
329
|
+
[stub, proto, auth](
|
|
330
|
+
grpc::ClientContext& ctx, v1::UpsertResponse& resp, std::function<void(grpc::Status)> cb) {
|
|
331
|
+
if (!auth.empty()) {
|
|
332
|
+
ctx.AddMetadata("authorization", auth);
|
|
333
|
+
}
|
|
334
|
+
stub->async()->Upsert(&ctx, proto.get(), &resp, std::move(cb));
|
|
335
|
+
},
|
|
336
|
+
[handler = std::move(handler), id, proto, retry_attempts, retry_reasons](
|
|
337
|
+
grpc::Status status, v1::UpsertResponse resp) mutable {
|
|
338
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
339
|
+
auto ctx =
|
|
340
|
+
make_error_context(status, id, operation_kind::mutating, retry_attempts, retry_reasons);
|
|
341
|
+
handler(kv::decode(resp, std::move(ctx)));
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
auto
|
|
346
|
+
component::execute(const operations::insert_request& request,
|
|
347
|
+
utils::movable_function<void(operations::insert_response)>&& handler)
|
|
348
|
+
-> pending_call
|
|
349
|
+
{
|
|
350
|
+
const auto timeout = resolve_kv_timeout(request.timeout, request.durability_level, timeouts_);
|
|
351
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
352
|
+
return fail_expired(io_, request, handler);
|
|
353
|
+
}
|
|
354
|
+
auto proto = std::make_shared<v1::InsertRequest>(kv::encode(request, compression_));
|
|
355
|
+
const auto id = request.id;
|
|
356
|
+
const auto retry_attempts = request.retries.retry_attempts();
|
|
357
|
+
const auto retry_reasons = request.retries.retry_reasons();
|
|
358
|
+
const auto auth = authorization_;
|
|
359
|
+
auto* stub = stubs_->kv.get();
|
|
360
|
+
return dispatcher_.unary<v1::InsertResponse>(
|
|
361
|
+
timeout,
|
|
362
|
+
[stub, proto, auth](
|
|
363
|
+
grpc::ClientContext& ctx, v1::InsertResponse& resp, std::function<void(grpc::Status)> cb) {
|
|
364
|
+
if (!auth.empty()) {
|
|
365
|
+
ctx.AddMetadata("authorization", auth);
|
|
366
|
+
}
|
|
367
|
+
stub->async()->Insert(&ctx, proto.get(), &resp, std::move(cb));
|
|
368
|
+
},
|
|
369
|
+
[handler = std::move(handler), id, proto, retry_attempts, retry_reasons](
|
|
370
|
+
grpc::Status status, v1::InsertResponse resp) mutable {
|
|
371
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
372
|
+
auto ctx =
|
|
373
|
+
make_error_context(status, id, operation_kind::mutating, retry_attempts, retry_reasons);
|
|
374
|
+
handler(kv::decode(resp, std::move(ctx)));
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
auto
|
|
379
|
+
component::execute(const operations::replace_request& request,
|
|
380
|
+
utils::movable_function<void(operations::replace_response)>&& handler)
|
|
381
|
+
-> pending_call
|
|
382
|
+
{
|
|
383
|
+
const auto timeout = resolve_kv_timeout(request.timeout, request.durability_level, timeouts_);
|
|
384
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
385
|
+
return fail_expired(io_, request, handler);
|
|
386
|
+
}
|
|
387
|
+
auto proto = std::make_shared<v1::ReplaceRequest>(kv::encode(request, compression_));
|
|
388
|
+
const auto id = request.id;
|
|
389
|
+
const auto retry_attempts = request.retries.retry_attempts();
|
|
390
|
+
const auto retry_reasons = request.retries.retry_reasons();
|
|
391
|
+
const auto auth = authorization_;
|
|
392
|
+
auto* stub = stubs_->kv.get();
|
|
393
|
+
return dispatcher_.unary<v1::ReplaceResponse>(
|
|
394
|
+
timeout,
|
|
395
|
+
[stub, proto, auth](
|
|
396
|
+
grpc::ClientContext& ctx, v1::ReplaceResponse& resp, std::function<void(grpc::Status)> cb) {
|
|
397
|
+
if (!auth.empty()) {
|
|
398
|
+
ctx.AddMetadata("authorization", auth);
|
|
399
|
+
}
|
|
400
|
+
stub->async()->Replace(&ctx, proto.get(), &resp, std::move(cb));
|
|
401
|
+
},
|
|
402
|
+
[handler = std::move(handler), id, proto, retry_attempts, retry_reasons](
|
|
403
|
+
grpc::Status status, v1::ReplaceResponse resp) mutable {
|
|
404
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
405
|
+
auto ctx =
|
|
406
|
+
make_error_context(status, id, operation_kind::mutating, retry_attempts, retry_reasons);
|
|
407
|
+
handler(kv::decode(resp, std::move(ctx)));
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
auto
|
|
412
|
+
component::execute(const operations::remove_request& request,
|
|
413
|
+
utils::movable_function<void(operations::remove_response)>&& handler)
|
|
414
|
+
-> pending_call
|
|
415
|
+
{
|
|
416
|
+
const auto timeout = resolve_kv_timeout(request.timeout, request.durability_level, timeouts_);
|
|
417
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
418
|
+
return fail_expired(io_, request, handler);
|
|
419
|
+
}
|
|
420
|
+
auto proto = std::make_shared<v1::RemoveRequest>(kv::encode(request));
|
|
421
|
+
const auto id = request.id;
|
|
422
|
+
const auto retry_attempts = request.retries.retry_attempts();
|
|
423
|
+
const auto retry_reasons = request.retries.retry_reasons();
|
|
424
|
+
const auto auth = authorization_;
|
|
425
|
+
auto* stub = stubs_->kv.get();
|
|
426
|
+
return dispatcher_.unary<v1::RemoveResponse>(
|
|
427
|
+
timeout,
|
|
428
|
+
[stub, proto, auth](
|
|
429
|
+
grpc::ClientContext& ctx, v1::RemoveResponse& resp, std::function<void(grpc::Status)> cb) {
|
|
430
|
+
if (!auth.empty()) {
|
|
431
|
+
ctx.AddMetadata("authorization", auth);
|
|
432
|
+
}
|
|
433
|
+
stub->async()->Remove(&ctx, proto.get(), &resp, std::move(cb));
|
|
434
|
+
},
|
|
435
|
+
[handler = std::move(handler), id, proto, retry_attempts, retry_reasons](
|
|
436
|
+
grpc::Status status, v1::RemoveResponse resp) mutable {
|
|
437
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
438
|
+
auto ctx =
|
|
439
|
+
make_error_context(status, id, operation_kind::mutating, retry_attempts, retry_reasons);
|
|
440
|
+
handler(kv::decode(resp, std::move(ctx)));
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
auto
|
|
445
|
+
component::execute(const operations::touch_request& request,
|
|
446
|
+
utils::movable_function<void(operations::touch_response)>&& handler)
|
|
447
|
+
-> pending_call
|
|
448
|
+
{
|
|
449
|
+
auto proto = std::make_shared<v1::TouchRequest>(kv::encode(request));
|
|
450
|
+
const auto id = request.id;
|
|
451
|
+
const auto retry_attempts = request.retries.retry_attempts();
|
|
452
|
+
const auto retry_reasons = request.retries.retry_reasons();
|
|
453
|
+
const auto timeout = request.timeout.value_or(timeouts_.key_value);
|
|
454
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
455
|
+
return fail_expired(io_, request, handler);
|
|
456
|
+
}
|
|
457
|
+
const auto auth = authorization_;
|
|
458
|
+
auto* stub = stubs_->kv.get();
|
|
459
|
+
return dispatcher_.unary<v1::TouchResponse>(
|
|
460
|
+
timeout,
|
|
461
|
+
[stub, proto, auth](
|
|
462
|
+
grpc::ClientContext& ctx, v1::TouchResponse& resp, std::function<void(grpc::Status)> cb) {
|
|
463
|
+
if (!auth.empty()) {
|
|
464
|
+
ctx.AddMetadata("authorization", auth);
|
|
465
|
+
}
|
|
466
|
+
stub->async()->Touch(&ctx, proto.get(), &resp, std::move(cb));
|
|
467
|
+
},
|
|
468
|
+
[handler = std::move(handler), id, proto, retry_attempts, retry_reasons](
|
|
469
|
+
grpc::Status status, v1::TouchResponse resp) mutable {
|
|
470
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
471
|
+
auto ctx =
|
|
472
|
+
make_error_context(status, id, operation_kind::mutating, retry_attempts, retry_reasons);
|
|
473
|
+
handler(kv::decode(resp, std::move(ctx)));
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
auto
|
|
478
|
+
component::execute(const operations::exists_request& request,
|
|
479
|
+
utils::movable_function<void(operations::exists_response)>&& handler)
|
|
480
|
+
-> pending_call
|
|
481
|
+
{
|
|
482
|
+
auto proto = std::make_shared<v1::ExistsRequest>(kv::encode(request));
|
|
483
|
+
const auto id = request.id;
|
|
484
|
+
const auto retry_attempts = request.retries.retry_attempts();
|
|
485
|
+
const auto retry_reasons = request.retries.retry_reasons();
|
|
486
|
+
const auto timeout = request.timeout.value_or(timeouts_.key_value);
|
|
487
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
488
|
+
return fail_expired(io_, request, handler);
|
|
489
|
+
}
|
|
490
|
+
const auto auth = authorization_;
|
|
491
|
+
auto* stub = stubs_->kv.get();
|
|
492
|
+
return dispatcher_.unary<v1::ExistsResponse>(
|
|
493
|
+
timeout,
|
|
494
|
+
[stub, proto, auth](
|
|
495
|
+
grpc::ClientContext& ctx, v1::ExistsResponse& resp, std::function<void(grpc::Status)> cb) {
|
|
496
|
+
if (!auth.empty()) {
|
|
497
|
+
ctx.AddMetadata("authorization", auth);
|
|
498
|
+
}
|
|
499
|
+
stub->async()->Exists(&ctx, proto.get(), &resp, std::move(cb));
|
|
500
|
+
},
|
|
501
|
+
[handler = std::move(handler), id, proto, retry_attempts, retry_reasons](
|
|
502
|
+
grpc::Status status, v1::ExistsResponse resp) mutable {
|
|
503
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
504
|
+
auto ctx =
|
|
505
|
+
make_error_context(status, id, operation_kind::read_only, retry_attempts, retry_reasons);
|
|
506
|
+
handler(kv::decode(resp, std::move(ctx)));
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
auto
|
|
511
|
+
component::execute(const operations::get_and_lock_request& request,
|
|
512
|
+
utils::movable_function<void(operations::get_and_lock_response)>&& handler)
|
|
513
|
+
-> pending_call
|
|
514
|
+
{
|
|
515
|
+
auto proto = std::make_shared<v1::GetAndLockRequest>(kv::encode(request, compression_));
|
|
516
|
+
const auto id = request.id;
|
|
517
|
+
const auto retry_attempts = request.retries.retry_attempts();
|
|
518
|
+
const auto retry_reasons = request.retries.retry_reasons();
|
|
519
|
+
const auto timeout = request.timeout.value_or(timeouts_.key_value);
|
|
520
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
521
|
+
return fail_expired(io_, request, handler);
|
|
522
|
+
}
|
|
523
|
+
const auto auth = authorization_;
|
|
524
|
+
auto* stub = stubs_->kv.get();
|
|
525
|
+
return dispatcher_.unary<v1::GetAndLockResponse>(
|
|
526
|
+
timeout,
|
|
527
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
528
|
+
v1::GetAndLockResponse& resp,
|
|
529
|
+
std::function<void(grpc::Status)> cb) {
|
|
530
|
+
if (!auth.empty()) {
|
|
531
|
+
ctx.AddMetadata("authorization", auth);
|
|
532
|
+
}
|
|
533
|
+
stub->async()->GetAndLock(&ctx, proto.get(), &resp, std::move(cb));
|
|
534
|
+
},
|
|
535
|
+
[handler = std::move(handler), id, proto, retry_attempts, retry_reasons](
|
|
536
|
+
grpc::Status status, v1::GetAndLockResponse resp) mutable {
|
|
537
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
538
|
+
auto ctx =
|
|
539
|
+
make_error_context(status, id, operation_kind::mutating, retry_attempts, retry_reasons);
|
|
540
|
+
handler(kv::decode(resp, std::move(ctx)));
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
auto
|
|
545
|
+
component::execute(const operations::unlock_request& request,
|
|
546
|
+
utils::movable_function<void(operations::unlock_response)>&& handler)
|
|
547
|
+
-> pending_call
|
|
548
|
+
{
|
|
549
|
+
auto proto = std::make_shared<v1::UnlockRequest>(kv::encode(request));
|
|
550
|
+
const auto id = request.id;
|
|
551
|
+
const auto retry_attempts = request.retries.retry_attempts();
|
|
552
|
+
const auto retry_reasons = request.retries.retry_reasons();
|
|
553
|
+
const auto timeout = request.timeout.value_or(timeouts_.key_value);
|
|
554
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
555
|
+
return fail_expired(io_, request, handler);
|
|
556
|
+
}
|
|
557
|
+
const auto auth = authorization_;
|
|
558
|
+
auto* stub = stubs_->kv.get();
|
|
559
|
+
return dispatcher_.unary<v1::UnlockResponse>(
|
|
560
|
+
timeout,
|
|
561
|
+
[stub, proto, auth](
|
|
562
|
+
grpc::ClientContext& ctx, v1::UnlockResponse& resp, std::function<void(grpc::Status)> cb) {
|
|
563
|
+
if (!auth.empty()) {
|
|
564
|
+
ctx.AddMetadata("authorization", auth);
|
|
565
|
+
}
|
|
566
|
+
stub->async()->Unlock(&ctx, proto.get(), &resp, std::move(cb));
|
|
567
|
+
},
|
|
568
|
+
[handler = std::move(handler), id, proto, retry_attempts, retry_reasons](
|
|
569
|
+
grpc::Status status, v1::UnlockResponse resp) mutable {
|
|
570
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
571
|
+
auto ctx =
|
|
572
|
+
make_error_context(status, id, operation_kind::mutating, retry_attempts, retry_reasons);
|
|
573
|
+
handler(kv::decode(resp, std::move(ctx)));
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
auto
|
|
578
|
+
component::execute(const operations::get_and_touch_request& request,
|
|
579
|
+
utils::movable_function<void(operations::get_and_touch_response)>&& handler)
|
|
580
|
+
-> pending_call
|
|
581
|
+
{
|
|
582
|
+
auto proto = std::make_shared<v1::GetAndTouchRequest>(kv::encode(request, compression_));
|
|
583
|
+
const auto id = request.id;
|
|
584
|
+
const auto retry_attempts = request.retries.retry_attempts();
|
|
585
|
+
const auto retry_reasons = request.retries.retry_reasons();
|
|
586
|
+
const auto timeout = request.timeout.value_or(timeouts_.key_value);
|
|
587
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
588
|
+
return fail_expired(io_, request, handler);
|
|
589
|
+
}
|
|
590
|
+
const auto auth = authorization_;
|
|
591
|
+
auto* stub = stubs_->kv.get();
|
|
592
|
+
return dispatcher_.unary<v1::GetAndTouchResponse>(
|
|
593
|
+
timeout,
|
|
594
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
595
|
+
v1::GetAndTouchResponse& resp,
|
|
596
|
+
std::function<void(grpc::Status)> cb) {
|
|
597
|
+
if (!auth.empty()) {
|
|
598
|
+
ctx.AddMetadata("authorization", auth);
|
|
599
|
+
}
|
|
600
|
+
stub->async()->GetAndTouch(&ctx, proto.get(), &resp, std::move(cb));
|
|
601
|
+
},
|
|
602
|
+
[handler = std::move(handler), id, proto, retry_attempts, retry_reasons](
|
|
603
|
+
grpc::Status status, v1::GetAndTouchResponse resp) mutable {
|
|
604
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
605
|
+
auto ctx =
|
|
606
|
+
make_error_context(status, id, operation_kind::mutating, retry_attempts, retry_reasons);
|
|
607
|
+
handler(kv::decode(resp, std::move(ctx)));
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
namespace
|
|
612
|
+
{
|
|
613
|
+
// initial_value is uint64 while the proto's `initial` field is int64, so anything above INT64_MAX
|
|
614
|
+
// would reach the gateway as a negative seed for the counter. Refused here rather than in the
|
|
615
|
+
// converter: kv::encode() returns the request message by value and has no error channel, so the
|
|
616
|
+
// narrowing has to be caught before anything is encoded or sent. The classic path carries the same
|
|
617
|
+
// representation mismatch, so this is not a couchbase2 regression -- this boundary is simply the
|
|
618
|
+
// first place that can reject it instead of silently wrapping.
|
|
619
|
+
template<typename Request>
|
|
620
|
+
[[nodiscard]] auto
|
|
621
|
+
counter_initial_value_out_of_range(const Request& request) -> bool
|
|
622
|
+
{
|
|
623
|
+
return request.initial_value.has_value() &&
|
|
624
|
+
request.initial_value.value() >
|
|
625
|
+
static_cast<std::uint64_t>(std::numeric_limits<std::int64_t>::max());
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// Same delivery contract as fail_expired: nothing is sent, and the completion still arrives on the
|
|
629
|
+
// io_context rather than inline on the caller's thread.
|
|
630
|
+
template<typename Request, typename Handler>
|
|
631
|
+
auto
|
|
632
|
+
fail_invalid_argument(asio::io_context& io, const Request& request, Handler& handler)
|
|
633
|
+
-> pending_call
|
|
634
|
+
{
|
|
635
|
+
auto response =
|
|
636
|
+
request.make_response(make_key_value_error_context(errc::common::invalid_argument, request.id),
|
|
637
|
+
typename Request::encoded_response_type{});
|
|
638
|
+
asio::post(io, [handler = std::move(handler), response = std::move(response)]() mutable {
|
|
639
|
+
handler(std::move(response));
|
|
640
|
+
});
|
|
641
|
+
return {};
|
|
642
|
+
}
|
|
643
|
+
} // namespace
|
|
644
|
+
|
|
645
|
+
auto
|
|
646
|
+
component::execute(const operations::increment_request& request,
|
|
647
|
+
utils::movable_function<void(operations::increment_response)>&& handler)
|
|
648
|
+
-> pending_call
|
|
649
|
+
{
|
|
650
|
+
if (counter_initial_value_out_of_range(request)) {
|
|
651
|
+
return fail_invalid_argument(io_, request, handler);
|
|
652
|
+
}
|
|
653
|
+
auto proto = std::make_shared<v1::IncrementRequest>(kv::encode(request));
|
|
654
|
+
const auto id = request.id;
|
|
655
|
+
const auto retry_attempts = request.retries.retry_attempts();
|
|
656
|
+
const auto retry_reasons = request.retries.retry_reasons();
|
|
657
|
+
const auto timeout = resolve_kv_timeout(request.timeout, request.durability_level, timeouts_);
|
|
658
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
659
|
+
return fail_expired(io_, request, handler);
|
|
660
|
+
}
|
|
661
|
+
const auto auth = authorization_;
|
|
662
|
+
auto* stub = stubs_->kv.get();
|
|
663
|
+
return dispatcher_.unary<v1::IncrementResponse>(
|
|
664
|
+
timeout,
|
|
665
|
+
[stub, proto, auth](
|
|
666
|
+
grpc::ClientContext& ctx, v1::IncrementResponse& resp, std::function<void(grpc::Status)> cb) {
|
|
667
|
+
if (!auth.empty()) {
|
|
668
|
+
ctx.AddMetadata("authorization", auth);
|
|
669
|
+
}
|
|
670
|
+
stub->async()->Increment(&ctx, proto.get(), &resp, std::move(cb));
|
|
671
|
+
},
|
|
672
|
+
[handler = std::move(handler), id, proto, retry_attempts, retry_reasons](
|
|
673
|
+
grpc::Status status, v1::IncrementResponse resp) mutable {
|
|
674
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
675
|
+
auto ctx =
|
|
676
|
+
make_error_context(status, id, operation_kind::mutating, retry_attempts, retry_reasons);
|
|
677
|
+
handler(kv::decode(resp, std::move(ctx)));
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
auto
|
|
682
|
+
component::execute(const operations::decrement_request& request,
|
|
683
|
+
utils::movable_function<void(operations::decrement_response)>&& handler)
|
|
684
|
+
-> pending_call
|
|
685
|
+
{
|
|
686
|
+
if (counter_initial_value_out_of_range(request)) {
|
|
687
|
+
return fail_invalid_argument(io_, request, handler);
|
|
688
|
+
}
|
|
689
|
+
auto proto = std::make_shared<v1::DecrementRequest>(kv::encode(request));
|
|
690
|
+
const auto id = request.id;
|
|
691
|
+
const auto retry_attempts = request.retries.retry_attempts();
|
|
692
|
+
const auto retry_reasons = request.retries.retry_reasons();
|
|
693
|
+
const auto timeout = resolve_kv_timeout(request.timeout, request.durability_level, timeouts_);
|
|
694
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
695
|
+
return fail_expired(io_, request, handler);
|
|
696
|
+
}
|
|
697
|
+
const auto auth = authorization_;
|
|
698
|
+
auto* stub = stubs_->kv.get();
|
|
699
|
+
return dispatcher_.unary<v1::DecrementResponse>(
|
|
700
|
+
timeout,
|
|
701
|
+
[stub, proto, auth](
|
|
702
|
+
grpc::ClientContext& ctx, v1::DecrementResponse& resp, std::function<void(grpc::Status)> cb) {
|
|
703
|
+
if (!auth.empty()) {
|
|
704
|
+
ctx.AddMetadata("authorization", auth);
|
|
705
|
+
}
|
|
706
|
+
stub->async()->Decrement(&ctx, proto.get(), &resp, std::move(cb));
|
|
707
|
+
},
|
|
708
|
+
[handler = std::move(handler), id, proto, retry_attempts, retry_reasons](
|
|
709
|
+
grpc::Status status, v1::DecrementResponse resp) mutable {
|
|
710
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
711
|
+
auto ctx =
|
|
712
|
+
make_error_context(status, id, operation_kind::mutating, retry_attempts, retry_reasons);
|
|
713
|
+
handler(kv::decode(resp, std::move(ctx)));
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
auto
|
|
718
|
+
component::execute(const operations::append_request& request,
|
|
719
|
+
utils::movable_function<void(operations::append_response)>&& handler)
|
|
720
|
+
-> pending_call
|
|
721
|
+
{
|
|
722
|
+
auto proto = std::make_shared<v1::AppendRequest>(kv::encode(request));
|
|
723
|
+
const auto id = request.id;
|
|
724
|
+
const auto retry_attempts = request.retries.retry_attempts();
|
|
725
|
+
const auto retry_reasons = request.retries.retry_reasons();
|
|
726
|
+
const auto timeout = resolve_kv_timeout(request.timeout, request.durability_level, timeouts_);
|
|
727
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
728
|
+
return fail_expired(io_, request, handler);
|
|
729
|
+
}
|
|
730
|
+
const auto auth = authorization_;
|
|
731
|
+
auto* stub = stubs_->kv.get();
|
|
732
|
+
return dispatcher_.unary<v1::AppendResponse>(
|
|
733
|
+
timeout,
|
|
734
|
+
[stub, proto, auth](
|
|
735
|
+
grpc::ClientContext& ctx, v1::AppendResponse& resp, std::function<void(grpc::Status)> cb) {
|
|
736
|
+
if (!auth.empty()) {
|
|
737
|
+
ctx.AddMetadata("authorization", auth);
|
|
738
|
+
}
|
|
739
|
+
stub->async()->Append(&ctx, proto.get(), &resp, std::move(cb));
|
|
740
|
+
},
|
|
741
|
+
[handler = std::move(handler), id, proto, retry_attempts, retry_reasons](
|
|
742
|
+
grpc::Status status, v1::AppendResponse resp) mutable {
|
|
743
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
744
|
+
auto ctx =
|
|
745
|
+
make_error_context(status, id, operation_kind::mutating, retry_attempts, retry_reasons);
|
|
746
|
+
handler(kv::decode(resp, std::move(ctx)));
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
auto
|
|
751
|
+
component::execute(const operations::prepend_request& request,
|
|
752
|
+
utils::movable_function<void(operations::prepend_response)>&& handler)
|
|
753
|
+
-> pending_call
|
|
754
|
+
{
|
|
755
|
+
auto proto = std::make_shared<v1::PrependRequest>(kv::encode(request));
|
|
756
|
+
const auto id = request.id;
|
|
757
|
+
const auto retry_attempts = request.retries.retry_attempts();
|
|
758
|
+
const auto retry_reasons = request.retries.retry_reasons();
|
|
759
|
+
const auto timeout = resolve_kv_timeout(request.timeout, request.durability_level, timeouts_);
|
|
760
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
761
|
+
return fail_expired(io_, request, handler);
|
|
762
|
+
}
|
|
763
|
+
const auto auth = authorization_;
|
|
764
|
+
auto* stub = stubs_->kv.get();
|
|
765
|
+
return dispatcher_.unary<v1::PrependResponse>(
|
|
766
|
+
timeout,
|
|
767
|
+
[stub, proto, auth](
|
|
768
|
+
grpc::ClientContext& ctx, v1::PrependResponse& resp, std::function<void(grpc::Status)> cb) {
|
|
769
|
+
if (!auth.empty()) {
|
|
770
|
+
ctx.AddMetadata("authorization", auth);
|
|
771
|
+
}
|
|
772
|
+
stub->async()->Prepend(&ctx, proto.get(), &resp, std::move(cb));
|
|
773
|
+
},
|
|
774
|
+
[handler = std::move(handler), id, proto, retry_attempts, retry_reasons](
|
|
775
|
+
grpc::Status status, v1::PrependResponse resp) mutable {
|
|
776
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
777
|
+
auto ctx =
|
|
778
|
+
make_error_context(status, id, operation_kind::mutating, retry_attempts, retry_reasons);
|
|
779
|
+
handler(kv::decode(resp, std::move(ctx)));
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
auto
|
|
784
|
+
component::execute(const operations::query_request& request,
|
|
785
|
+
utils::movable_function<void(operations::query_response)>&& handler)
|
|
786
|
+
-> pending_call
|
|
787
|
+
{
|
|
788
|
+
auto statement = request.statement;
|
|
789
|
+
auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
790
|
+
// Stamped even on the paths that send nothing: the error context identifies which query failed,
|
|
791
|
+
// and a caller correlating by statement or client_context_id has no other handle on it.
|
|
792
|
+
const auto stamped = [&statement, &client_context_id]() {
|
|
793
|
+
operations::query_response response;
|
|
794
|
+
response.ctx.statement = statement;
|
|
795
|
+
response.ctx.client_context_id = client_context_id;
|
|
796
|
+
return response;
|
|
797
|
+
};
|
|
798
|
+
|
|
799
|
+
const auto timeout = request.timeout.value_or(timeouts_.query);
|
|
800
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
801
|
+
return fail_expired_ctx(io_, handler, stamped());
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
// Features with no couchbase2 equivalent (raw passthrough, use_replica, node targeting,
|
|
805
|
+
// out-of-range tuning values): fail cleanly rather than silently dropping the caller's intent.
|
|
806
|
+
// The streaming row_callback is wired below and is deliberately not among them.
|
|
807
|
+
if (!query::can_encode(request)) {
|
|
808
|
+
auto response = stamped();
|
|
809
|
+
response.ctx.ec = errc::common::feature_not_available;
|
|
810
|
+
// Posted rather than invoked here, for the reason fail_expired above gives: completions arrive
|
|
811
|
+
// on the SDK's execution context, and calling back inline would re-enter the caller before it
|
|
812
|
+
// has its pending_call.
|
|
813
|
+
asio::post(io_, [handler = std::move(handler), response = std::move(response)]() mutable {
|
|
814
|
+
handler(std::move(response));
|
|
815
|
+
});
|
|
816
|
+
return {};
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
auto proto = std::make_shared<query_v1::QueryRequest>(query::encode(request));
|
|
820
|
+
const auto auth = authorization_;
|
|
821
|
+
// N1QL is the one service where read-only-ness is a property of the statement rather than of
|
|
822
|
+
// the operation, and the request already carries the flag, so a timed-out read-only query is
|
|
823
|
+
// reported as unambiguous exactly like a KV read.
|
|
824
|
+
const auto kind = request.readonly ? operation_kind::read_only : operation_kind::mutating;
|
|
825
|
+
auto* stub = stubs_->query.get();
|
|
826
|
+
|
|
827
|
+
// Accumulated across streamed messages; shared between the row and completion callbacks. With a
|
|
828
|
+
// row_callback wired, rows are delivered to the consumer as they arrive and `rows` stays empty.
|
|
829
|
+
auto rows = std::make_shared<std::vector<std::string>>();
|
|
830
|
+
auto meta = std::make_shared<operations::query_response::query_meta_data>();
|
|
831
|
+
// Whether a MetaData message arrived at all, which is not the same as what it said. The gateway
|
|
832
|
+
// leaves MetaData nil when its own result.MetaData() fails and still ends the stream OK, and an
|
|
833
|
+
// absent status must not be classified as a failed one.
|
|
834
|
+
auto meta_received = std::make_shared<bool>(false);
|
|
835
|
+
auto stream = std::make_shared<row_stream_state>();
|
|
836
|
+
if (request.row_callback) {
|
|
837
|
+
stream->callback = std::move(*request.row_callback);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
return dispatcher_.server_stream<query_v1::QueryResponse>(
|
|
841
|
+
timeout,
|
|
842
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
843
|
+
grpc::ClientReadReactor<query_v1::QueryResponse>* reactor) {
|
|
844
|
+
if (!auth.empty()) {
|
|
845
|
+
ctx.AddMetadata("authorization", auth);
|
|
846
|
+
}
|
|
847
|
+
stub->async()->Query(&ctx, proto.get(), reactor);
|
|
848
|
+
},
|
|
849
|
+
[rows, meta, meta_received, stream](query_v1::QueryResponse message) {
|
|
850
|
+
stream->received_any = true;
|
|
851
|
+
for (auto& row : *message.mutable_rows()) {
|
|
852
|
+
if (stream->consume(std::move(row))) {
|
|
853
|
+
rows->push_back(std::move(row));
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
if (message.has_meta_data()) {
|
|
857
|
+
*meta_received = true;
|
|
858
|
+
query::decode_meta_data(message.meta_data(), *meta);
|
|
859
|
+
}
|
|
860
|
+
},
|
|
861
|
+
// `proto` is captured so the request outlives the in-flight stream.
|
|
862
|
+
[handler = std::move(handler),
|
|
863
|
+
rows,
|
|
864
|
+
meta,
|
|
865
|
+
meta_received,
|
|
866
|
+
stream,
|
|
867
|
+
proto,
|
|
868
|
+
statement,
|
|
869
|
+
client_context_id,
|
|
870
|
+
kind](grpc::Status status) mutable {
|
|
871
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
872
|
+
operations::query_response response;
|
|
873
|
+
response.ctx.ec = map_status(status, kind);
|
|
874
|
+
// CXXCBC-909: a mid-stream error after the gateway sent anything cannot be retried.
|
|
875
|
+
if (stream->received_any && retry_reason_for(response.ctx.ec).has_value()) {
|
|
876
|
+
response.ctx.ec = errc::common::request_canceled;
|
|
877
|
+
}
|
|
878
|
+
response.ctx.statement = std::move(statement);
|
|
879
|
+
response.ctx.client_context_id =
|
|
880
|
+
meta->client_context_id.empty() ? std::move(client_context_id) : meta->client_context_id;
|
|
881
|
+
if (!status.ok()) {
|
|
882
|
+
response.ctx.first_error_message = error_message(status);
|
|
883
|
+
}
|
|
884
|
+
response.meta = std::move(*meta);
|
|
885
|
+
response.rows = std::move(*rows);
|
|
886
|
+
// A terminal status other than "success" arriving with an OK trailer would otherwise be
|
|
887
|
+
// reported as a successful query whose own metadata says it failed. map_query_error is the
|
|
888
|
+
// classifier the classic path uses, so the two transports agree on the mapping; the proto
|
|
889
|
+
// carries no errors list, and for that case it yields internal_server_failure -- the same
|
|
890
|
+
// fallback document_query.cxx applies when the payload has no error code to classify.
|
|
891
|
+
//
|
|
892
|
+
// A transport-level error already in ctx.ec is more specific, so it wins.
|
|
893
|
+
if (!response.ctx.ec && *meta_received) {
|
|
894
|
+
response.ctx.ec = operations::map_query_error(response.meta);
|
|
895
|
+
}
|
|
896
|
+
handler(std::move(response));
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
auto
|
|
901
|
+
component::execute(const operations::analytics_request& request,
|
|
902
|
+
utils::movable_function<void(operations::analytics_response)>&& handler)
|
|
903
|
+
-> pending_call
|
|
904
|
+
{
|
|
905
|
+
auto statement = request.statement;
|
|
906
|
+
auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
907
|
+
// Stamped even on the paths that send nothing: the error context identifies which statement
|
|
908
|
+
// failed, and a caller correlating by statement or client_context_id has no other handle on it.
|
|
909
|
+
const auto stamped = [&statement, &client_context_id]() {
|
|
910
|
+
operations::analytics_response response;
|
|
911
|
+
response.ctx.statement = statement;
|
|
912
|
+
response.ctx.client_context_id = client_context_id;
|
|
913
|
+
return response;
|
|
914
|
+
};
|
|
915
|
+
|
|
916
|
+
const auto timeout = request.timeout.value_or(timeouts_.analytics);
|
|
917
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
918
|
+
return fail_expired_ctx(io_, handler, stamped());
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
// Scoped analytics and raw passthrough have no couchbase2 mapping: fail cleanly rather than
|
|
922
|
+
// dropping the caller's intent. The streaming row_callback is wired below and is not among them.
|
|
923
|
+
if (!analytics::can_encode(request)) {
|
|
924
|
+
auto response = stamped();
|
|
925
|
+
response.ctx.ec = errc::common::feature_not_available;
|
|
926
|
+
// Posted rather than invoked here, for the reason fail_expired above gives: completions arrive
|
|
927
|
+
// on the SDK's execution context, and calling back inline would re-enter the caller before it
|
|
928
|
+
// has its pending_call.
|
|
929
|
+
asio::post(io_, [handler = std::move(handler), response = std::move(response)]() mutable {
|
|
930
|
+
handler(std::move(response));
|
|
931
|
+
});
|
|
932
|
+
return {};
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
auto proto = std::make_shared<analytics_v1::AnalyticsQueryRequest>(analytics::encode(request));
|
|
936
|
+
const auto auth = authorization_;
|
|
937
|
+
// Analytics carries the same readonly flag as N1QL, so the same RFC 77 rule applies.
|
|
938
|
+
const auto kind = request.readonly ? operation_kind::read_only : operation_kind::mutating;
|
|
939
|
+
auto* stub = stubs_->analytics.get();
|
|
940
|
+
|
|
941
|
+
auto rows = std::make_shared<std::vector<std::string>>();
|
|
942
|
+
auto meta = std::make_shared<operations::analytics_response::analytics_meta_data>();
|
|
943
|
+
// Whether a MetaData message arrived, which the status alone cannot tell us: analytics_status's
|
|
944
|
+
// first enumerator is `running`, so a default-constructed meta is indistinguishable from one the
|
|
945
|
+
// gateway reported as running. Classifying without this would turn a stream that ended OK with no
|
|
946
|
+
// metadata into an error.
|
|
947
|
+
auto meta_received = std::make_shared<bool>(false);
|
|
948
|
+
auto stream = std::make_shared<row_stream_state>();
|
|
949
|
+
if (request.row_callback) {
|
|
950
|
+
stream->callback = std::move(*request.row_callback);
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
return dispatcher_.server_stream<analytics_v1::AnalyticsQueryResponse>(
|
|
954
|
+
timeout,
|
|
955
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
956
|
+
grpc::ClientReadReactor<analytics_v1::AnalyticsQueryResponse>* reactor) {
|
|
957
|
+
if (!auth.empty()) {
|
|
958
|
+
ctx.AddMetadata("authorization", auth);
|
|
959
|
+
}
|
|
960
|
+
stub->async()->AnalyticsQuery(&ctx, proto.get(), reactor);
|
|
961
|
+
},
|
|
962
|
+
[rows, meta, meta_received, stream](analytics_v1::AnalyticsQueryResponse message) {
|
|
963
|
+
stream->received_any = true;
|
|
964
|
+
for (auto& row : *message.mutable_rows()) {
|
|
965
|
+
if (stream->consume(std::move(row))) {
|
|
966
|
+
rows->push_back(std::move(row));
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
if (message.has_meta_data()) {
|
|
970
|
+
*meta_received = true;
|
|
971
|
+
analytics::decode_meta_data(message.meta_data(), *meta);
|
|
972
|
+
}
|
|
973
|
+
},
|
|
974
|
+
// `proto` is captured so the request outlives the in-flight stream.
|
|
975
|
+
[handler = std::move(handler),
|
|
976
|
+
rows,
|
|
977
|
+
meta,
|
|
978
|
+
meta_received,
|
|
979
|
+
stream,
|
|
980
|
+
proto,
|
|
981
|
+
statement,
|
|
982
|
+
client_context_id,
|
|
983
|
+
kind](grpc::Status status) mutable {
|
|
984
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
985
|
+
operations::analytics_response response;
|
|
986
|
+
response.ctx.ec = map_status(status, kind);
|
|
987
|
+
// CXXCBC-909: a mid-stream error after the gateway sent anything cannot be retried.
|
|
988
|
+
if (stream->received_any && retry_reason_for(response.ctx.ec).has_value()) {
|
|
989
|
+
response.ctx.ec = errc::common::request_canceled;
|
|
990
|
+
}
|
|
991
|
+
response.ctx.statement = std::move(statement);
|
|
992
|
+
response.ctx.client_context_id =
|
|
993
|
+
meta->client_context_id.empty() ? std::move(client_context_id) : meta->client_context_id;
|
|
994
|
+
if (!status.ok()) {
|
|
995
|
+
response.ctx.first_error_message = error_message(status);
|
|
996
|
+
}
|
|
997
|
+
response.meta = std::move(*meta);
|
|
998
|
+
response.rows = std::move(*rows);
|
|
999
|
+
// A terminal status other than success arriving with an OK trailer would otherwise be
|
|
1000
|
+
// reported as a successful query whose own metadata says it failed. map_analytics_error is
|
|
1001
|
+
// the classifier the classic path uses, so both transports agree; the proto carries no errors
|
|
1002
|
+
// list, and for that case it yields internal_server_failure -- the fallback its own comment
|
|
1003
|
+
// documents for exactly this caller.
|
|
1004
|
+
//
|
|
1005
|
+
// A transport-level error already in ctx.ec is more specific, so it wins.
|
|
1006
|
+
if (!response.ctx.ec && *meta_received) {
|
|
1007
|
+
response.ctx.ec = operations::map_analytics_error(response.meta);
|
|
1008
|
+
}
|
|
1009
|
+
handler(std::move(response));
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
auto
|
|
1014
|
+
component::execute(const operations::search_request& request,
|
|
1015
|
+
utils::movable_function<void(operations::search_response)>&& handler)
|
|
1016
|
+
-> pending_call
|
|
1017
|
+
{
|
|
1018
|
+
auto index_name = request.index_name;
|
|
1019
|
+
auto query_str = request.query.str();
|
|
1020
|
+
auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1021
|
+
// Stamped even on the paths that send nothing, as the query overload does: the error context
|
|
1022
|
+
// identifies which search failed, and a caller correlating by index or client_context_id has no
|
|
1023
|
+
// other handle on it.
|
|
1024
|
+
const auto stamped = [&index_name, &query_str, &client_context_id]() {
|
|
1025
|
+
operations::search_response response;
|
|
1026
|
+
response.ctx.index_name = index_name;
|
|
1027
|
+
response.ctx.query = query_str;
|
|
1028
|
+
response.ctx.client_context_id = client_context_id;
|
|
1029
|
+
return response;
|
|
1030
|
+
};
|
|
1031
|
+
|
|
1032
|
+
const auto timeout = request.timeout.value_or(timeouts_.search);
|
|
1033
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1034
|
+
return fail_expired_ctx(io_, handler, stamped());
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
// Unmappable query shape or gated feature (facets, sort specs, vector search, mutation tokens,
|
|
1038
|
+
// raw): fail cleanly rather than dropping the caller's intent. A query that is not JSON at all is
|
|
1039
|
+
// the caller's own error and is reported as invalid_argument, so a malformed query is not
|
|
1040
|
+
// mistaken for a gap in couchbase2 search support.
|
|
1041
|
+
auto encoded = search::encode(request);
|
|
1042
|
+
if (!encoded.has_value()) {
|
|
1043
|
+
auto response = stamped();
|
|
1044
|
+
response.ctx.ec = search::query_is_malformed(request) ? errc::common::invalid_argument
|
|
1045
|
+
: errc::common::feature_not_available;
|
|
1046
|
+
// Posted rather than invoked here, for the reason fail_expired above gives: completions arrive
|
|
1047
|
+
// on the io context, never inline out of execute().
|
|
1048
|
+
asio::post(io_, [handler = std::move(handler), response = std::move(response)]() mutable {
|
|
1049
|
+
handler(std::move(response));
|
|
1050
|
+
});
|
|
1051
|
+
return {};
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
auto proto = std::make_shared<search_v1::SearchQueryRequest>(std::move(*encoded));
|
|
1055
|
+
const auto auth = authorization_;
|
|
1056
|
+
auto* stub = stubs_->search.get();
|
|
1057
|
+
auto response = std::make_shared<operations::search_response>();
|
|
1058
|
+
|
|
1059
|
+
return dispatcher_.server_stream<search_v1::SearchQueryResponse>(
|
|
1060
|
+
timeout,
|
|
1061
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1062
|
+
grpc::ClientReadReactor<search_v1::SearchQueryResponse>* reactor) {
|
|
1063
|
+
if (!auth.empty()) {
|
|
1064
|
+
ctx.AddMetadata("authorization", auth);
|
|
1065
|
+
}
|
|
1066
|
+
stub->async()->SearchQuery(&ctx, proto.get(), reactor);
|
|
1067
|
+
},
|
|
1068
|
+
[response](search_v1::SearchQueryResponse message) {
|
|
1069
|
+
search::decode(message, *response);
|
|
1070
|
+
},
|
|
1071
|
+
[handler = std::move(handler), response, proto, index_name, query_str, client_context_id](
|
|
1072
|
+
grpc::Status status) mutable {
|
|
1073
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1074
|
+
response->ctx.ec = map_status(status, operation_kind::read_only);
|
|
1075
|
+
response->ctx.first_error_message = error_message(status);
|
|
1076
|
+
response->ctx.index_name = std::move(index_name);
|
|
1077
|
+
response->ctx.query = std::move(query_str);
|
|
1078
|
+
response->ctx.client_context_id = std::move(client_context_id);
|
|
1079
|
+
handler(std::move(*response));
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
auto
|
|
1084
|
+
component::execute(const operations::document_view_request& request,
|
|
1085
|
+
utils::movable_function<void(operations::document_view_response)>&& handler)
|
|
1086
|
+
-> pending_call
|
|
1087
|
+
{
|
|
1088
|
+
auto design_document = request.document_name;
|
|
1089
|
+
auto view_name = request.view_name;
|
|
1090
|
+
auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1091
|
+
// Stamped on every path for the reason the query and search overloads give: a response naming no
|
|
1092
|
+
// view leaves the caller nothing to correlate the failure with.
|
|
1093
|
+
const auto stamped = [&design_document, &view_name, &client_context_id]() {
|
|
1094
|
+
operations::document_view_response response;
|
|
1095
|
+
response.ctx.design_document_name = design_document;
|
|
1096
|
+
response.ctx.view_name = view_name;
|
|
1097
|
+
response.ctx.client_context_id = client_context_id;
|
|
1098
|
+
return response;
|
|
1099
|
+
};
|
|
1100
|
+
|
|
1101
|
+
const auto timeout = request.timeout.value_or(timeouts_.view);
|
|
1102
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1103
|
+
return fail_expired_ctx(io_, handler, stamped());
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
// raw / query_string / full_set have no couchbase2 mapping: fail cleanly.
|
|
1107
|
+
if (!view::can_encode(request)) {
|
|
1108
|
+
auto response = stamped();
|
|
1109
|
+
response.ctx.ec = errc::common::feature_not_available;
|
|
1110
|
+
// Posted rather than invoked here, for the reason fail_expired above gives: completions arrive
|
|
1111
|
+
// on the io context, never inline out of execute().
|
|
1112
|
+
asio::post(io_, [handler = std::move(handler), response = std::move(response)]() mutable {
|
|
1113
|
+
handler(std::move(response));
|
|
1114
|
+
});
|
|
1115
|
+
return {};
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
auto proto = std::make_shared<view_v1::ViewQueryRequest>(view::encode(request));
|
|
1119
|
+
const auto auth = authorization_;
|
|
1120
|
+
auto* stub = stubs_->view.get();
|
|
1121
|
+
auto response = std::make_shared<operations::document_view_response>();
|
|
1122
|
+
|
|
1123
|
+
return dispatcher_.server_stream<view_v1::ViewQueryResponse>(
|
|
1124
|
+
timeout,
|
|
1125
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1126
|
+
grpc::ClientReadReactor<view_v1::ViewQueryResponse>* reactor) {
|
|
1127
|
+
if (!auth.empty()) {
|
|
1128
|
+
ctx.AddMetadata("authorization", auth);
|
|
1129
|
+
}
|
|
1130
|
+
stub->async()->ViewQuery(&ctx, proto.get(), reactor);
|
|
1131
|
+
},
|
|
1132
|
+
[response](view_v1::ViewQueryResponse message) {
|
|
1133
|
+
view::decode_rows(message, *response);
|
|
1134
|
+
},
|
|
1135
|
+
[handler = std::move(handler), response, proto, design_document, view_name, client_context_id](
|
|
1136
|
+
grpc::Status status) mutable {
|
|
1137
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1138
|
+
response->ctx.ec = map_status(status, operation_kind::read_only);
|
|
1139
|
+
response->ctx.first_error_message = error_message(status);
|
|
1140
|
+
response->ctx.design_document_name = std::move(design_document);
|
|
1141
|
+
response->ctx.view_name = std::move(view_name);
|
|
1142
|
+
response->ctx.client_context_id = std::move(client_context_id);
|
|
1143
|
+
handler(std::move(*response));
|
|
1144
|
+
});
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
auto
|
|
1148
|
+
component::execute(
|
|
1149
|
+
const operations::management::bucket_get_all_request& request,
|
|
1150
|
+
utils::movable_function<void(operations::management::bucket_get_all_response)>&& handler)
|
|
1151
|
+
-> pending_call
|
|
1152
|
+
{
|
|
1153
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1154
|
+
auto proto = std::make_shared<bucket_admin_v1::ListBucketsRequest>();
|
|
1155
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1156
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1157
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1158
|
+
}
|
|
1159
|
+
const auto auth = authorization_;
|
|
1160
|
+
auto* stub = stubs_->bucket_admin.get();
|
|
1161
|
+
return dispatcher_.unary<bucket_admin_v1::ListBucketsResponse>(
|
|
1162
|
+
timeout,
|
|
1163
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1164
|
+
bucket_admin_v1::ListBucketsResponse& resp,
|
|
1165
|
+
std::function<void(grpc::Status)> cb) {
|
|
1166
|
+
if (!auth.empty()) {
|
|
1167
|
+
ctx.AddMetadata("authorization", auth);
|
|
1168
|
+
}
|
|
1169
|
+
stub->async()->ListBuckets(&ctx, proto.get(), &resp, std::move(cb));
|
|
1170
|
+
},
|
|
1171
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
1172
|
+
grpc::Status status, bucket_admin_v1::ListBucketsResponse resp) mutable {
|
|
1173
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1174
|
+
operations::management::bucket_get_all_response response;
|
|
1175
|
+
response.ctx.client_context_id = client_context_id;
|
|
1176
|
+
response.ctx.ec = map_status(status, operation_kind::read_only);
|
|
1177
|
+
for (const auto& bucket : resp.buckets()) {
|
|
1178
|
+
response.buckets.push_back(bucket_admin::decode_bucket(bucket));
|
|
1179
|
+
}
|
|
1180
|
+
handler(std::move(response));
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
auto
|
|
1185
|
+
component::execute(
|
|
1186
|
+
const operations::management::bucket_get_request& request,
|
|
1187
|
+
utils::movable_function<void(operations::management::bucket_get_response)>&& handler)
|
|
1188
|
+
-> pending_call
|
|
1189
|
+
{
|
|
1190
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1191
|
+
// admin.bucket.v1 has no GetBucket RPC; filter the bucket list by name.
|
|
1192
|
+
auto proto = std::make_shared<bucket_admin_v1::ListBucketsRequest>();
|
|
1193
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1194
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1195
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1196
|
+
}
|
|
1197
|
+
const auto auth = authorization_;
|
|
1198
|
+
const auto name = request.name;
|
|
1199
|
+
auto* stub = stubs_->bucket_admin.get();
|
|
1200
|
+
return dispatcher_.unary<bucket_admin_v1::ListBucketsResponse>(
|
|
1201
|
+
timeout,
|
|
1202
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1203
|
+
bucket_admin_v1::ListBucketsResponse& resp,
|
|
1204
|
+
std::function<void(grpc::Status)> cb) {
|
|
1205
|
+
if (!auth.empty()) {
|
|
1206
|
+
ctx.AddMetadata("authorization", auth);
|
|
1207
|
+
}
|
|
1208
|
+
stub->async()->ListBuckets(&ctx, proto.get(), &resp, std::move(cb));
|
|
1209
|
+
},
|
|
1210
|
+
[handler = std::move(handler), proto, client_context_id, name](
|
|
1211
|
+
grpc::Status status, bucket_admin_v1::ListBucketsResponse resp) mutable {
|
|
1212
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1213
|
+
operations::management::bucket_get_response response;
|
|
1214
|
+
response.ctx.client_context_id = client_context_id;
|
|
1215
|
+
response.ctx.ec = map_status(status, operation_kind::read_only);
|
|
1216
|
+
if (!response.ctx.ec) {
|
|
1217
|
+
bool found = false;
|
|
1218
|
+
for (const auto& bucket : resp.buckets()) {
|
|
1219
|
+
if (bucket.bucket_name() == name) {
|
|
1220
|
+
response.bucket = bucket_admin::decode_bucket(bucket);
|
|
1221
|
+
found = true;
|
|
1222
|
+
break;
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
if (!found) {
|
|
1226
|
+
response.ctx.ec = errc::common::bucket_not_found;
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
handler(std::move(response));
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
auto
|
|
1234
|
+
component::execute(
|
|
1235
|
+
const operations::management::bucket_create_request& request,
|
|
1236
|
+
utils::movable_function<void(operations::management::bucket_create_response)>&& handler)
|
|
1237
|
+
-> pending_call
|
|
1238
|
+
{
|
|
1239
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1240
|
+
auto proto = std::make_shared<bucket_admin_v1::CreateBucketRequest>();
|
|
1241
|
+
bucket_admin::apply_settings(request.bucket, *proto);
|
|
1242
|
+
if (!bucket_admin::apply_create_only_settings(request.bucket, *proto)) {
|
|
1243
|
+
operations::management::bucket_create_response response;
|
|
1244
|
+
response.ctx.client_context_id = client_context_id;
|
|
1245
|
+
response.ctx.ec = errc::common::feature_not_available;
|
|
1246
|
+
// Posted rather than invoked here, for the reason fail_expired gives: completions arrive on the
|
|
1247
|
+
// io context, never inline out of execute().
|
|
1248
|
+
asio::post(io_, [handler = std::move(handler), response = std::move(response)]() mutable {
|
|
1249
|
+
handler(std::move(response));
|
|
1250
|
+
});
|
|
1251
|
+
return {};
|
|
1252
|
+
}
|
|
1253
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1254
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1255
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1256
|
+
}
|
|
1257
|
+
const auto auth = authorization_;
|
|
1258
|
+
auto* stub = stubs_->bucket_admin.get();
|
|
1259
|
+
return dispatcher_.unary<bucket_admin_v1::CreateBucketResponse>(
|
|
1260
|
+
timeout,
|
|
1261
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1262
|
+
bucket_admin_v1::CreateBucketResponse& resp,
|
|
1263
|
+
std::function<void(grpc::Status)> cb) {
|
|
1264
|
+
if (!auth.empty()) {
|
|
1265
|
+
ctx.AddMetadata("authorization", auth);
|
|
1266
|
+
}
|
|
1267
|
+
stub->async()->CreateBucket(&ctx, proto.get(), &resp, std::move(cb));
|
|
1268
|
+
},
|
|
1269
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
1270
|
+
grpc::Status status, bucket_admin_v1::CreateBucketResponse /* resp */) mutable {
|
|
1271
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1272
|
+
operations::management::bucket_create_response response;
|
|
1273
|
+
response.ctx.client_context_id = client_context_id;
|
|
1274
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
1275
|
+
if (response.ctx.ec) {
|
|
1276
|
+
response.error_message = error_message(status);
|
|
1277
|
+
}
|
|
1278
|
+
handler(std::move(response));
|
|
1279
|
+
});
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
auto
|
|
1283
|
+
component::execute(
|
|
1284
|
+
const operations::management::bucket_update_request& request,
|
|
1285
|
+
utils::movable_function<void(operations::management::bucket_update_response)>&& handler)
|
|
1286
|
+
-> pending_call
|
|
1287
|
+
{
|
|
1288
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1289
|
+
auto proto = std::make_shared<bucket_admin_v1::UpdateBucketRequest>();
|
|
1290
|
+
bucket_admin::apply_settings(request.bucket, *proto);
|
|
1291
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1292
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1293
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1294
|
+
}
|
|
1295
|
+
const auto auth = authorization_;
|
|
1296
|
+
auto* stub = stubs_->bucket_admin.get();
|
|
1297
|
+
return dispatcher_.unary<bucket_admin_v1::UpdateBucketResponse>(
|
|
1298
|
+
timeout,
|
|
1299
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1300
|
+
bucket_admin_v1::UpdateBucketResponse& resp,
|
|
1301
|
+
std::function<void(grpc::Status)> cb) {
|
|
1302
|
+
if (!auth.empty()) {
|
|
1303
|
+
ctx.AddMetadata("authorization", auth);
|
|
1304
|
+
}
|
|
1305
|
+
stub->async()->UpdateBucket(&ctx, proto.get(), &resp, std::move(cb));
|
|
1306
|
+
},
|
|
1307
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
1308
|
+
grpc::Status status, bucket_admin_v1::UpdateBucketResponse /* resp */) mutable {
|
|
1309
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1310
|
+
operations::management::bucket_update_response response;
|
|
1311
|
+
response.ctx.client_context_id = client_context_id;
|
|
1312
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
1313
|
+
if (response.ctx.ec) {
|
|
1314
|
+
response.error_message = error_message(status);
|
|
1315
|
+
}
|
|
1316
|
+
handler(std::move(response));
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
auto
|
|
1321
|
+
component::execute(
|
|
1322
|
+
const operations::management::bucket_drop_request& request,
|
|
1323
|
+
utils::movable_function<void(operations::management::bucket_drop_response)>&& handler)
|
|
1324
|
+
-> pending_call
|
|
1325
|
+
{
|
|
1326
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1327
|
+
auto proto = std::make_shared<bucket_admin_v1::DeleteBucketRequest>();
|
|
1328
|
+
proto->set_bucket_name(request.name);
|
|
1329
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1330
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1331
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1332
|
+
}
|
|
1333
|
+
const auto auth = authorization_;
|
|
1334
|
+
auto* stub = stubs_->bucket_admin.get();
|
|
1335
|
+
return dispatcher_.unary<bucket_admin_v1::DeleteBucketResponse>(
|
|
1336
|
+
timeout,
|
|
1337
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1338
|
+
bucket_admin_v1::DeleteBucketResponse& resp,
|
|
1339
|
+
std::function<void(grpc::Status)> cb) {
|
|
1340
|
+
if (!auth.empty()) {
|
|
1341
|
+
ctx.AddMetadata("authorization", auth);
|
|
1342
|
+
}
|
|
1343
|
+
stub->async()->DeleteBucket(&ctx, proto.get(), &resp, std::move(cb));
|
|
1344
|
+
},
|
|
1345
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
1346
|
+
grpc::Status status, bucket_admin_v1::DeleteBucketResponse /* resp */) mutable {
|
|
1347
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1348
|
+
operations::management::bucket_drop_response response;
|
|
1349
|
+
response.ctx.client_context_id = client_context_id;
|
|
1350
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
1351
|
+
handler(std::move(response));
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
auto
|
|
1356
|
+
component::execute(
|
|
1357
|
+
const operations::management::bucket_flush_request& request,
|
|
1358
|
+
utils::movable_function<void(operations::management::bucket_flush_response)>&& handler)
|
|
1359
|
+
-> pending_call
|
|
1360
|
+
{
|
|
1361
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1362
|
+
auto proto = std::make_shared<bucket_admin_v1::FlushBucketRequest>();
|
|
1363
|
+
proto->set_bucket_name(request.name);
|
|
1364
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1365
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1366
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1367
|
+
}
|
|
1368
|
+
const auto auth = authorization_;
|
|
1369
|
+
auto* stub = stubs_->bucket_admin.get();
|
|
1370
|
+
return dispatcher_.unary<bucket_admin_v1::FlushBucketResponse>(
|
|
1371
|
+
timeout,
|
|
1372
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1373
|
+
bucket_admin_v1::FlushBucketResponse& resp,
|
|
1374
|
+
std::function<void(grpc::Status)> cb) {
|
|
1375
|
+
if (!auth.empty()) {
|
|
1376
|
+
ctx.AddMetadata("authorization", auth);
|
|
1377
|
+
}
|
|
1378
|
+
stub->async()->FlushBucket(&ctx, proto.get(), &resp, std::move(cb));
|
|
1379
|
+
},
|
|
1380
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
1381
|
+
grpc::Status status, bucket_admin_v1::FlushBucketResponse /* resp */) mutable {
|
|
1382
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1383
|
+
operations::management::bucket_flush_response response;
|
|
1384
|
+
response.ctx.client_context_id = client_context_id;
|
|
1385
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
1386
|
+
handler(std::move(response));
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
auto
|
|
1391
|
+
component::execute(
|
|
1392
|
+
const operations::management::scope_get_all_request& request,
|
|
1393
|
+
utils::movable_function<void(operations::management::scope_get_all_response)>&& handler)
|
|
1394
|
+
-> pending_call
|
|
1395
|
+
{
|
|
1396
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1397
|
+
auto proto = std::make_shared<collection_admin_v1::ListCollectionsRequest>();
|
|
1398
|
+
proto->set_bucket_name(request.bucket_name);
|
|
1399
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1400
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1401
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1402
|
+
}
|
|
1403
|
+
const auto auth = authorization_;
|
|
1404
|
+
auto* stub = stubs_->collection_admin.get();
|
|
1405
|
+
return dispatcher_.unary<collection_admin_v1::ListCollectionsResponse>(
|
|
1406
|
+
timeout,
|
|
1407
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1408
|
+
collection_admin_v1::ListCollectionsResponse& resp,
|
|
1409
|
+
std::function<void(grpc::Status)> cb) {
|
|
1410
|
+
if (!auth.empty()) {
|
|
1411
|
+
ctx.AddMetadata("authorization", auth);
|
|
1412
|
+
}
|
|
1413
|
+
stub->async()->ListCollections(&ctx, proto.get(), &resp, std::move(cb));
|
|
1414
|
+
},
|
|
1415
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
1416
|
+
grpc::Status status, collection_admin_v1::ListCollectionsResponse resp) mutable {
|
|
1417
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1418
|
+
operations::management::scope_get_all_response response;
|
|
1419
|
+
response.ctx.client_context_id = client_context_id;
|
|
1420
|
+
response.ctx.ec = map_status(status, operation_kind::read_only);
|
|
1421
|
+
if (!response.ctx.ec) {
|
|
1422
|
+
response.manifest = collection_admin::decode_manifest(resp);
|
|
1423
|
+
}
|
|
1424
|
+
handler(std::move(response));
|
|
1425
|
+
});
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
auto
|
|
1429
|
+
component::execute(
|
|
1430
|
+
const operations::management::scope_create_request& request,
|
|
1431
|
+
utils::movable_function<void(operations::management::scope_create_response)>&& handler)
|
|
1432
|
+
-> pending_call
|
|
1433
|
+
{
|
|
1434
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1435
|
+
auto proto = std::make_shared<collection_admin_v1::CreateScopeRequest>();
|
|
1436
|
+
proto->set_bucket_name(request.bucket_name);
|
|
1437
|
+
proto->set_scope_name(request.scope_name);
|
|
1438
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1439
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1440
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1441
|
+
}
|
|
1442
|
+
const auto auth = authorization_;
|
|
1443
|
+
auto* stub = stubs_->collection_admin.get();
|
|
1444
|
+
return dispatcher_.unary<collection_admin_v1::CreateScopeResponse>(
|
|
1445
|
+
timeout,
|
|
1446
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1447
|
+
collection_admin_v1::CreateScopeResponse& resp,
|
|
1448
|
+
std::function<void(grpc::Status)> cb) {
|
|
1449
|
+
if (!auth.empty()) {
|
|
1450
|
+
ctx.AddMetadata("authorization", auth);
|
|
1451
|
+
}
|
|
1452
|
+
stub->async()->CreateScope(&ctx, proto.get(), &resp, std::move(cb));
|
|
1453
|
+
},
|
|
1454
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
1455
|
+
grpc::Status status, collection_admin_v1::CreateScopeResponse resp) mutable {
|
|
1456
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1457
|
+
operations::management::scope_create_response response;
|
|
1458
|
+
response.ctx.client_context_id = client_context_id;
|
|
1459
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
1460
|
+
response.uid = resp.manifest_uid();
|
|
1461
|
+
handler(std::move(response));
|
|
1462
|
+
});
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
auto
|
|
1466
|
+
component::execute(
|
|
1467
|
+
const operations::management::scope_drop_request& request,
|
|
1468
|
+
utils::movable_function<void(operations::management::scope_drop_response)>&& handler)
|
|
1469
|
+
-> pending_call
|
|
1470
|
+
{
|
|
1471
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1472
|
+
auto proto = std::make_shared<collection_admin_v1::DeleteScopeRequest>();
|
|
1473
|
+
proto->set_bucket_name(request.bucket_name);
|
|
1474
|
+
proto->set_scope_name(request.scope_name);
|
|
1475
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1476
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1477
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1478
|
+
}
|
|
1479
|
+
const auto auth = authorization_;
|
|
1480
|
+
auto* stub = stubs_->collection_admin.get();
|
|
1481
|
+
return dispatcher_.unary<collection_admin_v1::DeleteScopeResponse>(
|
|
1482
|
+
timeout,
|
|
1483
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1484
|
+
collection_admin_v1::DeleteScopeResponse& resp,
|
|
1485
|
+
std::function<void(grpc::Status)> cb) {
|
|
1486
|
+
if (!auth.empty()) {
|
|
1487
|
+
ctx.AddMetadata("authorization", auth);
|
|
1488
|
+
}
|
|
1489
|
+
stub->async()->DeleteScope(&ctx, proto.get(), &resp, std::move(cb));
|
|
1490
|
+
},
|
|
1491
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
1492
|
+
grpc::Status status, collection_admin_v1::DeleteScopeResponse resp) mutable {
|
|
1493
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1494
|
+
operations::management::scope_drop_response response;
|
|
1495
|
+
response.ctx.client_context_id = client_context_id;
|
|
1496
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
1497
|
+
response.uid = resp.manifest_uid();
|
|
1498
|
+
handler(std::move(response));
|
|
1499
|
+
});
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
auto
|
|
1503
|
+
component::execute(
|
|
1504
|
+
const operations::management::collection_create_request& request,
|
|
1505
|
+
utils::movable_function<void(operations::management::collection_create_response)>&& handler)
|
|
1506
|
+
-> pending_call
|
|
1507
|
+
{
|
|
1508
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1509
|
+
// -1 is the lowest value the sign carries a meaning for, and the classic path refuses anything
|
|
1510
|
+
// below it before encoding (collection_create.cxx:39-44). encode_max_expiry maps every negative
|
|
1511
|
+
// onto the no-expiry wire form, so without this the same request would be invalid over
|
|
1512
|
+
// couchbase:// and create a never-expiring collection over couchbase2://.
|
|
1513
|
+
if (request.max_expiry.value_or(0) < -1) {
|
|
1514
|
+
auto response = stamped_management(request);
|
|
1515
|
+
response.ctx.ec = errc::common::invalid_argument;
|
|
1516
|
+
asio::post(io_, [handler = std::move(handler), response = std::move(response)]() mutable {
|
|
1517
|
+
handler(std::move(response));
|
|
1518
|
+
});
|
|
1519
|
+
return {};
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
auto proto = std::make_shared<collection_admin_v1::CreateCollectionRequest>();
|
|
1523
|
+
proto->set_bucket_name(request.bucket_name);
|
|
1524
|
+
proto->set_scope_name(request.scope_name);
|
|
1525
|
+
proto->set_collection_name(request.collection_name);
|
|
1526
|
+
// A created collection inherits the bucket default from an unset max_expiry_secs, which is what
|
|
1527
|
+
// a core max_expiry of 0 asks for, so encode_max_expiry declining to produce a value is already
|
|
1528
|
+
// the right wire form here.
|
|
1529
|
+
if (request.max_expiry.has_value()) {
|
|
1530
|
+
if (const auto secs = collection_admin::encode_max_expiry(*request.max_expiry);
|
|
1531
|
+
secs.has_value()) {
|
|
1532
|
+
proto->set_max_expiry_secs(secs.value());
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
if (request.history.has_value()) {
|
|
1536
|
+
proto->set_history_retention_enabled(*request.history);
|
|
1537
|
+
}
|
|
1538
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1539
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1540
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1541
|
+
}
|
|
1542
|
+
const auto auth = authorization_;
|
|
1543
|
+
auto* stub = stubs_->collection_admin.get();
|
|
1544
|
+
return dispatcher_.unary<collection_admin_v1::CreateCollectionResponse>(
|
|
1545
|
+
timeout,
|
|
1546
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1547
|
+
collection_admin_v1::CreateCollectionResponse& resp,
|
|
1548
|
+
std::function<void(grpc::Status)> cb) {
|
|
1549
|
+
if (!auth.empty()) {
|
|
1550
|
+
ctx.AddMetadata("authorization", auth);
|
|
1551
|
+
}
|
|
1552
|
+
stub->async()->CreateCollection(&ctx, proto.get(), &resp, std::move(cb));
|
|
1553
|
+
},
|
|
1554
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
1555
|
+
grpc::Status status, collection_admin_v1::CreateCollectionResponse resp) mutable {
|
|
1556
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1557
|
+
operations::management::collection_create_response response;
|
|
1558
|
+
response.ctx.client_context_id = client_context_id;
|
|
1559
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
1560
|
+
response.uid = resp.manifest_uid();
|
|
1561
|
+
handler(std::move(response));
|
|
1562
|
+
});
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
auto
|
|
1566
|
+
component::execute(
|
|
1567
|
+
const operations::management::collection_update_request& request,
|
|
1568
|
+
utils::movable_function<void(operations::management::collection_update_response)>&& handler)
|
|
1569
|
+
-> pending_call
|
|
1570
|
+
{
|
|
1571
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1572
|
+
// The sentinel translation create does, minus the one value update cannot express, and with the
|
|
1573
|
+
// same lower bound. Below -1 the classic path refuses the request (collection_update.cxx:39-45).
|
|
1574
|
+
// An explicit 0 is the reset to the bucket's own expiry that the classic path sends as maxTTL=0,
|
|
1575
|
+
// and there is no wire form left for it: an explicit 0 already means "no expiry", and an unset
|
|
1576
|
+
// field means "leave the collection as it is" rather than "inherit the bucket default". Refuse
|
|
1577
|
+
// it, because reporting success for a setting the gateway was never asked to apply would leave
|
|
1578
|
+
// the caller's documents expiring on the old policy.
|
|
1579
|
+
if (request.max_expiry.has_value()) {
|
|
1580
|
+
std::error_code refusal{};
|
|
1581
|
+
if (*request.max_expiry < -1) {
|
|
1582
|
+
refusal = errc::common::invalid_argument;
|
|
1583
|
+
} else if (*request.max_expiry == 0) {
|
|
1584
|
+
refusal = errc::common::feature_not_available;
|
|
1585
|
+
}
|
|
1586
|
+
if (refusal) {
|
|
1587
|
+
auto response = stamped_management(request);
|
|
1588
|
+
response.ctx.ec = refusal;
|
|
1589
|
+
// Posted rather than invoked inline, so the completion arrives on the SDK's execution context
|
|
1590
|
+
// after the caller holds its pending_call.
|
|
1591
|
+
asio::post(io_, [handler = std::move(handler), response = std::move(response)]() mutable {
|
|
1592
|
+
handler(std::move(response));
|
|
1593
|
+
});
|
|
1594
|
+
return {};
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
auto proto = std::make_shared<collection_admin_v1::UpdateCollectionRequest>();
|
|
1599
|
+
proto->set_bucket_name(request.bucket_name);
|
|
1600
|
+
proto->set_scope_name(request.scope_name);
|
|
1601
|
+
proto->set_collection_name(request.collection_name);
|
|
1602
|
+
// Zero is refused above, so what reaches here is a no-expiry sentinel or a positive TTL, and
|
|
1603
|
+
// both of those encode to a value.
|
|
1604
|
+
if (request.max_expiry.has_value()) {
|
|
1605
|
+
if (const auto secs = collection_admin::encode_max_expiry(*request.max_expiry);
|
|
1606
|
+
secs.has_value()) {
|
|
1607
|
+
proto->set_max_expiry_secs(secs.value());
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
if (request.history.has_value()) {
|
|
1611
|
+
proto->set_history_retention_enabled(*request.history);
|
|
1612
|
+
}
|
|
1613
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1614
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1615
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1616
|
+
}
|
|
1617
|
+
const auto auth = authorization_;
|
|
1618
|
+
auto* stub = stubs_->collection_admin.get();
|
|
1619
|
+
return dispatcher_.unary<collection_admin_v1::UpdateCollectionResponse>(
|
|
1620
|
+
timeout,
|
|
1621
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1622
|
+
collection_admin_v1::UpdateCollectionResponse& resp,
|
|
1623
|
+
std::function<void(grpc::Status)> cb) {
|
|
1624
|
+
if (!auth.empty()) {
|
|
1625
|
+
ctx.AddMetadata("authorization", auth);
|
|
1626
|
+
}
|
|
1627
|
+
stub->async()->UpdateCollection(&ctx, proto.get(), &resp, std::move(cb));
|
|
1628
|
+
},
|
|
1629
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
1630
|
+
grpc::Status status, collection_admin_v1::UpdateCollectionResponse resp) mutable {
|
|
1631
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1632
|
+
operations::management::collection_update_response response;
|
|
1633
|
+
response.ctx.client_context_id = client_context_id;
|
|
1634
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
1635
|
+
response.uid = resp.manifest_uid();
|
|
1636
|
+
handler(std::move(response));
|
|
1637
|
+
});
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
auto
|
|
1641
|
+
component::execute(
|
|
1642
|
+
const operations::management::collection_drop_request& request,
|
|
1643
|
+
utils::movable_function<void(operations::management::collection_drop_response)>&& handler)
|
|
1644
|
+
-> pending_call
|
|
1645
|
+
{
|
|
1646
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1647
|
+
auto proto = std::make_shared<collection_admin_v1::DeleteCollectionRequest>();
|
|
1648
|
+
proto->set_bucket_name(request.bucket_name);
|
|
1649
|
+
proto->set_scope_name(request.scope_name);
|
|
1650
|
+
proto->set_collection_name(request.collection_name);
|
|
1651
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1652
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1653
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1654
|
+
}
|
|
1655
|
+
const auto auth = authorization_;
|
|
1656
|
+
auto* stub = stubs_->collection_admin.get();
|
|
1657
|
+
return dispatcher_.unary<collection_admin_v1::DeleteCollectionResponse>(
|
|
1658
|
+
timeout,
|
|
1659
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1660
|
+
collection_admin_v1::DeleteCollectionResponse& resp,
|
|
1661
|
+
std::function<void(grpc::Status)> cb) {
|
|
1662
|
+
if (!auth.empty()) {
|
|
1663
|
+
ctx.AddMetadata("authorization", auth);
|
|
1664
|
+
}
|
|
1665
|
+
stub->async()->DeleteCollection(&ctx, proto.get(), &resp, std::move(cb));
|
|
1666
|
+
},
|
|
1667
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
1668
|
+
grpc::Status status, collection_admin_v1::DeleteCollectionResponse resp) mutable {
|
|
1669
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1670
|
+
operations::management::collection_drop_response response;
|
|
1671
|
+
response.ctx.client_context_id = client_context_id;
|
|
1672
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
1673
|
+
response.uid = resp.manifest_uid();
|
|
1674
|
+
handler(std::move(response));
|
|
1675
|
+
});
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
auto
|
|
1679
|
+
component::execute(
|
|
1680
|
+
const operations::management::query_index_get_all_request& request,
|
|
1681
|
+
utils::movable_function<void(operations::management::query_index_get_all_response)>&& handler)
|
|
1682
|
+
-> pending_call
|
|
1683
|
+
{
|
|
1684
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1685
|
+
auto proto = std::make_shared<query_admin_v1::GetAllIndexesRequest>(
|
|
1686
|
+
query_index_admin::encode_get_all(request));
|
|
1687
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1688
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1689
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1690
|
+
}
|
|
1691
|
+
const auto auth = authorization_;
|
|
1692
|
+
auto* stub = stubs_->query_admin.get();
|
|
1693
|
+
return dispatcher_.unary<query_admin_v1::GetAllIndexesResponse>(
|
|
1694
|
+
timeout,
|
|
1695
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1696
|
+
query_admin_v1::GetAllIndexesResponse& resp,
|
|
1697
|
+
std::function<void(grpc::Status)> cb) {
|
|
1698
|
+
if (!auth.empty()) {
|
|
1699
|
+
ctx.AddMetadata("authorization", auth);
|
|
1700
|
+
}
|
|
1701
|
+
stub->async()->GetAllIndexes(&ctx, proto.get(), &resp, std::move(cb));
|
|
1702
|
+
},
|
|
1703
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
1704
|
+
grpc::Status status, query_admin_v1::GetAllIndexesResponse resp) mutable {
|
|
1705
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1706
|
+
operations::management::query_index_get_all_response response;
|
|
1707
|
+
response.ctx.client_context_id = client_context_id;
|
|
1708
|
+
response.ctx.ec = map_status(status, operation_kind::read_only);
|
|
1709
|
+
for (const auto& index : resp.indexes()) {
|
|
1710
|
+
response.indexes.push_back(query_index_admin::decode_index(index));
|
|
1711
|
+
}
|
|
1712
|
+
handler(std::move(response));
|
|
1713
|
+
});
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
auto
|
|
1717
|
+
component::execute(
|
|
1718
|
+
const operations::management::query_index_create_request& request,
|
|
1719
|
+
utils::movable_function<void(operations::management::query_index_create_response)>&& handler)
|
|
1720
|
+
-> pending_call
|
|
1721
|
+
{
|
|
1722
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1723
|
+
if (!query_index_admin::can_encode(request)) {
|
|
1724
|
+
auto response = stamped_management(request);
|
|
1725
|
+
response.ctx.ec = errc::common::feature_not_available;
|
|
1726
|
+
// Posted rather than invoked here, for the reason fail_expired above gives: completions arrive
|
|
1727
|
+
// on the io context, never inline out of execute().
|
|
1728
|
+
asio::post(io_, [handler = std::move(handler), response = std::move(response)]() mutable {
|
|
1729
|
+
handler(std::move(response));
|
|
1730
|
+
});
|
|
1731
|
+
return {};
|
|
1732
|
+
}
|
|
1733
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1734
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1735
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1736
|
+
}
|
|
1737
|
+
const auto auth = authorization_;
|
|
1738
|
+
auto* stub = stubs_->query_admin.get();
|
|
1739
|
+
|
|
1740
|
+
if (request.is_primary) {
|
|
1741
|
+
auto proto = std::make_shared<query_admin_v1::CreatePrimaryIndexRequest>(
|
|
1742
|
+
query_index_admin::encode_create_primary(request));
|
|
1743
|
+
return dispatcher_.unary<query_admin_v1::CreatePrimaryIndexResponse>(
|
|
1744
|
+
timeout,
|
|
1745
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1746
|
+
query_admin_v1::CreatePrimaryIndexResponse& resp,
|
|
1747
|
+
std::function<void(grpc::Status)> cb) {
|
|
1748
|
+
if (!auth.empty()) {
|
|
1749
|
+
ctx.AddMetadata("authorization", auth);
|
|
1750
|
+
}
|
|
1751
|
+
stub->async()->CreatePrimaryIndex(&ctx, proto.get(), &resp, std::move(cb));
|
|
1752
|
+
},
|
|
1753
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
1754
|
+
grpc::Status status, query_admin_v1::CreatePrimaryIndexResponse /* resp */) mutable {
|
|
1755
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1756
|
+
operations::management::query_index_create_response response;
|
|
1757
|
+
response.ctx.client_context_id = client_context_id;
|
|
1758
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
1759
|
+
handler(std::move(response));
|
|
1760
|
+
});
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
auto proto =
|
|
1764
|
+
std::make_shared<query_admin_v1::CreateIndexRequest>(query_index_admin::encode_create(request));
|
|
1765
|
+
return dispatcher_.unary<query_admin_v1::CreateIndexResponse>(
|
|
1766
|
+
timeout,
|
|
1767
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1768
|
+
query_admin_v1::CreateIndexResponse& resp,
|
|
1769
|
+
std::function<void(grpc::Status)> cb) {
|
|
1770
|
+
if (!auth.empty()) {
|
|
1771
|
+
ctx.AddMetadata("authorization", auth);
|
|
1772
|
+
}
|
|
1773
|
+
stub->async()->CreateIndex(&ctx, proto.get(), &resp, std::move(cb));
|
|
1774
|
+
},
|
|
1775
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
1776
|
+
grpc::Status status, query_admin_v1::CreateIndexResponse /* resp */) mutable {
|
|
1777
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1778
|
+
operations::management::query_index_create_response response;
|
|
1779
|
+
response.ctx.client_context_id = client_context_id;
|
|
1780
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
1781
|
+
handler(std::move(response));
|
|
1782
|
+
});
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
auto
|
|
1786
|
+
component::execute(
|
|
1787
|
+
const operations::management::query_index_drop_request& request,
|
|
1788
|
+
utils::movable_function<void(operations::management::query_index_drop_response)>&& handler)
|
|
1789
|
+
-> pending_call
|
|
1790
|
+
{
|
|
1791
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1792
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1793
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1794
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1795
|
+
}
|
|
1796
|
+
const auto auth = authorization_;
|
|
1797
|
+
auto* stub = stubs_->query_admin.get();
|
|
1798
|
+
|
|
1799
|
+
if (request.is_primary) {
|
|
1800
|
+
auto proto = std::make_shared<query_admin_v1::DropPrimaryIndexRequest>(
|
|
1801
|
+
query_index_admin::encode_drop_primary(request));
|
|
1802
|
+
return dispatcher_.unary<query_admin_v1::DropPrimaryIndexResponse>(
|
|
1803
|
+
timeout,
|
|
1804
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1805
|
+
query_admin_v1::DropPrimaryIndexResponse& resp,
|
|
1806
|
+
std::function<void(grpc::Status)> cb) {
|
|
1807
|
+
if (!auth.empty()) {
|
|
1808
|
+
ctx.AddMetadata("authorization", auth);
|
|
1809
|
+
}
|
|
1810
|
+
stub->async()->DropPrimaryIndex(&ctx, proto.get(), &resp, std::move(cb));
|
|
1811
|
+
},
|
|
1812
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
1813
|
+
grpc::Status status, query_admin_v1::DropPrimaryIndexResponse /* resp */) mutable {
|
|
1814
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1815
|
+
operations::management::query_index_drop_response response;
|
|
1816
|
+
response.ctx.client_context_id = client_context_id;
|
|
1817
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
1818
|
+
handler(std::move(response));
|
|
1819
|
+
});
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
auto proto =
|
|
1823
|
+
std::make_shared<query_admin_v1::DropIndexRequest>(query_index_admin::encode_drop(request));
|
|
1824
|
+
return dispatcher_.unary<query_admin_v1::DropIndexResponse>(
|
|
1825
|
+
timeout,
|
|
1826
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1827
|
+
query_admin_v1::DropIndexResponse& resp,
|
|
1828
|
+
std::function<void(grpc::Status)> cb) {
|
|
1829
|
+
if (!auth.empty()) {
|
|
1830
|
+
ctx.AddMetadata("authorization", auth);
|
|
1831
|
+
}
|
|
1832
|
+
stub->async()->DropIndex(&ctx, proto.get(), &resp, std::move(cb));
|
|
1833
|
+
},
|
|
1834
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
1835
|
+
grpc::Status status, query_admin_v1::DropIndexResponse /* resp */) mutable {
|
|
1836
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1837
|
+
operations::management::query_index_drop_response response;
|
|
1838
|
+
response.ctx.client_context_id = client_context_id;
|
|
1839
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
1840
|
+
handler(std::move(response));
|
|
1841
|
+
});
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
auto
|
|
1845
|
+
component::execute(
|
|
1846
|
+
const operations::management::query_index_build_deferred_request& request,
|
|
1847
|
+
utils::movable_function<void(operations::management::query_index_build_deferred_response)>&&
|
|
1848
|
+
handler) -> pending_call
|
|
1849
|
+
{
|
|
1850
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1851
|
+
auto proto = std::make_shared<query_admin_v1::BuildDeferredIndexesRequest>(
|
|
1852
|
+
query_index_admin::encode_build_deferred(request));
|
|
1853
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1854
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1855
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1856
|
+
}
|
|
1857
|
+
const auto auth = authorization_;
|
|
1858
|
+
auto* stub = stubs_->query_admin.get();
|
|
1859
|
+
return dispatcher_.unary<query_admin_v1::BuildDeferredIndexesResponse>(
|
|
1860
|
+
timeout,
|
|
1861
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
1862
|
+
query_admin_v1::BuildDeferredIndexesResponse& resp,
|
|
1863
|
+
std::function<void(grpc::Status)> cb) {
|
|
1864
|
+
if (!auth.empty()) {
|
|
1865
|
+
ctx.AddMetadata("authorization", auth);
|
|
1866
|
+
}
|
|
1867
|
+
stub->async()->BuildDeferredIndexes(&ctx, proto.get(), &resp, std::move(cb));
|
|
1868
|
+
},
|
|
1869
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
1870
|
+
grpc::Status status, query_admin_v1::BuildDeferredIndexesResponse /* resp */) mutable {
|
|
1871
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
1872
|
+
operations::management::query_index_build_deferred_response response;
|
|
1873
|
+
response.ctx.client_context_id = client_context_id;
|
|
1874
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
1875
|
+
handler(std::move(response));
|
|
1876
|
+
});
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
auto
|
|
1880
|
+
component::execute(
|
|
1881
|
+
const operations::management::search_index_upsert_request& request,
|
|
1882
|
+
utils::movable_function<void(operations::management::search_index_upsert_response)>&& handler)
|
|
1883
|
+
-> pending_call
|
|
1884
|
+
{
|
|
1885
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1886
|
+
if (request.index.name.empty()) {
|
|
1887
|
+
return fail_ctx(io_, handler, stamped_management(request), errc::common::invalid_argument);
|
|
1888
|
+
}
|
|
1889
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1890
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1891
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1892
|
+
}
|
|
1893
|
+
const auto auth = authorization_;
|
|
1894
|
+
const auto name = request.index.name;
|
|
1895
|
+
auto* stub = stubs_->search_admin.get();
|
|
1896
|
+
|
|
1897
|
+
// A uuid identifies a definition that already exists, so an upsert carrying one is an update and
|
|
1898
|
+
// an upsert without one is a create. That is the same rule the classic path applies -- it sends
|
|
1899
|
+
// the uuid as the body's "uuid" member, which FTS reads as prevIndexUUID -- and the two RPCs
|
|
1900
|
+
// divide along the same line: UpdateIndex refuses a request with no uuid, and CreateIndex refuses
|
|
1901
|
+
// a name that already exists.
|
|
1902
|
+
//
|
|
1903
|
+
// The proto is built before the handler is moved into the completion, so a definition the
|
|
1904
|
+
// converter refuses is still reported through the handler the caller passed.
|
|
1905
|
+
std::shared_ptr<search_admin_v1::UpdateIndexRequest> update_proto;
|
|
1906
|
+
std::shared_ptr<search_admin_v1::CreateIndexRequest> create_proto;
|
|
1907
|
+
if (!request.index.uuid.empty()) {
|
|
1908
|
+
update_proto = std::make_shared<search_admin_v1::UpdateIndexRequest>();
|
|
1909
|
+
if (!search_index_admin::apply_index(request.index, *update_proto->mutable_index())) {
|
|
1910
|
+
return fail_ctx(io_, handler, stamped_management(request), errc::common::invalid_argument);
|
|
1911
|
+
}
|
|
1912
|
+
if (request.bucket_name.has_value()) {
|
|
1913
|
+
update_proto->set_bucket_name(*request.bucket_name);
|
|
1914
|
+
}
|
|
1915
|
+
if (request.scope_name.has_value()) {
|
|
1916
|
+
update_proto->set_scope_name(*request.scope_name);
|
|
1917
|
+
}
|
|
1918
|
+
} else {
|
|
1919
|
+
create_proto = std::make_shared<search_admin_v1::CreateIndexRequest>();
|
|
1920
|
+
if (!search_index_admin::apply_index(request.index, *create_proto)) {
|
|
1921
|
+
return fail_ctx(io_, handler, stamped_management(request), errc::common::invalid_argument);
|
|
1922
|
+
}
|
|
1923
|
+
if (request.bucket_name.has_value()) {
|
|
1924
|
+
create_proto->set_bucket_name(*request.bucket_name);
|
|
1925
|
+
}
|
|
1926
|
+
if (request.scope_name.has_value()) {
|
|
1927
|
+
create_proto->set_scope_name(*request.scope_name);
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
auto invoke =
|
|
1932
|
+
[handler = std::move(handler), client_context_id, name](grpc::Status status) mutable {
|
|
1933
|
+
operations::management::search_index_upsert_response response;
|
|
1934
|
+
response.ctx.client_context_id = client_context_id;
|
|
1935
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
1936
|
+
response.name = name;
|
|
1937
|
+
set_ok_status(response);
|
|
1938
|
+
handler(std::move(response));
|
|
1939
|
+
};
|
|
1940
|
+
|
|
1941
|
+
if (update_proto) {
|
|
1942
|
+
return dispatcher_.unary<search_admin_v1::UpdateIndexResponse>(
|
|
1943
|
+
timeout,
|
|
1944
|
+
[stub, proto = update_proto, auth](grpc::ClientContext& ctx,
|
|
1945
|
+
search_admin_v1::UpdateIndexResponse& resp,
|
|
1946
|
+
std::function<void(grpc::Status)> cb) {
|
|
1947
|
+
if (!auth.empty()) {
|
|
1948
|
+
ctx.AddMetadata("authorization", auth);
|
|
1949
|
+
}
|
|
1950
|
+
stub->async()->UpdateIndex(&ctx, proto.get(), &resp, std::move(cb));
|
|
1951
|
+
},
|
|
1952
|
+
[invoke = std::move(invoke), proto = update_proto](
|
|
1953
|
+
grpc::Status status, search_admin_v1::UpdateIndexResponse /* r */) mutable {
|
|
1954
|
+
invoke(std::move(status));
|
|
1955
|
+
});
|
|
1956
|
+
}
|
|
1957
|
+
return dispatcher_.unary<search_admin_v1::CreateIndexResponse>(
|
|
1958
|
+
timeout,
|
|
1959
|
+
[stub, proto = create_proto, auth](grpc::ClientContext& ctx,
|
|
1960
|
+
search_admin_v1::CreateIndexResponse& resp,
|
|
1961
|
+
std::function<void(grpc::Status)> cb) {
|
|
1962
|
+
if (!auth.empty()) {
|
|
1963
|
+
ctx.AddMetadata("authorization", auth);
|
|
1964
|
+
}
|
|
1965
|
+
stub->async()->CreateIndex(&ctx, proto.get(), &resp, std::move(cb));
|
|
1966
|
+
},
|
|
1967
|
+
[invoke = std::move(invoke), proto = create_proto](
|
|
1968
|
+
grpc::Status status, search_admin_v1::CreateIndexResponse /* r */) mutable {
|
|
1969
|
+
invoke(std::move(status));
|
|
1970
|
+
});
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
auto
|
|
1974
|
+
component::execute(
|
|
1975
|
+
const operations::management::search_index_get_request& request,
|
|
1976
|
+
utils::movable_function<void(operations::management::search_index_get_response)>&& handler)
|
|
1977
|
+
-> pending_call
|
|
1978
|
+
{
|
|
1979
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
1980
|
+
if (request.index_name.empty()) {
|
|
1981
|
+
return fail_ctx(io_, handler, stamped_management(request), errc::common::invalid_argument);
|
|
1982
|
+
}
|
|
1983
|
+
auto proto = std::make_shared<search_admin_v1::GetIndexRequest>();
|
|
1984
|
+
proto->set_name(request.index_name);
|
|
1985
|
+
if (request.bucket_name.has_value()) {
|
|
1986
|
+
proto->set_bucket_name(*request.bucket_name);
|
|
1987
|
+
}
|
|
1988
|
+
if (request.scope_name.has_value()) {
|
|
1989
|
+
proto->set_scope_name(*request.scope_name);
|
|
1990
|
+
}
|
|
1991
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
1992
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
1993
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
1994
|
+
}
|
|
1995
|
+
const auto auth = authorization_;
|
|
1996
|
+
auto* stub = stubs_->search_admin.get();
|
|
1997
|
+
return dispatcher_.unary<search_admin_v1::GetIndexResponse>(
|
|
1998
|
+
timeout,
|
|
1999
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
2000
|
+
search_admin_v1::GetIndexResponse& resp,
|
|
2001
|
+
std::function<void(grpc::Status)> cb) {
|
|
2002
|
+
if (!auth.empty()) {
|
|
2003
|
+
ctx.AddMetadata("authorization", auth);
|
|
2004
|
+
}
|
|
2005
|
+
stub->async()->GetIndex(&ctx, proto.get(), &resp, std::move(cb));
|
|
2006
|
+
},
|
|
2007
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
2008
|
+
grpc::Status status, search_admin_v1::GetIndexResponse resp) mutable {
|
|
2009
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
2010
|
+
operations::management::search_index_get_response response;
|
|
2011
|
+
response.ctx.client_context_id = client_context_id;
|
|
2012
|
+
response.ctx.ec = map_status(status, operation_kind::read_only);
|
|
2013
|
+
if (!response.ctx.ec) {
|
|
2014
|
+
// A success carrying no index describes no index. Reporting it as one -- the response
|
|
2015
|
+
// would hold a default-constructed definition with an empty name -- is worse than saying
|
|
2016
|
+
// the index is not there.
|
|
2017
|
+
if (!resp.has_index()) {
|
|
2018
|
+
response.ctx.ec = errc::common::index_not_found;
|
|
2019
|
+
} else if (auto index = search_index_admin::decode_index(resp.index()); index.has_value()) {
|
|
2020
|
+
response.index = std::move(*index);
|
|
2021
|
+
} else {
|
|
2022
|
+
response.ctx.ec = errc::common::parsing_failure;
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
set_ok_status(response);
|
|
2026
|
+
handler(std::move(response));
|
|
2027
|
+
});
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
auto
|
|
2031
|
+
component::execute(
|
|
2032
|
+
const operations::management::search_index_get_all_request& request,
|
|
2033
|
+
utils::movable_function<void(operations::management::search_index_get_all_response)>&& handler)
|
|
2034
|
+
-> pending_call
|
|
2035
|
+
{
|
|
2036
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
2037
|
+
auto proto = std::make_shared<search_admin_v1::ListIndexesRequest>();
|
|
2038
|
+
if (request.bucket_name.has_value()) {
|
|
2039
|
+
proto->set_bucket_name(*request.bucket_name);
|
|
2040
|
+
}
|
|
2041
|
+
if (request.scope_name.has_value()) {
|
|
2042
|
+
proto->set_scope_name(*request.scope_name);
|
|
2043
|
+
}
|
|
2044
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
2045
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
2046
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
2047
|
+
}
|
|
2048
|
+
const auto auth = authorization_;
|
|
2049
|
+
auto* stub = stubs_->search_admin.get();
|
|
2050
|
+
return dispatcher_.unary<search_admin_v1::ListIndexesResponse>(
|
|
2051
|
+
timeout,
|
|
2052
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
2053
|
+
search_admin_v1::ListIndexesResponse& resp,
|
|
2054
|
+
std::function<void(grpc::Status)> cb) {
|
|
2055
|
+
if (!auth.empty()) {
|
|
2056
|
+
ctx.AddMetadata("authorization", auth);
|
|
2057
|
+
}
|
|
2058
|
+
stub->async()->ListIndexes(&ctx, proto.get(), &resp, std::move(cb));
|
|
2059
|
+
},
|
|
2060
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
2061
|
+
grpc::Status status, search_admin_v1::ListIndexesResponse resp) mutable {
|
|
2062
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
2063
|
+
operations::management::search_index_get_all_response response;
|
|
2064
|
+
response.ctx.client_context_id = client_context_id;
|
|
2065
|
+
response.ctx.ec = map_status(status, operation_kind::read_only);
|
|
2066
|
+
for (const auto& index : resp.indexes()) {
|
|
2067
|
+
auto decoded = search_index_admin::decode_index(index);
|
|
2068
|
+
if (!decoded.has_value()) {
|
|
2069
|
+
// One definition that cannot be represented fails the listing. Skipping it would return
|
|
2070
|
+
// a list shorter than the server's, which reads as "that index does not exist".
|
|
2071
|
+
response.ctx.ec = errc::common::parsing_failure;
|
|
2072
|
+
response.indexes.clear();
|
|
2073
|
+
break;
|
|
2074
|
+
}
|
|
2075
|
+
response.indexes.push_back(std::move(*decoded));
|
|
2076
|
+
}
|
|
2077
|
+
set_ok_status(response);
|
|
2078
|
+
handler(std::move(response));
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
auto
|
|
2083
|
+
component::execute(
|
|
2084
|
+
const operations::management::search_index_drop_request& request,
|
|
2085
|
+
utils::movable_function<void(operations::management::search_index_drop_response)>&& handler)
|
|
2086
|
+
-> pending_call
|
|
2087
|
+
{
|
|
2088
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
2089
|
+
if (request.index_name.empty()) {
|
|
2090
|
+
return fail_ctx(io_, handler, stamped_management(request), errc::common::invalid_argument);
|
|
2091
|
+
}
|
|
2092
|
+
auto proto = std::make_shared<search_admin_v1::DeleteIndexRequest>();
|
|
2093
|
+
proto->set_name(request.index_name);
|
|
2094
|
+
if (request.bucket_name.has_value()) {
|
|
2095
|
+
proto->set_bucket_name(*request.bucket_name);
|
|
2096
|
+
}
|
|
2097
|
+
if (request.scope_name.has_value()) {
|
|
2098
|
+
proto->set_scope_name(*request.scope_name);
|
|
2099
|
+
}
|
|
2100
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
2101
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
2102
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
2103
|
+
}
|
|
2104
|
+
const auto auth = authorization_;
|
|
2105
|
+
auto* stub = stubs_->search_admin.get();
|
|
2106
|
+
return dispatcher_.unary<search_admin_v1::DeleteIndexResponse>(
|
|
2107
|
+
timeout,
|
|
2108
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
2109
|
+
search_admin_v1::DeleteIndexResponse& resp,
|
|
2110
|
+
std::function<void(grpc::Status)> cb) {
|
|
2111
|
+
if (!auth.empty()) {
|
|
2112
|
+
ctx.AddMetadata("authorization", auth);
|
|
2113
|
+
}
|
|
2114
|
+
stub->async()->DeleteIndex(&ctx, proto.get(), &resp, std::move(cb));
|
|
2115
|
+
},
|
|
2116
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
2117
|
+
grpc::Status status, search_admin_v1::DeleteIndexResponse /* r */) mutable {
|
|
2118
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
2119
|
+
operations::management::search_index_drop_response response;
|
|
2120
|
+
response.ctx.client_context_id = client_context_id;
|
|
2121
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
2122
|
+
set_ok_status(response);
|
|
2123
|
+
handler(std::move(response));
|
|
2124
|
+
});
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2127
|
+
auto
|
|
2128
|
+
component::execute(
|
|
2129
|
+
const operations::management::search_index_analyze_document_request& request,
|
|
2130
|
+
utils::movable_function<void(operations::management::search_index_analyze_document_response)>&&
|
|
2131
|
+
handler) -> pending_call
|
|
2132
|
+
{
|
|
2133
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
2134
|
+
if (request.index_name.empty()) {
|
|
2135
|
+
return fail_ctx(io_, handler, stamped_management(request), errc::common::invalid_argument);
|
|
2136
|
+
}
|
|
2137
|
+
auto proto = std::make_shared<search_admin_v1::AnalyzeDocumentRequest>();
|
|
2138
|
+
proto->set_name(request.index_name);
|
|
2139
|
+
proto->set_doc(request.encoded_document);
|
|
2140
|
+
if (request.bucket_name.has_value()) {
|
|
2141
|
+
proto->set_bucket_name(*request.bucket_name);
|
|
2142
|
+
}
|
|
2143
|
+
if (request.scope_name.has_value()) {
|
|
2144
|
+
proto->set_scope_name(*request.scope_name);
|
|
2145
|
+
}
|
|
2146
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
2147
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
2148
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
2149
|
+
}
|
|
2150
|
+
const auto auth = authorization_;
|
|
2151
|
+
auto* stub = stubs_->search_admin.get();
|
|
2152
|
+
return dispatcher_.unary<search_admin_v1::AnalyzeDocumentResponse>(
|
|
2153
|
+
timeout,
|
|
2154
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
2155
|
+
search_admin_v1::AnalyzeDocumentResponse& resp,
|
|
2156
|
+
std::function<void(grpc::Status)> cb) {
|
|
2157
|
+
if (!auth.empty()) {
|
|
2158
|
+
ctx.AddMetadata("authorization", auth);
|
|
2159
|
+
}
|
|
2160
|
+
stub->async()->AnalyzeDocument(&ctx, proto.get(), &resp, std::move(cb));
|
|
2161
|
+
},
|
|
2162
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
2163
|
+
grpc::Status status, search_admin_v1::AnalyzeDocumentResponse resp) mutable {
|
|
2164
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
2165
|
+
operations::management::search_index_analyze_document_response response;
|
|
2166
|
+
response.ctx.client_context_id = client_context_id;
|
|
2167
|
+
response.ctx.ec = map_status(status, operation_kind::read_only);
|
|
2168
|
+
response.analysis = resp.analyzed();
|
|
2169
|
+
// The only response in this service that relays FTS's own status string; the rest infer it
|
|
2170
|
+
// from the RPC. Prefer what the server said, and fall back only when it said nothing.
|
|
2171
|
+
if (!response.ctx.ec && !resp.status().empty()) {
|
|
2172
|
+
response.status = resp.status();
|
|
2173
|
+
} else {
|
|
2174
|
+
set_ok_status(response);
|
|
2175
|
+
}
|
|
2176
|
+
handler(std::move(response));
|
|
2177
|
+
});
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
auto
|
|
2181
|
+
component::execute(
|
|
2182
|
+
const operations::management::search_index_get_documents_count_request& request,
|
|
2183
|
+
utils::movable_function<void(operations::management::search_index_get_documents_count_response)>&&
|
|
2184
|
+
handler) -> pending_call
|
|
2185
|
+
{
|
|
2186
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
2187
|
+
auto proto = std::make_shared<search_admin_v1::GetIndexedDocumentsCountRequest>();
|
|
2188
|
+
proto->set_name(request.index_name);
|
|
2189
|
+
if (request.bucket_name.has_value()) {
|
|
2190
|
+
proto->set_bucket_name(*request.bucket_name);
|
|
2191
|
+
}
|
|
2192
|
+
if (request.scope_name.has_value()) {
|
|
2193
|
+
proto->set_scope_name(*request.scope_name);
|
|
2194
|
+
}
|
|
2195
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
2196
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
2197
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
2198
|
+
}
|
|
2199
|
+
const auto auth = authorization_;
|
|
2200
|
+
auto* stub = stubs_->search_admin.get();
|
|
2201
|
+
return dispatcher_.unary<search_admin_v1::GetIndexedDocumentsCountResponse>(
|
|
2202
|
+
timeout,
|
|
2203
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
2204
|
+
search_admin_v1::GetIndexedDocumentsCountResponse& resp,
|
|
2205
|
+
std::function<void(grpc::Status)> cb) {
|
|
2206
|
+
if (!auth.empty()) {
|
|
2207
|
+
ctx.AddMetadata("authorization", auth);
|
|
2208
|
+
}
|
|
2209
|
+
stub->async()->GetIndexedDocumentsCount(&ctx, proto.get(), &resp, std::move(cb));
|
|
2210
|
+
},
|
|
2211
|
+
[handler = std::move(handler), proto, client_context_id](
|
|
2212
|
+
grpc::Status status, search_admin_v1::GetIndexedDocumentsCountResponse resp) mutable {
|
|
2213
|
+
(void)proto; // kept only to keep the request alive for the call
|
|
2214
|
+
operations::management::search_index_get_documents_count_response response;
|
|
2215
|
+
response.ctx.client_context_id = client_context_id;
|
|
2216
|
+
response.ctx.ec = map_status(status, operation_kind::read_only);
|
|
2217
|
+
response.count = resp.count();
|
|
2218
|
+
set_ok_status(response);
|
|
2219
|
+
handler(std::move(response));
|
|
2220
|
+
});
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
auto
|
|
2224
|
+
component::execute(
|
|
2225
|
+
const operations::management::search_index_control_ingest_request& request,
|
|
2226
|
+
utils::movable_function<void(operations::management::search_index_control_ingest_response)>&&
|
|
2227
|
+
handler) -> pending_call
|
|
2228
|
+
{
|
|
2229
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
2230
|
+
if (request.index_name.empty()) {
|
|
2231
|
+
return fail_ctx(io_, handler, stamped_management(request), errc::common::invalid_argument);
|
|
2232
|
+
}
|
|
2233
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
2234
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
2235
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
2236
|
+
}
|
|
2237
|
+
const auto auth = authorization_;
|
|
2238
|
+
const auto name = request.index_name;
|
|
2239
|
+
const auto bucket = request.bucket_name;
|
|
2240
|
+
const auto scope = request.scope_name;
|
|
2241
|
+
auto* stub = stubs_->search_admin.get();
|
|
2242
|
+
auto invoke = [handler = std::move(handler), client_context_id](grpc::Status status) mutable {
|
|
2243
|
+
operations::management::search_index_control_ingest_response response;
|
|
2244
|
+
response.ctx.client_context_id = client_context_id;
|
|
2245
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
2246
|
+
set_ok_status(response);
|
|
2247
|
+
handler(std::move(response));
|
|
2248
|
+
};
|
|
2249
|
+
if (request.pause) {
|
|
2250
|
+
auto proto = std::make_shared<search_admin_v1::PauseIndexIngestRequest>();
|
|
2251
|
+
proto->set_name(name);
|
|
2252
|
+
if (bucket.has_value()) {
|
|
2253
|
+
proto->set_bucket_name(*bucket);
|
|
2254
|
+
}
|
|
2255
|
+
if (scope.has_value()) {
|
|
2256
|
+
proto->set_scope_name(*scope);
|
|
2257
|
+
}
|
|
2258
|
+
return dispatcher_.unary<search_admin_v1::PauseIndexIngestResponse>(
|
|
2259
|
+
timeout,
|
|
2260
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
2261
|
+
search_admin_v1::PauseIndexIngestResponse& resp,
|
|
2262
|
+
std::function<void(grpc::Status)> cb) {
|
|
2263
|
+
if (!auth.empty()) {
|
|
2264
|
+
ctx.AddMetadata("authorization", auth);
|
|
2265
|
+
}
|
|
2266
|
+
stub->async()->PauseIndexIngest(&ctx, proto.get(), &resp, std::move(cb));
|
|
2267
|
+
},
|
|
2268
|
+
[invoke = std::move(invoke),
|
|
2269
|
+
proto](grpc::Status status, search_admin_v1::PauseIndexIngestResponse /* r */) mutable {
|
|
2270
|
+
invoke(std::move(status));
|
|
2271
|
+
});
|
|
2272
|
+
}
|
|
2273
|
+
auto proto = std::make_shared<search_admin_v1::ResumeIndexIngestRequest>();
|
|
2274
|
+
proto->set_name(name);
|
|
2275
|
+
if (bucket.has_value()) {
|
|
2276
|
+
proto->set_bucket_name(*bucket);
|
|
2277
|
+
}
|
|
2278
|
+
if (scope.has_value()) {
|
|
2279
|
+
proto->set_scope_name(*scope);
|
|
2280
|
+
}
|
|
2281
|
+
return dispatcher_.unary<search_admin_v1::ResumeIndexIngestResponse>(
|
|
2282
|
+
timeout,
|
|
2283
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
2284
|
+
search_admin_v1::ResumeIndexIngestResponse& resp,
|
|
2285
|
+
std::function<void(grpc::Status)> cb) {
|
|
2286
|
+
if (!auth.empty()) {
|
|
2287
|
+
ctx.AddMetadata("authorization", auth);
|
|
2288
|
+
}
|
|
2289
|
+
stub->async()->ResumeIndexIngest(&ctx, proto.get(), &resp, std::move(cb));
|
|
2290
|
+
},
|
|
2291
|
+
[invoke = std::move(invoke),
|
|
2292
|
+
proto](grpc::Status status, search_admin_v1::ResumeIndexIngestResponse /* r */) mutable {
|
|
2293
|
+
invoke(std::move(status));
|
|
2294
|
+
});
|
|
2295
|
+
}
|
|
2296
|
+
|
|
2297
|
+
auto
|
|
2298
|
+
component::execute(
|
|
2299
|
+
const operations::management::search_index_control_query_request& request,
|
|
2300
|
+
utils::movable_function<void(operations::management::search_index_control_query_response)>&&
|
|
2301
|
+
handler) -> pending_call
|
|
2302
|
+
{
|
|
2303
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
2304
|
+
if (request.index_name.empty()) {
|
|
2305
|
+
return fail_ctx(io_, handler, stamped_management(request), errc::common::invalid_argument);
|
|
2306
|
+
}
|
|
2307
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
2308
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
2309
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
2310
|
+
}
|
|
2311
|
+
const auto auth = authorization_;
|
|
2312
|
+
const auto name = request.index_name;
|
|
2313
|
+
const auto bucket = request.bucket_name;
|
|
2314
|
+
const auto scope = request.scope_name;
|
|
2315
|
+
auto* stub = stubs_->search_admin.get();
|
|
2316
|
+
auto invoke = [handler = std::move(handler), client_context_id](grpc::Status status) mutable {
|
|
2317
|
+
operations::management::search_index_control_query_response response;
|
|
2318
|
+
response.ctx.client_context_id = client_context_id;
|
|
2319
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
2320
|
+
set_ok_status(response);
|
|
2321
|
+
handler(std::move(response));
|
|
2322
|
+
};
|
|
2323
|
+
if (request.allow) {
|
|
2324
|
+
auto proto = std::make_shared<search_admin_v1::AllowIndexQueryingRequest>();
|
|
2325
|
+
proto->set_name(name);
|
|
2326
|
+
if (bucket.has_value()) {
|
|
2327
|
+
proto->set_bucket_name(*bucket);
|
|
2328
|
+
}
|
|
2329
|
+
if (scope.has_value()) {
|
|
2330
|
+
proto->set_scope_name(*scope);
|
|
2331
|
+
}
|
|
2332
|
+
return dispatcher_.unary<search_admin_v1::AllowIndexQueryingResponse>(
|
|
2333
|
+
timeout,
|
|
2334
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
2335
|
+
search_admin_v1::AllowIndexQueryingResponse& resp,
|
|
2336
|
+
std::function<void(grpc::Status)> cb) {
|
|
2337
|
+
if (!auth.empty()) {
|
|
2338
|
+
ctx.AddMetadata("authorization", auth);
|
|
2339
|
+
}
|
|
2340
|
+
stub->async()->AllowIndexQuerying(&ctx, proto.get(), &resp, std::move(cb));
|
|
2341
|
+
},
|
|
2342
|
+
[invoke = std::move(invoke),
|
|
2343
|
+
proto](grpc::Status status, search_admin_v1::AllowIndexQueryingResponse /* r */) mutable {
|
|
2344
|
+
invoke(std::move(status));
|
|
2345
|
+
});
|
|
2346
|
+
}
|
|
2347
|
+
auto proto = std::make_shared<search_admin_v1::DisallowIndexQueryingRequest>();
|
|
2348
|
+
proto->set_name(name);
|
|
2349
|
+
if (bucket.has_value()) {
|
|
2350
|
+
proto->set_bucket_name(*bucket);
|
|
2351
|
+
}
|
|
2352
|
+
if (scope.has_value()) {
|
|
2353
|
+
proto->set_scope_name(*scope);
|
|
2354
|
+
}
|
|
2355
|
+
return dispatcher_.unary<search_admin_v1::DisallowIndexQueryingResponse>(
|
|
2356
|
+
timeout,
|
|
2357
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
2358
|
+
search_admin_v1::DisallowIndexQueryingResponse& resp,
|
|
2359
|
+
std::function<void(grpc::Status)> cb) {
|
|
2360
|
+
if (!auth.empty()) {
|
|
2361
|
+
ctx.AddMetadata("authorization", auth);
|
|
2362
|
+
}
|
|
2363
|
+
stub->async()->DisallowIndexQuerying(&ctx, proto.get(), &resp, std::move(cb));
|
|
2364
|
+
},
|
|
2365
|
+
[invoke = std::move(invoke),
|
|
2366
|
+
proto](grpc::Status status, search_admin_v1::DisallowIndexQueryingResponse /* r */) mutable {
|
|
2367
|
+
invoke(std::move(status));
|
|
2368
|
+
});
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2371
|
+
auto
|
|
2372
|
+
component::execute(
|
|
2373
|
+
const operations::management::search_index_control_plan_freeze_request& request,
|
|
2374
|
+
utils::movable_function<void(operations::management::search_index_control_plan_freeze_response)>&&
|
|
2375
|
+
handler) -> pending_call
|
|
2376
|
+
{
|
|
2377
|
+
const auto client_context_id = request.client_context_id.value_or(std::string{});
|
|
2378
|
+
if (request.index_name.empty()) {
|
|
2379
|
+
return fail_ctx(io_, handler, stamped_management(request), errc::common::invalid_argument);
|
|
2380
|
+
}
|
|
2381
|
+
const auto timeout = request.timeout.value_or(timeouts_.management);
|
|
2382
|
+
if (timeout <= std::chrono::milliseconds::zero()) {
|
|
2383
|
+
return fail_expired_ctx(io_, handler, stamped_management(request));
|
|
2384
|
+
}
|
|
2385
|
+
const auto auth = authorization_;
|
|
2386
|
+
const auto name = request.index_name;
|
|
2387
|
+
const auto bucket = request.bucket_name;
|
|
2388
|
+
const auto scope = request.scope_name;
|
|
2389
|
+
auto* stub = stubs_->search_admin.get();
|
|
2390
|
+
auto invoke = [handler = std::move(handler), client_context_id](grpc::Status status) mutable {
|
|
2391
|
+
operations::management::search_index_control_plan_freeze_response response;
|
|
2392
|
+
response.ctx.client_context_id = client_context_id;
|
|
2393
|
+
response.ctx.ec = map_status(status, operation_kind::mutating);
|
|
2394
|
+
set_ok_status(response);
|
|
2395
|
+
handler(std::move(response));
|
|
2396
|
+
};
|
|
2397
|
+
if (request.freeze) {
|
|
2398
|
+
auto proto = std::make_shared<search_admin_v1::FreezeIndexPlanRequest>();
|
|
2399
|
+
proto->set_name(name);
|
|
2400
|
+
if (bucket.has_value()) {
|
|
2401
|
+
proto->set_bucket_name(*bucket);
|
|
2402
|
+
}
|
|
2403
|
+
if (scope.has_value()) {
|
|
2404
|
+
proto->set_scope_name(*scope);
|
|
2405
|
+
}
|
|
2406
|
+
return dispatcher_.unary<search_admin_v1::FreezeIndexPlanResponse>(
|
|
2407
|
+
timeout,
|
|
2408
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
2409
|
+
search_admin_v1::FreezeIndexPlanResponse& resp,
|
|
2410
|
+
std::function<void(grpc::Status)> cb) {
|
|
2411
|
+
if (!auth.empty()) {
|
|
2412
|
+
ctx.AddMetadata("authorization", auth);
|
|
2413
|
+
}
|
|
2414
|
+
stub->async()->FreezeIndexPlan(&ctx, proto.get(), &resp, std::move(cb));
|
|
2415
|
+
},
|
|
2416
|
+
[invoke = std::move(invoke),
|
|
2417
|
+
proto](grpc::Status status, search_admin_v1::FreezeIndexPlanResponse /* r */) mutable {
|
|
2418
|
+
invoke(std::move(status));
|
|
2419
|
+
});
|
|
2420
|
+
}
|
|
2421
|
+
auto proto = std::make_shared<search_admin_v1::UnfreezeIndexPlanRequest>();
|
|
2422
|
+
proto->set_name(name);
|
|
2423
|
+
if (bucket.has_value()) {
|
|
2424
|
+
proto->set_bucket_name(*bucket);
|
|
2425
|
+
}
|
|
2426
|
+
if (scope.has_value()) {
|
|
2427
|
+
proto->set_scope_name(*scope);
|
|
2428
|
+
}
|
|
2429
|
+
return dispatcher_.unary<search_admin_v1::UnfreezeIndexPlanResponse>(
|
|
2430
|
+
timeout,
|
|
2431
|
+
[stub, proto, auth](grpc::ClientContext& ctx,
|
|
2432
|
+
search_admin_v1::UnfreezeIndexPlanResponse& resp,
|
|
2433
|
+
std::function<void(grpc::Status)> cb) {
|
|
2434
|
+
if (!auth.empty()) {
|
|
2435
|
+
ctx.AddMetadata("authorization", auth);
|
|
2436
|
+
}
|
|
2437
|
+
stub->async()->UnfreezeIndexPlan(&ctx, proto.get(), &resp, std::move(cb));
|
|
2438
|
+
},
|
|
2439
|
+
[invoke = std::move(invoke),
|
|
2440
|
+
proto](grpc::Status status, search_admin_v1::UnfreezeIndexPlanResponse /* r */) mutable {
|
|
2441
|
+
invoke(std::move(status));
|
|
2442
|
+
});
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2445
|
+
} // namespace couchbase::core::protostellar
|