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
@@ -21,6 +21,8 @@
21
21
  #include "get_all_replicas.hxx"
22
22
  #include "get_any_replica.hxx"
23
23
  #include "internal_scan_result.hxx"
24
+ #include "invoke_with_node_id.hxx"
25
+ #include "observability_recorder.hxx"
24
26
  #include "observe_poll.hxx"
25
27
 
26
28
  #include "core/agent_group.hxx"
@@ -28,6 +30,7 @@
28
30
  #include "core/cluster.hxx"
29
31
  #include "core/impl/subdoc/command.hxx"
30
32
  #include "core/logger/logger.hxx"
33
+ #include "core/metrics/meter_wrapper.hxx"
31
34
  #include "core/operations/document_append.hxx"
32
35
  #include "core/operations/document_decrement.hxx"
33
36
  #include "core/operations/document_exists.hxx"
@@ -53,6 +56,8 @@
53
56
  #include "core/range_scan_orchestrator.hxx"
54
57
  #include "core/range_scan_orchestrator_options.hxx"
55
58
  #include "core/topology/configuration.hxx"
59
+ #include "core/tracing/constants.hxx"
60
+ #include "core/tracing/tracer_wrapper.hxx"
56
61
 
57
62
  #include <couchbase/binary_collection.hxx>
58
63
  #include <couchbase/cas.hxx>
@@ -92,6 +97,10 @@
92
97
 
93
98
  #include <spdlog/fmt/bundled/core.h>
94
99
 
100
+ #include <asio/error.hpp>
101
+ #include <asio/steady_timer.hpp>
102
+
103
+ #include <atomic>
95
104
  #include <chrono>
96
105
  #include <cstdint>
97
106
  #include <future>
@@ -103,8 +112,12 @@
103
112
  #include <variant>
104
113
  #include <vector>
105
114
 
115
+ #include "core/tracing/attribute_helpers.hxx"
116
+
106
117
  namespace couchbase
