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.
Files changed (473) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/ext/CMakeLists.txt +16 -1
  4. data/ext/cache/cpm/{CPM_0.42.0.cmake → CPM_0.43.1.cmake} +18 -2
  5. data/ext/cache/extconf_include.rb +6 -6
  6. data/ext/cache/mozilla-ca-bundle.crt +121 -55
  7. data/ext/cache/mozilla-ca-bundle.sha256 +1 -1
  8. data/ext/couchbase/CMakeLists.txt +130 -21
  9. data/ext/couchbase/cmake/APKBUILD.in +25 -4
  10. data/ext/couchbase/cmake/Bundler.cmake +143 -34
  11. data/ext/couchbase/cmake/CPM.cmake +126 -12
  12. data/ext/couchbase/cmake/Cache.cmake +7 -1
  13. data/ext/couchbase/cmake/CompilerOptions.cmake +1 -1
  14. data/ext/couchbase/cmake/CompilerWarnings.cmake +17 -6
  15. data/ext/couchbase/cmake/GrpcProtobuf.cmake +481 -0
  16. data/ext/couchbase/cmake/OpenSSL.cmake +10 -3
  17. data/ext/couchbase/cmake/Packaging.cmake +519 -65
  18. data/ext/couchbase/cmake/Protostellar.cmake +250 -0
  19. data/ext/couchbase/cmake/Sanitizers.cmake +61 -50
  20. data/ext/couchbase/cmake/StaticAnalyzers.cmake +16 -5
  21. data/ext/couchbase/cmake/TestFramework.cmake +283 -0
  22. data/ext/couchbase/cmake/TestFrameworkAddTests.cmake +51 -0
  23. data/ext/couchbase/cmake/Testing.cmake +27 -9
  24. data/ext/couchbase/cmake/ThirdPartyDependencies.cmake +141 -8
  25. data/ext/couchbase/cmake/VersionInfo.cmake +50 -0
  26. data/ext/couchbase/cmake/build_config.hxx.in +2 -1
  27. data/ext/couchbase/cmake/couchbase-cxx-client.spec.in +101 -23
  28. data/ext/couchbase/cmake/couchbase_cxx_client_static-config.cmake.in +7 -0
  29. data/ext/couchbase/cmake/couchbase_cxx_client_static.pc.in +2 -0
  30. data/ext/couchbase/cmake/gRPC_Generate.cmake +58 -0
  31. data/ext/couchbase/cmake/protobuf_Generate.cmake +69 -0
  32. data/ext/couchbase/cmake/require-git-checkout.cmake +25 -0
  33. data/ext/couchbase/cmake/tarball_glob.txt +49 -0
  34. data/ext/couchbase/core/agent_group.cxx +0 -8
  35. data/ext/couchbase/core/agent_group.hxx +0 -4
  36. data/ext/couchbase/core/analytics_stream.cxx +314 -0
  37. data/ext/couchbase/core/analytics_stream.hxx +129 -0
  38. data/ext/couchbase/core/analytics_stream_component.cxx +245 -0
  39. data/ext/couchbase/core/analytics_stream_component.hxx +67 -0
  40. data/ext/couchbase/core/app_telemetry_meter.cxx +25 -3
  41. data/ext/couchbase/core/app_telemetry_meter.hxx +77 -0
  42. data/ext/couchbase/core/app_telemetry_reporter.cxx +7 -6
  43. data/ext/couchbase/core/bucket.cxx +381 -87
  44. data/ext/couchbase/core/bucket.hxx +105 -25
  45. data/ext/couchbase/core/bucket_unit_test_api.hxx +57 -0
  46. data/ext/couchbase/core/capella.hxx +91 -0
  47. data/ext/couchbase/core/cluster.cxx +1554 -398
  48. data/ext/couchbase/core/cluster.hxx +39 -8
  49. data/ext/couchbase/core/cluster_agent.cxx +0 -8
  50. data/ext/couchbase/core/cluster_agent.hxx +0 -4
  51. data/ext/couchbase/core/cluster_options.hxx +26 -3
  52. data/ext/couchbase/core/collections_component.cxx +39 -15
  53. data/ext/couchbase/core/config_profiles.cxx +1 -1
  54. data/ext/couchbase/core/crud_component.cxx +2 -2
  55. data/ext/couchbase/core/crud_options.hxx +34 -0
  56. data/ext/couchbase/core/crypto/cbcrypto.cc +18 -13
  57. data/ext/couchbase/core/document_id_redaction.hxx +81 -0
  58. data/ext/couchbase/core/error_context/base_error_context.hxx +7 -6
  59. data/ext/couchbase/core/error_context/key_value.cxx +25 -2
  60. data/ext/couchbase/core/error_context/key_value.hxx +60 -33
  61. data/ext/couchbase/core/error_context/key_value_error_context.hxx +16 -15
  62. data/ext/couchbase/core/error_context/search.hxx +5 -0
  63. data/ext/couchbase/core/error_context/search_json.hxx +3 -0
  64. data/ext/couchbase/core/error_context/subdocument_error_context.hxx +19 -18
  65. data/ext/couchbase/core/error_context/view.hxx +5 -0
  66. data/ext/couchbase/core/free_form_http_request.cxx +237 -4
  67. data/ext/couchbase/core/free_form_http_request.hxx +41 -8
  68. data/ext/couchbase/core/http_component.cxx +300 -284
  69. data/ext/couchbase/core/http_component.hxx +0 -4
  70. data/ext/couchbase/core/impl/analytics.cxx +38 -5
  71. data/ext/couchbase/core/impl/analytics.hxx +34 -0
  72. data/ext/couchbase/core/impl/bootstrap_error.hxx +0 -3
  73. data/ext/couchbase/core/impl/collection.cxx +215 -202
  74. data/ext/couchbase/core/impl/collection_manager.cxx +1 -1
  75. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +45 -18
  76. data/ext/couchbase/core/impl/error.cxx +22 -2
  77. data/ext/couchbase/core/impl/internal_analytics_stream_result.hxx +111 -0
  78. data/ext/couchbase/core/impl/internal_query_stream_result.hxx +110 -0
  79. data/ext/couchbase/core/impl/invoke_with_node_id.hxx +15 -7
  80. data/ext/couchbase/core/impl/key_value_error_category.cxx +6 -0
  81. data/ext/couchbase/core/impl/lookup_in_replica.cxx +10 -10
  82. data/ext/couchbase/core/impl/lookup_in_replica.hxx +4 -4
  83. data/ext/couchbase/core/impl/node_id.cxx +49 -13
  84. data/ext/couchbase/core/impl/observability_recorder.cxx +12 -2
  85. data/ext/couchbase/core/impl/observe_poll.cxx +63 -23
  86. data/ext/couchbase/core/impl/public_analytics_stream_result.cxx +372 -0
  87. data/ext/couchbase/core/impl/public_bucket.cxx +48 -2
  88. data/ext/couchbase/core/impl/public_cluster.cxx +229 -42
  89. data/ext/couchbase/core/impl/public_query_stream_result.cxx +380 -0
  90. data/ext/couchbase/core/impl/public_transaction_get_multi_replicas_from_preferred_server_group_result.cxx +42 -0
  91. data/ext/couchbase/core/impl/public_transaction_get_multi_result.cxx +42 -0
  92. data/ext/couchbase/core/impl/query.cxx +76 -7
  93. data/ext/couchbase/core/impl/query.hxx +36 -0
  94. data/ext/couchbase/core/impl/query_index_manager.cxx +54 -1
  95. data/ext/couchbase/core/impl/replica_utils.cxx +101 -0
  96. data/ext/couchbase/core/impl/replica_utils.hxx +64 -0
  97. data/ext/couchbase/core/impl/resolve_node_id.hxx +125 -0
  98. data/ext/couchbase/core/impl/scope.cxx +70 -0
  99. data/ext/couchbase/core/impl/search.cxx +31 -1
  100. data/ext/couchbase/core/impl/transactions.cxx +130 -0
  101. data/ext/couchbase/core/impl/wait_until_ready.cxx +439 -0
  102. data/ext/couchbase/core/impl/wait_until_ready.hxx +110 -0
  103. data/ext/couchbase/core/impl/with_bucket_config_or_timeout.hxx +180 -0
  104. data/ext/couchbase/core/impl/with_cancellation.hxx +11 -3
  105. data/ext/couchbase/core/io/configuration_belongs_to_session.hxx +1 -2
  106. data/ext/couchbase/core/io/dns_client.cxx +122 -45
  107. data/ext/couchbase/core/io/dns_codec.hxx +21 -21
  108. data/ext/couchbase/core/io/dns_config.cxx +21 -6
  109. data/ext/couchbase/core/io/http_command.hxx +149 -121
  110. data/ext/couchbase/core/io/http_error.hxx +107 -0
  111. data/ext/couchbase/core/io/http_parser.cxx +4 -0
  112. data/ext/couchbase/core/io/http_session.cxx +606 -154
  113. data/ext/couchbase/core/io/http_session.hxx +147 -30
  114. data/ext/couchbase/core/io/http_session_manager.hxx +329 -382
  115. data/ext/couchbase/core/io/http_streaming_parser.cxx +4 -0
  116. data/ext/couchbase/core/io/http_streaming_response.cxx +328 -43
  117. data/ext/couchbase/core/io/http_streaming_response.hxx +37 -3
  118. data/ext/couchbase/core/io/mcbp_buffer_pool.hxx +122 -0
  119. data/ext/couchbase/core/io/mcbp_command.hxx +150 -51
  120. data/ext/couchbase/core/io/mcbp_command_id.hxx +45 -0
  121. data/ext/couchbase/core/io/mcbp_message.cxx +9 -1
  122. data/ext/couchbase/core/io/mcbp_message.hxx +19 -0
  123. data/ext/couchbase/core/io/mcbp_output_queue.hxx +150 -0
  124. data/ext/couchbase/core/io/mcbp_parser.cxx +24 -7
  125. data/ext/couchbase/core/io/mcbp_session.cxx +309 -301
  126. data/ext/couchbase/core/io/mcbp_session.hxx +27 -18
  127. data/ext/couchbase/core/io/opaque_ring_table.hxx +145 -0
  128. data/ext/couchbase/core/io/retry_orchestrator.hxx +6 -5
  129. data/ext/couchbase/core/io/stream_deadline.hxx +50 -0
  130. data/ext/couchbase/core/io/streams.cxx +151 -21
  131. data/ext/couchbase/core/io/streams.hxx +48 -1
  132. data/ext/couchbase/core/logger/logger.cxx +36 -0
  133. data/ext/couchbase/core/logger/logger.hxx +46 -6
  134. data/ext/couchbase/core/logger/redaction.hxx +503 -0
  135. data/ext/couchbase/core/management/eventing_status.hxx +10 -0
  136. data/ext/couchbase/core/management/eventing_status_json.hxx +4 -0
  137. data/ext/couchbase/core/mcbp/big_endian.cxx +1 -1
  138. data/ext/couchbase/core/mcbp/codec.cxx +27 -18
  139. data/ext/couchbase/core/mcbp/operation_queue.cxx +2 -2
  140. data/ext/couchbase/core/mcbp/packet.hxx +2 -2
  141. data/ext/couchbase/core/mcbp/queue_request.cxx +23 -6
  142. data/ext/couchbase/core/mcbp/queue_request.hxx +21 -0
  143. data/ext/couchbase/core/meta/features.hxx +13 -0
  144. data/ext/couchbase/core/meta/version.cxx +6 -3
  145. data/ext/couchbase/core/metrics/logging_meter.cxx +5 -10
  146. data/ext/couchbase/core/metrics/meter_wrapper.cxx +63 -33
  147. data/ext/couchbase/core/metrics/meter_wrapper.hxx +55 -3
  148. data/ext/couchbase/core/operations/analytics_response_parsing.cxx +177 -0
  149. data/ext/couchbase/core/operations/analytics_response_parsing.hxx +55 -0
  150. data/ext/couchbase/core/operations/document_analytics.cxx +48 -130
  151. data/ext/couchbase/core/operations/document_analytics.hxx +14 -2
  152. data/ext/couchbase/core/operations/document_get_all_replicas.hxx +15 -7
  153. data/ext/couchbase/core/operations/document_get_any_replica.hxx +19 -8
  154. data/ext/couchbase/core/operations/document_get_projected.cxx +1 -1
  155. data/ext/couchbase/core/{impl/get_replica.cxx → operations/document_get_replica.cxx} +21 -3
  156. data/ext/couchbase/core/{impl/get_replica.hxx → operations/document_get_replica.hxx} +31 -4
  157. data/ext/couchbase/core/operations/document_lookup_in.cxx +10 -10
  158. data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +228 -198
  159. data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +215 -217
  160. data/ext/couchbase/core/operations/document_query.cxx +108 -221
  161. data/ext/couchbase/core/operations/document_query.hxx +18 -4
  162. data/ext/couchbase/core/operations/document_search.cxx +52 -8
  163. data/ext/couchbase/core/operations/document_search.hxx +3 -0
  164. data/ext/couchbase/core/operations/document_view.cxx +3 -3
  165. data/ext/couchbase/core/operations/management/analytics_dataset_create.cxx +15 -8
  166. data/ext/couchbase/core/operations/management/analytics_dataset_create.hxx +4 -0
  167. data/ext/couchbase/core/operations/management/analytics_dataset_drop.cxx +11 -6
  168. data/ext/couchbase/core/operations/management/analytics_dataset_get_all.cxx +3 -2
  169. data/ext/couchbase/core/operations/management/analytics_dataverse_create.cxx +10 -5
  170. data/ext/couchbase/core/operations/management/analytics_dataverse_drop.cxx +10 -5
  171. data/ext/couchbase/core/operations/management/analytics_get_pending_mutations.cxx +2 -1
  172. data/ext/couchbase/core/operations/management/analytics_index_create.cxx +33 -8
  173. data/ext/couchbase/core/operations/management/analytics_index_drop.cxx +12 -7
  174. data/ext/couchbase/core/operations/management/analytics_index_get_all.cxx +3 -2
  175. data/ext/couchbase/core/operations/management/analytics_link_connect.cxx +11 -6
  176. data/ext/couchbase/core/operations/management/analytics_link_create.cxx +3 -3
  177. data/ext/couchbase/core/operations/management/analytics_link_disconnect.cxx +10 -4
  178. data/ext/couchbase/core/operations/management/analytics_link_drop.cxx +6 -4
  179. data/ext/couchbase/core/operations/management/analytics_link_get_all.cxx +4 -3
  180. data/ext/couchbase/core/operations/management/analytics_link_replace.cxx +3 -3
  181. data/ext/couchbase/core/operations/management/analytics_link_utils.hxx +1 -1
  182. data/ext/couchbase/core/operations/management/change_password.cxx +2 -0
  183. data/ext/couchbase/core/operations/management/collection_drop.cxx +5 -1
  184. data/ext/couchbase/core/operations/management/error_utils.cxx +59 -5
  185. data/ext/couchbase/core/operations/management/error_utils.hxx +29 -1
  186. data/ext/couchbase/core/operations/management/eventing_deploy_function.cxx +9 -3
  187. data/ext/couchbase/core/operations/management/eventing_drop_function.cxx +8 -3
  188. data/ext/couchbase/core/operations/management/eventing_get_all_functions.cxx +4 -2
  189. data/ext/couchbase/core/operations/management/eventing_get_function.cxx +5 -3
  190. data/ext/couchbase/core/operations/management/eventing_get_status.cxx +4 -2
  191. data/ext/couchbase/core/operations/management/eventing_pause_function.cxx +9 -3
  192. data/ext/couchbase/core/operations/management/eventing_resume_function.cxx +9 -3
  193. data/ext/couchbase/core/operations/management/eventing_undeploy_function.cxx +9 -3
  194. data/ext/couchbase/core/operations/management/eventing_upsert_function.cxx +9 -3
  195. data/ext/couchbase/core/operations/management/group_drop.cxx +3 -1
  196. data/ext/couchbase/core/operations/management/group_get.cxx +3 -1
  197. data/ext/couchbase/core/operations/management/group_upsert.cxx +11 -8
  198. data/ext/couchbase/core/operations/management/query_index_build.cxx +5 -2
  199. data/ext/couchbase/core/operations/management/query_index_create.cxx +9 -3
  200. data/ext/couchbase/core/operations/management/query_index_drop.cxx +11 -4
  201. data/ext/couchbase/core/operations/management/query_index_get_all.cxx +1 -1
  202. data/ext/couchbase/core/operations/management/query_index_get_all_deferred.cxx +1 -1
  203. data/ext/couchbase/core/operations/management/scope_drop.cxx +5 -1
  204. data/ext/couchbase/core/operations/management/scope_get_all.cxx +6 -1
  205. data/ext/couchbase/core/operations/management/search_get_stats.cxx +10 -0
  206. data/ext/couchbase/core/operations/management/search_index_analyze_document.cxx +3 -2
  207. data/ext/couchbase/core/operations/management/search_index_control_ingest.cxx +4 -3
  208. data/ext/couchbase/core/operations/management/search_index_control_plan_freeze.cxx +4 -3
  209. data/ext/couchbase/core/operations/management/search_index_control_query.cxx +4 -3
  210. data/ext/couchbase/core/operations/management/search_index_drop.cxx +2 -2
  211. data/ext/couchbase/core/operations/management/search_index_get.cxx +2 -2
  212. data/ext/couchbase/core/operations/management/search_index_get_documents_count.cxx +3 -2
  213. data/ext/couchbase/core/operations/management/search_index_get_stats.cxx +3 -1
  214. data/ext/couchbase/core/operations/management/search_index_upsert.cxx +2 -2
  215. data/ext/couchbase/core/operations/management/user_drop.cxx +3 -1
  216. data/ext/couchbase/core/operations/management/user_get.cxx +3 -1
  217. data/ext/couchbase/core/operations/management/user_upsert.cxx +12 -9
  218. data/ext/couchbase/core/operations/management/view_index_drop.cxx +1 -1
  219. data/ext/couchbase/core/operations/management/view_index_get.cxx +1 -1
  220. data/ext/couchbase/core/operations/management/view_index_upsert.cxx +1 -1
  221. data/ext/couchbase/core/operations/operation_traits.hxx +18 -0
  222. data/ext/couchbase/core/operations/query_response_parsing.cxx +211 -0
  223. data/ext/couchbase/core/operations/query_response_parsing.hxx +60 -0
  224. data/ext/couchbase/core/operations_fwd.hxx +3 -3
  225. data/ext/couchbase/core/origin.cxx +54 -26
  226. data/ext/couchbase/core/origin.hxx +12 -0
  227. data/ext/couchbase/core/orphan_reporter.cxx +2 -1
  228. data/ext/couchbase/core/platform/random.cc +7 -7
  229. data/ext/couchbase/core/protocol/client_request.cxx +2 -2
  230. data/ext/couchbase/core/protocol/client_request.hxx +38 -21
  231. data/ext/couchbase/core/protocol/client_response.cxx +11 -3
  232. data/ext/couchbase/core/protocol/client_response.hxx +27 -6
  233. data/ext/couchbase/core/protocol/cmd_append.cxx +2 -2
  234. data/ext/couchbase/core/protocol/cmd_cluster_map_change_notification.cxx +2 -2
  235. data/ext/couchbase/core/protocol/cmd_decrement.cxx +6 -6
  236. data/ext/couchbase/core/protocol/cmd_get.cxx +1 -1
  237. data/ext/couchbase/core/protocol/cmd_get_and_lock.cxx +2 -2
  238. data/ext/couchbase/core/protocol/cmd_get_and_touch.cxx +2 -2
  239. data/ext/couchbase/core/protocol/cmd_get_cluster_config.cxx +6 -4
  240. data/ext/couchbase/core/protocol/cmd_get_collection_id.cxx +2 -2
  241. data/ext/couchbase/core/protocol/cmd_get_error_map.cxx +1 -1
  242. data/ext/couchbase/core/protocol/cmd_get_meta.cxx +4 -4
  243. data/ext/couchbase/core/protocol/cmd_get_replica.cxx +1 -1
  244. data/ext/couchbase/core/protocol/cmd_hello.cxx +1 -1
  245. data/ext/couchbase/core/protocol/cmd_increment.cxx +6 -6
  246. data/ext/couchbase/core/protocol/cmd_insert.cxx +4 -4
  247. data/ext/couchbase/core/protocol/cmd_lookup_in.cxx +4 -3
  248. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.cxx +4 -3
  249. data/ext/couchbase/core/protocol/cmd_mutate_in.cxx +10 -9
  250. data/ext/couchbase/core/protocol/cmd_mutate_in.hxx +10 -10
  251. data/ext/couchbase/core/protocol/cmd_observe_seqno.cxx +7 -7
  252. data/ext/couchbase/core/protocol/cmd_prepend.cxx +2 -2
  253. data/ext/couchbase/core/protocol/cmd_remove.cxx +2 -2
  254. data/ext/couchbase/core/protocol/cmd_replace.cxx +4 -4
  255. data/ext/couchbase/core/protocol/cmd_touch.cxx +1 -1
  256. data/ext/couchbase/core/protocol/cmd_upsert.cxx +4 -4
  257. data/ext/couchbase/core/protocol/datatype.hxx +118 -1
  258. data/ext/couchbase/core/protocol/frame_info_utils.cxx +1 -1
  259. data/ext/couchbase/core/protocol/magic.hxx +4 -0
  260. data/ext/couchbase/core/protocol/magic_fmt.hxx +3 -0
  261. data/ext/couchbase/core/protocol/server_request.hxx +3 -1
  262. data/ext/couchbase/core/protocol/status.cxx +1 -1
  263. data/ext/couchbase/core/protostellar/analytics_converter.hxx +171 -0
  264. data/ext/couchbase/core/protostellar/bucket_admin_converter.hxx +301 -0
  265. data/ext/couchbase/core/protostellar/collection_admin_converter.hxx +92 -0
  266. data/ext/couchbase/core/protostellar/component.cxx +2445 -0
  267. data/ext/couchbase/core/protostellar/component.hxx +391 -0
  268. data/ext/couchbase/core/{columnar/bootstrap_notification_subscriber.hxx → protostellar/compression_settings.hxx} +11 -10
  269. data/ext/couchbase/core/protostellar/credentials.cxx +233 -0
  270. data/ext/couchbase/core/protostellar/credentials.hxx +88 -0
  271. data/ext/couchbase/core/protostellar/dispatcher.cxx +57 -0
  272. data/ext/couchbase/core/protostellar/dispatcher.hxx +482 -0
  273. data/ext/couchbase/core/protostellar/error_utils.cxx +293 -0
  274. data/ext/couchbase/core/protostellar/error_utils.hxx +97 -0
  275. data/ext/couchbase/core/protostellar/json_payload.hxx +49 -0
  276. data/ext/couchbase/core/protostellar/kv_converter.cxx +70 -0
  277. data/ext/couchbase/core/protostellar/kv_converter.hxx +600 -0
  278. data/ext/couchbase/core/protostellar/query_converter.hxx +265 -0
  279. data/ext/couchbase/core/protostellar/query_index_admin_converter.hxx +291 -0
  280. data/ext/couchbase/core/protostellar/query_proto.hxx +73 -0
  281. data/ext/couchbase/core/protostellar/search_converter.hxx +244 -0
  282. data/ext/couchbase/core/protostellar/search_index_admin_converter.hxx +156 -0
  283. data/ext/couchbase/core/protostellar/view_converter.hxx +158 -0
  284. data/ext/couchbase/core/query_stream.cxx +447 -0
  285. data/ext/couchbase/core/query_stream.hxx +141 -0
  286. data/ext/couchbase/core/query_stream_component.cxx +243 -0
  287. data/ext/couchbase/core/query_stream_component.hxx +68 -0
  288. data/ext/couchbase/core/range_scan_load_balancer.cxx +15 -8
  289. data/ext/couchbase/core/range_scan_orchestrator.cxx +15 -3
  290. data/ext/couchbase/core/response_handler.hxx +41 -4
  291. data/ext/couchbase/core/row_streamer.cxx +332 -46
  292. data/ext/couchbase/core/row_streamer.hxx +31 -1
  293. data/ext/couchbase/core/row_streamer_options.hxx +55 -0
  294. data/ext/couchbase/core/sasl/client.h +3 -0
  295. data/ext/couchbase/core/search_scoring.hxx +66 -0
  296. data/ext/couchbase/core/stream_error_details.hxx +69 -0
  297. data/ext/couchbase/core/timeout_defaults.hxx +0 -1
  298. data/ext/couchbase/core/topology/capabilities.hxx +6 -0
  299. data/ext/couchbase/core/topology/capabilities_fmt.hxx +3 -0
  300. data/ext/couchbase/core/topology/configuration.cxx +21 -6
  301. data/ext/couchbase/core/topology/configuration.hxx +29 -8
  302. data/ext/couchbase/core/topology/configuration_json.hxx +3 -0
  303. data/ext/couchbase/core/topology/error_map_json.hxx +3 -1
  304. data/ext/couchbase/core/tracing/threshold_logging_tracer.cxx +70 -4
  305. data/ext/couchbase/core/tracing/threshold_logging_tracer.hxx +10 -0
  306. data/ext/couchbase/core/transactions/active_transaction_record.cxx +0 -34
  307. data/ext/couchbase/core/transactions/attempt_context_impl.cxx +108 -63
  308. data/ext/couchbase/core/transactions/attempt_context_impl.hxx +19 -2
  309. data/ext/couchbase/core/transactions/error_list.hxx +2 -2
  310. data/ext/couchbase/core/transactions/get_multi_fetch.hxx +160 -0
  311. data/ext/couchbase/core/transactions/get_multi_orchestrator.cxx +326 -125
  312. data/ext/couchbase/core/transactions/get_multi_transaction_id.hxx +62 -0
  313. data/ext/couchbase/core/transactions/internal/atr_entry.hxx +22 -2
  314. data/ext/couchbase/core/transactions/internal/transaction_context.hxx +2 -2
  315. data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +23 -1
  316. data/ext/couchbase/core/transactions/internal/utils.hxx +50 -14
  317. data/ext/couchbase/core/transactions/staged_mutation.cxx +23 -18
  318. data/ext/couchbase/core/transactions/staged_mutation.hxx +15 -4
  319. data/ext/couchbase/core/transactions/transaction_context.cxx +55 -40
  320. data/ext/couchbase/core/transactions/transaction_get_result.hxx +16 -0
  321. data/ext/couchbase/core/transactions/transactions.cxx +3 -55
  322. data/ext/couchbase/core/transactions/transactions_cleanup.cxx +165 -72
  323. data/ext/couchbase/core/transactions/transactions_config.cxx +0 -11
  324. data/ext/couchbase/core/transactions/utils.cxx +10 -0
  325. data/ext/couchbase/core/transactions/waitable_op_list.hxx +2 -2
  326. data/ext/couchbase/core/transactions.hxx +9 -9
  327. data/ext/couchbase/core/utils/byteswap.hxx +166 -9
  328. data/ext/couchbase/core/utils/connection_string.cxx +50 -85
  329. data/ext/couchbase/core/utils/connection_string.hxx +15 -0
  330. data/ext/couchbase/core/{columnar/backoff_calculator.hxx → utils/deadline.hxx} +13 -13
  331. data/ext/couchbase/core/utils/duration_parser.cxx +1 -1
  332. data/ext/couchbase/core/utils/json_streaming_lexer.cxx +48 -5
  333. data/ext/couchbase/core/utils/json_streaming_lexer.hxx +4 -1
  334. data/ext/couchbase/core/utils/movable_function.hxx +301 -52
  335. data/ext/couchbase/core/utils/name_codec.hxx +154 -11
  336. data/ext/couchbase/core/{columnar/retry_info.hxx → utils/process_id.hxx} +18 -13
  337. data/ext/couchbase/core/utils/url_codec.cxx +12 -51
  338. data/ext/couchbase/core/websocket_codec.cxx +3 -29
  339. data/ext/couchbase/couchbase/analytics_options.hxx +21 -10
  340. data/ext/couchbase/couchbase/analytics_row.hxx +105 -0
  341. data/ext/couchbase/couchbase/analytics_stream_result.hxx +266 -0
  342. data/ext/couchbase/couchbase/boolean_query.hxx +3 -3
  343. data/ext/couchbase/couchbase/bucket.hxx +57 -0
  344. data/ext/couchbase/couchbase/cluster.hxx +183 -5
  345. data/ext/couchbase/{core/columnar/security_options.hxx → couchbase/cluster_state.hxx} +18 -14
  346. data/ext/couchbase/couchbase/codec/lenient_json_transcoder.hxx +69 -0
  347. data/ext/couchbase/couchbase/collection.hxx +234 -14
  348. data/ext/couchbase/couchbase/common_durability_options.hxx +18 -3
  349. data/ext/couchbase/couchbase/conjunction_query.hxx +1 -1
  350. data/ext/couchbase/couchbase/create_dataset_analytics_options.hxx +6 -1
  351. data/ext/couchbase/couchbase/date_range_query.hxx +2 -2
  352. data/ext/couchbase/couchbase/decrement_options.hxx +1 -1
  353. data/ext/couchbase/couchbase/disjunction_query.hxx +1 -1
  354. data/ext/couchbase/couchbase/error.hxx +32 -0
  355. data/ext/couchbase/couchbase/error_codes.hxx +32 -0
  356. data/ext/couchbase/couchbase/geo_bounding_box_query.hxx +1 -1
  357. data/ext/couchbase/couchbase/geo_distance_query.hxx +1 -1
  358. data/ext/couchbase/couchbase/geo_polygon_query.hxx +1 -1
  359. data/ext/couchbase/couchbase/get_replica_options.hxx +68 -0
  360. data/ext/couchbase/couchbase/get_replica_result.hxx +5 -3
  361. data/ext/couchbase/couchbase/get_replica_strategy.hxx +161 -0
  362. data/ext/couchbase/couchbase/get_result.hxx +1 -0
  363. data/ext/couchbase/couchbase/increment_options.hxx +1 -1
  364. data/ext/couchbase/couchbase/insert_options.hxx +1 -1
  365. data/ext/couchbase/couchbase/match_phrase_query.hxx +1 -1
  366. data/ext/couchbase/couchbase/match_query.hxx +1 -1
  367. data/ext/couchbase/couchbase/mutate_in_options.hxx +3 -3
  368. data/ext/couchbase/couchbase/network_options.hxx +1 -1
  369. data/ext/couchbase/couchbase/node_id.hxx +42 -14
  370. data/ext/couchbase/couchbase/node_id_for_options.hxx +7 -1
  371. data/ext/couchbase/couchbase/node_ids_options.hxx +8 -2
  372. data/ext/couchbase/couchbase/numeric_range_query.hxx +1 -1
  373. data/ext/couchbase/couchbase/phrase_query.hxx +1 -1
  374. data/ext/couchbase/couchbase/prefix_query.hxx +1 -1
  375. data/ext/couchbase/couchbase/query_options.hxx +23 -12
  376. data/ext/couchbase/couchbase/query_row.hxx +111 -0
  377. data/ext/couchbase/couchbase/query_stream_result.hxx +302 -0
  378. data/ext/couchbase/couchbase/query_string_query.hxx +3 -3
  379. data/ext/couchbase/couchbase/regexp_query.hxx +1 -1
  380. data/ext/couchbase/couchbase/replace_options.hxx +3 -3
  381. data/ext/couchbase/couchbase/result.hxx +14 -3
  382. data/ext/couchbase/couchbase/scan_result_item.hxx +1 -0
  383. data/ext/couchbase/couchbase/scope.hxx +85 -2
  384. data/ext/couchbase/couchbase/search_options.hxx +58 -8
  385. data/ext/couchbase/couchbase/search_scoring.hxx +94 -0
  386. data/ext/couchbase/couchbase/search_scoring_none.hxx +51 -0
  387. data/ext/couchbase/couchbase/search_scoring_reciprocal_rank_fusion.hxx +88 -0
  388. data/ext/couchbase/couchbase/search_scoring_relative_score_fusion.hxx +70 -0
  389. data/ext/couchbase/couchbase/term_range_query.hxx +1 -1
  390. data/ext/couchbase/couchbase/tracing/request_span.hxx +46 -0
  391. data/ext/couchbase/couchbase/transactions/transaction_get_multi_replicas_from_preferred_server_group_result.hxx +23 -21
  392. data/ext/couchbase/couchbase/transactions/transaction_get_multi_result.hxx +24 -19
  393. data/ext/couchbase/couchbase/transactions/transaction_get_result.hxx +17 -3
  394. data/ext/couchbase/couchbase/transactions/transactions_config.hxx +4 -2
  395. data/ext/couchbase/couchbase/transactions.hxx +27 -18
  396. data/ext/couchbase/couchbase/upsert_options.hxx +3 -3
  397. data/ext/couchbase/couchbase/vector_query.hxx +1 -1
  398. data/ext/couchbase/couchbase/wait_until_ready_options.hxx +111 -0
  399. data/ext/couchbase/couchbase/wildcard_query.hxx +1 -1
  400. data/ext/extconf.rb +15 -10
  401. data/ext/rcb_analytics.cxx +82 -102
  402. data/ext/rcb_backend.cxx +42 -36
  403. data/ext/rcb_backend.hxx +2 -0
  404. data/ext/rcb_buckets.cxx +47 -59
  405. data/ext/rcb_collections.cxx +42 -52
  406. data/ext/rcb_crud.cxx +345 -224
  407. data/ext/rcb_diagnostics.cxx +117 -27
  408. data/ext/rcb_exceptions.cxx +152 -99
  409. data/ext/rcb_exceptions.hxx +25 -0
  410. data/ext/rcb_extras.cxx +18 -19
  411. data/ext/rcb_hdr_histogram.cxx +19 -4
  412. data/ext/rcb_logger.cxx +202 -27
  413. data/ext/rcb_logger.hxx +12 -0
  414. data/ext/rcb_multi.cxx +40 -40
  415. data/ext/rcb_observability.cxx +7 -5
  416. data/ext/rcb_query.cxx +99 -142
  417. data/ext/rcb_range_scan.cxx +41 -35
  418. data/ext/rcb_search.cxx +98 -99
  419. data/ext/rcb_users.cxx +36 -56
  420. data/ext/rcb_utils.cxx +100 -37
  421. data/ext/rcb_utils.hxx +287 -33
  422. data/ext/rcb_version.cxx +1 -1
  423. data/ext/rcb_views.cxx +55 -51
  424. data/lib/active_support/cache/couchbase_store.rb +77 -12
  425. data/lib/couchbase/bucket.rb +20 -0
  426. data/lib/couchbase/cluster.rb +17 -0
  427. data/lib/couchbase/collection.rb +36 -1
  428. data/lib/couchbase/errors.rb +18 -0
  429. data/lib/couchbase/fork_hooks.rb +16 -7
  430. data/lib/couchbase/get_replica_strategy.rb +89 -0
  431. data/lib/couchbase/logger.rb +1 -1
  432. data/lib/couchbase/management/analytics_index_manager.rb +15 -15
  433. data/lib/couchbase/management/bucket_manager.rb +6 -6
  434. data/lib/couchbase/management/collection_manager.rb +6 -6
  435. data/lib/couchbase/management/query_index_manager.rb +7 -7
  436. data/lib/couchbase/management/search_index_manager.rb +13 -13
  437. data/lib/couchbase/management/user_manager.rb +10 -10
  438. data/lib/couchbase/management/view_index_manager.rb +5 -5
  439. data/lib/couchbase/options.rb +174 -42
  440. data/lib/couchbase/protostellar/bucket.rb +4 -0
  441. data/lib/couchbase/protostellar/cluster.rb +4 -0
  442. data/lib/couchbase/protostellar/collection.rb +4 -0
  443. data/lib/couchbase/protostellar/error_handling.rb +2 -1
  444. data/lib/couchbase/protostellar/request.rb +1 -0
  445. data/lib/couchbase/protostellar/request_generator/kv.rb +16 -2
  446. data/lib/couchbase/protostellar/request_generator/search.rb +17 -1
  447. data/lib/couchbase/protostellar/retry/orchestrator.rb +3 -2
  448. data/lib/couchbase/protostellar/retry/strategies/fail_fast.rb +33 -0
  449. data/lib/couchbase/protostellar/retry/strategies.rb +1 -0
  450. data/lib/couchbase/search_options.rb +95 -6
  451. data/lib/couchbase/version.rb +1 -1
  452. metadata +91 -33
  453. data/ext/0001-fix-build-for-mingw-w64-ucrt-x86_64-toolchain.patch +0 -40
  454. data/ext/couchbase/core/columnar/agent.hxx +0 -71
  455. data/ext/couchbase/core/columnar/agent_config.hxx +0 -59
  456. data/ext/couchbase/core/columnar/background_bootstrap_listener.hxx +0 -42
  457. data/ext/couchbase/core/columnar/backoff_calculator.cxx +0 -62
  458. data/ext/couchbase/core/columnar/columnar_agent.cxx +0 -147
  459. data/ext/couchbase/core/columnar/columnar_agent_config.cxx +0 -48
  460. data/ext/couchbase/core/columnar/columnar_error.cxx +0 -51
  461. data/ext/couchbase/core/columnar/database_management_options.hxx +0 -56
  462. data/ext/couchbase/core/columnar/error.hxx +0 -51
  463. data/ext/couchbase/core/columnar/error_codes.cxx +0 -107
  464. data/ext/couchbase/core/columnar/error_codes.hxx +0 -75
  465. data/ext/couchbase/core/columnar/management_component.cxx +0 -300
  466. data/ext/couchbase/core/columnar/management_component.hxx +0 -56
  467. data/ext/couchbase/core/columnar/query_component.cxx +0 -523
  468. data/ext/couchbase/core/columnar/query_component.hxx +0 -57
  469. data/ext/couchbase/core/columnar/query_options.hxx +0 -59
  470. data/ext/couchbase/core/columnar/query_result.cxx +0 -130
  471. data/ext/couchbase/core/columnar/query_result.hxx +0 -78
  472. data/ext/couchbase/core/io/config_tracker.cxx +0 -687
  473. data/ext/couchbase/core/io/config_tracker.hxx +0 -123
