couchbase 3.8.1 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (475) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  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 +214 -155
  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 +325 -25
  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 +66 -0
  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 +316 -317
  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 +275 -14
  131. data/ext/couchbase/core/io/streams.hxx +53 -0
  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/bucket_create.cxx +37 -38
  183. data/ext/couchbase/core/operations/management/bucket_update.cxx +26 -28
  184. data/ext/couchbase/core/operations/management/change_password.cxx +2 -0
  185. data/ext/couchbase/core/operations/management/collection_drop.cxx +5 -1
  186. data/ext/couchbase/core/operations/management/error_utils.cxx +59 -5
  187. data/ext/couchbase/core/operations/management/error_utils.hxx +29 -1
  188. data/ext/couchbase/core/operations/management/eventing_deploy_function.cxx +9 -3
  189. data/ext/couchbase/core/operations/management/eventing_drop_function.cxx +8 -3
  190. data/ext/couchbase/core/operations/management/eventing_get_all_functions.cxx +4 -2
  191. data/ext/couchbase/core/operations/management/eventing_get_function.cxx +5 -3
  192. data/ext/couchbase/core/operations/management/eventing_get_status.cxx +4 -2
  193. data/ext/couchbase/core/operations/management/eventing_pause_function.cxx +9 -3
  194. data/ext/couchbase/core/operations/management/eventing_resume_function.cxx +9 -3
  195. data/ext/couchbase/core/operations/management/eventing_undeploy_function.cxx +9 -3
  196. data/ext/couchbase/core/operations/management/eventing_upsert_function.cxx +9 -3
  197. data/ext/couchbase/core/operations/management/group_drop.cxx +3 -1
  198. data/ext/couchbase/core/operations/management/group_get.cxx +3 -1
  199. data/ext/couchbase/core/operations/management/group_upsert.cxx +11 -8
  200. data/ext/couchbase/core/operations/management/query_index_build.cxx +5 -2
  201. data/ext/couchbase/core/operations/management/query_index_create.cxx +9 -3
  202. data/ext/couchbase/core/operations/management/query_index_drop.cxx +11 -4
  203. data/ext/couchbase/core/operations/management/query_index_get_all.cxx +1 -1
  204. data/ext/couchbase/core/operations/management/query_index_get_all_deferred.cxx +1 -1
  205. data/ext/couchbase/core/operations/management/scope_drop.cxx +5 -1
  206. data/ext/couchbase/core/operations/management/scope_get_all.cxx +6 -1
  207. data/ext/couchbase/core/operations/management/search_get_stats.cxx +10 -0
  208. data/ext/couchbase/core/operations/management/search_index_analyze_document.cxx +3 -2
  209. data/ext/couchbase/core/operations/management/search_index_control_ingest.cxx +4 -3
  210. data/ext/couchbase/core/operations/management/search_index_control_plan_freeze.cxx +4 -3
  211. data/ext/couchbase/core/operations/management/search_index_control_query.cxx +4 -3
  212. data/ext/couchbase/core/operations/management/search_index_drop.cxx +2 -2
  213. data/ext/couchbase/core/operations/management/search_index_get.cxx +2 -2
  214. data/ext/couchbase/core/operations/management/search_index_get_documents_count.cxx +3 -2
  215. data/ext/couchbase/core/operations/management/search_index_get_stats.cxx +3 -1
  216. data/ext/couchbase/core/operations/management/search_index_upsert.cxx +2 -2
  217. data/ext/couchbase/core/operations/management/user_drop.cxx +3 -1
  218. data/ext/couchbase/core/operations/management/user_get.cxx +3 -1
  219. data/ext/couchbase/core/operations/management/user_upsert.cxx +12 -9
  220. data/ext/couchbase/core/operations/management/view_index_drop.cxx +1 -1
  221. data/ext/couchbase/core/operations/management/view_index_get.cxx +1 -1
  222. data/ext/couchbase/core/operations/management/view_index_upsert.cxx +1 -1
  223. data/ext/couchbase/core/operations/operation_traits.hxx +18 -0
  224. data/ext/couchbase/core/operations/query_response_parsing.cxx +211 -0
  225. data/ext/couchbase/core/operations/query_response_parsing.hxx +60 -0
  226. data/ext/couchbase/core/operations_fwd.hxx +3 -3
  227. data/ext/couchbase/core/origin.cxx +54 -26
  228. data/ext/couchbase/core/origin.hxx +12 -0
  229. data/ext/couchbase/core/orphan_reporter.cxx +2 -1
  230. data/ext/couchbase/core/platform/random.cc +7 -7
  231. data/ext/couchbase/core/protocol/client_request.cxx +2 -2
  232. data/ext/couchbase/core/protocol/client_request.hxx +38 -21
  233. data/ext/couchbase/core/protocol/client_response.cxx +11 -3
  234. data/ext/couchbase/core/protocol/client_response.hxx +27 -6
  235. data/ext/couchbase/core/protocol/cmd_append.cxx +2 -2
  236. data/ext/couchbase/core/protocol/cmd_cluster_map_change_notification.cxx +2 -2
  237. data/ext/couchbase/core/protocol/cmd_decrement.cxx +6 -6
  238. data/ext/couchbase/core/protocol/cmd_get.cxx +1 -1
  239. data/ext/couchbase/core/protocol/cmd_get_and_lock.cxx +2 -2
  240. data/ext/couchbase/core/protocol/cmd_get_and_touch.cxx +2 -2
  241. data/ext/couchbase/core/protocol/cmd_get_cluster_config.cxx +6 -4
  242. data/ext/couchbase/core/protocol/cmd_get_collection_id.cxx +2 -2
  243. data/ext/couchbase/core/protocol/cmd_get_error_map.cxx +1 -1
  244. data/ext/couchbase/core/protocol/cmd_get_meta.cxx +4 -4
  245. data/ext/couchbase/core/protocol/cmd_get_replica.cxx +1 -1
  246. data/ext/couchbase/core/protocol/cmd_hello.cxx +1 -1
  247. data/ext/couchbase/core/protocol/cmd_increment.cxx +6 -6
  248. data/ext/couchbase/core/protocol/cmd_insert.cxx +4 -4
  249. data/ext/couchbase/core/protocol/cmd_lookup_in.cxx +4 -3
  250. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.cxx +4 -3
  251. data/ext/couchbase/core/protocol/cmd_mutate_in.cxx +10 -9
  252. data/ext/couchbase/core/protocol/cmd_mutate_in.hxx +10 -10
  253. data/ext/couchbase/core/protocol/cmd_observe_seqno.cxx +7 -7
  254. data/ext/couchbase/core/protocol/cmd_prepend.cxx +2 -2
  255. data/ext/couchbase/core/protocol/cmd_remove.cxx +2 -2
  256. data/ext/couchbase/core/protocol/cmd_replace.cxx +4 -4
  257. data/ext/couchbase/core/protocol/cmd_touch.cxx +1 -1
  258. data/ext/couchbase/core/protocol/cmd_upsert.cxx +4 -4
  259. data/ext/couchbase/core/protocol/datatype.hxx +118 -1
  260. data/ext/couchbase/core/protocol/frame_info_utils.cxx +1 -1
  261. data/ext/couchbase/core/protocol/magic.hxx +4 -0
  262. data/ext/couchbase/core/protocol/magic_fmt.hxx +3 -0
  263. data/ext/couchbase/core/protocol/server_request.hxx +3 -1
  264. data/ext/couchbase/core/protocol/status.cxx +1 -1
  265. data/ext/couchbase/core/protostellar/analytics_converter.hxx +171 -0
  266. data/ext/couchbase/core/protostellar/bucket_admin_converter.hxx +301 -0
  267. data/ext/couchbase/core/protostellar/collection_admin_converter.hxx +92 -0
  268. data/ext/couchbase/core/protostellar/component.cxx +2445 -0
  269. data/ext/couchbase/core/protostellar/component.hxx +391 -0
  270. data/ext/couchbase/core/{columnar/bootstrap_notification_subscriber.hxx → protostellar/compression_settings.hxx} +11 -10
  271. data/ext/couchbase/core/protostellar/credentials.cxx +233 -0
  272. data/ext/couchbase/core/protostellar/credentials.hxx +88 -0
  273. data/ext/couchbase/core/protostellar/dispatcher.cxx +57 -0
  274. data/ext/couchbase/core/protostellar/dispatcher.hxx +482 -0
  275. data/ext/couchbase/core/protostellar/error_utils.cxx +293 -0
  276. data/ext/couchbase/core/protostellar/error_utils.hxx +97 -0
  277. data/ext/couchbase/core/protostellar/json_payload.hxx +49 -0
  278. data/ext/couchbase/core/protostellar/kv_converter.cxx +70 -0
  279. data/ext/couchbase/core/protostellar/kv_converter.hxx +600 -0
  280. data/ext/couchbase/core/protostellar/query_converter.hxx +265 -0
  281. data/ext/couchbase/core/protostellar/query_index_admin_converter.hxx +291 -0
  282. data/ext/couchbase/core/protostellar/query_proto.hxx +73 -0
  283. data/ext/couchbase/core/protostellar/search_converter.hxx +244 -0
  284. data/ext/couchbase/core/protostellar/search_index_admin_converter.hxx +156 -0
  285. data/ext/couchbase/core/protostellar/view_converter.hxx +158 -0
  286. data/ext/couchbase/core/query_stream.cxx +447 -0
  287. data/ext/couchbase/core/query_stream.hxx +141 -0
  288. data/ext/couchbase/core/query_stream_component.cxx +243 -0
  289. data/ext/couchbase/core/query_stream_component.hxx +68 -0
  290. data/ext/couchbase/core/range_scan_load_balancer.cxx +15 -8
  291. data/ext/couchbase/core/range_scan_orchestrator.cxx +15 -3
  292. data/ext/couchbase/core/response_handler.hxx +41 -4
  293. data/ext/couchbase/core/row_streamer.cxx +332 -46
  294. data/ext/couchbase/core/row_streamer.hxx +31 -1
  295. data/ext/couchbase/core/row_streamer_options.hxx +55 -0
  296. data/ext/couchbase/core/sasl/client.h +3 -0
  297. data/ext/couchbase/core/search_scoring.hxx +66 -0
  298. data/ext/couchbase/core/stream_error_details.hxx +69 -0
  299. data/ext/couchbase/core/timeout_defaults.hxx +0 -1
  300. data/ext/couchbase/core/topology/capabilities.hxx +6 -0
  301. data/ext/couchbase/core/topology/capabilities_fmt.hxx +3 -0
  302. data/ext/couchbase/core/topology/configuration.cxx +21 -6
  303. data/ext/couchbase/core/topology/configuration.hxx +29 -8
  304. data/ext/couchbase/core/topology/configuration_json.hxx +3 -0
  305. data/ext/couchbase/core/topology/error_map_json.hxx +3 -1
  306. data/ext/couchbase/core/tracing/threshold_logging_tracer.cxx +70 -4
  307. data/ext/couchbase/core/tracing/threshold_logging_tracer.hxx +10 -0
  308. data/ext/couchbase/core/transactions/active_transaction_record.cxx +0 -34
  309. data/ext/couchbase/core/transactions/attempt_context_impl.cxx +362 -241
  310. data/ext/couchbase/core/transactions/attempt_context_impl.hxx +24 -3
  311. data/ext/couchbase/core/transactions/error_list.hxx +2 -2
  312. data/ext/couchbase/core/transactions/get_multi_fetch.hxx +160 -0
  313. data/ext/couchbase/core/transactions/get_multi_orchestrator.cxx +326 -125
  314. data/ext/couchbase/core/transactions/get_multi_transaction_id.hxx +62 -0
  315. data/ext/couchbase/core/transactions/internal/atr_entry.hxx +22 -2
  316. data/ext/couchbase/core/transactions/internal/transaction_context.hxx +2 -2
  317. data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +23 -1
  318. data/ext/couchbase/core/transactions/internal/utils.hxx +50 -14
  319. data/ext/couchbase/core/transactions/staged_mutation.cxx +23 -18
  320. data/ext/couchbase/core/transactions/staged_mutation.hxx +15 -4
  321. data/ext/couchbase/core/transactions/transaction_context.cxx +55 -40
  322. data/ext/couchbase/core/transactions/transaction_get_result.hxx +16 -0
  323. data/ext/couchbase/core/transactions/transactions.cxx +3 -55
  324. data/ext/couchbase/core/transactions/transactions_cleanup.cxx +194 -66
  325. data/ext/couchbase/core/transactions/transactions_config.cxx +0 -11
  326. data/ext/couchbase/core/transactions/utils.cxx +10 -0
  327. data/ext/couchbase/core/transactions/waitable_op_list.hxx +15 -4
  328. data/ext/couchbase/core/transactions.hxx +9 -9
  329. data/ext/couchbase/core/utils/byteswap.hxx +166 -9
  330. data/ext/couchbase/core/utils/connection_string.cxx +50 -85
  331. data/ext/couchbase/core/utils/connection_string.hxx +15 -0
  332. data/ext/couchbase/core/{columnar/backoff_calculator.hxx → utils/deadline.hxx} +13 -13
  333. data/ext/couchbase/core/utils/duration_parser.cxx +1 -1
  334. data/ext/couchbase/core/utils/json_streaming_lexer.cxx +48 -5
  335. data/ext/couchbase/core/utils/json_streaming_lexer.hxx +4 -1
  336. data/ext/couchbase/core/utils/movable_function.hxx +301 -52
  337. data/ext/couchbase/core/utils/name_codec.hxx +154 -11
  338. data/ext/couchbase/core/{columnar/retry_info.hxx → utils/process_id.hxx} +18 -13
  339. data/ext/couchbase/core/utils/url_codec.cxx +12 -51
  340. data/ext/couchbase/core/websocket_codec.cxx +3 -29
  341. data/ext/couchbase/couchbase/analytics_options.hxx +21 -10
  342. data/ext/couchbase/couchbase/analytics_row.hxx +105 -0
  343. data/ext/couchbase/couchbase/analytics_stream_result.hxx +266 -0
  344. data/ext/couchbase/couchbase/boolean_query.hxx +3 -3
  345. data/ext/couchbase/couchbase/bucket.hxx +57 -0
  346. data/ext/couchbase/couchbase/cluster.hxx +216 -5
  347. data/ext/couchbase/{core/columnar/security_options.hxx → couchbase/cluster_state.hxx} +18 -14
  348. data/ext/couchbase/couchbase/codec/lenient_json_transcoder.hxx +69 -0
  349. data/ext/couchbase/couchbase/collection.hxx +234 -14
  350. data/ext/couchbase/couchbase/common_durability_options.hxx +18 -3
  351. data/ext/couchbase/couchbase/conjunction_query.hxx +1 -1
  352. data/ext/couchbase/couchbase/create_dataset_analytics_options.hxx +6 -1
  353. data/ext/couchbase/couchbase/date_range_query.hxx +2 -2
  354. data/ext/couchbase/couchbase/decrement_options.hxx +1 -1
  355. data/ext/couchbase/couchbase/disjunction_query.hxx +1 -1
  356. data/ext/couchbase/couchbase/error.hxx +32 -0
  357. data/ext/couchbase/couchbase/error_codes.hxx +32 -0
  358. data/ext/couchbase/couchbase/geo_bounding_box_query.hxx +1 -1
  359. data/ext/couchbase/couchbase/geo_distance_query.hxx +1 -1
  360. data/ext/couchbase/couchbase/geo_polygon_query.hxx +1 -1
  361. data/ext/couchbase/couchbase/get_replica_options.hxx +68 -0
  362. data/ext/couchbase/couchbase/get_replica_result.hxx +5 -3
  363. data/ext/couchbase/couchbase/get_replica_strategy.hxx +161 -0
  364. data/ext/couchbase/couchbase/get_result.hxx +1 -0
  365. data/ext/couchbase/couchbase/increment_options.hxx +1 -1
  366. data/ext/couchbase/couchbase/insert_options.hxx +1 -1
  367. data/ext/couchbase/couchbase/match_phrase_query.hxx +1 -1
  368. data/ext/couchbase/couchbase/match_query.hxx +1 -1
  369. data/ext/couchbase/couchbase/mutate_in_options.hxx +3 -3
  370. data/ext/couchbase/couchbase/network_options.hxx +1 -1
  371. data/ext/couchbase/couchbase/node_id.hxx +42 -14
  372. data/ext/couchbase/couchbase/node_id_for_options.hxx +7 -1
  373. data/ext/couchbase/couchbase/node_ids_options.hxx +8 -2
  374. data/ext/couchbase/couchbase/numeric_range_query.hxx +1 -1
  375. data/ext/couchbase/couchbase/phrase_query.hxx +1 -1
  376. data/ext/couchbase/couchbase/prefix_query.hxx +1 -1
  377. data/ext/couchbase/couchbase/query_options.hxx +23 -12
  378. data/ext/couchbase/couchbase/query_row.hxx +111 -0
  379. data/ext/couchbase/couchbase/query_stream_result.hxx +302 -0
  380. data/ext/couchbase/couchbase/query_string_query.hxx +3 -3
  381. data/ext/couchbase/couchbase/regexp_query.hxx +1 -1
  382. data/ext/couchbase/couchbase/replace_options.hxx +3 -3
  383. data/ext/couchbase/couchbase/result.hxx +14 -3
  384. data/ext/couchbase/couchbase/scan_result_item.hxx +1 -0
  385. data/ext/couchbase/couchbase/scope.hxx +85 -2
  386. data/ext/couchbase/couchbase/search_options.hxx +58 -8
  387. data/ext/couchbase/couchbase/search_scoring.hxx +94 -0
  388. data/ext/couchbase/couchbase/search_scoring_none.hxx +51 -0
  389. data/ext/couchbase/couchbase/search_scoring_reciprocal_rank_fusion.hxx +88 -0
  390. data/ext/couchbase/couchbase/search_scoring_relative_score_fusion.hxx +70 -0
  391. data/ext/couchbase/couchbase/term_range_query.hxx +1 -1
  392. data/ext/couchbase/couchbase/tracing/request_span.hxx +46 -0
  393. data/ext/couchbase/couchbase/transactions/transaction_get_multi_replicas_from_preferred_server_group_result.hxx +23 -21
  394. data/ext/couchbase/couchbase/transactions/transaction_get_multi_result.hxx +24 -19
  395. data/ext/couchbase/couchbase/transactions/transaction_get_result.hxx +17 -3
  396. data/ext/couchbase/couchbase/transactions/transactions_config.hxx +4 -2
  397. data/ext/couchbase/couchbase/transactions.hxx +27 -18
  398. data/ext/couchbase/couchbase/upsert_options.hxx +3 -3
  399. data/ext/couchbase/couchbase/vector_query.hxx +1 -1
  400. data/ext/couchbase/couchbase/wait_until_ready_options.hxx +111 -0
  401. data/ext/couchbase/couchbase/wildcard_query.hxx +1 -1
  402. data/ext/extconf.rb +15 -10
  403. data/ext/rcb_analytics.cxx +82 -102
  404. data/ext/rcb_backend.cxx +42 -36
  405. data/ext/rcb_backend.hxx +2 -0
  406. data/ext/rcb_buckets.cxx +47 -59
  407. data/ext/rcb_collections.cxx +42 -52
  408. data/ext/rcb_crud.cxx +345 -224
  409. data/ext/rcb_diagnostics.cxx +117 -27
  410. data/ext/rcb_exceptions.cxx +152 -99
  411. data/ext/rcb_exceptions.hxx +25 -0
  412. data/ext/rcb_extras.cxx +18 -19
  413. data/ext/rcb_hdr_histogram.cxx +19 -4
  414. data/ext/rcb_logger.cxx +202 -27
  415. data/ext/rcb_logger.hxx +12 -0
  416. data/ext/rcb_multi.cxx +40 -40
  417. data/ext/rcb_observability.cxx +7 -5
  418. data/ext/rcb_query.cxx +99 -142
  419. data/ext/rcb_range_scan.cxx +41 -35
  420. data/ext/rcb_search.cxx +98 -99
  421. data/ext/rcb_users.cxx +36 -56
  422. data/ext/rcb_utils.cxx +100 -37
  423. data/ext/rcb_utils.hxx +287 -33
  424. data/ext/rcb_version.cxx +1 -1
  425. data/ext/rcb_views.cxx +55 -51
  426. data/lib/active_support/cache/couchbase_store.rb +77 -12
  427. data/lib/couchbase/bucket.rb +20 -0
  428. data/lib/couchbase/cluster.rb +33 -14
  429. data/lib/couchbase/collection.rb +36 -1
  430. data/lib/couchbase/errors.rb +18 -0
  431. data/lib/couchbase/fork_hooks.rb +16 -7
  432. data/lib/couchbase/get_replica_strategy.rb +89 -0
  433. data/lib/couchbase/logger.rb +1 -1
  434. data/lib/couchbase/management/analytics_index_manager.rb +15 -15
  435. data/lib/couchbase/management/bucket_manager.rb +6 -6
  436. data/lib/couchbase/management/collection_manager.rb +6 -6
  437. data/lib/couchbase/management/query_index_manager.rb +7 -7
  438. data/lib/couchbase/management/search_index_manager.rb +13 -13
  439. data/lib/couchbase/management/user_manager.rb +10 -10
  440. data/lib/couchbase/management/view_index_manager.rb +5 -5
  441. data/lib/couchbase/options.rb +181 -44
  442. data/lib/couchbase/protostellar/bucket.rb +4 -0
  443. data/lib/couchbase/protostellar/cluster.rb +4 -0
  444. data/lib/couchbase/protostellar/collection.rb +4 -0
  445. data/lib/couchbase/protostellar/error_handling.rb +2 -1
  446. data/lib/couchbase/protostellar/request.rb +1 -0
  447. data/lib/couchbase/protostellar/request_generator/kv.rb +16 -2
  448. data/lib/couchbase/protostellar/request_generator/search.rb +17 -1
  449. data/lib/couchbase/protostellar/retry/orchestrator.rb +3 -2
  450. data/lib/couchbase/protostellar/retry/strategies/fail_fast.rb +33 -0
  451. data/lib/couchbase/protostellar/retry/strategies.rb +1 -0
  452. data/lib/couchbase/search_options.rb +95 -6
  453. data/lib/couchbase/version.rb +1 -1
  454. metadata +92 -33
  455. data/ext/0001-fix-build-for-mingw-w64-ucrt-x86_64-toolchain.patch +0 -40
  456. data/ext/couchbase/core/columnar/agent.hxx +0 -71
  457. data/ext/couchbase/core/columnar/agent_config.hxx +0 -59
  458. data/ext/couchbase/core/columnar/background_bootstrap_listener.hxx +0 -42
  459. data/ext/couchbase/core/columnar/backoff_calculator.cxx +0 -62
  460. data/ext/couchbase/core/columnar/columnar_agent.cxx +0 -147
  461. data/ext/couchbase/core/columnar/columnar_agent_config.cxx +0 -48
  462. data/ext/couchbase/core/columnar/columnar_error.cxx +0 -51
  463. data/ext/couchbase/core/columnar/database_management_options.hxx +0 -56
  464. data/ext/couchbase/core/columnar/error.hxx +0 -51
  465. data/ext/couchbase/core/columnar/error_codes.cxx +0 -107
  466. data/ext/couchbase/core/columnar/error_codes.hxx +0 -75
  467. data/ext/couchbase/core/columnar/management_component.cxx +0 -300
  468. data/ext/couchbase/core/columnar/management_component.hxx +0 -56
  469. data/ext/couchbase/core/columnar/query_component.cxx +0 -523
  470. data/ext/couchbase/core/columnar/query_component.hxx +0 -57
  471. data/ext/couchbase/core/columnar/query_options.hxx +0 -59
  472. data/ext/couchbase/core/columnar/query_result.cxx +0 -130
  473. data/ext/couchbase/core/columnar/query_result.hxx +0 -78
  474. data/ext/couchbase/core/io/config_tracker.cxx +0 -687
  475. data/ext/couchbase/core/io/config_tracker.hxx +0 -123
