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
@@ -17,6 +17,7 @@
17
17
 
18
18
  #pragma once
19
19
 
20
+ #include <cstddef>
20
21
  #include <cstdint>
21
22
 
22
23
  namespace couchbase::core::protocol
@@ -28,6 +29,122 @@ enum class datatype : std::uint8_t {
28
29
  xattr = 0x04,
29
30
  };
30
31
 
32
+ /*
33
+ * Free-standing bitwise operators for the datatype flag set.
34
+ *
35
+ * Combining two datatypes stays inside the enum domain and yields a datatype.
36
+ * Combining a datatype with a raw protocol byte yields std::byte (in either
37
+ * operand order), because the result may carry bits outside the named values
38
+ * and therefore should not pretend to be a well-formed datatype.
39
+ */
40
+
41
+ constexpr auto
42
+ operator|(datatype lhs, datatype rhs) noexcept -> datatype
43
+ {
44
+ return static_cast<datatype>(static_cast<std::uint8_t>(lhs) | static_cast<std::uint8_t>(rhs));
45
+ }
46
+
47
+ constexpr auto
48
+ operator&(datatype lhs, datatype rhs) noexcept -> datatype
49
+ {
50
+ return static_cast<datatype>(static_cast<std::uint8_t>(lhs) & static_cast<std::uint8_t>(rhs));
51
+ }
52
+
53
+ constexpr auto
54
+ operator^(datatype lhs, datatype rhs) noexcept -> datatype
55
+ {
56
+ return static_cast<datatype>(static_cast<std::uint8_t>(lhs) ^ static_cast<std::uint8_t>(rhs));
57
+ }
58
+
59
+ constexpr auto
60
+ operator|(datatype lhs, std::byte rhs) noexcept -> std::byte
61
+ {
62
+ return static_cast<std::byte>(lhs) | rhs;
63
+ }
64
+
65
+ constexpr auto
66
+ operator|(std::byte lhs, datatype rhs) noexcept -> std::byte
67
+ {
68
+ return lhs | static_cast<std::byte>(rhs);
69
+ }
70
+
71
+ constexpr auto
72
+ operator&(datatype lhs, std::byte rhs) noexcept -> std::byte
73
+ {
74
+ return static_cast<std::byte>(lhs) & rhs;
75
+ }
76
+
77
+ constexpr auto
78
+ operator&(std::byte lhs, datatype rhs) noexcept -> std::byte
79
+ {
80
+ return lhs & static_cast<std::byte>(rhs);
81
+ }
82
+
83
+ constexpr auto
84
+ operator^(datatype lhs, std::byte rhs) noexcept -> std::byte
85
+ {
86
+ return static_cast<std::byte>(lhs) ^ rhs;
87
+ }
88
+
89
+ constexpr auto
90
+ operator^(std::byte lhs, datatype rhs) noexcept -> std::byte
91
+ {
92
+ return lhs ^ static_cast<std::byte>(rhs);
93
+ }
94
+
95
+ /*
96
+ * Type-safe flag presence test. Returns true when every bit of flag is set in
97
+ * value; using the composite flag itself as the right-hand side keeps the check
98
+ * correct even when flag carries more than one bit.
99
+ */
100
+
101
+ constexpr auto
102
+ has_flag(datatype value, datatype flag) noexcept -> bool
103
+ {
104
+ const auto masked = value & flag;
105
+ return masked == flag;
106
+ }
107
+
108
+ constexpr auto
109
+ has_flag(std::byte value, datatype flag) noexcept -> bool
110
+ {
111
+ const auto masked = value & flag;
112
+ return masked == static_cast<std::byte>(flag);
113
+ }
114
+
115
+ /*
116
+ * In-place mutators that set or clear flag bits. The flag is always a named
117
+ * datatype, while the value being modified may live in the typed enum domain or
118
+ * as a raw protocol byte.
119
+ */
120
+
121
+ constexpr void
122
+ set_flag(datatype& value, datatype flag) noexcept
123
+ {
124
+ value = value | flag;
125
+ }
126
+
127
+ constexpr void
128
+ set_flag(std::byte& value, datatype flag) noexcept
129
+ {
130
+ value = value | flag;
131
+ }
132
+
133
+ constexpr void
134
+ clear_flag(datatype& value, datatype flag) noexcept
135
+ {
136
+ // Complement the flag in the integer domain: the bitwise negation of a single
137
+ // flag is not itself a valid datatype, so it must never be cast back to the enum.
138
+ value =
139
+ static_cast<datatype>(static_cast<std::uint8_t>(value) & ~static_cast<std::uint8_t>(flag));
140
+ }
141
+
142
+ constexpr void
143
+ clear_flag(std::byte& value, datatype flag) noexcept
144
+ {
145
+ value &= ~static_cast<std::byte>(flag);
146
+ }
147
+
31
148
  constexpr auto
