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
data/ext/rcb_views.cxx CHANGED
@@ -23,6 +23,7 @@
23
23
  #include <core/operations/management/view_index_get.hxx>
24
24
  #include <core/operations/management/view_index_get_all.hxx>
25
25
  #include <core/operations/management/view_index_upsert.hxx>
26
+ #include <core/utils/url_codec.hxx>
26
27
  #undef COUCHBASE_CXX_CLIENT_IGNORE_CORE_DEPRECATIONS
27
28
 
28
29
  #include <future>
@@ -46,8 +47,8 @@ cb_Backend_view_index_get_all(VALUE self,
46
47
  {
47
48
  auto cluster = cb_backend_to_core_api_cluster(self);
48
49
 
49
- Check_Type(bucket_name, T_STRING);
50
- Check_Type(name_space, T_SYMBOL);
50
+ cb_check_type(bucket_name, T_STRING);
51
+ cb_check_type(name_space, T_SYMBOL);
51
52
 
52
53
  core::design_document_namespace ns{};
53
54
  if (ID type = rb_sym2id(name_space); type == rb_intern("development")) {
@@ -55,8 +56,8 @@ cb_Backend_view_index_get_all(VALUE self,
55
56
  } else if (type == rb_intern("production")) {
56
57
  ns = core::design_document_namespace::production;
57
58
  } else {
58
- rb_raise(rb_eArgError, "Unknown design document namespace: %+" PRIsVALUE, type);
59
- return Qnil;
59
+ throw ruby_exception(rb_eArgError,
60
+ cb_sprintf("Unknown design document namespace: %+" PRIsVALUE, name_space));
60
61
  }
61
62
 
62
63
  try {
@@ -106,10 +107,8 @@ cb_Backend_view_index_get_all(VALUE self,
106
107
  }
107
108
  return res;
108
109
  } catch (const std::system_error& se) {
109
- rb_exc_raise(cb_map_error_code(
110
+ throw ruby_exception(cb_map_error_code(
110
111
  se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
111
- } catch (const ruby_exception& e) {
112
- rb_exc_raise(e.exception_object());
113
112
  }
114
113
  return Qnil;
115
114
  }
@@ -124,9 +123,9 @@ cb_Backend_view_index_get(VALUE self,
124
123
  {
125
124
  auto cluster = cb_backend_to_core_api_cluster(self);
126
125
 
127
- Check_Type(bucket_name, T_STRING);
128
- Check_Type(document_name, T_STRING);
129
- Check_Type(name_space, T_SYMBOL);
126
+ cb_check_type(bucket_name, T_STRING);
127
+ cb_check_type(document_name, T_STRING);
128
+ cb_check_type(name_space, T_SYMBOL);
130
129
 
131
130
  core::design_document_namespace ns{};
132
131
  if (ID type = rb_sym2id(name_space); type == rb_intern("development")) {
@@ -134,8 +133,8 @@ cb_Backend_view_index_get(VALUE self,
134
133
  } else if (type == rb_intern("production")) {
135
134
  ns = core::design_document_namespace::production;
136
135
  } else {
137
- rb_raise(rb_eArgError, "Unknown design document namespace: %+" PRIsVALUE, type);
138
- return Qnil;
136
+ throw ruby_exception(rb_eArgError,
137
+ cb_sprintf("Unknown design document namespace: %+" PRIsVALUE, name_space));
139
138
  }
140
139
 
141
140
  try {
@@ -186,10 +185,8 @@ cb_Backend_view_index_get(VALUE self,
186
185
  rb_hash_aset(res, rb_id2sym(rb_intern("views")), views);
187
186
  return res;
188
187
  } catch (const std::system_error& se) {
189
- rb_exc_raise(cb_map_error_code(
188
+ throw ruby_exception(cb_map_error_code(
190
189
  se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
191
- } catch (const ruby_exception& e) {
192
- rb_exc_raise(e.exception_object());
193
190
  }
194
191
  return Qnil;
195
192
  }
@@ -204,9 +201,9 @@ cb_Backend_view_index_drop(VALUE self,
204
201
  {
205
202
  auto cluster = cb_backend_to_core_api_cluster(self);
206
203
 
207
- Check_Type(bucket_name, T_STRING);
208
- Check_Type(document_name, T_STRING);
209
- Check_Type(name_space, T_SYMBOL);
204
+ cb_check_type(bucket_name, T_STRING);
205
+ cb_check_type(document_name, T_STRING);
206
+ cb_check_type(name_space, T_SYMBOL);
210
207
 
211
208
  core::design_document_namespace ns{};
212
209
  if (ID type = rb_sym2id(name_space); type == rb_intern("development")) {
@@ -214,8 +211,8 @@ cb_Backend_view_index_drop(VALUE self,
214
211
  } else if (type == rb_intern("production")) {
215
212
  ns = core::design_document_namespace::production;
216
213
  } else {
217
- rb_raise(rb_eArgError, "Unknown design document namespace: %+" PRIsVALUE, type);
218
- return Qnil;
214
+ throw ruby_exception(rb_eArgError,
215
+ cb_sprintf("Unknown design document namespace: %+" PRIsVALUE, name_space));
219
216
  }
220
217
 
221
218
  try {
@@ -242,10 +239,8 @@ cb_Backend_view_index_drop(VALUE self,
242
239
  }
243
240
  return Qtrue;
244
241
  } catch (const std::system_error& se) {
245
- rb_exc_raise(cb_map_error_code(
242
+ throw ruby_exception(cb_map_error_code(
246
243
  se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
247
- } catch (const ruby_exception& e) {
248
- rb_exc_raise(e.exception_object());
249
244
  }
250
245
  return Qnil;
251
246
  }
@@ -260,9 +255,9 @@ cb_Backend_view_index_upsert(VALUE self,
260
255
  {
261
256
  auto cluster = cb_backend_to_core_api_cluster(self);
262
257
 
263
- Check_Type(bucket_name, T_STRING);
264
- Check_Type(document, T_HASH);
265
- Check_Type(name_space, T_SYMBOL);
258
+ cb_check_type(bucket_name, T_STRING);
259
+ cb_check_type(document, T_HASH);
260
+ cb_check_type(name_space, T_SYMBOL);
266
261
 
267
262
  core::design_document_namespace ns{};
268
263
  if (ID type = rb_sym2id(name_space); type == rb_intern("development")) {
@@ -270,8 +265,8 @@ cb_Backend_view_index_upsert(VALUE self,
270
265
  } else if (type == rb_intern("production")) {
271
266
  ns = core::design_document_namespace::production;
272
267
  } else {
273
- rb_raise(rb_eArgError, "Unknown design document namespace: %+" PRIsVALUE, type);
274
- return Qnil;
268
+ throw ruby_exception(rb_eArgError,
269
+ cb_sprintf("Unknown design document namespace: %+" PRIsVALUE, name_space));
275
270
  }
276
271
 
277
272
  try {
@@ -280,18 +275,18 @@ cb_Backend_view_index_upsert(VALUE self,
280
275
  req.document.ns = ns;
281
276
  if (VALUE document_name = rb_hash_aref(document, rb_id2sym(rb_intern("name")));
282
277
  !NIL_P(document_name)) {
283
- Check_Type(document_name, T_STRING);
278
+ cb_check_type(document_name, T_STRING);
284
279
  req.document.name = cb_string_new(document_name);
285
280
  }
286
281
  if (VALUE views = rb_hash_aref(document, rb_id2sym(rb_intern("views"))); !NIL_P(views)) {
287
- Check_Type(views, T_ARRAY);
282
+ cb_check_type(views, T_ARRAY);
288
283
  auto entries_num = static_cast<std::size_t>(RARRAY_LEN(views));
289
284
  for (std::size_t i = 0; i < entries_num; ++i) {
290
285
  VALUE entry = rb_ary_entry(views, static_cast<long>(i));
291
- Check_Type(entry, T_HASH);
286
+ cb_check_type(entry, T_HASH);
292
287
  core::management::views::design_document::view view;
293
288
  VALUE name = rb_hash_aref(entry, rb_id2sym(rb_intern("name")));
294
- Check_Type(name, T_STRING);
289
+ cb_check_type(name, T_STRING);
295
290
  view.name = cb_string_new(name);
296
291
  if (VALUE map = rb_hash_aref(entry, rb_id2sym(rb_intern("map"))); !NIL_P(map)) {
297
292
  view.map.emplace(cb_string_new(map));
@@ -322,10 +317,8 @@ cb_Backend_view_index_upsert(VALUE self,
322
317
  }
323
318
  return Qtrue;
324
319
  } catch (const std::system_error& se) {
325
- rb_exc_raise(cb_map_error_code(
320
+ throw ruby_exception(cb_map_error_code(
326
321
  se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
327
- } catch (const ruby_exception& e) {
328
- rb_exc_raise(e.exception_object());
329
322
  }
330
323
  return Qnil;
331
324
  }
@@ -341,10 +334,10 @@ cb_Backend_document_view(VALUE self,
341
334
  {
342
335
  auto cluster = cb_backend_to_core_api_cluster(self);
343
336
 
344
- Check_Type(bucket_name, T_STRING);
345
- Check_Type(design_document_name, T_STRING);
346
- Check_Type(view_name, T_STRING);
347
- Check_Type(name_space, T_SYMBOL);
337
+ cb_check_type(bucket_name, T_STRING);
338
+ cb_check_type(design_document_name, T_STRING);
339
+ cb_check_type(view_name, T_STRING);
340
+ cb_check_type(name_space, T_SYMBOL);
348
341
 
349
342
  core::design_document_namespace ns{};
350
343
  if (ID type = rb_sym2id(name_space); type == rb_intern("development")) {
@@ -352,11 +345,11 @@ cb_Backend_document_view(VALUE self,
352
345
  } else if (type == rb_intern("production")) {
353
346
  ns = core::design_document_namespace::production;
354
347
  } else {
355
- rb_raise(rb_eArgError, "Unknown design document namespace: %+" PRIsVALUE, type);
356
- return Qnil;
348
+ throw ruby_exception(rb_eArgError,
349
+ cb_sprintf("Unknown design document namespace: %+" PRIsVALUE, name_space));
357
350
  }
358
351
  if (!NIL_P(options)) {
359
- Check_Type(options, T_HASH);
352
+ cb_check_type(options, T_HASH);
360
353
  }
361
354
 
362
355
  try {
@@ -439,6 +432,17 @@ cb_Backend_document_view(VALUE self,
439
432
  req.keys.emplace_back(cb_string_new(entry));
440
433
  }
441
434
  }
435
+ if (VALUE raw_params = rb_hash_aref(options, rb_id2sym(rb_intern("raw_parameters")));
436
+ !NIL_P(raw_params)) {
437
+ cb_check_type(raw_params, T_HASH);
438
+ std::map<std::string, std::string> raw{};
439
+ cb_extract_string_hash(raw, raw_params, "raw_parameters");
440
+ // The core appends raw entries to the query string verbatim.
441
+ for (const auto& [name, value] : raw) {
442
+ req.raw[core::utils::string_codec::form_encode(name)] =
443
+ core::utils::string_codec::form_encode(value);
444
+ }
445
+ }
442
446
  }
443
447
 
444
448
  auto parent_span = cb_create_parent_span(req, self);
@@ -486,10 +490,8 @@ cb_Backend_document_view(VALUE self,
486
490
 
487
491
  return res;
488
492
  } catch (const std::system_error& se) {
489
- rb_exc_raise(cb_map_error_code(
493
+ throw ruby_exception(cb_map_error_code(
490
494
  se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
491
- } catch (const ruby_exception& e) {
492
- rb_exc_raise(e.exception_object());
493
495
  }
494
496
  return Qnil;
495
497
  }
@@ -499,11 +501,13 @@ cb_Backend_document_view(VALUE self,
499
501
  void
500
502
  init_views(VALUE cBackend)
501
503
  {
502
- rb_define_method(cBackend, "document_view", cb_Backend_document_view, 6);
503
-
504
- rb_define_method(cBackend, "view_index_get_all", cb_Backend_view_index_get_all, 4);
505
- rb_define_method(cBackend, "view_index_get", cb_Backend_view_index_get, 5);
506
- rb_define_method(cBackend, "view_index_drop", cb_Backend_view_index_drop, 5);
507
- rb_define_method(cBackend, "view_index_upsert", cb_Backend_view_index_upsert, 5);
504
+ rb_define_method(cBackend, "document_view", cb_method<cb_Backend_document_view>::invoke, 6);
505
+
506
+ rb_define_method(
507
+ cBackend, "view_index_get_all", cb_method<cb_Backend_view_index_get_all>::invoke, 4);
508
+ rb_define_method(cBackend, "view_index_get", cb_method<cb_Backend_view_index_get>::invoke, 5);
509
+ rb_define_method(cBackend, "view_index_drop", cb_method<cb_Backend_view_index_drop>::invoke, 5);
510
+ rb_define_method(
511
+ cBackend, "view_index_upsert", cb_method<cb_Backend_view_index_upsert>::invoke, 5);
508
512
  }
509
513
  } // namespace couchbase::ruby
@@ -36,6 +36,13 @@ module ActiveSupport
36
36
  # bucket: "app_cache"
37
37
  # }
38
38
  #
39
+ # +delete_matched+ and +clear+ query with +consistent_with+ the store's writes.
40
+ # By default that covers the last write only, which leaves earlier writes to
41
+ # other vBuckets out of the query until the index catches up. With
42
+ # +mutation_tracking: :all+ the store keeps the newest mutation token of every
43
+ # vBucket it wrote to, so both see every earlier write. It also accepts an
44
+ # object that responds to +record(*tokens)+ and +mutation_state+.
45
+ #
39
46
  # @see https://guides.rubyonrails.org/caching_with_rails.html#cache-stores
40
47
  class CouchbaseStore < Store
41
48
  MAX_KEY_BYTESIZE = 250
@@ -43,6 +50,51 @@ module ActiveSupport
43
50
  logger&.error { "CouchbaseStore: #{method} failed, returned #{returning.inspect}: #{exception.class}: #{exception.message}" }
44
51
  end
45
52
 
53
+ # Default +mutation_tracking+: the token of the last write.
54
+ class LastMutation
55
+ def initialize
56
+ @token = nil
57
+ end
58
+
59
+ def record(*tokens)
60
+ latest = tokens.compact.max_by(&:sequence_number)
61
+ @token = latest if latest
62
+ end
63
+
64
+ def mutation_state
65
+ token = @token
66
+ token && ::Couchbase::MutationState.new(token)
67
+ end
68
+ end
69
+
70
+ # +mutation_tracking: :all+: the newest token of every vBucket written to,
71
+ # at most one per vBucket however many writes there were.
72
+ class AllMutations
73
+ def initialize
74
+ @tokens = {}
75
+ @lock = Mutex.new
76
+ end
77
+
78
+ def record(*tokens)
79
+ @lock.synchronize do
80
+ tokens.compact.each do |token|
81
+ key = [token.bucket_name, token.partition_id]
82
+ known = @tokens[key]
83
+ # After a failover the partition_uuid changes and sequence numbers
84
+ # do not compare across it, so the token recorded last is kept.
85
+ next if known && known.partition_uuid == token.partition_uuid && known.sequence_number >= token.sequence_number
86
+
87
+ @tokens[key] = token
88
+ end
89
+ end
90
+ end
91
+
92
+ def mutation_state
93
+ tokens = @lock.synchronize { @tokens.values }
94
+ ::Couchbase::MutationState.new(*tokens) unless tokens.empty?
95
+ end
96
+ end
97
+
46
98
  # Advertise cache versioning support.
47
99
  def self.supports_cache_versioning?
48
100
  true
@@ -70,7 +122,17 @@ module ActiveSupport
70
122
  @options.delete(:bucket) { raise ArgumentError, "Missing bucket for Couchbase cache store. Use :bucket in the store options" }
71
123
  @couchbase_options[:scope] = @options.delete(:scope) if @options.key?(:scope)
72
124
  @couchbase_options[:collection] = @options.delete(:collection) if @options.key?(:collection)
73
- @last_mutation_token = nil
125
+ @mutations =
126
+ case (tracking = @options.delete(:mutation_tracking) { :last })
127
+ when :last, "last" then LastMutation.new
128
+ when :all, "all" then AllMutations.new
129
+ else
130
+ unless tracking.respond_to?(:record) && tracking.respond_to?(:mutation_state)
131
+ raise ArgumentError, "mutation_tracking must be :last, :all, or respond to #record and #mutation_state"
132
+ end
133
+
134
+ tracking
135
+ end
74
136
  end
75
137
 
76
138
  def collection
@@ -90,9 +152,10 @@ module ActiveSupport
90
152
  # The +matcher+ must be valid pattern for N1QL +REGEXP_MATCHES+ function. More info at
91
153
  # https://docs.couchbase.com/server/current/n1ql/n1ql-language-reference/patternmatchingfun.html#section_regex_matches
92
154
  #
93
- # Because the operation performed on query engine, and it might take time to propagate changes
94
- # from key/value engine to the indexer. Therefore the keys, that were created a moment ago
95
- # might not be deleted.
155
+ # The query is consistent with the writes this store recorded, as selected by
156
+ # +mutation_tracking+. With the default +:last+, keys written shortly before the
157
+ # last write to other vBuckets might not be deleted. Writes by other processes
158
+ # are not covered.
96
159
  #
97
160
  # Also this method assumes, that primary index created on the target bucket
98
161
  def delete_matched(matcher, _options = nil)
@@ -106,7 +169,8 @@ module ActiveSupport
106
169
  raise NotImplementedError, "Unable to convert #{matcher.inspect} to Regexp pattern"
107
170
  end
108
171
  operation_options = ::Couchbase::Options::Query(named_parameters: {"pattern" => pattern}, metrics: true)
109
- operation_options.consistent_with(::Couchbase::MutationState.new(@last_mutation_token)) if @last_mutation_token
172
+ mutation_state = @mutations.mutation_state
173
+ operation_options.consistent_with(mutation_state) if mutation_state
110
174
  begin
111
175
  result = cluster.query("DELETE FROM #{scope_qualifier} cache_store_ WHERE REGEXP_MATCHES(META(cache_store_).id, $pattern)",
112
176
  operation_options)
@@ -127,7 +191,7 @@ module ActiveSupport
127
191
  res = collection.binary.increment(
128
192
  key, ::Couchbase::Options::Increment(delta: amount, expiry: expires_in, initial: initial)
129
193
  )
130
- @last_mutation_token = res.mutation_token
194
+ @mutations.record(res.mutation_token)
131
195
  res.content
132
196
  end
133
197
  end
@@ -147,7 +211,7 @@ module ActiveSupport
147
211
  res = collection.binary.decrement(
148
212
  key, ::Couchbase::Options::Decrement(delta: amount, expiry: expires_in, initial: initial)
149
213
  )
150
- @last_mutation_token = res.mutation_token
214
+ @mutations.record(res.mutation_token)
151
215
  res.content
152
216
  end
153
217
  end
@@ -164,7 +228,8 @@ module ActiveSupport
164
228
  cluster.buckets.flush_bucket(@couchbase_options[:bucket_name])
165
229
  else
166
230
  operation_options = ::Couchbase::Options::Query.new
167
- operation_options.consistent_with(::Couchbase::MutationState.new(@last_mutation_token)) if @last_mutation_token
231
+ mutation_state = @mutations.mutation_state
232
+ operation_options.consistent_with(mutation_state) if mutation_state
168
233
  cluster.query("DELETE FROM #{scope_qualifier}", operation_options)
169
234
  end
170
235
  end
@@ -239,7 +304,7 @@ module ActiveSupport
239
304
  end
240
305
  failsafe(:write_entry, returning: false) do
241
306
  res = collection.upsert(key, payload, ::Couchbase::Options::Upsert(transcoder: nil, expiry: expires_in))
242
- @last_mutation_token = res.mutation_token
307
+ @mutations.record(res.mutation_token)
243
308
  true
244
309
  end
245
310
  end
@@ -259,7 +324,7 @@ module ActiveSupport
259
324
  successful = collection.upsert_multi(serialize_entries(entries, **options), operation_options).select(&:success?)
260
325
  return 0 if successful.empty?
261
326
 
262
- @last_mutation_token = successful.max_by { |r| r.mutation_token.sequence_number }
327
+ @mutations.record(*successful.map(&:mutation_token))
263
328
  successful.count
264
329
  end
265
330
  end
@@ -269,7 +334,7 @@ module ActiveSupport
269
334
  def delete_entry(key, **_options)
270
335
  failsafe(:delete_entry, returning: false) do
271
336
  res = collection.remove(key)
272
- @last_mutation_token = res.mutation_token
337
+ @mutations.record(res.mutation_token)
273
338
  true
274
339
  end
275
340
  end
@@ -282,7 +347,7 @@ module ActiveSupport
282
347
  successful = collection.remove_multi(entries).select(&:success?)
283
348
  return 0 if successful.empty?
284
349
 
285
- @last_mutation_token = successful.max_by { |r| r.mutation_token.sequence_number }
350
+ @mutations.record(*successful.map(&:mutation_token))
286
351
  successful.count
287
352
  end
288
353
  end
@@ -149,5 +149,25 @@ module Couchbase
149
149
  end
150
150
  end
151
151
  end
152
+
153
+ # Waits until the bucket reaches the desired state, actively pinging its services
154
+ #
155
+ # With +:online+, the wait also requires the bucket's vbucket map to be placed: every vbucket has its active copy
156
+ # and each replica the data nodes can hold assigned to a node. +:degraded+ only pings.
157
+ #
158
+ # +Thread#raise+ does not interrupt the wait. It ends on success, on +timeout+, or when the cluster is disconnected.
159
+ #
160
+ # @param [Integer, #in_milliseconds] timeout the maximum time to wait
161
+ # @param [Options::WaitUntilReady] options
162
+ #
163
+ # @return [void]
164
+ #
165
+ # @raise [Error::UnambiguousTimeout] if the desired state is not reached within +timeout+
166
+ # @raise [Error::ClusterClosed] if the cluster has been disconnected
167
+ # @raise [Error::InvalidArgument] if +timeout+ is negative or longer than 365 days, or +options+ name an
168
+ # unsupported desired state or service type
169
+ def wait_until_ready(timeout, options = Options::WaitUntilReady::DEFAULT)
170
+ @backend.wait_until_ready(@name, Utils::Time.extract_duration(timeout), options.to_backend)
171
+ end
152
172
  end
153
173
  end
@@ -326,26 +326,45 @@ module Couchbase
326
326
  #
327
327
  # @return [PingResult]
328
328
  def ping(options = Options::Ping::DEFAULT)
329
- resp = @backend.ping(nil, options.to_backend)
330
- PingResult.new do |res|
331
- res.version = resp[:version]
332
- res.id = resp[:id]
333
- res.sdk = resp[:sdk]
334
- resp[:services].each do |type, svcs|
335
- res.services[type] = svcs.map do |svc|
336
- PingResult::ServiceInfo.new do |info|
337
- info.id = svc[:id]
338
- info.state = svc[:state]
339
- info.latency = svc[:latency]
340
- info.remote = svc[:remote]
341
- info.local = svc[:local]
342
- info.error = svc[:error]
329
+ @observability.record_operation(Observability::OP_PING, options.parent_span, self) do |_obs_handler|
330
+ resp = @backend.ping(nil, options.to_backend)
331
+ PingResult.new do |res|
332
+ res.version = resp[:version]
333
+ res.id = resp[:id]
334
+ res.sdk = resp[:sdk]
335
+ resp[:services].each do |type, svcs|
336
+ res.services[type] = svcs.map do |svc|
337
+ PingResult::ServiceInfo.new do |info|
338
+ info.id = svc[:id]
339
+ info.state = svc[:state]
340
+ info.latency = svc[:latency]
341
+ info.remote = svc[:remote]
342
+ info.local = svc[:local]
343
+ info.error = svc[:error]
344
+ end
343
345
  end
344
346
  end
345
347
  end
346
348
  end
347
349
  end
348
350
 
351
+ # Waits until the cluster reaches the desired state, actively pinging its services
352
+ #
353
+ # +Thread#raise+ does not interrupt the wait. It ends on success, on +timeout+, or when the cluster is disconnected.
354
+ #
355
+ # @param [Integer, #in_milliseconds] timeout the maximum time to wait
356
+ # @param [Options::WaitUntilReady] options
357
+ #
358
+ # @return [void]
359
+ #
360
+ # @raise [Error::UnambiguousTimeout] if the desired state is not reached within +timeout+
361
+ # @raise [Error::ClusterClosed] if the cluster has been disconnected
362
+ # @raise [Error::InvalidArgument] if +timeout+ is negative or longer than 365 days, or +options+ name an
363
+ # unsupported desired state or service type
364
+ def wait_until_ready(timeout, options = Options::WaitUntilReady::DEFAULT)
365
+ @backend.wait_until_ready(nil, Utils::Time.extract_duration(timeout), options.to_backend)
366
+ end
367
+
349
368
  private
350
369
 
351
370
  # Initialize {Cluster} object
@@ -18,6 +18,7 @@ require "couchbase/errors"
18
18
  require "couchbase/collection_options"
19
19
  require "couchbase/binary_collection"
20
20
  require "couchbase/key_value_scan"
21
+ require "couchbase/get_replica_strategy"
21
22
 
22
23
  module Couchbase
23
24
  # Provides access to all collection APIs
@@ -203,6 +204,40 @@ module Couchbase
203
204
  end
204
205
  end
205
206
 
207
+ # Reads the document from the replica the strategy selects.
208
+ #
209
+ # @param [String] id the document id which is used to uniquely identify it.
210
+ # @param [GetReplicaStrategy] strategy selects the replica to read from
211
+ # @param [Options::GetReplica] options request customization
212
+ #
213
+ # @example Read the document from the second replica
214
+ # res = collection.get_replica("airline_10", GetReplicaStrategy.from_index(:second))
215
+ # res.replica? #=> true
216
+ # res.content["name"]
217
+ #
218
+ # @raise [Error::DocumentNotFoundOnReplica] if the replica does not hold the document
219
+ # @raise [Error::ReplicaIndexOutOfBounds] if the bucket is not configured with the requested replica
220
+ # @raise [Error::ReplicaIndexCurrentlyUnavailable] if the vbucket map places the requested replica on no node
221
+ # @raise [Error::UnambiguousTimeout] if the replica does not answer before the timeout
222
+ # @raise [Error::FeatureNotAvailable] over +couchbase2://+, which does not carry the operation
223
+ #
224
+ # @since 3.9.0
225
+ #
226
+ # @return [GetReplicaResult]
227
+ def get_replica(id, strategy, options = Options::GetReplica::DEFAULT)
228
+ @observability.record_operation(Observability::OP_GET_REPLICA, options.parent_span, self, :kv) do |obs_handler|
229
+ resp = @backend.document_get_replica(@bucket_name, @scope_name, @name, id, strategy.to_backend,
230
+ options.to_backend, obs_handler)
231
+ GetReplicaResult.new do |res|
232
+ res.transcoder = options.transcoder
233
+ res.cas = resp[:cas]
234
+ res.flags = resp[:flags]
235
+ res.encoded = resp[:content]
236
+ res.is_replica = true
237
+ end
238
+ end
239
+ end
240
+
206
241
  # Reads all available replicas and active, and returns the first found.
207
242
  #
208
243
  # @param [String] id the document id which is used to uniquely identify it.
@@ -210,7 +245,7 @@ module Couchbase
210
245
  #
211
246
  # @example Get document contents
212
247
  # res = collection.get_any_replica("customer123")
213
- # res.is_active #=> false
248
+ # res.replica? #=> true when a replica answered first, false for the active copy
214
249
  # res.content["addresses"]
215
250
  #
216
251
  # # {"billing"=>
@@ -185,6 +185,24 @@ module Couchbase
185
185
  class DocumentNotFound < CouchbaseError
186
186
  end
187
187
 
188
+ # Indicates that the replica selected by {Collection#get_replica} does not hold the document.
189
+ #
190
+ # @since 3.9.0
191
+ class DocumentNotFoundOnReplica < DocumentNotFound
192
+ end
193
+
194
+ # Indicates that {Collection#get_replica} requested a replica the bucket is not configured with.
195
+ #
196
+ # @since 3.9.0
197
+ class ReplicaIndexOutOfBounds < CouchbaseError
198
+ end
199
+
200
+ # Indicates that {Collection#get_replica} requested a configured replica. The vbucket map places it on no node.
201
+ #
202
+ # @since 3.9.0
203
+ class ReplicaIndexCurrentlyUnavailable < CouchbaseError
204
+ end
205
+
188
206
  # Indicates an operation completed but no successful document was retrievable.
189
207
  class DocumentIrretrievable < CouchbaseError
190
208
  end
@@ -17,14 +17,23 @@
17
17
  module Couchbase
18
18
  module ForkHooks
19
19
  def _fork
20
- Couchbase::Backend.notify_fork(:prepare)
21
- pid = super
22
- if pid
23
- Couchbase::Backend.notify_fork(:parent)
24
- else
25
- Couchbase::Backend.notify_fork(:child)
20
+ # :prepare stops the instances and only :parent or :child restarts them, so an asynchronous
21
+ # exception is deferred everywhere except inside the fork itself.
22
+ Thread.handle_interrupt(Object => :never) do
23
+ parent_pid = Process.pid
24
+ Couchbase::Backend.notify_fork(:prepare)
25
+ begin
26
+ Thread.handle_interrupt(Object => :immediate) do
27
+ # A check point: an interrupt deferred during :prepare lands here, before the fork.
28
+ Thread.pass
29
+ super
30
+ end
31
+ ensure
32
+ # Decided by pid rather than by the return value, which an exception raised after the fork
33
+ # never delivers.
34
+ Couchbase::Backend.notify_fork(Process.pid == parent_pid ? :parent : :child)
35
+ end
26
36
  end
27
- pid
28
37
  end
29
38
  end
30
39
  end