@@ -15,6 +15,8 @@
15
15
  * limitations under the License.
16
16
  */
17
17
 
18
+ #include <couchbase/build_config.hxx>
19
+
18
20
  #include "core/cluster.hxx"
19
21
 
20
22
  #include "analytics.hxx"
@@ -23,6 +25,7 @@
23
25
  #include "core/cluster_options.hxx"
24
26
  #include "core/core_sdk_shim.hxx"
25
27
  #include "core/io/ip_protocol.hxx"
28
+ #include "core/io/streams.hxx"
26
29
  #include "core/origin.hxx"
27
30
  #include "core/tls_verify_mode.hxx"
28
31
  #include "core/tracing/constants.hxx"
@@ -36,6 +39,7 @@
36
39
  #include "observability_recorder.hxx"
37
40
  #include "query.hxx"
38
41
  #include "search.hxx"
42
+ #include "wait_until_ready.hxx"
39
43
 
40
44
  #include <couchbase/analytics_index_manager.hxx>
41
45
  #include <couchbase/analytics_options.hxx>
@@ -46,6 +50,7 @@
46
50
  #include <couchbase/cluster_options.hxx>
47
51
  #include <couchbase/diagnostics_options.hxx>
48
52
  #include <couchbase/diagnostics_result.hxx>