32
149
  is_valid_datatype(std::uint8_t code) -> bool
33
150
  {
@@ -44,6 +161,6 @@ is_valid_datatype(std::uint8_t code) -> bool
44
161
  constexpr auto
45
162
  has_json_datatype(std::uint8_t code) -> bool
46
163
  {
47
- return (code & static_cast<std::uint8_t>(datatype::json)) != 0;
164
+ return has_flag(static_cast<std::byte>(code), datatype::json);
48
165
  }
49
166
  } // namespace couchbase::core::protocol
@@ -39,7 +39,7 @@ add_durability_frame_info(std::vector<std::byte>& framing_extras,
39
39
  framing_extras.resize(extras_old_size + 1 + static_cast<std::size_t>(frame_size));
40
40
  framing_extras[extras_old_size + 0] = (frame_id << 4U) | frame_size;
41
41
  framing_extras[extras_old_size + 1] = static_cast<std::byte>(level);
42
- std::uint16_t val = utils::byte_swap(*timeout);
42
+ std::uint16_t val = utils::host_to_network(*timeout);
43
43
  memcpy(framing_extras.data() + extras_old_size + 2, &val, sizeof(val));
44
44
  } else {
45
45
  const std::byte frame_size{ 1 /* 1 for level */ };
@@ -22,6 +22,8 @@
22
22
  namespace couchbase::core::protocol
23
23
  {
24
24
  enum class magic : std::uint8_t {
25
+ /// Sentinel value for default-constructed/invalid packets (not a real wire value)
26
+ invalid = 0x00,
25
27
  /// Request packet from client to server
26
28
  client_request = 0x80,
27
29
  /// The alternative request packet containing frame extras
@@ -47,6 +49,8 @@ is_valid_magic(std::uint8_t code) -> bool
47
49
  case magic::server_request:
48
50
  case magic::server_response:
49
51
  return true;
52
+ case magic::invalid:
53
+ break;
50
54
  }
51
55
  return false;
52
56
  }
@@ -52,6 +52,9 @@ struct fmt::formatter<couchbase::core::protocol::magic> {
52
52
  case couchbase::core::protocol::magic::server_response:
53
53
  name = "server_response (0x83)";
54
54
  break;
55
+ case couchbase::core::protocol::magic::invalid:
56
+ name = "invalid (0x00)";
57
+ break;
55
58
  }
56
59
  return format_to(ctx.out(), "{}", name);
57
60
  }
@@ -104,12 +104,14 @@ public:
104
104
 
105
105
  std::uint32_t field = 0;
106
106
  memcpy(&field, header_.data() + 8, sizeof(field));
107
- body_size_ = utils::byte_swap(field);
107
+ body_size_ = utils::network_to_host(field);
108
108
  data_.resize(body_size_);
109
109
 
110
110
  memcpy(&opaque_, header_.data() + 12, sizeof(opaque_));
111
+ opaque_ = utils::network_to_host(opaque_);
111
112
 
112
113
  memcpy(&cas_, header_.data() + 16, sizeof(cas_));
114
+ cas_ = utils::network_to_host(cas_);
113
115
  }
114
116
 
115
117
  void parse_body()
@@ -65,6 +65,7 @@ map_status_code(protocol::client_opcode opcode, std::uint16_t status) -> std::er
65
65
  case key_value_status_code::invalid:
66
66
  case key_value_status_code::xattr_invalid:
67
67
  case key_value_status_code::subdoc_invalid_combo:
68
+ case key_value_status_code::subdoc_invalid_xattr_order:
68
69
  case key_value_status_code::subdoc_deleted_document_cannot_have_value:
69
70
  return errc::common::invalid_argument;
70
71
 
@@ -181,7 +182,6 @@ map_status_code(protocol::client_opcode opcode, std::uint16_t status) -> std::er
181
182
  case key_value_status_code::scope_size_limit_exceeded:
182
183
  return errc::common::quota_limited;
183
184
 
