couchbase 3.8.2 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (473) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/ext/CMakeLists.txt +16 -1
  4. data/ext/cache/cpm/{CPM_0.42.0.cmake → CPM_0.43.1.cmake} +18 -2
  5. data/ext/cache/extconf_include.rb +6 -6
  6. data/ext/cache/mozilla-ca-bundle.crt +121 -55
  7. data/ext/cache/mozilla-ca-bundle.sha256 +1 -1
  8. data/ext/couchbase/CMakeLists.txt +130 -21
  9. data/ext/couchbase/cmake/APKBUILD.in +25 -4
  10. data/ext/couchbase/cmake/Bundler.cmake +143 -34
  11. data/ext/couchbase/cmake/CPM.cmake +126 -12
  12. data/ext/couchbase/cmake/Cache.cmake +7 -1
  13. data/ext/couchbase/cmake/CompilerOptions.cmake +1 -1
  14. data/ext/couchbase/cmake/CompilerWarnings.cmake +17 -6
  15. data/ext/couchbase/cmake/GrpcProtobuf.cmake +481 -0
  16. data/ext/couchbase/cmake/OpenSSL.cmake +10 -3
  17. data/ext/couchbase/cmake/Packaging.cmake +519 -65
  18. data/ext/couchbase/cmake/Protostellar.cmake +250 -0
  19. data/ext/couchbase/cmake/Sanitizers.cmake +61 -50
  20. data/ext/couchbase/cmake/StaticAnalyzers.cmake +16 -5
  21. data/ext/couchbase/cmake/TestFramework.cmake +283 -0
  22. data/ext/couchbase/cmake/TestFrameworkAddTests.cmake +51 -0
  23. data/ext/couchbase/cmake/Testing.cmake +27 -9
  24. data/ext/couchbase/cmake/ThirdPartyDependencies.cmake +141 -8
  25. data/ext/couchbase/cmake/VersionInfo.cmake +50 -0
  26. data/ext/couchbase/cmake/build_config.hxx.in +2 -1
  27. data/ext/couchbase/cmake/couchbase-cxx-client.spec.in +101 -23
  28. data/ext/couchbase/cmake/couchbase_cxx_client_static-config.cmake.in +7 -0
  29. data/ext/couchbase/cmake/couchbase_cxx_client_static.pc.in +2 -0
  30. data/ext/couchbase/cmake/gRPC_Generate.cmake +58 -0
  31. data/ext/couchbase/cmake/protobuf_Generate.cmake +69 -0
  32. data/ext/couchbase/cmake/require-git-checkout.cmake +25 -0
  33. data/ext/couchbase/cmake/tarball_glob.txt +49 -0
  34. data/ext/couchbase/core/agent_group.cxx +0 -8
  35. data/ext/couchbase/core/agent_group.hxx +0 -4
  36. data/ext/couchbase/core/analytics_stream.cxx +314 -0
  37. data/ext/couchbase/core/analytics_stream.hxx +129 -0
  38. data/ext/couchbase/core/analytics_stream_component.cxx +245 -0
  39. data/ext/couchbase/core/analytics_stream_component.hxx +67 -0
  40. data/ext/couchbase/core/app_telemetry_meter.cxx +25 -3
  41. data/ext/couchbase/core/app_telemetry_meter.hxx +77 -0
  42. data/ext/couchbase/core/app_telemetry_reporter.cxx +7 -6
  43. data/ext/couchbase/core/bucket.cxx +381 -87
  44. data/ext/couchbase/core/bucket.hxx +105 -25
  45. data/ext/couchbase/core/bucket_unit_test_api.hxx +57 -0
  46. data/ext/couchbase/core/capella.hxx +91 -0
  47. data/ext/couchbase/core/cluster.cxx +1554 -398
  48. data/ext/couchbase/core/cluster.hxx +39 -8
  49. data/ext/couchbase/core/cluster_agent.cxx +0 -8
  50. data/ext/couchbase/core/cluster_agent.hxx +0 -4
  51. data/ext/couchbase/core/cluster_options.hxx +26 -3
  52. data/ext/couchbase/core/collections_component.cxx +39 -15
  53. data/ext/couchbase/core/config_profiles.cxx +1 -1
  54. data/ext/couchbase/core/crud_component.cxx +2 -2
  55. data/ext/couchbase/core/crud_options.hxx +34 -0
  56. data/ext/couchbase/core/crypto/cbcrypto.cc +18 -13
  57. data/ext/couchbase/core/document_id_redaction.hxx +81 -0
  58. data/ext/couchbase/core/error_context/base_error_context.hxx +7 -6
  59. data/ext/couchbase/core/error_context/key_value.cxx +25 -2
  60. data/ext/couchbase/core/error_context/key_value.hxx +60 -33
  61. data/ext/couchbase/core/error_context/key_value_error_context.hxx +16 -15
  62. data/ext/couchbase/core/error_context/search.hxx +5 -0
  63. data/ext/couchbase/core/error_context/search_json.hxx +3 -0
  64. data/ext/couchbase/core/error_context/subdocument_error_context.hxx +19 -18
  65. data/ext/couchbase/core/error_context/view.hxx +5 -0
  66. data/ext/couchbase/core/free_form_http_request.cxx +237 -4
  67. data/ext/couchbase/core/free_form_http_request.hxx +41 -8
  68. data/ext/couchbase/core/http_component.cxx +300 -284
  69. data/ext/couchbase/core/http_component.hxx +0 -4
  70. data/ext/couchbase/core/impl/analytics.cxx +38 -5
  71. data/ext/couchbase/core/impl/analytics.hxx +34 -0
  72. data/ext/couchbase/core/impl/bootstrap_error.hxx +0 -3
  73. data/ext/couchbase/core/impl/collection.cxx +215 -202
  74. data/ext/couchbase/core/impl/collection_manager.cxx +1 -1
  75. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +45 -18
  76. data/ext/couchbase/core/impl/error.cxx +22 -2
  77. data/ext/couchbase/core/impl/internal_analytics_stream_result.hxx +111 -0
  78. data/ext/couchbase/core/impl/internal_query_stream_result.hxx +110 -0
  79. data/ext/couchbase/core/impl/invoke_with_node_id.hxx +15 -7
  80. data/ext/couchbase/core/impl/key_value_error_category.cxx +6 -0
  81. data/ext/couchbase/core/impl/lookup_in_replica.cxx +10 -10
  82. data/ext/couchbase/core/impl/lookup_in_replica.hxx +4 -4
  83. data/ext/couchbase/core/impl/node_id.cxx +49 -13
  84. data/ext/couchbase/core/impl/observability_recorder.cxx +12 -2
  85. data/ext/couchbase/core/impl/observe_poll.cxx +63 -23
  86. data/ext/couchbase/core/impl/public_analytics_stream_result.cxx +372 -0
  87. data/ext/couchbase/core/impl/public_bucket.cxx +48 -2
  88. data/ext/couchbase/core/impl/public_cluster.cxx +229 -42
  89. data/ext/couchbase/core/impl/public_query_stream_result.cxx +380 -0
  90. data/ext/couchbase/core/impl/public_transaction_get_multi_replicas_from_preferred_server_group_result.cxx +42 -0
  91. data/ext/couchbase/core/impl/public_transaction_get_multi_result.cxx +42 -0
  92. data/ext/couchbase/core/impl/query.cxx +76 -7
  93. data/ext/couchbase/core/impl/query.hxx +36 -0
  94. data/ext/couchbase/core/impl/query_index_manager.cxx +54 -1
  95. data/ext/couchbase/core/impl/replica_utils.cxx +101 -0
  96. data/ext/couchbase/core/impl/replica_utils.hxx +64 -0
  97. data/ext/couchbase/core/impl/resolve_node_id.hxx +125 -0
  98. data/ext/couchbase/core/impl/scope.cxx +70 -0
  99. data/ext/couchbase/core/impl/search.cxx +31 -1
  100. data/ext/couchbase/core/impl/transactions.cxx +130 -0
  101. data/ext/couchbase/core/impl/wait_until_ready.cxx +439 -0
  102. data/ext/couchbase/core/impl/wait_until_ready.hxx +110 -0
  103. data/ext/couchbase/core/impl/with_bucket_config_or_timeout.hxx +180 -0
  104. data/ext/couchbase/core/impl/with_cancellation.hxx +11 -3
  105. data/ext/couchbase/core/io/configuration_belongs_to_session.hxx +1 -2
  106. data/ext/couchbase/core/io/dns_client.cxx +122 -45
  107. data/ext/couchbase/core/io/dns_codec.hxx +21 -21
  108. data/ext/couchbase/core/io/dns_config.cxx +21 -6
  109. data/ext/couchbase/core/io/http_command.hxx +149 -121
  110. data/ext/couchbase/core/io/http_error.hxx +107 -0
  111. data/ext/couchbase/core/io/http_parser.cxx +4 -0
  112. data/ext/couchbase/core/io/http_session.cxx +606 -154
  113. data/ext/couchbase/core/io/http_session.hxx +147 -30
  114. data/ext/couchbase/core/io/http_session_manager.hxx +329 -382
  115. data/ext/couchbase/core/io/http_streaming_parser.cxx +4 -0
  116. data/ext/couchbase/core/io/http_streaming_response.cxx +328 -43
  117. data/ext/couchbase/core/io/http_streaming_response.hxx +37 -3
  118. data/ext/couchbase/core/io/mcbp_buffer_pool.hxx +122 -0
  119. data/ext/couchbase/core/io/mcbp_command.hxx +150 -51
  120. data/ext/couchbase/core/io/mcbp_command_id.hxx +45 -0
  121. data/ext/couchbase/core/io/mcbp_message.cxx +9 -1
  122. data/ext/couchbase/core/io/mcbp_message.hxx +19 -0
  123. data/ext/couchbase/core/io/mcbp_output_queue.hxx +150 -0
  124. data/ext/couchbase/core/io/mcbp_parser.cxx +24 -7
  125. data/ext/couchbase/core/io/mcbp_session.cxx +309 -301
  126. data/ext/couchbase/core/io/mcbp_session.hxx +27 -18
  127. data/ext/couchbase/core/io/opaque_ring_table.hxx +145 -0
  128. data/ext/couchbase/core/io/retry_orchestrator.hxx +6 -5
  129. data/ext/couchbase/core/io/stream_deadline.hxx +50 -0
  130. data/ext/couchbase/core/io/streams.cxx +151 -21
  131. data/ext/couchbase/core/io/streams.hxx +48 -1
  132. data/ext/couchbase/core/logger/logger.cxx +36 -0
  133. data/ext/couchbase/core/logger/logger.hxx +46 -6
  134. data/ext/couchbase/core/logger/redaction.hxx +503 -0
  135. data/ext/couchbase/core/management/eventing_status.hxx +10 -0
  136. data/ext/couchbase/core/management/eventing_status_json.hxx +4 -0
  137. data/ext/couchbase/core/mcbp/big_endian.cxx +1 -1
  138. data/ext/couchbase/core/mcbp/codec.cxx +27 -18
  139. data/ext/couchbase/core/mcbp/operation_queue.cxx +2 -2
  140. data/ext/couchbase/core/mcbp/packet.hxx +2 -2
  141. data/ext/couchbase/core/mcbp/queue_request.cxx +23 -6
  142. data/ext/couchbase/core/mcbp/queue_request.hxx +21 -0
  143. data/ext/couchbase/core/meta/features.hxx +13 -0
  144. data/ext/couchbase/core/meta/version.cxx +6 -3
  145. data/ext/couchbase/core/metrics/logging_meter.cxx +5 -10
  146. data/ext/couchbase/core/metrics/meter_wrapper.cxx +63 -33
  147. data/ext/couchbase/core/metrics/meter_wrapper.hxx +55 -3
  148. data/ext/couchbase/core/operations/analytics_response_parsing.cxx +177 -0
  149. data/ext/couchbase/core/operations/analytics_response_parsing.hxx +55 -0
  150. data/ext/couchbase/core/operations/document_analytics.cxx +48 -130
  151. data/ext/couchbase/core/operations/document_analytics.hxx +14 -2
  152. data/ext/couchbase/core/operations/document_get_all_replicas.hxx +15 -7
  153. data/ext/couchbase/core/operations/document_get_any_replica.hxx +19 -8
  154. data/ext/couchbase/core/operations/document_get_projected.cxx +1 -1
  155. data/ext/couchbase/core/{impl/get_replica.cxx → operations/document_get_replica.cxx} +21 -3
  156. data/ext/couchbase/core/{impl/get_replica.hxx → operations/document_get_replica.hxx} +31 -4
  157. data/ext/couchbase/core/operations/document_lookup_in.cxx +10 -10
  158. data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +228 -198
  159. data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +215 -217
  160. data/ext/couchbase/core/operations/document_query.cxx +108 -221
  161. data/ext/couchbase/core/operations/document_query.hxx +18 -4
  162. data/ext/couchbase/core/operations/document_search.cxx +52 -8
  163. data/ext/couchbase/core/operations/document_search.hxx +3 -0
  164. data/ext/couchbase/core/operations/document_view.cxx +3 -3
  165. data/ext/couchbase/core/operations/management/analytics_dataset_create.cxx +15 -8
  166. data/ext/couchbase/core/operations/management/analytics_dataset_create.hxx +4 -0
  167. data/ext/couchbase/core/operations/management/analytics_dataset_drop.cxx +11 -6
  168. data/ext/couchbase/core/operations/management/analytics_dataset_get_all.cxx +3 -2
  169. data/ext/couchbase/core/operations/management/analytics_dataverse_create.cxx +10 -5
  170. data/ext/couchbase/core/operations/management/analytics_dataverse_drop.cxx +10 -5
  171. data/ext/couchbase/core/operations/management/analytics_get_pending_mutations.cxx +2 -1
  172. data/ext/couchbase/core/operations/management/analytics_index_create.cxx +33 -8
  173. data/ext/couchbase/core/operations/management/analytics_index_drop.cxx +12 -7
  174. data/ext/couchbase/core/operations/management/analytics_index_get_all.cxx +3 -2
  175. data/ext/couchbase/core/operations/management/analytics_link_connect.cxx +11 -6
  176. data/ext/couchbase/core/operations/management/analytics_link_create.cxx +3 -3
  177. data/ext/couchbase/core/operations/management/analytics_link_disconnect.cxx +10 -4
  178. data/ext/couchbase/core/operations/management/analytics_link_drop.cxx +6 -4
  179. data/ext/couchbase/core/operations/management/analytics_link_get_all.cxx +4 -3
  180. data/ext/couchbase/core/operations/management/analytics_link_replace.cxx +3 -3
  181. data/ext/couchbase/core/operations/management/analytics_link_utils.hxx +1 -1
  182. data/ext/couchbase/core/operations/management/change_password.cxx +2 -0
  183. data/ext/couchbase/core/operations/management/collection_drop.cxx +5 -1
  184. data/ext/couchbase/core/operations/management/error_utils.cxx +59 -5
  185. data/ext/couchbase/core/operations/management/error_utils.hxx +29 -1
  186. data/ext/couchbase/core/operations/management/eventing_deploy_function.cxx +9 -3
  187. data/ext/couchbase/core/operations/management/eventing_drop_function.cxx +8 -3
  188. data/ext/couchbase/core/operations/management/eventing_get_all_functions.cxx +4 -2
  189. data/ext/couchbase/core/operations/management/eventing_get_function.cxx +5 -3
  190. data/ext/couchbase/core/operations/management/eventing_get_status.cxx +4 -2
  191. data/ext/couchbase/core/operations/management/eventing_pause_function.cxx +9 -3
  192. data/ext/couchbase/core/operations/management/eventing_resume_function.cxx +9 -3
  193. data/ext/couchbase/core/operations/management/eventing_undeploy_function.cxx +9 -3
  194. data/ext/couchbase/core/operations/management/eventing_upsert_function.cxx +9 -3
  195. data/ext/couchbase/core/operations/management/group_drop.cxx +3 -1
  196. data/ext/couchbase/core/operations/management/group_get.cxx +3 -1
  197. data/ext/couchbase/core/operations/management/group_upsert.cxx +11 -8
  198. data/ext/couchbase/core/operations/management/query_index_build.cxx +5 -2
  199. data/ext/couchbase/core/operations/management/query_index_create.cxx +9 -3
  200. data/ext/couchbase/core/operations/management/query_index_drop.cxx +11 -4
  201. data/ext/couchbase/core/operations/management/query_index_get_all.cxx +1 -1
  202. data/ext/couchbase/core/operations/management/query_index_get_all_deferred.cxx +1 -1
  203. data/ext/couchbase/core/operations/management/scope_drop.cxx +5 -1
  204. data/ext/couchbase/core/operations/management/scope_get_all.cxx +6 -1
  205. data/ext/couchbase/core/operations/management/search_get_stats.cxx +10 -0
  206. data/ext/couchbase/core/operations/management/search_index_analyze_document.cxx +3 -2
  207. data/ext/couchbase/core/operations/management/search_index_control_ingest.cxx +4 -3
  208. data/ext/couchbase/core/operations/management/search_index_control_plan_freeze.cxx +4 -3
  209. data/ext/couchbase/core/operations/management/search_index_control_query.cxx +4 -3
  210. data/ext/couchbase/core/operations/management/search_index_drop.cxx +2 -2
  211. data/ext/couchbase/core/operations/management/search_index_get.cxx +2 -2
  212. data/ext/couchbase/core/operations/management/search_index_get_documents_count.cxx +3 -2
  213. data/ext/couchbase/core/operations/management/search_index_get_stats.cxx +3 -1
  214. data/ext/couchbase/core/operations/management/search_index_upsert.cxx +2 -2
  215. data/ext/couchbase/core/operations/management/user_drop.cxx +3 -1
  216. data/ext/couchbase/core/operations/management/user_get.cxx +3 -1
  217. data/ext/couchbase/core/operations/management/user_upsert.cxx +12 -9
  218. data/ext/couchbase/core/operations/management/view_index_drop.cxx +1 -1
  219. data/ext/couchbase/core/operations/management/view_index_get.cxx +1 -1
  220. data/ext/couchbase/core/operations/management/view_index_upsert.cxx +1 -1
  221. data/ext/couchbase/core/operations/operation_traits.hxx +18 -0
  222. data/ext/couchbase/core/operations/query_response_parsing.cxx +211 -0
  223. data/ext/couchbase/core/operations/query_response_parsing.hxx +60 -0
  224. data/ext/couchbase/core/operations_fwd.hxx +3 -3
  225. data/ext/couchbase/core/origin.cxx +54 -26
  226. data/ext/couchbase/core/origin.hxx +12 -0
  227. data/ext/couchbase/core/orphan_reporter.cxx +2 -1
  228. data/ext/couchbase/core/platform/random.cc +7 -7
  229. data/ext/couchbase/core/protocol/client_request.cxx +2 -2
  230. data/ext/couchbase/core/protocol/client_request.hxx +38 -21
  231. data/ext/couchbase/core/protocol/client_response.cxx +11 -3
  232. data/ext/couchbase/core/protocol/client_response.hxx +27 -6
  233. data/ext/couchbase/core/protocol/cmd_append.cxx +2 -2
  234. data/ext/couchbase/core/protocol/cmd_cluster_map_change_notification.cxx +2 -2
  235. data/ext/couchbase/core/protocol/cmd_decrement.cxx +6 -6
  236. data/ext/couchbase/core/protocol/cmd_get.cxx +1 -1
  237. data/ext/couchbase/core/protocol/cmd_get_and_lock.cxx +2 -2
  238. data/ext/couchbase/core/protocol/cmd_get_and_touch.cxx +2 -2
  239. data/ext/couchbase/core/protocol/cmd_get_cluster_config.cxx +6 -4
  240. data/ext/couchbase/core/protocol/cmd_get_collection_id.cxx +2 -2
  241. data/ext/couchbase/core/protocol/cmd_get_error_map.cxx +1 -1
  242. data/ext/couchbase/core/protocol/cmd_get_meta.cxx +4 -4
  243. data/ext/couchbase/core/protocol/cmd_get_replica.cxx +1 -1
  244. data/ext/couchbase/core/protocol/cmd_hello.cxx +1 -1
  245. data/ext/couchbase/core/protocol/cmd_increment.cxx +6 -6
  246. data/ext/couchbase/core/protocol/cmd_insert.cxx +4 -4
  247. data/ext/couchbase/core/protocol/cmd_lookup_in.cxx +4 -3
  248. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.cxx +4 -3
  249. data/ext/couchbase/core/protocol/cmd_mutate_in.cxx +10 -9
  250. data/ext/couchbase/core/protocol/cmd_mutate_in.hxx +10 -10
  251. data/ext/couchbase/core/protocol/cmd_observe_seqno.cxx +7 -7
  252. data/ext/couchbase/core/protocol/cmd_prepend.cxx +2 -2
  253. data/ext/couchbase/core/protocol/cmd_remove.cxx +2 -2
  254. data/ext/couchbase/core/protocol/cmd_replace.cxx +4 -4
  255. data/ext/couchbase/core/protocol/cmd_touch.cxx +1 -1
  256. data/ext/couchbase/core/protocol/cmd_upsert.cxx +4 -4
  257. data/ext/couchbase/core/protocol/datatype.hxx +118 -1
  258. data/ext/couchbase/core/protocol/frame_info_utils.cxx +1 -1
  259. data/ext/couchbase/core/protocol/magic.hxx +4 -0
  260. data/ext/couchbase/core/protocol/magic_fmt.hxx +3 -0
  261. data/ext/couchbase/core/protocol/server_request.hxx +3 -1
  262. data/ext/couchbase/core/protocol/status.cxx +1 -1
  263. data/ext/couchbase/core/protostellar/analytics_converter.hxx +171 -0
  264. data/ext/couchbase/core/protostellar/bucket_admin_converter.hxx +301 -0
  265. data/ext/couchbase/core/protostellar/collection_admin_converter.hxx +92 -0
  266. data/ext/couchbase/core/protostellar/component.cxx +2445 -0
  267. data/ext/couchbase/core/protostellar/component.hxx +391 -0
  268. data/ext/couchbase/core/{columnar/bootstrap_notification_subscriber.hxx → protostellar/compression_settings.hxx} +11 -10
  269. data/ext/couchbase/core/protostellar/credentials.cxx +233 -0
  270. data/ext/couchbase/core/protostellar/credentials.hxx +88 -0
  271. data/ext/couchbase/core/protostellar/dispatcher.cxx +57 -0
  272. data/ext/couchbase/core/protostellar/dispatcher.hxx +482 -0
  273. data/ext/couchbase/core/protostellar/error_utils.cxx +293 -0
  274. data/ext/couchbase/core/protostellar/error_utils.hxx +97 -0
  275. data/ext/couchbase/core/protostellar/json_payload.hxx +49 -0
  276. data/ext/couchbase/core/protostellar/kv_converter.cxx +70 -0
  277. data/ext/couchbase/core/protostellar/kv_converter.hxx +600 -0
  278. data/ext/couchbase/core/protostellar/query_converter.hxx +265 -0
  279. data/ext/couchbase/core/protostellar/query_index_admin_converter.hxx +291 -0
  280. data/ext/couchbase/core/protostellar/query_proto.hxx +73 -0
  281. data/ext/couchbase/core/protostellar/search_converter.hxx +244 -0
  282. data/ext/couchbase/core/protostellar/search_index_admin_converter.hxx +156 -0
  283. data/ext/couchbase/core/protostellar/view_converter.hxx +158 -0
  284. data/ext/couchbase/core/query_stream.cxx +447 -0
  285. data/ext/couchbase/core/query_stream.hxx +141 -0
  286. data/ext/couchbase/core/query_stream_component.cxx +243 -0
  287. data/ext/couchbase/core/query_stream_component.hxx +68 -0
  288. data/ext/couchbase/core/range_scan_load_balancer.cxx +15 -8
  289. data/ext/couchbase/core/range_scan_orchestrator.cxx +15 -3
  290. data/ext/couchbase/core/response_handler.hxx +41 -4
  291. data/ext/couchbase/core/row_streamer.cxx +332 -46
  292. data/ext/couchbase/core/row_streamer.hxx +31 -1
  293. data/ext/couchbase/core/row_streamer_options.hxx +55 -0
  294. data/ext/couchbase/core/sasl/client.h +3 -0
  295. data/ext/couchbase/core/search_scoring.hxx +66 -0
  296. data/ext/couchbase/core/stream_error_details.hxx +69 -0
  297. data/ext/couchbase/core/timeout_defaults.hxx +0 -1
  298. data/ext/couchbase/core/topology/capabilities.hxx +6 -0
  299. data/ext/couchbase/core/topology/capabilities_fmt.hxx +3 -0
  300. data/ext/couchbase/core/topology/configuration.cxx +21 -6
  301. data/ext/couchbase/core/topology/configuration.hxx +29 -8
  302. data/ext/couchbase/core/topology/configuration_json.hxx +3 -0
  303. data/ext/couchbase/core/topology/error_map_json.hxx +3 -1
  304. data/ext/couchbase/core/tracing/threshold_logging_tracer.cxx +70 -4
  305. data/ext/couchbase/core/tracing/threshold_logging_tracer.hxx +10 -0
  306. data/ext/couchbase/core/transactions/active_transaction_record.cxx +0 -34
  307. data/ext/couchbase/core/transactions/attempt_context_impl.cxx +108 -63
  308. data/ext/couchbase/core/transactions/attempt_context_impl.hxx +19 -2
  309. data/ext/couchbase/core/transactions/error_list.hxx +2 -2
  310. data/ext/couchbase/core/transactions/get_multi_fetch.hxx +160 -0
  311. data/ext/couchbase/core/transactions/get_multi_orchestrator.cxx +326 -125
  312. data/ext/couchbase/core/transactions/get_multi_transaction_id.hxx +62 -0
  313. data/ext/couchbase/core/transactions/internal/atr_entry.hxx +22 -2
  314. data/ext/couchbase/core/transactions/internal/transaction_context.hxx +2 -2
  315. data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +23 -1
  316. data/ext/couchbase/core/transactions/internal/utils.hxx +50 -14
  317. data/ext/couchbase/core/transactions/staged_mutation.cxx +23 -18
  318. data/ext/couchbase/core/transactions/staged_mutation.hxx +15 -4
  319. data/ext/couchbase/core/transactions/transaction_context.cxx +55 -40
  320. data/ext/couchbase/core/transactions/transaction_get_result.hxx +16 -0
  321. data/ext/couchbase/core/transactions/transactions.cxx +3 -55
  322. data/ext/couchbase/core/transactions/transactions_cleanup.cxx +165 -72
  323. data/ext/couchbase/core/transactions/transactions_config.cxx +0 -11
  324. data/ext/couchbase/core/transactions/utils.cxx +10 -0
  325. data/ext/couchbase/core/transactions/waitable_op_list.hxx +2 -2
  326. data/ext/couchbase/core/transactions.hxx +9 -9
  327. data/ext/couchbase/core/utils/byteswap.hxx +166 -9
  328. data/ext/couchbase/core/utils/connection_string.cxx +50 -85
  329. data/ext/couchbase/core/utils/connection_string.hxx +15 -0
  330. data/ext/couchbase/core/{columnar/backoff_calculator.hxx → utils/deadline.hxx} +13 -13
  331. data/ext/couchbase/core/utils/duration_parser.cxx +1 -1
  332. data/ext/couchbase/core/utils/json_streaming_lexer.cxx +48 -5
  333. data/ext/couchbase/core/utils/json_streaming_lexer.hxx +4 -1
  334. data/ext/couchbase/core/utils/movable_function.hxx +301 -52
  335. data/ext/couchbase/core/utils/name_codec.hxx +154 -11
  336. data/ext/couchbase/core/{columnar/retry_info.hxx → utils/process_id.hxx} +18 -13
  337. data/ext/couchbase/core/utils/url_codec.cxx +12 -51
  338. data/ext/couchbase/core/websocket_codec.cxx +3 -29
  339. data/ext/couchbase/couchbase/analytics_options.hxx +21 -10
  340. data/ext/couchbase/couchbase/analytics_row.hxx +105 -0
  341. data/ext/couchbase/couchbase/analytics_stream_result.hxx +266 -0
  342. data/ext/couchbase/couchbase/boolean_query.hxx +3 -3
  343. data/ext/couchbase/couchbase/bucket.hxx +57 -0
  344. data/ext/couchbase/couchbase/cluster.hxx +183 -5
  345. data/ext/couchbase/{core/columnar/security_options.hxx → couchbase/cluster_state.hxx} +18 -14
  346. data/ext/couchbase/couchbase/codec/lenient_json_transcoder.hxx +69 -0
  347. data/ext/couchbase/couchbase/collection.hxx +234 -14
  348. data/ext/couchbase/couchbase/common_durability_options.hxx +18 -3
  349. data/ext/couchbase/couchbase/conjunction_query.hxx +1 -1
  350. data/ext/couchbase/couchbase/create_dataset_analytics_options.hxx +6 -1
  351. data/ext/couchbase/couchbase/date_range_query.hxx +2 -2
  352. data/ext/couchbase/couchbase/decrement_options.hxx +1 -1
  353. data/ext/couchbase/couchbase/disjunction_query.hxx +1 -1
  354. data/ext/couchbase/couchbase/error.hxx +32 -0
  355. data/ext/couchbase/couchbase/error_codes.hxx +32 -0
  356. data/ext/couchbase/couchbase/geo_bounding_box_query.hxx +1 -1
  357. data/ext/couchbase/couchbase/geo_distance_query.hxx +1 -1
  358. data/ext/couchbase/couchbase/geo_polygon_query.hxx +1 -1
  359. data/ext/couchbase/couchbase/get_replica_options.hxx +68 -0
  360. data/ext/couchbase/couchbase/get_replica_result.hxx +5 -3
  361. data/ext/couchbase/couchbase/get_replica_strategy.hxx +161 -0
  362. data/ext/couchbase/couchbase/get_result.hxx +1 -0
  363. data/ext/couchbase/couchbase/increment_options.hxx +1 -1
  364. data/ext/couchbase/couchbase/insert_options.hxx +1 -1
  365. data/ext/couchbase/couchbase/match_phrase_query.hxx +1 -1
  366. data/ext/couchbase/couchbase/match_query.hxx +1 -1
  367. data/ext/couchbase/couchbase/mutate_in_options.hxx +3 -3
  368. data/ext/couchbase/couchbase/network_options.hxx +1 -1
  369. data/ext/couchbase/couchbase/node_id.hxx +42 -14
  370. data/ext/couchbase/couchbase/node_id_for_options.hxx +7 -1
  371. data/ext/couchbase/couchbase/node_ids_options.hxx +8 -2
  372. data/ext/couchbase/couchbase/numeric_range_query.hxx +1 -1
  373. data/ext/couchbase/couchbase/phrase_query.hxx +1 -1
  374. data/ext/couchbase/couchbase/prefix_query.hxx +1 -1
  375. data/ext/couchbase/couchbase/query_options.hxx +23 -12
  376. data/ext/couchbase/couchbase/query_row.hxx +111 -0
  377. data/ext/couchbase/couchbase/query_stream_result.hxx +302 -0
  378. data/ext/couchbase/couchbase/query_string_query.hxx +3 -3
  379. data/ext/couchbase/couchbase/regexp_query.hxx +1 -1
  380. data/ext/couchbase/couchbase/replace_options.hxx +3 -3
  381. data/ext/couchbase/couchbase/result.hxx +14 -3
  382. data/ext/couchbase/couchbase/scan_result_item.hxx +1 -0
  383. data/ext/couchbase/couchbase/scope.hxx +85 -2
  384. data/ext/couchbase/couchbase/search_options.hxx +58 -8
  385. data/ext/couchbase/couchbase/search_scoring.hxx +94 -0
  386. data/ext/couchbase/couchbase/search_scoring_none.hxx +51 -0
  387. data/ext/couchbase/couchbase/search_scoring_reciprocal_rank_fusion.hxx +88 -0
  388. data/ext/couchbase/couchbase/search_scoring_relative_score_fusion.hxx +70 -0
  389. data/ext/couchbase/couchbase/term_range_query.hxx +1 -1
  390. data/ext/couchbase/couchbase/tracing/request_span.hxx +46 -0
  391. data/ext/couchbase/couchbase/transactions/transaction_get_multi_replicas_from_preferred_server_group_result.hxx +23 -21
  392. data/ext/couchbase/couchbase/transactions/transaction_get_multi_result.hxx +24 -19
  393. data/ext/couchbase/couchbase/transactions/transaction_get_result.hxx +17 -3
  394. data/ext/couchbase/couchbase/transactions/transactions_config.hxx +4 -2
  395. data/ext/couchbase/couchbase/transactions.hxx +27 -18
  396. data/ext/couchbase/couchbase/upsert_options.hxx +3 -3
  397. data/ext/couchbase/couchbase/vector_query.hxx +1 -1
  398. data/ext/couchbase/couchbase/wait_until_ready_options.hxx +111 -0
  399. data/ext/couchbase/couchbase/wildcard_query.hxx +1 -1
  400. data/ext/extconf.rb +15 -10
  401. data/ext/rcb_analytics.cxx +82 -102
  402. data/ext/rcb_backend.cxx +42 -36
  403. data/ext/rcb_backend.hxx +2 -0
  404. data/ext/rcb_buckets.cxx +47 -59
  405. data/ext/rcb_collections.cxx +42 -52
  406. data/ext/rcb_crud.cxx +345 -224
  407. data/ext/rcb_diagnostics.cxx +117 -27
  408. data/ext/rcb_exceptions.cxx +152 -99
  409. data/ext/rcb_exceptions.hxx +25 -0
  410. data/ext/rcb_extras.cxx +18 -19
  411. data/ext/rcb_hdr_histogram.cxx +19 -4
  412. data/ext/rcb_logger.cxx +202 -27
  413. data/ext/rcb_logger.hxx +12 -0
  414. data/ext/rcb_multi.cxx +40 -40
  415. data/ext/rcb_observability.cxx +7 -5
  416. data/ext/rcb_query.cxx +99 -142
  417. data/ext/rcb_range_scan.cxx +41 -35
  418. data/ext/rcb_search.cxx +98 -99
  419. data/ext/rcb_users.cxx +36 -56
  420. data/ext/rcb_utils.cxx +100 -37
  421. data/ext/rcb_utils.hxx +287 -33
  422. data/ext/rcb_version.cxx +1 -1
  423. data/ext/rcb_views.cxx +55 -51
  424. data/lib/active_support/cache/couchbase_store.rb +77 -12
  425. data/lib/couchbase/bucket.rb +20 -0
  426. data/lib/couchbase/cluster.rb +17 -0
  427. data/lib/couchbase/collection.rb +36 -1
  428. data/lib/couchbase/errors.rb +18 -0
  429. data/lib/couchbase/fork_hooks.rb +16 -7
  430. data/lib/couchbase/get_replica_strategy.rb +89 -0
  431. data/lib/couchbase/logger.rb +1 -1
  432. data/lib/couchbase/management/analytics_index_manager.rb +15 -15
  433. data/lib/couchbase/management/bucket_manager.rb +6 -6
  434. data/lib/couchbase/management/collection_manager.rb +6 -6
  435. data/lib/couchbase/management/query_index_manager.rb +7 -7
  436. data/lib/couchbase/management/search_index_manager.rb +13 -13
  437. data/lib/couchbase/management/user_manager.rb +10 -10
  438. data/lib/couchbase/management/view_index_manager.rb +5 -5
  439. data/lib/couchbase/options.rb +174 -42
  440. data/lib/couchbase/protostellar/bucket.rb +4 -0
  441. data/lib/couchbase/protostellar/cluster.rb +4 -0
  442. data/lib/couchbase/protostellar/collection.rb +4 -0
  443. data/lib/couchbase/protostellar/error_handling.rb +2 -1
  444. data/lib/couchbase/protostellar/request.rb +1 -0
  445. data/lib/couchbase/protostellar/request_generator/kv.rb +16 -2
  446. data/lib/couchbase/protostellar/request_generator/search.rb +17 -1
  447. data/lib/couchbase/protostellar/retry/orchestrator.rb +3 -2
  448. data/lib/couchbase/protostellar/retry/strategies/fail_fast.rb +33 -0
  449. data/lib/couchbase/protostellar/retry/strategies.rb +1 -0
  450. data/lib/couchbase/search_options.rb +95 -6
  451. data/lib/couchbase/version.rb +1 -1
  452. metadata +91 -33
  453. data/ext/0001-fix-build-for-mingw-w64-ucrt-x86_64-toolchain.patch +0 -40
  454. data/ext/couchbase/core/columnar/agent.hxx +0 -71
  455. data/ext/couchbase/core/columnar/agent_config.hxx +0 -59
  456. data/ext/couchbase/core/columnar/background_bootstrap_listener.hxx +0 -42
  457. data/ext/couchbase/core/columnar/backoff_calculator.cxx +0 -62
  458. data/ext/couchbase/core/columnar/columnar_agent.cxx +0 -147
  459. data/ext/couchbase/core/columnar/columnar_agent_config.cxx +0 -48
  460. data/ext/couchbase/core/columnar/columnar_error.cxx +0 -51
  461. data/ext/couchbase/core/columnar/database_management_options.hxx +0 -56
  462. data/ext/couchbase/core/columnar/error.hxx +0 -51
  463. data/ext/couchbase/core/columnar/error_codes.cxx +0 -107
  464. data/ext/couchbase/core/columnar/error_codes.hxx +0 -75
  465. data/ext/couchbase/core/columnar/management_component.cxx +0 -300
  466. data/ext/couchbase/core/columnar/management_component.hxx +0 -56
  467. data/ext/couchbase/core/columnar/query_component.cxx +0 -523
  468. data/ext/couchbase/core/columnar/query_component.hxx +0 -57
  469. data/ext/couchbase/core/columnar/query_options.hxx +0 -59
  470. data/ext/couchbase/core/columnar/query_result.cxx +0 -130
  471. data/ext/couchbase/core/columnar/query_result.hxx +0 -78
  472. data/ext/couchbase/core/io/config_tracker.cxx +0 -687
  473. data/ext/couchbase/core/io/config_tracker.hxx +0 -123
