couchbase 3.8.2 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (473) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/ext/CMakeLists.txt +16 -1
  4. data/ext/cache/cpm/{CPM_0.42.0.cmake → CPM_0.43.1.cmake} +18 -2
  5. data/ext/cache/extconf_include.rb +6 -6
  6. data/ext/cache/mozilla-ca-bundle.crt +121 -55
  7. data/ext/cache/mozilla-ca-bundle.sha256 +1 -1
  8. data/ext/couchbase/CMakeLists.txt +130 -21
  9. data/ext/couchbase/cmake/APKBUILD.in +25 -4
  10. data/ext/couchbase/cmake/Bundler.cmake +143 -34
  11. data/ext/couchbase/cmake/CPM.cmake +126 -12
  12. data/ext/couchbase/cmake/Cache.cmake +7 -1
  13. data/ext/couchbase/cmake/CompilerOptions.cmake +1 -1
  14. data/ext/couchbase/cmake/CompilerWarnings.cmake +17 -6
  15. data/ext/couchbase/cmake/GrpcProtobuf.cmake +481 -0
  16. data/ext/couchbase/cmake/OpenSSL.cmake +10 -3
  17. data/ext/couchbase/cmake/Packaging.cmake +519 -65
  18. data/ext/couchbase/cmake/Protostellar.cmake +250 -0
  19. data/ext/couchbase/cmake/Sanitizers.cmake +61 -50
  20. data/ext/couchbase/cmake/StaticAnalyzers.cmake +16 -5
  21. data/ext/couchbase/cmake/TestFramework.cmake +283 -0
  22. data/ext/couchbase/cmake/TestFrameworkAddTests.cmake +51 -0
  23. data/ext/couchbase/cmake/Testing.cmake +27 -9
  24. data/ext/couchbase/cmake/ThirdPartyDependencies.cmake +141 -8
  25. data/ext/couchbase/cmake/VersionInfo.cmake +50 -0
  26. data/ext/couchbase/cmake/build_config.hxx.in +2 -1
  27. data/ext/couchbase/cmake/couchbase-cxx-client.spec.in +101 -23
  28. data/ext/couchbase/cmake/couchbase_cxx_client_static-config.cmake.in +7 -0
  29. data/ext/couchbase/cmake/couchbase_cxx_client_static.pc.in +2 -0
  30. data/ext/couchbase/cmake/gRPC_Generate.cmake +58 -0
  31. data/ext/couchbase/cmake/protobuf_Generate.cmake +69 -0
  32. data/ext/couchbase/cmake/require-git-checkout.cmake +25 -0
  33. data/ext/couchbase/cmake/tarball_glob.txt +49 -0
  34. data/ext/couchbase/core/agent_group.cxx +0 -8
  35. data/ext/couchbase/core/agent_group.hxx +0 -4
  36. data/ext/couchbase/core/analytics_stream.cxx +314 -0
  37. data/ext/couchbase/core/analytics_stream.hxx +129 -0
  38. data/ext/couchbase/core/analytics_stream_component.cxx +245 -0
  39. data/ext/couchbase/core/analytics_stream_component.hxx +67 -0
  40. data/ext/couchbase/core/app_telemetry_meter.cxx +25 -3
  41. data/ext/couchbase/core/app_telemetry_meter.hxx +77 -0
  42. data/ext/couchbase/core/app_telemetry_reporter.cxx +7 -6
  43. data/ext/couchbase/core/bucket.cxx +381 -87
  44. data/ext/couchbase/core/bucket.hxx +105 -25
  45. data/ext/couchbase/core/bucket_unit_test_api.hxx +57 -0
  46. data/ext/couchbase/core/capella.hxx +91 -0
  47. data/ext/couchbase/core/cluster.cxx +1554 -398
  48. data/ext/couchbase/core/cluster.hxx +39 -8
  49. data/ext/couchbase/core/cluster_agent.cxx +0 -8
  50. data/ext/couchbase/core/cluster_agent.hxx +0 -4
  51. data/ext/couchbase/core/cluster_options.hxx +26 -3
  52. data/ext/couchbase/core/collections_component.cxx +39 -15
  53. data/ext/couchbase/core/config_profiles.cxx +1 -1
  54. data/ext/couchbase/core/crud_component.cxx +2 -2
  55. data/ext/couchbase/core/crud_options.hxx +34 -0
  56. data/ext/couchbase/core/crypto/cbcrypto.cc +18 -13
  57. data/ext/couchbase/core/document_id_redaction.hxx +81 -0
  58. data/ext/couchbase/core/error_context/base_error_context.hxx +7 -6
  59. data/ext/couchbase/core/error_context/key_value.cxx +25 -2
  60. data/ext/couchbase/core/error_context/key_value.hxx +60 -33
  61. data/ext/couchbase/core/error_context/key_value_error_context.hxx +16 -15
  62. data/ext/couchbase/core/error_context/search.hxx +5 -0
  63. data/ext/couchbase/core/error_context/search_json.hxx +3 -0
  64. data/ext/couchbase/core/error_context/subdocument_error_context.hxx +19 -18
  65. data/ext/couchbase/core/error_context/view.hxx +5 -0
  66. data/ext/couchbase/core/free_form_http_request.cxx +237 -4
  67. data/ext/couchbase/core/free_form_http_request.hxx +41 -8
  68. data/ext/couchbase/core/http_component.cxx +300 -284
  69. data/ext/couchbase/core/http_component.hxx +0 -4
  70. data/ext/couchbase/core/impl/analytics.cxx +38 -5
  71. data/ext/couchbase/core/impl/analytics.hxx +34 -0
  72. data/ext/couchbase/core/impl/bootstrap_error.hxx +0 -3
  73. data/ext/couchbase/core/impl/collection.cxx +215 -202
  74. data/ext/couchbase/core/impl/collection_manager.cxx +1 -1
  75. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +45 -18
  76. data/ext/couchbase/core/impl/error.cxx +22 -2
  77. data/ext/couchbase/core/impl/internal_analytics_stream_result.hxx +111 -0
  78. data/ext/couchbase/core/impl/internal_query_stream_result.hxx +110 -0
  79. data/ext/couchbase/core/impl/invoke_with_node_id.hxx +15 -7
  80. data/ext/couchbase/core/impl/key_value_error_category.cxx +6 -0
  81. data/ext/couchbase/core/impl/lookup_in_replica.cxx +10 -10
  82. data/ext/couchbase/core/impl/lookup_in_replica.hxx +4 -4
  83. data/ext/couchbase/core/impl/node_id.cxx +49 -13
  84. data/ext/couchbase/core/impl/observability_recorder.cxx +12 -2
  85. data/ext/couchbase/core/impl/observe_poll.cxx +63 -23
  86. data/ext/couchbase/core/impl/public_analytics_stream_result.cxx +372 -0
  87. data/ext/couchbase/core/impl/public_bucket.cxx +48 -2
  88. data/ext/couchbase/core/impl/public_cluster.cxx +229 -42
  89. data/ext/couchbase/core/impl/public_query_stream_result.cxx +380 -0
  90. data/ext/couchbase/core/impl/public_transaction_get_multi_replicas_from_preferred_server_group_result.cxx +42 -0
  91. data/ext/couchbase/core/impl/public_transaction_get_multi_result.cxx +42 -0
  92. data/ext/couchbase/core/impl/query.cxx +76 -7
  93. data/ext/couchbase/core/impl/query.hxx +36 -0
  94. data/ext/couchbase/core/impl/query_index_manager.cxx +54 -1
  95. data/ext/couchbase/core/impl/replica_utils.cxx +101 -0
  96. data/ext/couchbase/core/impl/replica_utils.hxx +64 -0
  97. data/ext/couchbase/core/impl/resolve_node_id.hxx +125 -0
  98. data/ext/couchbase/core/impl/scope.cxx +70 -0
  99. data/ext/couchbase/core/impl/search.cxx +31 -1
  100. data/ext/couchbase/core/impl/transactions.cxx +130 -0
  101. data/ext/couchbase/core/impl/wait_until_ready.cxx +439 -0
  102. data/ext/couchbase/core/impl/wait_until_ready.hxx +110 -0
  103. data/ext/couchbase/core/impl/with_bucket_config_or_timeout.hxx +180 -0
  104. data/ext/couchbase/core/impl/with_cancellation.hxx +11 -3
  105. data/ext/couchbase/core/io/configuration_belongs_to_session.hxx +1 -2
  106. data/ext/couchbase/core/io/dns_client.cxx +122 -45
  107. data/ext/couchbase/core/io/dns_codec.hxx +21 -21
  108. data/ext/couchbase/core/io/dns_config.cxx +21 -6
  109. data/ext/couchbase/core/io/http_command.hxx +149 -121
  110. data/ext/couchbase/core/io/http_error.hxx +107 -0
  111. data/ext/couchbase/core/io/http_parser.cxx +4 -0
  112. data/ext/couchbase/core/io/http_session.cxx +606 -154
  113. data/ext/couchbase/core/io/http_session.hxx +147 -30
  114. data/ext/couchbase/core/io/http_session_manager.hxx +329 -382
  115. data/ext/couchbase/core/io/http_streaming_parser.cxx +4 -0
  116. data/ext/couchbase/core/io/http_streaming_response.cxx +328 -43
  117. data/ext/couchbase/core/io/http_streaming_response.hxx +37 -3
  118. data/ext/couchbase/core/io/mcbp_buffer_pool.hxx +122 -0
  119. data/ext/couchbase/core/io/mcbp_command.hxx +150 -51
  120. data/ext/couchbase/core/io/mcbp_command_id.hxx +45 -0
  121. data/ext/couchbase/core/io/mcbp_message.cxx +9 -1
  122. data/ext/couchbase/core/io/mcbp_message.hxx +19 -0
  123. data/ext/couchbase/core/io/mcbp_output_queue.hxx +150 -0
  124. data/ext/couchbase/core/io/mcbp_parser.cxx +24 -7
  125. data/ext/couchbase/core/io/mcbp_session.cxx +309 -301
  126. data/ext/couchbase/core/io/mcbp_session.hxx +27 -18
  127. data/ext/couchbase/core/io/opaque_ring_table.hxx +145 -0
  128. data/ext/couchbase/core/io/retry_orchestrator.hxx +6 -5
  129. data/ext/couchbase/core/io/stream_deadline.hxx +50 -0
  130. data/ext/couchbase/core/io/streams.cxx +151 -21
  131. data/ext/couchbase/core/io/streams.hxx +48 -1
  132. data/ext/couchbase/core/logger/logger.cxx +36 -0
  133. data/ext/couchbase/core/logger/logger.hxx +46 -6
  134. data/ext/couchbase/core/logger/redaction.hxx +503 -0
  135. data/ext/couchbase/core/management/eventing_status.hxx +10 -0
  136. data/ext/couchbase/core/management/eventing_status_json.hxx +4 -0
  137. data/ext/couchbase/core/mcbp/big_endian.cxx +1 -1
  138. data/ext/couchbase/core/mcbp/codec.cxx +27 -18
  139. data/ext/couchbase/core/mcbp/operation_queue.cxx +2 -2
  140. data/ext/couchbase/core/mcbp/packet.hxx +2 -2
  141. data/ext/couchbase/core/mcbp/queue_request.cxx +23 -6
  142. data/ext/couchbase/core/mcbp/queue_request.hxx +21 -0
  143. data/ext/couchbase/core/meta/features.hxx +13 -0
  144. data/ext/couchbase/core/meta/version.cxx +6 -3
  145. data/ext/couchbase/core/metrics/logging_meter.cxx +5 -10
  146. data/ext/couchbase/core/metrics/meter_wrapper.cxx +63 -33
  147. data/ext/couchbase/core/metrics/meter_wrapper.hxx +55 -3
  148. data/ext/couchbase/core/operations/analytics_response_parsing.cxx +177 -0
  149. data/ext/couchbase/core/operations/analytics_response_parsing.hxx +55 -0
  150. data/ext/couchbase/core/operations/document_analytics.cxx +48 -130
  151. data/ext/couchbase/core/operations/document_analytics.hxx +14 -2
  152. data/ext/couchbase/core/operations/document_get_all_replicas.hxx +15 -7
  153. data/ext/couchbase/core/operations/document_get_any_replica.hxx +19 -8
  154. data/ext/couchbase/core/operations/document_get_projected.cxx +1 -1
  155. data/ext/couchbase/core/{impl/get_replica.cxx → operations/document_get_replica.cxx} +21 -3
  156. data/ext/couchbase/core/{impl/get_replica.hxx → operations/document_get_replica.hxx} +31 -4
  157. data/ext/couchbase/core/operations/document_lookup_in.cxx +10 -10
  158. data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +228 -198
  159. data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +215 -217
  160. data/ext/couchbase/core/operations/document_query.cxx +108 -221
  161. data/ext/couchbase/core/operations/document_query.hxx +18 -4
  162. data/ext/couchbase/core/operations/document_search.cxx +52 -8
  163. data/ext/couchbase/core/operations/document_search.hxx +3 -0
  164. data/ext/couchbase/core/operations/document_view.cxx +3 -3
  165. data/ext/couchbase/core/operations/management/analytics_dataset_create.cxx +15 -8
  166. data/ext/couchbase/core/operations/management/analytics_dataset_create.hxx +4 -0
  167. data/ext/couchbase/core/operations/management/analytics_dataset_drop.cxx +11 -6
  168. data/ext/couchbase/core/operations/management/analytics_dataset_get_all.cxx +3 -2
  169. data/ext/couchbase/core/operations/management/analytics_dataverse_create.cxx +10 -5
  170. data/ext/couchbase/core/operations/management/analytics_dataverse_drop.cxx +10 -5
  171. data/ext/couchbase/core/operations/management/analytics_get_pending_mutations.cxx +2 -1
  172. data/ext/couchbase/core/operations/management/analytics_index_create.cxx +33 -8
  173. data/ext/couchbase/core/operations/management/analytics_index_drop.cxx +12 -7
  174. data/ext/couchbase/core/operations/management/analytics_index_get_all.cxx +3 -2
  175. data/ext/couchbase/core/operations/management/analytics_link_connect.cxx +11 -6
  176. data/ext/couchbase/core/operations/management/analytics_link_create.cxx +3 -3
  177. data/ext/couchbase/core/operations/management/analytics_link_disconnect.cxx +10 -4
  178. data/ext/couchbase/core/operations/management/analytics_link_drop.cxx +6 -4
  179. data/ext/couchbase/core/operations/management/analytics_link_get_all.cxx +4 -3
  180. data/ext/couchbase/core/operations/management/analytics_link_replace.cxx +3 -3
  181. data/ext/couchbase/core/operations/management/analytics_link_utils.hxx +1 -1
  182. data/ext/couchbase/core/operations/management/change_password.cxx +2 -0
  183. data/ext/couchbase/core/operations/management/collection_drop.cxx +5 -1
  184. data/ext/couchbase/core/operations/management/error_utils.cxx +59 -5
  185. data/ext/couchbase/core/operations/management/error_utils.hxx +29 -1
  186. data/ext/couchbase/core/operations/management/eventing_deploy_function.cxx +9 -3
  187. data/ext/couchbase/core/operations/management/eventing_drop_function.cxx +8 -3
  188. data/ext/couchbase/core/operations/management/eventing_get_all_functions.cxx +4 -2
  189. data/ext/couchbase/core/operations/management/eventing_get_function.cxx +5 -3
  190. data/ext/couchbase/core/operations/management/eventing_get_status.cxx +4 -2
  191. data/ext/couchbase/core/operations/management/eventing_pause_function.cxx +9 -3
  192. data/ext/couchbase/core/operations/management/eventing_resume_function.cxx +9 -3
  193. data/ext/couchbase/core/operations/management/eventing_undeploy_function.cxx +9 -3
  194. data/ext/couchbase/core/operations/management/eventing_upsert_function.cxx +9 -3
  195. data/ext/couchbase/core/operations/management/group_drop.cxx +3 -1
  196. data/ext/couchbase/core/operations/management/group_get.cxx +3 -1
  197. data/ext/couchbase/core/operations/management/group_upsert.cxx +11 -8
  198. data/ext/couchbase/core/operations/management/query_index_build.cxx +5 -2
  199. data/ext/couchbase/core/operations/management/query_index_create.cxx +9 -3
  200. data/ext/couchbase/core/operations/management/query_index_drop.cxx +11 -4
  201. data/ext/couchbase/core/operations/management/query_index_get_all.cxx +1 -1
  202. data/ext/couchbase/core/operations/management/query_index_get_all_deferred.cxx +1 -1
  203. data/ext/couchbase/core/operations/management/scope_drop.cxx +5 -1
  204. data/ext/couchbase/core/operations/management/scope_get_all.cxx +6 -1
  205. data/ext/couchbase/core/operations/management/search_get_stats.cxx +10 -0
  206. data/ext/couchbase/core/operations/management/search_index_analyze_document.cxx +3 -2
  207. data/ext/couchbase/core/operations/management/search_index_control_ingest.cxx +4 -3
  208. data/ext/couchbase/core/operations/management/search_index_control_plan_freeze.cxx +4 -3
  209. data/ext/couchbase/core/operations/management/search_index_control_query.cxx +4 -3
  210. data/ext/couchbase/core/operations/management/search_index_drop.cxx +2 -2
  211. data/ext/couchbase/core/operations/management/search_index_get.cxx +2 -2
  212. data/ext/couchbase/core/operations/management/search_index_get_documents_count.cxx +3 -2
  213. data/ext/couchbase/core/operations/management/search_index_get_stats.cxx +3 -1
  214. data/ext/couchbase/core/operations/management/search_index_upsert.cxx +2 -2
  215. data/ext/couchbase/core/operations/management/user_drop.cxx +3 -1
  216. data/ext/couchbase/core/operations/management/user_get.cxx +3 -1
  217. data/ext/couchbase/core/operations/management/user_upsert.cxx +12 -9
  218. data/ext/couchbase/core/operations/management/view_index_drop.cxx +1 -1
  219. data/ext/couchbase/core/operations/management/view_index_get.cxx +1 -1
  220. data/ext/couchbase/core/operations/management/view_index_upsert.cxx +1 -1
  221. data/ext/couchbase/core/operations/operation_traits.hxx +18 -0
  222. data/ext/couchbase/core/operations/query_response_parsing.cxx +211 -0
  223. data/ext/couchbase/core/operations/query_response_parsing.hxx +60 -0
  224. data/ext/couchbase/core/operations_fwd.hxx +3 -3
  225. data/ext/couchbase/core/origin.cxx +54 -26
  226. data/ext/couchbase/core/origin.hxx +12 -0
  227. data/ext/couchbase/core/orphan_reporter.cxx +2 -1
  228. data/ext/couchbase/core/platform/random.cc +7 -7
  229. data/ext/couchbase/core/protocol/client_request.cxx +2 -2
  230. data/ext/couchbase/core/protocol/client_request.hxx +38 -21
  231. data/ext/couchbase/core/protocol/client_response.cxx +11 -3
  232. data/ext/couchbase/core/protocol/client_response.hxx +27 -6
  233. data/ext/couchbase/core/protocol/cmd_append.cxx +2 -2
  234. data/ext/couchbase/core/protocol/cmd_cluster_map_change_notification.cxx +2 -2
  235. data/ext/couchbase/core/protocol/cmd_decrement.cxx +6 -6
  236. data/ext/couchbase/core/protocol/cmd_get.cxx +1 -1
  237. data/ext/couchbase/core/protocol/cmd_get_and_lock.cxx +2 -2
  238. data/ext/couchbase/core/protocol/cmd_get_and_touch.cxx +2 -2
  239. data/ext/couchbase/core/protocol/cmd_get_cluster_config.cxx +6 -4
  240. data/ext/couchbase/core/protocol/cmd_get_collection_id.cxx +2 -2
  241. data/ext/couchbase/core/protocol/cmd_get_error_map.cxx +1 -1
  242. data/ext/couchbase/core/protocol/cmd_get_meta.cxx +4 -4
  243. data/ext/couchbase/core/protocol/cmd_get_replica.cxx +1 -1
  244. data/ext/couchbase/core/protocol/cmd_hello.cxx +1 -1
  245. data/ext/couchbase/core/protocol/cmd_increment.cxx +6 -6
  246. data/ext/couchbase/core/protocol/cmd_insert.cxx +4 -4
  247. data/ext/couchbase/core/protocol/cmd_lookup_in.cxx +4 -3
  248. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.cxx +4 -3
  249. data/ext/couchbase/core/protocol/cmd_mutate_in.cxx +10 -9
  250. data/ext/couchbase/core/protocol/cmd_mutate_in.hxx +10 -10
  251. data/ext/couchbase/core/protocol/cmd_observe_seqno.cxx +7 -7
  252. data/ext/couchbase/core/protocol/cmd_prepend.cxx +2 -2
  253. data/ext/couchbase/core/protocol/cmd_remove.cxx +2 -2
  254. data/ext/couchbase/core/protocol/cmd_replace.cxx +4 -4
  255. data/ext/couchbase/core/protocol/cmd_touch.cxx +1 -1
  256. data/ext/couchbase/core/protocol/cmd_upsert.cxx +4 -4
  257. data/ext/couchbase/core/protocol/datatype.hxx +118 -1
  258. data/ext/couchbase/core/protocol/frame_info_utils.cxx +1 -1
  259. data/ext/couchbase/core/protocol/magic.hxx +4 -0
  260. data/ext/couchbase/core/protocol/magic_fmt.hxx +3 -0
  261. data/ext/couchbase/core/protocol/server_request.hxx +3 -1
  262. data/ext/couchbase/core/protocol/status.cxx +1 -1
  263. data/ext/couchbase/core/protostellar/analytics_converter.hxx +171 -0
  264. data/ext/couchbase/core/protostellar/bucket_admin_converter.hxx +301 -0
  265. data/ext/couchbase/core/protostellar/collection_admin_converter.hxx +92 -0
  266. data/ext/couchbase/core/protostellar/component.cxx +2445 -0
  267. data/ext/couchbase/core/protostellar/component.hxx +391 -0
  268. data/ext/couchbase/core/{columnar/bootstrap_notification_subscriber.hxx → protostellar/compression_settings.hxx} +11 -10
  269. data/ext/couchbase/core/protostellar/credentials.cxx +233 -0
  270. data/ext/couchbase/core/protostellar/credentials.hxx +88 -0
  271. data/ext/couchbase/core/protostellar/dispatcher.cxx +57 -0
  272. data/ext/couchbase/core/protostellar/dispatcher.hxx +482 -0
  273. data/ext/couchbase/core/protostellar/error_utils.cxx +293 -0
  274. data/ext/couchbase/core/protostellar/error_utils.hxx +97 -0
  275. data/ext/couchbase/core/protostellar/json_payload.hxx +49 -0
  276. data/ext/couchbase/core/protostellar/kv_converter.cxx +70 -0
  277. data/ext/couchbase/core/protostellar/kv_converter.hxx +600 -0
  278. data/ext/couchbase/core/protostellar/query_converter.hxx +265 -0
  279. data/ext/couchbase/core/protostellar/query_index_admin_converter.hxx +291 -0
  280. data/ext/couchbase/core/protostellar/query_proto.hxx +73 -0
  281. data/ext/couchbase/core/protostellar/search_converter.hxx +244 -0
  282. data/ext/couchbase/core/protostellar/search_index_admin_converter.hxx +156 -0
  283. data/ext/couchbase/core/protostellar/view_converter.hxx +158 -0
  284. data/ext/couchbase/core/query_stream.cxx +447 -0
  285. data/ext/couchbase/core/query_stream.hxx +141 -0
  286. data/ext/couchbase/core/query_stream_component.cxx +243 -0
  287. data/ext/couchbase/core/query_stream_component.hxx +68 -0
  288. data/ext/couchbase/core/range_scan_load_balancer.cxx +15 -8
  289. data/ext/couchbase/core/range_scan_orchestrator.cxx +15 -3
  290. data/ext/couchbase/core/response_handler.hxx +41 -4
  291. data/ext/couchbase/core/row_streamer.cxx +332 -46
  292. data/ext/couchbase/core/row_streamer.hxx +31 -1
  293. data/ext/couchbase/core/row_streamer_options.hxx +55 -0
  294. data/ext/couchbase/core/sasl/client.h +3 -0
  295. data/ext/couchbase/core/search_scoring.hxx +66 -0
  296. data/ext/couchbase/core/stream_error_details.hxx +69 -0
  297. data/ext/couchbase/core/timeout_defaults.hxx +0 -1
  298. data/ext/couchbase/core/topology/capabilities.hxx +6 -0
  299. data/ext/couchbase/core/topology/capabilities_fmt.hxx +3 -0
  300. data/ext/couchbase/core/topology/configuration.cxx +21 -6
  301. data/ext/couchbase/core/topology/configuration.hxx +29 -8
  302. data/ext/couchbase/core/topology/configuration_json.hxx +3 -0
  303. data/ext/couchbase/core/topology/error_map_json.hxx +3 -1
  304. data/ext/couchbase/core/tracing/threshold_logging_tracer.cxx +70 -4
  305. data/ext/couchbase/core/tracing/threshold_logging_tracer.hxx +10 -0
  306. data/ext/couchbase/core/transactions/active_transaction_record.cxx +0 -34
  307. data/ext/couchbase/core/transactions/attempt_context_impl.cxx +108 -63
  308. data/ext/couchbase/core/transactions/attempt_context_impl.hxx +19 -2
  309. data/ext/couchbase/core/transactions/error_list.hxx +2 -2
  310. data/ext/couchbase/core/transactions/get_multi_fetch.hxx +160 -0
  311. data/ext/couchbase/core/transactions/get_multi_orchestrator.cxx +326 -125
  312. data/ext/couchbase/core/transactions/get_multi_transaction_id.hxx +62 -0
  313. data/ext/couchbase/core/transactions/internal/atr_entry.hxx +22 -2
  314. data/ext/couchbase/core/transactions/internal/transaction_context.hxx +2 -2
  315. data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +23 -1
  316. data/ext/couchbase/core/transactions/internal/utils.hxx +50 -14
  317. data/ext/couchbase/core/transactions/staged_mutation.cxx +23 -18
  318. data/ext/couchbase/core/transactions/staged_mutation.hxx +15 -4
  319. data/ext/couchbase/core/transactions/transaction_context.cxx +55 -40
  320. data/ext/couchbase/core/transactions/transaction_get_result.hxx +16 -0
  321. data/ext/couchbase/core/transactions/transactions.cxx +3 -55
  322. data/ext/couchbase/core/transactions/transactions_cleanup.cxx +165 -72
  323. data/ext/couchbase/core/transactions/transactions_config.cxx +0 -11
  324. data/ext/couchbase/core/transactions/utils.cxx +10 -0
  325. data/ext/couchbase/core/transactions/waitable_op_list.hxx +2 -2
  326. data/ext/couchbase/core/transactions.hxx +9 -9
  327. data/ext/couchbase/core/utils/byteswap.hxx +166 -9
  328. data/ext/couchbase/core/utils/connection_string.cxx +50 -85
  329. data/ext/couchbase/core/utils/connection_string.hxx +15 -0
  330. data/ext/couchbase/core/{columnar/backoff_calculator.hxx → utils/deadline.hxx} +13 -13
  331. data/ext/couchbase/core/utils/duration_parser.cxx +1 -1
  332. data/ext/couchbase/core/utils/json_streaming_lexer.cxx +48 -5
  333. data/ext/couchbase/core/utils/json_streaming_lexer.hxx +4 -1
  334. data/ext/couchbase/core/utils/movable_function.hxx +301 -52
  335. data/ext/couchbase/core/utils/name_codec.hxx +154 -11
  336. data/ext/couchbase/core/{columnar/retry_info.hxx → utils/process_id.hxx} +18 -13
  337. data/ext/couchbase/core/utils/url_codec.cxx +12 -51
  338. data/ext/couchbase/core/websocket_codec.cxx +3 -29
  339. data/ext/couchbase/couchbase/analytics_options.hxx +21 -10
  340. data/ext/couchbase/couchbase/analytics_row.hxx +105 -0
  341. data/ext/couchbase/couchbase/analytics_stream_result.hxx +266 -0
  342. data/ext/couchbase/couchbase/boolean_query.hxx +3 -3
  343. data/ext/couchbase/couchbase/bucket.hxx +57 -0
  344. data/ext/couchbase/couchbase/cluster.hxx +183 -5
  345. data/ext/couchbase/{core/columnar/security_options.hxx → couchbase/cluster_state.hxx} +18 -14
  346. data/ext/couchbase/couchbase/codec/lenient_json_transcoder.hxx +69 -0
  347. data/ext/couchbase/couchbase/collection.hxx +234 -14
  348. data/ext/couchbase/couchbase/common_durability_options.hxx +18 -3
  349. data/ext/couchbase/couchbase/conjunction_query.hxx +1 -1
  350. data/ext/couchbase/couchbase/create_dataset_analytics_options.hxx +6 -1
  351. data/ext/couchbase/couchbase/date_range_query.hxx +2 -2
  352. data/ext/couchbase/couchbase/decrement_options.hxx +1 -1
  353. data/ext/couchbase/couchbase/disjunction_query.hxx +1 -1
  354. data/ext/couchbase/couchbase/error.hxx +32 -0
  355. data/ext/couchbase/couchbase/error_codes.hxx +32 -0
  356. data/ext/couchbase/couchbase/geo_bounding_box_query.hxx +1 -1
  357. data/ext/couchbase/couchbase/geo_distance_query.hxx +1 -1
  358. data/ext/couchbase/couchbase/geo_polygon_query.hxx +1 -1
  359. data/ext/couchbase/couchbase/get_replica_options.hxx +68 -0
  360. data/ext/couchbase/couchbase/get_replica_result.hxx +5 -3
  361. data/ext/couchbase/couchbase/get_replica_strategy.hxx +161 -0
  362. data/ext/couchbase/couchbase/get_result.hxx +1 -0
  363. data/ext/couchbase/couchbase/increment_options.hxx +1 -1
  364. data/ext/couchbase/couchbase/insert_options.hxx +1 -1
  365. data/ext/couchbase/couchbase/match_phrase_query.hxx +1 -1
  366. data/ext/couchbase/couchbase/match_query.hxx +1 -1
  367. data/ext/couchbase/couchbase/mutate_in_options.hxx +3 -3
  368. data/ext/couchbase/couchbase/network_options.hxx +1 -1
  369. data/ext/couchbase/couchbase/node_id.hxx +42 -14
  370. data/ext/couchbase/couchbase/node_id_for_options.hxx +7 -1
  371. data/ext/couchbase/couchbase/node_ids_options.hxx +8 -2
  372. data/ext/couchbase/couchbase/numeric_range_query.hxx +1 -1
  373. data/ext/couchbase/couchbase/phrase_query.hxx +1 -1
  374. data/ext/couchbase/couchbase/prefix_query.hxx +1 -1
  375. data/ext/couchbase/couchbase/query_options.hxx +23 -12
  376. data/ext/couchbase/couchbase/query_row.hxx +111 -0
  377. data/ext/couchbase/couchbase/query_stream_result.hxx +302 -0
  378. data/ext/couchbase/couchbase/query_string_query.hxx +3 -3
  379. data/ext/couchbase/couchbase/regexp_query.hxx +1 -1
  380. data/ext/couchbase/couchbase/replace_options.hxx +3 -3
  381. data/ext/couchbase/couchbase/result.hxx +14 -3
  382. data/ext/couchbase/couchbase/scan_result_item.hxx +1 -0
  383. data/ext/couchbase/couchbase/scope.hxx +85 -2
  384. data/ext/couchbase/couchbase/search_options.hxx +58 -8
  385. data/ext/couchbase/couchbase/search_scoring.hxx +94 -0
  386. data/ext/couchbase/couchbase/search_scoring_none.hxx +51 -0
  387. data/ext/couchbase/couchbase/search_scoring_reciprocal_rank_fusion.hxx +88 -0
  388. data/ext/couchbase/couchbase/search_scoring_relative_score_fusion.hxx +70 -0
  389. data/ext/couchbase/couchbase/term_range_query.hxx +1 -1
  390. data/ext/couchbase/couchbase/tracing/request_span.hxx +46 -0
  391. data/ext/couchbase/couchbase/transactions/transaction_get_multi_replicas_from_preferred_server_group_result.hxx +23 -21
  392. data/ext/couchbase/couchbase/transactions/transaction_get_multi_result.hxx +24 -19
  393. data/ext/couchbase/couchbase/transactions/transaction_get_result.hxx +17 -3
  394. data/ext/couchbase/couchbase/transactions/transactions_config.hxx +4 -2
  395. data/ext/couchbase/couchbase/transactions.hxx +27 -18
  396. data/ext/couchbase/couchbase/upsert_options.hxx +3 -3
  397. data/ext/couchbase/couchbase/vector_query.hxx +1 -1
  398. data/ext/couchbase/couchbase/wait_until_ready_options.hxx +111 -0
  399. data/ext/couchbase/couchbase/wildcard_query.hxx +1 -1
  400. data/ext/extconf.rb +15 -10
  401. data/ext/rcb_analytics.cxx +82 -102
  402. data/ext/rcb_backend.cxx +42 -36
  403. data/ext/rcb_backend.hxx +2 -0
  404. data/ext/rcb_buckets.cxx +47 -59
  405. data/ext/rcb_collections.cxx +42 -52
  406. data/ext/rcb_crud.cxx +345 -224
  407. data/ext/rcb_diagnostics.cxx +117 -27
  408. data/ext/rcb_exceptions.cxx +152 -99
  409. data/ext/rcb_exceptions.hxx +25 -0
  410. data/ext/rcb_extras.cxx +18 -19
  411. data/ext/rcb_hdr_histogram.cxx +19 -4
  412. data/ext/rcb_logger.cxx +202 -27
  413. data/ext/rcb_logger.hxx +12 -0
  414. data/ext/rcb_multi.cxx +40 -40
  415. data/ext/rcb_observability.cxx +7 -5
  416. data/ext/rcb_query.cxx +99 -142
  417. data/ext/rcb_range_scan.cxx +41 -35
  418. data/ext/rcb_search.cxx +98 -99
  419. data/ext/rcb_users.cxx +36 -56
  420. data/ext/rcb_utils.cxx +100 -37
  421. data/ext/rcb_utils.hxx +287 -33
  422. data/ext/rcb_version.cxx +1 -1
  423. data/ext/rcb_views.cxx +55 -51
  424. data/lib/active_support/cache/couchbase_store.rb +77 -12
  425. data/lib/couchbase/bucket.rb +20 -0
  426. data/lib/couchbase/cluster.rb +17 -0
  427. data/lib/couchbase/collection.rb +36 -1
  428. data/lib/couchbase/errors.rb +18 -0
  429. data/lib/couchbase/fork_hooks.rb +16 -7
  430. data/lib/couchbase/get_replica_strategy.rb +89 -0
  431. data/lib/couchbase/logger.rb +1 -1
  432. data/lib/couchbase/management/analytics_index_manager.rb +15 -15
  433. data/lib/couchbase/management/bucket_manager.rb +6 -6
  434. data/lib/couchbase/management/collection_manager.rb +6 -6
  435. data/lib/couchbase/management/query_index_manager.rb +7 -7
  436. data/lib/couchbase/management/search_index_manager.rb +13 -13
  437. data/lib/couchbase/management/user_manager.rb +10 -10
  438. data/lib/couchbase/management/view_index_manager.rb +5 -5
  439. data/lib/couchbase/options.rb +174 -42
  440. data/lib/couchbase/protostellar/bucket.rb +4 -0
  441. data/lib/couchbase/protostellar/cluster.rb +4 -0
  442. data/lib/couchbase/protostellar/collection.rb +4 -0
  443. data/lib/couchbase/protostellar/error_handling.rb +2 -1
  444. data/lib/couchbase/protostellar/request.rb +1 -0
  445. data/lib/couchbase/protostellar/request_generator/kv.rb +16 -2
  446. data/lib/couchbase/protostellar/request_generator/search.rb +17 -1
  447. data/lib/couchbase/protostellar/retry/orchestrator.rb +3 -2
  448. data/lib/couchbase/protostellar/retry/strategies/fail_fast.rb +33 -0
  449. data/lib/couchbase/protostellar/retry/strategies.rb +1 -0
  450. data/lib/couchbase/search_options.rb +95 -6
  451. data/lib/couchbase/version.rb +1 -1
  452. metadata +91 -33
  453. data/ext/0001-fix-build-for-mingw-w64-ucrt-x86_64-toolchain.patch +0 -40
  454. data/ext/couchbase/core/columnar/agent.hxx +0 -71
  455. data/ext/couchbase/core/columnar/agent_config.hxx +0 -59
  456. data/ext/couchbase/core/columnar/background_bootstrap_listener.hxx +0 -42
  457. data/ext/couchbase/core/columnar/backoff_calculator.cxx +0 -62
  458. data/ext/couchbase/core/columnar/columnar_agent.cxx +0 -147
  459. data/ext/couchbase/core/columnar/columnar_agent_config.cxx +0 -48
  460. data/ext/couchbase/core/columnar/columnar_error.cxx +0 -51
  461. data/ext/couchbase/core/columnar/database_management_options.hxx +0 -56
  462. data/ext/couchbase/core/columnar/error.hxx +0 -51
  463. data/ext/couchbase/core/columnar/error_codes.cxx +0 -107
  464. data/ext/couchbase/core/columnar/error_codes.hxx +0 -75
  465. data/ext/couchbase/core/columnar/management_component.cxx +0 -300
  466. data/ext/couchbase/core/columnar/management_component.hxx +0 -56
  467. data/ext/couchbase/core/columnar/query_component.cxx +0 -523
  468. data/ext/couchbase/core/columnar/query_component.hxx +0 -57
  469. data/ext/couchbase/core/columnar/query_options.hxx +0 -59
  470. data/ext/couchbase/core/columnar/query_result.cxx +0 -130
  471. data/ext/couchbase/core/columnar/query_result.hxx +0 -78
  472. data/ext/couchbase/core/io/config_tracker.cxx +0 -687
  473. data/ext/couchbase/core/io/config_tracker.hxx +0 -123