184
- case key_value_status_code::subdoc_invalid_xattr_order:
185
185
  case key_value_status_code::not_my_vbucket:
186
186
  case key_value_status_code::auth_continue:
187
187
  case key_value_status_code::range_error:
@@ -0,0 +1,171 @@
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
+ // Translates the core analytics request/response to and from the couchbase.analytics.v1 protobuf
21
+ // messages, mirroring query_converter. Rows arrive across streamed AnalyticsQueryResponse messages
22
+ // and are buffered into analytics_response::rows when no callback is provided, or delivered
23
+ // incrementally to row_callback when present; the terminal message carries the metadata.
24
+ //
25
+ // Features with no couchbase2 equivalent are reported by can_encode() so the component can surface
26
+ // feature_not_available rather than silently dropping them: the `raw` passthrough map and scoped
27
+ // analytics.
28
+ //
29
+ // Scoped analytics is refused because the schema cannot express it, not merely because it is
30
+ // unimplemented. AnalyticsQueryRequest at the pinned protostellar revision retired the field the
31
+ // older schema used for this: field 8 is `reserved // bucket_name`, and field 9 was renamed from
32
+ // `scope_name` to `analytics_scope_name` -- one analytics-scope identifier rather than the
33
+ // bucket/scope pair the core request carries in bucket_name/scope_name/scope_qualifier. Collapsing
34
+ // a two-part qualification into that single name would be a guess about which the gateway means, so
35
+ // the request is refused instead. (Vendored copies in couchbase-jvm-clients and
36
+ // couchbase-net-client still carry the older bucket_name=8/scope_name=9 shape, so a mapping cribbed
37
+ // from them would target a schema this client does not speak.)
38
+
39
+ #include "core/operations/document_analytics.hxx"
40
+ #include "core/protostellar/json_payload.hxx"
41
+
42
+ #include <couchbase/analytics_scan_consistency.hxx>
43
+
44
+ #include <couchbase/analytics/v1/analytics.pb.h>
45
+
46
+ #include <chrono>
47
+ #include <cstddef>
48
+ #include <string>
49
+ #include <utility>
50
+ #include <vector>
51
+
52
+ namespace couchbase::core::protostellar::analytics
53
+ {
54
+ namespace v1 = ::couchbase::analytics::v1;
55
+
56
+ [[nodiscard]] inline auto
57
+ can_encode(const operations::analytics_request& request) -> bool
58
+ {
59
+ return request.raw.empty() && !request.bucket_name.has_value() &&
60
+ !request.scope_name.has_value() && !request.scope_qualifier.has_value();
61
+ }
62
+
63
+ inline auto
64
+ encode(const operations::analytics_request& request) -> v1::AnalyticsQueryRequest
65
+ {
66
+ v1::AnalyticsQueryRequest proto;
67
+ proto.set_statement(request.statement);
68
+ proto.set_read_only(request.readonly);
69
+ proto.set_priority(request.priority);
70
+ if (request.client_context_id.has_value()) {
71
+ proto.set_client_context_id(*request.client_context_id);
72
+ }
73
+ if (request.scan_consistency.has_value()) {
74
+ switch (*request.scan_consistency) {
75
+ case analytics_scan_consistency::not_bounded:
76
+ proto.set_scan_consistency(
77
+ v1::AnalyticsQueryRequest_ScanConsistency_SCAN_CONSISTENCY_NOT_BOUNDED);
78
+ break;
79
+ case analytics_scan_consistency::request_plus:
80
+ proto.set_scan_consistency(
81
+ v1::AnalyticsQueryRequest_ScanConsistency_SCAN_CONSISTENCY_REQUEST_PLUS);
82
+ break;
83
+ }
84
+ }
85
+ for (const auto& parameter : request.positional_parameters) {
86
+ proto.add_positional_parameters(json_payload(parameter));
87
+ }
88
+ for (const auto& [name, value] : request.named_parameters) {
89
+ (*proto.mutable_named_parameters())[name] = json_payload(value);
90
+ }
91
+ return proto;
92
+ }
93
+
94
+ [[nodiscard]] inline auto
95
+ to_nanoseconds(const google::protobuf::Duration& duration) -> std::chrono::nanoseconds
96
+ {
97
+ return std::chrono::seconds{ duration.seconds() } + std::chrono::nanoseconds{ duration.nanos() };
98
+ }
99
+
100
+ // The gateway reports status as a lowercase string; map it onto the core enum.
101
+ [[nodiscard]] inline auto
102
+ status_from_string(const std::string& status) -> operations::analytics_response::analytics_status
103
+ {
104
+ using s = operations::analytics_response::analytics_status;
105
+ if (status == "running") {
106
+ return s::running;
107
+ }
108
+ if (status == "success") {
109
+ return s::success;
110
+ }
111
+ if (status == "errors") {
112
+ return s::errors;
113
+ }
114
+ if (status == "completed") {
115
+ return s::completed;
116
+ }
117
+ if (status == "stopped") {
118
+ return s::stopped;
119
+ }
120
+ if (status == "timeout" || status == "timedout") {
121
+ return s::timedout;
122
+ }
123
+ if (status == "closed") {
124
+ return s::closed;
125
+ }
126
+ if (status == "fatal") {
127
+ return s::fatal;
128
+ }
129
+ if (status == "aborted") {
130
+ return s::aborted;
131
+ }
132
+ return s::unknown;
133
+ }
134
+
135
+ inline void
136
+ decode_meta_data(const v1::AnalyticsQueryResponse_MetaData& proto,
137
+ operations::analytics_response::analytics_meta_data& meta)
138
+ {
139
+ meta.request_id = proto.request_id();
140
+ meta.client_context_id = proto.client_context_id();
141
+ meta.status = status_from_string(proto.status());
142
+ if (!proto.signature().empty()) {
143
+ meta.signature = proto.signature();
144
+ }
145
+ if (proto.has_metrics()) {
146
+ const auto& m = proto.metrics();
147
+ meta.metrics.elapsed_time = to_nanoseconds(m.elapsed_time());
148
+ meta.metrics.execution_time = to_nanoseconds(m.execution_time());
149
+ meta.metrics.result_count = m.result_count();
150
+ meta.metrics.result_size = m.result_size();
151
+ meta.metrics.error_count = m.error_count();
152
+ meta.metrics.processed_objects = m.processed_objects();
153
+ meta.metrics.warning_count = m.warning_count();
154
+ }
155
+ // Replaced rather than appended, matching query_converter: decode_meta_data runs once per
156
+ // MetaData message, and appending would accumulate duplicates without bound if a gateway ever
157
+ // sent more than one.
158
+ if (proto.warnings_size() > 0) {
159
+ std::vector<operations::analytics_response::analytics_problem> warnings;
160
+ warnings.reserve(static_cast<std::size_t>(proto.warnings_size()));
161
+ for (const auto& w : proto.warnings()) {
162
+ operations::analytics_response::analytics_problem problem;
163
+ problem.code = w.code();
164
+ problem.message = w.message();
165
+ warnings.push_back(std::move(problem));
166
+ }
167
+ meta.warnings = std::move(warnings);
168
+ }
169
+ }
170
+
171
+ } // namespace couchbase::core::protostellar::analytics
@@ -0,0 +1,301 @@
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
+ // Translates core bucket management settings to and from couchbase.admin.bucket.v1 (unary admin
21
+ // RPCs). The proto enums have no `unknown` sentinel, so the core `unknown` values fall back to the
22
+ // server default on encode. memcached buckets have no couchbase2 representation;
23
+ // apply_create_only_settings() returns false for them so the component surfaces
24
+ // feature_not_available.
25
+ //
26
+ // Every field the encode side writes is read back by decode_bucket(), because get-modify-update is
27
+ // the ordinary way these settings are changed: a field that decodes to a default is sent back as a
28
+ // default on the next update and silently resets the bucket.
29
+
30
+ #include "core/management/bucket_settings.hxx"
31
+ #include "core/operations/management/bucket_get_all.hxx"
32
+
33
+ #include <couchbase/durability_level.hxx>
34
+
35
+ #include <couchbase/admin/bucket/v1/bucket.pb.h>
36
+ #include <couchbase/kv/v1/kv.pb.h>
37
+
38
+ #include <cstdint>
39
+ #include <limits>
40
+ #include <optional>
41
+
42
+ namespace couchbase::core::protostellar::bucket_admin
43
+ {
44
+ namespace v1 = ::couchbase::admin::bucket::v1;
45
+ namespace mgmt = ::couchbase::core::management::cluster;
46
+
47
+ [[nodiscard]] inline auto
48
+ to_proto_durability(couchbase::durability_level level)
49
+ -> std::optional<::couchbase::kv::v1::DurabilityLevel>
50
+ {
51
+ switch (level) {
52
+ case couchbase::durability_level::none:
53
+ return std::nullopt;
54
+ case couchbase::durability_level::majority:
55
+ return ::couchbase::kv::v1::DURABILITY_LEVEL_MAJORITY;
56
+ case couchbase::durability_level::majority_and_persist_to_active:
57
+ return ::couchbase::kv::v1::DURABILITY_LEVEL_MAJORITY_AND_PERSIST_TO_ACTIVE;
58
+ case couchbase::durability_level::persist_to_majority:
59
+ return ::couchbase::kv::v1::DURABILITY_LEVEL_PERSIST_TO_MAJORITY;
60
+ }
61
+ return std::nullopt;
62
+ }
63
+
64
+ // Populate the bucket-settings fields that are mutable on both Create and Update requests.
65
+ template<typename Request>
66
+ void
67
+ apply_settings(const mgmt::bucket_settings& settings, Request& proto)
68
+ {
69
+ proto.set_bucket_name(settings.name);
70
+ // ram_quota_mb == 0 means "unset" in the core settings (create defaults it to 100, update omits
71
+ // it); only send an explicit value so an unset quota does not overwrite the server-side value.
72
+ if (settings.ram_quota_mb != 0) {
73
+ proto.set_ram_quota_mb(settings.ram_quota_mb);
74
+ }
75
+
76
+ // Omitted when the caller expressed no opinion, so the server applies its own default. Sending an
77
+ // explicit zero instead would create a bucket with no replicas on their behalf.
78
+ if (settings.num_replicas.has_value()) {
79
+ proto.set_num_replicas(*settings.num_replicas);
80
+ }
81
+ if (settings.flush_enabled.has_value()) {
82
+ proto.set_flush_enabled(*settings.flush_enabled);
83
+ }
84
+ if (settings.max_expiry.has_value()) {
85
+ proto.set_max_expiry_secs(*settings.max_expiry);
86
+ }
87
+ if (settings.minimum_durability_level.has_value()) {
88
+ if (auto durability = to_proto_durability(*settings.minimum_durability_level);
89
+ durability.has_value()) {
90
+ proto.set_minimum_durability_level(*durability);
91
+ }
92
+ }
93
+ switch (settings.eviction_policy) {
94
+ case mgmt::bucket_eviction_policy::full:
95
+ proto.set_eviction_mode(v1::EVICTION_MODE_FULL);
96
+ break;
97
+ case mgmt::bucket_eviction_policy::value_only:
98
+ proto.set_eviction_mode(v1::EVICTION_MODE_VALUE_ONLY);
99
+ break;
100
+ case mgmt::bucket_eviction_policy::no_eviction:
101
+ proto.set_eviction_mode(v1::EVICTION_MODE_NONE);
102
+ break;
103
+ case mgmt::bucket_eviction_policy::not_recently_used:
104
+ proto.set_eviction_mode(v1::EVICTION_MODE_NOT_RECENTLY_USED);
105
+ break;
106
+ case mgmt::bucket_eviction_policy::unknown:
107
+ break; // leave server default
108
+ }
109
+ switch (settings.compression_mode) {
110
+ case mgmt::bucket_compression::off:
111
+ proto.set_compression_mode(v1::COMPRESSION_MODE_OFF);
112
+ break;
113
+ case mgmt::bucket_compression::active:
114
+ proto.set_compression_mode(v1::COMPRESSION_MODE_ACTIVE);
115
+ break;
116
+ case mgmt::bucket_compression::passive:
117
+ proto.set_compression_mode(v1::COMPRESSION_MODE_PASSIVE);
118
+ break;
119
+ case mgmt::bucket_compression::unknown:
120
+ break;
121
+ }
122
+ if (settings.history_retention_collection_default.has_value()) {
123
+ proto.set_history_retention_collection_default(*settings.history_retention_collection_default);
124
+ }
125
+ if (settings.history_retention_bytes.has_value()) {
126
+ proto.set_history_retention_bytes(*settings.history_retention_bytes);
127
+ }
128
+ if (settings.history_retention_duration.has_value()) {
129
+ proto.set_history_retention_duration_secs(*settings.history_retention_duration);
130
+ }
131
+ }
132
+
133
+ // Bucket type, replica indexes, storage backend, and conflict resolution are immutable after
134
+ // creation, so they are only set on CreateBucketRequest. Returns false when the bucket type has no
135
+ // couchbase2 representation (memcached).
136
+ [[nodiscard]] inline auto
137
+ apply_create_only_settings(const mgmt::bucket_settings& settings, v1::CreateBucketRequest& proto)
138
+ -> bool
139
+ {
140
+ switch (settings.bucket_type) {
141
+ case mgmt::bucket_type::couchbase:
142
+ proto.set_bucket_type(v1::BUCKET_TYPE_COUCHBASE);
143
+ break;
144
+ case mgmt::bucket_type::unknown:
145
+ // Leave bucket_type unset so the gateway applies its server-side default rather than
146
+ // silently forcing a couchbase bucket.
147
+ break;
148
+ case mgmt::bucket_type::ephemeral:
149
+ proto.set_bucket_type(v1::BUCKET_TYPE_EPHEMERAL);
150
+ break;
151
+ case mgmt::bucket_type::memcached:
152
+ return false;
153
+ }
154
+ // A bucket must be created with a RAM quota. Core uses ram_quota_mb == 0 to mean "unset" (and
155
+ // apply_settings() omits it in that case), so mirror the classic create path and fall back to the
156
+ // historical 100 MiB default rather than sending a zero quota.
157
+ if (settings.ram_quota_mb == 0) {
158
+ proto.set_ram_quota_mb(100);
159
+ }
160
+ if (settings.replica_indexes.has_value()) {
161
+ proto.set_replica_indexes(*settings.replica_indexes);
162
+ }
163
+ switch (settings.storage_backend) {
164
+ case mgmt::bucket_storage_backend::couchstore:
165
+ proto.set_storage_backend(v1::STORAGE_BACKEND_COUCHSTORE);
166
+ break;
167
+ case mgmt::bucket_storage_backend::magma:
168
+ proto.set_storage_backend(v1::STORAGE_BACKEND_MAGMA);
169
+ break;
170
+ case mgmt::bucket_storage_backend::unknown:
171
+ break;
172
+ }
173
+ switch (settings.conflict_resolution_type) {
174
+ case mgmt::bucket_conflict_resolution::timestamp:
175
+ proto.set_conflict_resolution_type(v1::CONFLICT_RESOLUTION_TYPE_TIMESTAMP);
176
+ break;
177
+ case mgmt::bucket_conflict_resolution::sequence_number:
178
+ proto.set_conflict_resolution_type(v1::CONFLICT_RESOLUTION_TYPE_SEQUENCE_NUMBER);
179
+ break;
180
+ case mgmt::bucket_conflict_resolution::custom:
181
+ proto.set_conflict_resolution_type(v1::CONFLICT_RESOLUTION_TYPE_CUSTOM);
182
+ break;
183
+ case mgmt::bucket_conflict_resolution::unknown:
184
+ break;
185
+ }
186
+ return true;
187
+ }
188
+
189
+ // Decode one ListBucketsResponse bucket back into core settings.
190
+ [[nodiscard]] inline auto
191
+ decode_bucket(const v1::ListBucketsResponse_Bucket& proto) -> mgmt::bucket_settings
192
+ {
193
+ mgmt::bucket_settings settings;
194
+ settings.name = proto.bucket_name();
195
+ settings.ram_quota_mb = proto.ram_quota_mb();
196
+ switch (proto.bucket_type()) {
197
+ case v1::BUCKET_TYPE_EPHEMERAL:
198
+ settings.bucket_type = mgmt::bucket_type::ephemeral;
199
+ break;
200
+ default:
201
+ settings.bucket_type = mgmt::bucket_type::couchbase;
202
+ break;
203
+ }
204
+ settings.num_replicas = proto.num_replicas();
205
+ settings.flush_enabled = proto.flush_enabled();
206
+ settings.replica_indexes = proto.replica_indexes();
207
+ settings.max_expiry = proto.max_expiry_secs();
208
+ switch (proto.eviction_mode()) {
209
+ case v1::EVICTION_MODE_FULL:
210
+ settings.eviction_policy = mgmt::bucket_eviction_policy::full;
211
+ break;
212
+ case v1::EVICTION_MODE_VALUE_ONLY:
213
+ settings.eviction_policy = mgmt::bucket_eviction_policy::value_only;
214
+ break;
215
+ case v1::EVICTION_MODE_NONE:
216
+ settings.eviction_policy = mgmt::bucket_eviction_policy::no_eviction;
217
+ break;
218
+ case v1::EVICTION_MODE_NOT_RECENTLY_USED:
219
+ settings.eviction_policy = mgmt::bucket_eviction_policy::not_recently_used;
220
+ break;
221
+ default:
222
+ break;
223
+ }
224
+ switch (proto.compression_mode()) {
225
+ case v1::COMPRESSION_MODE_OFF:
226
+ settings.compression_mode = mgmt::bucket_compression::off;
227
+ break;
228
+ case v1::COMPRESSION_MODE_ACTIVE:
229
+ settings.compression_mode = mgmt::bucket_compression::active;
230
+ break;
231
+ case v1::COMPRESSION_MODE_PASSIVE:
232
+ settings.compression_mode = mgmt::bucket_compression::passive;
233
+ break;
234
+ default:
235
+ break;
236
+ }
237
+ // storage_backend and minimum_durability_level are `optional` in the response, so the plain value
238
+ // getter cannot tell an explicit couchstore (enum 0) from a field the gateway did not send. Read
239
+ // through the presence bit: absent leaves the core `unknown` / empty optional, which is what the
240
+ // gateway means by omitting it.
241
+ if (proto.has_storage_backend()) {
242
+ switch (proto.storage_backend()) {
243
+ case v1::STORAGE_BACKEND_MAGMA:
244
+ settings.storage_backend = mgmt::bucket_storage_backend::magma;
245
+ break;
246
+ case v1::STORAGE_BACKEND_COUCHSTORE:
247
+ settings.storage_backend = mgmt::bucket_storage_backend::couchstore;
248
+ break;
249
+ default:
250
+ break;
251
+ }
252
+ }
253
+ if (proto.has_minimum_durability_level()) {
254
+ switch (proto.minimum_durability_level()) {
255
+ case ::couchbase::kv::v1::DURABILITY_LEVEL_MAJORITY:
256
+ settings.minimum_durability_level = couchbase::durability_level::majority;
257
+ break;
258
+ case ::couchbase::kv::v1::DURABILITY_LEVEL_MAJORITY_AND_PERSIST_TO_ACTIVE:
259
+ settings.minimum_durability_level =
260
+ couchbase::durability_level::majority_and_persist_to_active;
261
+ break;
262
+ case ::couchbase::kv::v1::DURABILITY_LEVEL_PERSIST_TO_MAJORITY:
263
+ settings.minimum_durability_level = couchbase::durability_level::persist_to_majority;
264
+ break;
265
+ default:
266
+ break;
267
+ }
268
+ }
269
+ // conflict_resolution_type carries no presence bit on this message, unlike the two above, so an
270
+ // unset field is indistinguishable from an explicit timestamp (enum 0) and is read as one.
271
+ switch (proto.conflict_resolution_type()) {
272
+ case v1::CONFLICT_RESOLUTION_TYPE_TIMESTAMP:
273
+ settings.conflict_resolution_type = mgmt::bucket_conflict_resolution::timestamp;
274
+ break;
275
+ case v1::CONFLICT_RESOLUTION_TYPE_SEQUENCE_NUMBER:
276
+ settings.conflict_resolution_type = mgmt::bucket_conflict_resolution::sequence_number;
277
+ break;
278
+ case v1::CONFLICT_RESOLUTION_TYPE_CUSTOM:
279
+ settings.conflict_resolution_type = mgmt::bucket_conflict_resolution::custom;
280
+ break;
281
+ default:
282
+ break;
283
+ }
284
+ if (proto.has_history_retention_collection_default()) {
285
+ settings.history_retention_collection_default = proto.history_retention_collection_default();
286
+ }
287
+ // The proto carries 64 bits and the core setting holds 32. Narrowing a larger value would report
288
+ // a retention size the bucket does not have, and the usual get-modify-update cycle would then
289
+ // send that smaller number back and shrink the setting. Leaving the optional empty is what the
290
+ // encode side omits, so the server keeps its own value.
291
+ if (proto.has_history_retention_bytes() &&
292
+ proto.history_retention_bytes() <= std::numeric_limits<std::uint32_t>::max()) {
293
+ settings.history_retention_bytes = static_cast<std::uint32_t>(proto.history_retention_bytes());
294
+ }
295
+ if (proto.has_history_retention_duration_secs()) {
296
+ settings.history_retention_duration = proto.history_retention_duration_secs();
297
+ }
298
+ return settings;
299
+ }
300
+
301
+ } // namespace couchbase::core::protostellar::bucket_admin