53
+ #include <couchbase/error_codes.hxx>
49
54
  #include <couchbase/fmt/error.hxx>
50
55
  #include <couchbase/fork_event.hxx>
51
56
  #include <couchbase/ip_protocol.hxx>
@@ -65,6 +70,8 @@
65
70
  #include <asio/execution_context.hpp>
66
71
  #include <asio/post.hpp>
67
72
 
73
+ #include <gsl/assert>
74
+
68
75
  #include <functional>
69
76
  #include <future>
70
77
  #include <memory>
@@ -173,6 +180,8 @@ options_to_origin(const std::string& connection_string, cluster_options::built o
173
180
  user_options.server_group = opts.network.server_group;
174
181
 
175
182
  user_options.enable_compression = opts.compression.enabled;
183
+ user_options.compression_min_size = opts.compression.min_size;
184
+ user_options.compression_min_ratio = opts.compression.min_ratio;
176
185
 
177
186
  user_options.enable_metrics = opts.metrics.enabled;
178
187
  if (opts.metrics.enabled) {
@@ -323,6 +332,28 @@ public:
323
332
  });
324
333
  }
325
334
 
335
+ // The open notify_fork(child) starts and does not wait for. Requests issued meanwhile wait in the
336
+ // core for the bootstrap. A failed open leaves the core closed, so they then get cluster_closed.
337
+ //
338
+ // The handler captures `this`. It runs inline when open() fails or succeeds without I/O, and
339
+ // otherwise on the IO thread before do_close() joins it: do_close() closes the core first, which
340
+ // completes a pending open.
341
+ void reopen()
342
+ {
343
+ opened_future_ = opened_.get_future().share();
344
+ core_.open(options_to_origin(connection_string_, options_), [this](std::error_code ec) {
345
+ if (ec) {
346
+ CB_LOG_ERROR("Unable to reconnect instance after fork: {}", ec.message());
347
+ }
348
+ opened_.set_value();
349
+ });
350
+ // Created now, not after the bootstrap, so transactions() never sees it unset and nothing
351
+ // writes it from the IO thread. The requests its cleanup issues wait in the core for the
352
+ // bootstrap.
353
+ transactions_ =
354
+ std::make_shared<core::transactions::transactions>(core_, options_.transactions);
355
+ }
356
+
326
357
  void query(std::string statement, query_options::built options, query_handler&& handler) const
