couchbase 3.7.0 → 3.8.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 (286) 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 -93
  6. data/ext/cache/mozilla-ca-bundle.sha256 +1 -1
  7. data/ext/couchbase/CMakeLists.txt +24 -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/free_form_http_request.hxx +0 -2
  33. data/ext/couchbase/core/http_component.cxx +12 -48
  34. data/ext/couchbase/core/impl/analytics.cxx +3 -2
  35. data/ext/couchbase/core/impl/analytics.hxx +2 -1
  36. data/ext/couchbase/core/impl/analytics_index_manager.cxx +249 -137
  37. data/ext/couchbase/core/impl/binary_collection.cxx +134 -58
  38. data/ext/couchbase/core/impl/bucket_manager.cxx +87 -35
  39. data/ext/couchbase/core/impl/collection.cxx +560 -245
  40. data/ext/couchbase/core/impl/collection_manager.cxx +89 -49
  41. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +4 -4
  42. data/ext/couchbase/core/impl/error.cxx +20 -13
  43. data/ext/couchbase/core/impl/error.hxx +15 -10
  44. data/ext/couchbase/core/impl/get_all_replicas.hxx +1 -1
  45. data/ext/couchbase/core/impl/get_any_replica.hxx +2 -1
  46. data/ext/couchbase/core/impl/get_replica.hxx +2 -0
  47. data/ext/couchbase/core/impl/lookup_in_replica.hxx +1 -1
  48. data/ext/couchbase/core/impl/observability_recorder.cxx +161 -0
  49. data/ext/couchbase/core/impl/observability_recorder.hxx +77 -0
  50. data/ext/couchbase/core/impl/observe_seqno.hxx +2 -0
  51. data/ext/couchbase/core/impl/public_bucket.cxx +31 -7
  52. data/ext/couchbase/core/impl/public_cluster.cxx +107 -19
  53. data/ext/couchbase/core/impl/query.cxx +6 -3
  54. data/ext/couchbase/core/impl/query.hxx +3 -1
  55. data/ext/couchbase/core/impl/query_index_manager.cxx +267 -102
  56. data/ext/couchbase/core/impl/scope.cxx +53 -11
  57. data/ext/couchbase/core/impl/search.cxx +8 -4
  58. data/ext/couchbase/core/impl/search.hxx +6 -2
  59. data/ext/couchbase/core/impl/search_index_manager.cxx +131 -41
  60. data/ext/couchbase/core/impl/with_cancellation.hxx +75 -0
  61. data/ext/couchbase/core/io/config_tracker.cxx +9 -9
  62. data/ext/couchbase/core/io/config_tracker.hxx +2 -1
  63. data/ext/couchbase/core/io/http_command.hxx +98 -49
  64. data/ext/couchbase/core/io/http_context.hxx +2 -0
  65. data/ext/couchbase/core/io/http_session.cxx +23 -10
  66. data/ext/couchbase/core/io/http_session.hxx +17 -9
  67. data/ext/couchbase/core/io/http_session_manager.hxx +163 -228
  68. data/ext/couchbase/core/io/http_traits.hxx +0 -7
  69. data/ext/couchbase/core/io/mcbp_command.hxx +123 -44
  70. data/ext/couchbase/core/io/mcbp_session.cxx +251 -26
  71. data/ext/couchbase/core/io/mcbp_session.hxx +9 -1
  72. data/ext/couchbase/core/io/mcbp_traits.hxx +0 -8
  73. data/ext/couchbase/core/io/streams.cxx +3 -3
  74. data/ext/couchbase/core/io/streams.hxx +3 -2
  75. data/ext/couchbase/core/meta/features.hxx +15 -0
  76. data/ext/couchbase/core/meta/version.cxx +13 -0
  77. data/ext/couchbase/core/meta/version.hxx +3 -0
  78. data/ext/couchbase/core/metrics/constants.hxx +23 -0
  79. data/ext/couchbase/core/metrics/logging_meter.cxx +5 -5
  80. data/ext/couchbase/core/metrics/meter_wrapper.cxx +65 -63
  81. data/ext/couchbase/core/metrics/meter_wrapper.hxx +12 -10
  82. data/ext/couchbase/core/operations/document_analytics.hxx +0 -5
  83. data/ext/couchbase/core/operations/document_append.hxx +0 -4
  84. data/ext/couchbase/core/operations/document_decrement.hxx +0 -5
  85. data/ext/couchbase/core/operations/document_exists.hxx +0 -7
  86. data/ext/couchbase/core/operations/document_get.hxx +0 -7
  87. data/ext/couchbase/core/operations/document_get_all_replicas.hxx +77 -27
  88. data/ext/couchbase/core/operations/document_get_and_lock.hxx +0 -9
  89. data/ext/couchbase/core/operations/document_get_and_touch.hxx +0 -9
  90. data/ext/couchbase/core/operations/document_get_any_replica.hxx +83 -2
  91. data/ext/couchbase/core/operations/document_get_projected.hxx +0 -9
  92. data/ext/couchbase/core/operations/document_increment.hxx +0 -5
  93. data/ext/couchbase/core/operations/document_insert.hxx +0 -4
  94. data/ext/couchbase/core/operations/document_lookup_in.hxx +0 -9
  95. data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +46 -4
  96. data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +121 -43
  97. data/ext/couchbase/core/operations/document_mutate_in.hxx +0 -5
  98. data/ext/couchbase/core/operations/document_prepend.hxx +0 -4
  99. data/ext/couchbase/core/operations/document_query.hxx +0 -4
  100. data/ext/couchbase/core/operations/document_remove.hxx +0 -4
  101. data/ext/couchbase/core/operations/document_replace.hxx +0 -4
  102. data/ext/couchbase/core/operations/document_search.hxx +0 -7
  103. data/ext/couchbase/core/operations/document_touch.hxx +0 -7
  104. data/ext/couchbase/core/operations/document_unlock.hxx +0 -6
  105. data/ext/couchbase/core/operations/document_upsert.hxx +0 -4
  106. data/ext/couchbase/core/operations/document_view.cxx +2 -0
  107. data/ext/couchbase/core/operations/document_view.hxx +10 -13
  108. data/ext/couchbase/core/operations/http_noop.hxx +2 -0
  109. data/ext/couchbase/core/operations/management/analytics_dataset_create.hxx +2 -0
  110. data/ext/couchbase/core/operations/management/analytics_dataset_drop.hxx +2 -0
  111. data/ext/couchbase/core/operations/management/analytics_dataset_get_all.hxx +2 -0
  112. data/ext/couchbase/core/operations/management/analytics_dataverse_create.hxx +2 -0
  113. data/ext/couchbase/core/operations/management/analytics_dataverse_drop.hxx +2 -0
  114. data/ext/couchbase/core/operations/management/analytics_get_pending_mutations.hxx +2 -0
  115. data/ext/couchbase/core/operations/management/analytics_index_create.hxx +2 -0
  116. data/ext/couchbase/core/operations/management/analytics_index_drop.hxx +2 -0
  117. data/ext/couchbase/core/operations/management/analytics_index_get_all.hxx +2 -0
  118. data/ext/couchbase/core/operations/management/analytics_link_connect.hxx +2 -0
  119. data/ext/couchbase/core/operations/management/analytics_link_create.hxx +2 -0
  120. data/ext/couchbase/core/operations/management/analytics_link_disconnect.hxx +2 -0
  121. data/ext/couchbase/core/operations/management/analytics_link_drop.hxx +2 -0
  122. data/ext/couchbase/core/operations/management/analytics_link_get_all.hxx +2 -0
  123. data/ext/couchbase/core/operations/management/analytics_link_replace.hxx +2 -0
  124. data/ext/couchbase/core/operations/management/bucket_create.hxx +2 -0
  125. data/ext/couchbase/core/operations/management/bucket_describe.hxx +2 -0
  126. data/ext/couchbase/core/operations/management/bucket_drop.hxx +2 -0
  127. data/ext/couchbase/core/operations/management/bucket_flush.hxx +2 -0
  128. data/ext/couchbase/core/operations/management/bucket_get.hxx +2 -0
  129. data/ext/couchbase/core/operations/management/bucket_get_all.hxx +2 -0
  130. data/ext/couchbase/core/operations/management/bucket_update.hxx +2 -0
  131. data/ext/couchbase/core/operations/management/change_password.hxx +2 -0
  132. data/ext/couchbase/core/operations/management/cluster_describe.hxx +2 -0
  133. data/ext/couchbase/core/operations/management/cluster_developer_preview_enable.hxx +2 -0
  134. data/ext/couchbase/core/operations/management/collection_create.hxx +2 -0
  135. data/ext/couchbase/core/operations/management/collection_drop.hxx +2 -0
  136. data/ext/couchbase/core/operations/management/collection_update.hxx +2 -0
  137. data/ext/couchbase/core/operations/management/collections_manifest_get.hxx +2 -0
  138. data/ext/couchbase/core/operations/management/error_utils.cxx +4 -1
  139. data/ext/couchbase/core/operations/management/eventing_deploy_function.hxx +2 -0
  140. data/ext/couchbase/core/operations/management/eventing_drop_function.hxx +2 -0
  141. data/ext/couchbase/core/operations/management/eventing_get_all_functions.hxx +2 -0
  142. data/ext/couchbase/core/operations/management/eventing_get_function.hxx +2 -0
  143. data/ext/couchbase/core/operations/management/eventing_get_status.hxx +2 -0
  144. data/ext/couchbase/core/operations/management/eventing_pause_function.hxx +2 -0
  145. data/ext/couchbase/core/operations/management/eventing_resume_function.hxx +2 -0
  146. data/ext/couchbase/core/operations/management/eventing_undeploy_function.hxx +2 -0
  147. data/ext/couchbase/core/operations/management/eventing_upsert_function.hxx +2 -0
  148. data/ext/couchbase/core/operations/management/freeform.hxx +2 -0
  149. data/ext/couchbase/core/operations/management/group_drop.hxx +2 -0
  150. data/ext/couchbase/core/operations/management/group_get.hxx +2 -0
  151. data/ext/couchbase/core/operations/management/group_get_all.hxx +2 -0
  152. data/ext/couchbase/core/operations/management/group_upsert.hxx +2 -0
  153. data/ext/couchbase/core/operations/management/query_index_build.hxx +2 -0
  154. data/ext/couchbase/core/operations/management/query_index_build_deferred.hxx +68 -30
  155. data/ext/couchbase/core/operations/management/query_index_create.hxx +2 -0
  156. data/ext/couchbase/core/operations/management/query_index_drop.hxx +2 -0
  157. data/ext/couchbase/core/operations/management/query_index_get_all.hxx +4 -3
  158. data/ext/couchbase/core/operations/management/query_index_get_all_deferred.hxx +2 -1
  159. data/ext/couchbase/core/operations/management/role_get_all.hxx +2 -0
  160. data/ext/couchbase/core/operations/management/scope_create.hxx +2 -0
  161. data/ext/couchbase/core/operations/management/scope_drop.hxx +2 -0
  162. data/ext/couchbase/core/operations/management/scope_get_all.hxx +2 -0
  163. data/ext/couchbase/core/operations/management/search_get_stats.hxx +2 -0
  164. data/ext/couchbase/core/operations/management/search_index_analyze_document.hxx +2 -0
  165. data/ext/couchbase/core/operations/management/search_index_control_ingest.hxx +2 -0
  166. data/ext/couchbase/core/operations/management/search_index_control_plan_freeze.hxx +2 -0
  167. data/ext/couchbase/core/operations/management/search_index_control_query.hxx +2 -0
  168. data/ext/couchbase/core/operations/management/search_index_drop.hxx +2 -0
  169. data/ext/couchbase/core/operations/management/search_index_get.hxx +2 -0
  170. data/ext/couchbase/core/operations/management/search_index_get_all.hxx +2 -0
  171. data/ext/couchbase/core/operations/management/search_index_get_documents_count.hxx +2 -0
  172. data/ext/couchbase/core/operations/management/search_index_get_stats.hxx +2 -0
  173. data/ext/couchbase/core/operations/management/search_index_upsert.hxx +2 -0
  174. data/ext/couchbase/core/operations/management/user_drop.hxx +2 -0
  175. data/ext/couchbase/core/operations/management/user_get.hxx +2 -0
  176. data/ext/couchbase/core/operations/management/user_get_all.hxx +2 -0
  177. data/ext/couchbase/core/operations/management/user_upsert.hxx +2 -0
  178. data/ext/couchbase/core/operations/management/view_index_drop.hxx +2 -0
  179. data/ext/couchbase/core/operations/management/view_index_get.hxx +2 -0
  180. data/ext/couchbase/core/operations/management/view_index_get_all.hxx +2 -0
  181. data/ext/couchbase/core/operations/management/view_index_upsert.hxx +2 -0
  182. data/ext/couchbase/core/operations/operation_traits.hxx +6 -0
  183. data/ext/couchbase/core/operations.hxx +0 -1
  184. data/ext/couchbase/core/operations_fwd.hxx +8 -0
  185. data/ext/couchbase/core/origin.cxx +67 -12
  186. data/ext/couchbase/core/origin.hxx +13 -8
  187. data/ext/couchbase/core/orphan_reporter.cxx +164 -0
  188. data/ext/couchbase/core/orphan_reporter.hxx +65 -0
  189. data/ext/couchbase/core/sasl/CMakeLists.txt +1 -0
  190. data/ext/couchbase/core/sasl/client.cc +6 -0
  191. data/ext/couchbase/core/sasl/mechanism.cc +2 -1
  192. data/ext/couchbase/core/sasl/mechanism.h +2 -1
  193. data/ext/couchbase/core/sasl/oauthbearer/oauthbearer.cc +41 -0
  194. data/ext/couchbase/core/sasl/oauthbearer/oauthbearer.h +47 -0
  195. data/ext/couchbase/core/tls_context_provider.cxx +44 -0
  196. data/ext/couchbase/core/tls_context_provider.hxx +44 -0
  197. data/ext/couchbase/core/tracing/attribute_helpers.hxx +45 -0
  198. data/ext/couchbase/core/tracing/constants.hxx +148 -68
  199. data/ext/couchbase/core/tracing/threshold_logging_options.hxx +0 -3
  200. data/ext/couchbase/core/tracing/threshold_logging_tracer.cxx +122 -170
  201. data/ext/couchbase/core/tracing/tracer_wrapper.cxx +17 -24
  202. data/ext/couchbase/core/tracing/tracer_wrapper.hxx +8 -10
  203. data/ext/couchbase/core/tracing/wrapper_sdk_tracer.cxx +114 -0
  204. data/ext/couchbase/core/tracing/wrapper_sdk_tracer.hxx +85 -0
  205. data/ext/couchbase/core/transactions/attempt_context_impl.cxx +16 -14
  206. data/ext/couchbase/core/transactions/attempt_context_impl.hxx +4 -4
  207. data/ext/couchbase/core/transactions/transactions.cxx +1 -1
  208. data/ext/couchbase/core/transactions/transactions_cleanup.cxx +1 -2
  209. data/ext/couchbase/core/utils/byteswap.hxx +12 -0
  210. data/ext/couchbase/core/utils/concurrent_fixed_priority_queue.hxx +102 -0
  211. data/ext/couchbase/core/utils/connection_string.cxx +2 -0
  212. data/ext/couchbase/couchbase/certificate_authenticator.hxx +1 -0
  213. data/ext/couchbase/couchbase/cluster.hxx +47 -0
  214. data/ext/couchbase/couchbase/cluster_options.hxx +16 -0
  215. data/ext/couchbase/couchbase/collection.hxx +60 -15
  216. data/ext/couchbase/couchbase/error_codes.hxx +48 -48
  217. data/ext/couchbase/couchbase/jwt_authenticator.hxx +52 -0
  218. data/ext/couchbase/couchbase/metrics/meter.hxx +2 -1
  219. data/ext/couchbase/couchbase/metrics/otel_meter.hxx +75 -80
  220. data/ext/couchbase/couchbase/network_options.hxx +19 -0
  221. data/ext/couchbase/couchbase/password_authenticator.hxx +1 -0
  222. data/ext/couchbase/couchbase/tracing/otel_tracer.hxx +15 -17
  223. data/ext/couchbase/couchbase/tracing/request_span.hxx +2 -2
  224. data/ext/couchbase.cxx +4 -0
  225. data/ext/extconf.rb +1 -0
  226. data/ext/rcb_analytics.cxx +157 -47
  227. data/ext/rcb_backend.cxx +118 -71
  228. data/ext/rcb_buckets.cxx +39 -16
  229. data/ext/rcb_collections.cxx +36 -12
  230. data/ext/rcb_crud.cxx +587 -294
  231. data/ext/rcb_hdr_histogram.cxx +219 -0
  232. data/ext/rcb_hdr_histogram.hxx +28 -0
  233. data/ext/rcb_multi.cxx +142 -59
  234. data/ext/rcb_observability.cxx +132 -0
  235. data/ext/rcb_observability.hxx +49 -0
  236. data/ext/rcb_query.cxx +77 -27
  237. data/ext/rcb_search.cxx +92 -31
  238. data/ext/rcb_users.cxx +69 -26
  239. data/ext/rcb_utils.cxx +91 -0
  240. data/ext/rcb_utils.hxx +141 -168
  241. data/ext/rcb_views.cxx +36 -12
  242. data/lib/active_support/cache/couchbase_store.rb +6 -6
  243. data/lib/couchbase/authenticator.rb +14 -0
  244. data/lib/couchbase/binary_collection.rb +37 -22
  245. data/lib/couchbase/bucket.rb +46 -31
  246. data/lib/couchbase/cluster.rb +146 -61
  247. data/lib/couchbase/collection.rb +257 -186
  248. data/lib/couchbase/datastructures/couchbase_list.rb +81 -50
  249. data/lib/couchbase/datastructures/couchbase_map.rb +86 -50
  250. data/lib/couchbase/datastructures/couchbase_queue.rb +64 -38
  251. data/lib/couchbase/datastructures/couchbase_set.rb +57 -41
  252. data/lib/couchbase/deprecations.rb +1 -1
  253. data/lib/couchbase/diagnostics.rb +8 -8
  254. data/lib/couchbase/errors.rb +6 -0
  255. data/lib/couchbase/management/analytics_index_manager.rb +90 -59
  256. data/lib/couchbase/management/bucket_manager.rb +73 -45
  257. data/lib/couchbase/management/collection_manager.rb +86 -43
  258. data/lib/couchbase/management/collection_query_index_manager.rb +56 -33
  259. data/lib/couchbase/management/query_index_manager.rb +88 -36
  260. data/lib/couchbase/management/scope_search_index_manager.rb +119 -52
  261. data/lib/couchbase/management/search_index_manager.rb +401 -178
  262. data/lib/couchbase/management/user_manager.rb +343 -174
  263. data/lib/couchbase/management/view_index_manager.rb +166 -73
  264. data/lib/couchbase/metrics/logging_meter.rb +108 -0
  265. data/lib/couchbase/metrics/logging_value_recorder.rb +50 -0
  266. data/lib/couchbase/metrics/meter.rb +27 -0
  267. data/lib/couchbase/metrics/noop_meter.rb +30 -0
  268. data/lib/couchbase/metrics/noop_value_recorder.rb +27 -0
  269. data/lib/couchbase/metrics/value_recorder.rb +25 -0
  270. data/lib/couchbase/options.rb +69 -3
  271. data/lib/couchbase/protostellar/cluster.rb +3 -0
  272. data/lib/couchbase/scope.rb +62 -48
  273. data/lib/couchbase/search_options.rb +18 -18
  274. data/lib/couchbase/tracing/noop_span.rb +29 -0
  275. data/lib/couchbase/tracing/noop_tracer.rb +29 -0
  276. data/lib/couchbase/tracing/request_span.rb +34 -0
  277. data/lib/couchbase/tracing/request_tracer.rb +28 -0
  278. data/lib/couchbase/tracing/threshold_logging_span.rb +112 -0
  279. data/lib/couchbase/tracing/threshold_logging_tracer.rb +231 -0
  280. data/lib/couchbase/utils/hdr_histogram.rb +55 -0
  281. data/lib/couchbase/utils/observability.rb +257 -0
  282. data/lib/couchbase/utils/observability_constants.rb +200 -0
  283. data/lib/couchbase/utils/stdlib_logger_adapter.rb +1 -3
  284. data/lib/couchbase/version.rb +1 -1
  285. data/lib/couchbase.rb +2 -2
  286. metadata +58 -6