@@ -169,20 +169,21 @@ private:
169
169
 
170
170
  class observe_context;
171
171
  void
172
- observe_poll(const cluster& core, std::shared_ptr<observe_context> ctx);
172
+ observe_poll(const std::shared_ptr<observe_context>& ctx);
173
173
 
174
174
  class observe_context : public std::enable_shared_from_this<observe_context>
175
175
  {
176
176
  public:
177
- observe_context(asio::io_context& io,
177
+ observe_context(cluster core,
178
178
  document_id id,
179
179
  mutation_token token,
180
180
  std::optional<std::chrono::milliseconds> timeout,
181
181
  couchbase::persist_to persist_to,
182
182
  couchbase::replicate_to replicate_to,
183
183
  observe_handler&& handler)
184
- : poll_deadline_{ io }
185
- , poll_backoff_{ io }
184
+ : poll_deadline_{ core.io_context() }
185
+ , poll_backoff_{ core.io_context() }
186
+ , core_{ std::move(core) }
186
187
  , id_{ std::move(id) }
187
188
  , status_{ std::move(token) }
188
189
  , timeout_{ timeout }
@@ -192,6 +193,38 @@ public:
192
193
  {
193
194
  }
194
195
 
196
+ observe_context(const observe_context&) = delete;
197
+ observe_context(observe_context&&) = delete;
198
+ auto operator=(const observe_context&) -> observe_context& = delete;
199
+ auto operator=(observe_context&&) -> observe_context& = delete;
200
+
201
+ ~observe_context()
202
+ {
203
+ // Fail closed. The context is anchored on the io_context by poll_deadline_ for the whole
204
+ // operation, while the config wait captures a weak_ptr and the seqno requests are cancellable
205
+ // core operations. If the io_context is torn down mid-poll, every continuation is dropped and
206
+ // the context is destroyed here with handler_ still set. Deliver an error so a std::future
207
+ // caller never observes broken_promise and a callback caller never hangs -- this is the
208
+ // backstop for every legacy-durability mutation (persist_to / replicate_to), which routes its
209
+ // handler through the observe poll.
210
+ observe_handler handler{};
211
+ {
212
+ const std::scoped_lock lock(handler_mutex_);
213
+ std::swap(handler_, handler);
214
+ }
215
+ if (handler) {
216
+ try {
217
+ handler(errc::network::cluster_closed);
218
+ } catch (...) { // NOLINT(bugprone-empty-catch)
219
+ }
220
+ }
221
+ }
222
+
223
+ [[nodiscard]] auto core() const -> const cluster&
224
+ {
225
+ return core_;
226
+ }
227
+
195
228
  void start()
196
229
  {
197
230
  poll_deadline_.expires_after(poll_deadline_interval_);
@@ -294,27 +327,30 @@ public:
294
327
  on_last_response_ = std::move(handler);
295
328
  }
296
329
 
297
- void execute(const cluster& core)
330
+ void execute()
298
331
  {
299
332
  auto requests = std::move(requests_);
300
333
  status_.reset();
301
- on_last_response(requests.size(), [core, ctx = shared_from_this()](std::error_code ec) mutable {
334
+ on_last_response(requests.size(), [weak = weak_from_this()](std::error_code ec) mutable {
302
335
  if (ec == asio::error::operation_aborted) {
303
336
  return;
304
337
  }
305
- observe_poll(core, std::move(ctx));
338
+ if (auto ctx = weak.lock()) {
339
+ observe_poll(ctx);
340
+ }
306
341
  });
307
342
  for (auto&& request : requests) {
308
- core.execute(std::move(request),
309
- [ctx = shared_from_this()](observe_seqno_response&& response) {
310
- ctx->handle_response(std::move(response));
311
- });
343
+ core_.execute(std::move(request),
344
+ [ctx = shared_from_this()](observe_seqno_response&& response) {
345
+ ctx->handle_response(std::move(response));
346
+ });
312
347
  }
313
348
  }
314
349
 
315
350
  private:
316
351
  asio::steady_timer poll_deadline_;
317
352
  asio::steady_timer poll_backoff_;
353
+ cluster core_;
318
354
  const document_id id_;
319
355
  observe_status status_;
320
356
  std::optional<std::chrono::milliseconds> timeout_;
@@ -330,13 +366,22 @@ private:
330
366
  };
331
367
 
332
368
  void
333
- observe_poll(const cluster& core, std::shared_ptr<observe_context> ctx)
369
+ observe_poll(const std::shared_ptr<observe_context>& ctx)
334
370
  {
335
371
  const std::string bucket_name = ctx->bucket_name();
336
- core.with_bucket_configuration(
372
+ // Capture a weak_ptr, not the context or a core copy: with_bucket_configuration parks this
373
+ // callback in the core (in the bucket-bootstrap window it is not drained on close). The context
374
+ // is kept alive meanwhile by poll_deadline_ on the io_context, and it owns the core through its
375
+ // core_ member -- capturing either strongly here would form a cycle that survives cluster close
376
+ // and strand the handler.
377
+ ctx->core().with_bucket_configuration(
337
378
  bucket_name,
338
- [core, ctx = std::move(ctx)](
379
+ [weak = std::weak_ptr<observe_context>(ctx)](
339
380
  std::error_code ec, const std::shared_ptr<core::topology::configuration>& config) mutable {
381
+ auto ctx = weak.lock();
382
+ if (!ctx) {
383
+ return;
384
+ }
340
385
  if (ec) {
341
386
  return ctx->finish(ec);
342
387
  }
@@ -360,7 +405,7 @@ observe_poll(const cluster& core, std::shared_ptr<observe_context> ctx)
360
405
  observe_seqno_request{ replica_id, false, ctx->partition_uuid(), ctx->timeout() });
361
406
  }
362
407
  }
363
- ctx->execute(core);
408
+ ctx->execute();
364
409
  });
365
410
  }
366
411
  } // namespace
@@ -374,14 +419,9 @@ initiate_observe_poll(const cluster& core,
374
419
  couchbase::replicate_to replicate_to,
375
420
  observe_handler&& handler)
376
421
  {
377
- auto ctx = std::make_shared<observe_context>(core.io_context(),
378
- std::move(id),
379
- std::move(token),
380
- timeout,
381
- persist_to,
382
- replicate_to,
383
- std::move(handler));
422
+ auto ctx = std::make_shared<observe_context>(
423
+ core, std::move(id), std::move(token), timeout, persist_to, replicate_to, std::move(handler));
384
424
  ctx->start();
385
- return observe_poll(core, std::move(ctx));
425
+ return observe_poll(ctx);
386
426
  }
387
427
  } // namespace couchbase::core::impl