@@ -16,13 +16,17 @@
16
16
  */
17
17
 
18
18
  #include "queue_request.hxx"
19
+
19
20
  #include "../operation_map.hxx"
20
- #include "core/logger/logger.hxx"
21
21
  #include "operation_queue.hxx"
22
22
  #include "queue_response.hxx"
23
23
 
24
24
  #include <couchbase/error_codes.hxx>
25
25
 
26
+ #include <spdlog/fmt/bundled/core.h>
27
+
28
+ #include <couchbase/fmt/retry_reason.hxx>
29
+
26
30
  #include <atomic>
27
31
 
28
32
  namespace couchbase::core::mcbp
@@ -127,32 +131,42 @@ void
127
131
  queue_request::cancel(std::error_code error)
128
132
  {
129
133
  if (internal_cancel()) {
130
- callback_({}, shared_from_this(), error);
134
+ // Move callback_ before invoking to release any captured state (e.g. shared_ptr cycles)
135
+ // as soon as the callback returns rather than retaining it for the lifetime of the request.
136
+ auto cb = std::move(callback_);
137
+ cb({}, shared_from_this(), error);
131
138
  }
132
139
  }
133
140
 
134
141
  void
135
142
  queue_request::set_deadline(std::shared_ptr<asio::steady_timer> timer)