327
358
  {
328
359
  auto obs_rec = create_observability_recorder(
@@ -339,6 +370,22 @@ public:
339
370
  });
340
371
  }
341
372
 
373
+ void query_stream(std::string statement,
374
+ query_options::built options,
375
+ query_stream_handler&& handler) const
376
+ {
377
+ // Instrument the streaming operation exactly like the buffered query(): build the recorder,
378
+ // thread its operation span into the request as parent_span, and hand the recorder to the
379
+ // stream so it finishes (latency metric + span end) at the terminal.
380
+ auto obs_rec = create_observability_recorder(
381
+ core::tracing::operation::query, core::service_type::query, options.parent_span);
382
+ obs_rec->with_query_statement(statement, options);
383
+ auto request = core::impl::build_query_request(
384
+ std::move(statement), {}, std::move(options), obs_rec->operation_span());
385
+ core::impl::dispatch_query_stream(
386
+ core_, std::move(request), std::move(obs_rec), std::move(handler));
387
+ }
388
+
342
389
  void analytics_query(std::string statement,
343
390
  analytics_options::built options,
344
391
  analytics_handler&& handler) const
@@ -357,10 +404,36 @@ public:
357
404
  });
358
405
  }
359
406
 
407
+ void analytics_query_stream(std::string statement,
408
+ analytics_options::built options,
409
+ analytics_stream_handler&& handler) const
410
+ {
411
+ // Instrument the streaming operation exactly like the buffered analytics_query() (see
412
+ // query_stream above for the recorder lifetime).
413
+ auto obs_rec = create_observability_recorder(
414
+ core::tracing::operation::analytics, core::service_type::analytics, options.parent_span);
415
+ obs_rec->with_query_statement(statement, options);
416
+ auto request = core::impl::build_analytics_request(
417
+ std::move(statement), std::move(options), {}, {}, obs_rec->operation_span());
418
+ core::impl::dispatch_analytics_stream(
419
+ core_, std::move(request), std::move(obs_rec), std::move(handler));
420
+ }
421
+
360
422
  void ping(const ping_options::built& options, ping_handler&& handler) const