@@ -0,0 +1,372 @@
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 <couchbase/analytics_meta_data.hxx>
19
+ #include <couchbase/analytics_metrics.hxx>
20
+ #include <couchbase/analytics_status.hxx>
21
+ #include <couchbase/analytics_stream_result.hxx>
22
+ #include <couchbase/analytics_warning.hxx>
23
+ #include <couchbase/error_codes.hxx>
24
+
25
+ #include "core/operations/document_analytics.hxx"
26
+ #include "core/utils/binary.hxx"
27
+
28
+ #include "analytics.hxx"
29
+ #include "error.hxx"
30
+ #include "internal_analytics_stream_result.hxx"
31
+ #include "observability_recorder.hxx"
32
+
33
+ #include <future>
34
+ #include <memory>
35
+ #include <mutex>
36
+ #include <optional>
37
+ #include <string>
38
+ #include <system_error>
39
+ #include <utility>
40
+ #include <vector>
41
+
42
+ namespace couchbase
43
+ {
44
+ namespace
45
+ {
46
+ auto
47
+ to_binary(const std::string& s) -> codec::binary
48
+ {
49
+ return core::utils::to_binary(s);
50
+ }
51
+
52
+ auto
53
+ build_analytics_meta_data(core::operations::analytics_response::analytics_meta_data meta)
54
+ -> analytics_meta_data
55
+ {
56
+ std::vector<analytics_warning> warnings;
57
+ warnings.reserve(meta.warnings.size());
58
+ for (auto& w : meta.warnings) {
59
+ warnings.emplace_back(w.code, std::move(w.message));
60
+ }
61
+
62
+ const analytics_metrics metrics{
63
+ meta.metrics.elapsed_time, meta.metrics.execution_time, meta.metrics.result_count,
64
+ meta.metrics.result_size, meta.metrics.processed_objects, meta.metrics.error_count,
65
+ meta.metrics.warning_count,
66
+ };
67
+
68
+ std::optional<codec::binary> signature;
69
+ if (meta.signature) {
70
+ signature = to_binary(*meta.signature);
71
+ }
72
+
73
+ return analytics_meta_data{
74
+ std::move(meta.request_id),
75
+ std::move(meta.client_context_id),
76
+ core::impl::map_analytics_status(meta.status),
77
+ std::move(warnings),
78
+ metrics,
79
+ std::move(signature),
80
+ };
81
+ }
82
+ } // namespace
83
+
84
+ // ---------------------------------------------------------------------------
85
+ // internal_analytics_stream_result implementation
86
+ // ---------------------------------------------------------------------------
87
+
88
+ internal_analytics_stream_result::internal_analytics_stream_result(
89
+ core::analytics_stream stream,
90
+ std::unique_ptr<core::impl::observability_recorder> obs_rec,
91
+ core::error_context::analytics ctx)
92
+ : stream_{ std::move(stream) }
93
+ , ctx_{ std::move(ctx) }
94
+ , obs_rec_{ std::move(obs_rec) }
95
+ {
96
+ }
97
+
98
+ internal_analytics_stream_result::~internal_analytics_stream_result()
99
+ {
100
+ cancel();
101
+ }
102
+
103
+ void
104
+ internal_analytics_stream_result::cancel()
105
+ {
106
+ // Resolve any parked meta_data() futures with a cancellation error so they don't throw
107
+ // broken_promise when the stream is torn down before reaching a natural terminal. Idempotent
108
+ // via terminal_reached_, so a real terminal that already ran is preserved.
109
+ resolve_meta_data(errc::common::request_canceled);
110
+ stream_.cancel();
111
+ }
112
+
113
+ auto
114
+ internal_analytics_stream_result::signature() const -> std::optional<codec::binary>
115
+ {
116
+ auto raw = stream_.signature();
117
+ if (!raw) {
118
+ return {};
119
+ }
120
+ return to_binary(*raw);
121
+ }
122
+
123
+ void
124
+ internal_analytics_stream_result::resolve_meta_data(std::error_code ec)
125
+ {
126
+ std::pair<error, analytics_meta_data> value;
127
+ if (ec) {
128
+ // Report the terminal against the request's context with whatever the response said stamped on,
129
+ // so a mid-stream failure carries the same detail (statement, service error, endpoint) as one
130
+ // that never started. A cancellation leaves the service error code and message unset, because
131
+ // the service never reported one, but the envelope parsed so far is still reported as the body:
132
+ // it names the request id the service logs are keyed by, and the buffered path likewise reports
133
+ // whatever body it received.
134
+ auto ctx = ctx_;
135
+ ctx.ec = ec;
136
+ core::apply_error_details(ctx, stream_.error_details());
137
+ value.first = core::impl::make_error(ctx);
138
+ }
139
+ auto core_meta = stream_.meta_data();
140
+ if (core_meta) {
141
+ value.second = build_analytics_meta_data(std::move(*core_meta));
142
+ }
143
+
144
+ std::vector<std::promise<std::pair<error, analytics_meta_data>>> to_satisfy;
145
+ {
146
+ const std::scoped_lock lk{ meta_mutex_ };
147
+ if (terminal_reached_) {
148
+ return;
149
+ }
150
+ terminal_reached_ = true;
151
+ terminal_value_ = value;
152
+ to_satisfy = std::move(pending_meta_promises_);
153
+ pending_meta_promises_.clear();
154
+ }
155
+ for (auto& promise : to_satisfy) {
156
+ promise.set_value(value);
157
+ }
158
+ // Reached exactly once (the terminal_reached_ guard above returns on every later call), so the
159
+ // operation is finished here: record the latency metric and end the operation span. ec is the
160
+ // terminal error (falsy on a clean drain, request_canceled on teardown before a natural end).
161
+ if (obs_rec_) {
162
+ obs_rec_->finish(ec);
163
+ }
164
+ }
165
+
166
+ auto
167
+ internal_analytics_stream_result::meta_data() -> std::future<std::pair<error, analytics_meta_data>>
168
+ {
169
+ const std::scoped_lock lk{ meta_mutex_ };
170
+ std::promise<std::pair<error, analytics_meta_data>> promise;
171
+ auto future = promise.get_future();
172
+ if (terminal_reached_) {
173
+ promise.set_value(terminal_value_);
174
+ } else {
175
+ pending_meta_promises_.push_back(std::move(promise));
176
+ }
177
+ return future;
178
+ }
179
+
180
+ void
181
+ internal_analytics_stream_result::next(analytics_row_handler&& handler)
182
+ {
183
+ {
184
+ // Idempotent terminal: once the stream has ended, re-deliver the terminal (clean end or the
185
+ // terminal error) instead of issuing a pull that would block forever on the drained channel.
186
+ const std::scoped_lock lk{ meta_mutex_ };
187
+ if (terminal_reached_) {
188
+ return handler(terminal_value_.first, std::nullopt);
189
+ }
190
+ }
191
+ bool expected = false;
192
+ if (!pull_in_flight_.compare_exchange_strong(expected, true)) {
193
+ // Enforce the single-outstanding-next() contract instead of racing the single-consumer channel.
194
+ return handler(
195
+ error{ errc::common::invalid_argument, "a previous next() call is still in flight" },
196
+ std::nullopt);
197
+ }
198
+ // Capture a strong self so the object outlives an in-flight pull; dropping the public handle
199
+ // mid-pull would otherwise destroy this object before the channel completion runs (use-after-
200
+ // free). The stream is always owned via shared_ptr (make_shared in dispatch_analytics_stream).
201
+ stream_.next_row([handler = std::move(handler), self = shared_from_this()](
202
+ std::optional<std::string> row, std::error_code ec) mutable {
203
+ if (row.has_value()) {
204
+ // Real row (ec is falsy). Release the pull gate before invoking the handler so it may
205
+ // immediately issue the next pull.
206
+ self->pull_in_flight_.store(false);
207
+ return handler({}, analytics_row{ to_binary(*row) });
208
+ }
209
+ // Terminal (nullopt row): publish the terminal state and intentionally leave pull_in_flight_
210
+ // set. Every later next() is served by the terminal_reached_ guard (idempotent re-delivery) and
211
+ // must never issue another pull onto the drained channel, so the gate is never reopened — this
212
+ // also backstops a caller that violates the single-outstanding-next() contract from a racing
213
+ // thread before terminal_reached_ becomes visible.
214
+ self->resolve_meta_data(ec);
215
+ if (ec) {
216
+ // Deliver the contextual error resolve_meta_data() has just published rather than building a
217
+ // bare one here. This is the first and usually only observation of a mid-stream terminal, so
218
+ // it has to carry the same diagnostics as every later next() (served by the terminal_reached_
219
+ // guard above) and as meta_data(); constructing a fresh error here would report the one case
220
+ // this class exists to describe with an empty context.
221
+ error terminal_error;
222
+ {
223
+ const std::scoped_lock lk{ self->meta_mutex_ };
224
+ terminal_error = self->terminal_value_.first;
225
+ }
226
+ return handler(std::move(terminal_error), {});
227
+ }
228
+ return handler({}, {});
229
+ });
230
+ }
231
+
232
+ // ---------------------------------------------------------------------------
233
+ // analytics_stream_result public implementation
234
+ // ---------------------------------------------------------------------------
235
+
236
+ analytics_stream_result::analytics_stream_result(
237
+ std::shared_ptr<internal_analytics_stream_result> internal)
238
+ : internal_{ std::move(internal) }
239
+ {
240
+ }
241
+
242
+ void
243
+ analytics_stream_result::next(analytics_row_handler&& handler) const
244
+ {
245
+ if (!internal_) {
246
+ // Empty handle behaves as an immediately-exhausted stream.
247
+ handler(error{}, std::nullopt);
248
+ return;
249
+ }
250
+ return internal_->next(std::move(handler));
251
+ }
252
+
253
+ auto
254
+ analytics_stream_result::next() const -> std::future<std::pair<error, std::optional<analytics_row>>>
255
+ {
256
+ auto barrier = std::make_shared<std::promise<std::pair<error, std::optional<analytics_row>>>>();
257
+ if (!internal_) {
258
+ // Empty handle behaves as an immediately-exhausted stream.
259
+ barrier->set_value({ error{}, std::nullopt });
260
+ return barrier->get_future();
261
+ }
262
+ internal_->next([barrier](const auto& err, const auto& row) mutable {
263
+ barrier->set_value({ err, row });
264
+ });
265
+ return barrier->get_future();
266
+ }
267
+
268
+ auto
269
+ analytics_stream_result::signature() const -> std::optional<codec::binary>
270
+ {
271
+ if (!internal_) {
272
+ return {};
273
+ }
274
+ return internal_->signature();
275
+ }
276
+
277
+ auto
278
+ analytics_stream_result::meta_data() const -> std::future<std::pair<error, analytics_meta_data>>
279
+ {
280
+ if (!internal_) {
281
+ // Empty handle resolves immediately with empty metadata.
282
+ std::promise<std::pair<error, analytics_meta_data>> p;
283
+ p.set_value({ error{}, analytics_meta_data{} });
284
+ return p.get_future();
285
+ }
286
+ return internal_->meta_data();
287
+ }
288
+
289
+ void
290
+ analytics_stream_result::cancel() const
291
+ {
292
+ if (internal_) {
293
+ return internal_->cancel();
294
+ }
295
+ }
296
+
297
+ // ---------------------------------------------------------------------------
298
+ // iterator implementation
299
+ // ---------------------------------------------------------------------------
300
+
301
+ analytics_stream_result::iterator::iterator(
302
+ std::shared_ptr<internal_analytics_stream_result> internal)
303
+ : internal_{ std::move(internal) }
304
+ {
305
+ if (internal_) {
306
+ fetch_item();
307
+ } else {
308
+ // An empty result handle has no rows: the iterator starts already at end.
309
+ terminal_ = true;
310
+ }
311
+ }
312
+
313
+ void
314
+ analytics_stream_result::iterator::fetch_item()
315
+ {
316
+ auto barrier = std::make_shared<std::promise<std::pair<error, std::optional<analytics_row>>>>();
317
+ internal_->next([barrier](const error& err, std::optional<analytics_row> row) mutable {
318
+ barrier->set_value({ err, std::move(row) });
319
+ });
320
+ auto result = barrier->get_future().get();
321
+ if (result.first) {
322
+ // Terminal error: deliver it as one visible element (still != end()) so a range-for loop can
323
+ // observe it; the next increment then advances to true end.
324
+ item_ = { result.first, {} };
325
+ terminal_ = false;
326
+ error_pending_ = true;
327
+ } else if (!result.second.has_value()) {
328
+ // Clean end-of-stream.
329
+ item_ = {};
330
+ terminal_ = true;
331
+ error_pending_ = false;
332
+ } else {
333
+ item_ = { {}, *result.second };
334
+ terminal_ = false;
335
+ error_pending_ = false;
336
+ }
337
+ }
338
+
339
+ auto
340
+ analytics_stream_result::iterator::operator*() const -> std::pair<error, analytics_row>
341
+ {
342
+ return item_;
343
+ }
344
+
345
+ auto
346
+ analytics_stream_result::iterator::operator++() -> analytics_stream_result::iterator&
347
+ {
348
+ if (error_pending_) {
349
+ // The terminal error element has been consumed; advance to end().
350
+ error_pending_ = false;
351
+ item_ = {};
352
+ terminal_ = true;
353
+ return *this;
354
+ }
355
+ fetch_item();
356
+ return *this;
357
+ }
358
+
359
+ auto
360
+ analytics_stream_result::begin() const -> analytics_stream_result::iterator
361
+ {
362
+ // The iterator constructor treats a null internal handle as an already-drained stream, so an
363
+ // empty result handle yields begin() == end().
364
+ return analytics_stream_result::iterator{ internal_ };
365
+ }
366
+
367
+ auto
368
+ analytics_stream_result::end() const -> analytics_stream_result::end_sentinel
369
+ {
370
+ return {};
371
+ }
372
+ } // namespace couchbase
@@ -15,21 +15,24 @@
15
15
  * limitations under the License.
