couchbase 3.8.1 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (475) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/CMakeLists.txt +16 -1
  4. data/ext/cache/cpm/{CPM_0.42.0.cmake → CPM_0.43.1.cmake} +18 -2
  5. data/ext/cache/extconf_include.rb +6 -6
  6. data/ext/cache/mozilla-ca-bundle.crt +214 -155
  7. data/ext/cache/mozilla-ca-bundle.sha256 +1 -1
  8. data/ext/couchbase/CMakeLists.txt +130 -21
  9. data/ext/couchbase/cmake/APKBUILD.in +25 -4
  10. data/ext/couchbase/cmake/Bundler.cmake +143 -34
  11. data/ext/couchbase/cmake/CPM.cmake +126 -12
  12. data/ext/couchbase/cmake/Cache.cmake +7 -1
  13. data/ext/couchbase/cmake/CompilerOptions.cmake +1 -1
  14. data/ext/couchbase/cmake/CompilerWarnings.cmake +17 -6
  15. data/ext/couchbase/cmake/GrpcProtobuf.cmake +481 -0
  16. data/ext/couchbase/cmake/OpenSSL.cmake +10 -3
  17. data/ext/couchbase/cmake/Packaging.cmake +519 -65
  18. data/ext/couchbase/cmake/Protostellar.cmake +250 -0
  19. data/ext/couchbase/cmake/Sanitizers.cmake +61 -50
  20. data/ext/couchbase/cmake/StaticAnalyzers.cmake +16 -5
  21. data/ext/couchbase/cmake/TestFramework.cmake +283 -0
  22. data/ext/couchbase/cmake/TestFrameworkAddTests.cmake +51 -0
  23. data/ext/couchbase/cmake/Testing.cmake +27 -9
  24. data/ext/couchbase/cmake/ThirdPartyDependencies.cmake +141 -8
  25. data/ext/couchbase/cmake/VersionInfo.cmake +50 -0
  26. data/ext/couchbase/cmake/build_config.hxx.in +2 -1
  27. data/ext/couchbase/cmake/couchbase-cxx-client.spec.in +101 -23
  28. data/ext/couchbase/cmake/couchbase_cxx_client_static-config.cmake.in +7 -0
  29. data/ext/couchbase/cmake/couchbase_cxx_client_static.pc.in +2 -0
  30. data/ext/couchbase/cmake/gRPC_Generate.cmake +58 -0
  31. data/ext/couchbase/cmake/protobuf_Generate.cmake +69 -0
  32. data/ext/couchbase/cmake/require-git-checkout.cmake +25 -0
  33. data/ext/couchbase/cmake/tarball_glob.txt +49 -0
  34. data/ext/couchbase/core/agent_group.cxx +0 -8
  35. data/ext/couchbase/core/agent_group.hxx +0 -4
  36. data/ext/couchbase/core/analytics_stream.cxx +314 -0
  37. data/ext/couchbase/core/analytics_stream.hxx +129 -0
  38. data/ext/couchbase/core/analytics_stream_component.cxx +245 -0
  39. data/ext/couchbase/core/analytics_stream_component.hxx +67 -0
  40. data/ext/couchbase/core/app_telemetry_meter.cxx +25 -3
  41. data/ext/couchbase/core/app_telemetry_meter.hxx +77 -0
  42. data/ext/couchbase/core/app_telemetry_reporter.cxx +7 -6
  43. data/ext/couchbase/core/bucket.cxx +381 -87
  44. data/ext/couchbase/core/bucket.hxx +105 -25
  45. data/ext/couchbase/core/bucket_unit_test_api.hxx +57 -0
  46. data/ext/couchbase/core/capella.hxx +91 -0
  47. data/ext/couchbase/core/cluster.cxx +1554 -398
  48. data/ext/couchbase/core/cluster.hxx +39 -8
  49. data/ext/couchbase/core/cluster_agent.cxx +0 -8
  50. data/ext/couchbase/core/cluster_agent.hxx +0 -4
  51. data/ext/couchbase/core/cluster_options.hxx +26 -3
  52. data/ext/couchbase/core/collections_component.cxx +39 -15
  53. data/ext/couchbase/core/config_profiles.cxx +1 -1
  54. data/ext/couchbase/core/crud_component.cxx +2 -2
  55. data/ext/couchbase/core/crud_options.hxx +34 -0
  56. data/ext/couchbase/core/crypto/cbcrypto.cc +18 -13
  57. data/ext/couchbase/core/document_id_redaction.hxx +81 -0
  58. data/ext/couchbase/core/error_context/base_error_context.hxx +7 -6
  59. data/ext/couchbase/core/error_context/key_value.cxx +25 -2
  60. data/ext/couchbase/core/error_context/key_value.hxx +60 -33
  61. data/ext/couchbase/core/error_context/key_value_error_context.hxx +16 -15
  62. data/ext/couchbase/core/error_context/search.hxx +5 -0
  63. data/ext/couchbase/core/error_context/search_json.hxx +3 -0
  64. data/ext/couchbase/core/error_context/subdocument_error_context.hxx +19 -18
  65. data/ext/couchbase/core/error_context/view.hxx +5 -0
  66. data/ext/couchbase/core/free_form_http_request.cxx +237 -4
  67. data/ext/couchbase/core/free_form_http_request.hxx +41 -8
  68. data/ext/couchbase/core/http_component.cxx +300 -284
  69. data/ext/couchbase/core/http_component.hxx +0 -4
  70. data/ext/couchbase/core/impl/analytics.cxx +38 -5
  71. data/ext/couchbase/core/impl/analytics.hxx +34 -0
  72. data/ext/couchbase/core/impl/bootstrap_error.hxx +0 -3
  73. data/ext/couchbase/core/impl/collection.cxx +215 -202
  74. data/ext/couchbase/core/impl/collection_manager.cxx +1 -1
  75. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +45 -18
  76. data/ext/couchbase/core/impl/error.cxx +22 -2
  77. data/ext/couchbase/core/impl/internal_analytics_stream_result.hxx +111 -0
  78. data/ext/couchbase/core/impl/internal_query_stream_result.hxx +110 -0
  79. data/ext/couchbase/core/impl/invoke_with_node_id.hxx +15 -7
  80. data/ext/couchbase/core/impl/key_value_error_category.cxx +6 -0
  81. data/ext/couchbase/core/impl/lookup_in_replica.cxx +10 -10
  82. data/ext/couchbase/core/impl/lookup_in_replica.hxx +4 -4
  83. data/ext/couchbase/core/impl/node_id.cxx +49 -13
  84. data/ext/couchbase/core/impl/observability_recorder.cxx +12 -2
  85. data/ext/couchbase/core/impl/observe_poll.cxx +63 -23
  86. data/ext/couchbase/core/impl/public_analytics_stream_result.cxx +372 -0
  87. data/ext/couchbase/core/impl/public_bucket.cxx +48 -2
  88. data/ext/couchbase/core/impl/public_cluster.cxx +325 -25
  89. data/ext/couchbase/core/impl/public_query_stream_result.cxx +380 -0
  90. data/ext/couchbase/core/impl/public_transaction_get_multi_replicas_from_preferred_server_group_result.cxx +42 -0
  91. data/ext/couchbase/core/impl/public_transaction_get_multi_result.cxx +42 -0
  92. data/ext/couchbase/core/impl/query.cxx +76 -7
  93. data/ext/couchbase/core/impl/query.hxx +36 -0
  94. data/ext/couchbase/core/impl/query_index_manager.cxx +54 -1
  95. data/ext/couchbase/core/impl/replica_utils.cxx +101 -0
  96. data/ext/couchbase/core/impl/replica_utils.hxx +64 -0
  97. data/ext/couchbase/core/impl/resolve_node_id.hxx +125 -0
  98. data/ext/couchbase/core/impl/scope.cxx +70 -0
  99. data/ext/couchbase/core/impl/search.cxx +31 -1
  100. data/ext/couchbase/core/impl/transactions.cxx +130 -0
  101. data/ext/couchbase/core/impl/wait_until_ready.cxx +439 -0
  102. data/ext/couchbase/core/impl/wait_until_ready.hxx +110 -0
  103. data/ext/couchbase/core/impl/with_bucket_config_or_timeout.hxx +180 -0
  104. data/ext/couchbase/core/impl/with_cancellation.hxx +11 -3
  105. data/ext/couchbase/core/io/configuration_belongs_to_session.hxx +66 -0
  106. data/ext/couchbase/core/io/dns_client.cxx +122 -45
  107. data/ext/couchbase/core/io/dns_codec.hxx +21 -21
  108. data/ext/couchbase/core/io/dns_config.cxx +21 -6
  109. data/ext/couchbase/core/io/http_command.hxx +149 -121
  110. data/ext/couchbase/core/io/http_error.hxx +107 -0
  111. data/ext/couchbase/core/io/http_parser.cxx +4 -0
  112. data/ext/couchbase/core/io/http_session.cxx +606 -154
  113. data/ext/couchbase/core/io/http_session.hxx +147 -30
  114. data/ext/couchbase/core/io/http_session_manager.hxx +329 -382
  115. data/ext/couchbase/core/io/http_streaming_parser.cxx +4 -0
  116. data/ext/couchbase/core/io/http_streaming_response.cxx +328 -43
  117. data/ext/couchbase/core/io/http_streaming_response.hxx +37 -3
  118. data/ext/couchbase/core/io/mcbp_buffer_pool.hxx +122 -0
  119. data/ext/couchbase/core/io/mcbp_command.hxx +150 -51
  120. data/ext/couchbase/core/io/mcbp_command_id.hxx +45 -0
  121. data/ext/couchbase/core/io/mcbp_message.cxx +9 -1
  122. data/ext/couchbase/core/io/mcbp_message.hxx +19 -0
  123. data/ext/couchbase/core/io/mcbp_output_queue.hxx +150 -0
  124. data/ext/couchbase/core/io/mcbp_parser.cxx +24 -7
  125. data/ext/couchbase/core/io/mcbp_session.cxx +316 -317
  126. data/ext/couchbase/core/io/mcbp_session.hxx +27 -18
  127. data/ext/couchbase/core/io/opaque_ring_table.hxx +145 -0
  128. data/ext/couchbase/core/io/retry_orchestrator.hxx +6 -5
  129. data/ext/couchbase/core/io/stream_deadline.hxx +50 -0
  130. data/ext/couchbase/core/io/streams.cxx +275 -14
  131. data/ext/couchbase/core/io/streams.hxx +53 -0
  132. data/ext/couchbase/core/logger/logger.cxx +36 -0
  133. data/ext/couchbase/core/logger/logger.hxx +46 -6
  134. data/ext/couchbase/core/logger/redaction.hxx +503 -0
  135. data/ext/couchbase/core/management/eventing_status.hxx +10 -0
  136. data/ext/couchbase/core/management/eventing_status_json.hxx +4 -0
  137. data/ext/couchbase/core/mcbp/big_endian.cxx +1 -1
  138. data/ext/couchbase/core/mcbp/codec.cxx +27 -18
  139. data/ext/couchbase/core/mcbp/operation_queue.cxx +2 -2
  140. data/ext/couchbase/core/mcbp/packet.hxx +2 -2
  141. data/ext/couchbase/core/mcbp/queue_request.cxx +23 -6
  142. data/ext/couchbase/core/mcbp/queue_request.hxx +21 -0
  143. data/ext/couchbase/core/meta/features.hxx +13 -0
  144. data/ext/couchbase/core/meta/version.cxx +6 -3
  145. data/ext/couchbase/core/metrics/logging_meter.cxx +5 -10
  146. data/ext/couchbase/core/metrics/meter_wrapper.cxx +63 -33
  147. data/ext/couchbase/core/metrics/meter_wrapper.hxx +55 -3
  148. data/ext/couchbase/core/operations/analytics_response_parsing.cxx +177 -0
  149. data/ext/couchbase/core/operations/analytics_response_parsing.hxx +55 -0
  150. data/ext/couchbase/core/operations/document_analytics.cxx +48 -130
  151. data/ext/couchbase/core/operations/document_analytics.hxx +14 -2
  152. data/ext/couchbase/core/operations/document_get_all_replicas.hxx +15 -7
  153. data/ext/couchbase/core/operations/document_get_any_replica.hxx +19 -8
  154. data/ext/couchbase/core/operations/document_get_projected.cxx +1 -1
  155. data/ext/couchbase/core/{impl/get_replica.cxx → operations/document_get_replica.cxx} +21 -3
  156. data/ext/couchbase/core/{impl/get_replica.hxx → operations/document_get_replica.hxx} +31 -4
  157. data/ext/couchbase/core/operations/document_lookup_in.cxx +10 -10
  158. data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +228 -198
  159. data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +215 -217
  160. data/ext/couchbase/core/operations/document_query.cxx +108 -221
  161. data/ext/couchbase/core/operations/document_query.hxx +18 -4
  162. data/ext/couchbase/core/operations/document_search.cxx +52 -8
  163. data/ext/couchbase/core/operations/document_search.hxx +3 -0
  164. data/ext/couchbase/core/operations/document_view.cxx +3 -3
  165. data/ext/couchbase/core/operations/management/analytics_dataset_create.cxx +15 -8
  166. data/ext/couchbase/core/operations/management/analytics_dataset_create.hxx +4 -0
  167. data/ext/couchbase/core/operations/management/analytics_dataset_drop.cxx +11 -6
  168. data/ext/couchbase/core/operations/management/analytics_dataset_get_all.cxx +3 -2
  169. data/ext/couchbase/core/operations/management/analytics_dataverse_create.cxx +10 -5
  170. data/ext/couchbase/core/operations/management/analytics_dataverse_drop.cxx +10 -5
  171. data/ext/couchbase/core/operations/management/analytics_get_pending_mutations.cxx +2 -1
  172. data/ext/couchbase/core/operations/management/analytics_index_create.cxx +33 -8
  173. data/ext/couchbase/core/operations/management/analytics_index_drop.cxx +12 -7
  174. data/ext/couchbase/core/operations/management/analytics_index_get_all.cxx +3 -2
  175. data/ext/couchbase/core/operations/management/analytics_link_connect.cxx +11 -6
  176. data/ext/couchbase/core/operations/management/analytics_link_create.cxx +3 -3
  177. data/ext/couchbase/core/operations/management/analytics_link_disconnect.cxx +10 -4
  178. data/ext/couchbase/core/operations/management/analytics_link_drop.cxx +6 -4
  179. data/ext/couchbase/core/operations/management/analytics_link_get_all.cxx +4 -3
  180. data/ext/couchbase/core/operations/management/analytics_link_replace.cxx +3 -3
  181. data/ext/couchbase/core/operations/management/analytics_link_utils.hxx +1 -1
  182. data/ext/couchbase/core/operations/management/bucket_create.cxx +37 -38
  183. data/ext/couchbase/core/operations/management/bucket_update.cxx +26 -28
  184. data/ext/couchbase/core/operations/management/change_password.cxx +2 -0
  185. data/ext/couchbase/core/operations/management/collection_drop.cxx +5 -1
  186. data/ext/couchbase/core/operations/management/error_utils.cxx +59 -5
  187. data/ext/couchbase/core/operations/management/error_utils.hxx +29 -1
  188. data/ext/couchbase/core/operations/management/eventing_deploy_function.cxx +9 -3
  189. data/ext/couchbase/core/operations/management/eventing_drop_function.cxx +8 -3
  190. data/ext/couchbase/core/operations/management/eventing_get_all_functions.cxx +4 -2
  191. data/ext/couchbase/core/operations/management/eventing_get_function.cxx +5 -3
  192. data/ext/couchbase/core/operations/management/eventing_get_status.cxx +4 -2
  193. data/ext/couchbase/core/operations/management/eventing_pause_function.cxx +9 -3
  194. data/ext/couchbase/core/operations/management/eventing_resume_function.cxx +9 -3
  195. data/ext/couchbase/core/operations/management/eventing_undeploy_function.cxx +9 -3
  196. data/ext/couchbase/core/operations/management/eventing_upsert_function.cxx +9 -3
  197. data/ext/couchbase/core/operations/management/group_drop.cxx +3 -1
  198. data/ext/couchbase/core/operations/management/group_get.cxx +3 -1
  199. data/ext/couchbase/core/operations/management/group_upsert.cxx +11 -8
  200. data/ext/couchbase/core/operations/management/query_index_build.cxx +5 -2
  201. data/ext/couchbase/core/operations/management/query_index_create.cxx +9 -3
  202. data/ext/couchbase/core/operations/management/query_index_drop.cxx +11 -4
  203. data/ext/couchbase/core/operations/management/query_index_get_all.cxx +1 -1
  204. data/ext/couchbase/core/operations/management/query_index_get_all_deferred.cxx +1 -1
  205. data/ext/couchbase/core/operations/management/scope_drop.cxx +5 -1
  206. data/ext/couchbase/core/operations/management/scope_get_all.cxx +6 -1
  207. data/ext/couchbase/core/operations/management/search_get_stats.cxx +10 -0
  208. data/ext/couchbase/core/operations/management/search_index_analyze_document.cxx +3 -2
  209. data/ext/couchbase/core/operations/management/search_index_control_ingest.cxx +4 -3
  210. data/ext/couchbase/core/operations/management/search_index_control_plan_freeze.cxx +4 -3
  211. data/ext/couchbase/core/operations/management/search_index_control_query.cxx +4 -3
  212. data/ext/couchbase/core/operations/management/search_index_drop.cxx +2 -2
  213. data/ext/couchbase/core/operations/management/search_index_get.cxx +2 -2
  214. data/ext/couchbase/core/operations/management/search_index_get_documents_count.cxx +3 -2
  215. data/ext/couchbase/core/operations/management/search_index_get_stats.cxx +3 -1
  216. data/ext/couchbase/core/operations/management/search_index_upsert.cxx +2 -2
  217. data/ext/couchbase/core/operations/management/user_drop.cxx +3 -1
  218. data/ext/couchbase/core/operations/management/user_get.cxx +3 -1
  219. data/ext/couchbase/core/operations/management/user_upsert.cxx +12 -9
  220. data/ext/couchbase/core/operations/management/view_index_drop.cxx +1 -1
  221. data/ext/couchbase/core/operations/management/view_index_get.cxx +1 -1
  222. data/ext/couchbase/core/operations/management/view_index_upsert.cxx +1 -1
  223. data/ext/couchbase/core/operations/operation_traits.hxx +18 -0
  224. data/ext/couchbase/core/operations/query_response_parsing.cxx +211 -0
  225. data/ext/couchbase/core/operations/query_response_parsing.hxx +60 -0
  226. data/ext/couchbase/core/operations_fwd.hxx +3 -3
  227. data/ext/couchbase/core/origin.cxx +54 -26
  228. data/ext/couchbase/core/origin.hxx +12 -0
  229. data/ext/couchbase/core/orphan_reporter.cxx +2 -1
  230. data/ext/couchbase/core/platform/random.cc +7 -7
  231. data/ext/couchbase/core/protocol/client_request.cxx +2 -2
  232. data/ext/couchbase/core/protocol/client_request.hxx +38 -21
  233. data/ext/couchbase/core/protocol/client_response.cxx +11 -3
  234. data/ext/couchbase/core/protocol/client_response.hxx +27 -6
  235. data/ext/couchbase/core/protocol/cmd_append.cxx +2 -2
  236. data/ext/couchbase/core/protocol/cmd_cluster_map_change_notification.cxx +2 -2
  237. data/ext/couchbase/core/protocol/cmd_decrement.cxx +6 -6
  238. data/ext/couchbase/core/protocol/cmd_get.cxx +1 -1
  239. data/ext/couchbase/core/protocol/cmd_get_and_lock.cxx +2 -2
  240. data/ext/couchbase/core/protocol/cmd_get_and_touch.cxx +2 -2
  241. data/ext/couchbase/core/protocol/cmd_get_cluster_config.cxx +6 -4
  242. data/ext/couchbase/core/protocol/cmd_get_collection_id.cxx +2 -2
  243. data/ext/couchbase/core/protocol/cmd_get_error_map.cxx +1 -1
  244. data/ext/couchbase/core/protocol/cmd_get_meta.cxx +4 -4
  245. data/ext/couchbase/core/protocol/cmd_get_replica.cxx +1 -1
  246. data/ext/couchbase/core/protocol/cmd_hello.cxx +1 -1
  247. data/ext/couchbase/core/protocol/cmd_increment.cxx +6 -6
  248. data/ext/couchbase/core/protocol/cmd_insert.cxx +4 -4
  249. data/ext/couchbase/core/protocol/cmd_lookup_in.cxx +4 -3
  250. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.cxx +4 -3
  251. data/ext/couchbase/core/protocol/cmd_mutate_in.cxx +10 -9
  252. data/ext/couchbase/core/protocol/cmd_mutate_in.hxx +10 -10
  253. data/ext/couchbase/core/protocol/cmd_observe_seqno.cxx +7 -7
  254. data/ext/couchbase/core/protocol/cmd_prepend.cxx +2 -2
  255. data/ext/couchbase/core/protocol/cmd_remove.cxx +2 -2
  256. data/ext/couchbase/core/protocol/cmd_replace.cxx +4 -4
  257. data/ext/couchbase/core/protocol/cmd_touch.cxx +1 -1
  258. data/ext/couchbase/core/protocol/cmd_upsert.cxx +4 -4
  259. data/ext/couchbase/core/protocol/datatype.hxx +118 -1
  260. data/ext/couchbase/core/protocol/frame_info_utils.cxx +1 -1
  261. data/ext/couchbase/core/protocol/magic.hxx +4 -0
  262. data/ext/couchbase/core/protocol/magic_fmt.hxx +3 -0
  263. data/ext/couchbase/core/protocol/server_request.hxx +3 -1
  264. data/ext/couchbase/core/protocol/status.cxx +1 -1
  265. data/ext/couchbase/core/protostellar/analytics_converter.hxx +171 -0
  266. data/ext/couchbase/core/protostellar/bucket_admin_converter.hxx +301 -0
  267. data/ext/couchbase/core/protostellar/collection_admin_converter.hxx +92 -0
  268. data/ext/couchbase/core/protostellar/component.cxx +2445 -0
  269. data/ext/couchbase/core/protostellar/component.hxx +391 -0
  270. data/ext/couchbase/core/{columnar/bootstrap_notification_subscriber.hxx → protostellar/compression_settings.hxx} +11 -10
  271. data/ext/couchbase/core/protostellar/credentials.cxx +233 -0
  272. data/ext/couchbase/core/protostellar/credentials.hxx +88 -0
  273. data/ext/couchbase/core/protostellar/dispatcher.cxx +57 -0
  274. data/ext/couchbase/core/protostellar/dispatcher.hxx +482 -0
  275. data/ext/couchbase/core/protostellar/error_utils.cxx +293 -0
  276. data/ext/couchbase/core/protostellar/error_utils.hxx +97 -0
  277. data/ext/couchbase/core/protostellar/json_payload.hxx +49 -0
  278. data/ext/couchbase/core/protostellar/kv_converter.cxx +70 -0
  279. data/ext/couchbase/core/protostellar/kv_converter.hxx +600 -0
  280. data/ext/couchbase/core/protostellar/query_converter.hxx +265 -0
  281. data/ext/couchbase/core/protostellar/query_index_admin_converter.hxx +291 -0
  282. data/ext/couchbase/core/protostellar/query_proto.hxx +73 -0
  283. data/ext/couchbase/core/protostellar/search_converter.hxx +244 -0
  284. data/ext/couchbase/core/protostellar/search_index_admin_converter.hxx +156 -0
  285. data/ext/couchbase/core/protostellar/view_converter.hxx +158 -0
  286. data/ext/couchbase/core/query_stream.cxx +447 -0
  287. data/ext/couchbase/core/query_stream.hxx +141 -0
  288. data/ext/couchbase/core/query_stream_component.cxx +243 -0
  289. data/ext/couchbase/core/query_stream_component.hxx +68 -0
  290. data/ext/couchbase/core/range_scan_load_balancer.cxx +15 -8
  291. data/ext/couchbase/core/range_scan_orchestrator.cxx +15 -3
  292. data/ext/couchbase/core/response_handler.hxx +41 -4
  293. data/ext/couchbase/core/row_streamer.cxx +332 -46
  294. data/ext/couchbase/core/row_streamer.hxx +31 -1
  295. data/ext/couchbase/core/row_streamer_options.hxx +55 -0
  296. data/ext/couchbase/core/sasl/client.h +3 -0
  297. data/ext/couchbase/core/search_scoring.hxx +66 -0
  298. data/ext/couchbase/core/stream_error_details.hxx +69 -0
  299. data/ext/couchbase/core/timeout_defaults.hxx +0 -1
  300. data/ext/couchbase/core/topology/capabilities.hxx +6 -0
  301. data/ext/couchbase/core/topology/capabilities_fmt.hxx +3 -0
  302. data/ext/couchbase/core/topology/configuration.cxx +21 -6
  303. data/ext/couchbase/core/topology/configuration.hxx +29 -8
  304. data/ext/couchbase/core/topology/configuration_json.hxx +3 -0
  305. data/ext/couchbase/core/topology/error_map_json.hxx +3 -1
  306. data/ext/couchbase/core/tracing/threshold_logging_tracer.cxx +70 -4
  307. data/ext/couchbase/core/tracing/threshold_logging_tracer.hxx +10 -0
  308. data/ext/couchbase/core/transactions/active_transaction_record.cxx +0 -34
  309. data/ext/couchbase/core/transactions/attempt_context_impl.cxx +362 -241
  310. data/ext/couchbase/core/transactions/attempt_context_impl.hxx +24 -3
  311. data/ext/couchbase/core/transactions/error_list.hxx +2 -2
  312. data/ext/couchbase/core/transactions/get_multi_fetch.hxx +160 -0
  313. data/ext/couchbase/core/transactions/get_multi_orchestrator.cxx +326 -125
  314. data/ext/couchbase/core/transactions/get_multi_transaction_id.hxx +62 -0
  315. data/ext/couchbase/core/transactions/internal/atr_entry.hxx +22 -2
  316. data/ext/couchbase/core/transactions/internal/transaction_context.hxx +2 -2
  317. data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +23 -1
  318. data/ext/couchbase/core/transactions/internal/utils.hxx +50 -14
  319. data/ext/couchbase/core/transactions/staged_mutation.cxx +23 -18
  320. data/ext/couchbase/core/transactions/staged_mutation.hxx +15 -4
  321. data/ext/couchbase/core/transactions/transaction_context.cxx +55 -40
  322. data/ext/couchbase/core/transactions/transaction_get_result.hxx +16 -0
  323. data/ext/couchbase/core/transactions/transactions.cxx +3 -55
  324. data/ext/couchbase/core/transactions/transactions_cleanup.cxx +194 -66
  325. data/ext/couchbase/core/transactions/transactions_config.cxx +0 -11
  326. data/ext/couchbase/core/transactions/utils.cxx +10 -0
  327. data/ext/couchbase/core/transactions/waitable_op_list.hxx +15 -4
  328. data/ext/couchbase/core/transactions.hxx +9 -9
  329. data/ext/couchbase/core/utils/byteswap.hxx +166 -9
  330. data/ext/couchbase/core/utils/connection_string.cxx +50 -85
  331. data/ext/couchbase/core/utils/connection_string.hxx +15 -0
  332. data/ext/couchbase/core/{columnar/backoff_calculator.hxx → utils/deadline.hxx} +13 -13
  333. data/ext/couchbase/core/utils/duration_parser.cxx +1 -1
  334. data/ext/couchbase/core/utils/json_streaming_lexer.cxx +48 -5
  335. data/ext/couchbase/core/utils/json_streaming_lexer.hxx +4 -1
  336. data/ext/couchbase/core/utils/movable_function.hxx +301 -52
  337. data/ext/couchbase/core/utils/name_codec.hxx +154 -11
  338. data/ext/couchbase/core/{columnar/retry_info.hxx → utils/process_id.hxx} +18 -13
  339. data/ext/couchbase/core/utils/url_codec.cxx +12 -51
  340. data/ext/couchbase/core/websocket_codec.cxx +3 -29
  341. data/ext/couchbase/couchbase/analytics_options.hxx +21 -10
  342. data/ext/couchbase/couchbase/analytics_row.hxx +105 -0
  343. data/ext/couchbase/couchbase/analytics_stream_result.hxx +266 -0
  344. data/ext/couchbase/couchbase/boolean_query.hxx +3 -3
  345. data/ext/couchbase/couchbase/bucket.hxx +57 -0
  346. data/ext/couchbase/couchbase/cluster.hxx +216 -5
  347. data/ext/couchbase/{core/columnar/security_options.hxx → couchbase/cluster_state.hxx} +18 -14
  348. data/ext/couchbase/couchbase/codec/lenient_json_transcoder.hxx +69 -0
  349. data/ext/couchbase/couchbase/collection.hxx +234 -14
  350. data/ext/couchbase/couchbase/common_durability_options.hxx +18 -3
  351. data/ext/couchbase/couchbase/conjunction_query.hxx +1 -1
  352. data/ext/couchbase/couchbase/create_dataset_analytics_options.hxx +6 -1
  353. data/ext/couchbase/couchbase/date_range_query.hxx +2 -2
  354. data/ext/couchbase/couchbase/decrement_options.hxx +1 -1
  355. data/ext/couchbase/couchbase/disjunction_query.hxx +1 -1
  356. data/ext/couchbase/couchbase/error.hxx +32 -0
  357. data/ext/couchbase/couchbase/error_codes.hxx +32 -0
  358. data/ext/couchbase/couchbase/geo_bounding_box_query.hxx +1 -1
  359. data/ext/couchbase/couchbase/geo_distance_query.hxx +1 -1
  360. data/ext/couchbase/couchbase/geo_polygon_query.hxx +1 -1
  361. data/ext/couchbase/couchbase/get_replica_options.hxx +68 -0
  362. data/ext/couchbase/couchbase/get_replica_result.hxx +5 -3
  363. data/ext/couchbase/couchbase/get_replica_strategy.hxx +161 -0
  364. data/ext/couchbase/couchbase/get_result.hxx +1 -0
  365. data/ext/couchbase/couchbase/increment_options.hxx +1 -1
  366. data/ext/couchbase/couchbase/insert_options.hxx +1 -1
  367. data/ext/couchbase/couchbase/match_phrase_query.hxx +1 -1
  368. data/ext/couchbase/couchbase/match_query.hxx +1 -1
  369. data/ext/couchbase/couchbase/mutate_in_options.hxx +3 -3
  370. data/ext/couchbase/couchbase/network_options.hxx +1 -1
  371. data/ext/couchbase/couchbase/node_id.hxx +42 -14
  372. data/ext/couchbase/couchbase/node_id_for_options.hxx +7 -1
  373. data/ext/couchbase/couchbase/node_ids_options.hxx +8 -2
  374. data/ext/couchbase/couchbase/numeric_range_query.hxx +1 -1
  375. data/ext/couchbase/couchbase/phrase_query.hxx +1 -1
  376. data/ext/couchbase/couchbase/prefix_query.hxx +1 -1
  377. data/ext/couchbase/couchbase/query_options.hxx +23 -12
  378. data/ext/couchbase/couchbase/query_row.hxx +111 -0
  379. data/ext/couchbase/couchbase/query_stream_result.hxx +302 -0
  380. data/ext/couchbase/couchbase/query_string_query.hxx +3 -3
  381. data/ext/couchbase/couchbase/regexp_query.hxx +1 -1
  382. data/ext/couchbase/couchbase/replace_options.hxx +3 -3
  383. data/ext/couchbase/couchbase/result.hxx +14 -3
  384. data/ext/couchbase/couchbase/scan_result_item.hxx +1 -0
  385. data/ext/couchbase/couchbase/scope.hxx +85 -2
  386. data/ext/couchbase/couchbase/search_options.hxx +58 -8
  387. data/ext/couchbase/couchbase/search_scoring.hxx +94 -0
  388. data/ext/couchbase/couchbase/search_scoring_none.hxx +51 -0
  389. data/ext/couchbase/couchbase/search_scoring_reciprocal_rank_fusion.hxx +88 -0
  390. data/ext/couchbase/couchbase/search_scoring_relative_score_fusion.hxx +70 -0
  391. data/ext/couchbase/couchbase/term_range_query.hxx +1 -1
  392. data/ext/couchbase/couchbase/tracing/request_span.hxx +46 -0
  393. data/ext/couchbase/couchbase/transactions/transaction_get_multi_replicas_from_preferred_server_group_result.hxx +23 -21
  394. data/ext/couchbase/couchbase/transactions/transaction_get_multi_result.hxx +24 -19
  395. data/ext/couchbase/couchbase/transactions/transaction_get_result.hxx +17 -3
  396. data/ext/couchbase/couchbase/transactions/transactions_config.hxx +4 -2
  397. data/ext/couchbase/couchbase/transactions.hxx +27 -18
  398. data/ext/couchbase/couchbase/upsert_options.hxx +3 -3
  399. data/ext/couchbase/couchbase/vector_query.hxx +1 -1
  400. data/ext/couchbase/couchbase/wait_until_ready_options.hxx +111 -0
  401. data/ext/couchbase/couchbase/wildcard_query.hxx +1 -1
  402. data/ext/extconf.rb +15 -10
  403. data/ext/rcb_analytics.cxx +82 -102
  404. data/ext/rcb_backend.cxx +42 -36
  405. data/ext/rcb_backend.hxx +2 -0
  406. data/ext/rcb_buckets.cxx +47 -59
  407. data/ext/rcb_collections.cxx +42 -52
  408. data/ext/rcb_crud.cxx +345 -224
  409. data/ext/rcb_diagnostics.cxx +117 -27
  410. data/ext/rcb_exceptions.cxx +152 -99
  411. data/ext/rcb_exceptions.hxx +25 -0
  412. data/ext/rcb_extras.cxx +18 -19
  413. data/ext/rcb_hdr_histogram.cxx +19 -4
  414. data/ext/rcb_logger.cxx +202 -27
  415. data/ext/rcb_logger.hxx +12 -0
  416. data/ext/rcb_multi.cxx +40 -40
  417. data/ext/rcb_observability.cxx +7 -5
  418. data/ext/rcb_query.cxx +99 -142
  419. data/ext/rcb_range_scan.cxx +41 -35
  420. data/ext/rcb_search.cxx +98 -99
  421. data/ext/rcb_users.cxx +36 -56
  422. data/ext/rcb_utils.cxx +100 -37
  423. data/ext/rcb_utils.hxx +287 -33
  424. data/ext/rcb_version.cxx +1 -1
  425. data/ext/rcb_views.cxx +55 -51
  426. data/lib/active_support/cache/couchbase_store.rb +77 -12
  427. data/lib/couchbase/bucket.rb +20 -0
  428. data/lib/couchbase/cluster.rb +33 -14
  429. data/lib/couchbase/collection.rb +36 -1
  430. data/lib/couchbase/errors.rb +18 -0
  431. data/lib/couchbase/fork_hooks.rb +16 -7
  432. data/lib/couchbase/get_replica_strategy.rb +89 -0
  433. data/lib/couchbase/logger.rb +1 -1
  434. data/lib/couchbase/management/analytics_index_manager.rb +15 -15
  435. data/lib/couchbase/management/bucket_manager.rb +6 -6
  436. data/lib/couchbase/management/collection_manager.rb +6 -6
  437. data/lib/couchbase/management/query_index_manager.rb +7 -7
  438. data/lib/couchbase/management/search_index_manager.rb +13 -13
  439. data/lib/couchbase/management/user_manager.rb +10 -10
  440. data/lib/couchbase/management/view_index_manager.rb +5 -5
  441. data/lib/couchbase/options.rb +181 -44
  442. data/lib/couchbase/protostellar/bucket.rb +4 -0
  443. data/lib/couchbase/protostellar/cluster.rb +4 -0
  444. data/lib/couchbase/protostellar/collection.rb +4 -0
  445. data/lib/couchbase/protostellar/error_handling.rb +2 -1
  446. data/lib/couchbase/protostellar/request.rb +1 -0
  447. data/lib/couchbase/protostellar/request_generator/kv.rb +16 -2
  448. data/lib/couchbase/protostellar/request_generator/search.rb +17 -1
  449. data/lib/couchbase/protostellar/retry/orchestrator.rb +3 -2
  450. data/lib/couchbase/protostellar/retry/strategies/fail_fast.rb +33 -0
  451. data/lib/couchbase/protostellar/retry/strategies.rb +1 -0
  452. data/lib/couchbase/search_options.rb +95 -6
  453. data/lib/couchbase/version.rb +1 -1
  454. metadata +92 -33
  455. data/ext/0001-fix-build-for-mingw-w64-ucrt-x86_64-toolchain.patch +0 -40
  456. data/ext/couchbase/core/columnar/agent.hxx +0 -71
  457. data/ext/couchbase/core/columnar/agent_config.hxx +0 -59
  458. data/ext/couchbase/core/columnar/background_bootstrap_listener.hxx +0 -42
  459. data/ext/couchbase/core/columnar/backoff_calculator.cxx +0 -62
  460. data/ext/couchbase/core/columnar/columnar_agent.cxx +0 -147
  461. data/ext/couchbase/core/columnar/columnar_agent_config.cxx +0 -48
  462. data/ext/couchbase/core/columnar/columnar_error.cxx +0 -51
  463. data/ext/couchbase/core/columnar/database_management_options.hxx +0 -56
  464. data/ext/couchbase/core/columnar/error.hxx +0 -51
  465. data/ext/couchbase/core/columnar/error_codes.cxx +0 -107
  466. data/ext/couchbase/core/columnar/error_codes.hxx +0 -75
  467. data/ext/couchbase/core/columnar/management_component.cxx +0 -300
  468. data/ext/couchbase/core/columnar/management_component.hxx +0 -56
  469. data/ext/couchbase/core/columnar/query_component.cxx +0 -523
  470. data/ext/couchbase/core/columnar/query_component.hxx +0 -57
  471. data/ext/couchbase/core/columnar/query_options.hxx +0 -59
  472. data/ext/couchbase/core/columnar/query_result.cxx +0 -130
  473. data/ext/couchbase/core/columnar/query_result.hxx +0 -78
  474. data/ext/couchbase/core/io/config_tracker.cxx +0 -687
  475. data/ext/couchbase/core/io/config_tracker.hxx +0 -123
