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
@@ -17,106 +17,355 @@
17
17
 
18
18
  #pragma once
19
19
 
20
+ #include <cstddef>
20
21
  #include <functional>
21
22
  #include <memory>
23
+ #include <new>
24
+ #include <type_traits>
25
+ #include <utility>
22
26
 
23
- /* replace with standard version once http://wg21.link/P0288 will be accepted and implemented */
27
+ /* replace with std::move_only_function once http://wg21.link/P0288 is available (C++23) */
24
28
  namespace couchbase::core::utils
25
29
  {
30
+ #ifdef __clang_analyzer__
31
+ // Declared but never defined: an opaque sink (analysis only; analysis does not link, and it is
32
+ // absent from every real build). See emplace() below -- handing the owned target pointer to a
33
+ // non-const opaque sink marks it "escaped" so MallocChecker stops tracking an allocation it would
34
+ // otherwise lose inside asio's deeply templated post/dispatch machinery and report as a spurious
35
+ // leak. The parameter is NON-const on purpose: checkPointerEscapeAux only releases a symbol through
36
+ // a const pointer when it is new/new[]-family, but unconditionally through a non-const pointer.
37
+ void
38
+ movable_function_analyzer_escape(void*) noexcept;
39
+ #endif
40
+
26
41
  template<typename Signature>
27
- class movable_function : public std::function<Signature>
28
- {
29
- template<typename Functor, typename En = void>
30
- struct wrapper;
42
+ class movable_function;
31
43
 
32
- template<typename Functor>
33
- struct wrapper<Functor, std::enable_if_t<std::is_copy_constructible_v<Functor>>> {
34
- Functor fn;
44
+ /**
45
+ * A move-only, type-erased callable, equivalent in spirit to std::move_only_function (C++23).
46
+ *
47
+ * A target that fits the inline buffer and is nothrow-move-constructible is stored in place, so the
48
+ * common asio/KV handlers (a captured shared_ptr `self` plus a few members) are type-erased with no
49
+ * heap allocation; larger targets are held on the heap. The type owns its target and transfers
50
+ * ownership on move (copying is not provided). It offers `operator bool` and comparison against
51
+ * nullptr, and throws std::bad_function_call when invoked while empty.
52
+ */
53
+ template<typename R, typename... Args>
54
+ class movable_function<R(Args...)>
55
+ {
56
+ #ifdef __clang_analyzer__
57
+ // Analyzer-only implementation (compiled only under the Clang Static Analyzer, never in real
58
+ // builds). The production small-buffer path below frees its target through an indirect
59
+ // `vtable_->destroy(buffer_)` function pointer the analyzer cannot resolve; blind to the free,
60
+ // MallocChecker reports spurious "Potential memory leak" at every caller that stores a
61
+ // heap-owning handler (libstdc++'s own std::move_only_function hits the identical limitation,
62
+ // llvm-project#69602). Under analysis we instead own the target via
63
+ // std::unique_ptr<callable_base>, whose destruction is an ordinary virtual delete that
64
+ // MallocChecker models natively -- no manual vtable, no unresolved indirect free, no escape
65
+ // heuristics. This models the same own-once / free-once / move-transfers semantics as the real
66
+ // path, so it does not mask genuine leaks.
67
+ struct callable_base {
68
+ callable_base() = default;
69
+ callable_base(const callable_base&) = delete;
70
+ callable_base(callable_base&&) = delete;
71
+ auto operator=(const callable_base&) -> callable_base& = delete;
72
+ auto operator=(callable_base&&) -> callable_base& = delete;
73
+ virtual ~callable_base() = default;
74
+ virtual auto invoke(Args... args) -> R = 0;
75
+ };
35
76
 
36
- template<typename... Args>
37
- auto operator()(Args&&... args)
77
+ template<typename F>
78
+ struct callable_model : callable_base {
79
+ F fn;
80
+ // Forwarding ctor so the target is copied from an lvalue or moved from an rvalue, matching the
81
+ // production `decayed(std::forward<F>(f))` -- a plain `F&&` parameter would reject lvalue
82
+ // targets.
83
+ template<typename U>
84
+ explicit callable_model(U&& u)
85
+ : fn(std::forward<U>(u))
86
+ {
87
+ }
88
+ auto invoke(Args... args) -> R override
38
89
  {
39
- return fn(std::forward<Args>(args)...);
90
+ if constexpr (std::is_void_v<R>) {
91
+ fn(std::forward<Args>(args)...);
92
+ } else {
93
+ return fn(std::forward<Args>(args)...);
94
+ }
40
95
  }
41
96
  };
42
97
 
43
- template<typename Functor>
44
- struct copy_wrapper {
45
- Functor fn;
98
+ std::unique_ptr<callable_base> holder_{};
46
99
 
47
- explicit copy_wrapper(Functor&& f)
48
- : fn(std::move(f))
49
- {
50
- }
100
+ template<typename F>
101
+ void emplace(F&& f)
102
+ {
103
+ holder_ = std::make_unique<callable_model<std::decay_t<F>>>(std::forward<F>(f));
104
+ // Escape the owned block: some callers (e.g. asio::post/dispatch) move *this into templated
105
+ // machinery the analyzer cannot follow, where it would otherwise lose this allocation and
106
+ // report a spurious leak. holder_.get() is a direct object pointer, so the non-const escape
107
+ // releases exactly the callable_model block (see the sink declaration).
108
+ movable_function_analyzer_escape(static_cast<void*>(holder_.get()));
109
+ }
110
+
111
+ void move_from(movable_function&& other) noexcept
112
+ {
113
+ holder_ = std::move(other.holder_);
114
+ }
115
+
116
+ void reset() noexcept
117
+ {
118
+ holder_.reset();
119
+ }
120
+ #else
121
+ // Sized to hold typical handlers (e.g. a shared_ptr self, a time_point, and a shared_ptr span)
122
+ // inline; larger callables fall back to the heap. The 6-pointer estimate is 48 bytes on 64-bit;
123
+ // a 48-byte floor keeps that inline capacity on 32-bit too (where 6 pointers would be only 24
124
+ // bytes), so the small-buffer optimization does not silently regress to more heap allocations.
125
+ static constexpr std::size_t buffer_size = (6 * sizeof(void*) > 48) ? (6 * sizeof(void*)) : 48;
126
+
127
+ struct vtable {
128
+ R (*invoke)(void* self, Args&&... args);
129
+ void (*move)(void* dst, void* src) noexcept; // move-construct dst from src, then destroy src
130
+ void (*destroy)(void* self) noexcept;
51
131
  };
52
132
 
53
- template<typename Functor>
54
- struct wrapper<Functor,
55
- std::enable_if_t<!std::is_copy_constructible_v<Functor> &&
56
- std::is_move_constructible_v<Functor>>> {
57
- std::shared_ptr<copy_wrapper<Functor>> fnPtr;
133
+ template<typename F>
134
+ static constexpr bool fits_inline_v =
135
+ sizeof(F) <= buffer_size && alignof(F) <= alignof(std::max_align_t) &&
136
+ std::is_nothrow_move_constructible_v<F>;
58
137
 
59
- explicit wrapper(Functor&& f)
60
- : fnPtr(new copy_wrapper<Functor>(std::move(f)))
61
- {
62
- }
138
+ template<typename F>
139
+ static auto inline_vtable() -> const vtable&
140
+ {
141
+ // The target lives in buffer_ (an unsigned char array) via placement-new, so accesses go
142
+ // through std::launder to obtain a pointer with the target's lifetime rather than the array's.
143
+ static const vtable vt{
144
+ [](void* self, Args&&... args) -> R {
145
+ // For a void signature the target's result is discardable (std::is_invocable_r_v<void, ...>
146
+ // admits a value-returning callable), so a value-returning target must be invoked without a
147
+ // return statement -- `return <non-void>;` in a void thunk is ill-formed.
148
+ if constexpr (std::is_void_v<R>) {
149
+ (*std::launder(static_cast<F*>(self)))(std::forward<Args>(args)...);
150
+ } else {
151
+ return (*std::launder(static_cast<F*>(self)))(std::forward<Args>(args)...);
152
+ }
153
+ },
154
+ [](void* dst, void* src) noexcept {
155
+ ::new (dst) F(std::move(*std::launder(static_cast<F*>(src))));
156
+ std::launder(static_cast<F*>(src))->~F();
157
+ },
158
+ [](void* self) noexcept {
159
+ std::launder(static_cast<F*>(self))->~F();
160
+ },
161
+ };
162
+ return vt;
163
+ }
63
164
 
64
- wrapper(wrapper&& /* other */) noexcept = default;
65
- auto operator=(wrapper&& /* other */) noexcept -> wrapper& = default;
165
+ template<typename F>
166
+ static auto heap_vtable() -> const vtable&
167
+ {
168
+ // The buffer holds an owned F* (placement-new'd in emplace()), so every access to that pointer
169
+ // goes through std::launder to reflect the pointer object's lifetime, not the array's.
170
+ static const vtable vt{
171
+ [](void* self, Args&&... args) -> R {
172
+ // Same void-result handling as the inline thunk: discard a value-returning target rather
173
+ // than emit `return <non-void>;` in a void-returning thunk.
174
+ if constexpr (std::is_void_v<R>) {
175
+ (**std::launder(static_cast<F**>(self)))(std::forward<Args>(args)...);
176
+ } else {
177
+ return (**std::launder(static_cast<F**>(self)))(std::forward<Args>(args)...);
178
+ }
179
+ },
180
+ [](void* dst, void* src) noexcept {
181
+ // Begin the lifetime of the owned pointer in dst (uninitialized storage) rather than
182
+ // assigning through an F** into it, matching the placement-new in emplace(). The alias
183
+ // keeps this a new-expression rather than something that reads as a C-style cast.
184
+ using owned_ptr = F*;
185
+ ::new (dst) owned_ptr(*std::launder(static_cast<F**>(src)));
186
+ *std::launder(static_cast<F**>(src)) = nullptr;
187
+ },
188
+ [](void* self) noexcept {
189
+ delete *std::launder(static_cast<F**>(self));
190
+ },
191
+ };
192
+ return vt;
193
+ }
66
194
 
67
- wrapper(const wrapper& other) = default;
68
- auto operator=(const wrapper& /* other */) -> wrapper& = default;
195
+ // Zero-initialized so the object has no uninitialized members; the bytes are always overwritten
196
+ // by emplace()/move_from() before vtable_ is set and are only ever read back through vtable_
197
+ // (null while the buffer holds no target), so the initialization is defensive, not relied upon.
198
+ alignas(std::max_align_t) unsigned char buffer_[buffer_size]{};
199
+ const vtable* vtable_{ nullptr };
69
200
 
70
- template<typename... Args>
71
- auto operator()(Args&&... args)
72
- {
73
- return std::move(fnPtr->fn)(std::forward<Args>(args)...);
201
+ // MSVC emits C4702 (unreachable code) during a late optimization pass, not during parsing, so a
202
+ // push/pop around the individual store does not catch it -- the suppression must wrap the whole
203
+ // function. For an F whose selected constructor can only throw (e.g. throwing_copy_functor in the
204
+ // unit tests) MSVC proves construction never returns and flags every following statement as
205
+ // unreachable; every other F reaches them normally, so the warning is a false positive here.
206
+ #if defined(_MSC_VER)
207
+ #pragma warning(push)
208
+ #pragma warning(disable : 4702)
209
+ #endif
210
+ template<typename F>
211
+ void emplace(F&& f)
212
+ {
213
+ using decayed = std::decay_t<F>;
214
+ if constexpr (fits_inline_v<decayed>) {
215
+ ::new (static_cast<void*>(buffer_)) decayed(std::forward<F>(f));
216
+ vtable_ = &inline_vtable<decayed>();
217
+ } else {
218
+ // Begin the lifetime of a decayed* in the buffer (symmetric with the inline placement-new
219
+ // above), then read it back through the heap vtable.
220
+ ::new (static_cast<void*>(buffer_)) decayed*(new decayed(std::forward<F>(f)));
221
+ vtable_ = &heap_vtable<decayed>();
74
222
  }
75
- };
223
+ }
224
+ #if defined(_MSC_VER)
225
+ #pragma warning(pop)
226
+ #endif
76
227
 
77
- using base = std::function<Signature>;
228
+ void move_from(movable_function&& other) noexcept
229
+ {
230
+ if (other.vtable_ != nullptr) {
231
+ other.vtable_->move(buffer_, other.buffer_);
232
+ vtable_ = other.vtable_;
233
+ other.vtable_ = nullptr;
234
+ }
235
+ }
236
+
237
+ void reset() noexcept
238
+ {
239
+ if (vtable_ != nullptr) {
240
+ vtable_->destroy(buffer_);
241
+ vtable_ = nullptr;
242
+ }
243
+ }
244
+ #endif
245
+
246
+ // Constrain on constructibility as well as invocability: emplace() stores the target by
247
+ // constructing a std::decay_t<F> from the forwarded argument, so a callable that cannot be
248
+ // constructed there (e.g. a non-movable functor passed as an rvalue) is removed from overload
249
+ // resolution rather than producing a hard error inside emplace().
250
+ //
251
+ // std::conjunction, not &&: the terms have to be instantiated one at a time, stopping at the
252
+ // first that is false. Asking whether this type is copy constructible -- which anything holding
253
+ // it in a std::any does -- instantiates this constraint with F = const movable_function&, and the
254
+ // constructibility term then asks for the trait that is already being computed. && evaluates
255
+ // lazily but instantiates every operand regardless, so the self-exclusion has to gate the others
256
+ // rather than merely precede them.
257
+ template<typename F>
258
+ using enable_if_callable = std::enable_if_t<
259
+ std::conjunction_v<std::negation<std::is_same<std::decay_t<F>, movable_function>>,
260
+ std::is_constructible<std::decay_t<F>, F>,
261
+ std::is_invocable_r<R, std::decay_t<F>&, Args...>>>;
78
262
 
79
263
  public:
80
264
  movable_function() noexcept = default;
81
265
  movable_function(std::nullptr_t) noexcept
82
- : base(nullptr)
83
266
  {
84
267
  }
85
268
 
86
- template<typename Functor>
87
- movable_function(Functor&& f)
88
- : base(wrapper<Functor>{ std::forward<Functor>(f) })
269
+ template<typename F, typename = enable_if_callable<F>>
270
+ movable_function(F&& f)
89
271
  {
272
+ emplace(std::forward<F>(f));
90
273
  }
91
274
 
92
275
  movable_function(movable_function&& other) noexcept
93
- : base(std::move(static_cast<base&&>(other)))
94
276
  {
95
- other = nullptr;
277
+ move_from(std::move(other));
96
278
  }
97
279
 
98
280
  auto operator=(movable_function&& other) noexcept -> movable_function&
99
281
  {
100
- base::operator=(std::move(static_cast<base&&>(other)));
101
- other = nullptr;
282
+ if (this != &other) {
283
+ reset();
284
+ move_from(std::move(other));
285
+ }
102
286
  return *this;
103
287
  }
104
288
 
105
- auto operator=(std::nullptr_t /* other */) -> movable_function&
289
+ movable_function(const movable_function&) = delete;
290
+ auto operator=(const movable_function&) -> movable_function& = delete;
291
+
292
+ ~movable_function()
106
293
  {
107
- base::operator=(nullptr);
294
+ reset();
295
+ }
296
+
297
+ auto operator=(std::nullptr_t) noexcept -> movable_function&
298
+ {
299
+ reset();
108
300
  return *this;
109
301
  }
110
302
 
111
- template<typename Functor>
112
- auto operator=(Functor&& f) -> movable_function&
303
+ // Same MSVC C4702 false positive as emplace(), and the same whole-function suppression: for an F
304
+ // whose constructor can only throw, the temporary below can never return normally, so MSVC flags
305
+ // the assignment and return as unreachable, even though every other F reaches them normally.
306
+ #if defined(_MSC_VER)
307
+ #pragma warning(push)
308
+ #pragma warning(disable : 4702)
309
+ #endif
310
+ template<typename F, typename = enable_if_callable<F>>
311
+ auto operator=(F&& f) -> movable_function&
113
312
  {
114
- base::operator=(wrapper<Functor>{ std::forward<Functor>(f) });
313
+ // Strong exception guarantee, matching std::function / std::move_only_function: build the new
314
+ // target in a temporary first -- the only step that can throw (heap allocation, or a throwing
315
+ // copy when f is an lvalue) -- then adopt it through the noexcept move-assignment. A bare
316
+ // reset()+emplace() would give only the basic guarantee: a throwing emplace() would leave the
317
+ // previous target already destroyed and *this empty.
318
+ *this = movable_function(std::forward<F>(f));
115
319
  return *this;
116
320
  }
321
+ #if defined(_MSC_VER)
322
+ #pragma warning(pop)
323
+ #endif
324
+
325
+ explicit operator bool() const noexcept
326
+ {
327
+ #ifdef __clang_analyzer__
328
+ return static_cast<bool>(holder_);
329
+ #else
330
+ return vtable_ != nullptr;
331
+ #endif
332
+ }
333
+
334
+ friend auto operator==(const movable_function& f, std::nullptr_t) noexcept -> bool
335
+ {
336
+ return !static_cast<bool>(f);
337
+ }
338
+
339
+ friend auto operator==(std::nullptr_t, const movable_function& f) noexcept -> bool
340
+ {
341
+ return !static_cast<bool>(f);
342
+ }
343
+
344
+ friend auto operator!=(const movable_function& f, std::nullptr_t) noexcept -> bool
345
+ {
346
+ return static_cast<bool>(f);
347
+ }
117
348
 
118
- using base::operator bool;
119
- using base::operator();
349
+ friend auto operator!=(std::nullptr_t, const movable_function& f) noexcept -> bool
350
+ {
351
+ return static_cast<bool>(f);
352
+ }
353
+
354
+ auto operator()(Args... args) const -> R
355
+ {
356
+ #ifdef __clang_analyzer__
357
+ if (!holder_) {
358
+ throw std::bad_function_call{};
359
+ }
360
+ return holder_->invoke(std::forward<Args>(args)...);
361
+ #else
362
+ if (vtable_ == nullptr) {
363
+ throw std::bad_function_call{};
364
+ }
365
+ return vtable_->invoke(const_cast<void*>(static_cast<const void*>(buffer_)),
366
+ std::forward<Args>(args)...);
367
+ #endif
368
+ }
120
369
  };
121
370
 
122
371
  } // namespace couchbase::core::utils
@@ -17,25 +17,168 @@
17
17
 
18
18
  #pragma once
19
19
 
20
- #include <sstream>
20
+ #include <algorithm>
21
+ #include <initializer_list>
21
22
  #include <string>
23
+ #include <string_view>
22
24
 
23
25
  namespace couchbase::core::utils
24
26
  {
27
+ /**
28
+ * Renders names as Analytics SQL++ delimited identifiers.
29
+ *
30
+ * Two distinct operations are involved, and this file keeps them apart deliberately:
31
+ *
32
+ * - QUOTING wraps a name in backticks so the parser reads it as one identifier token instead of
33
+ * as keywords and punctuation. Analytics calls the result a delimited identifier.
34
+ * - ESCAPING rewrites individual characters inside those backticks so that none of them can end
35
+ * the token early or be reinterpreted by the parser.
36
+ *
37
+ * Both are needed: quoting alone is not safe, because a character inside the quotes can still
38
+ * terminate them.
39
+ *
40
+ * The grammar for a delimited identifier is (asterix-lang-sqlpp SQLPP.jj, token QUOTED_STRING):
41
+ *
42
+ * "`" ( "\\\\" | "\\\"" | "\\/" | "\\b" | "\\f" | "\\n" | "\\r" | "\\t" | ~["`","\\"] )* "`"
43
+ *
44
+ * so the only escape mechanism is a backslash sequence, and the only two characters with any
45
+ * special meaning inside the quotes are the backslash and the backtick. Three consequences shape
46
+ * this code:
47
+ *
48
+ * - THE BACKSLASH MUST BE ESCAPED, as "\\\\". It is the escape introducer, and before the lexer
49
+ * ever runs, the character stream expands a \\uXXXX sequence into the character it denotes
50
+ * (JavaCharStream::readChar). That expansion fires only when the backslash run preceding the
51
+ * 'u' is of odd length, so doubling every backslash makes every run even and puts the
52
+ * expansion permanently out of reach. Leaving backslashes alone instead would let the six
53
+ * characters \\u0060 become a real backtick and close the identifier.
54
+ *
55
+ * - A BACKTICK CANNOT BE ESCAPED AT ALL, so a name containing one has no representation as a
56
+ * delimited identifier. Note that doubling it is NOT an escape here: unlike a string literal,
57
+ * whose grammar rule concatenates adjacent tokens and so does give "``" the meaning of one
58
+ * literal quote, an identifier is a single token with no such rule, and "`a``b`" is simply two
59
+ * adjacent tokens. Requests reject these names up front via all_quotable(); see the note on
60
+ * append_escaped() for what happens if one gets through anyway.
61
+ *
62
+ * - NOTHING ELSE NEEDS ESCAPING. Every other byte, including a raw quote, slash, newline, tab,
63
+ * NUL and anything above 0x7f, is matched by ~["`","\\"] and passes through unchanged. In
64
+ * particular a double quote must NOT be escaped as "\\\"": the server only honours that escape
65
+ * when the escaped character is the same as the opening delimiter, so inside backticks it
66
+ * would silently drop the quote and corrupt the name.
67
+ */
25
68
  struct analytics {
26
- static auto uncompound_name(const std::string& name) -> std::string
69
+ /**
70
+ * True when every name can be quoted, i.e. none of them contains a backtick.
71
+ *
72
+ * Requests call this before building a statement and fail with errc::common::invalid_argument
73
+ * when it returns false. It reports only whether the whole set is usable, not which name was at
74
+ * fault: the encoders return a single error code and have no channel for a richer message.
75
+ */
76
+ [[nodiscard]] static auto all_quotable(std::initializer_list<std::string_view> names) -> bool
27
77
  {
28
- std::stringstream ss;
29
- ss << '`';
78
+ return std::all_of(names.begin(), names.end(), [](const auto name) {
79
+ return name.find('`') == std::string_view::npos;
80
+ });
81
+ }
82
+
83
+ /**
84
+ * Quotes a name as a single delimited identifier, escaping its body.
85
+ *
86
+ * Preconditions: all_quotable({ name }). Separators are not interpreted, so a '.' or '/' in the
87
+ * name becomes part of the identifier rather than splitting it.
88
+ */
89
+ [[nodiscard]] static auto quote_identifier(const std::string& name) -> std::string
90
+ {
91
+ std::string result;
92
+ result.reserve(name.size() + 2);
93
+ result.push_back('`');
30
94
  for (const auto symbol : name) {
31
- if (symbol == '/') {
32
- ss << "`.`";
33
- } else {
34
- ss << symbol;
95
+ append_escaped(result, symbol);
96
+ }
97
+ result.push_back('`');
98
+ return result;
99
+ }
100
+
101
+ /**
102
+ * Quotes a dotted field path ("address.city") by quoting each segment separately and rejoining
103
+ * them with an unquoted '.', so that the parser sees a path of identifiers rather than one
104
+ * identifier containing dots.
105
+ *
106
+ * Preconditions: all_quotable({ path }).
107
+ */
108
+ [[nodiscard]] static auto quote_field_path(const std::string& path) -> std::string
109
+ {
110
+ return quote_parts(path, '.', '.');
111
+ }
112
+
113
+ /**
114
+ * Quotes a dataverse name, which the SDK spells as a '/'-separated compound ("bucket/scope"),
115
+ * into the dot-qualified form the statement needs: "bucket/scope" becomes `bucket`.`scope`.
116
+ *
117
+ * Preconditions: all_quotable({ name }).
118
+ *
119
+ * This is a pure encoder: it does not substitute a default for an empty name. Requests that treat
120
+ * the dataverse as optional already default it to "Default" in their own declarations, and the
121
+ * two that do not (analytics_dataverse_create, analytics_dataverse_drop) take the dataverse as a
122
+ * required argument naming the object to create or drop, where silently retargeting an empty name
123
+ * onto "Default" would be destructive.
124
+ */
125
+ [[nodiscard]] static auto quote_dataverse_name(const std::string& name) -> std::string
126
+ {
127
+ return quote_parts(name, '/', '.');
128
+ }
129
+
130
+ private:
131
+ /**
132
+ * Splits on separator, quotes each part, and rejoins with joiner. The separator itself is never
133
+ * escaped, because it is consumed here rather than passed to quote_identifier(); an empty part
134
+ * yields an empty identifier, which the server rejects rather than misinterprets.
135
+ */
136
+ [[nodiscard]] static auto quote_parts(const std::string& name, char separator, char joiner)
137
+ -> std::string
138
+ {
139
+ std::string result;
140
+ result.reserve(name.size() + 2);
141
+ for (std::size_t start = 0;;) {
142
+ const auto pos = name.find(separator, start);
143
+ // Standing in for "this is not the first part", which holds only because quote_identifier()
144
+ // never returns an empty string. Were that to change, a leading separator would lose its
145
+ // empty first part and silently retarget the name instead of producing one the server
146
+ // rejects.
147
+ if (!result.empty()) {
148
+ result.push_back(joiner);
35
149
  }
150
+ result.append(quote_identifier(
151
+ name.substr(start, pos == std::string::npos ? std::string::npos : pos - start)));
152
+ if (pos == std::string::npos) {
153
+ return result;
154
+ }
155
+ start = pos + 1;
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Appends one character of an identifier body.
161
+ *
162
+ * The backslash is escaped, which is the whole of what escaping means here. The backtick has no
163
+ * escape, so it cannot be handled correctly at all; emitting it doubled is a deliberate last
164
+ * resort for a name that reached this point without passing all_quotable(). It produces two
165
+ * adjacent identifier tokens and therefore an unparseable statement, which fails closed, rather
166
+ * than a lone backtick, which would end the identifier and let the rest of the name be parsed as
167
+ * SQL++. It is a backstop against a future caller forgetting the precondition, not an escape.
168
+ */
169
+ static void append_escaped(std::string& result, char symbol)
170
+ {
171
+ switch (symbol) {
172
+ case '\\':
173
+ result.append("\\\\");
174
+ break;
175
+ case '`':
176
+ result.append("``");
177
+ break;
178
+ default:
179
+ result.push_back(symbol);
180
+ break;
36
181
  }
37
- ss << '`';
38
- return ss.str();
39
182
  }
40
183
  };
41
- } // namespace couchbase::core::utils
184
+ } // namespace couchbase::core::utils
@@ -1,6 +1,6 @@
1
1
  /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
2
  /*
3
- * Copyright 2024. Couchbase, Inc.
3
+ * Copyright 2026. Couchbase, Inc.
4
4
  *
5
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
6
  * you may not use this file except in compliance with the License.
@@ -17,18 +17,23 @@
17
17
 
18
18
  #pragma once
19
19
 
20
- #include "error.hxx"
20
+ #include <cstdint>
21
21
 
22
- #include <cstddef>
23
- #include <string>
22
+ #if defined(_WIN32)
23
+ #include <process.h>
24
+ #else
25
+ #include <unistd.h>
26
+ #endif
24
27
 
25
- namespace couchbase::core::columnar
28
+ namespace couchbase::core::utils
26
29
  {
27
- struct retry_info {
28
- std::size_t retry_attempts{ 0 };
29
- std::string last_dispatched_to{};
30
- std::string last_dispatched_from{};
31
- std::string last_dispatched_to_host{};
32
- error last_error{};
33
- };
34
- } // namespace couchbase::core::columnar
30
+ inline auto
31
+ current_process_id() -> std::int64_t
32
+ {
33
+ #if defined(_WIN32)
34
+ return static_cast<std::int64_t>(::_getpid());
35
+ #else
36
+ return static_cast<std::int64_t>(::getpid());
37
+ #endif
38
+ }
39
+ } // namespace couchbase::core::utils