16
16
  */
17
17
 
18
- #include <couchbase/bucket.hxx>
19
-
20
18
  #include "core/cluster.hxx"
21
19
  #include "core/tracing/constants.hxx"
22
20
  #include "core/tracing/tracer_wrapper.hxx"
23
21
  #include "diagnostics.hxx"
24
22
  #include "observability_recorder.hxx"
23
+ #include "wait_until_ready.hxx"
24
+ #include <couchbase/bucket.hxx>
25
+ #include <couchbase/build_config.hxx>
25
26
 
26
27
  #include <couchbase/collection.hxx>
27
28
  #include <couchbase/collection_manager.hxx>
28
29
  #include <couchbase/error.hxx>
30
+ #include <couchbase/error_codes.hxx>
29
31
  #include <couchbase/ping_options.hxx>
30
32
  #include <couchbase/ping_result.hxx>
31
33
  #include <couchbase/scope.hxx>
32
34
 
35
+ #include <chrono>
33
36
  #include <future>
34
37
  #include <memory>
35
38
  #include <string_view>
@@ -68,6 +71,15 @@ public:
68
71
  {
69
72
  auto obs_rec = create_observability_recorder(
70
73
  core::tracing::operation::ping, std::nullopt, options.parent_span);
74
+ #ifdef COUCHBASE_CXX_CLIENT_BUILD_COUCHBASE2
75
+ if (core_.is_protostellar()) {
76
+ // couchbase2 has no per-bucket sessions to probe; mirror cluster::ping and the other SDKs.
77
+ obs_rec->finish(errc::common::feature_not_available);
78
+ return handler(error{ errc::common::feature_not_available,
79
+ "ping is not supported over the couchbase2 protocol" },
80
+ {});
81
+ }
82
+ #endif
71
83
  return core_.ping(
72
84
  options.report_id,
73
85
  name_,
@@ -79,6 +91,20 @@ public:
79
91
  });