361
423
  {
362
424
  auto obs_rec = create_observability_recorder(
363
425
  core::tracing::operation::ping, std::nullopt, options.parent_span);
426
+ #ifdef COUCHBASE_CXX_CLIENT_BUILD_COUCHBASE2
427
+ if (core_.is_protostellar()) {
428
+ // couchbase2 is a thin gRPC client with no per-service sessions to actively probe, and RFC 77
429
+ // defines no ping semantics for it. Mirror Java/Go/.NET, which surface ping as
430
+ // feature_not_available on this protocol, rather than returning a misleading empty report.
431
+ obs_rec->finish(errc::common::feature_not_available);
432
+ return handler(error{ errc::common::feature_not_available,
433
+ "ping is not supported over the couchbase2 protocol" },
434
+ {});
435
+ }
436
+ #endif
364
437
  return core_.ping(
365
438
  options.report_id,
366
439
  {},
@@ -376,6 +449,16 @@ public:
376
449
  {
377
450
  auto obs_rec = create_observability_recorder(
378
451
  core::tracing::operation::diagnostics, std::nullopt, options.parent_span);
452
+ #ifdef COUCHBASE_CXX_CLIENT_BUILD_COUCHBASE2
453
+ if (core_.is_protostellar()) {
454
+ // No per-service sessions exist to report on over couchbase2, and the RFC 77 Diagnostics
455
+ // section is empty. Mirror Java/Go/.NET (feature_not_available) instead of an empty report.
456
+ obs_rec->finish(errc::common::feature_not_available);
457
+ return handler(error{ errc::common::feature_not_available,
458
+ "diagnostics is not supported over the couchbase2 protocol" },
459
+ {});
460
+ }
461
+ #endif
379
462
  return core_.diagnostics(
380
463
  options.report_id,
381
464
  [obs_rec = std::move(obs_rec), handler = std::move(handler)](const auto& resp) mutable {
@@ -384,6 +467,20 @@ public:
384
467
  });
385
468
  }
386
469
 
470
+ void wait_until_ready(std::chrono::milliseconds timeout,
471
+ const wait_until_ready_options::built& options,
472
+ wait_until_ready_handler&& handler) const
473
+ {
474
+ return core::impl::wait_until_ready(core_,
475
+ std::nullopt,
476
+ timeout,
477
+ options.desired_state,
478
+ core::impl::to_core_service_types(options.service_types),
479
+ [handler = std::move(handler)](std::error_code ec) mutable {
480
+ return handler(couchbase::error{ ec });
481
+ });
482
+ }
483
+
387
484
  void search(std::string index_name,
388
485
  couchbase::search_request request,
389
486
  const search_options::built& options,
@@ -414,19 +511,124 @@ public:
414
511
 
415
512
  void notify_fork(fork_event event)
416
513
  {
514
+ // asio requires notify_fork() to run with no thread inside io_context::run():
515
+ //
516
+ // "This function must not be called while any other execution_context
517
+ // function, or any function on an I/O object associated with the
518
+ // execution_context, is being called in another thread."
519
+ // -- asio/execution_context.hpp
520
+ //
521
+ // That is not a formality for fork_child: epoll_reactor::notify_fork() closes
522
+ // and recreates epoll_fd_, timer_fd_ and the interrupter, then rewrites every
523
+ // descriptor registration. Running it against a live reactor makes the IO
524
+ // thread epoll_wait() on a descriptor another thread is closing, and then
525
+ // dereference whatever epoll reports as a descriptor_state.
526
+ //
527
+ // So the fixup goes in the window where the IO thread is not running: after
528
+ // the join in fork_prepare, and before the restart that starts the new one.
417
529
  if (event == fork_event::prepare) {
530
+ // Quiesce the transactions cleanup threads BEFORE stopping the io_context.
531
+ // transactions_cleanup::stop() joins workers that may be blocking on a KV
532
+ // operation, and only the IO thread can complete those -- so stopping the
533
+ // io_context first can leave that join waiting forever.
534
+ if (transactions_) {
535
+ transactions_->notify_fork(event);
536
+ }
418
537
  io_.stop();
419
- io_thread_.join();
538
+ // Guarded like do_close() below, and for the same reason: close() already
539
+ // stopped the io_context and joined this thread, so a notify_fork(prepare)
540
+ // afterwards has nothing left to join -- and join() on a thread that is not
541
+ // joinable throws std::system_error, out of a void public API.
542
+ if (io_thread_.joinable()) {
543
+ io_thread_.join();
544
+ }
545
+ }
546
+
547
+ // Our own IO thread is gone at this point, checkable in program order
548
+ // rather than only by a sanitizer: fork_prepare has just joined it, and
549
+ // fork_child/fork_parent inherit an already-joined one, because prepare runs
550
+ // before fork() and only the forking thread survives into the child. If a
551
+ // later change moves the restart back above this line, this fires
552
+ // immediately instead of turning into an intermittent use-after-free.
553
+ //
554
+ // The transactions cleanup threads were stopped above, before io_.stop(), so
555
+ // by here the only threads this cluster owned are gone.
556
+ Expects(!io_thread_.joinable());
557
+
558
+ if (event == fork_event::prepare) {
559
+ try {
560
+ io_.notify_fork(fork_event_to_asio(event));
561
+ } catch (...) {
562
+ // Undo everything this prepare did, then report. Returning stopped and threadless
563
+ // would hang ~cluster_impl, which waits on a completion only the IO thread can
564
+ // deliver -- the same hazard as the fork_parent path below. The fork
565
+ // must not go ahead, but the cluster stays usable and destructible.
566
+ //
567
+ // The io_context comes back first: restarting cleanup spawns workers that issue KV
568
+ // operations, and only the IO thread completes those. Restoring cleanup matters as
569
+ // much as restoring the thread -- it was stopped above, and leaving it stopped
570
+ // would silently disable lost-attempts cleanup for the rest of the process while
571
+ // this function claimed the cluster was fine.
572
+ //
573
+ // Note for the caller: do not try to compensate by calling notify_fork(parent)
574
+ // after this throws. Prepare has already been undone here, and that call would
575
+ // find a restarted IO thread and trip the precondition above.
576
+ io_.restart();
577
+ io_thread_ = std::thread{ [&io = io_] {
578
+ io.run();
579
+ } };
580
+ if (transactions_) {
581
+ transactions_->notify_fork(fork_event::parent);
582
+ }
583
+ throw;
584
+ }
585
+ } else if (event == fork_event::parent) {
586
+ io_.restart();
587
+ try {
588
+ io_.notify_fork(fork_event_to_asio(event));
589
+ } catch (...) {
590
+ // A service's notify_fork() threw. The io_context is unusable after that (asio says
591
+ // to destroy it), but destruction itself needs a runner: do_close()
592
+ // waits on a completion only the IO thread can deliver, so returning
593
+ // from here stopped and threadless would hang ~cluster_impl instead of
594
+ // surfacing the failure.
595
+ io_thread_ = std::thread{ [&io = io_] {
596
+ io.run();
597
+ } };
598
+ throw;
599
+ }
600
+ io_thread_ = std::thread{ [&io = io_] {
601
+ io.run();
602
+ } };
420
603
  } else {
421
- // TODO(SA): close all sockets in fork_event::child
604
+ // The sockets of this io_context share open file descriptions with the parent, and their
605
+ // pending reads, writes and timers belong to the parent's sessions. The child detaches every
606
+ // registered stream and socket, then runs the inherited core's teardown to completion. The
607
+ // teardown cannot reach the parent's connections through them.
608
+ //
609
+ // close() comes before the fixup. It sets stopped_, so if the fixup throws, ~cluster_impl
610
+ // still completes without a runner.
611
+ std::promise<void> closed;
612
+ auto closed_future = closed.get_future();
613
+ core_.close([closed = std::move(closed)]() mutable {
614
+ closed.set_value();
615
+ });
616
+ // The fixup gives the child its own reactor, and on kqueue it is the only code that repairs
617
+ // kqueue_fd_. It must come before the detach: releasing a socket removes it from the
618
+ // reactor, and until the fixup that reactor is the parent's.
619
+ io_.notify_fork(fork_event_to_asio(event));
620
+ core::io::detach_inherited_sockets(io_);
422
621
  io_.restart();
423
622
  io_thread_ = std::thread{ [&io = io_] {
424
623
  io.run();
425
624
  } };
625
+ closed_future.get();
426
626
  }
427
- io_.notify_fork(fork_event_to_asio(event));
428
627
 
429
- if (event != fork_event::child && transactions_) {
628
+ // prepare was handled above, before the io_context was stopped. The child does
629
+ // not restart cleanup on this impl: it is about to be replaced, and the
630
+ // replacement starts its own.
631
+ if (event == fork_event::parent && transactions_) {
430
632
  transactions_->notify_fork(event);
431
633
  }
432
634
  }
@@ -436,6 +638,13 @@ public:
436
638
  // Spawn new thread to avoid joining IO thread from the same thread
437
639
  std::thread([self = shared_from_this(), handler = std::move(handler)]() mutable {
438
640
  self->do_close();
641
+ // Drop the reference before signalling completion, not after. handler() is what releases
642
+ // the caller's wait, so anything this thread still owns afterwards outlives that wait. When
643
+ // this is the last reference, releasing it later means ~cluster_impl -- which starts another
644
+ // thread and joins the IO thread -- runs unsynchronised with the caller, and a caller that
645
+ // returns from main() leaves those threads running while static destructors tear down the
646
+ // gRPC and abseil singletons underneath them.
647
+ self.reset();
439
648
  handler();
440
649
  }).detach();
441
650
  }
@@ -445,14 +654,33 @@ public:
445
654
  return core_;
446
655
  }
447
656
 
448
- [[nodiscard]] auto transactions() const -> std::shared_ptr<core::transactions::transactions>
657
+ [[nodiscard]] auto core_transactions() const
658
+ -> const std::shared_ptr<core::transactions::transactions>&
449
659
  {
450
660
  return transactions_;
451
661
  }
452
662
 
663
+ [[nodiscard]] auto transactions() const -> std::shared_ptr<transactions::transactions>
664
+ {
665
+ return std::make_shared<transactions::transactions>(transactions_);
666
+ }
667
+
453
668
  private:
454
669
  void do_close()
455
670
  {
671
+ if (opened_future_.valid() &&
672
+ opened_future_.wait_for(std::chrono::seconds::zero()) != std::future_status::ready) {
673
+ // Closing the core fails the pending bootstrap and releases the requests the transactions
674
+ // cleanup holds, so neither wait below runs to bootstrap_timeout. The second core_.close()
675
+ // further down finds the core stopped and returns at once.
676
+ std::promise<void> core_stopped;
677
+ auto f = core_stopped.get_future();
678
+ core_.close([core_stopped = std::move(core_stopped)]() mutable {
679
+ core_stopped.set_value();
680
+ });
681
+ f.get();
682
+ opened_future_.wait();
683
+ }
456
684
  if (auto txns = std::move(transactions_); txns != nullptr) {
457
685
  // blocks until cleanup is finished
458
686
  txns->close();
@@ -487,7 +715,10 @@ private:
487
715
  cluster_options::built options_;
488
716
  asio::io_context io_{ ASIO_CONCURRENCY_HINT_SAFE };
489
717
  core::cluster core_{ io_ };
490
- std::shared_ptr<core::transactions::transactions> transactions_{ nullptr };
718
+ std::shared_ptr<couchbase::core::transactions::transactions> transactions_{ nullptr };
719
+ // Set by reopen(); fulfilled once its open has finished, either way. do_close() reads it.
720
+ std::promise<void> opened_{};
721
+ std::shared_future<void> opened_future_{};
491
722
  std::thread io_thread_{ [&io = io_] {
492
723
  io.run();
493
724
  } };
@@ -508,6 +739,19 @@ extract_core_cluster(const couchbase::cluster& cluster) -> const core::cluster&
508
739
  return reinterpret_cast<const std::shared_ptr<cluster_impl>*>(&cluster)->get()->core();
509
740
  }
510
741
 
742
+ /*
743
+ * This function exists only for usage in the unit tests, and might be removed at any moment.
744
+ * Avoid using it unless it is absolutely necessary.
745
+ */
746
+ auto
747
+ extract_core_transactions(const couchbase::cluster& cluster)
748
+ -> const std::shared_ptr<core::transactions::transactions>&
749
+ {
750
+ return reinterpret_cast<const std::shared_ptr<cluster_impl>*>(&cluster)
751
+ ->get()
752
+ ->core_transactions();
753
+ }
754
+
511
755
  void
512
756
  cluster::query(std::string statement, const query_options& options, query_handler&& handler) const
513
757
  {
@@ -526,6 +770,26 @@ cluster::query(std::string statement, const query_options& options) const
526
770
  return future;
527
771
  }
528
772
 
773
+ void
774
+ cluster::query_stream(std::string statement,
775
+ const query_options& options,
776
+ query_stream_handler&& handler) const
777
+ {
778
+ return impl_->query_stream(std::move(statement), options.build(), std::move(handler));
779
+ }
780
+
781
+ auto
782
+ cluster::query_stream(std::string statement, const query_options& options) const
783
+ -> std::future<std::pair<error, query_stream_result>>
784
+ {
785
+ auto barrier = std::make_shared<std::promise<std::pair<error, query_stream_result>>>();
786
+ auto future = barrier->get_future();
787
+ query_stream(std::move(statement), options, [barrier](auto err, auto result) {
788
+ barrier->set_value({ std::move(err), std::move(result) });
789
+ });
790
+ return future;
791
+ }
792
+
529
793
  void
530
794
  cluster::analytics_query(std::string statement,
531
795
  const analytics_options& options,
@@ -546,6 +810,26 @@ cluster::analytics_query(std::string statement, const analytics_options& options
546
810
  return future;
547
811
  }
548
812
 
813
+ void
814
+ cluster::analytics_query_stream(std::string statement,
815
+ const analytics_options& options,
816
+ analytics_stream_handler&& handler) const
817
+ {
818
+ return impl_->analytics_query_stream(std::move(statement), options.build(), std::move(handler));
819
+ }
820
+
821
+ auto
822
+ cluster::analytics_query_stream(std::string statement, const analytics_options& options) const
823
+ -> std::future<std::pair<error, analytics_stream_result>>
824
+ {
825
+ auto barrier = std::make_shared<std::promise<std::pair<error, analytics_stream_result>>>();
826
+ auto future = barrier->get_future();
827
+ analytics_query_stream(std::move(statement), options, [barrier](auto err, auto result) {
828
+ barrier->set_value({ std::move(err), std::move(result) });
829
+ });
830
+ return future;
831
+ }
832
+
549
833
  void
550
834
  cluster::ping(const couchbase::ping_options& options, couchbase::ping_handler&& handler) const
551
835
  {
@@ -581,6 +865,26 @@ cluster::diagnostics(const couchbase::diagnostics_options& options) const
581
865
  return barrier->get_future();
582
866
  }
583
867
 
868
+ void
869
+ cluster::wait_until_ready(std::chrono::milliseconds timeout,
870
+ const couchbase::wait_until_ready_options& options,
871
+ couchbase::wait_until_ready_handler&& handler) const
872
+ {
873
+ return impl_->wait_until_ready(timeout, options.build(), std::move(handler));
874
+ }
875
+
876
+ auto
877
+ cluster::wait_until_ready(std::chrono::milliseconds timeout,
878
+ const couchbase::wait_until_ready_options& options) const
879
+ -> std::future<error>
880
+ {
881
+ auto barrier = std::make_shared<std::promise<error>>();
882
+ wait_until_ready(timeout, options, [barrier](auto err) mutable {
883
+ barrier->set_value(std::move(err));
884
+ });
885
+ return barrier->get_future();
886
+ }
887
+
584
888
  void
585
889
  cluster::search(std::string index_name,
586
890
  search_request request,
@@ -640,6 +944,16 @@ cluster::connect(const std::string& connection_string,
640
944
  auto
641
945
  cluster::notify_fork(fork_event event) -> void
642
946
  {
947
+ #if defined(_WIN32)
948
+ // No fork(2) on Windows, so there is nothing to prepare for or recover from.
949
+ // The function stays part of the API on every platform -- callers, the wrapper
950
+ // SDKs especially, should not have to compile differently per platform -- but
951
+ // here it does nothing. Doing the POSIX work instead would stop and restart the
952
+ // io_context and re-bootstrap the cluster for no reason, and asio's IOCP
953
+ // backend has no notify_fork to apply either.
954
+ (void)event;
955
+ return;
956
+ #else
643
957
  if (!impl_) {
644
958
  return;
645
959
  }
@@ -648,25 +962,11 @@ cluster::notify_fork(fork_event event) -> void
648
962
  return;
649
963
  }
650
964
 
651
- auto new_impl = std::make_shared<cluster_impl>(impl_->connection_string(), impl_->options());
652
- impl_.reset();
653
-
654
- {
655
- auto barrier = std::make_shared<std::promise<void>>();
656
- auto future = barrier->get_future();
657
-
658
- new_impl->open([this, barrier, new_impl](const auto& err, const auto& /* c */) {
659
- if (err.ec()) {
660
- // TODO(SA): we should fall to background reconnect loop similar to Columnar build
661
- CB_LOG_ERROR("Unable to reconnect instance after fork: {}", err.ec().message());
662
- return;
663
- }
664
- impl_ = new_impl;
665
- barrier->set_value();
666
- });
667
-
668
- future.get();
669
- }
965
+ impl_ = std::make_shared<cluster_impl>(impl_->connection_string(), impl_->options());
966
+ // Does not wait for the bootstrap: a cluster whose nodes do not answer would hold the child for
967
+ // the bootstrap timeout. The child has one thread here, so nothing reads impl_ concurrently.
968
+ impl_->reopen();
969
+ #endif
670
970
  }
671
971
 
672
972
  void