@@ -0,0 +1,66 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2020-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
+ #pragma once
19
+
20
+ #include <cstdint>
21
+ #include <optional>
22
+ #include <variant>
23
+
24
+ namespace couchbase::core
25
+ {
26
+ /**
27
+ * Disables scoring.
28
+ */
29
+ struct search_scoring_none {
30
+ };
31
+
32
+ /**
33
+ * Reciprocal Rank Fusion.
34
+ */
35
+ struct search_scoring_reciprocal_rank_fusion {
36
+ std::optional<std::uint32_t> rank_constant{};
37
+ std::optional<std::uint32_t> window_size{};
38
+ };
39
+
40
+ /**
41
+ * Relative Score Fusion.
42
+ */
43
+ struct search_scoring_relative_score_fusion {
44
+ std::optional<std::uint32_t> window_size{};
45
+ };
46
+
47
+ /**
48
+ * The value of the top-level "score" field of a search request. `std::monostate` means the field
49
+ * was not set.
50
+ */
51
+ using search_scoring_mode = std::variant<std::monostate,
52
+ search_scoring_none,
53
+ search_scoring_reciprocal_rank_fusion,
54
+ search_scoring_relative_score_fusion>;
55
+
56
+ /**
57
+ * Whether the strategy is one of the score fusion strategies, and therefore requires the
58
+ * "scoreFusion" cluster capability.
59
+ */
60
+ [[nodiscard]] inline auto
61
+ is_score_fusion(const search_scoring_mode& scoring) -> bool
62
+ {
63
+ return std::holds_alternative<search_scoring_reciprocal_rank_fusion>(scoring) ||
64
+ std::holds_alternative<search_scoring_relative_score_fusion>(scoring);
65
+ }
66
+ } // namespace couchbase::core
@@ -0,0 +1,69 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2026. Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #pragma once
19
+
20
+ #include <cstdint>
21
+ #include <string>
22
+
23
+ namespace couchbase::core
24
+ {
25
+ /**
26
+ * Service-reported diagnostics lifted out of a streaming response, so a streaming failure can be
27
+ * reported with the same context the buffered path provides.
28
+ *
29
+ * A stream parses two JSON sections that can carry errors: the preamble (everything before the row
30
+ * array, which is where a rejected request reports itself) and the trailer (which is where a
31
+ * request that failed part-way through reports itself). Whichever section produced the latest
32
+ * diagnostics is what these fields describe; `raw` is the JSON text they came from, and stands in
33
+ * for the buffered path's whole-body capture.
34
+ */
35
+ struct stream_error_details {
36
+ std::uint64_t first_error_code{};
37
+ std::string first_error_message{};
38
+ std::string client_context_id{};
39
+ std::string raw{};
40
+ };
41
+
42
+ /**
43
+ * Stamps stream diagnostics onto a query/analytics error context. Templated on the context because
44
+ * the two services carry structurally identical contexts under different types.
45
+ *
46
+ * Each field is only written when the stream actually reported it, so these diagnostics augment the
47
+ * context rather than erasing it. That matters for the prepared-statement path, which reaches the
48
+ * streaming handle by replaying an already-buffered response: its context arrives fully populated
49
+ * (http_command captures the response body for every request), and there is no raw JSON left for
50
+ * the replay to report, so an unconditional write would clear the body it already had.
51
+ *
52
+ * client_context_id is deliberately left alone: the context already holds the id the request was
53
+ * sent with, which is the one to correlate against server logs, and the echoed value can differ.
54
+ */
55
+ template<typename Context>
56
+ void
57
+ apply_error_details(Context& ctx, const stream_error_details& details)
58
+ {
59
+ if (details.first_error_code != 0) {
60
+ ctx.first_error_code = details.first_error_code;
61
+ }
62
+ if (!details.first_error_message.empty()) {
63
+ ctx.first_error_message = details.first_error_message;
64
+ }
65
+ if (!details.raw.empty()) {
66
+ ctx.http_body = details.raw;
67
+ }
68
+ }
69
+ } // namespace couchbase::core
@@ -22,7 +22,6 @@
22
22
  namespace couchbase::core::timeout_defaults