80
92
  }
81
93
 
94
+ void wait_until_ready(std::chrono::milliseconds timeout,
95
+ const wait_until_ready_options::built& options,
96
+ wait_until_ready_handler&& handler) const
97
+ {
98
+ return core::impl::wait_until_ready(core_,
99
+ name_,
100
+ timeout,
101
+ options.desired_state,
102
+ core::impl::to_core_service_types(options.service_types),
103
+ [handler = std::move(handler)](std::error_code ec) mutable {
104
+ return handler(couchbase::error{ ec });
105
+ });
106
+ }
107
+
82
108
  private:
83
109
  [[nodiscard]] auto create_observability_recorder(
84
110
  const std::string& operation_name,
@@ -148,6 +174,26 @@ bucket::ping(const couchbase::ping_options& options) const
148
174
  return barrier->get_future();
149
175
  }
150
176
 
177
+ void
178
+ bucket::wait_until_ready(std::chrono::milliseconds timeout,
179
+ const couchbase::wait_until_ready_options& options,
180
+ couchbase::wait_until_ready_handler&& handler) const
181
+ {
182
+ return impl_->wait_until_ready(timeout, options.build(), std::move(handler));
183
+ }
184
+
185
+ auto
186
+ bucket::wait_until_ready(std::chrono::milliseconds timeout,
187
+ const couchbase::wait_until_ready_options& options) const
188
+ -> std::future<error>
189
+ {
190
+ auto barrier = std::make_shared<std::promise<error>>();
191
+ wait_until_ready(timeout, options, [barrier](auto err) mutable {
192
+ barrier->set_value(std::move(err));
193
+ });
194
+ return barrier->get_future();
195
+ }
196
+
151
197
  auto
152
198
  bucket::collections() const -> collection_manager
153
199
  {