@@ -32,8 +32,31 @@ namespace couchbase::core
32
32
  auto
33
33
  make_key_value_error_context(std::error_code ec, const document_id& id) -> key_value_error_context
34
34
  {
35
- return {
36
- {}, ec, {}, {}, 0, {}, id.key(), id.bucket(), id.scope(), id.collection(), 0, {}, {}, {}, {},
35
+ return make_key_value_error_context(ec, id, 0, {});
36
+ }
37
+
38
+ auto
39
+ make_key_value_error_context(std::error_code ec,
40
+ const document_id& id,
41
+ std::size_t retry_attempts,
42
+ std::set<retry_reason> retry_reasons) -> key_value_error_context
43
+ {
44
+ return key_value_error_context{
45
+ {},
46
+ ec,
47
+ {},
48
+ {},
49
+ retry_attempts,
50
+ std::move(retry_reasons),
51
+ id.key(),
52
+ id.bucket(),
53
+ id.scope(),
54
+ id.collection(),
55
+ 0,
56
+ {},
57
+ {},
58
+ {},
59
+ {},
37
60
  };
38
61
  }
39
62
 
@@ -30,9 +30,43 @@
30
30
 
31
31
  namespace couchbase::core
32
32
  {
33
+ /**
34
+ * Convenience overload that constructs a @ref key_value_error_context with zero retry attempts and
35
+ * an empty retry-reasons set. Delegates to the four-argument overload.
36
+ *
37
+ * @param ec Error code describing the failure.
38
+ * @param id Document identifier carrying bucket/scope/collection/key.
39
+ * @return A fully initialised @ref key_value_error_context.
40
+ *
41
+ * @since 1.0.0
42
+ * @internal
43
+ */
33
44
  auto
34
45
  make_key_value_error_context(std::error_code ec, const document_id& id) -> key_value_error_context;
35
46
 
47
+ /**
48
+ * Constructs a @ref key_value_error_context for a document-not-dispatched error path where the
49
+ * internal retry bookkeeping fields are available directly (e.g. from @ref queue_request), without
50
+ * requiring a Command/Response template instantiation.
51
+ *
52
+ * Fields that belong to the protocol exchange (opaque, status code, CAS, error-map info, extended
53
+ * error info, dispatched addresses) are left empty because no server response was received.
54
+ *
55
+ * @param ec Error code describing the failure.
56
+ * @param id Document identifier carrying bucket/scope/collection/key.
57
+ * @param retry_attempts Number of retry attempts already performed for the request.
58
+ * @param retry_reasons Set of reasons recorded during those retry attempts.
59
+ * @return A fully initialised @ref key_value_error_context.
60
+ *
61
+ * @since 1.0.0
62
+ * @internal
63
+ */
64
+ auto
65
+ make_key_value_error_context(std::error_code ec,
66
+ const document_id& id,
67
+ std::size_t retry_attempts,
68
+ std::set<retry_reason> retry_reasons) -> key_value_error_context;
69
+
36
70
  template<typename Command, typename Response>
37
71
  auto
38
72
  make_key_value_error_context(std::error_code ec,
@@ -58,43 +92,36 @@ make_key_value_error_context(std::error_code ec,
58
92
  auto retry_attempts = command->request.retries.retry_attempts();
59
93
  auto retry_reasons = command->request.retries.retry_reasons();
60
94
 
61
- // Build node_id from the session that handled this request.
62
- // The session carries the node_uuid (empty on pre-8.0 servers),
63
- // canonical hostname, and port — we use these to construct the
64
- // fallback identifier when nodeUUID is unavailable.
65
- //
66
- // Only construct a node_id once the session has actually been bound to a
67
- // concrete node: either a non-empty UUID, or a non-empty canonical
68
- // hostname *and* a non-zero canonical KV port. Otherwise the fallback
69
- // hash of ("", "", 0) would yield a truthy-but-meaningless node_id and
70
- // break the contract that a default-constructed node_id means "unknown".
95
+ // Build node_id from the session that handled this request. The session
96
+ // carries the node_uuid (empty on pre-8.0 servers), canonical hostname, and
97
+ // KV port — we feed these into internal_node_id::build, which preserves the
98
+ // "falsy = unknown" contract for not-yet-bound sessions by returning a
99
+ // default node_id when the (uuid, host, port) inputs are all empty/zero.
71
100
  couchbase::node_id dispatched_to_node_id{};
72
101
  if (command->session_) {
73
- const auto& node_uuid = command->session_->node_uuid();
74
- const auto& canonical_hostname = command->session_->canonical_hostname();
75
- const auto canonical_port = command->session_->canonical_port_number();
76
- if (!node_uuid.empty() || (!canonical_hostname.empty() && canonical_port != 0)) {
77
- dispatched_to_node_id =
78
- internal_node_id::build(node_uuid, canonical_hostname, canonical_port);
79
- }
102
+ dispatched_to_node_id = internal_node_id::build(command->session_->node_uuid(),
103
+ command->session_->canonical_hostname(),
104
+ command->session_->canonical_port_number());
80
105
  }
81
106
 
82
- return { command->id_,
83
- ec,
84
- command->last_dispatched_to_,
85
- command->last_dispatched_from_,
86
- retry_attempts,
87
- std::move(retry_reasons),
88
- std::move(dispatched_to_node_id),
89
- key,
90
- bucket,
91
- scope,
92
- collection,
93
- opaque,
94
- status,
95
- response.cas(),
96
- std::move(error_map_info),
97
- response.error_info() };
107
+ return {
108
+ command->id(),
109
+ ec,
110
+ command->last_dispatched_to_,
111
+ command->last_dispatched_from_,
112
+ retry_attempts,
113
+ std::move(retry_reasons),
114
+ std::move(dispatched_to_node_id),
115
+ key,
116
+ bucket,
117
+ scope,
118
+ collection,
119
+ opaque,
120
+ status,
121
+ response.cas(),
122
+ std::move(error_map_info),
123
+ response.error_info(),
124
+ };
98
125
  }
99
126
 
100
127
  auto
@@ -83,21 +83,22 @@ public:
83
83
  couchbase::cas cas,
84
84
  std::optional<key_value_error_map_info> error_map_info,
85
85
  std::optional<key_value_extended_error_info> extended_error_info)
86
- : base_error_context{ std::move(operation_id),
87
- ec,
88
- std::move(last_dispatched_to),
89
- std::move(last_dispatched_from),
90
- retry_attempts,
91
- std::move(retry_reasons) }
92
- , id_{ std::move(id) }
93
- , bucket_{ std::move(bucket) }
94
- , scope_{ std::move(scope) }
95
- , collection_{ std::move(collection) }
96
- , opaque_{ opaque }
97
- , status_code_{ status_code }
98
- , cas_{ cas }
99
- , error_map_info_{ std::move(error_map_info) }
100
- , extended_error_info_{ std::move(extended_error_info) }
86
+ : key_value_error_context{ std::move(operation_id),
87
+ ec,
88
+ std::move(last_dispatched_to),
89
+ std::move(last_dispatched_from),
90
+ retry_attempts,
91
+ std::move(retry_reasons),
92
+ couchbase::node_id{},
93
+ std::move(id),
94
+ std::move(bucket),
95
+ std::move(scope),
96
+ std::move(collection),
97
+ opaque,
98
+ status_code,
99
+ cas,
100
+ std::move(error_map_info),
101
+ std::move(extended_error_info) }
101
102
  {
102
103
  }
103
104
 
@@ -35,6 +35,11 @@ struct search {
35
35
  std::string query{};
36
36
  std::optional<std::string> parameters{};
37
37
 
38
+ // The message the service reported, when it reported one. Over couchbase2 this is the gRPC
39
+ // status message, which is the only error detail that transport carries -- http_status and
40
+ // http_body stay empty there.
41
+ std::string first_error_message{};
42
+
38
43
  std::string method{};
39
44
  std::string path{};
40
45
  std::uint32_t http_status{};
@@ -48,6 +48,9 @@ struct traits<couchbase::core::error_context::search> {
48
48
  if (const auto& val = ctx.parameters; val.has_value()) {
49
49
  v["parameters"] = val.value();
50
50
  }
51
+ if (!ctx.first_error_message.empty()) {
52
+ v["first_error_message"] = ctx.first_error_message;
53
+ }
51
54
  if (const auto& reasons = ctx.retry_reasons; !reasons.empty()) {
52
55
  tao::json::value reasons_json = tao::json::empty_array;
53
56
  for (const auto& reason : reasons) {
@@ -81,24 +81,25 @@ public:
81
81
  std::optional<std::string> first_error_path,
82
82
  std::optional<std::uint64_t> first_error_index,
83
83
  bool deleted)
84
- : key_value_error_context{ std::move(operation_id),
85
- ec,
86
- std::move(last_dispatched_to),
87
- std::move(last_dispatched_from),
88
- retry_attempts,
89
- std::move(retry_reasons),
90
- std::move(id),
91
- std::move(bucket),
92
- std::move(scope),
93
- std::move(collection),
94
- opaque,
95
- status_code,
96
- cas,
97
- std::move(error_map_info),
98
- std::move(extended_error_info) }
99
- , first_error_path_{ std::move(first_error_path) }
100
- , first_error_index_{ first_error_index }
101
- , deleted_{ deleted }
84
+ : subdocument_error_context{ std::move(operation_id),
85
+ ec,
86
+ std::move(last_dispatched_to),
87
+ std::move(last_dispatched_from),
88
+ retry_attempts,
89
+ std::move(retry_reasons),
90
+ couchbase::node_id{},
91
+ std::move(id),
92
+ std::move(bucket),
93
+ std::move(scope),
94
+ std::move(collection),
95
+ opaque,
96
+ status_code,
97
+ cas,
98
+ std::move(error_map_info),
99
+ std::move(extended_error_info),
100
+ std::move(first_error_path),
101
+ first_error_index,
102
+ deleted }
102
103
  {
103
104
  }
104
105
 
@@ -36,6 +36,11 @@ struct view {
36
36
  std::string view_name{};
37
37
  std::vector<std::string> query_string{};
38
38
 
39
+ // The message the service reported, when it reported one. Over couchbase2 this is the gRPC
40
+ // status message, which is the only error detail that transport carries -- http_status and
41
+ // http_body stay empty there.
42
+ std::string first_error_message{};
43
+
39
44
  std::string method{};
40
45
  std::string path{};
41
46
  std::uint32_t http_status{};
@@ -19,16 +19,25 @@
19
19
  #include "io/http_streaming_response.hxx"
20
20
  #include "utils/movable_function.hxx"
21
21
 
22
+ #include <couchbase/error_codes.hxx>
23
+
24
+ #include <asio/io_context.hpp>
25
+ #include <asio/steady_timer.hpp>
26
+
27
+ #include <chrono>
28
+
22
29
  #include <cstddef>
23
30
  #include <cstdint>
24
31
  #include <memory>
32
+ #include <mutex>
33
+ #include <optional>
25
34
  #include <string>
26
35
  #include <system_error>
27
36
  #include <utility>
28
37
 
29
38
  namespace couchbase::core
30
39
  {
31
- class http_response_impl
40
+ class http_response_impl : public std::enable_shared_from_this<http_response_impl>
32
41
  {
33
42
  public:
34
43
  http_response_impl() = default;
@@ -38,36 +47,222 @@ public:
38
47
  {
39
48
  }
40
49
 
50
+ http_response_impl(asio::io_context& io, std::string cached_data, std::size_t cached_chunk_size)
51
+ : cached_body_{ io::http_streaming_response_body{ io,
52
+ nullptr,
53
+ std::move(cached_data),
54
+ true,
55
+ cached_chunk_size } }
56
+ {
57
+ }
58
+
59
+ // Fault-injecting in-memory body (test seam): see http_response_body::create_in_memory_faulty.
60
+ http_response_impl(asio::io_context& io,
61
+ std::string fault_data,
62
+ std::size_t fault_chunk_size,
63
+ std::error_code fault_terminal_ec,
64
+ bool fault_stall)
65
+ : fault_deadline_{ std::make_shared<asio::steady_timer>(io) }
66
+ , fault_enabled_{ true }
67
+ , fault_data_{ std::move(fault_data) }
68
+ , fault_chunk_size_{ fault_chunk_size }
69
+ , fault_terminal_ec_{ fault_terminal_ec }
70
+ , fault_stall_{ fault_stall }
71
+ {
72
+ }
73
+
41
74
  [[nodiscard]] auto endpoint() const -> std::string
42
75
  {
43
- return {};
76
+ if (cached_body_ || fault_enabled_) {
77
+ return {};
78
+ }
79
+ return streaming_resp_.dispatch_info().remote_address;
80
+ }
81
+
82
+ [[nodiscard]] auto dispatch_info() const -> io::http_dispatch_info
83
+ {
84
+ if (cached_body_ || fault_enabled_) {
85
+ return {};
86
+ }
87
+ return streaming_resp_.dispatch_info();
44
88
  }
45
89
 
46
90
  [[nodiscard]] auto status_code() const -> std::uint32_t
47
91
  {
92
+ if (cached_body_) {
93
+ return 200;
94
+ }
48
95
  return streaming_resp_.status_code();
49
96
  }
50
97
 
51
98
  [[nodiscard]] auto content_length() const -> std::size_t
52
99
  {
100
+ if (cached_body_) {
101
+ return 0;
102
+ }
53
103
  if (streaming_resp_.headers().find("content-length") == streaming_resp_.headers().end()) {
54
104
  return 0;
55
105
  }
56
106
  return std::stoul(streaming_resp_.headers().at("content-length"));
57
107
  }
58
108
 
59
- void next_body(utils::movable_function<void(std::string, std::error_code)> callback)
109
+ void next_body(utils::movable_function<void(std::string, bool, std::error_code)> callback)
60
110
  {
111
+ if (fault_enabled_) {
112
+ // Handlers are invoked after the lock is dropped.
113
+ std::unique_lock<std::mutex> lock{ fault_mutex_ };
114
+ if (fault_cancelled_) {
115
+ const auto ec = fault_closed_ec_;
116
+ lock.unlock();
117
+ return callback({}, false, ec);
118
+ }
119
+ if (!fault_data_.empty()) {
120
+ std::string chunk;
121
+ if (fault_chunk_size_ == 0 || fault_data_.size() <= fault_chunk_size_) {
122
+ std::swap(chunk, fault_data_);
123
+ } else {
124
+ chunk = fault_data_.substr(0, fault_chunk_size_);
125
+ fault_data_.erase(0, fault_chunk_size_);
126
+ }
127
+ // has_more is always true here: whatever comes after the data (a stall, an injected
128
+ // terminal error, or a clean end) is delivered on a subsequent pull.
129
+ lock.unlock();
130
+ return callback(std::move(chunk), true, {});
131
+ }
132
+ if (fault_stall_) {
133
+ // Simulate a server that stopped sending mid-body: park the pull and never complete it
134
+ // until cancel() (close_body) or an expired deadline fires it.
135
+ fault_parked_ = std::move(callback);
136
+ return;
137
+ }
138
+ // Drained: no deadline is accepted from here on. The generation is bumped for the same
139
+ // reason close_body() bumps it -- cancel() does not stop a completion already queued -- so
140
+ // both drain paths supersede one identically rather than relying on fault_finished_ alone.
141
+ fault_finished_ = true;
142
+ ++fault_generation_;
143
+ fault_deadline_->cancel();
144
+ const auto ec = fault_terminal_ec_;
145
+ lock.unlock();
146
+ return callback({}, false, ec);
147
+ }
148
+ if (cached_body_) {
149
+ return cached_body_->next(std::move(callback));
150
+ }
61
151
  return streaming_resp_.body().next(std::move(callback));
62
152
  }
63
153
 
154
+ void cancel_body_deadline()
155
+ {
156
+ if (fault_enabled_) {
157
+ const std::scoped_lock lock{ fault_mutex_ };
158
+ ++fault_generation_;
159
+ fault_deadline_->cancel();
160
+ return;
161
+ }
162
+ if (cached_body_) {
163
+ return cached_body_->cancel_deadline();
164
+ }
165
+ return streaming_resp_.body().cancel_deadline();
166
+ }
167
+
168
+ auto set_body_deadline(std::chrono::time_point<std::chrono::steady_clock> deadline_tp,
169
+ io::deadline_terminal on_expiry) -> io::deadline_state
170
+ {
171
+ if (fault_enabled_) {
172
+ const std::scoped_lock lock{ fault_mutex_ };
173
+ // A seam with no bytes left and no stall is terminal before the drain branch of next_body()
174
+ // has run. The real body answers body_already_ended in the same state -- reading_complete_
175
+ // with an empty cache -- and a seam that armed instead would hold the io_context open until
176
+ // it fired. fault_finished_ is recorded here, so a close_body() after this refusal keeps the
177
+ // configured terminal, as the real body refuses a close once drained.
178
+ if (fault_data_.empty() && !fault_stall_) {
179
+ fault_finished_ = true;
180
+ }
181
+ if (fault_cancelled_ || fault_finished_) {
182
+ return io::deadline_state::body_already_ended;
183
+ }
184
+ const auto generation = ++fault_generation_;
185
+ fault_deadline_->expires_at(deadline_tp);
186
+ fault_deadline_->async_wait([self = shared_from_this(), on_expiry, generation](auto ec) {
187
+ if (ec == asio::error::operation_aborted) {
188
+ return;
189
+ }
190
+ self->close_body_at_deadline(on_expiry, generation);
191
+ });
192
+ return io::deadline_state::armed;
193
+ }
194
+ if (cached_body_) {
195
+ return cached_body_->set_deadline(deadline_tp, on_expiry);
196
+ }
197
+ return streaming_resp_.body().set_deadline(deadline_tp, on_expiry);
198
+ }
199
+
200
+ void close_body_at_deadline(io::deadline_terminal on_expiry, std::uint64_t generation)
201
+ {
202
+ utils::movable_function<void(std::string, bool, std::error_code)> parked;
203
+ {
204
+ const std::scoped_lock lock{ fault_mutex_ };
205
+ // expires_at/cancel do not stop a completion already queued; ignore a superseded one.
206
+ if (generation != fault_generation_ || fault_cancelled_ || fault_finished_) {
207
+ return;
208
+ }
209
+ fault_cancelled_ = true;
210
+ fault_closed_ec_ = io::terminal_error_code(on_expiry);
211
+ fault_deadline_->cancel();
212
+ parked = std::move(fault_parked_);
213
+ }
214
+ if (parked) {
215
+ parked({}, false, io::terminal_error_code(on_expiry));
216
+ }
217
+ }
218
+
64
219
  void close_body()
65
220
  {
221
+ if (fault_enabled_) {
222
+ std::unique_lock<std::mutex> lock{ fault_mutex_ };
223
+ // First terminal wins, as in the real body. set_body_deadline() and
224
+ // close_body_at_deadline() test the same pair; a cancel arriving after the terminal path
225
+ // unlocked would otherwise change later pulls to request_canceled.
226
+ if (fault_cancelled_ || fault_finished_) {
227
+ return;
228
+ }
229
+ fault_cancelled_ = true;
230
+ ++fault_generation_;
231
+ fault_deadline_->cancel();
232
+ auto cb = std::move(fault_parked_);
233
+ const auto ec = fault_closed_ec_;
234
+ lock.unlock();
235
+ if (cb) {
236
+ cb({}, false, ec);
237
+ }
238
+ return;
239
+ }
240
+ if (cached_body_) {
241
+ return cached_body_->close();
242
+ }
66
243
  return streaming_resp_.body().close();
67
244
  }
68
245
 
69
246
  private:
70
247
  io::http_streaming_response streaming_resp_;
248
+ std::optional<io::http_streaming_response_body> cached_body_{};
249
+ // fault_mutex_ guards every fault_* member written after construction, including the timer:
250
+ // asio timers are not safe under concurrent use. fault_enabled_ is set once by the
251
+ // constructor and read unlocked. Only the fault seam owns a timer; the other bodies forward to an
252
+ // existing one.
253
+ mutable std::mutex fault_mutex_{};
254
+ std::shared_ptr<asio::steady_timer> fault_deadline_{};
255
+ // Fault-injection test seam (see the fault-injecting ctor and create_in_memory_faulty).
256
+ bool fault_enabled_{ false };
257
+ std::string fault_data_{};
258
+ std::size_t fault_chunk_size_{ 0 };
259
+ std::error_code fault_terminal_ec_{};
260
+ bool fault_stall_{ false };
261
+ bool fault_cancelled_{ false };
262
+ bool fault_finished_{ false };
263
+ std::uint64_t fault_generation_{ 0 };
264
+ std::error_code fault_closed_ec_{ errc::common::request_canceled };
265
+ utils::movable_function<void(std::string, bool, std::error_code)> fault_parked_{};
71
266
  };
72
267
 
73
268
  class buffered_http_response_impl
@@ -116,6 +311,11 @@ http_response::endpoint() const -> std::string
116
311
  return impl_->endpoint();
117
312
  }
118
313
  auto
314
+ http_response::dispatch_info() const -> io::http_dispatch_info
315
+ {
316
+ return impl_->dispatch_info();
317
+ }
318
+ auto
119
319
  http_response::status_code() const -> std::uint32_t
120
320
  {
121
321
  return impl_->status_code();
@@ -143,6 +343,39 @@ http_response_body::http_response_body(std::shared_ptr<http_response_impl> impl)
143
343
  {
144
344
  }
145
345
 
346
+ auto
347
+ http_response_body::create_in_memory(asio::io_context& io,
348
+ std::string data,
349
+ std::size_t cached_chunk_size) -> http_response_body
350
+ {
351
+ return http_response_body{ std::make_shared<http_response_impl>(
352
+ io, std::move(data), cached_chunk_size) };
353
+ }
354
+
355
+ auto
356
+ http_response_body::create_in_memory_faulty(asio::io_context& io,
357
+ std::string data,
358
+ std::size_t cached_chunk_size,
359
+ std::error_code terminal_ec,
360
+ bool stall) -> http_response_body
361
+ {
362
+ return http_response_body{ std::make_shared<http_response_impl>(
363
+ io, std::move(data), cached_chunk_size, terminal_ec, stall) };
364
+ }
365
+
366
+ auto
367
+ http_response_body::set_deadline(std::chrono::time_point<std::chrono::steady_clock> deadline_tp,
368
+ io::deadline_terminal on_expiry) -> io::deadline_state
369
+ {
370
+ return impl_->set_body_deadline(deadline_tp, on_expiry);
371
+ }
372
+
373
+ void
374
+ http_response_body::cancel_deadline()
375
+ {
376
+ return impl_->cancel_body_deadline();
377
+ }
378
+
146
379
  void
147
380
  http_response_body::cancel()
148
381
  {
@@ -150,7 +383,7 @@ http_response_body::cancel()
150
383
  }
151
384
 
152
385
  void
153
- http_response_body::next(utils::movable_function<void(std::string, std::error_code)> callback)
386
+ http_response_body::next(utils::movable_function<void(std::string, bool, std::error_code)> callback)
154
387
  {
155
388
  return impl_->next_body(std::move(callback));
156
389
  }
@@ -15,14 +15,14 @@
15
15
 
16
16
  #pragma once
17
17
 
18
- #include <couchbase/build_config.hxx>
19
-
20
18
  #include "core/impl/bootstrap_error.hxx"
19
+ #include "core/io/http_streaming_response.hxx"
21
20
  #include "service_type.hxx"
22
21
  #include "utils/movable_function.hxx"
23
22
 
24
23
  #include <chrono>
25
24
  #include <cinttypes>
25
+ #include <cstddef>
26
26
  #include <map>
27
27
  #include <memory>
28
28
  #include <optional>
@@ -30,6 +30,11 @@
30
30
  #include <system_error>
31
31
  #include <vector>
32
32
 
33
+ namespace asio
34
+ {
35
+ class io_context;
36
+ } // namespace asio
37
+
33
38
  namespace couchbase
34
39
  {
35
40
  class retry_strategy;
@@ -78,9 +83,39 @@ class http_response_body
78
83
  public:
79
84
  explicit http_response_body(std::shared_ptr<http_response_impl> impl);
80
85
 
81
- void next(utils::movable_function<void(std::string, std::error_code)> callback);
86
+ // cached_chunk_size > 0 makes the in-memory body deliver at most that many bytes per next()
87
+ // call (a test seam simulating a socket that dribbles the response out, so back-pressure can be
88
+ // exercised); 0 delivers the whole body in one chunk.
89
+ static auto create_in_memory(asio::io_context& io,
90
+ std::string data,
91
+ std::size_t cached_chunk_size = 0) -> http_response_body;
92
+
93
+ // Test-only fault-injection seam extending create_in_memory. The body first hands out `data` (in
94
+ // cached_chunk_size-byte slices, 0 = all at once), then once that is drained:
95
+ // * if `stall` is true, the next pull never completes until cancel() or an expired deadline
96
+ // fires it, delivering request_canceled or the deadline's error respectively — this is how
97
+ // the row_streamer idle timer (and its read-only-aware timeout classification) is exercised
98
+ // deterministically; otherwise
99
+ // * the next pull's terminal carries `terminal_ec` (a simulated mid-stream transport error).
100
+ static auto create_in_memory_faulty(asio::io_context& io,
101
+ std::string data,
102
+ std::size_t cached_chunk_size,
103
+ std::error_code terminal_ec,
104
+ bool stall) -> http_response_body;
105
+
106
+ // See io::http_streaming_response_body::next: the bool is `has_more` (false marks end-of-stream).
107
+ // An empty data string with has_more==true is a valid mid-stream chunk, not the terminal.
108
+ void next(utils::movable_function<void(std::string, bool, std::error_code)> callback);
82
109
  void cancel();
83
110
 
111
+ // Closes the body with `on_expiry` at `deadline_tp`, whether or not a pull is outstanding.
112
+ // Optional.
113
+ [[nodiscard]] auto set_deadline(std::chrono::time_point<std::chrono::steady_clock> deadline_tp,
114
+ io::deadline_terminal on_expiry) -> io::deadline_state;
115
+ // See io::http_streaming_response_body::cancel_deadline: supersedes an armed deadline without
116
+ // ending the body.
117
+ void cancel_deadline();
118
+
84
119
  private:
85
120
  std::shared_ptr<http_response_impl> impl_;
86
121
  };
@@ -92,6 +127,9 @@ public:
92
127
  explicit http_response(io::http_streaming_response resp);
93
128
 
94
129
  [[nodiscard]] auto endpoint() const -> std::string;
130
+ // Where this response was dispatched. Empty for the in-memory/fault test bodies, which have no
131
+ // session behind them.
132
+ [[nodiscard]] auto dispatch_info() const -> io::http_dispatch_info;
95
133
  [[nodiscard]] auto status_code() const -> std::uint32_t;
96
134
  [[nodiscard]] auto content_length() const -> std::size_t;
97
135
 
@@ -102,13 +140,8 @@ private:
102
140
  std::shared_ptr<http_response_impl> impl_;
103
141
  };
104
142
 
105
- #ifdef COUCHBASE_CXX_CLIENT_COLUMNAR
106
- using free_form_http_request_callback =
107
- utils::movable_function<void(http_response response, couchbase::core::error_union err)>;
108
- #else
109
143
  using free_form_http_request_callback =
110
144
  utils::movable_function<void(http_response response, std::error_code ec)>;
111
- #endif
112
145
 
113
146
  class buffered_http_response_impl;
114
147