136
143
  {
144
+ const std::scoped_lock lock(processing_mutex_);
137
145
  deadline_ = std::move(timer);
138
146
  }
139
147
 
140
148
  void
141
149
  queue_request::set_retry_backoff(std::shared_ptr<asio::steady_timer> timer)
142
150
  {
151
+ const std::scoped_lock lock(processing_mutex_);
143
152
  retry_backoff_ = std::move(timer);
144
153
  }
145
154
 
146
155
  void
147
156
  queue_request::try_callback(std::shared_ptr<queue_response> response, std::error_code error)
148
157
  {
149
- cancel_timer(deadline_);
150
- cancel_timer(retry_backoff_);
158
+ {
159
+ const std::scoped_lock lock(processing_mutex_);
160
+ cancel_timer(deadline_);
161
+ cancel_timer(retry_backoff_);
162
+ }
151
163
 
152
164
  if (persistent_) {
153
165
  if (error) {
154
166
  if (internal_cancel()) {
155
- return callback_(std::move(response), shared_from_this(), error);
167
+ // Move callback_ before invoking to release any captured state (e.g. shared_ptr cycles).
168
+ auto cb = std::move(callback_);
169
+ return cb(std::move(response), shared_from_this(), error);
156
170
  }
157
171
  } else if (!is_completed_) {
158
172
  return callback_(std::move(response), shared_from_this(), error);
@@ -160,7 +174,10 @@ queue_request::try_callback(std::shared_ptr<queue_response> response, std::error
160
174
  return;
161
175
  }
162
176
  if (bool expected_state{ false }; is_completed_.compare_exchange_strong(expected_state, true)) {
163
- return callback_(std::move(response), shared_from_this(), error);
177
+ // Move callback_ before invoking to release any captured state (e.g. shared_ptr cycles)
178
+ // as soon as the callback returns.
179
+ auto cb = std::move(callback_);
180
+ return cb(std::move(response), shared_from_this(), error);
164
181
  }
165
182
  }
166
183
 
@@ -27,6 +27,7 @@
27
27
  #include <asio/steady_timer.hpp>
28
28
 
29
29
  #include <atomic>
30
+ #include <functional>
30
31
  #include <memory>
31
32
  #include <mutex>
32
33
  #include <set>
@@ -36,6 +37,11 @@ namespace couchbase::core
36
37
  class operation_map;
37
38
  } // namespace couchbase::core
38
39
 
40
+ namespace couchbase::tracing
41
+ {
42
+ class request_span;
43
+ } // namespace couchbase::tracing
44
+
39
45
  namespace couchbase::core::mcbp
40
46
  {
41
47
  class operation_queue;
@@ -73,6 +79,13 @@ public:
73
79
  std::string collection_name_{};
74
80
  std::string scope_name_{};
75
81
  std::size_t replica_index_{ 0 };
82
+
83
+ // Set by collections_component when a request is dispatched through the collection-id cache.
84
+ // Invoked by the KV response path on an unknown_collection status to invalidate the cached id,
85
+ // re-resolve it (GetCollectionID) and retry the request. Returns true if a retry was scheduled.
86
+ // Left empty for requests that bypass the cache (e.g. the GetCollectionID resolution requests
87
+ // themselves), which must not recurse.
88
+ std::function<bool()> on_unknown_collection_{};
76
89
  // This tracks when the request was dispatched so that we can properly prioritize older requests
77
90
  // to try and meet timeout requirements.
78
91
  std::chrono::steady_clock::time_point dispatched_time_{};
@@ -86,6 +99,14 @@ public:
86
99
  // the request and calculating any back-off time period.
87
100
  std::shared_ptr<couchbase::retry_strategy> retry_strategy_{};
88
101
 
102
+ // The parent tracing span for this operation, set by crud_component before dispatching.
103
+ // Kept alive here so the span outlives any retry loops.
104
+ std::shared_ptr<couchbase::tracing::request_span> parent_span_{ nullptr };
105
+
106
+ // The per-dispatch child span representing a single attempt on a specific node.
107
+ // Reset and recreated on every retry by crud_component.
108
+ std::shared_ptr<couchbase::tracing::request_span> dispatch_span_{ nullptr };
109
+
89
110
  private:
90
111
  // Static routing properties
91
112
  queue_callback callback_;
@@ -268,3 +268,16 @@
268
268
  * Support for the stable OpenTelemetry conventions (Observability RFC revisions 26 & 27)
269
269
  */
270
270
  #define COUCHBASE_CXX_CLIENT_STABLE_OTEL_CONVENTIONS 1
271
+
272
+ /**
273
+ * An HTTP 400 that matches no more specific error is reported as
274
+ * couchbase::errc::common::invalid_argument (SDK-RFC 58 revision 22).
275
+ */
276
+ #define COUCHBASE_CXX_CLIENT_HTTP_400_IS_INVALID_ARGUMENT 1
277
+
278
+ /**
279
+ * The implementations for couchbase::transactions::transactions and
280
+ * couchbase::core::transactions::transactions are separate, i.e.,
281
+ * couchbase::core::transactions::transactions does not implement the Public API.
282
+ */
283
+ #define COUCHBASE_CXX_CLIENT_TRANSACTIONS_PUBLIC_CORE_IMPL_SEPARATION 1
@@ -89,8 +89,11 @@ sdk_build_info() -> std::map<std::string, std::string>
89
89
  "false"
90
90
  #endif
91
91
  ;
92
- info["columnar"] =
93
- #if defined(COUCHBASE_CXX_CLIENT_COLUMNAR)
92
+ // Whether this build can serve couchbase2:// connection strings, i.e. whether it was compiled
93
+ // with Cloud Native Gateway support. A build without it rejects the scheme at connect time, so
94
+ // the answer is worth reporting next to the other build-time switches.
95
+ info["couchbase2"] =
96
+ #if defined(COUCHBASE_CXX_CLIENT_BUILD_COUCHBASE2)
94
97
  "true"
95
98
  #else
96
99
  "false"
@@ -194,7 +197,7 @@ sdk_build_info_json() -> std::string
194
197
  name == "version_build" || name == "mozilla_ca_bundle_size") {
195
198
  info[name] = std::stoi(value);
196
199
  } else if (name == "snapshot" || name == "static_stdlib" || name == "static_openssl" ||
197
- name == "mozilla_ca_bundle_embedded") {
200
+ name == "couchbase2" || name == "mozilla_ca_bundle_embedded") {
198
201
  info[name] = value == "true";
199
202
  } else {
200
203
  info[name] = value;
@@ -21,6 +21,7 @@
21
21
 
22
22
  #include "constants.hxx"
23
23
  #include "core/logger/logger.hxx"
24
+ #include "core/logger/redaction.hxx"
24
25
  #include "core/tracing/constants.hxx"
25
26
  #include "core/utils/json.hxx"
26
27
  #include "noop_meter.hxx"
@@ -161,7 +162,7 @@ logging_meter::log_report() const
161
162
  }
162
163
  }