107
118
  {
119
+ using core::impl::invoke_with_node_id;
120
+
108
121
  class collection_impl : public std::enable_shared_from_this<collection_impl>
109
122
  {
110
123
  public:
@@ -148,47 +161,69 @@ public:
148
161
 
149
162
  void get(std::string document_key, get_options::built options, get_handler&& handler) const
150
163
  {
164
+ auto obs_rec =
165
+ create_observability_recorder(core::tracing::operation::mcbp_get, options.parent_span);
166
+
151
167
  if (!options.with_expiry && options.projections.empty()) {
152
- return core_.execute(
153
- core::operations::get_request{
154
- core::document_id{ bucket_name_, scope_name_, name_, std::move(document_key) },
155
- {},
156
- {},
157
- options.timeout,
158
- { options.retry_strategy },
159
- options.parent_span,
168
+ core::operations::get_request request{
169
+ core::document_id{
170
+ bucket_name_,
171
+ scope_name_,
172
+ name_,
173
+ std::move(document_key),
160
174
  },
161
- [crypto_manager = crypto_manager_, handler = std::move(handler)](auto resp) mutable {
162
- return handler(
163
- core::impl::make_error(std::move(resp.ctx)),
164
- get_result{
165
- resp.cas, { std::move(resp.value), resp.flags }, {}, std::move(crypto_manager) });
166
- });
167
- }
168
- return core_.execute(
169
- core::operations::get_projected_request{
170
- core::document_id{ bucket_name_, scope_name_, name_, std::move(document_key) },
171
- {},
172
175
  {},
173
- options.projections,
174
- options.with_expiry,
175
176
  {},
176
- false,
177
177
  options.timeout,
178
178
  { options.retry_strategy },
179
- options.parent_span,
179
+ obs_rec->operation_span(),
180
+ };
181
+ return core_.execute(std::move(request),
182
+ [obs_rec = std::move(obs_rec),
183
+ crypto_manager = crypto_manager_,
184
+ handler = std::move(handler)](auto resp) mutable {
185
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
186
+ invoke_with_node_id(std::move(handler),
187
+ core::impl::make_error(std::move(resp.ctx)),
188
+ get_result{ resp.cas,
189
+ { std::move(resp.value), resp.flags },
190
+ {},
191
+ std::move(crypto_manager) });
192
+ });
193
+ }
194
+ core::operations::get_projected_request request{
195
+ core::document_id{
196
+ bucket_name_,
197
+ scope_name_,
198
+ name_,
199
+ std::move(document_key),
180
200
  },
181
- [crypto_manager = crypto_manager_, handler = std::move(handler)](auto resp) mutable {
182
- std::optional<std::chrono::system_clock::time_point> expiry_time{};
183
- if (resp.expiry && resp.expiry.value() > 0) {
184
- expiry_time.emplace(std::chrono::seconds{ resp.expiry.value() });
185
- }
186
- return handler(core::impl::make_error(std::move(resp.ctx)),
187
- get_result{ resp.cas,
188
- { std::move(resp.value), resp.flags },
189
- expiry_time,
190
- std::move(crypto_manager) });
191
- });
201
+ {},
202
+ {},
203
+ options.projections,
204
+ options.with_expiry,
205
+ {},
206
+ false,
207
+ options.timeout,
208
+ { options.retry_strategy },
209
+ obs_rec->operation_span(),
210
+ };
211
+ return core_.execute(std::move(request),
212
+ [obs_rec = std::move(obs_rec),
213
+ crypto_manager = crypto_manager_,
214
+ handler = std::move(handler)](auto resp) mutable {
215
+ std::optional<std::chrono::system_clock::time_point> expiry_time{};
216
+ if (resp.expiry && resp.expiry.value() > 0) {
217
+ expiry_time.emplace(std::chrono::seconds{ resp.expiry.value() });
218
+ }
219
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
220
+ invoke_with_node_id(std::move(handler),
221
+ core::impl::make_error(std::move(resp.ctx)),
222
+ get_result{ resp.cas,
223
+ { std::move(resp.value), resp.flags },
224
+ expiry_time,
225
+ std::move(crypto_manager) });
226
+ });
192
227
  }
193
228
 
194
229
  void get_and_touch(std::string document_key,
@@ -196,22 +231,36 @@ public:
196
231
  get_and_touch_options::built options,
197
232
  get_and_touch_handler&& handler) const
198
233
  {
199
- return core_.execute(
200
- core::operations::get_and_touch_request{
201
- core::document_id{ bucket_name_, scope_name_, name_, std::move(document_key) },
202
- {},
203
- {},
204
- expiry,
205
- options.timeout,
206
- { options.retry_strategy },
207
- options.parent_span,
234
+ auto obs_rec = create_observability_recorder(core::tracing::operation::mcbp_get_and_touch,
235
+ options.parent_span);
236
+
237
+ core::operations::get_and_touch_request request{
238
+ core::document_id{
239
+ bucket_name_,
240
+ scope_name_,
241
+ name_,
242
+ std::move(document_key),
208
243
  },
209
- [crypto_manager = crypto_manager_, handler = std::move(handler)](auto resp) mutable {
210
- return handler(
211
- core::impl::make_error(std::move(resp.ctx)),
212
- get_result{
213
- resp.cas, { std::move(resp.value), resp.flags }, {}, std::move(crypto_manager) });
214
- });
244
+ {},
245
+ {},
246
+ expiry,
247
+ options.timeout,
248
+ { options.retry_strategy },
249
+ obs_rec->operation_span(),
250
+ };
251
+
252
+ return core_.execute(std::move(request),
253
+ [obs_rec = std::move(obs_rec),
254
+ crypto_manager = crypto_manager_,
255
+ handler = std::move(handler)](auto resp) mutable {
256
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
257
+ invoke_with_node_id(std::move(handler),
258
+ core::impl::make_error(std::move(resp.ctx)),
259
+ get_result{ resp.cas,
260
+ { std::move(resp.value), resp.flags },
261
+ {},
262
+ std::move(crypto_manager) });
263
+ });
215
264
  }
216
265
 
217
266
  void touch(std::string document_key,
@@ -219,18 +268,29 @@ public:
219
268
  touch_options::built options,
220
269
  touch_handler&& handler) const
221
270
  {
222
- return core_.execute(
223
- core::operations::touch_request{
224
- core::document_id{ bucket_name_, scope_name_, name_, std::move(document_key) },
225
- {},
226
- {},
227
- expiry,
228
- options.timeout,
229
- { options.retry_strategy },
230
- options.parent_span,
271
+ auto obs_rec =
272
+ create_observability_recorder(core::tracing::operation::mcbp_touch, options.parent_span);
273
+
274
+ core::operations::touch_request request{
275
+ core::document_id{
276
+ bucket_name_,
277
+ scope_name_,
278
+ name_,
279
+ std::move(document_key),
231
280
  },
232
- [handler = std::move(handler)](const auto& resp) mutable {
233
- return handler(core::impl::make_error(std::move(resp.ctx)), result{ resp.cas });
281
+ {},
282
+ {},
283
+ expiry,
284
+ options.timeout,
285
+ { options.retry_strategy },
286
+ obs_rec->operation_span(),
287
+ };
288
+ return core_.execute(
289
+ std::move(request),
290
+ [obs_rec = std::move(obs_rec), handler = std::move(handler)](const auto& resp) mutable {
291
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
292
+ invoke_with_node_id(
293
+ std::move(handler), core::impl::make_error(std::move(resp.ctx)), result{ resp.cas });
234
294
  });
235
295
  }
236
296
 
@@ -238,51 +298,82 @@ public:
238
298
  const get_any_replica_options::built& options,
239
299
  core::impl::movable_get_any_replica_handler&& handler) const
240
300
  {
241
- return core_.execute(
242
- core::operations::get_any_replica_request{
243
- core::document_id{ bucket_name_, scope_name_, name_, std::move(document_key) },
244
- options.timeout,
245
- options.read_preference,
301
+ auto obs_rec = create_observability_recorder(core::tracing::operation::mcbp_get_any_replica,
302
+ options.parent_span);
303
+
304
+ core::operations::get_any_replica_request request{
305
+ core::document_id{
306
+ bucket_name_,
307
+ scope_name_,
308
+ name_,
309
+ std::move(document_key),
246
310
  },
247
- [crypto_manager = crypto_manager_, handler = std::move(handler)](auto resp) mutable {
248
- return handler(core::impl::make_error(std::move(resp.ctx)),
249
- get_replica_result{
250
- resp.cas,
251
- resp.replica,
252
- { std::move(resp.value), resp.flags },
253
- std::move(crypto_manager),
254
- });
255
- });
311
+ options.timeout,
312
+ options.read_preference,
313
+ obs_rec->operation_span(),
314
+ };
315
+ return core_.execute(std::move(request),
316
+ [obs_rec = std::move(obs_rec),
317
+ crypto_manager = crypto_manager_,
318
+ handler = std::move(handler)](auto resp) mutable {
319
+ obs_rec->finish(resp.ctx.ec());
320
+ invoke_with_node_id(std::move(handler),
321
+ core::impl::make_error(std::move(resp.ctx)),
322
+ get_replica_result{
323
+ resp.cas,
324
+ resp.replica,
325
+ { std::move(resp.value), resp.flags },
326
+ std::move(crypto_manager),
327
+ });
328
+ });
256
329
  }
257
330
 
258
331
  void get_all_replicas(std::string document_key,
259
332
  const get_all_replicas_options::built& options,
260
333
  core::impl::movable_get_all_replicas_handler&& handler) const
261
334
  {
262
- return core_.execute(
263
- core::operations::get_all_replicas_request{
264
- core::document_id{ bucket_name_, scope_name_, name_, std::move(document_key) },
265
- options.timeout,
266
- options.read_preference,
335
+ auto obs_rec = create_observability_recorder(core::tracing::operation::mcbp_get_all_replicas,
336
+ options.parent_span);
337
+
338
+ core::operations::get_all_replicas_request request{
339
+ core::document_id{
340
+ bucket_name_,
341
+ scope_name_,
342
+ name_,
343
+ std::move(document_key),
267
344
  },
268
- [crypto_manager = crypto_manager_, handler = std::move(handler)](auto resp) mutable {
269
- get_all_replicas_result result{};
270
- for (auto& entry : resp.entries) {
271
- result.emplace_back(get_replica_result{
272
- entry.cas,
273
- entry.replica,
274
- { std::move(entry.value), entry.flags },
275
- crypto_manager,
276
- });
277
- }
278
- return handler(core::impl::make_error(std::move(resp.ctx)), std::move(result));
279
- });
345
+ options.timeout,
346
+ options.read_preference,
347
+ obs_rec->operation_span(),
348
+ };
349
+ return core_.execute(std::move(request),
350
+ [obs_rec = std::move(obs_rec),
351
+ crypto_manager = crypto_manager_,
352
+ handler = std::move(handler)](auto resp) mutable {
353
+ get_all_replicas_result result{};
354
+ for (auto& entry : resp.entries) {
355
+ get_replica_result replica_result{
356
+ entry.cas,
357
+ entry.replica,
358
+ { std::move(entry.value), entry.flags },
359
+ crypto_manager,
360
+ };
361
+ replica_result.node_id(std::move(entry.dispatched_to_node_id));
362
+ result.emplace_back(std::move(replica_result));
363
+ }
364
+ obs_rec->finish(resp.ctx.ec());
365
+ return handler(core::impl::make_error(std::move(resp.ctx)),
366
+ std::move(result));
367
+ });
280
368
  }
281
369
 
282
370
  void remove(std::string document_key,
283
371
  remove_options::built options,
284
372
  remove_handler&& handler) const
285
373
  {
374
+ auto obs_rec =
375
+ create_observability_recorder(core::tracing::operation::mcbp_remove, options.parent_span);
376
+
286
377
  auto id = core::document_id{
287
378
  bucket_name_,
288
379
  scope_name_,
@@ -290,23 +381,28 @@ public:
290
381
  std::move(document_key),
291
382
  };
292
383
  if (options.persist_to == persist_to::none && options.replicate_to == replicate_to::none) {
384
+ core::operations::remove_request request{
385
+ std::move(id),
386
+ {},
387
+ {},
388
+ options.cas,
389
+ options.durability_level,
390
+ options.timeout,
391
+ { options.retry_strategy },
392
+ obs_rec->operation_span(),
393
+ };
293
394
  return core_.execute(
294
- core::operations::remove_request{
295
- std::move(id),
296
- {},
297
- {},
298
- options.cas,
299
- options.durability_level,
300
- options.timeout,
301
- { options.retry_strategy },
302
- options.parent_span,
303
- },
304
- [handler = std::move(handler)](auto resp) mutable {
395
+ std::move(request),
396
+ [obs_rec = std::move(obs_rec), handler = std::move(handler)](auto resp) mutable {
397
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
305
398
  if (resp.ctx.ec()) {
306
- return handler(core::impl::make_error(std::move(resp.ctx)), mutation_result{});
399
+ invoke_with_node_id(
400
+ std::move(handler), core::impl::make_error(std::move(resp.ctx)), mutation_result{});
401
+ return;
307
402
  }
308
- return handler(core::impl::make_error(std::move(resp.ctx)),
309
- mutation_result{ resp.cas, std::move(resp.token) });
403
+ invoke_with_node_id(std::move(handler),
404
+ core::impl::make_error(std::move(resp.ctx)),
405
+ mutation_result{ resp.cas, std::move(resp.token) });
310
406
  });
311
407
  }
312
408
 
@@ -318,33 +414,44 @@ public:
318
414
  durability_level::none,
319
415
  options.timeout,
320
416
  { options.retry_strategy },
321
- options.parent_span,
417
+ obs_rec->operation_span(),
322
418
  };
323
- return core_.execute(std::move(request),
324
- [core = core_, id = std::move(id), options, handler = std::move(handler)](
325
- auto&& resp) mutable {
326
- if (resp.ctx.ec()) {
327
- return handler(core::impl::make_error(std::move(resp.ctx)),
328
- mutation_result{ resp.cas, std::move(resp.token) });
329
- }
330
- auto token = resp.token;
331
- core::impl::initiate_observe_poll(
332
- core,
333
- std::move(id),
334
- token,
335
- options.timeout,
336
- options.persist_to,
337
- options.replicate_to,
338
- [resp, handler = std::move(handler)](std::error_code ec) mutable {
339
- if (ec) {
340
- resp.ctx.override_ec(ec);
341
- return handler(core::impl::make_error(std::move(resp.ctx)),
342
- mutation_result{});
343
- }
344
- return handler(core::impl::make_error(std::move(resp.ctx)),
345
- mutation_result{ resp.cas, std::move(resp.token) });
346
- });
347
- });
419
+ return core_.execute(
420
+ std::move(request),
421
+ [obs_rec = std::move(obs_rec),
422
+ core = core_,
423
+ id = std::move(id),
424
+ options,
425
+ handler = std::move(handler)](auto&& resp) mutable {
426
+ if (resp.ctx.ec()) {
427
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
428
+ invoke_with_node_id(std::move(handler),
429
+ core::impl::make_error(std::move(resp.ctx)),
430
+ mutation_result{ resp.cas, std::move(resp.token) });
431
+ return;
432
+ }
433
+ auto token = resp.token;
434
+ core::impl::initiate_observe_poll(
435
+ core,
436
+ std::move(id),
437
+ token,
438
+ options.timeout,
439
+ options.persist_to,
440
+ options.replicate_to,
441
+ [obs_rec = std::move(obs_rec), resp, handler = std::move(handler)](
442
+ std::error_code ec) mutable {
443
+ obs_rec->finish(resp.ctx.retry_attempts(), ec);
444
+ if (ec) {
445
+ resp.ctx.override_ec(ec);
446
+ invoke_with_node_id(
447
+ std::move(handler), core::impl::make_error(std::move(resp.ctx)), mutation_result{});
448
+ return;
449
+ }
450
+ invoke_with_node_id(std::move(handler),
451
+ core::impl::make_error(std::move(resp.ctx)),
452
+ mutation_result{ resp.cas, std::move(resp.token) });
453
+ });
454
+ });
348
455
  }
349
456
 
350
457
  void get_and_lock(std::string document_key,
@@ -352,22 +459,35 @@ public:
352
459
  get_and_lock_options::built options,
353
460
  get_and_lock_handler&& handler) const
354
461
  {
355
- core_.execute(
356
- core::operations::get_and_lock_request{
357
- core::document_id{ bucket_name_, scope_name_, name_, std::move(document_key) },
358
- {},
359
- {},
360
- static_cast<uint32_t>(lock_duration.count()),
361
- options.timeout,
362
- { options.retry_strategy },
363
- options.parent_span,
462
+ auto obs_rec = create_observability_recorder(core::tracing::operation::mcbp_get_and_lock,
463
+ options.parent_span);
464
+
465
+ core::operations::get_and_lock_request request{
466
+ core::document_id{
467
+ bucket_name_,
468
+ scope_name_,
469
+ name_,
470
+ std::move(document_key),
364
471
  },
365
- [crypto_manager = crypto_manager_, handler = std::move(handler)](auto&& resp) mutable {
366
- return handler(
367
- core::impl::make_error(std::move(resp.ctx)),
368
- get_result{
369
- resp.cas, { std::move(resp.value), resp.flags }, {}, std::move(crypto_manager) });
370
- });
472
+ {},
473
+ {},
474
+ static_cast<uint32_t>(lock_duration.count()),
475
+ options.timeout,
476
+ { options.retry_strategy },
477
+ obs_rec->operation_span(),
478
+ };
479
+ core_.execute(std::move(request),
480
+ [obs_rec = std::move(obs_rec),
481
+ crypto_manager = crypto_manager_,
482
+ handler = std::move(handler)](auto&& resp) mutable {
483
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
484
+ invoke_with_node_id(std::move(handler),
485
+ core::impl::make_error(std::move(resp.ctx)),
486
+ get_result{ resp.cas,
487
+ { std::move(resp.value), resp.flags },
488
+ {},
489
+ std::move(crypto_manager) });
490
+ });
371
491
  }
372
492
 
373
493
  void unlock(std::string document_key,
@@ -375,17 +495,27 @@ public:
375
495
  unlock_options::built options,
376
496
  unlock_handler&& handler) const
377
497
  {
378
- core_.execute(
379
- core::operations::unlock_request{
380
- core::document_id{ bucket_name_, scope_name_, name_, std::move(document_key) },
381
- {},
382
- {},
383
- cas,
384
- options.timeout,
385
- { options.retry_strategy },
386
- options.parent_span,
498
+ auto obs_rec =
499
+ create_observability_recorder(core::tracing::operation::mcbp_unlock, options.parent_span);
500
+
501
+ core::operations::unlock_request request{
502
+ core::document_id{
503
+ bucket_name_,
504
+ scope_name_,
505
+ name_,
506
+ std::move(document_key),
387
507
  },
388
- [handler = std::move(handler)](auto&& resp) mutable {
508
+ {},
509
+ {},
510
+ cas,
511
+ options.timeout,
512
+ { options.retry_strategy },
513
+ obs_rec->operation_span(),
514
+ };
515
+ core_.execute(
516
+ std::move(request),
517
+ [obs_rec = std::move(obs_rec), handler = std::move(handler)](auto&& resp) mutable {
518
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
389
519
  return handler(core::impl::make_error(std::move(resp.ctx)));
390
520
  });
391
521
  }
@@ -394,18 +524,29 @@ public:
394
524
  exists_options::built options,
395
525
  exists_handler&& handler) const
396
526
  {
397
- core_.execute(
398
- core::operations::exists_request{
399
- core::document_id{ bucket_name_, scope_name_, name_, std::move(document_key) },
400
- {},
401
- {},
402
- options.timeout,
403
- { options.retry_strategy },
404
- options.parent_span,
527
+ auto obs_rec =
528
+ create_observability_recorder(core::tracing::operation::mcbp_exists, options.parent_span);
529
+
530
+ core::operations::exists_request request{
531
+ core::document_id{
532
+ bucket_name_,
533
+ scope_name_,
534
+ name_,
535
+ std::move(document_key),
405
536
  },
406
- [handler = std::move(handler)](auto&& resp) mutable {
407
- return handler(core::impl::make_error(std::move(resp.ctx)),
408
- exists_result{ resp.cas, resp.exists() });
537
+ {},
538
+ {},
539
+ options.timeout,
540
+ { options.retry_strategy },
541
+ obs_rec->operation_span(),
542
+ };
543
+ core_.execute(
544
+ std::move(request),
545
+ [obs_rec = std::move(obs_rec), handler = std::move(handler)](auto&& resp) mutable {
546
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
547
+ invoke_with_node_id(std::move(handler),
548
+ core::impl::make_error(std::move(resp.ctx)),
549
+ exists_result{ resp.cas, resp.exists() });
409
550
  });
410
551
  }
411
552
 
@@ -414,25 +555,33 @@ public:
414
555
  lookup_in_options::built options,
415
556
  lookup_in_handler&& handler) const
416
557
  {
417
- return core_.execute(
418
- core::operations::lookup_in_request{
419
- core::document_id{
420
- bucket_name_,
421
- scope_name_,
422
- name_,
423
- std::move(document_key),
424
- },
425
- {},
426
- {},
427
- options.access_deleted,
428
- specs,
429
- options.timeout,
430
- { options.retry_strategy },
431
- options.parent_span,
558
+ auto obs_rec =
559
+ create_observability_recorder(core::tracing::operation::mcbp_lookup_in, options.parent_span);
560
+
561
+ core::operations::lookup_in_request request{
562
+ core::document_id{
563
+ bucket_name_,
564
+ scope_name_,
565
+ name_,
566
+ std::move(document_key),
432
567
  },
433
- [handler = std::move(handler)](auto resp) mutable {
568
+ {},
569
+ {},
570
+ options.access_deleted,
571
+ specs,
572
+ options.timeout,
573
+ { options.retry_strategy },
574
+ obs_rec->operation_span(),
575
+ };
576
+ return core_.execute(
577
+ std::move(request),
578
+ [obs_rec = std::move(obs_rec), handler = std::move(handler)](auto resp) mutable {
579
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
580
+
434
581
  if (resp.ctx.ec()) {
435
- return handler(core::impl::make_error(std::move(resp.ctx)), lookup_in_result{});
582
+ invoke_with_node_id(
583
+ std::move(handler), core::impl::make_error(std::move(resp.ctx)), lookup_in_result{});
584
+ return;
436
585
  }
437
586
 
438
587
  std::vector<lookup_in_result::entry> entries{};
@@ -446,8 +595,9 @@ public:
446
595
  entry.ec,
447
596
  });
448
597
  }
449
- return handler(core::impl::make_error(std::move(resp.ctx)),
450
- lookup_in_result{ resp.cas, std::move(entries), resp.deleted });
598
+ invoke_with_node_id(std::move(handler),
599
+ core::impl::make_error(std::move(resp.ctx)),
600
+ lookup_in_result{ resp.cas, std::move(entries), resp.deleted });
451
601
  });
452
602
  }
453
603
 
@@ -456,15 +606,24 @@ public:
456
606
  const lookup_in_all_replicas_options::built& options,
457
607
  lookup_in_all_replicas_handler&& handler) const
458
608
  {
459
- return core_.execute(
460
- core::operations::lookup_in_all_replicas_request{
461
- core::document_id{ bucket_name_, scope_name_, name_, std::move(document_key) },
462
- specs,
463
- options.timeout,
464
- options.parent_span,
465
- options.read_preference,
609
+ auto obs_rec = create_observability_recorder(
610
+ core::tracing::operation::mcbp_lookup_in_all_replicas, options.parent_span);
611
+
612
+ core::operations::lookup_in_all_replicas_request request{
613
+ core::document_id{
614
+ bucket_name_,
615
+ scope_name_,
616
+ name_,
617
+ std::move(document_key),
466
618
  },
467
- [handler = std::move(handler)](auto resp) mutable {
619
+ specs,
620
+ options.timeout,
621
+ obs_rec->operation_span(),
622
+ options.read_preference,
623
+ };
624
+ return core_.execute(
625
+ std::move(request),
626
+ [obs_rec = std::move(obs_rec), handler = std::move(handler)](auto resp) mutable {
468
627
  lookup_in_all_replicas_result result{};
469
628
  for (auto& res : resp.entries) {
470
629
  std::vector<lookup_in_result::entry> entries;
@@ -478,14 +637,17 @@ public:
478
637
  field.ec,
479
638
  });
480
639
  }
481
- result.emplace_back(lookup_in_replica_result{
640
+ lookup_in_replica_result replica_result{
482
641
  res.cas,
483
642
  std::move(entries),
484
643
  res.deleted,
485
644
  res.is_replica,
486
- });
645
+ };
646
+ replica_result.node_id(std::move(res.dispatched_to_node_id));
647
+ result.emplace_back(std::move(replica_result));
487
648
  }
488
- return handler(core::impl::make_error(std::move(resp.ctx)), result);
649
+ obs_rec->finish(resp.ctx.ec());
650
+ return handler(core::impl::make_error(std::move(resp.ctx)), std::move(result));
489
651
  });
490
652
  }
491
653
 
@@ -494,15 +656,24 @@ public:
494
656
  const lookup_in_any_replica_options::built& options,
495
657
  lookup_in_any_replica_handler&& handler) const
496
658
  {
497
- return core_.execute(
498
- core::operations::lookup_in_any_replica_request{
499
- core::document_id{ bucket_name_, scope_name_, name_, std::move(document_key) },
500
- specs,
501
- options.timeout,
502
- options.parent_span,
503
- options.read_preference,
659
+ auto obs_rec = create_observability_recorder(
660
+ core::tracing::operation::mcbp_lookup_in_any_replica, options.parent_span);
661
+
662
+ core::operations::lookup_in_any_replica_request request{
663
+ core::document_id{
664
+ bucket_name_,
665
+ scope_name_,
666
+ name_,
667
+ std::move(document_key),
504
668
  },
505
- [handler = std::move(handler)](auto resp) mutable {
669
+ specs,
670
+ options.timeout,
671
+ obs_rec->operation_span(),
672
+ options.read_preference,
673
+ };
674
+ return core_.execute(
675
+ std::move(request),
676
+ [obs_rec = std::move(obs_rec), handler = std::move(handler)](auto resp) mutable {
506
677
  std::vector<lookup_in_result::entry> entries;
507
678
  entries.reserve(resp.fields.size());
508
679
  for (auto& field : resp.fields) {
@@ -514,8 +685,9 @@ public:
514
685
  field.ec,
515
686
  });
516
687
  }
517
- entries.reserve(resp.fields.size());
518
- return handler(
688
+ obs_rec->finish(resp.ctx.ec());
689
+ invoke_with_node_id(
690
+ std::move(handler),
519
691
  core::impl::make_error(std::move(resp.ctx)),
520
692
  lookup_in_replica_result{ resp.cas, std::move(entries), resp.deleted, resp.is_replica });
521
693
  });
@@ -526,6 +698,9 @@ public:
526
698
  mutate_in_options::built options,
527
699
  mutate_in_handler&& handler) const
528
700
  {
701
+ auto obs_rec = create_observability_recorder(
702
+ core::tracing::operation::mcbp_mutate_in, options.parent_span, options.durability_level);
703
+
529
704
  auto id = core::document_id{
530
705
  bucket_name_,
531
706
  scope_name_,
@@ -533,27 +708,31 @@ public:
533
708
  std::move(document_key),
534
709
  };
535
710
  if (options.persist_to == persist_to::none && options.replicate_to == replicate_to::none) {
711
+ core::operations::mutate_in_request request{
712
+ std::move(id),
713
+ {},
714
+ {},
715
+ options.cas,
716
+ options.access_deleted,
717
+ options.create_as_deleted,
718
+ false,
719
+ options.expiry,
720
+ options.store_semantics,
721
+ specs,
722
+ options.durability_level,
723
+ options.timeout,
724
+ { options.retry_strategy },
725
+ options.preserve_expiry,
726
+ obs_rec->operation_span(),
727
+ };
536
728
  return core_.execute(
537
- core::operations::mutate_in_request{
538
- std::move(id),
539
- {},
540
- {},
541
- options.cas,
542
- options.access_deleted,
543
- options.create_as_deleted,
544
- false,
545
- options.expiry,
546
- options.store_semantics,
547
- specs,
548
- options.durability_level,
549
- options.timeout,
550
- { options.retry_strategy },
551
- options.preserve_expiry,
552
- options.parent_span,
553
- },
554
- [handler = std::move(handler)](auto resp) mutable {
729
+ std::move(request),
730
+ [obs_rec = std::move(obs_rec), handler = std::move(handler)](auto resp) mutable {
731
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
555
732
  if (resp.ctx.ec()) {
556
- return handler(core::impl::make_error(std::move(resp.ctx)), mutate_in_result{});
733
+ invoke_with_node_id(
734
+ std::move(handler), core::impl::make_error(std::move(resp.ctx)), mutate_in_result{});
735
+ return;
557
736
  }
558
737
  std::vector<mutate_in_result::entry> entries{};
559
738
  entries.reserve(resp.fields.size());
@@ -564,7 +743,8 @@ public:
564
743
  entry.original_index,
565
744
  });
566
745
  }
567
- return handler(
746
+ invoke_with_node_id(
747
+ std::move(handler),
568
748
  core::impl::make_error(std::move(resp.ctx)),
569
749
  mutate_in_result{ resp.cas, std::move(resp.token), std::move(entries), resp.deleted });
570
750
  });
@@ -585,51 +765,68 @@ public:
585
765
  options.timeout,
586
766
  { options.retry_strategy },
587
767
  options.preserve_expiry,
588
- options.parent_span,
768
+ obs_rec->operation_span(),
589
769
  };
590
- return core_.execute(
591
- std::move(request),
592
- [core = core_, id = std::move(id), options, handler = std::move(handler)](
593
- auto&& resp) mutable {
594
- if (resp.ctx.ec()) {
595
- return handler(core::impl::make_error(std::move(resp.ctx)), mutate_in_result{});
596
- }
770
+ return core_.execute(std::move(request),
771
+ [obs_rec = std::move(obs_rec),
772
+ core = core_,
773
+ id = std::move(id),
774
+ options,
775
+ handler = std::move(handler)](auto&& resp) mutable {
776
+ if (resp.ctx.ec()) {
777
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
778
+ invoke_with_node_id(std::move(handler),
779
+ core::impl::make_error(std::move(resp.ctx)),
780
+ mutate_in_result{});
781
+ return;
782
+ }
597
783
 
598
- auto token = resp.token;
599
- core::impl::initiate_observe_poll(
600
- core,
601
- std::move(id),
602
- token,
603
- options.timeout,
604
- options.persist_to,
605
- options.replicate_to,
606
- [resp, handler = std::move(handler)](std::error_code ec) mutable {
607
- if (ec) {
608
- resp.ctx.override_ec(ec);
609
- return handler(core::impl::make_error(std::move(resp.ctx)), mutate_in_result{});
610
- }
611
- std::vector<mutate_in_result::entry> entries{};
612
- entries.reserve(resp.fields.size());
613
- for (auto& entry : resp.fields) {
614
- entries.emplace_back(mutate_in_result::entry{
615
- std::move(entry.path),
616
- std::move(entry.value),
617
- entry.original_index,
618
- });
619
- }
620
- return handler(core::impl::make_error(std::move(resp.ctx)),
621
- mutate_in_result{
622
- resp.cas, std::move(resp.token), std::move(entries), resp.deleted });
623
- });
624
- });
784
+ auto token = resp.token;
785
+ core::impl::initiate_observe_poll(
786
+ core,
787
+ std::move(id),
788
+ token,
789
+ options.timeout,
790
+ options.persist_to,
791
+ options.replicate_to,
792
+ [obs_rec = std::move(obs_rec), resp, handler = std::move(handler)](
793
+ std::error_code ec) mutable {
794
+ obs_rec->finish(resp.ctx.retry_attempts(), ec);
795
+ if (ec) {
796
+ resp.ctx.override_ec(ec);
797
+ invoke_with_node_id(std::move(handler),
798
+ core::impl::make_error(std::move(resp.ctx)),
799
+ mutate_in_result{});
800
+ return;
801
+ }
802
+ std::vector<mutate_in_result::entry> entries{};
803
+ entries.reserve(resp.fields.size());
804
+ for (auto& entry : resp.fields) {
805
+ entries.emplace_back(mutate_in_result::entry{
806
+ std::move(entry.path),
807
+ std::move(entry.value),
808
+ entry.original_index,
809
+ });
810
+ }
811
+ invoke_with_node_id(std::move(handler),
812
+ core::impl::make_error(std::move(resp.ctx)),
813
+ mutate_in_result{ resp.cas,
814
+ std::move(resp.token),
815
+ std::move(entries),
816
+ resp.deleted });
817
+ });
818
+ });
625
819
  }
626
820
 
627
821
  void upsert(std::string document_key,
628
- codec::encoded_value encoded,
822
+ std::variant<codec::encoded_value, std::function<codec::encoded_value()>> value,
629
823
  upsert_options::built options,
630
824
  upsert_handler&& handler) const
631
825
  {
632
- auto value = std::move(encoded);
826
+ auto obs_rec = create_observability_recorder(
827
+ core::tracing::operation::mcbp_upsert, options.parent_span, options.durability_level);
828
+
829
+ auto [data, flags] = get_encoded_value(std::move(value), obs_rec);
633
830
  auto id = core::document_id{
634
831
  bucket_name_,
635
832
  scope_name_,
@@ -637,45 +834,55 @@ public:
637
834
  std::move(document_key),
638
835
  };
639
836
  if (options.persist_to == persist_to::none && options.replicate_to == replicate_to::none) {
837
+ core::operations::upsert_request request{
838
+ std::move(id),
839
+ std::move(data),
840
+ {},
841
+ {},
842
+ flags,
843
+ options.expiry,
844
+ options.durability_level,
845
+ options.timeout,
846
+ { options.retry_strategy },
847
+ options.preserve_expiry,
848
+ obs_rec->operation_span(),
849
+ };
640
850
  return core_.execute(
641
- core::operations::upsert_request{
642
- std::move(id),
643
- std::move(value.data),
644
- {},
645
- {},
646
- value.flags,
647
- options.expiry,
648
- options.durability_level,
649
- options.timeout,
650
- { options.retry_strategy },
651
- options.preserve_expiry,
652
- options.parent_span,
653
- },
654
- [handler = std::move(handler)](auto resp) mutable {
655
- return handler(core::impl::make_error(std::move(resp.ctx)),
656
- mutation_result{ resp.cas, std::move(resp.token) });
851
+ std::move(request),
852
+ [obs_rec = std::move(obs_rec), handler = std::move(handler)](auto resp) mutable {
853
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
854
+ invoke_with_node_id(std::move(handler),
855
+ core::impl::make_error(std::move(resp.ctx)),
856
+ mutation_result{ resp.cas, std::move(resp.token) });
657
857
  });
658
858
  }
659
859
 
660
860
  core::operations::upsert_request request{
661
861
  id,
662
- std::move(value.data),
862
+ std::move(data),
663
863
  {},
664
864
  {},
665
- value.flags,
865
+ flags,
666
866
  options.expiry,
667
867
  durability_level::none,
668
868
  options.timeout,
669
869
  { options.retry_strategy },
670
870
  options.preserve_expiry,
671
- options.parent_span,
871
+ obs_rec->operation_span(),
672
872
  };
673
873
  return core_.execute(
674
874
  std::move(request),
675
- [core = core_, id = std::move(id), options, handler = std::move(handler)](auto resp) mutable {
875
+ [obs_rec = std::move(obs_rec),
876
+ core = core_,
877
+ id = std::move(id),
878
+ options,
879
+ handler = std::move(handler)](auto resp) mutable {
676
880
  if (resp.ctx.ec()) {
677
- return handler(core::impl::make_error(std::move(resp.ctx)),
678
- mutation_result{ resp.cas, std::move(resp.token) });
881
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
882
+ invoke_with_node_id(std::move(handler),
883
+ core::impl::make_error(std::move(resp.ctx)),
884
+ mutation_result{ resp.cas, std::move(resp.token) });
885
+ return;
679
886
  }
680
887
 
681
888
  auto token = resp.token;
@@ -686,23 +893,31 @@ public:
686
893
  options.timeout,
687
894
  options.persist_to,
688
895
  options.replicate_to,
689
- [resp, handler = std::move(handler)](std::error_code ec) mutable {
896
+ [obs_rec = std::move(obs_rec), resp, handler = std::move(handler)](
897
+ std::error_code ec) mutable {
898
+ obs_rec->finish(resp.ctx.retry_attempts(), ec);
690
899
  if (ec) {
691
900
  resp.ctx.override_ec(ec);
692
- return handler(core::impl::make_error(std::move(resp.ctx)), mutation_result{});
901
+ invoke_with_node_id(
902
+ std::move(handler), core::impl::make_error(std::move(resp.ctx)), mutation_result{});
903
+ return;
693
904
  }
694
- return handler(core::impl::make_error(std::move(resp.ctx)),
695
- mutation_result{ resp.cas, std::move(resp.token) });
905
+ invoke_with_node_id(std::move(handler),
906
+ core::impl::make_error(std::move(resp.ctx)),
907
+ mutation_result{ resp.cas, std::move(resp.token) });
696
908
  });
697
909
  });
698
910
  }
699
911
 
700
912
  void insert(std::string document_key,
701
- codec::encoded_value encoded,
913
+ std::variant<codec::encoded_value, std::function<codec::encoded_value()>> value,
702
914
  insert_options::built options,
703
915
  insert_handler&& handler) const
704
916
  {
705
- auto value = std::move(encoded);
917
+ auto obs_rec = create_observability_recorder(
918
+ core::tracing::operation::mcbp_insert, options.parent_span, options.durability_level);
919
+
920
+ auto [data, flags] = get_encoded_value(std::move(value), obs_rec);
706
921
  auto id = core::document_id{
707
922
  bucket_name_,
708
923
  scope_name_,
@@ -710,46 +925,58 @@ public:
710
925
  std::move(document_key),
711
926
  };
712
927
  if (options.persist_to == persist_to::none && options.replicate_to == replicate_to::none) {
928
+ core::operations::insert_request request{
929
+ std::move(id),
930
+ std::move(data),
931
+ {},
932
+ {},
933
+ flags,
934
+ options.expiry,
935
+ options.durability_level,
936
+ options.timeout,
937
+ { options.retry_strategy },
938
+ obs_rec->operation_span(),
939
+ };
713
940
  return core_.execute(
714
- core::operations::insert_request{
715
- std::move(id),
716
- std::move(value.data),
717
- {},
718
- {},
719
- value.flags,
720
- options.expiry,
721
- options.durability_level,
722
- options.timeout,
723
- { options.retry_strategy },
724
- options.parent_span,
725
- },
726
- [handler = std::move(handler)](auto&& resp) mutable {
941
+ std::move(request),
942
+ [obs_rec = std::move(obs_rec), handler = std::move(handler)](auto&& resp) mutable {
943
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
727
944
  if (resp.ctx.ec()) {
728
- return handler(core::impl::make_error(std::move(resp.ctx)), mutation_result{});
945
+ invoke_with_node_id(
946
+ std::move(handler), core::impl::make_error(std::move(resp.ctx)), mutation_result{});
947
+ return;
729
948
  }
730
- return handler(core::impl::make_error(std::move(resp.ctx)),
731
- mutation_result{ resp.cas, std::move(resp.token) });
949
+ invoke_with_node_id(std::move(handler),
950
+ core::impl::make_error(std::move(resp.ctx)),
951
+ mutation_result{ resp.cas, std::move(resp.token) });
732
952
  });
733
953
  }
734
954
 
735
955
  core::operations::insert_request request{
736
956
  id,
737
- std::move(value.data),
957
+ std::move(data),
738
958
  {},
739
959
  {},
740
- value.flags,
960
+ flags,
741
961
  options.expiry,
742
962
  durability_level::none,
743
963
  options.timeout,
744
964
  { options.retry_strategy },
745
- options.parent_span,
965
+ obs_rec->operation_span(),
746
966
  };
747
967
  return core_.execute(
748
968
  std::move(request),
749
- [core = core_, id = std::move(id), options, handler = std::move(handler)](auto resp) mutable {
969
+ [obs_rec = std::move(obs_rec),
970
+ core = core_,
971
+ id = std::move(id),
972
+ options,
973
+ handler = std::move(handler)](auto resp) mutable {
750
974
  if (resp.ctx.ec()) {
751
- return handler(core::impl::make_error(std::move(resp.ctx)),
752
- mutation_result{ resp.cas, std::move(resp.token) });
975
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
976
+ invoke_with_node_id(std::move(handler),
977
+ core::impl::make_error(std::move(resp.ctx)),
978
+ mutation_result{ resp.cas, std::move(resp.token) });
979
+ return;
753
980
  }
754
981
 
755
982
  auto token = resp.token;
@@ -760,22 +987,32 @@ public:
760
987
  options.timeout,
761
988
  options.persist_to,
762
989
  options.replicate_to,
763
- [resp, handler = std::move(handler)](std::error_code ec) mutable {
990
+ [obs_rec = std::move(obs_rec), resp, handler = std::move(handler)](
991
+ std::error_code ec) mutable {
992
+ obs_rec->finish(resp.ctx.retry_attempts(), ec);
764
993
  if (ec) {
765
994
  resp.ctx.override_ec(ec);
766
- return handler(core::impl::make_error(std::move(resp.ctx)), mutation_result{});
995
+ invoke_with_node_id(
996
+ std::move(handler), core::impl::make_error(std::move(resp.ctx)), mutation_result{});
997
+ return;
767
998
  }
768
- return handler(core::impl::make_error(std::move(resp.ctx)),
769
- mutation_result{ resp.cas, std::move(resp.token) });
999
+ invoke_with_node_id(std::move(handler),
1000
+ core::impl::make_error(std::move(resp.ctx)),
1001
+ mutation_result{ resp.cas, std::move(resp.token) });
770
1002
  });
771
1003
  });
772
1004
  }
1005
+
773
1006
  void replace(std::string document_key,
774
- codec::encoded_value encoded,
1007
+ std::variant<codec::encoded_value, std::function<codec::encoded_value()>> value,
775
1008
  replace_options::built options,
776
1009
  replace_handler&& handler) const
777
1010
  {
778
- auto value = std::move(encoded);
1011
+ auto obs_rec = create_observability_recorder(
1012
+ core::tracing::operation::mcbp_replace, options.parent_span, options.durability_level);
1013
+
1014
+ auto [data, flags] = get_encoded_value(std::move(value), obs_rec);
1015
+
779
1016
  auto id = core::document_id{
780
1017
  bucket_name_,
781
1018
  scope_name_,
@@ -783,74 +1020,93 @@ public:
783
1020
  std::move(document_key),
784
1021
  };
785
1022
  if (options.persist_to == persist_to::none && options.replicate_to == replicate_to::none) {
1023
+ core::operations::replace_request request{
1024
+ std::move(id),
1025
+ std::move(data),
1026
+ {},
1027
+ {},
1028
+ flags,
1029
+ options.expiry,
1030
+ options.cas,
1031
+ options.durability_level,
1032
+ options.timeout,
1033
+ { options.retry_strategy },
1034
+ options.preserve_expiry,
1035
+ obs_rec->operation_span(),
1036
+ };
786
1037
  return core_.execute(
787
- core::operations::replace_request{
788
- std::move(id),
789
- std::move(value.data),
790
- {},
791
- {},
792
- value.flags,
793
- options.expiry,
794
- options.cas,
795
- options.durability_level,
796
- options.timeout,
797
- { options.retry_strategy },
798
- options.preserve_expiry,
799
- options.parent_span,
800
- },
801
- [handler = std::move(handler)](auto resp) mutable {
1038
+ std::move(request),
1039
+ [obs_rec = std::move(obs_rec), handler = std::move(handler)](auto resp) mutable {
1040
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
802
1041
  if (resp.ctx.ec()) {
803
- return handler(core::impl::make_error(std::move(resp.ctx)), mutation_result{});
1042
+ invoke_with_node_id(
1043
+ std::move(handler), core::impl::make_error(std::move(resp.ctx)), mutation_result{});
1044
+ return;
804
1045
  }
805
- return handler(core::impl::make_error(std::move(resp.ctx)),
806
- mutation_result{ resp.cas, std::move(resp.token) });
1046
+ invoke_with_node_id(std::move(handler),
1047
+ core::impl::make_error(std::move(resp.ctx)),
1048
+ mutation_result{ resp.cas, std::move(resp.token) });
807
1049
  });
808
1050
  }
809
1051
 
810
1052
  core::operations::replace_request request{
811
1053
  id,
812
- std::move(value.data),
1054
+ std::move(data),
813
1055
  {},
814
1056
  {},
815
- value.flags,
1057
+ flags,
816
1058
  options.expiry,
817
1059
  options.cas,
818
1060
  durability_level::none,
819
1061
  options.timeout,
820
1062
  { options.retry_strategy },
821
1063
  options.preserve_expiry,
822
- options.parent_span,
1064
+ obs_rec->operation_span(),
823
1065
  };
824
- return core_.execute(std::move(request),
825
- [core = core_, id = std::move(id), options, handler = std::move(handler)](
826
- auto&& resp) mutable {
827
- if (resp.ctx.ec()) {
828
- return handler(core::impl::make_error(std::move(resp.ctx)),
829
- mutation_result{ resp.cas, std::move(resp.token) });
830
- }
1066
+ return core_.execute(
1067
+ std::move(request),
1068
+ [obs_rec = std::move(obs_rec),
1069
+ core = core_,
1070
+ id = std::move(id),
1071
+ options,
1072
+ handler = std::move(handler)](auto&& resp) mutable {
1073
+ if (resp.ctx.ec()) {
1074
+ obs_rec->finish(resp.ctx.retry_attempts(), resp.ctx.ec());
1075
+ invoke_with_node_id(std::move(handler),
1076
+ core::impl::make_error(std::move(resp.ctx)),
1077
+ mutation_result{ resp.cas, std::move(resp.token) });
1078
+ return;
1079
+ }
831
1080
 
832
- auto token = resp.token;
833
- core::impl::initiate_observe_poll(
834
- core,
835
- std::move(id),
836
- token,
837
- options.timeout,
838
- options.persist_to,
839
- options.replicate_to,
840
- [resp, handler = std::move(handler)](std::error_code ec) mutable {
841
- if (ec) {
842
- resp.ctx.override_ec(ec);
843
- return handler(core::impl::make_error(std::move(resp.ctx)),
844
- mutation_result{});
845
- }
846
- return handler(core::impl::make_error(std::move(resp.ctx)),
847
- mutation_result{ resp.cas, std::move(resp.token) });
848
- });
849
- });
1081
+ auto token = resp.token;
1082
+ core::impl::initiate_observe_poll(
1083
+ core,
1084
+ std::move(id),
1085
+ token,
1086
+ options.timeout,
1087
+ options.persist_to,
1088
+ options.replicate_to,
1089
+ [obs_rec = std::move(obs_rec), resp, handler = std::move(handler)](
1090
+ std::error_code ec) mutable {
1091
+ obs_rec->finish(resp.ctx.retry_attempts(), ec);
1092
+ if (ec) {
1093
+ resp.ctx.override_ec(ec);
1094
+ invoke_with_node_id(
1095
+ std::move(handler), core::impl::make_error(std::move(resp.ctx)), mutation_result{});
1096
+ return;
1097
+ }
1098
+ invoke_with_node_id(std::move(handler),
1099
+ core::impl::make_error(std::move(resp.ctx)),
1100
+ mutation_result{ resp.cas, std::move(resp.token) });
1101
+ });
1102
+ });
850
1103
  }
851
1104
 
852
1105
  void scan(scan_type::built scan_type, scan_options::built options, scan_handler&& handler) const
853
1106
  {
1107
+ auto obs_rec =
1108
+ create_observability_recorder(core::tracing::operation::mcbp_scan, options.parent_span);
1109
+
854
1110
  core::range_scan_orchestrator_options orchestrator_opts{ options.ids_only };
855
1111
  if (!options.mutation_state.empty()) {
856
1112
  orchestrator_opts.consistent_with = core::mutation_state{ options.mutation_state };
@@ -903,22 +1159,31 @@ public:
903
1159
 
904
1160
  return core_.open_bucket(
905
1161
  bucket_name_,
906
- [this, handler = std::move(handler), orchestrator_opts, core_scan_type](
907
- std::error_code ec) mutable {
1162
+ [this,
1163
+ obs_rec = std::move(obs_rec),
1164
+ handler = std::move(handler),
1165
+ orchestrator_opts,
1166
+ core_scan_type](std::error_code ec) mutable {
908
1167
  if (ec) {
1168
+ obs_rec->finish(ec);
909
1169
  return handler(error(ec), {});
910
1170
  }
911
1171
  return core_.with_bucket_configuration(
912
1172
  bucket_name_,
913
- [this, handler = std::move(handler), orchestrator_opts, core_scan_type](
914
- std::error_code ec,
915
- const std::shared_ptr<core::topology::configuration>& config) mutable {
1173
+ [this,
1174
+ obs_rec = std::move(obs_rec),
1175
+ handler = std::move(handler),
1176
+ orchestrator_opts,
1177
+ core_scan_type](std::error_code ec,
1178
+ const std::shared_ptr<core::topology::configuration>& config) mutable {
916
1179
  if (ec) {
1180
+ obs_rec->finish(ec);
917
1181
  return handler(
918
1182
  error(ec, "An error occurred when attempting to fetch the bucket configuration."),
919
1183
  {});
920
1184
  }
921
1185
  if (!config->capabilities.supports_range_scan()) {
1186
+ obs_rec->finish(ec);
922
1187
  return handler(error(errc::common::feature_not_available,
923
1188
  "This bucket does not support range scan."),
924
1189
  {});
@@ -927,6 +1192,7 @@ public:
927
1192
  core::agent_group(core_.io_context(), core::agent_group_config{ { core_ } });
928
1193
  ec = agent_group.open_bucket(bucket_name_);
929
1194
  if (ec) {
1195
+ obs_rec->finish(ec);
930
1196
  return handler(error(ec,
931
1197
  fmt::format("An error occurred while opening the `{}` bucket.",
932
1198
  bucket_name_)),
@@ -934,6 +1200,7 @@ public:
934
1200
  }
935
1201
  auto agent = agent_group.get_agent(bucket_name_);
936
1202
  if (!agent.has_value()) {
1203
+ obs_rec->finish(ec);
937
1204
  return handler(
938
1205
  error(agent.error(),
939
1206
  fmt::format(
@@ -944,6 +1211,7 @@ public:
944
1211
  if (!config->vbmap.has_value() || config->vbmap->empty()) {
945
1212
  CB_LOG_WARNING("Unable to get vbucket map for `{}` - cannot perform scan operation",
946
1213
  bucket_name_);
1214
+ obs_rec->finish(ec);
947
1215
  return handler(error(errc::common::request_canceled,
948
1216
  "No vbucket map included with the bucket config"),
949
1217
  {});
@@ -957,8 +1225,10 @@ public:
957
1225
  core_scan_type,
958
1226
  orchestrator_opts);
959
1227
  return orchestrator.scan(
960
- [crypto_manager = crypto_manager_,
1228
+ [obs_rec = std::move(obs_rec),
1229
+ crypto_manager = crypto_manager_,
961
1230
  handler = std::move(handler)](auto ec, auto core_scan_result) mutable {
1231
+ obs_rec->finish(ec);
962
1232
  if (ec) {
963
1233
  return handler(error(ec, "Error while starting the range scan"), {});
964
1234
  }
@@ -970,7 +1240,168 @@ public:
970
1240
  });
971
1241
  }
972
1242
 
1243
+ void node_id_for(std::string document_key,
1244
+ const node_id_for_options::built& options,
1245
+ node_id_for_handler&& handler) const
1246
+ {
1247
+ auto [origin_ec, origin] = core_.origin();
1248
+ if (origin_ec) {
1249
+ return handler(error{ origin_ec }, node_id{});
1250
+ }
1251
+ const bool is_tls = origin.options().enable_tls;
1252
+ const auto timeout = options.timeout.value_or(origin.options().key_value_timeout);
1253
+
1254
+ // Shared state so that only one of {timeout timer, bucket-config callback}
1255
+ // can invoke the user handler. with_bucket_configuration() is not
1256
+ // cancellable — if config never arrives, the timer is the only way to
1257
+ // guarantee the handler completes.
1258
+ struct state {
1259
+ std::atomic<bool> done{ false };
1260
+ asio::steady_timer timer;
1261
+ node_id_for_handler handler;
1262
+
1263
+ state(asio::io_context& ioc, node_id_for_handler&& h)
1264
+ : timer{ ioc }
1265
+ , handler{ std::move(h) }
1266
+ {
1267
+ }
1268
+ };
1269
+ auto shared = std::make_shared<state>(core_.io_context(), std::move(handler));
1270
+
1271
+ shared->timer.expires_after(timeout);
1272
+ shared->timer.async_wait([shared](std::error_code timer_ec) -> void {
1273
+ if (timer_ec == asio::error::operation_aborted) {
1274
+ return;
1275
+ }
1276
+ if (shared->done.exchange(true)) {
1277
+ return;
1278
+ }
1279
+ shared->handler(error{ errc::common::unambiguous_timeout }, node_id{});
1280
+ });
1281
+
1282
+ core_.with_bucket_configuration(
1283
+ bucket_name_,
1284
+ [shared, document_key = std::move(document_key), is_tls](
1285
+ std::error_code ec, const std::shared_ptr<core::topology::configuration>& config) -> void {
1286
+ if (shared->done.exchange(true)) {
1287
+ return;
1288
+ }
1289
+ shared->timer.cancel();
1290
+ if (ec) {
1291
+ return shared->handler(error{ ec }, node_id{});
1292
+ }
1293
+ if (!config || !config->vbmap.has_value() || config->vbmap->empty()) {
1294
+ return shared->handler(error{ errc::network::configuration_not_available }, node_id{});
1295
+ }
1296
+ // Only server_index is needed here; vbucket is intentionally unused.
1297
+ // Binding it as [[maybe_unused]] would require C++20 structured-
1298
+ // binding attribute support, so take the pair by value and pull the
1299
+ // field we need instead.
1300
+ const auto mapping = config->map_key(document_key, 0);
1301
+ const auto& server_index = mapping.second;
1302
+ if (!server_index.has_value() || server_index.value() >= config->nodes.size()) {
1303
+ // An unresolvable server_index means the vBucket map is present
1304
+ // but does not map this key to a known node (out-of-range or
1305
+ // missing entry). Surface this as configuration_not_available
1306
+ // rather than request_canceled so callers can distinguish an
1307
+ // unusable map from an actual caller-initiated cancellation.
1308
+ return shared->handler(error{ errc::network::configuration_not_available }, node_id{});
1309
+ }
1310
+ return shared->handler({}, config->nodes[server_index.value()].effective_node_id(is_tls));
1311
+ });
1312
+ }
1313
+
1314
+ void node_ids(const node_ids_options::built& options, node_ids_handler&& handler) const
1315
+ {
1316
+ auto [origin_ec, origin] = core_.origin();
1317
+ if (origin_ec) {
1318
+ return handler(error{ origin_ec }, {});
1319
+ }
1320
+ const bool is_tls = origin.options().enable_tls;
1321
+ const auto timeout = options.timeout.value_or(origin.options().key_value_timeout);
1322
+
1323
+ // Same shape as node_id_for: with_bucket_configuration() is not
1324
+ // cancellable, so a steady_timer guarded by an atomic done-flag is
1325
+ // the only way to bound the wait when no config arrives.
1326
+ struct state {
1327
+ std::atomic<bool> done{ false };
1328
+ asio::steady_timer timer;
1329
+ node_ids_handler handler;
1330
+
1331
+ state(asio::io_context& ioc, node_ids_handler&& h)
1332
+ : timer{ ioc }
1333
+ , handler{ std::move(h) }
1334
+ {
1335
+ }
1336
+ };
1337
+ auto shared = std::make_shared<state>(core_.io_context(), std::move(handler));
1338
+
1339
+ shared->timer.expires_after(timeout);
1340
+ shared->timer.async_wait([shared](std::error_code timer_ec) -> void {
1341
+ if (timer_ec == asio::error::operation_aborted) {
1342
+ return;
1343
+ }
1344
+ if (shared->done.exchange(true)) {
1345
+ return;
1346
+ }
1347
+ shared->handler(error{ errc::common::unambiguous_timeout }, {});
1348
+ });
1349
+
1350
+ core_.with_bucket_configuration(
1351
+ bucket_name_,
1352
+ [shared, is_tls](std::error_code ec,
1353
+ const std::shared_ptr<core::topology::configuration>& config) -> void {
1354
+ if (shared->done.exchange(true)) {
1355
+ return;
1356
+ }
1357
+ shared->timer.cancel();
1358
+ if (ec) {
1359
+ return shared->handler(error{ ec }, {});
1360
+ }
1361
+ if (!config) {
1362
+ // No config arrived but no error either — this should not
1363
+ // happen in practice, but surface it the same way node_id_for
1364
+ // does so callers can distinguish from request_canceled.
1365
+ return shared->handler(error{ errc::network::configuration_not_available }, {});
1366
+ }
1367
+ return shared->handler({}, config->effective_node_ids(is_tls));
1368
+ });
1369
+ }
1370
+
973
1371
  private:
1372
+ static auto get_encoded_value(
1373
+ std::variant<codec::encoded_value, std::function<codec::encoded_value()>> value,
1374
+ const std::unique_ptr<core::impl::observability_recorder>& obs_rec) -> codec::encoded_value
1375
+ {
1376
+ if (std::holds_alternative<codec::encoded_value>(value)) {
1377
+ return std::get<codec::encoded_value>(value);
1378
+ }
1379
+ const auto request_encoding_span = obs_rec->create_request_encoding_span();
1380
+ auto encoded = std::get<std::function<codec::encoded_value()>>(value)();
1381
+ request_encoding_span->end();
1382
+ return encoded;
1383
+ }
1384
+
1385
+ [[nodiscard]] auto create_observability_recorder(
1386
+ const std::string& operation_name,
1387
+ const std::shared_ptr<tracing::request_span>& parent_span,
1388
+ const std::optional<durability_level> durability = {}) const
1389
+ -> std::unique_ptr<core::impl::observability_recorder>
1390
+ {
1391
+ auto rec = core::impl::observability_recorder::create(
1392
+ operation_name, parent_span, core_.tracer(), core_.meter());
1393
+
1394
+ rec->with_service(core::tracing::service::key_value);
1395
+ rec->with_bucket_name(bucket_name_);
1396
+ rec->with_scope_name(scope_name_);
1397
+ rec->with_collection_name(name_);
1398
+ if (durability.has_value()) {
1399
+ rec->with_durability(durability.value());
1400
+ }
1401
+
1402
+ return rec;
1403
+ }
1404
+
974
1405
  core::cluster core_;
975
1406
  std::string bucket_name_;
976
1407
  std::string scope_name_;
@@ -1027,6 +1458,44 @@ collection::crypto_manager() const -> const std::shared_ptr<crypto::manager>&
1027
1458
  return impl_->crypto_manager();
1028
1459
  }
1029
1460
 
1461
+ void
1462
+ collection::node_id_for(std::string document_id,
1463
+ const node_id_for_options& options,
1464
+ node_id_for_handler&& handler) const
1465
+ {
1466
+ return impl_->node_id_for(std::move(document_id), options.build(), std::move(handler));
1467
+ }
1468
+
1469
+ auto
1470
+ collection::node_id_for(std::string document_id, const node_id_for_options& options) const
1471
+ -> std::future<std::pair<error, node_id>>
1472
+ {
1473
+ auto barrier = std::make_shared<std::promise<std::pair<error, node_id>>>();
1474
+ auto future = barrier->get_future();
1475
+ node_id_for(std::move(document_id), options, [barrier](auto err, auto nid) {
1476
+ barrier->set_value({ std::move(err), std::move(nid) });
1477
+ });
1478
+ return future;
1479
+ }
1480
+
1481
+ void
1482
+ collection::node_ids(const node_ids_options& options, node_ids_handler&& handler) const
1483
+ {
1484
+ return impl_->node_ids(options.build(), std::move(handler));
1485
+ }
1486
+
1487
+ auto
1488
+ collection::node_ids(const node_ids_options& options) const
1489
+ -> std::future<std::pair<error, std::vector<node_id>>>
1490
+ {
1491
+ auto barrier = std::make_shared<std::promise<std::pair<error, std::vector<node_id>>>>();
1492
+ auto future = barrier->get_future();
1493
+ node_ids(options, [barrier](auto err, auto nids) {
1494
+ barrier->set_value({ std::move(err), std::move(nids) });
1495
+ });
1496
+ return future;
1497
+ }
1498
+
1030
1499
  void
1031
1500
  collection::get(std::string document_id, const get_options& options, get_handler&& handler) const
1032
1501
  {
@@ -1392,6 +1861,30 @@ collection::upsert(std::string document_id,
1392
1861
  return future;
1393
1862
  }
1394
1863
 
1864
+ auto
1865
+ collection::upsert(std::string document_id,
1866
+ std::function<codec::encoded_value()> document_fn,
1867
+ const upsert_options& options,
1868
+ upsert_handler&& handler) const -> void
1869
+ {
1870
+ impl_->upsert(
1871
+ std::move(document_id), std::move(document_fn), options.build(), std::move(handler));
1872
+ }
1873
+
1874
+ auto
1875
+ collection::upsert(std::string document_id,
1876
+ std::function<codec::encoded_value()> document_fn,
1877
+ const upsert_options& options) const
1878
+ -> std::future<std::pair<error, mutation_result>>
1879
+ {
1880
+ auto barrier = std::make_shared<std::promise<std::pair<error, mutation_result>>>();
1881
+ auto future = barrier->get_future();
1882
+ upsert(std::move(document_id), std::move(document_fn), options, [barrier](auto err, auto result) {
1883
+ barrier->set_value({ std::move(err), std::move(result) });
1884
+ });
1885
+ return future;
1886
+ }
1887
+
1395
1888
  void
1396
1889
  collection::insert(std::string document_id,
1397
1890
  codec::encoded_value document,
@@ -1416,6 +1909,30 @@ collection::insert(std::string document_id,
1416
1909
  return future;
1417
1910
  }
1418
1911
 
1912
+ auto
1913
+ collection::insert(std::string document_id,
1914
+ std::function<codec::encoded_value()> document_fn,
1915
+ const insert_options& options,
1916
+ insert_handler&& handler) const -> void
1917
+ {
1918
+ impl_->insert(
1919
+ std::move(document_id), std::move(document_fn), options.build(), std::move(handler));
1920
+ }
1921
+
1922
+ auto
1923
+ collection::insert(std::string document_id,
1924
+ std::function<codec::encoded_value()> document_fn,
1925
+ const insert_options& options) const
1926
+ -> std::future<std::pair<error, mutation_result>>
1927
+ {
1928
+ auto barrier = std::make_shared<std::promise<std::pair<error, mutation_result>>>();
1929
+ auto future = barrier->get_future();
1930
+ insert(std::move(document_id), std::move(document_fn), options, [barrier](auto err, auto result) {
1931
+ barrier->set_value({ std::move(err), std::move(result) });
1932
+ });
1933
+ return future;
1934
+ }
1935
+
1419
1936
  void
1420
1937
  collection::replace(std::string document_id,
1421
1938
  codec::encoded_value document,
@@ -1440,6 +1957,31 @@ collection::replace(std::string document_id,
1440
1957
  return future;
1441
1958
  }
1442
1959
 
1960
+ void
1961
+ collection::replace(std::string document_id,
1962
+ std::function<codec::encoded_value()> document_fn,
1963
+ const replace_options& options,
1964
+ replace_handler&& handler) const
1965
+ {
1966
+ impl_->replace(
1967
+ std::move(document_id), std::move(document_fn), options.build(), std::move(handler));
1968
+ }
1969
+
1970
+ auto
1971
+ collection::replace(std::string document_id,
1972
+ std::function<codec::encoded_value()> document_fn,
1973
+ const replace_options& options) const
1974
+ -> std::future<std::pair<error, mutation_result>>
1975
+ {
1976
+ auto barrier = std::make_shared<std::promise<std::pair<error, mutation_result>>>();
1977
+ auto future = barrier->get_future();
1978
+ replace(
1979
+ std::move(document_id), std::move(document_fn), options, [barrier](auto err, auto result) {
1980
+ barrier->set_value({ std::move(err), std::move(result) });
1981
+ });
1982
+ return future;
1983
+ }
1984
+
1443
1985
  void
1444
1986
  collection::scan(const couchbase::scan_type& scan_type,
1445
1987
  const couchbase::scan_options& options,