couchbase 3.7.0 → 3.8.1

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 (349) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/ext/CMakeLists.txt +4 -1
  4. data/ext/cache/extconf_include.rb +4 -3
  5. data/ext/cache/mozilla-ca-bundle.crt +66 -665
  6. data/ext/cache/mozilla-ca-bundle.sha256 +1 -1
  7. data/ext/couchbase/CMakeLists.txt +26 -11
  8. data/ext/couchbase/cmake/APKBUILD.in +17 -1
  9. data/ext/couchbase/cmake/Bundler.cmake +9 -1
  10. data/ext/couchbase/cmake/Cache.cmake +48 -19
  11. data/ext/couchbase/cmake/CompilerOptions.cmake +3 -1
  12. data/ext/couchbase/cmake/OpenSSL.cmake +10 -2
  13. data/ext/couchbase/cmake/Packaging.cmake +48 -8
  14. data/ext/couchbase/cmake/ThirdPartyDependencies.cmake +43 -1
  15. data/ext/couchbase/cmake/build_config.hxx.in +2 -0
  16. data/ext/couchbase/cmake/couchbase-cxx-client.spec.in +18 -0
  17. data/ext/couchbase/cmake/tarball_glob.txt +10 -0
  18. data/ext/couchbase/core/app_telemetry_meter.cxx +1 -0
  19. data/ext/couchbase/core/app_telemetry_reporter.cxx +45 -43
  20. data/ext/couchbase/core/app_telemetry_reporter.hxx +4 -3
  21. data/ext/couchbase/core/bucket.cxx +128 -13
  22. data/ext/couchbase/core/bucket.hxx +12 -2
  23. data/ext/couchbase/core/cluster.cxx +304 -152
  24. data/ext/couchbase/core/cluster.hxx +32 -0
  25. data/ext/couchbase/core/cluster_credentials.cxx +25 -0
  26. data/ext/couchbase/core/cluster_credentials.hxx +5 -0
  27. data/ext/couchbase/core/cluster_label_listener.cxx +72 -0
  28. data/ext/couchbase/core/cluster_label_listener.hxx +46 -0
  29. data/ext/couchbase/core/cluster_options.hxx +4 -0
  30. data/ext/couchbase/core/deprecation_utils.hxx +26 -0
  31. data/ext/couchbase/core/error.hxx +27 -0
  32. data/ext/couchbase/core/error_context/base_error_context.hxx +32 -0
  33. data/ext/couchbase/core/error_context/key_value.cxx +1 -0
  34. data/ext/couchbase/core/error_context/key_value.hxx +23 -0
  35. data/ext/couchbase/core/error_context/key_value_error_context.hxx +35 -0
  36. data/ext/couchbase/core/error_context/subdocument_error_context.hxx +41 -0
  37. data/ext/couchbase/core/free_form_http_request.hxx +0 -2
  38. data/ext/couchbase/core/http_component.cxx +12 -48
  39. data/ext/couchbase/core/impl/analytics.cxx +3 -2
  40. data/ext/couchbase/core/impl/analytics.hxx +2 -1
  41. data/ext/couchbase/core/impl/analytics_index_manager.cxx +249 -137
  42. data/ext/couchbase/core/impl/binary_collection.cxx +239 -128
  43. data/ext/couchbase/core/impl/bucket_manager.cxx +87 -35
  44. data/ext/couchbase/core/impl/collection.cxx +914 -372
  45. data/ext/couchbase/core/impl/collection_manager.cxx +89 -49
  46. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +4 -4
  47. data/ext/couchbase/core/impl/error.cxx +49 -17
  48. data/ext/couchbase/core/impl/error.hxx +15 -10
  49. data/ext/couchbase/core/impl/get_all_replicas.hxx +1 -1
  50. data/ext/couchbase/core/impl/get_any_replica.hxx +2 -1
  51. data/ext/couchbase/core/impl/get_replica.hxx +2 -0
  52. data/ext/couchbase/core/impl/invoke_with_node_id.hxx +44 -0
  53. data/ext/couchbase/core/impl/lookup_in_replica.hxx +1 -1
  54. data/ext/couchbase/core/impl/node_id.cxx +110 -0
  55. data/ext/couchbase/core/impl/node_id.hxx +40 -0
  56. data/ext/couchbase/core/impl/observability_recorder.cxx +161 -0
  57. data/ext/couchbase/core/impl/observability_recorder.hxx +77 -0
  58. data/ext/couchbase/core/impl/observe_seqno.hxx +2 -0
  59. data/ext/couchbase/core/impl/public_bucket.cxx +31 -7
  60. data/ext/couchbase/core/impl/public_cluster.cxx +107 -19
  61. data/ext/couchbase/core/impl/query.cxx +6 -3
  62. data/ext/couchbase/core/impl/query.hxx +3 -1
  63. data/ext/couchbase/core/impl/query_index_manager.cxx +267 -102
  64. data/ext/couchbase/core/impl/scope.cxx +53 -11
  65. data/ext/couchbase/core/impl/search.cxx +8 -4
  66. data/ext/couchbase/core/impl/search.hxx +6 -2
  67. data/ext/couchbase/core/impl/search_index_manager.cxx +131 -41
  68. data/ext/couchbase/core/impl/with_cancellation.hxx +75 -0
  69. data/ext/couchbase/core/io/config_tracker.cxx +9 -9
  70. data/ext/couchbase/core/io/config_tracker.hxx +2 -1
  71. data/ext/couchbase/core/io/http_command.hxx +98 -49
  72. data/ext/couchbase/core/io/http_context.hxx +2 -0
  73. data/ext/couchbase/core/io/http_session.cxx +23 -10
  74. data/ext/couchbase/core/io/http_session.hxx +17 -9
  75. data/ext/couchbase/core/io/http_session_manager.hxx +245 -270
  76. data/ext/couchbase/core/io/http_traits.hxx +0 -7
  77. data/ext/couchbase/core/io/mcbp_command.hxx +123 -44
  78. data/ext/couchbase/core/io/mcbp_session.cxx +251 -26
  79. data/ext/couchbase/core/io/mcbp_session.hxx +9 -1
  80. data/ext/couchbase/core/io/mcbp_traits.hxx +0 -8
  81. data/ext/couchbase/core/io/streams.cxx +3 -3
  82. data/ext/couchbase/core/io/streams.hxx +3 -2
  83. data/ext/couchbase/core/meta/features.hxx +15 -0
  84. data/ext/couchbase/core/meta/version.cxx +13 -0
  85. data/ext/couchbase/core/meta/version.hxx +3 -0
  86. data/ext/couchbase/core/metrics/constants.hxx +23 -0
  87. data/ext/couchbase/core/metrics/logging_meter.cxx +5 -5
  88. data/ext/couchbase/core/metrics/meter_wrapper.cxx +65 -63
  89. data/ext/couchbase/core/metrics/meter_wrapper.hxx +12 -10
  90. data/ext/couchbase/core/operations/document_analytics.hxx +0 -5
  91. data/ext/couchbase/core/operations/document_append.hxx +0 -4
  92. data/ext/couchbase/core/operations/document_decrement.hxx +0 -5
  93. data/ext/couchbase/core/operations/document_exists.hxx +0 -7
  94. data/ext/couchbase/core/operations/document_get.hxx +0 -7
  95. data/ext/couchbase/core/operations/document_get_all_replicas.hxx +89 -29
  96. data/ext/couchbase/core/operations/document_get_and_lock.hxx +0 -9
  97. data/ext/couchbase/core/operations/document_get_and_touch.hxx +0 -9
  98. data/ext/couchbase/core/operations/document_get_any_replica.hxx +83 -2
  99. data/ext/couchbase/core/operations/document_get_projected.cxx +3 -4
  100. data/ext/couchbase/core/operations/document_get_projected.hxx +0 -9
  101. data/ext/couchbase/core/operations/document_increment.hxx +0 -5
  102. data/ext/couchbase/core/operations/document_insert.hxx +0 -4
  103. data/ext/couchbase/core/operations/document_lookup_in.hxx +0 -9
  104. data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +50 -4
  105. data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +121 -43
  106. data/ext/couchbase/core/operations/document_mutate_in.hxx +0 -5
  107. data/ext/couchbase/core/operations/document_prepend.hxx +0 -4
  108. data/ext/couchbase/core/operations/document_query.cxx +12 -12
  109. data/ext/couchbase/core/operations/document_query.hxx +0 -4
  110. data/ext/couchbase/core/operations/document_remove.hxx +0 -4
  111. data/ext/couchbase/core/operations/document_replace.hxx +0 -4
  112. data/ext/couchbase/core/operations/document_search.hxx +0 -7
  113. data/ext/couchbase/core/operations/document_touch.hxx +0 -7
  114. data/ext/couchbase/core/operations/document_unlock.hxx +0 -6
  115. data/ext/couchbase/core/operations/document_upsert.hxx +0 -4
  116. data/ext/couchbase/core/operations/document_view.cxx +2 -0
  117. data/ext/couchbase/core/operations/document_view.hxx +10 -13
  118. data/ext/couchbase/core/operations/http_noop.hxx +2 -0
  119. data/ext/couchbase/core/operations/management/analytics_dataset_create.hxx +2 -0
  120. data/ext/couchbase/core/operations/management/analytics_dataset_drop.hxx +2 -0
  121. data/ext/couchbase/core/operations/management/analytics_dataset_get_all.hxx +2 -0
  122. data/ext/couchbase/core/operations/management/analytics_dataverse_create.hxx +2 -0
  123. data/ext/couchbase/core/operations/management/analytics_dataverse_drop.hxx +2 -0
  124. data/ext/couchbase/core/operations/management/analytics_get_pending_mutations.hxx +2 -0
  125. data/ext/couchbase/core/operations/management/analytics_index_create.hxx +2 -0
  126. data/ext/couchbase/core/operations/management/analytics_index_drop.hxx +2 -0
  127. data/ext/couchbase/core/operations/management/analytics_index_get_all.hxx +2 -0
  128. data/ext/couchbase/core/operations/management/analytics_link_connect.hxx +2 -0
  129. data/ext/couchbase/core/operations/management/analytics_link_create.hxx +2 -0
  130. data/ext/couchbase/core/operations/management/analytics_link_disconnect.hxx +2 -0
  131. data/ext/couchbase/core/operations/management/analytics_link_drop.hxx +2 -0
  132. data/ext/couchbase/core/operations/management/analytics_link_get_all.hxx +2 -0
  133. data/ext/couchbase/core/operations/management/analytics_link_replace.hxx +2 -0
  134. data/ext/couchbase/core/operations/management/bucket_create.hxx +2 -0
  135. data/ext/couchbase/core/operations/management/bucket_describe.hxx +2 -0
  136. data/ext/couchbase/core/operations/management/bucket_drop.hxx +2 -0
  137. data/ext/couchbase/core/operations/management/bucket_flush.hxx +2 -0
  138. data/ext/couchbase/core/operations/management/bucket_get.hxx +2 -0
  139. data/ext/couchbase/core/operations/management/bucket_get_all.hxx +2 -0
  140. data/ext/couchbase/core/operations/management/bucket_update.hxx +2 -0
  141. data/ext/couchbase/core/operations/management/change_password.hxx +2 -0
  142. data/ext/couchbase/core/operations/management/cluster_describe.hxx +2 -0
  143. data/ext/couchbase/core/operations/management/cluster_developer_preview_enable.hxx +2 -0
  144. data/ext/couchbase/core/operations/management/collection_create.cxx +11 -11
  145. data/ext/couchbase/core/operations/management/collection_create.hxx +2 -0
  146. data/ext/couchbase/core/operations/management/collection_drop.cxx +11 -11
  147. data/ext/couchbase/core/operations/management/collection_drop.hxx +2 -0
  148. data/ext/couchbase/core/operations/management/collection_update.cxx +11 -11
  149. data/ext/couchbase/core/operations/management/collection_update.hxx +2 -0
  150. data/ext/couchbase/core/operations/management/collections_manifest_get.hxx +2 -0
  151. data/ext/couchbase/core/operations/management/error_utils.cxx +13 -7
  152. data/ext/couchbase/core/operations/management/eventing_deploy_function.hxx +2 -0
  153. data/ext/couchbase/core/operations/management/eventing_drop_function.hxx +2 -0
  154. data/ext/couchbase/core/operations/management/eventing_get_all_functions.hxx +2 -0
  155. data/ext/couchbase/core/operations/management/eventing_get_function.hxx +2 -0
  156. data/ext/couchbase/core/operations/management/eventing_get_status.hxx +2 -0
  157. data/ext/couchbase/core/operations/management/eventing_pause_function.hxx +2 -0
  158. data/ext/couchbase/core/operations/management/eventing_resume_function.hxx +2 -0
  159. data/ext/couchbase/core/operations/management/eventing_undeploy_function.hxx +2 -0
  160. data/ext/couchbase/core/operations/management/eventing_upsert_function.hxx +2 -0
  161. data/ext/couchbase/core/operations/management/freeform.hxx +2 -0
  162. data/ext/couchbase/core/operations/management/group_drop.hxx +2 -0
  163. data/ext/couchbase/core/operations/management/group_get.hxx +2 -0
  164. data/ext/couchbase/core/operations/management/group_get_all.hxx +2 -0
  165. data/ext/couchbase/core/operations/management/group_upsert.hxx +2 -0
  166. data/ext/couchbase/core/operations/management/query_index_build.hxx +2 -0
  167. data/ext/couchbase/core/operations/management/query_index_build_deferred.hxx +68 -30
  168. data/ext/couchbase/core/operations/management/query_index_create.cxx +5 -4
  169. data/ext/couchbase/core/operations/management/query_index_create.hxx +2 -0
  170. data/ext/couchbase/core/operations/management/query_index_drop.cxx +7 -6
  171. data/ext/couchbase/core/operations/management/query_index_drop.hxx +2 -0
  172. data/ext/couchbase/core/operations/management/query_index_get_all.hxx +4 -3
  173. data/ext/couchbase/core/operations/management/query_index_get_all_deferred.hxx +2 -1
  174. data/ext/couchbase/core/operations/management/role_get_all.hxx +2 -0
  175. data/ext/couchbase/core/operations/management/scope_create.cxx +12 -13
  176. data/ext/couchbase/core/operations/management/scope_create.hxx +2 -0
  177. data/ext/couchbase/core/operations/management/scope_drop.cxx +8 -9
  178. data/ext/couchbase/core/operations/management/scope_drop.hxx +2 -0
  179. data/ext/couchbase/core/operations/management/scope_get_all.hxx +2 -0
  180. data/ext/couchbase/core/operations/management/search_get_stats.hxx +2 -0
  181. data/ext/couchbase/core/operations/management/search_index_analyze_document.hxx +2 -0
  182. data/ext/couchbase/core/operations/management/search_index_control_ingest.hxx +2 -0
  183. data/ext/couchbase/core/operations/management/search_index_control_plan_freeze.hxx +2 -0
  184. data/ext/couchbase/core/operations/management/search_index_control_query.hxx +2 -0
  185. data/ext/couchbase/core/operations/management/search_index_drop.hxx +2 -0
  186. data/ext/couchbase/core/operations/management/search_index_get.hxx +2 -0
  187. data/ext/couchbase/core/operations/management/search_index_get_all.hxx +2 -0
  188. data/ext/couchbase/core/operations/management/search_index_get_documents_count.hxx +2 -0
  189. data/ext/couchbase/core/operations/management/search_index_get_stats.hxx +2 -0
  190. data/ext/couchbase/core/operations/management/search_index_upsert.hxx +2 -0
  191. data/ext/couchbase/core/operations/management/user_drop.hxx +2 -0
  192. data/ext/couchbase/core/operations/management/user_get.hxx +2 -0
  193. data/ext/couchbase/core/operations/management/user_get_all.hxx +2 -0
  194. data/ext/couchbase/core/operations/management/user_upsert.hxx +2 -0
  195. data/ext/couchbase/core/operations/management/view_index_drop.hxx +2 -0
  196. data/ext/couchbase/core/operations/management/view_index_get.hxx +2 -0
  197. data/ext/couchbase/core/operations/management/view_index_get_all.hxx +2 -0
  198. data/ext/couchbase/core/operations/management/view_index_upsert.hxx +2 -0
  199. data/ext/couchbase/core/operations/operation_traits.hxx +6 -0
  200. data/ext/couchbase/core/operations.hxx +0 -1
  201. data/ext/couchbase/core/operations_fwd.hxx +8 -0
  202. data/ext/couchbase/core/origin.cxx +67 -12
  203. data/ext/couchbase/core/origin.hxx +13 -8
  204. data/ext/couchbase/core/orphan_reporter.cxx +164 -0
  205. data/ext/couchbase/core/orphan_reporter.hxx +65 -0
  206. data/ext/couchbase/core/sasl/CMakeLists.txt +1 -0
  207. data/ext/couchbase/core/sasl/client.cc +6 -0
  208. data/ext/couchbase/core/sasl/mechanism.cc +2 -1
  209. data/ext/couchbase/core/sasl/mechanism.h +2 -1
  210. data/ext/couchbase/core/sasl/oauthbearer/oauthbearer.cc +41 -0
  211. data/ext/couchbase/core/sasl/oauthbearer/oauthbearer.h +47 -0
  212. data/ext/couchbase/core/tls_context_provider.cxx +44 -0
  213. data/ext/couchbase/core/tls_context_provider.hxx +44 -0
  214. data/ext/couchbase/core/topology/configuration.cxx +21 -0
  215. data/ext/couchbase/core/topology/configuration.hxx +28 -0
  216. data/ext/couchbase/core/tracing/attribute_helpers.hxx +45 -0
  217. data/ext/couchbase/core/tracing/constants.hxx +148 -68
  218. data/ext/couchbase/core/tracing/threshold_logging_options.hxx +0 -3
  219. data/ext/couchbase/core/tracing/threshold_logging_tracer.cxx +122 -170
  220. data/ext/couchbase/core/tracing/tracer_wrapper.cxx +17 -24
  221. data/ext/couchbase/core/tracing/tracer_wrapper.hxx +8 -10
  222. data/ext/couchbase/core/tracing/wrapper_sdk_tracer.cxx +114 -0
  223. data/ext/couchbase/core/tracing/wrapper_sdk_tracer.hxx +85 -0
  224. data/ext/couchbase/core/transactions/attempt_context_impl.cxx +16 -14
  225. data/ext/couchbase/core/transactions/attempt_context_impl.hxx +4 -4
  226. data/ext/couchbase/core/transactions/transactions.cxx +1 -1
  227. data/ext/couchbase/core/transactions/transactions_cleanup.cxx +1 -2
  228. data/ext/couchbase/core/utils/byteswap.hxx +12 -0
  229. data/ext/couchbase/core/utils/concurrent_fixed_priority_queue.hxx +102 -0
  230. data/ext/couchbase/core/utils/connection_string.cxx +2 -0
  231. data/ext/couchbase/core/utils/contains_string.cxx +61 -0
  232. data/ext/couchbase/core/utils/contains_string.hxx +26 -0
  233. data/ext/couchbase/couchbase/certificate_authenticator.hxx +1 -0
  234. data/ext/couchbase/couchbase/cluster.hxx +47 -0
  235. data/ext/couchbase/couchbase/cluster_options.hxx +16 -0
  236. data/ext/couchbase/couchbase/collection.hxx +133 -15
  237. data/ext/couchbase/couchbase/error.hxx +16 -0
  238. data/ext/couchbase/couchbase/error_codes.hxx +48 -48
  239. data/ext/couchbase/couchbase/jwt_authenticator.hxx +52 -0
  240. data/ext/couchbase/couchbase/metrics/meter.hxx +2 -1
  241. data/ext/couchbase/couchbase/metrics/otel_meter.hxx +75 -80
  242. data/ext/couchbase/couchbase/network_options.hxx +19 -0
  243. data/ext/couchbase/couchbase/node_id.hxx +123 -0
  244. data/ext/couchbase/couchbase/node_id_for_options.hxx +61 -0
  245. data/ext/couchbase/couchbase/node_ids_options.hxx +62 -0
  246. data/ext/couchbase/couchbase/password_authenticator.hxx +1 -0
  247. data/ext/couchbase/couchbase/result.hxx +42 -0
  248. data/ext/couchbase/couchbase/tracing/otel_tracer.hxx +15 -17
  249. data/ext/couchbase/couchbase/tracing/request_span.hxx +2 -2
  250. data/ext/couchbase.cxx +4 -0
  251. data/ext/extconf.rb +1 -0
  252. data/ext/rcb_analytics.cxx +157 -47
  253. data/ext/rcb_backend.cxx +118 -71
  254. data/ext/rcb_buckets.cxx +39 -16
  255. data/ext/rcb_collections.cxx +36 -12
  256. data/ext/rcb_crud.cxx +589 -294
  257. data/ext/rcb_hdr_histogram.cxx +219 -0
  258. data/ext/rcb_hdr_histogram.hxx +28 -0
  259. data/ext/rcb_logger.cxx +15 -17
  260. data/ext/rcb_multi.cxx +142 -59
  261. data/ext/rcb_observability.cxx +132 -0
  262. data/ext/rcb_observability.hxx +49 -0
  263. data/ext/rcb_query.cxx +77 -27
  264. data/ext/rcb_search.cxx +92 -31
  265. data/ext/rcb_users.cxx +69 -26
  266. data/ext/rcb_utils.cxx +91 -0
  267. data/ext/rcb_utils.hxx +141 -168
  268. data/ext/rcb_views.cxx +36 -12
  269. data/lib/active_support/cache/couchbase_store.rb +6 -6
  270. data/lib/couchbase/authenticator.rb +14 -0
  271. data/lib/couchbase/binary_collection.rb +37 -22
  272. data/lib/couchbase/bucket.rb +46 -31
  273. data/lib/couchbase/cluster.rb +146 -61
  274. data/lib/couchbase/collection.rb +257 -186
  275. data/lib/couchbase/datastructures/couchbase_list.rb +82 -50
  276. data/lib/couchbase/datastructures/couchbase_map.rb +87 -50
  277. data/lib/couchbase/datastructures/couchbase_queue.rb +65 -38
  278. data/lib/couchbase/datastructures/couchbase_set.rb +58 -41
  279. data/lib/couchbase/deprecations.rb +1 -1
  280. data/lib/couchbase/diagnostics.rb +8 -8
  281. data/lib/couchbase/errors.rb +7 -1
  282. data/lib/couchbase/json_transcoder.rb +1 -1
  283. data/lib/couchbase/management/analytics_index_manager.rb +90 -59
  284. data/lib/couchbase/management/bucket_manager.rb +73 -45
  285. data/lib/couchbase/management/collection_manager.rb +86 -43
  286. data/lib/couchbase/management/collection_query_index_manager.rb +56 -33
  287. data/lib/couchbase/management/query_index_manager.rb +88 -36
  288. data/lib/couchbase/management/scope_search_index_manager.rb +119 -52
  289. data/lib/couchbase/management/search_index_manager.rb +401 -178
  290. data/lib/couchbase/management/user_manager.rb +343 -174
  291. data/lib/couchbase/management/view_index_manager.rb +166 -73
  292. data/lib/couchbase/metrics/logging_meter.rb +108 -0
  293. data/lib/couchbase/metrics/logging_value_recorder.rb +50 -0
  294. data/lib/couchbase/metrics/meter.rb +27 -0
  295. data/lib/couchbase/metrics/noop_meter.rb +30 -0
  296. data/lib/couchbase/metrics/noop_value_recorder.rb +27 -0
  297. data/lib/couchbase/metrics/value_recorder.rb +25 -0
  298. data/lib/couchbase/options.rb +71 -5
  299. data/lib/couchbase/protostellar/client.rb +0 -2
  300. data/lib/couchbase/protostellar/cluster.rb +7 -0
  301. data/lib/couchbase/protostellar/generated/admin/analytics/v1/analytics_pb.rb +54 -0
  302. data/lib/couchbase/protostellar/generated/admin/analytics/v1/analytics_services_pb.rb +51 -0
  303. data/lib/couchbase/protostellar/generated/admin/bucket/v1/bucket_pb.rb +5 -24
  304. data/lib/couchbase/protostellar/generated/admin/bucket/v1/bucket_services_pb.rb +16 -0
  305. data/lib/couchbase/protostellar/generated/admin/collection/v1/collection_pb.rb +5 -24
  306. data/lib/couchbase/protostellar/generated/admin/collection/v1/collection_services_pb.rb +16 -0
  307. data/lib/couchbase/protostellar/generated/admin/query/v1/query_pb.rb +5 -24
  308. data/lib/couchbase/protostellar/generated/admin/query/v1/query_services_pb.rb +18 -0
  309. data/lib/couchbase/protostellar/generated/admin/search/v1/search_pb.rb +2 -23
  310. data/lib/couchbase/protostellar/generated/admin/search/v1/search_services_pb.rb +23 -0
  311. data/lib/couchbase/protostellar/generated/analytics/v1/analytics_pb.rb +4 -25
  312. data/lib/couchbase/protostellar/generated/analytics/v1/analytics_services_pb.rb +10 -0
  313. data/lib/couchbase/protostellar/generated/internal/hooks/v1/hooks_pb.rb +6 -25
  314. data/lib/couchbase/protostellar/generated/internal/hooks/v1/hooks_services_pb.rb +18 -0
  315. data/lib/couchbase/protostellar/generated/internal/xdcr/v1/xdcr_pb.rb +46 -0
  316. data/lib/couchbase/protostellar/generated/internal/xdcr/v1/xdcr_services_pb.rb +56 -0
  317. data/lib/couchbase/protostellar/generated/kv/v1/kv_pb.rb +3 -26
  318. data/lib/couchbase/protostellar/generated/kv/v1/kv_services_pb.rb +47 -0
  319. data/lib/couchbase/protostellar/generated/query/v1/query_pb.rb +4 -26
  320. data/lib/couchbase/protostellar/generated/query/v1/query_services_pb.rb +10 -0
  321. data/lib/couchbase/protostellar/generated/routing/v2/routing_pb.rb +26 -0
  322. data/lib/couchbase/protostellar/generated/routing/v2/routing_services_pb.rb +43 -0
  323. data/lib/couchbase/protostellar/generated/search/v1/search_pb.rb +5 -26
  324. data/lib/couchbase/protostellar/generated/search/v1/search_services_pb.rb +11 -0
  325. data/lib/couchbase/protostellar/generated/transactions/v1/transactions_pb.rb +2 -23
  326. data/lib/couchbase/protostellar/generated/transactions/v1/transactions_services_pb.rb +30 -0
  327. data/lib/couchbase/protostellar/generated/view/v1/view_pb.rb +2 -23
  328. data/lib/couchbase/protostellar/generated/view/v1/view_services_pb.rb +9 -0
  329. data/lib/couchbase/protostellar/request_generator/admin/collection.rb +4 -2
  330. data/lib/couchbase/protostellar/request_generator/admin/query.rb +2 -0
  331. data/lib/couchbase/protostellar/request_generator/kv.rb +1 -1
  332. data/lib/couchbase/protostellar/scope.rb +4 -0
  333. data/lib/couchbase/scope.rb +62 -48
  334. data/lib/couchbase/search_options.rb +18 -18
  335. data/lib/couchbase/tracing/noop_span.rb +29 -0
  336. data/lib/couchbase/tracing/noop_tracer.rb +29 -0
  337. data/lib/couchbase/tracing/request_span.rb +34 -0
  338. data/lib/couchbase/tracing/request_tracer.rb +28 -0
  339. data/lib/couchbase/tracing/threshold_logging_span.rb +112 -0
  340. data/lib/couchbase/tracing/threshold_logging_tracer.rb +231 -0
  341. data/lib/couchbase/utils/hdr_histogram.rb +55 -0
  342. data/lib/couchbase/utils/observability.rb +263 -0
  343. data/lib/couchbase/utils/observability_constants.rb +200 -0
  344. data/lib/couchbase/utils/stdlib_logger_adapter.rb +1 -3
  345. data/lib/couchbase/version.rb +1 -1
  346. data/lib/couchbase.rb +2 -2
  347. metadata +72 -8
  348. data/lib/couchbase/protostellar/generated/routing/v1/routing_pb.rb +0 -52
  349. data/lib/couchbase/protostellar/generated/routing/v1/routing_services_pb.rb +0 -30