163
164
  if (report.find("operations") != nullptr) {
164
- CB_LOG_INFO("Metrics: {}", utils::json::generate(report));
165
+ CB_LOG_INFO("Metrics: {}", logger::metadata(utils::json::generate(report)));
165
166
  }
166
167
  }
167
168
 
@@ -228,14 +229,8 @@ logging_meter::get_value_recorder(const std::string& name,
228
229
  const std::scoped_lock lock(recorders_mutex_);
229
230
  auto& service_recorders = recorders_[service->second];
230
231
 
231
- auto recorder = service_recorders.find(operation->second);
232
- if (recorder != service_recorders.end()) {
233
- return recorder->second;
234
- }
235
-
236
- service_recorders.try_emplace(operation->second,
237
- std::make_shared<logging_value_recorder>(operation->second, tags));
238
- recorder = service_recorders.find(operation->second);
239
- return recorder->second;
232
+ auto [it, _] = service_recorders.try_emplace(
233
+ operation->second, std::make_shared<logging_value_recorder>(operation->second, tags));
234
+ return it->second;
240
235
  }
241
236
  } // namespace couchbase::core::metrics
@@ -22,6 +22,9 @@
22
22
  #include "core/metrics/constants.hxx"
23
23
  #include "core/tracing/constants.hxx"