23
23
  {
24
24
  constexpr std::chrono::milliseconds bootstrap_timeout{ 10'000 };
25
- constexpr std::chrono::milliseconds dispatch_timeout{ 30'000 };
26
25
 
27
26
  constexpr std::chrono::milliseconds resolve_timeout{ 2'000 };
28
27
  constexpr std::chrono::milliseconds connect_timeout{ 2'000 };
@@ -57,6 +57,7 @@ enum class cluster_capability {
57
57
  n1ql_read_from_replica,
58
58
  search_vector_search,
59
59
  search_scoped_search_index,
60
+ search_score_fusion,
60
61
  };
61
62
 
62
63
  struct configuration_capabilities {
@@ -121,6 +122,11 @@ struct configuration_capabilities {
121
122
  return has_cluster_capability(cluster_capability::search_vector_search);
122
123
  }
123
124
 
125
+ [[nodiscard]] auto supports_score_fusion() const -> bool
126
+ {
127
+ return has_cluster_capability(cluster_capability::search_score_fusion);
128
+ }
129
+
124
130
  [[nodiscard]] auto is_analytics_cluster(const cluster_options& options) const -> bool;
125
131
  };
126
132
 
@@ -142,6 +142,9 @@ struct fmt::formatter<couchbase::core::cluster_capability> {
142
142
  case couchbase::core::cluster_capability::search_scoped_search_index:
143
143
  name = "search_scoped_search_index";
144
144
  break;
145
+ case couchbase::core::cluster_capability::search_score_fusion:
146
+ name = "search_score_fusion";
147
+ break;
145
148
  }
146
149
  return format_to(ctx.out(), "{}", name);
147
150
  }
@@ -173,21 +173,23 @@ configuration::node::endpoint(const std::string& network, service_type type, boo
173
173
  }
174
174
 
175
175
  auto
176
- configuration::node::effective_node_id(bool is_tls) const -> couchbase::node_id
176
+ configuration::node::effective_node_id(transport t) const -> couchbase::node_id
177
177
  {
178
+ const bool is_tls = (t == transport::tls);
178
179
  return internal_node_id::build(node_uuid, hostname, port_or(service_type::key_value, is_tls, 0));
179
180
  }
180
181
 
181
182
  auto
182
- configuration::effective_node_ids(bool is_tls) const -> std::vector<couchbase::node_id>
183
+ configuration::effective_node_ids(transport t) const -> std::vector<couchbase::node_id>
183
184
  {
185
+ const bool is_tls = (t == transport::tls);
184
186
  std::vector<couchbase::node_id> result;
185
187
  result.reserve(nodes.size());
186
188
  for (const auto& n : nodes) {
187
189
  if (n.port_or(service_type::key_value, is_tls, 0) == 0) {
188
190
  continue;
189
191
  }
190
- result.push_back(n.effective_node_id(is_tls));
192
+ result.push_back(n.effective_node_id(t));
191
193
  }
192
194
  return result;
193
195
  }
@@ -300,7 +302,16 @@ configuration::server_by_vbucket(std::uint16_t vbucket, std::size_t index) const
300
302
  if (!vbmap.has_value() || vbucket >= vbmap->size()) {
301
303
  return {};
302
304
  }
303
- if (auto server_index = vbmap->at(vbucket)[index]; server_index >= 0) {
305
+ // A chain row may be shorter than num_replicas + 1: the server publishes the
306
+ // new replica count as soon as the bucket is reconfigured, while the vbucket
307
+ // map keeps its old width until the rebalance that places the replicas.
308
+ // Callers derive the index from num_replicas, so a surplus index must read as
309
+ // "no server" rather than past the end of the row.
310
+ const auto& chain = vbmap->at(vbucket);
311
+ if (index >= chain.size()) {
312
+ return {};
313
+ }
314
+ if (auto server_index = chain[index]; server_index >= 0) {
304
315
  return static_cast<std::size_t>(server_index);
305
316
  }
306
317
  return {};
@@ -310,7 +321,9 @@ auto
310
321
  configuration::map_key(const std::string& key, std::size_t index) const
311
322
  -> std::pair<std::uint16_t, std::optional<std::size_t>>
312
323
  {
313
- if (!vbmap.has_value()) {
324
+ // The number of vbuckets comes from the map itself, so a map without rows
325
+ // cannot be asked which vbucket a key belongs to.
326
+ if (!vbmap.has_value() || vbmap->empty()) {
314
327
  return { 0, {} };
315
328
  }
316
329
  const std::uint32_t crc = utils::hash_crc32(key.data(), key.size());
@@ -322,7 +335,9 @@ auto
322
335
  configuration::map_key(const std::vector<std::byte>& key, std::size_t index) const
323
336
  -> std::pair<std::uint16_t, std::optional<std::size_t>>
324
337
  {
325
- if (!vbmap.has_value()) {
338
+ // The number of vbuckets comes from the map itself, so a map without rows
339
+ // cannot be asked which vbucket a key belongs to.
340
+ if (!vbmap.has_value() || vbmap->empty()) {
326
341
  return { 0, {} };
327
342
  }
328
343
  const std::uint32_t crc = utils::hash_crc32(key.data(), key.size());
@@ -31,6 +31,21 @@
31
31
 
32
32
  namespace couchbase::core::topology
33
33
  {
34
+
35
+ /**
36
+ * Selects which side of the (plain, TLS) port pair to use when deriving a
37
+ * node identity from a topology snapshot.
38
+ *
39
+ * Internal-only strong type: a bare @c bool here is bug-bait because the same
40
+ * flag flows through 6+ layers from origin() into effective_node_id() and a
41
+ * silent sign flip would corrupt the pre-8.0 fallback hash without any
42
+ * compile-time warning.
43
+ */
44
+ enum class transport {
45
+ plain,
46
+ tls,
47
+ };
48
+
34
49
  struct configuration {
35
50
  enum class node_locator_type {
36
51
  unknown,
@@ -92,11 +107,17 @@ struct configuration {
92
107
  * KV port for older servers.
93
108
  *
94
109
  * The KV port selected mirrors what mcbp_session uses for the same node
95
- * (TLS port when @p is_tls, plain port otherwise), ensuring that the
96
- * node_id surfaced on the request side via collection::node_id_for
97
- * matches the node_id attached to results and errors.
110
+ * (TLS port when @p t is @c transport::tls, plain port otherwise),
111
+ * ensuring that the node_id surfaced on the request side via
112
+ * collection::node_id_for matches the node_id attached to results and
113
+ * errors.
114
+ *
115
+ * Returns a default-constructed (falsy) @c node_id when this node does
116
+ * not expose a KV port for the requested transport — the contract that
117
+ * "falsy = unknown / not identifiable" is enforced by
118
+ * @c internal_node_id::build for the empty case.
98
119
  */
99
- [[nodiscard]] auto effective_node_id(bool is_tls) const -> couchbase::node_id;
120
+ [[nodiscard]] auto effective_node_id(transport t) const -> couchbase::node_id;
100
121
  };
101
122
 
102
123
  [[nodiscard]] auto select_network(const std::string& bootstrap_hostname) const -> std::string;
@@ -104,16 +125,16 @@ struct configuration {
104
125
  /**
105
126
  * Returns one node_id per cluster node that currently serves the
106
127
  * key-value service over the requested transport. Nodes that do not
107
- * expose a KV port for @p is_tls are filtered out — without a KV port
108
- * the fallback hash would be derived from a meaningless port=0 and
109
- * could collide with a sibling node that is also missing its KV port.
128
+ * expose a KV port for @p t are filtered out — without a KV port the
129
+ * fallback hash would be derived from a meaningless port=0 and could
130
+ * collide with a sibling node that is also missing its KV port.
110
131
  *
111
132
  * The returned vector preserves topology order; callers that want a
112
133
  * set semantic should hash the entries themselves (couchbase::node_id
113
134
  * is hashable). Topology nodes are unique by construction, so no
114
135
  * dedup is performed here.
115
136
  */
116
- [[nodiscard]] auto effective_node_ids(bool is_tls) const -> std::vector<couchbase::node_id>;
137
+ [[nodiscard]] auto effective_node_ids(transport t) const -> std::vector<couchbase::node_id>;
117
138
 
118
139
  using vbucket_map = typename std::vector<std::vector<std::int16_t>>;
119
140
 
@@ -324,6 +324,9 @@ struct traits<couchbase::core::topology::configuration> {
324
324
  } else if (name == "scopedSearchIndex") {
325
325
  result.capabilities.cluster.insert(
326
326
  couchbase::core::cluster_capability::search_scoped_search_index);
327
+ } else if (name == "scoreFusion") {
328
+ result.capabilities.cluster.insert(
329
+ couchbase::core::cluster_capability::search_score_fusion);
327
330
  }
328
331
  }
329
332
  }
@@ -17,6 +17,7 @@
17
17
 
18
18
  #pragma once
19
19
 
20
+ #include "core/logger/redaction.hxx"
20
21
  #include "error_map.hxx"
21
22
 
22
23
  #include <gsl/narrow>
@@ -86,7 +87,8 @@ struct traits<couchbase::core::error_map> {
86
87
  R"(skipping unknown attribute "{}" in error map for code={} and name="{}")",
87
88
  attr_val,
88
89
  code,
89
- name);
90
+ // the name of an error in the error map, not a Couchbase resource name
91
+ couchbase::core::logger::not_sensitive(name));
90
92
  }
91
93
  }
92
94
  result.errors.emplace(
@@ -21,6 +21,7 @@
21
21
 
22
22
  #include "constants.hxx"
23
23
  #include "core/logger/logger.hxx"
24
+ #include "core/logger/redaction.hxx"
24
25
  #include "core/meta/version.hxx"
25
26
  #include "core/platform/uuid.h"
26
27
  #include "core/service_type_fmt.hxx"
@@ -31,11 +32,24 @@
31
32
  #include <memory>
32
33
  #include <tao/json/value.hpp>
33
34
 
35
+ #include <array>
34
36
  #include <chrono>
37
+ #include <cstdint>
38
+ #include <optional>
35
39
  #include <utility>
36
40
 
37
41
  namespace couchbase::core::tracing
38
42
  {
43
+ auto
44
+ format_dispatch_operation_id(std::uint32_t opaque) -> std::string
45
+ {
46
+ // A uint32 in "0x<hex>" form is at most "0x" plus 8 hex digits, so a 12-byte buffer never
47
+ // overflows and the string is built without a heap allocation until the final copy out.
48
+ std::array<char, 12> buffer{};
49
+ const auto result = fmt::format_to_n(buffer.data(), buffer.size(), "0x{:x}", opaque);
50
+ return { buffer.data(), result.out };
51
+ }
52
+
39
53
  struct reported_span {
40
54
  std::chrono::microseconds duration;
41
55
  tao::json::value payload;
@@ -62,6 +76,7 @@ private:
62
76
  std::uint64_t last_server_duration_us_{ 0 };
63
77
  std::uint64_t total_server_duration_us_{ 0 };
64
78
  std::optional<std::string> operation_id_{};
79
+ std::optional<std::uint32_t> operation_id_opaque_{};
65
80
  std::optional<std::string> last_local_id_{};
66
81
  std::optional<std::string> service_{};
67
82
  std::optional<std::string> peer_hostname_{};
@@ -107,6 +122,40 @@ public:
107
122
  }
108
123
  }
109
124
 
125
+ [[nodiscard]] auto try_set_dispatch_operation_id(std::uint32_t opaque) -> bool override
126
+ {
127
+ // Capture the raw opaque; it is formatted lazily in operation_id(), and only when this span is
128
+ // actually reported (i.e. exceeds the threshold), which keeps the formatting off the hot path.
129
+ operation_id_opaque_ = opaque;
130
+ return true;
131
+ }
132
+
133
+ [[nodiscard]] auto try_set_dispatch_local_id(const std::string& local_id) -> bool override
134
+ {
135
+ // Capture directly, bypassing the tag-name string that add_tag() would materialize on the hot
136
+ // path (see request_span::try_set_dispatch_local_id).
137
+ last_local_id_ = local_id;
138
+ return true;
139
+ }
140
+
141
+ [[nodiscard]] auto try_set_dispatch_result(std::uint64_t server_duration_us,
142
+ const std::string& peer_address,
143
+ std::uint16_t peer_port) -> bool override
144
+ {
145
+ // Mirror the add_tag() bookkeeping without materializing any tag-name strings, including the
146
+ // same rule for the running total: it is accumulated only on non-dispatch spans, so a dispatch
147
+ // span records last_server_duration_us_ and leaves the total to be rolled up on its parent in
148
+ // end(). (In current wiring this setter only runs on the dispatch span, but the guard is kept
149
+ // so the two paths stay behaviourally identical.)
150
+ last_server_duration_us_ = server_duration_us;
151
+ if (name() != tracing::operation::step_dispatch) {
152
+ total_server_duration_us_ += server_duration_us;
153
+ }
154
+ peer_hostname_ = peer_address;
155
+ peer_port_ = peer_port;
156
+ return true;
157
+ }
158
+
110
159
  void end() override;
111
160
 
112
161
  void set_last_local_id(const std::string& id)
@@ -119,6 +168,11 @@ public:
119
168
  operation_id_ = id;
120
169
  }
121
170
 
171
+ void set_operation_id_opaque(std::uint32_t opaque)
172
+ {
173
+ operation_id_opaque_ = opaque;
174
+ }
175
+
122
176
  void set_peer_hostname(const std::string& hostname)
123
177
  {
124
178
  peer_hostname_ = hostname;
@@ -160,7 +214,14 @@ public:
160
214
 
161
215
  [[nodiscard]] auto operation_id() const -> std::optional<std::string>
162
216
  {
163
- return operation_id_;
217
+ if (operation_id_.has_value()) {
218
+ return operation_id_;
219
+ }
220
+ if (operation_id_opaque_.has_value()) {
221
+ // Build the string only here — on the reporting path, never on the hot path.
222
+ return format_dispatch_operation_id(operation_id_opaque_.value());
223
+ }
224
+ return {};
164
225
  }
165
226
 
166
227
  [[nodiscard]] auto last_local_id() const -> std::optional<std::string>
@@ -216,8 +277,8 @@ convert(const std::shared_ptr<threshold_logging_span>& span) -> reported_span
216
277
  entry["total_server_duration_us"] = span->total_server_duration_us();
217
278
  }
218
279
 
219
- if (span->operation_id().has_value()) {
220
- entry["last_operation_id"] = span->operation_id().value();
280
+ if (const auto operation_id = span->operation_id(); operation_id.has_value()) {
281
+ entry["last_operation_id"] = operation_id.value();
221
282
  }
222
283
 
223
284
  if (span->last_local_id().has_value()) {
@@ -321,7 +382,8 @@ private:
321
382
  queue.pop();
322
383
  }
323
384
  report["top"] = entries;
324
- CB_LOG_WARNING("Operations over threshold: {}", utils::json::generate(report));
385
+ CB_LOG_WARNING("Operations over threshold: {}",
386
+ logger::system_data(utils::json::generate(report)));
325
387
  }
326
388
  }
327
389
 
@@ -380,6 +442,10 @@ threshold_logging_span::end()
380
442
  }
381
443
  if (operation_id_.has_value()) {
382
444
  p->set_operation_id(operation_id_.value());
445
+ } else if (operation_id_opaque_.has_value()) {
446
+ // Propagate the raw opaque so the parent still reports the operation id, while keeping the
447
+ // (rarely needed) formatting deferred to the parent's reporting path.
448
+ p->set_operation_id_opaque(operation_id_opaque_.value());
383
449
  }
384
450
  if (peer_hostname_.has_value()) {
385
451
  p->set_peer_hostname(peer_hostname_.value());
@@ -23,6 +23,7 @@
23
23
 
24
24
  #include <asio/io_context.hpp>
25
25
 
26
+ #include <cstdint>
26
27
  #include <memory>
27
28
  #include <string>
28
29
 
@@ -31,6 +32,15 @@ namespace couchbase::core::tracing
31
32
  class threshold_logging_span;
32
33
  class threshold_logging_tracer_impl;
33
34
 
35
+ /**
36
+ * Format a dispatch operation identifier (the request opaque) into the "0x<hex>" form used in
37
+ * threshold reports. The built-in span captures the raw opaque on the hot path and formats it here,
38
+ * lazily, only when a span is actually reported. Declared in the header so the formatting contract
39
+ * can be unit-tested directly.
40
+ */
41
+ [[nodiscard]] auto
42
+ format_dispatch_operation_id(std::uint32_t opaque) -> std::string;
43
+
34
44
  class threshold_logging_tracer
35
45
  : public couchbase::tracing::request_tracer
36
46
  , public std::enable_shared_from_this<threshold_logging_tracer>
@@ -30,40 +30,6 @@
30
30
 
31
31
  namespace couchbase::core::transactions
32
32
  {
33
- /**
34
- * ${Mutation.CAS} is written by kvengine with
35
- * 'macroToString(htonll(info.cas))'. Discussed this with KV team and, though
36
- * there is consensus that this is off (htonll is definitely wrong, and a string
37
- * is an odd choice), there are clients (SyncGateway) that consume the current
38
- * string, so it can't be changed. Note that only little-endian servers are
39
- * supported for Couchbase, so the 8 byte long inside the string will always be
40
- * little-endian ordered.
41
- *
42
- * Looks like: "0x000058a71dd25c15"
43
- * Want: 0x155CD21DA7580000 (1539336197457313792 in base10, an epoch
44
- * time in millionths of a second)
45
- *
46
- * returns epoch time in ms
47
- */
48
- auto
49
- parse_mutation_cas(const std::string& cas) -> std::uint64_t
50
- {
51
- if (cas.empty()) {
52
- return 0;
53
- }
54
-
55
- std::uint64_t val = stoull(cas, nullptr, 16);
56
- /* byteswap */
57
- std::size_t ii = 0;
58
- std::uint64_t ret = 0;
59
- for (ii = 0; ii < sizeof(std::uint64_t); ii++) {
60
- ret <<= 8ULL;
61
- ret |= val & 0xffULL;
62
- val >>= 8ULL;
63
- }
64
- return ret / 1000000;
65
- }
66
-
67
33
  auto
68
34
  process_document_ids(const tao::json::value& entry,
69
35
  const std::string& key) -> std::optional<std::vector<doc_record>>