@@ -0,0 +1,219 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2025-Present 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 "rcb_hdr_histogram.hxx"
19
+ #include "rcb_exceptions.hxx"
20
+
21
+ #include <hdr/hdr_histogram.h>
22
+ #include <ruby.h>
23
+
24
+ #include <mutex>
25
+ #include <shared_mutex>
26
+ #include <vector>
27
+
28
+ namespace couchbase::ruby
29
+ {
30
+ namespace
31
+ {
32
+ struct cb_hdr_histogram_data {
33
+ hdr_histogram* histogram{ nullptr };
34
+ std::shared_mutex mutex{};
35
+ };
36
+
37
+ void
38
+ cb_hdr_histogram_close(cb_hdr_histogram_data* hdr_histogram_data)
39
+ {
40
+ if (hdr_histogram_data->histogram != nullptr) {
41
+ hdr_close(hdr_histogram_data->histogram);
42
+ hdr_histogram_data->histogram = nullptr;
43
+ }
44
+ }
45
+
46
+ void
47
+ cb_HdrHistogramC_mark(void* /* ptr */)
48
+ {
49
+ /* no embedded ruby objects -- no mark */
50
+ }
51
+
52
+ void
53
+ cb_HdrHistogramC_free(void* ptr)
54
+ {
55
+ auto* hdr_histogram_data = static_cast<cb_hdr_histogram_data*>(ptr);
56
+ cb_hdr_histogram_close(hdr_histogram_data);
57
+ hdr_histogram_data->~cb_hdr_histogram_data();
58
+ ruby_xfree(hdr_histogram_data);
59
+ }
60
+
61
+ std::size_t
62
+ cb_HdrHistogramC_memsize(const void* ptr)
63
+ {
64
+ const auto* hdr_histogram_data = static_cast<const cb_hdr_histogram_data*>(ptr);
65
+ return sizeof(*hdr_histogram_data);
66
+ }
67
+
68
+ const rb_data_type_t cb_hdr_histogram_type{
69
+ "Couchbase/Utils/HdrHistogramC",
70
+ {
71
+ cb_HdrHistogramC_mark,
72
+ cb_HdrHistogramC_free,
73
+ cb_HdrHistogramC_memsize,
74
+ // only one reserved field when GC.compact implemented
75
+ #ifdef T_MOVED
76
+ nullptr,
77
+ #endif
78
+ {},
79
+ },
80
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
81
+ nullptr,
82
+ nullptr,
83
+ RUBY_TYPED_FREE_IMMEDIATELY,
84
+ #endif
85
+ };
86
+
87
+ VALUE
88
+ cb_HdrHistogramC_allocate(VALUE klass)
89
+ {
90
+ cb_hdr_histogram_data* hdr_histogram = nullptr;
91
+ VALUE obj =
92
+ TypedData_Make_Struct(klass, cb_hdr_histogram_data, &cb_hdr_histogram_type, hdr_histogram);
93
+ new (hdr_histogram) cb_hdr_histogram_data();
94
+ return obj;
95
+ }
96
+
97
+ VALUE
98
+ cb_HdrHistogramC_initialize(VALUE self,
99
+ VALUE lowest_discernible_value,
100
+ VALUE highest_trackable_value,
101
+ VALUE significant_figures)
102
+ {
103
+ Check_Type(lowest_discernible_value, T_FIXNUM);
104
+ Check_Type(highest_trackable_value, T_FIXNUM);
105
+ Check_Type(significant_figures, T_FIXNUM);
106
+
107
+ std::int64_t lowest = NUM2LL(lowest_discernible_value);
108
+ std::int64_t highest = NUM2LL(highest_trackable_value);
109
+ int sigfigs = NUM2INT(significant_figures);
110
+
111
+ cb_hdr_histogram_data* hdr_histogram;
112
+ TypedData_Get_Struct(self, cb_hdr_histogram_data, &cb_hdr_histogram_type, hdr_histogram);
113
+
114
+ int res;
115
+ {
116
+ const std::unique_lock lock(hdr_histogram->mutex);
117
+ res = hdr_init(lowest, highest, sigfigs, &hdr_histogram->histogram);
118
+ }
119
+ if (res != 0) {
120
+ rb_raise(exc_couchbase_error(), "failed to initialize HDR histogram");
121
+ return self;
122
+ }
123
+
124
+ return self;
125
+ }
126
+
127
+ VALUE
128
+ cb_HdrHistogramC_close(VALUE self)
129
+ {
130
+ cb_hdr_histogram_data* hdr_histogram;
131
+ TypedData_Get_Struct(self, cb_hdr_histogram_data, &cb_hdr_histogram_type, hdr_histogram);
132
+ {
133
+ const std::unique_lock lock(hdr_histogram->mutex);
134
+ cb_hdr_histogram_close(hdr_histogram);
135
+ }
136
+ return Qnil;
137
+ }
138
+
139
+ VALUE
140
+ cb_HdrHistogramC_record_value(VALUE self, VALUE value)
141
+ {
142
+ Check_Type(value, T_FIXNUM);
143
+
144
+ std::int64_t val = NUM2LL(value);
145
+
146
+ cb_hdr_histogram_data* hdr_histogram;
147
+ TypedData_Get_Struct(self, cb_hdr_histogram_data, &cb_hdr_histogram_type, hdr_histogram);
148
+
149
+ {
150
+ const std::shared_lock lock(hdr_histogram->mutex);
151
+ hdr_record_value_atomic(hdr_histogram->histogram, val);
152
+ }
153
+ return Qnil;
154
+ }
155
+
156
+ VALUE
157
+ cb_HdrHistogramC_get_percentiles_and_reset(VALUE self, VALUE percentiles)
158
+ {
159
+ Check_Type(percentiles, T_ARRAY);
160
+
161
+ cb_hdr_histogram_data* hdr_histogram;
162
+ TypedData_Get_Struct(self, cb_hdr_histogram_data, &cb_hdr_histogram_type, hdr_histogram);
163
+
164
+ std::vector<std::int64_t> percentile_values{};
165
+ std::int64_t total_count;
166
+ {
167
+ const std::unique_lock lock(hdr_histogram->mutex);
168
+ total_count = hdr_histogram->histogram->total_count;
169
+ for (std::size_t i = 0; i < static_cast<std::size_t>(RARRAY_LEN(percentiles)); ++i) {
170
+ VALUE entry = rb_ary_entry(percentiles, static_cast<long>(i));
171
+ Check_Type(entry, T_FLOAT);
172
+ double perc = NUM2DBL(entry);
173
+ std::int64_t value_at_perc = hdr_value_at_percentile(hdr_histogram->histogram, perc);
174
+ percentile_values.push_back(value_at_perc);
175
+ }
176
+ hdr_reset(hdr_histogram->histogram);
177
+ }
178
+
179
+ static const VALUE sym_total_count = rb_id2sym(rb_intern("total_count"));
180
+ static const VALUE sym_percentiles = rb_id2sym(rb_intern("percentiles"));
181
+ VALUE res = rb_hash_new();
182
+ rb_hash_aset(res, sym_total_count, LL2NUM(total_count));
183
+ VALUE perc_array = rb_ary_new_capa(static_cast<long>(percentile_values.size()));
184
+ for (const auto& val : percentile_values) {
185
+ rb_ary_push(perc_array, LL2NUM(val));
186
+ }
187
+ rb_hash_aset(res, sym_percentiles, perc_array);
188
+ return res;
189
+ }
190
+
191
+ VALUE
192
+ cb_HdrHistogramC_bin_count(VALUE self)
193
+ {
194
+ cb_hdr_histogram_data* hdr_histogram;
195
+ TypedData_Get_Struct(self, cb_hdr_histogram_data, &cb_hdr_histogram_type, hdr_histogram);
196
+
197
+ std::int32_t bin_count;
198
+ {
199
+ const std::unique_lock lock(hdr_histogram->mutex);
200
+ bin_count = hdr_histogram->histogram->bucket_count;
201
+ }
202
+ return LONG2NUM(bin_count);
203
+ }
204
+ } // namespace
205
+
206
+ void
207
+ init_hdr_histogram(VALUE mCouchbase)
208
+ {
209
+ VALUE mUtils = rb_define_module_under(mCouchbase, "Utils");
210
+ VALUE cHdrHistogramC = rb_define_class_under(mUtils, "HdrHistogramC", rb_cObject);
211
+ rb_define_alloc_func(cHdrHistogramC, cb_HdrHistogramC_allocate);
212
+ rb_define_method(cHdrHistogramC, "initialize", cb_HdrHistogramC_initialize, 3);
213
+ rb_define_method(cHdrHistogramC, "close", cb_HdrHistogramC_close, 0);
214
+ rb_define_method(cHdrHistogramC, "record_value", cb_HdrHistogramC_record_value, 1);
215
+ rb_define_method(cHdrHistogramC, "bin_count", cb_HdrHistogramC_bin_count, 0);
216
+ rb_define_method(
217
+ cHdrHistogramC, "get_percentiles_and_reset", cb_HdrHistogramC_get_percentiles_and_reset, 1);
218
+ }
219
+ } // namespace couchbase::ruby
@@ -0,0 +1,28 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2025-Present 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
+ #ifndef COUCHBASE_RUBY_RCB_HDR_HISTOGRAM_HXX
19
+ #define COUCHBASE_RUBY_RCB_HDR_HISTOGRAM_HXX
20
+
21
+ #include <ruby/internal/value.h>
22
+
23
+ namespace couchbase::ruby
24
+ {
25
+ void
26
+ init_hdr_histogram(VALUE mCouchbase);
27
+ } // namespace couchbase::ruby
28
+ #endif // COUCHBASE_RUBY_RCB_HDR_HISTOGRAM_HXX
data/ext/rcb_multi.cxx CHANGED
@@ -17,7 +17,20 @@
17
17
 