24
24
 
25
+ #include <algorithm>
26
+ #include <array>
27
+ #include <cctype>
25
28
  #include <map>
26
29
  #include <memory>
27
30
  #include <string>
@@ -62,23 +65,15 @@ extract_error_name(std::error_code ec) -> std::string
62
65
  return ec.message();
63
66
  }
64
67
 
68
+ } // namespace
69
+
65
70
  auto
66
- get_standardized_error_type(std::error_code ec) -> std::string
71
+ standardized_error_type(std::error_code ec) -> std::string
67
72
  {
68
73
  if (!ec) {
69
74
  return {};
70
75
  }
71
76
 
72
- // SDK-specific errors
73
- if (ec.value() >= 1000) {
74
- return "CouchbaseError";
75
- }
76
-
77
- // Errors where message and RFC-message don't match
78
- if (ec == errc::field_level_encryption::generic_cryptography_failure) {
79
- return "CryptoError";
80
- }
81
-
82
77
  static const std::array<const std::error_category*, 12> cb_categories = {
83
78
  &impl::common_category(), &impl::key_value_category(),
84
79
  &impl::query_category(), &impl::analytics_category(),
@@ -88,16 +83,30 @@ get_standardized_error_type(std::error_code ec) -> std::string
88
83
  &impl::transaction_category(), &impl::transaction_op_category(),
89
84
  };
90
85
 
91
- if (std::any_of(
92
- cb_categories.begin(), cb_categories.end(), [&ec](const std::error_category* cat) -> bool {
93
- return &ec.category() == cat;
94
- })) {
95
- return snake_case_to_camel_case(extract_error_name(ec));
86
+ // Classify only against the Couchbase categories. Numeric error values overlap across the
87
+ // platform/system/asio categories, so a value-based check alone would misclassify a foreign error
88
+ // (e.g. a TLS or system error that happens to have value >= 1000) as a Couchbase error.
89
+ const bool couchbase_error =
90
+ std::any_of(cb_categories.begin(), cb_categories.end(), [&ec](const std::error_category* cat) {
91
+ return &ec.category() == cat;
92
+ });
93
+ if (!couchbase_error) {
94
+ return "_OTHER";
95
+ }
96
+
97
+ // The SDK's network errors (couchbase::errc::network) use values >= 1000 and are reported under a
98
+ // single generic bucket rather than by individual name.
99
+ if (ec.value() >= 1000) {
100
+ return "CouchbaseError";
96
101
  }
97
102
 
98
- return "_OTHER";
103
+ // Errors where message and RFC-message don't match
104
+ if (ec == errc::field_level_encryption::generic_cryptography_failure) {
105
+ return "CryptoError";
106
+ }
107
+
108
+ return snake_case_to_camel_case(extract_error_name(ec));
99
109
  }
100
- } // namespace
101
110
 