@@ -28,6 +28,7 @@
28
28
  #include "core/metrics/meter_wrapper.hxx"
29
29
  #include "core/operations/http_noop.hxx"
30
30
  #include "core/service_type.hxx"
31
+ #include "core/tls_context_provider.hxx"
31
32
  #include "core/tracing/noop_tracer.hxx"
32
33
  #include "core/tracing/tracer_wrapper.hxx"
33
34
  #include "http_command.hxx"
@@ -58,10 +59,14 @@ class http_session_manager
58
59
  {
59
60
  #endif
60
61
  public:
61
- http_session_manager(std::string client_id, asio::io_context& ctx, asio::ssl::context& tls)
62
+ http_session_manager(std::string client_id,
63
+ asio::io_context& ctx,
64
+ tls_context_provider& tls,
65
+ origin& origin)
62
66
  : client_id_(std::move(client_id))
63
67
  , ctx_(ctx)
64
68
  , tls_(tls)
69
+ , origin_(origin)
65
70
  {
66
71
  }
67
72
 
@@ -192,8 +197,7 @@ public:
192
197
  template<typename Collector>
193
198
  void ping(std::set<service_type> services,
194
199
  std::optional<std::chrono::milliseconds> timeout,
195
- std::shared_ptr<Collector> collector,
196
- const couchbase::core::cluster_credentials& credentials)
200
+ std::shared_ptr<Collector> collector)
197
201
  {
198
202
  std::array known_types{
199
203
  service_type::query, service_type::analytics, service_type::search,
@@ -212,7 +216,16 @@ public:
212
216
  std::uint16_t port = node.port_or(options_.network, type, options_.enable_tls, 0);
213
217
  if (port != 0) {
214
218
  const auto& hostname = node.hostname_for(options_.network);
215
- auto session = create_session(type, credentials, hostname, port, node.node_uuid);
219
+ const auto& canonical_hostname = node.hostname;
220
+ std::uint16_t canonical_port = node.port_or(type, options_.enable_tls, 0);
221
+ auto session = create_session(type,
222
+ node_details{
223
+ hostname,
224
+ port,
225
+ node.node_uuid,
226
+ canonical_hostname,
227
+ canonical_port,
228
+ });
216
229
  if (session->is_connected()) {
217
230
  std::scoped_lock lock(sessions_mutex_);
218
231
  busy_sessions_[type].push_back(session);
@@ -238,66 +251,45 @@ public:
238
251
  app_telemetry_meter_,
239
252
  options_.default_timeout_for(request.type));
240
253
  #endif
241
-
242
- cmd->start([start = std::chrono::steady_clock::now(),
243
- self = shared_from_this(),
244
- type,
245
- cmd,
246
- #ifdef COUCHBASE_CXX_CLIENT_COLUMNAR
247
- handler = collector->build_reporter()](error_union err,
248
- io::http_response&& msg) {
249
- diag::ping_state state = diag::ping_state::ok;
250
- std::optional<std::string> error{};
251
- if (!std::holds_alternative<std::monostate>(err)) {
252
- auto ec = std::holds_alternative<impl::bootstrap_error>(err)
253
- ? std::get<impl::bootstrap_error>(err).ec
254
- : std::get<std::error_code>(err);
255
- if (ec) {
254
+ cmd->start(
255
+ [start = std::chrono::steady_clock::now(),
256
+ self = shared_from_this(),
257
+ type,
258
+ cmd,
259
+ handler = collector->build_reporter()](operations::http_noop_response&& resp) {
260
+ diag::ping_state state = diag::ping_state::ok;
261
+ std::optional<std::string> error{};
262
+ if (auto ec = resp.ctx.ec; ec) {
256
263
  if (ec == errc::common::unambiguous_timeout ||
257
264
  ec == errc::common::ambiguous_timeout) {
258
265
  state = diag::ping_state::timeout;
259
266
  } else {
260
267
  state = diag::ping_state::error;
261
268
  }
262
- error.emplace(fmt::format(
263
- "code={}, message={}, http_code={}", ec.value(), ec.message(), msg.status_code));
269
+ error.emplace(fmt::format("code={}, message={}, http_code={}",
270
+ ec.value(),
271
+ ec.message(),
272
+ resp.ctx.http_status));
264
273
  }
265
- }
266
- #else
267
- handler = collector->build_reporter()](std::error_code ec,
268
- io::http_response&& msg) {
269
- diag::ping_state state = diag::ping_state::ok;
270
- std::optional<std::string> error{};
271
- if (ec) {
272
- if (ec == errc::common::unambiguous_timeout ||
273
- ec == errc::common::ambiguous_timeout) {
274
- state = diag::ping_state::timeout;
275
- } else {
276
- state = diag::ping_state::error;
274
+ auto remote_address = cmd->session_->remote_address();
275
+ // If not connected, the remote address will be empty. Better to
276
+ // give the user some context on the "attempted" remote address.
277
+ if (remote_address.empty()) {
278
+ remote_address =
279
+ fmt::format("{}:{}", cmd->session_->hostname(), cmd->session_->port());
277
280
  }
278
- error.emplace(fmt::format(
279
- "code={}, message={}, http_code={}", ec.value(), ec.message(), msg.status_code));
280
- }
281
- #endif
282
- auto remote_address = cmd->session_->remote_address();
283
- // If not connected, the remote address will be empty. Better to
284
- // give the user some context on the "attempted" remote address.
285
- if (remote_address.empty()) {
286
- remote_address =
287
- fmt::format("{}:{}", cmd->session_->hostname(), cmd->session_->port());
288
- }
289
- handler->report(
290
- diag::endpoint_ping_info{ type,
291
- cmd->session_->id(),
292
- std::chrono::duration_cast<std::chrono::microseconds>(
293
- std::chrono::steady_clock::now() - start),
294
- remote_address,
295
- cmd->session_->local_address(),
296
- state,
297
- {},
298
- error });
299
- self->check_in(type, cmd->session_);
300
- });
281
+ handler->report(
282
+ diag::endpoint_ping_info{ type,
283
+ cmd->session_->id(),
284
+ std::chrono::duration_cast<std::chrono::microseconds>(
285
+ std::chrono::steady_clock::now() - start),
286
+ remote_address,
287
+ cmd->session_->local_address(),
288
+ state,
289
+ {},
290
+ error });
291
+ self->check_in(type, cmd->session_);
292
+ });
301
293
 
302
294
  cmd->set_command_session(session);
303
295
  if (!session->is_connected()) {
@@ -310,19 +302,34 @@ public:
310
302
  }
311
303
  }
312
304
 
305
+ struct node_details {
306
+ std::string hostname{};
307
+ std::uint16_t port{};
308
+ std::string node_uuid{};
309
+ std::string canonical_hostname{};
310
+ std::uint16_t canonical_port{};
311
+ };
312
+
313
313
  auto check_out(service_type type,
314
- const couchbase::core::cluster_credentials& credentials,
315
- std::string preferred_node,
316
- const std::string& undesired_node = {})
314
+ std::string preferred_node_address,
315
+ const std::string& undesired_node_address = {})
317
316
  -> std::pair<std::error_code, std::shared_ptr<http_session>>
318
317
  {
319
- std::string node_uuid{};
320
-
321
- if (preferred_node.empty() && !undesired_node.empty()) {
322
- auto [hostname, port, uuid] = pick_random_node(type, undesired_node);
323
- if (port != 0) {
324
- preferred_node = fmt::format("{}:{}", hostname, port);
325
- node_uuid = uuid;
318
+ node_details preferred_node{};
319
+
320
+ if (preferred_node_address.empty() && !undesired_node_address.empty()) {
321
+ // This is currently only used by Columnar to avoid the node
322
+ // that was last used and to satisfy the requirement for retrying on a different randomly
323
+ // selected node (as opposed to any node we have an idle session to).
324
+ if (auto n = pick_random_node(type, undesired_node_address); n.port != 0) {
325
+ preferred_node_address = fmt::format("{}:{}", n.hostname, n.port);
326
+ preferred_node = std::move(n);
327
+ }
328
+ } else if (!preferred_node_address.empty()) {
329
+ // A 'sticky' node was specified. We should populate the node details.
330
+ preferred_node = lookup_node(type, preferred_node_address);
331
+ if (preferred_node.port == 0) {
332
+ return { errc::common::service_not_available, nullptr };
326
333
  }
327
334
  }
328
335
 
@@ -338,21 +345,21 @@ public:
338
345
  });
339
346
  std::shared_ptr<http_session> session{};
340
347
  while (!idle_sessions_[type].empty()) {
341
- if (preferred_node.empty()) {
348
+ if (preferred_node_address.empty()) {
342
349
  session = idle_sessions_[type].front();
343
350
  idle_sessions_[type].pop_front();
344
351
  if (session->reset_idle()) {
345
352
  break;
346
353
  }
347
354
  } else {
348
- auto [hostname, port] = split_host_port(preferred_node);
349
-
350
355
  auto ptr = std::find_if(idle_sessions_[type].begin(),
351
356
  idle_sessions_[type].end(),
352
- [&preferred_node, &h = hostname, &p = port](const auto& s) {
357
+ [&preferred_node_address,
358
+ &h = preferred_node.hostname,
359
+ &p = preferred_node.port](const auto& s) {
353
360
  // Check for a match using both the unresolved hostname & IP
354
361
  // address
355
- return (s->remote_address() == preferred_node ||
362
+ return (s->remote_address() == preferred_node_address ||
356
363
  (s->hostname() == h && s->port() == std::to_string(p)));
357
364
  });
358
365
  if (ptr != idle_sessions_[type].end()) {
@@ -362,7 +369,7 @@ public:
362
369
  break;
363
370
  }
364
371
  } else {
365
- session = create_session(type, credentials, hostname, port, node_uuid);
372
+ session = create_session(type, preferred_node);
366
373
  break;
367
374
  }
368
375
  }
@@ -374,12 +381,12 @@ public:
374
381
  session.reset();
375
382
  }
376
383
  if (!session) {
377
- auto [hostname, port, uuid] =
378
- preferred_node.empty() ? next_node(type) : lookup_node(type, preferred_node);
379
- if (port == 0) {
384
+ auto node = preferred_node_address.empty() ? next_node(type)
385
+ : lookup_node(type, preferred_node_address);
386
+ if (node.port == 0) {
380
387
  return { errc::common::service_not_available, nullptr };
381
388
  }
382
- session = create_session(type, credentials, hostname, port, uuid);
389
+ session = create_session(type, node);
383
390
  }
384
391
  if (session->is_connected()) {
385
392
  busy_sessions_[type].push_back(session);
@@ -395,9 +402,20 @@ public:
395
402
  return;
396
403
  }
397
404
  if (!session->is_connected()) {
398
- CB_LOG_DEBUG("{} HTTP session never connected. Skipping check-in", session->log_prefix());
399
- return session.reset();
405
+ {
406
+ std::scoped_lock lock(sessions_mutex_);
407
+ if (auto pend_it = pending_sessions_.find(type); pend_it != pending_sessions_.end()) {
408
+ pend_it->second.remove_if([id = session->id()](const auto& s) {
409
+ return !s || s->id() == id;
410
+ });
411
+ }
412
+ }
413
+ CB_LOG_DEBUG("{} HTTP session never connected. Ensured session is not in pending.",
414
+ session->log_prefix());
415
+ return;
400
416
  }
417
+ bool should_stop = false;
418
+ std::chrono::milliseconds idle_timeout{};
401
419
  {
402
420
  std::scoped_lock lock(config_mutex_);
403
421
  if (!session->keep_alive() || !config_.has_node(options_.network,
@@ -405,22 +423,34 @@ public:
405
423
  options_.enable_tls,
406
424
  session->hostname(),
407
425
  session->port())) {
408
- return asio::post(session->get_executor(), [session]() {
409
- session->stop();
410
- });
426
+ should_stop = true;
427
+ } else {
428
+ idle_timeout = options_.idle_http_connection_timeout;
411
429
  }
412
430
  }
431
+ if (should_stop) {
432
+ return asio::post(session->get_executor(), [session]() {
433
+ session->stop();
434
+ });
435
+ }
413
436
  if (!session->is_stopped()) {
414
- session->set_idle(options_.idle_http_connection_timeout);
437
+ // set_idle() arms the idle timer via async_wait — it never calls stop() inline,
438
+ // so on_stop cannot re-enter sessions_mutex_ here. It must precede publication to
439
+ // idle_sessions_ so a concurrent check_out's reset_idle() finds a pending timer.
440
+ session->set_idle(idle_timeout);
415
441
  CB_LOG_DEBUG("{} put HTTP session back to idle connections", session->log_prefix());
416
442
  std::scoped_lock lock(sessions_mutex_);
417
443
  idle_sessions_[type].push_back(session);
418
- busy_sessions_[type].remove_if([id = session->id()](const auto& s) -> bool {
419
- return !s || s->id() == id;
420
- });
421
- pending_sessions_[type].remove_if([id = session->id()](const auto& s) -> bool {
422
- return !s || s->id() == id;
423
- });
444
+ if (auto busy_it = busy_sessions_.find(type); busy_it != busy_sessions_.end()) {
445
+ busy_it->second.remove_if([id = session->id()](const auto& s) -> bool {
446
+ return !s || s->id() == id;
447
+ });
448
+ }
449
+ if (auto pend_it = pending_sessions_.find(type); pend_it != pending_sessions_.end()) {
450
+ pend_it->second.remove_if([id = session->id()](const auto& s) -> bool {
451
+ return !s || s->id() == id;
452
+ });
453
+ }
424
454
  }
425
455
  }
426
456
 
@@ -462,13 +492,11 @@ public:
462
492
  }
463
493
 
464
494
  template<typename Request, typename Handler>
465
- void execute(Request request,
466
- Handler&& handler,
467
- const couchbase::core::cluster_credentials& credentials)
495
+ void execute(Request request, Handler&& handler)
468
496
  {
469
497
  #ifdef COUCHBASE_CXX_CLIENT_COLUMNAR
470
498
  if (!configured_) {
471
- return defer_command(request, std::move(handler), credentials);
499
+ return defer_command(request, std::move(handler));
472
500
  }
473
501
  #endif
474
502
  std::string preferred_node;
@@ -477,12 +505,12 @@ public:
477
505
  preferred_node = *request.send_to_node;
478
506
  }
479
507
  }
480
- auto [error, session] = check_out(request.type, credentials, preferred_node);
508
+ auto [error, session] = check_out(request.type, preferred_node);
481
509
  if (error) {
482
510
  typename Request::error_context_type ctx{};
483
511
  ctx.ec = error;
484
- using response_type = typename Request::encoded_response_type;
485
- return handler(request.make_response(std::move(ctx), response_type{}));
512
+ using encoded_response_type = typename Request::encoded_response_type;
513
+ return handler(request.make_response(std::move(ctx), encoded_response_type{}));
486
514
  }
487
515
 
488
516
  #ifdef COUCHBASE_CXX_CLIENT_COLUMNAR
@@ -494,8 +522,6 @@ public:
494
522
  app_telemetry_meter_,
495
523
  options_.default_timeout_for(request.type),
496
524
  dispatch_timeout_);
497
- cmd->start([self = shared_from_this(), cmd, handler = std::forward<Handler>(handler)](
498
- error_union err, io::http_response&& msg) mutable {
499
525
  #else
500
526
  auto cmd = std::make_shared<operations::http_command<Request>>(
501
527
  ctx_,
@@ -504,42 +530,12 @@ public:
504
530
  meter_,
505
531
  app_telemetry_meter_,
506
532
  options_.default_timeout_for(request.type));
507
- cmd->start([self = shared_from_this(), cmd, handler = std::forward<Handler>(handler)](
508
- std::error_code ec, io::http_response&& msg) mutable {
509
- #endif
510
- using command_type = typename decltype(cmd)::element_type;
511
- using encoded_response_type = typename command_type::encoded_response_type;
512
- using error_context_type = typename command_type::error_context_type;
513
- encoded_response_type resp{ std::move(msg) };
514
- error_context_type ctx{};
515
- #ifdef COUCHBASE_CXX_CLIENT_COLUMNAR
516
- if (!std::holds_alternative<std::monostate>(err)) {
517
- if (std::holds_alternative<impl::bootstrap_error>(err)) {
518
- auto bootstrap_error = std::get<impl::bootstrap_error>(err);
519
- if (bootstrap_error.ec == errc::common::unambiguous_timeout) {
520
- CB_LOG_DEBUG("Timeout caused by bootstrap error. code={}, ec_message={}, message={}.",
521
- bootstrap_error.ec.value(),
522
- bootstrap_error.ec.message(),
523
- bootstrap_error.error_message);
524
- }
525
- ctx.ec = bootstrap_error.ec;
526
- } else {
527
- ctx.ec = std::get<std::error_code>(err);
528
- }
529
- }
530
- #else
531
- ctx.ec = ec;
532
533
  #endif
533
- ctx.client_context_id = cmd->client_context_id_;
534
- ctx.method = cmd->encoded.method;
535
- ctx.path = cmd->encoded.path;
536
- ctx.http_status = resp.status_code;
537
- ctx.http_body = resp.body.data();
538
- ctx.last_dispatched_from = cmd->session_->local_address();
539
- ctx.last_dispatched_to = cmd->session_->remote_address();
540
- ctx.hostname = cmd->session_->http_context().hostname;
541
- ctx.port = cmd->session_->http_context().port;
542
- handler(cmd->request.make_response(std::move(ctx), std::move(resp)));
534
+
535
+ using response_type = typename Request::response_type;
536
+ cmd->start([self = shared_from_this(), cmd, handler = std::forward<Handler>(handler)](
537
+ response_type&& resp) mutable {
538
+ handler(std::move(resp));
543
539
  self->check_in(cmd->request.type, cmd->session_);
544
540
  });
545
541
  cmd->set_command_session(session);
@@ -596,15 +592,14 @@ public:
596
592
 
597
593
  // stop this session and create a new one w/ new hostname + port
598
594
  session->stop();
599
- auto [hostname, port, node_uuid] = preferred_node.empty()
600
- ? self->next_node(session->type())
601
- : self->lookup_node(session->type(), preferred_node);
602
- if (port == 0) {
595
+ const auto node = preferred_node.empty()
596
+ ? self->next_node(session->type())
597
+ : self->lookup_node(session->type(), preferred_node);
598
+ if (node.port == 0) {
603
599
  cb(errc::common::service_not_available, {});
604
600
  return;
605
601
  }
606
- auto new_session =
607
- self->create_session(session->type(), session->credentials(), hostname, port, node_uuid);
602
+ auto new_session = self->create_session(session->type(), node);
608
603
  if (new_session->is_connected()) {
609
604
  {
610
605
  const std::scoped_lock inner_lock(self->sessions_mutex_);
@@ -704,15 +699,14 @@ private:
704
699
  }
705
700
  // stop this session and create a new one w/ new hostname + port
706
701
  session->stop();
707
- auto [hostname, port, node_uuid] = preferred_node.empty()
708
- ? self->next_node(session->type())
709
- : self->lookup_node(session->type(), preferred_node);
710
- if (port == 0) {
702
+ const auto node = preferred_node.empty()
703
+ ? self->next_node(session->type())
704
+ : self->lookup_node(session->type(), preferred_node);
705
+ if (node.port == 0) {
711
706
  cmd->invoke_handler(errc::common::service_not_available, {});
712
707
  return;
713
708
  }
714
- auto new_session =
715
- self->create_session(session->type(), session->credentials(), hostname, port, node_uuid);
709
+ auto new_session = self->create_session(session->type(), node);
716
710
  cmd->set_command_session(new_session);
717
711
  if (new_session->is_connected()) {
718
712
  std::scoped_lock inner_lock(self->sessions_mutex_);
@@ -729,53 +723,78 @@ private:
729
723
  });
730
724
  }
731
725
 
732
- auto create_session(service_type type,
733
- const couchbase::core::cluster_credentials& credentials,
734
- const std::string& hostname,
735
- std::uint16_t port,
736
- const std::string& node_uuid) -> std::shared_ptr<http_session>
726
+ auto create_session(service_type type, const node_details& node) -> std::shared_ptr<http_session>
737
727
  {
738
728
  std::shared_ptr<http_session> session;
739
729
  if (options_.enable_tls) {
740
- session = std::make_shared<http_session>(
741
- type,
742
- client_id_,
743
- node_uuid,
744
- ctx_,
745
- tls_,
746
- credentials,
747
- hostname,
748
- std::to_string(port),
749
- http_context{ config_, options_, query_cache_, hostname, port });
730
+ session = std::make_shared<http_session>(type,
731
+ client_id_,
732
+ node.node_uuid,
733
+ ctx_,
734
+ tls_,
735
+ origin_,
736
+ node.hostname,
737
+ std::to_string(node.port),
738
+ http_context{
739
+ config_,
740
+ options_,
741
+ query_cache_,
742
+ node.hostname,
743
+ node.port,
744
+ node.canonical_hostname,
745
+ node.canonical_port,
746
+ });
750
747
  } else {
751
- session = std::make_shared<http_session>(
752
- type,
753
- client_id_,
754
- node_uuid,
755
- ctx_,
756
- credentials,
757
- hostname,
758
- std::to_string(port),
759
- http_context{ config_, options_, query_cache_, hostname, port });
748
+ session = std::make_shared<http_session>(type,
749
+ client_id_,
750
+ node.node_uuid,
751
+ ctx_,
752
+ origin_,
753
+ node.hostname,
754
+ std::to_string(node.port),
755
+ http_context{
756
+ config_,
757
+ options_,
758
+ query_cache_,
759
+ node.hostname,
760
+ node.port,
761
+ node.canonical_hostname,
762
+ node.canonical_port,
763
+ });
760
764
  }
761
765
 
762
766
  session->on_stop([type, id = session->id(), self = this->shared_from_this()]() {
763
- std::scoped_lock inner_lock(self->sessions_mutex_);
764
- self->busy_sessions_[type].remove_if([&id](const auto& s) {
765
- return !s || s->id() == id;
766
- });
767
- self->idle_sessions_[type].remove_if([&id](const auto& s) {
768
- return !s || s->id() == id;
769
- });
767
+ // Declared outside the lock so destructors run after sessions_mutex_ is released.
768
+ // cppcheck-suppress variableScope
769
+ std::vector<std::shared_ptr<http_session>> dropped;
770
+ {
771
+ const std::scoped_lock inner_lock(self->sessions_mutex_);
772
+ for (auto* map :
773
+ { &self->busy_sessions_, &self->idle_sessions_, &self->pending_sessions_ }) {
774
+ auto map_it = map->find(type);
775
+ if (map_it == map->end()) {
776
+ continue;
777
+ }
778
+ auto& list = map_it->second;
779
+ for (auto it = list.begin(); it != list.end();) {
780
+ if (!*it || (*it)->id() == id) {
781
+ if (*it) {
782
+ dropped.push_back(std::move(*it));
783
+ }
784
+ it = list.erase(it);
785
+ } else {
786
+ ++it;
787
+ }
788
+ }
789
+ }
790
+ }
770
791
  });
771
792
  return session;
772
793
  }
773
794
 
774
795
  #ifdef COUCHBASE_CXX_CLIENT_COLUMNAR
775
796
  template<typename Request, typename Handler>
776
- void defer_command(Request request,
777
- Handler&& handler,
778
- const couchbase::core::cluster_credentials& credentials)
797
+ void defer_command(Request request, Handler&& handler)
779
798
  {
780
799
  {
781
800
  std::scoped_lock bootstrap_error_lock(last_bootstrap_error_mutex_);
@@ -794,74 +813,44 @@ private:
794
813
  app_telemetry_meter_,
795
814
  options_.default_timeout_for(request.type),
796
815
  dispatch_timeout_);
816
+ using response_type = typename Request::response_type;
797
817
  cmd->start([self = shared_from_this(), cmd, handler = std::forward<Handler>(handler)](
798
- error_union err, io::http_response&& msg) mutable {
799
- using command_type = typename decltype(cmd)::element_type;
800
- using encoded_response_type = typename command_type::encoded_response_type;
801
- using error_context_type = typename command_type::error_context_type;
802
- encoded_response_type resp{ std::move(msg) };
803
- error_context_type ctx{};
804
- if (!std::holds_alternative<std::monostate>(err)) {
805
- if (std::holds_alternative<impl::bootstrap_error>(err)) {
806
- auto bootstrap_error = std::get<impl::bootstrap_error>(err);
807
- if (bootstrap_error.ec == errc::common::unambiguous_timeout) {
808
- CB_LOG_DEBUG("Timeout caused by bootstrap error. code={}, ec_message={}, message={}.",
809
- bootstrap_error.ec.value(),
810
- bootstrap_error.ec.message(),
811
- bootstrap_error.error_message);
812
- }
813
- ctx.ec = bootstrap_error.ec;
814
- } else {
815
- ctx.ec = std::get<std::error_code>(err);
816
- }
817
- }
818
- ctx.client_context_id = cmd->client_context_id_;
819
- ctx.method = cmd->encoded.method;
820
- ctx.path = cmd->encoded.path;
821
- ctx.http_status = resp.status_code;
822
- ctx.http_body = resp.body.data();
823
- if (cmd->session_) {
824
- ctx.last_dispatched_from = cmd->session_->local_address();
825
- ctx.last_dispatched_to = cmd->session_->remote_address();
826
- ctx.hostname = cmd->session_->http_context().hostname;
827
- ctx.port = cmd->session_->http_context().port;
828
- }
829
- handler(cmd->request.make_response(std::move(ctx), std::move(resp)));
818
+ response_type&& resp) mutable {
819
+ handler(std::move(resp));
830
820
  self->check_in(cmd->request.type, cmd->session_);
831
821
  });
832
822
  CB_LOG_DEBUG(R"(Adding HTTP request to deferred queue: {}, client_context_id="{}")",
833
823
  cmd->request.type,
834
824
  cmd->client_context_id_);
835
- add_to_deferred_queue(
836
- [self = shared_from_this(), cmd, request, credentials](error_union err) mutable {
837
- if (!std::holds_alternative<std::monostate>(err)) {
838
- using response_type = typename Request::encoded_response_type;
839
- return cmd->invoke_handler(err, response_type{});
840
- }
825
+ add_to_deferred_queue([self = shared_from_this(), cmd, request](error_union err) mutable {
826
+ if (!std::holds_alternative<std::monostate>(err)) {
827
+ using response_type = typename Request::encoded_response_type;
828
+ return cmd->invoke_handler(err, response_type{});
829
+ }
841
830
 
842
- // don't do anything if the command wasn't dispatched or has already timed out
843
- auto now = std::chrono::steady_clock::now();
844
- if (cmd->dispatch_deadline_expiry() < now || cmd->deadline_expiry() < now) {
845
- return;
846
- }
847
- std::string preferred_node;
848
- if constexpr (http_traits::supports_sticky_node_v<Request>) {
849
- if (request.send_to_node) {
850
- preferred_node = *request.send_to_node;
851
- }
852
- }
853
- auto [error, session] = self->check_out(request.type, credentials, preferred_node);
854
- if (error) {
855
- using response_type = typename Request::encoded_response_type;
856
- return cmd->invoke_handler(error, response_type{});
857
- }
858
- cmd->set_command_session(session);
859
- if (!session->is_connected()) {
860
- self->connect_then_send(session, cmd, preferred_node);
861
- } else {
862
- cmd->send_to();
831
+ // don't do anything if the command wasn't dispatched or has already timed out
832
+ auto now = std::chrono::steady_clock::now();
833
+ if (cmd->dispatch_deadline_expiry() < now || cmd->deadline_expiry() < now) {
834
+ return;
835
+ }
836
+ std::string preferred_node;
837
+ if constexpr (http_traits::supports_sticky_node_v<Request>) {
838
+ if (request.send_to_node) {
839
+ preferred_node = *request.send_to_node;
863
840
  }
864
- });
841
+ }
842
+ auto [error, session] = self->check_out(request.type, preferred_node);
843
+ if (error) {
844
+ using response_type = typename Request::encoded_response_type;
845
+ return cmd->invoke_handler(error, response_type{});
846
+ }
847
+ cmd->set_command_session(session);
848
+ if (!session->is_connected()) {
849
+ self->connect_then_send(session, cmd, preferred_node);
850
+ } else {
851
+ cmd->send_to();
852
+ }
853
+ });
865
854
  }
866
855
 
867
856
  void drain_deferred_queue(error_union err)
@@ -881,34 +870,29 @@ private:
881
870
  }
882
871
  #endif
883
872
 
884
- auto next_node(service_type type) -> std::tuple<std::string, std::uint16_t, std::string>
873
+ auto next_node(service_type type) -> node_details
885
874
  {
886
875
  std::scoped_lock lock(config_mutex_);
887
876
  auto candidates = config_.nodes.size();
888
877
  while (candidates > 0) {
889
878
  --candidates;
890
- std::scoped_lock index_lock(next_index_mutex_);
879
+ const std::scoped_lock index_lock(next_index_mutex_);
891
880
  const auto& node = config_.nodes[next_index_];
892
881
  next_index_ = (next_index_ + 1) % config_.nodes.size();
893
- std::uint16_t port = node.port_or(options_.network, type, options_.enable_tls, 0);
882
+ const std::uint16_t port = node.port_or(options_.network, type, options_.enable_tls, 0);
894
883
  if (port != 0) {
895
884
  return {
896
- node.hostname_for(options_.network),
897
- port,
898
- node.node_uuid,
885
+ node.hostname_for(options_.network), port, node.node_uuid, node.hostname,
886
+ node.port_or(type, options_.enable_tls, 0),
899
887
  };
900
888
  }
901
889
  }
902
- return {
903
- "",
904
- static_cast<std::uint16_t>(0U),
905
- "",
906
- };
890
+ return {};
907
891
  }
908
892
 
909
893
  auto split_host_port(const std::string& address) -> std::pair<std::string, std::uint16_t>
910
894
  {
911
- auto last_colon = address.find_last_of(':');
895
+ const auto last_colon = address.find_last_of(':');
912
896
  if (last_colon == std::string::npos || address.size() - 1 == last_colon) {
913
897
  return { "", static_cast<std::uint16_t>(0U) };
914
898
  }
@@ -917,30 +901,22 @@ private:
917
901
  return { hostname, port };
918
902
  }
919
903
 
920
- auto lookup_node(service_type type, const std::string& preferred_node)
921
- -> std::tuple<std::string, std::uint16_t, std::string>
904
+ auto lookup_node(service_type type, const std::string& preferred_node_address) -> node_details
922
905
  {
923
- std::scoped_lock lock(config_mutex_);
924
- auto [hostname, port] = split_host_port(preferred_node);
906
+ const std::scoped_lock lock(config_mutex_);
907
+ auto [hostname, port] = split_host_port(preferred_node_address);
925
908
  for (const auto& node : config_.nodes) {
926
909
  if (node.hostname_for(options_.network) == hostname &&
927
910
  node.port_or(options_.network, type, options_.enable_tls, 0) == port) {
928
911
  return {
929
- hostname,
930
- port,
931
- node.node_uuid,
912
+ hostname, port, node.node_uuid, node.hostname, node.port_or(type, options_.enable_tls, 0),
932
913
  };
933
914
  }
934
915
  }
935
- return {
936
- "",
937
- static_cast<std::uint16_t>(0U),
938
- "",
939
- };
916
+ return {};
940
917
  }
941
918
 
942
- auto pick_random_node(service_type type, const std::string& undesired_node)
943
- -> std::tuple<std::string, std::uint16_t, std::string>
919
+ auto pick_random_node(service_type type, const std::string& undesired_node) -> node_details
944
920
  {
945
921
  std::vector<topology::configuration::node> candidate_nodes{};
946
922
  {
@@ -956,11 +932,7 @@ private:
956
932
 
957
933
  if (candidate_nodes.empty()) {
958
934
  // Could not find any other nodes
959
- return {
960
- "",
961
- static_cast<std::uint16_t>(0U),
962
- "",
963
- };
935
+ return {};
964
936
  }
965
937
 
966
938
  std::vector<topology::configuration::node> selected{};
@@ -974,12 +946,15 @@ private:
974
946
  first_selected.hostname_for(options_.network),
975
947
  first_selected.port_or(options_.network, type, options_.enable_tls, 0),
976
948
  first_selected.node_uuid,
949
+ first_selected.hostname,
950
+ first_selected.port_or(type, options_.enable_tls, 0),
977
951
  };
978
952
  }
979
953
 
980
954
  std::string client_id_;
981
955
  asio::io_context& ctx_;
982
- asio::ssl::context& tls_;
956
+ tls_context_provider& tls_;
957
+ origin& origin_;
983
958
  std::shared_ptr<tracing::tracer_wrapper> tracer_{ nullptr };
984
959
  std::shared_ptr<metrics::meter_wrapper> meter_{ nullptr };
985
960
  std::shared_ptr<core::app_telemetry_meter> app_telemetry_meter_{ nullptr };