18
18
  #include <core/cluster.hxx>
19
19
  #include <core/document_id.hxx>
20
+
21
+ // TODO(DC): Compilation fails unless all operations that support legacy durability are included
22
+ // This is probably something we should address in the C++ core. Including them all for now.
23
+ #include <core/operations/document_append.hxx>
24
+ #include <core/operations/document_decrement.hxx>
20
25
  #include <core/operations/document_get.hxx>
26
+ #include <core/operations/document_increment.hxx>
27
+ #include <core/operations/document_insert.hxx>
28
+ #include <core/operations/document_mutate_in.hxx>
29
+ #include <core/operations/document_prepend.hxx>
30
+ #include <core/operations/document_remove.hxx>
31
+ #include <core/operations/document_replace.hxx>
32
+ #include <core/operations/document_upsert.hxx>
33
+
21
34
  #include <couchbase/cluster.hxx>
22
35
  #include <couchbase/upsert_options.hxx>
23
36
 
@@ -32,7 +45,6 @@ namespace couchbase::ruby
32
45
  {
33
46
  namespace
34
47
  {
35
-
36
48
  void
37
49
  cb_extract_array_of_ids(std::vector<core::document_id>& ids, VALUE arg)
38
50
  {
@@ -82,21 +94,29 @@ cb_extract_array_of_ids(std::vector<core::document_id>& ids, VALUE arg)
82
94
 
83
95
  void
84
96
  cb_extract_array_of_id_content(
85
- std::vector<std::pair<std::string, couchbase::codec::encoded_value>>& id_content,
86
- VALUE arg)
97
+ std::vector<std::pair<core::document_id, couchbase::codec::encoded_value>>& id_content,
98
+ VALUE bucket_name,
99
+ VALUE scope_name,
100
+ VALUE collection_name,
101
+ VALUE tuples)
87
102
  {
88
- if (TYPE(arg) != T_ARRAY) {
103
+ cb_check_type(bucket_name, T_STRING);
104
+ cb_check_type(scope_name, T_STRING);
105
+ cb_check_type(collection_name, T_STRING);
106
+
107
+ if (TYPE(tuples) != T_ARRAY) {
89
108
  throw ruby_exception(
90
109
  rb_eArgError,
91
- rb_sprintf("Type of ID/content tuples must be an Array, but given %+" PRIsVALUE, arg));
110
+ rb_sprintf("Type of ID/content tuples must be an Array, but given %+" PRIsVALUE, tuples));
92
111
  }
93
- auto num_of_tuples = static_cast<std::size_t>(RARRAY_LEN(arg));
112
+
113
+ auto num_of_tuples = static_cast<std::size_t>(RARRAY_LEN(tuples));
94
114
  if (num_of_tuples < 1) {
95
115
  throw ruby_exception(rb_eArgError, "Array of ID/content tuples must not be empty");
96
116
  }
97
117
  id_content.reserve(num_of_tuples);
98
118
  for (std::size_t i = 0; i < num_of_tuples; ++i) {
99
- VALUE entry = rb_ary_entry(arg, static_cast<long>(i));
119
+ VALUE entry = rb_ary_entry(tuples, static_cast<long>(i));
100
120
  if (TYPE(entry) != T_ARRAY || RARRAY_LEN(entry) != 3) {
101
121
  throw ruby_exception(rb_eArgError,
102
122
  rb_sprintf("ID/content tuple must be represented as an Array[id, "
@@ -118,27 +138,40 @@ cb_extract_array_of_id_content(
118
138
  throw ruby_exception(rb_eArgError,
119
139
  rb_sprintf("Flags must be an Integer, but given %+" PRIsVALUE, flags));
120
140
  }
121
- id_content.emplace_back(
122
- cb_string_new(id),
123
- couchbase::codec::encoded_value{ cb_binary_new(content), FIX2UINT(flags) });
141
+ id_content.emplace_back(core::document_id{ cb_string_new(bucket_name),
142
+ cb_string_new(scope_name),
143
+ cb_string_new(collection_name),
144
+ cb_string_new(id) },
145
+ couchbase::codec::encoded_value{
146
+ cb_binary_new(content),
147
+ FIX2UINT(flags),
148
+ });
124
149
  }
125
150
  }
126
151
 
127
152
  void
128
- cb_extract_array_of_id_cas(std::vector<std::pair<std::string, couchbase::cas>>& id_cas, VALUE arg)
153
+ cb_extract_array_of_id_cas(std::vector<std::pair<core::document_id, couchbase::cas>>& id_cas,
154
+ VALUE bucket_name,
155
+ VALUE scope_name,
156
+ VALUE collection_name,
157
+ VALUE tuples)
129
158
  {
130
- if (TYPE(arg) != T_ARRAY) {
159
+ cb_check_type(bucket_name, T_STRING);
160
+ cb_check_type(scope_name, T_STRING);
161
+ cb_check_type(collection_name, T_STRING);
162
+
163
+ if (TYPE(tuples) != T_ARRAY) {
131
164
  throw ruby_exception(
132
165
  rb_eArgError,
133
- rb_sprintf("Type of ID/CAS tuples must be an Array, but given %+" PRIsVALUE, arg));
166
+ rb_sprintf("Type of ID/CAS tuples must be an Array, but given %+" PRIsVALUE, tuples));
134
167
  }
135
- auto num_of_tuples = static_cast<std::size_t>(RARRAY_LEN(arg));
168
+ auto num_of_tuples = static_cast<std::size_t>(RARRAY_LEN(tuples));
136
169
  if (num_of_tuples < 1) {
137
170
  rb_raise(rb_eArgError, "Array of ID/CAS tuples must not be empty");
138
171
  }
139
172
  id_cas.reserve(num_of_tuples);
140
173
  for (std::size_t i = 0; i < num_of_tuples; ++i) {
141
- VALUE entry = rb_ary_entry(arg, static_cast<long>(i));
174
+ VALUE entry = rb_ary_entry(tuples, static_cast<long>(i));
142
175
  if (TYPE(entry) != T_ARRAY || RARRAY_LEN(entry) != 2) {
143
176
  throw ruby_exception(
144
177
  rb_eArgError,
@@ -156,7 +189,11 @@ cb_extract_array_of_id_cas(std::vector<std::pair<std::string, couchbase::cas>>&
156
189
  cb_extract_cas(cas_val, cas);
157
190
  }
158
191
 
159
- id_cas.emplace_back(cb_string_new(id), cas_val);
192
+ id_cas.emplace_back(core::document_id{ cb_string_new(bucket_name),
193
+ cb_string_new(scope_name),
194
+ cb_string_new(collection_name),
195
+ cb_string_new(id) },
196
+ cas_val);
160
197
  }
161
198
  }
162
199
 
@@ -222,45 +259,72 @@ cb_Backend_document_upsert_multi(VALUE self,
222
259
  VALUE id_content,
223
260
  VALUE options)
224
261
  {
225
- auto cluster = cb_backend_to_public_api_cluster(self);
226
-
227
- try {
228
- couchbase::upsert_options opts;
229
- set_timeout(opts, options);
230
- set_expiry(opts, options);
231
- set_durability(opts, options);
232
- set_preserve_expiry(opts, options);
262
+ auto cluster = cb_backend_to_core_api_cluster(self);
233
263
 
234
- auto c = cluster.bucket(cb_string_new(bucket))
235
- .scope(cb_string_new(scope))
236
- .collection(cb_string_new(collection));
264
+ Check_Type(bucket, T_STRING);
265
+ Check_Type(scope, T_STRING);
266
+ Check_Type(collection, T_STRING);
267
+ if (!NIL_P(options)) {
268
+ Check_Type(options, T_HASH);
269
+ }
237
270
 
238
- std::vector<std::pair<std::string, couchbase::codec::encoded_value>> tuples{};
239
- cb_extract_array_of_id_content(tuples, id_content);
271
+ try {
272
+ std::vector<std::pair<core::document_id, couchbase::codec::encoded_value>> tuples{};
273
+ cb_extract_array_of_id_content(tuples, bucket, scope, collection, id_content);
240
274
 
241
275
  auto num_of_tuples = tuples.size();
242
- std::vector<
243
- std::pair<std::string, std::future<std::pair<couchbase::error, couchbase::mutation_result>>>>
244
- futures;
276
+ std::vector<std::pair<std::string, std::future<core::operations::upsert_response>>> futures;
245
277
  futures.reserve(num_of_tuples);
246
278
 
247
279
  for (auto& [id, content] : tuples) {
248
- futures.emplace_back(id, c.upsert(id, std::move(content), opts));
280
+ core::operations::upsert_request req{
281
+ id,
282
+ std::move(content.data),
283
+ };
284
+ req.flags = content.flags;
285
+ cb_extract_timeout(req, options);
286
+ cb_extract_expiry(req, options);
287
+ cb_extract_durability_level(req, options);
288
+ cb_extract_preserve_expiry(req, options);
289
+
290
+ std::promise<core::operations::upsert_response> promise;
291
+ futures.emplace_back(id.key(), promise.get_future());
292
+
293
+ if (const auto legacy_durability = extract_legacy_durability_constraints(options);
294
+ legacy_durability.has_value()) {
295
+ cluster.execute(
296
+ core::operations::upsert_request_with_legacy_durability{
297
+ std::move(req),
298
+ legacy_durability.value().first,
299
+ legacy_durability.value().second,
300
+ },
301
+ [promise = std::move(promise)](auto&& resp) mutable {
302
+ promise.set_value(std::forward<decltype(resp)>(resp));
303
+ });
304
+ } else {
305
+ cluster.execute(std::move(req), [promise = std::move(promise)](auto&& resp) mutable {
306
+ promise.set_value(std::forward<decltype(resp)>(resp));
307
+ });
308
+ }
249
309
  }
250
310
 
251
311
  VALUE res = rb_ary_new_capa(static_cast<long>(num_of_tuples));
252
312
  for (auto& [id, f] : futures) {
253
- auto [err, resp] = f.get();
254
- VALUE entry = to_mutation_result_value(resp);
255
- if (err.ec()) {
313
+ auto resp = f.get();
314
+ VALUE entry;
315
+ if (resp.ctx.ec()) {
316
+ entry = rb_hash_new();
256
317
  static const auto sym_error = rb_id2sym(rb_intern("error"));
257
- rb_hash_aset(entry, sym_error, cb_map_error(err, "unable (multi)upsert"));
318
+ rb_hash_aset(entry, sym_error, cb_map_error(resp.ctx, "unable (multi)upsert"));
319
+ } else {
320
+ entry = cb_create_mutation_result(resp);
258
321
  }
259
322
  static const auto sym_id = rb_id2sym(rb_intern("id"));
260
323
  rb_hash_aset(entry, sym_id, cb_str_new(id));
261
324
  rb_ary_push(res, entry);
262
325
  }
263
326
  return res;
327
+
264
328
  } catch (const std::system_error& se) {
265
329
  rb_exc_raise(cb_map_error_code(
266
330
  se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
@@ -278,50 +342,69 @@ cb_Backend_document_remove_multi(VALUE self,
278
342
  VALUE id_cas,
279
343
  VALUE options)
280
344
  {
281
- auto cluster = cb_backend_to_public_api_cluster(self);
345
+ auto cluster = cb_backend_to_core_api_cluster(self);
282
346
 
347
+ Check_Type(bucket, T_STRING);
348
+ Check_Type(scope, T_STRING);
349
+ Check_Type(collection, T_STRING);
283
350
  if (!NIL_P(options)) {
284
351
  Check_Type(options, T_HASH);
285
352
  }
286
353
 
287
354
  try {
288
- couchbase::remove_options opts;
289
- set_timeout(opts, options);
290
- set_durability(opts, options);
291
-
292
- std::vector<std::pair<std::string, couchbase::cas>> tuples{};
293
- cb_extract_array_of_id_cas(tuples, id_cas);
294
-
295
- auto c = cluster.bucket(cb_string_new(bucket))
296
- .scope(cb_string_new(scope))
297
- .collection(cb_string_new(collection));
355
+ std::vector<std::pair<core::document_id, couchbase::cas>> tuples{};
356
+ cb_extract_array_of_id_cas(tuples, bucket, scope, collection, id_cas);
298
357
 
299
358
  auto num_of_tuples = tuples.size();
300
- std::vector<
301
- std::pair<std::string, std::future<std::pair<couchbase::error, couchbase::mutation_result>>>>
302
- futures;
359
+ std::vector<std::pair<std::string, std::future<core::operations::remove_response>>> futures;
303
360
  futures.reserve(num_of_tuples);
304
361
 
305
362
  for (const auto& [id, cas] : tuples) {
306
- opts.cas(cas);
307
- futures.emplace_back(id, c.remove(id, opts));
363
+ core::operations::remove_request req{
364
+ id,
365
+ };
366
+ cb_extract_timeout(req, options);
367
+ cb_extract_durability_level(req, options);
368
+ req.cas = cas;
369
+
370
+ std::promise<core::operations::remove_response> promise;
371
+ futures.emplace_back(id.key(), promise.get_future());
372
+
373
+ if (const auto legacy_durability = extract_legacy_durability_constraints(options);
374
+ legacy_durability.has_value()) {
375
+ cluster.execute(
376
+ core::operations::remove_request_with_legacy_durability{
377
+ std::move(req),
378
+ legacy_durability.value().first,
379
+ legacy_durability.value().second,
380
+ },
381
+ [promise = std::move(promise)](auto&& resp) mutable {
382
+ promise.set_value(std::forward<decltype(resp)>(resp));
383
+ });
384
+ } else {
385
+ cluster.execute(std::move(req), [promise = std::move(promise)](auto&& resp) mutable {
386
+ promise.set_value(std::forward<decltype(resp)>(resp));
387
+ });
388
+ }
308
389
  }
309
390
 
310
391
  VALUE res = rb_ary_new_capa(static_cast<long>(num_of_tuples));
311
392
  for (auto& [id, f] : futures) {
312
- auto [ctx, resp] = f.get();
313
- VALUE entry = to_mutation_result_value(resp);
314
- if (ctx.ec()) {
393
+ auto resp = f.get();
394
+ VALUE entry;
395
+ if (resp.ctx.ec()) {
396
+ entry = rb_hash_new();
315
397
  static const auto sym_error = rb_id2sym(rb_intern("error"));
316
- rb_hash_aset(entry, sym_error, cb_map_error(ctx, "unable (multi)remove"));
398
+ rb_hash_aset(entry, sym_error, cb_map_error(resp.ctx, "unable (multi)remove"));
399
+ } else {
400
+ entry = cb_create_mutation_result(resp);
317
401
  }
318
402
  static const auto sym_id = rb_id2sym(rb_intern("id"));
319
403
  rb_hash_aset(entry, sym_id, cb_str_new(id));
320
-
321
404
  rb_ary_push(res, entry);
322
405
  }
323
-
324
406
  return res;
407
+
325
408
  } catch (const std::system_error& se) {
326
409
  rb_exc_raise(cb_map_error_code(
327
410
  se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
@@ -0,0 +1,132 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2025-Present 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 "rcb_observability.hxx"
19
+
20
+ #include "rcb_backend.hxx"
21
+ #include "rcb_utils.hxx"
22
+
23
+ #include <core/cluster.hxx>
24
+ #include <core/cluster_label_listener.hxx>
25
+ #include <core/tracing/wrapper_sdk_tracer.hxx>
26
+
27
+ #include <ruby.h>
28
+
29
+ #include <chrono>
30
+ #include <memory>
31
+
32
+ namespace couchbase::ruby
33
+ {
34
+ namespace
35
+ {
36
+ VALUE
37
+ core_span_to_rb_hash(std::shared_ptr<couchbase::core::tracing::wrapper_sdk_span> core_span)
38
+ {
39
+ VALUE res = rb_hash_new();
40
+
41
+ static VALUE sym_name = rb_id2sym(rb_intern("name"));
42
+ static VALUE sym_attributes = rb_id2sym(rb_intern("attributes"));
43
+ static VALUE sym_start_timestamp = rb_id2sym(rb_intern("start_timestamp"));
44
+ static VALUE sym_end_timestamp = rb_id2sym(rb_intern("end_timestamp"));
45
+ static VALUE sym_children = rb_id2sym(rb_intern("children"));
46
+
47
+ VALUE attributes = rb_hash_new();
48
+
49
+ for (const auto& [key, value] : core_span->uint_tags()) {
50
+ rb_hash_aset(attributes, cb_str_new(key), ULL2NUM(value));
51
+ }
52
+
53
+ for (const auto& [key, value] : core_span->string_tags()) {
54
+ rb_hash_aset(attributes, cb_str_new(key), cb_str_new(value));
55
+ }
56
+
57
+ rb_hash_aset(res, sym_name, cb_str_new(core_span->name()));
58
+ rb_hash_aset(res, sym_attributes, attributes);
59
+ rb_hash_aset(res,
60
+ sym_start_timestamp,
61
+ LL2NUM(std::chrono::duration_cast<std::chrono::microseconds>(
62
+ core_span->start_time().time_since_epoch())
63
+ .count()));
64
+ rb_hash_aset(res,
65
+ sym_end_timestamp,
66
+ LL2NUM(std::chrono::duration_cast<std::chrono::microseconds>(
67
+ core_span->end_time().time_since_epoch())
68
+ .count()));
69
+
70
+ VALUE children = rb_ary_new_capa(static_cast<long>(core_span->children().size()));
71
+ for (const auto& child : core_span->children()) {
72
+ rb_ary_push(children, core_span_to_rb_hash(child));
73
+ }
74
+ rb_hash_aset(res, sym_children, children);
75
+
76
+ return res;
77
+ }
78
+ } // namespace
79
+
80
+ void
81
+ cb_add_core_spans(VALUE observability_handler,
82
+ std::shared_ptr<couchbase::core::tracing::wrapper_sdk_span> parent_span,
83
+ std::size_t retry_attempts)
84
+ {
85
+ const auto children = parent_span->children();
86
+ VALUE spans = rb_ary_new_capa(static_cast<long>(children.size()));
87
+
88
+ for (const auto& child : parent_span->children()) {
89
+ rb_ary_push(spans, core_span_to_rb_hash(child));
90
+ }
91
+
92
+ static ID add_backend_spans_func = rb_intern("add_spans_from_backend");
93
+ rb_funcall(observability_handler, add_backend_spans_func, 1, spans);
94
+
95
+ static ID add_retries_func = rb_intern("add_retries");
96
+ rb_funcall(observability_handler, add_retries_func, 1, ULONG2NUM(retry_attempts));
97
+ }
98
+
99
+ namespace
100
+ {
101
+ VALUE
102
+ cb_Backend_cluster_labels(VALUE self)
103
+ {
104
+ VALUE res = rb_hash_new();
105
+ {
106
+ auto cluster = cb_backend_to_core_api_cluster(self);
107
+ auto labels = cluster.cluster_label_listener()->cluster_labels();
108
+
109
+ static const auto sym_cluster_name = rb_id2sym(rb_intern("cluster_name"));
110
+ static const auto sym_cluster_uuid = rb_id2sym(rb_intern("cluster_uuid"));
111
+
112
+ if (labels.cluster_name.has_value()) {
113
+ rb_hash_aset(res, sym_cluster_name, cb_str_new(labels.cluster_name.value()));
114
+ } else {
115
+ rb_hash_aset(res, sym_cluster_name, Qnil);
116
+ }
117
+ if (labels.cluster_uuid.has_value()) {
118
+ rb_hash_aset(res, sym_cluster_uuid, cb_str_new(labels.cluster_uuid.value()));
119
+ } else {
120
+ rb_hash_aset(res, sym_cluster_uuid, Qnil);
121
+ }
122
+ }
123
+ return res;
124
+ }
125
+ } // namespace
126
+
127
+ void
128
+ init_observability(VALUE cBackend)
129
+ {
130
+ rb_define_method(cBackend, "cluster_labels", cb_Backend_cluster_labels, 0);
131
+ }
132
+ } // namespace couchbase::ruby