102
111
  auto
103
112
  metric_attributes::encode() const -> std::map<std::string, std::string>
@@ -124,8 +133,8 @@ metric_attributes::encode() const -> std::map<std::string, std::string>
124
133
  if (collection_name) {
125
134
  tags.emplace(tracing::attributes::op::collection_name, collection_name.value());
126
135
  }
127
- if (ec) {
128
- tags.emplace(tracing::attributes::op::error_type, get_standardized_error_type(ec));
136
+ if (!error_type.empty()) {
137
+ tags.emplace(tracing::attributes::op::error_type, error_type);
129
138
  }
130
139
 
131
140
  return tags;
@@ -150,28 +159,49 @@ meter_wrapper::stop()
150
159
  meter_->stop();
151
160
  }
152
161
 
153
- void
154
- meter_wrapper::record_value(const std::map<std::string, std::string>& raw_attrs,
155
- std::chrono::microseconds duration)
162
+ auto
163
+ meter_wrapper::value_recorder_for(const metric_attributes& attrs)
164
+ -> std::shared_ptr<couchbase::metrics::value_recorder>
156
165
  {
157
- meter_->get_value_recorder(operation_meter_name, raw_attrs)->record_value(duration.count());
166
+ {
167
+ const std::scoped_lock lock(recorder_cache_mutex_);
168
+ if (auto it = recorder_cache_.find(attrs); it != recorder_cache_.end()) {
169
+ return it->second;
170
+ }
171
+ }
172
+
173
+ // Resolve outside the lock: encode() and the pluggable meter's get_value_recorder() are
174
+ // user-visible code paths, and holding the cache mutex across them would serialize every
175
+ // first-time resolution and risk deadlock if a custom meter re-entered record_value(). The
176
+ // meter returns a stable recorder for a given name/tag set, so resolving the same key twice on
177
+ // a race is harmless.
178
+ auto recorder = meter_->get_value_recorder(operation_meter_name, attrs.encode());
179
+
180
+ const std::scoped_lock lock(recorder_cache_mutex_);
181
+ // A concurrent caller may have inserted this key while the lock was released; emplace keeps the
182
+ // first-inserted recorder and returns it, so all callers share one recorder per key.
183
+ return recorder_cache_.emplace(attrs, std::move(recorder)).first->second;
158
184
  }
159
185
 
160
186
  void
161
187
  meter_wrapper::record_value(metric_attributes attrs,
162
188
  std::chrono::steady_clock::time_point start_time)
163
189
  {
164
- auto [cluster_name, cluster_uuid] = cluster_label_listener_->cluster_labels();
165
- if (cluster_name) {
166
- attrs.internal.cluster_name = cluster_name;
167
- }
168
- if (cluster_uuid) {
169
- attrs.internal.cluster_uuid = cluster_uuid;
190
+ // The listener is optional -- the wrapper can be constructed without one -- so only enrich the
191
+ // attributes with cluster labels when it is present.
192
+ if (cluster_label_listener_) {
193
+ auto [cluster_name, cluster_uuid] = cluster_label_listener_->cluster_labels();
194
+ if (cluster_name) {
195
+ attrs.internal.cluster_name = cluster_name;
196
+ }
197
+ if (cluster_uuid) {
198
+ attrs.internal.cluster_uuid = cluster_uuid;
199
+ }
170
200
  }
171
201
 
172
- record_value(attrs.encode(),
173
- std::chrono::duration_cast<std::chrono::microseconds>(
174
- std::chrono::steady_clock::now() - start_time));
202
+ value_recorder_for(attrs)->record_value(std::chrono::duration_cast<std::chrono::microseconds>(
203
+ std::chrono::steady_clock::now() - start_time)
204
+ .count());
175
205
  }
176
206
 
177
207
  auto
@@ -25,9 +25,12 @@
25
25
 
26
26
  #include <chrono>
27
27
  #include <map>
28
+ #include <memory>
29
+ #include <mutex>
28
30
  #include <optional>
29
31
  #include <string>
30
32
  #include <system_error>
33
+ #include <tuple>
31
34
 
32
35
  #include "core/cluster_label_listener.hxx"
33
36
 
@@ -36,7 +39,11 @@ namespace couchbase::core::metrics
36
39
  struct metric_attributes {
37
40
  std::string service;
38
41
  std::string operation;
39
- std::error_code ec;
42
+ // The standardized error type, precomputed once from the operation's error code (see
43
+ // standardized_error_type()). Stored rather than the raw error code so that both the encoded tag
44
+ // set and the recorder-cache key (operator<) use it without recomputing a string per comparison.
45
+ // Empty denotes "no error".
46
+ std::string error_type{};
40
47
  std::optional<std::string> bucket_name{};
41
48
  std::optional<std::string> scope_name{};
42
49
  std::optional<std::string> collection_name{};
@@ -49,6 +56,38 @@ struct metric_attributes {
49
56
  [[nodiscard]] auto encode() const -> std::map<std::string, std::string>;
50
57
  };
51
58
 
59
+ // Map an error code to the standardized error-type string used as the metric's error_type tag (see
60
+ // metric_attributes::encode()). The empty string denotes "no error". Exposed so the recorder cache
61
+ // can key on the same bounded set of error types that actually reach the tags.
62
+ [[nodiscard]] auto
63
+ standardized_error_type(std::error_code ec) -> std::string;
64
+
65
+ inline auto
66
+ operator<(const metric_attributes& lhs, const metric_attributes& rhs) -> bool
67
+ {
68
+ // Order by the precomputed standardized error type, not the raw error code. encode() only ever
69
+ // emits the standardized type in the tag set, so keying on it collapses the many distinct codes
70
+ // that share a type onto one recorder and keeps the cache bounded by the tag cardinality (rather
71
+ // than one entry per raw code, unbounded for high-cardinality system/asio codes). Because the
72
+ // type is stored on the attributes, every comparison is a plain string compare -- no per-lookup
73
+ // string construction or allocation, which is what keeps the cache lookup cheap on the hot path.
74
+ return std::tie(lhs.service,
75
+ lhs.operation,
76
+ lhs.error_type,
77
+ lhs.bucket_name,
78
+ lhs.scope_name,
79
+ lhs.collection_name,
80
+ lhs.internal.cluster_name,
81
+ lhs.internal.cluster_uuid) < std::tie(rhs.service,
82
+ rhs.operation,
83
+ rhs.error_type,
84
+ rhs.bucket_name,
85
+ rhs.scope_name,
86
+ rhs.collection_name,
87
+ rhs.internal.cluster_name,
88
+ rhs.internal.cluster_uuid);
89
+ }
90
+
52
91
  class meter_wrapper
53
92
  {
54
93
  public:
@@ -59,8 +98,12 @@ public:
59
98
  void stop();
60
99
 
61
100
  void record_value(metric_attributes attrs, std::chrono::steady_clock::time_point start_time);
62
- void record_value(const std::map<std::string, std::string>& raw_attrs,
63
- std::chrono::microseconds duration);
101
+
102
+ // Resolve (and cache) the value recorder for a set of attributes. The underlying meter returns a
103
+ // stable recorder for a given name/tag set, so resolving once per distinct attribute set keeps
104
+ // the per-operation tag-map construction and recorder lookup off the hot path.
105
+ [[nodiscard]] auto value_recorder_for(const metric_attributes& attrs)
106
+ -> std::shared_ptr<couchbase::metrics::value_recorder>;
64
107
 
65
108
  [[nodiscard]] auto wrapped() -> std::shared_ptr<couchbase::metrics::meter>;
66
109
 
@@ -71,5 +114,14 @@ public:
71
114
  private:
72
115
  std::shared_ptr<couchbase::metrics::meter> meter_;
73
116
  std::shared_ptr<cluster_label_listener> cluster_label_listener_;
117
+ std::mutex recorder_cache_mutex_{};
118
+ // Keyed by the full attribute set (not just service/operation): the meter is pluggable, and a
119
+ // custom meter may hand out a distinct recorder per tag combination, so the cache must ask it
120
+ // once for each distinct attribute set rather than assume any particular dedup granularity. The
121
+ // key mirrors what encode() emits -- in particular it orders by the standardized error type (see
122
+ // operator<), not the raw error code -- so the key space is finite (services x operations x
123
+ // scope/collection x standardized error type x cluster) and the cache stays bounded.
124
+ std::map<metric_attributes, std::shared_ptr<couchbase::metrics::value_recorder>>
125
+ recorder_cache_{};
74
126
  };
75
127
  } // namespace couchbase::core::metrics
@@ -0,0 +1,177 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2020-2021 Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include "analytics_response_parsing.hxx"
19
+
20
+ #include "core/utils/duration_parser.hxx"
21
+ #include "core/utils/json.hxx"
22
+
23
+ #include <couchbase/error_codes.hxx>
24
+
25
+ #include <tao/json/value.hpp>
26
+
27
+ namespace couchbase::core::operations
28
+ {
29
+
30
+ auto
31
+ parse_analytics_meta(const tao::json::value& payload) -> analytics_response::analytics_meta_data
32
+ {
33
+ analytics_response::analytics_meta_data meta{};
34
+
35
+ if (const auto* i = payload.find("requestID"); i != nullptr) {
36
+ meta.request_id = i->get_string();
37
+ }
38
+ if (const auto* i = payload.find("clientContextID"); i != nullptr) {
39
+ meta.client_context_id = i->get_string();
40
+ }
41
+
42
+ if (const auto* s = payload.find("status"); s != nullptr && s->is_string()) {
43
+ const auto& status = s->get_string();
44
+ if (status == "running") {
45
+ meta.status = analytics_response::analytics_status::running;
46
+ } else if (status == "success") {
47
+ meta.status = analytics_response::analytics_status::success;
48
+ } else if (status == "errors") {
49
+ meta.status = analytics_response::analytics_status::errors;
50
+ } else if (status == "completed") {
51
+ meta.status = analytics_response::analytics_status::completed;
52
+ } else if (status == "stopped") {
53
+ meta.status = analytics_response::analytics_status::stopped;
54
+ } else if (status == "timedout") {
55
+ meta.status = analytics_response::analytics_status::timedout;
56
+ } else if (status == "closed") {
57
+ meta.status = analytics_response::analytics_status::closed;
58
+ } else if (status == "fatal") {
59
+ meta.status = analytics_response::analytics_status::fatal;
60
+ } else if (status == "aborted") {
61
+ meta.status = analytics_response::analytics_status::aborted;
62
+ } else {
63
+ meta.status = analytics_response::analytics_status::unknown;
64
+ }
65
+ } else {
66
+ meta.status = analytics_response::analytics_status::unknown;
67
+ }
68
+
69
+ if (const auto* s = payload.find("signature"); s != nullptr) {
70
+ meta.signature = couchbase::core::utils::json::generate(*s);
71
+ }
72
+
73
+ if (const auto* m = payload.find("metrics"); m != nullptr) {
74
+ meta.metrics.result_count = m->at("resultCount").get_unsigned();
75
+ meta.metrics.result_size = m->at("resultSize").get_unsigned();
76
+ meta.metrics.elapsed_time = utils::parse_duration(m->at("elapsedTime").get_string());
77
+ meta.metrics.execution_time = utils::parse_duration(m->at("executionTime").get_string());
78
+ meta.metrics.processed_objects = m->at("processedObjects").get_unsigned();
79
+ meta.metrics.error_count = m->optional<std::uint64_t>("errorCount").value_or(0);
80
+ meta.metrics.warning_count = m->optional<std::uint64_t>("warningCount").value_or(0);
81
+ }
82
+
83
+ if (const auto* e = payload.find("errors"); e != nullptr) {
84
+ for (const auto& err : e->get_array()) {
85
+ analytics_response::analytics_problem problem;
86
+ problem.code = err.at("code").get_unsigned();
87
+ problem.message = err.at("msg").get_string();
88
+ meta.errors.emplace_back(problem);
89
+ }
90
+ }
91
+
92
+ if (const auto* w = payload.find("warnings"); w != nullptr) {
93
+ for (const auto& warn : w->get_array()) {
94
+ analytics_response::analytics_problem problem;
95
+ problem.code = warn.at("code").get_unsigned();
96
+ problem.message = warn.at("msg").get_string();
97
+ meta.warnings.emplace_back(problem);
98
+ }
99
+ }
100
+
101
+ return meta;
102
+ }
103
+
104
+ auto
105
+ map_analytics_error(const analytics_response::analytics_meta_data& meta, std::uint32_t http_status)
106
+ -> std::error_code
107
+ {
108
+ if (meta.status == analytics_response::analytics_status::success && http_status != 400) {
109
+ return {};
110
+ }
111
+ const auto unmatched =
112
+ http_status == 400 ? errc::common::invalid_argument : errc::common::internal_server_failure;
113
+
114
+ if (meta.errors.empty()) {
115
+ /* Reachable from make_response, which calls this for any non-success status even when the
116
+ * payload carries no "errors" array, and from the streaming-path caller, which has no such
117
+ * guarantee either. */
118
+ return unmatched;
119
+ }
120
+
121
+ const auto first_error_code = meta.errors.front().code;
122
+
123
+ std::error_code ec{};
124
+ switch (first_error_code) {
125
+ case 21002: /* Request timed out and will be cancelled */
126
+ ec = errc::common::unambiguous_timeout;
127
+ break;
128
+ case 24000: /* RFC-58: ParsingFailure */
129
+ ec = errc::common::parsing_failure;
130
+ break;
131
+ case 23000: /* RFC-58: TemporaryFailure */
132
+ case 23003: /* RFC-58: TemporaryFailure */
133
+ ec = errc::common::temporary_failure;
134
+ break;
135
+ case 23007: /* Job queue is full with [string] jobs */
136
+ ec = errc::analytics::job_queue_full;
137
+ break;
138
+ case 24044: /* Cannot find dataset [string] because there is no dataverse declared, nor an
139
+ alias with name [string]! */
140
+ case 24045: /* Cannot find dataset [string] in dataverse [string] nor an alias with name
141
+ [string]! */
142
+ case 24025: /* Cannot find dataset with name [string] in dataverse [string] */
143
+ ec = errc::analytics::dataset_not_found;
144
+ break;
145
+ case 24034: /* Cannot find dataverse with name [string] */
146
+ ec = errc::analytics::dataverse_not_found;
147
+ break;
148
+ case 24040: /* A dataset with name [string] already exists in dataverse [string] */
149
+ ec = errc::analytics::dataset_exists;
150
+ break;
151
+ case 24039: /* A dataverse with this name [string] already exists. */
152
+ ec = errc::analytics::dataverse_exists;
153
+ break;
154
+ case 24006: /* Link [string] does not exist | Link [string] does not exist */
155
+ ec = errc::analytics::link_not_found;
156
+ break;
157
+ default:
158
+ // RFC-58 maps these ranges whatever the HTTP status, so a 400 carrying one is not
159
+ // invalid_argument.
160
+ if (first_error_code >= 24000 && first_error_code < 25000) {
161
+ ec = errc::analytics::compilation_failure;
162
+ } else if (first_error_code >= 20000 && first_error_code < 21000) {
163
+ ec = errc::common::authentication_failure;
164
+ } else if (first_error_code >= 25000 && first_error_code < 26000) {
165
+ ec = errc::common::internal_server_failure;
166
+ }
167
+ break;
168
+ }
169
+
170
+ if (!ec) {
171
+ ec = unmatched;
172
+ }
173
+
174
+ return ec;
175
+ }
176
+
177
+ } // namespace couchbase::core::operations
@@ -0,0 +1,55 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2020-2021 Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #pragma once
19
+
20
+ #include "core/operations/document_analytics.hxx"
21
+
22
+ #include <couchbase/error_codes.hxx>
23
+
24
+ #include <tao/json/forward.hpp>
25
+
26
+ #include <cstdint>
27
+ #include <system_error>
28
+
29
+ namespace couchbase::core::operations
30
+ {
31
+
32
+ /**
33
+ * Parse analytics meta-data fields (status, metrics, warnings, errors, signature, requestID,
34
+ * clientContextID) from a top-level response payload.
35
+ *
36
+ * Pure function — no side effects, no access to request state.
37
+ */
38
+ auto
39
+ parse_analytics_meta(const tao::json::value& payload) -> analytics_response::analytics_meta_data;
40
+
41
+ /**
42
+ * Map analytics meta-data to an error_code.
43
+ *
44
+ * Pure classifier — no side effects, no exceptions thrown. Returns an empty error_code when the
45
+ * analytics query succeeded (meta.status == success and http_status is not 400).
46
+ *
47
+ * http_status is the status of the response that carried the metadata, or 0 where there is none.
48
+ * A failure that matches no specific mapping is invalid_argument for an HTTP 400 (RFC-58) and
49
+ * internal_server_failure otherwise.
50
+ */
51
+ [[nodiscard]] auto
52
+ map_analytics_error(const analytics_response::analytics_meta_data& meta,
53
+ std::uint32_t http_status = 0) -> std::error_code;
54
+
55
+ } // namespace couchbase::core::operations