couchbase 3.8.2 → 3.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +136 -23
  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 +82 -7
  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 +1551 -397
  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 +60 -6
  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 +13 -37
  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 +33 -1
  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
@@ -0,0 +1,503 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2024-Present Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ /*
19
+ * Log redaction annotations.
20
+ *
21
+ * The SDK never removes or obscures anything itself. It wraps sensitive values in fixed tags so
22
+ * that an external tool can strip or hash them after the fact. Three categories exist:
23
+ *
24
+ * <ud>...</ud> user data document keys and values, application usernames, query statements,
25
+ * email addresses, document xattrs
26
+ * <md>...</md> metadata cluster names, bucket/scope/collection names, design document,
27
+ * view and index names, replication stream names
28
+ * <sd>...</sd> system data IP addresses, hostnames, ports, DNS topology
29
+ *
30
+ * Usage at a log site:
31
+ *
32
+ * CB_LOG_INFO("connecting to {}", logger::system_data(host));
33
+ * CB_LOG_DEBUG("fetching {}", logger::user_data(key));
34
+ *
35
+ * Choosing a category, in order:
36
+ *
37
+ * A literal from this source takes no tag: an opcode name, a status enum, an error code, a
38
+ * duration, a retry count. It reads the same for every deployment and identifies nobody.
39
+ *
40
+ * A secret takes no tag either, because it must not be logged at all: a password, a bearer
41
+ * token, a TLS private key, a SASL payload, a session cookie. A tag would be no protection
42
+ * here, since redaction is off by default and a credential that reaches a log file has already
43
+ * left the process. There is deliberately no wrapper for this case.
44
+ *
45
+ * Otherwise the origin of the value decides. Something the application supplied is user data, a
46
+ * Couchbase resource name is metadata, a host or the network path to it is system data. A value
47
+ * that came from outside the SDK and fits none of the three is user data, because the fallback
48
+ * has to be the strictest category rather than no tag at all.
49
+ *
50
+ * A tag belongs to a log line and nowhere else, so it goes on in the log statement rather than in
51
+ * the code that produced the value. Nothing headed for the wire, into a config, or back to the
52
+ * caller may carry one, which means no getter, no to_json() and no fmt formatter for a core type
53
+ * returns a tagged value: those same functions are reached from places a tag would corrupt.
54
+ * key_value_error_context::to_json() is the case to keep in mind, since couchbase/fmt/error.hxx
55
+ * puts its output into any fmt::format("{}", error) an application writes, with no log statement
56
+ * involved. Leaving the tag to the statement also keeps a bucket name rendering the same way
57
+ * whether the statement got it from config parsing or from a user call. An accessor added to serve
58
+ * a log statement therefore returns its value bare: get_node_addresses() hands back "host:port"
59
+ * and each of the four call sites wraps it.
60
+ *
61
+ * The categories are the ones Couchbase Server's log redaction specification defines, and are not
62
+ * ours to reinterpret. The tool that consumes these tags removes only user data today; removing
63
+ * metadata and system data as well is specified but unreleased. Tagging all three regardless is
64
+ * what makes that a change in the tool rather than an audit of every log statement in the SDK, so
65
+ * a tag being inert today is not a reason to leave it off.
66
+ *
67
+ * A list of values gets one tag per entry rather than one around the whole list, so that an entry
68
+ * still matches the same value logged on its own elsewhere. There is a list form of each category,
69
+ * and it also renders the double quotes some of these lines already carry, because a tag has to sit
70
+ * inside them:
71
+ *
72
+ * CB_LOG_INFO("bootstrap nodes: [{}]",
73
+ * logger::system_data_list(addresses, logger::list_entries::quoted));
74
+ *
75
+ * A serialized document goes the other way: annotate the whole argument, or none of it, but never
76
+ * a value inside it. A tag written into a JSON string value is read back as part of that value by
77
+ * anything that parses the line, and some of what this SDK logs has a shape other tools consume --
78
+ * SDK RFC 0067 fixes the threshold and orphan reports field by field. So the tag sits outside the
79
+ * document. Note that the values inside are still escaped as described below, so this is no longer
80
+ * byte-identical. It is still safe for a consumer that parses the line, because both escapes are
81
+ * JSON's own: "\n" is how JSON spells a newline inside a string, where a literal one is illegal,
82
+ * and "\u003c" is a legal escape for "<". A parser therefore reconstructs the original value
83
+ * exactly, which is what SDK RFC 0067 consumers depend on:
84
+ *
85
+ * CB_LOG_WARNING("Operations over threshold: {}",
86
+ * logger::system_data(utils::json::generate(report)));
87
+ *
88
+ * One tag then has to carry values that may span categories, so pick the strictest category any
89
+ * value inside the document could belong to. The whole document hashes as a single token either
90
+ * way, so what a coarse span costs is diagnosability, not protection. "None of it" is the other
91
+ * legitimate answer, and it is the one the configuration dumps below take.
92
+ *
93
+ * The same holds outside a serialized document: a value that mixes categories takes one tag,
94
+ * around the whole value, at the strictest category it contains. A connection string carries a
95
+ * hostname, a bucket name and a username at once, and an HTTP request path can carry a view's
96
+ * start_key, so both are tagged whole as user data. Reaching inside a value to tag only the part
97
+ * of it that is sensitive is where this feature gets implemented wrong: the boundaries move with
98
+ * the format, and a miss is silent.
99
+ *
100
+ * Two things must never appear inside a tagged value, and the wrappers remove both while redaction
101
+ * is enabled, so that no call site has to remember.
102
+ *
103
+ * A newline. The tool that consumes these tags is line-oriented, so a value that spans lines leaves
104
+ * its opening tag and its closing tag on different lines; the tool reports an unmatched tag and
105
+ * passes the value through in clear text, which is the one failure mode this whole mechanism exists
106
+ * to prevent. Newlines and carriage returns become "\n" and "\r". The values most likely to span
107
+ * lines are HTTP bodies and serialized documents, which is to say exactly the ones that must not
108
+ * leak.
109
+ *
110
+ * A tag sequence. A value containing "</ud>" closes its own span early, and the rest of it is then
111
+ * outside any tag. This is not an attack -- whoever controls the value already knows it -- but it
112
+ * is a silent failure: an application whose document happens to contain one of these sequences
113
+ * hands out a log it believes was redacted. Only the "<" of such a sequence is escaped, and only
114
+ * when it really begins one, so ordinary markup in a logged body stays readable.
115
+ *
116
+ * The exclusion markers below escape neither, because the whole point of not_redacted() is to show
117
+ * the bytes as they are.
118
+ *
119
+ * One shape stays untagged for the opposite reason. A hex dump written with the "{:a}" spec
120
+ * renders as a multi-line grid, so escaping would keep the tag intact but flatten the dump into a
121
+ * single line of "\n" literals, and a flattened hex dump is not a hex dump. So a hex dump is never
122
+ * tagged, and the checker rejects a tag around one. The dumps left in the tree are frame headers
123
+ * and raw socket reads, neither of which carries application data, so they are passed bare rather
124
+ * than marked; the one that could have carried a document body was removed instead of annotated.
125
+ *
126
+ * `bin/check-log-annotations` cannot help with the general case. Whether a value contains a
127
+ * newline is a property of the value at run time, not of the source.
128
+ *
129
+ * Qualify the calls as above. In particular `metadata` is also a member function on several core
130
+ * types (query_result, row_streamer, transaction_get_result), where an unqualified call would
131
+ * resolve to the member instead. In a file whose enclosing namespace is `couchbase` rather than
132
+ * `couchbase::core`, write `core::logger::` instead: a plain `logger::` there finds the public
133
+ * `couchbase::logger` from <couchbase/logger.hxx>, which has none of these functions.
134
+ *
135
+ * When redaction is disabled the wrappers format exactly as the underlying value, so annotating a
136
+ * log statement never changes its output for users who have not opted in.
137
+ *
138
+ * These wrappers hold a reference to the value and are only valid within the enclosing
139
+ * full-expression. That is always the case inside a CB_LOG_* macro. Do not store one:
140
+ *
141
+ * auto tagged = logger::user_data(build_key()); // DANGLING - build_key() is destroyed here
142
+ *
143
+ * Note that CB_LOG_*_RAW bypasses fmt entirely and cannot carry annotations, and CB_LOG_PROTOCOL
144
+ * is deliberately not redacted. The configuration dumps behind the dump_configuration option are
145
+ * left unannotated for the same reason: both exist to show exactly what crossed the wire, and both
146
+ * are opt-in debugging aids rather than something a deployment leaves on. Each of those sites says
147
+ * so with logger::not_redacted(), so the choice is visible where the dump is written.
148
+ *
149
+ * `bin/check-log-annotations` reports log arguments that look sensitive but are not wrapped. It is
150
+ * a heuristic over argument names, so it suggests rather than decides. It cannot see a value that
151
+ * was tagged anywhere other than the log site, which is why the list forms above exist as named
152
+ * wrappers rather than as a helper per file: the checker recognises the name and counts the
153
+ * argument as annotated, instead of having to be told to look away from it.
154
+ *
155
+ * Two wrappers record a reviewed exclusion:
156
+ *
157
+ * logger::not_sensitive(value) the identifier suggests a category the value does not belong to
158
+ * logger::not_redacted(value) sensitive, and deliberately logged untagged anyway
159
+ *
160
+ * Neither changes what is printed. Prefer them to the `no-redact` comment the checker also honours,
161
+ * which silences a whole log statement and so also silences arguments added to it later.
162
+ */
163
+
164
+ #pragma once
165
+
166
+ #include "logger.hxx"
167
+
168
+ #include <spdlog/fmt/bundled/core.h>
169
+ #include <spdlog/fmt/bundled/format.h>
170
+
171
+ #include <cstddef>
172
+ #include <string>
173
+ #include <string_view>
174
+
175
+ namespace couchbase::core::logger
176
+ {
177
+
178
+ template<typename T>
179
+ struct redacted_user_data {
180
+ const T& value;
181
+ };
182
+
183
+ template<typename T>
184
+ struct redacted_meta_data {
185
+ const T& value;
186
+ };
187
+
188
+ template<typename T>
189
+ struct redacted_system_data {
190
+ const T& value;
191
+ };
192
+
193
+ template<typename T>
194
+ struct conditionally_redacted_user_data {
195
+ const T& value;
196
+ bool sensitive;
197
+ };
198
+
199
+ template<typename T>
200
+ struct not_sensitive_value {
201
+ const T& value;
202
+ };
203
+
204
+ template<typename T>
205
+ struct not_redacted_value {
206
+ const T& value;
207
+ };
208
+
209
+ /**
210
+ * Tag a value as user data (<ud>): document keys and values, application usernames, query
211
+ * statements, email addresses, document xattrs.
212
+ */
213
+ template<typename T>
214
+ auto
215
+ user_data(const T& value)
216
+ {
217
+ return redacted_user_data<T>{ value };
218
+ }
219
+
220
+ /**
221
+ * Tag a value as metadata (<md>): cluster, bucket, scope and collection names, design document,
222
+ * view and index names, and other Couchbase resource names.
223
+ */
224
+ template<typename T>
225
+ auto
226
+ metadata(const T& value)
227
+ {
228
+ return redacted_meta_data<T>{ value };
229
+ }
230
+
231
+ /**
232
+ * Tag a value as system data (<sd>): IP addresses, hostnames, ports and DNS topology.
233
+ */
234
+ template<typename T>
235
+ auto
236
+ system_data(const T& value)
237
+ {
238
+ return redacted_system_data<T>{ value };
239
+ }
240
+
241
+ /**
242
+ * Tag a value as user data (<ud>) only when `sensitive` holds, and print it unchanged otherwise.
243
+ *
244
+ * For an argument that is sensitive on one branch of a log statement and a constant on another.
245
+ * Tagging the constant hashes it to a fixed digest, which protects nothing -- the domain is one
246
+ * value, so anyone holding the salt recovers it immediately -- and costs the reader the diagnostic
247
+ * the constant was there to give. A body the SDK elided to "[hidden]" and a body it redacted are
248
+ * then indistinguishable in the output.
249
+ */
250
+ template<typename T>
251
+ auto
252
+ user_data_if(bool sensitive, const T& value)
253
+ {
254
+ return conditionally_redacted_user_data<T>{ value, sensitive };
255
+ }
256
+
257
+ /**
258
+ * Mark a value the annotation checker flags but that is not sensitive, because the identifier
259
+ * suggests a category the value does not belong to. Formats exactly as the value would unwrapped,
260
+ * so this is an assertion for the reader and for the checker rather than a change in behaviour.
261
+ */
262
+ template<typename T>
263
+ auto
264
+ not_sensitive(const T& value)
265
+ {
266
+ return not_sensitive_value<T>{ value };
267
+ }
268
+
269
+ /**
270
+ * Mark a sensitive value that is deliberately logged without a tag, because wrapping it here is
271
+ * either not possible or not wanted. Formats exactly as the value would unwrapped. Unlike
272
+ * not_sensitive() this asserts nothing about the content, so say at the call site why the value
273
+ * carries no tag, and reference a ticket when the answer is that it eventually should.
274
+ */
275
+ template<typename T>
276
+ auto
277
+ not_redacted(const T& value)
278
+ {
279
+ return not_redacted_value<T>{ value };
280
+ }
281
+
282
+ /**
283
+ * Whether the entries of a tagged list render inside double quotes. The tag sits inside the quotes,
284
+ * never around them: a span that swallows the punctuation hashes to something matching no other
285
+ * line in the log.
286
+ */
287
+ enum class list_entries {
288
+ bare,
289
+ quoted,
290
+ };
291
+
292
+ namespace detail
293
+ {
294
+ /*
295
+ * The tag sequences themselves, which must not survive inside a tagged value: a value carrying one
296
+ * would close its own span early, and whatever followed would sit outside any tag.
297
+ */
298
+ inline constexpr std::string_view tag_sequences[]{
299
+ "<ud>", "</ud>", "<md>", "</md>", "<sd>", "</sd>",
300
+ };
301
+
302
+ constexpr auto
303
+ opens_tag_sequence(std::string_view value) -> bool
304
+ {
305
+ for (const auto sequence : tag_sequences) {
306
+ if (value.substr(0, sequence.size()) == sequence) {
307
+ return true;
308
+ }
309
+ }
310
+ return false;
311
+ }
312
+
313
+ /*
314
+ * Replace what would otherwise break the span around a value.
315
+ *
316
+ * A newline splits it: the consumer of these tags is line-oriented, so an embedded newline leaves
317
+ * the opening tag and the closing tag on different lines, and the value is then passed through
318
+ * untouched instead of being redacted. A tag sequence inside the value closes the span early, with
319
+ * the same result for whatever follows it. Only the "<" of such a sequence is escaped, which is
320
+ * enough to break it; escaping it to "\<" would not be, because "\</ud>" still contains "</ud>".
321
+ *
322
+ * A "<" that does not begin a tag sequence is left alone, so ordinary markup in a logged body is
323
+ * still readable.
324
+ */
325
+ template<typename OutputIt>
326
+ auto
327
+ write_escaped(OutputIt out, std::string_view value) -> OutputIt
328
+ {
329
+ // std::copy is deliberately not used here. fmt's appender does not satisfy MSVC's
330
+ // iterator_traits requirements, so std::copy over it fails to compile on Windows.
331
+ std::size_t copied = 0;
332
+ for (std::size_t index = 0; index < value.size(); ++index) {
333
+ std::string_view replacement{};
334
+ switch (value[index]) {
335
+ case '\n':
336
+ replacement = "\\n";
337
+ break;
338
+ case '\r':
339
+ replacement = "\\r";
340
+ break;
341
+ case '<':
342
+ if (!opens_tag_sequence(value.substr(index))) {
343
+ continue;
344
+ }
345
+ replacement = "\\u003c";
346
+ break;
347
+ default:
348
+ continue;
349
+ }
350
+ out = fmt::format_to(out, "{}{}", value.substr(copied, index - copied), replacement);
351
+ copied = index + 1;
352
+ }
353
+ return fmt::format_to(out, "{}", value.substr(copied));
354
+ }
355
+
356
+ template<typename Container, typename Wrap>
357
+ auto
358
+ tagged_list(const Container& values, list_entries entries, std::string_view separator, Wrap wrap)
359
+ -> std::string
360
+ {
361
+ std::string result;
362
+ auto first = true;
363
+ for (const auto& value : values) {
364
+ if (!first) {
365
+ result.append(separator);
366
+ }
367
+ first = false;
368
+ if (entries == list_entries::quoted) {
369
+ result.append(fmt::format(R"("{}")", wrap(value)));
370
+ } else {
371
+ result.append(fmt::format("{}", wrap(value)));
372
+ }
373
+ }
374
+ return result;
375
+ }
376
+ } // namespace detail
377
+
378
+ /*
379
+ * Tag every entry of a container and join them, so a list correlates entry by entry. One tag around
380
+ * the joined string would hash the whole list as a single token, matching nothing else in the log,
381
+ * not even the same value logged beside it in a span of its own.
382
+ *
383
+ * Unlike the wrappers above, these return a std::string rather than a view of the value, because
384
+ * there is nothing to view: the tagged entries do not exist until they are built. Call them inside
385
+ * the CB_LOG_* argument list, so they stay as lazy as the statement that needs them.
386
+ */
387
+
388
+ /**
389
+ * Tag each entry of a container as user data (<ud>) and join them.
390
+ */
391
+ template<typename Container>
392
+ auto
393
+ user_data_list(const Container& values,
394
+ list_entries entries = list_entries::bare,
395
+ std::string_view separator = ", ") -> std::string
396
+ {
397
+ return detail::tagged_list(values, entries, separator, [](const auto& value) {
398
+ return user_data(value);
399
+ });
400
+ }
401
+
402
+ /**
403
+ * Tag each entry of a container as metadata (<md>) and join them.
404
+ */
405
+ template<typename Container>
406
+ auto
407
+ metadata_list(const Container& values,
408
+ list_entries entries = list_entries::bare,
409
+ std::string_view separator = ", ") -> std::string
410
+ {
411
+ return detail::tagged_list(values, entries, separator, [](const auto& value) {
412
+ return metadata(value);
413
+ });
414
+ }
415
+
416
+ /**
417
+ * Tag each entry of a container as system data (<sd>) and join them.
418
+ */
419
+ template<typename Container>
420
+ auto
421
+ system_data_list(const Container& values,
422
+ list_entries entries = list_entries::bare,
423
+ std::string_view separator = ", ") -> std::string
424
+ {
425
+ return detail::tagged_list(values, entries, separator, [](const auto& value) {
426
+ return system_data(value);
427
+ });
428
+ }
429
+
430
+ } // namespace couchbase::core::logger
431
+
432
+ #ifndef COUCHBASE_CXX_CLIENT_DOXYGEN
433
+ /*
434
+ * The formatters inherit parse() from the underlying formatter, so format specifications keep
435
+ * working. Note that a specification applies to the value only, so "{:>10}" pads inside the tags.
436
+ */
437
+ #define COUCHBASE_LOGGER_REDACTION_FORMATTER(wrapper, tag) \
438
+ template<typename T> \
439
+ struct fmt::formatter<couchbase::core::logger::wrapper<T>> : fmt::formatter<T> { \
440
+ template<typename FormatContext> \
441
+ auto format(const couchbase::core::logger::wrapper<T>& redacted, FormatContext& ctx) const \
442
+ { \
443
+ if (!couchbase::core::logger::is_log_redaction_enabled()) { \
444
+ return fmt::formatter<T>::format(redacted.value, ctx); \
445
+ } \
446
+ fmt::memory_buffer buffer; \
447
+ /* The caller's arguments come along: a dynamic specification such as "{:{}}" resolves its \
448
+ * width through the context, so an empty argument store would throw here while the \
449
+ * unredacted branch worked. */ \
450
+ fmt::basic_format_context<fmt::appender, char> buffered{ fmt::appender(buffer), \
451
+ ctx.args(), \
452
+ ctx.locale() }; \
453
+ fmt::formatter<T>::format(redacted.value, buffered); \
454
+ ctx.advance_to(fmt::format_to(ctx.out(), "<" tag ">")); \
455
+ ctx.advance_to(couchbase::core::logger::detail::write_escaped( \
456
+ ctx.out(), std::string_view{ buffer.data(), buffer.size() })); \
457
+ return fmt::format_to(ctx.out(), "</" tag ">"); \
458
+ } \
459
+ }
460
+
461
+ COUCHBASE_LOGGER_REDACTION_FORMATTER(redacted_user_data, "ud");
462
+ COUCHBASE_LOGGER_REDACTION_FORMATTER(redacted_meta_data, "md");
463
+ COUCHBASE_LOGGER_REDACTION_FORMATTER(redacted_system_data, "sd");
464
+
465
+ #undef COUCHBASE_LOGGER_REDACTION_FORMATTER
466
+
467
+ /*
468
+ * Reuses the <ud> formatter for the tagged branch rather than repeating it, so the two cannot
469
+ * drift apart on escaping or on what a disabled redaction level prints.
470
+ */
471
+ template<typename T>
472
+ struct fmt::formatter<couchbase::core::logger::conditionally_redacted_user_data<T>>
473
+ : fmt::formatter<couchbase::core::logger::redacted_user_data<T>> {
474
+ template<typename FormatContext>
475
+ auto format(const couchbase::core::logger::conditionally_redacted_user_data<T>& redacted,
476
+ FormatContext& ctx) const
477
+ {
478
+ if (!redacted.sensitive) {
479
+ return fmt::formatter<T>::format(redacted.value, ctx);
480
+ }
481
+ return fmt::formatter<couchbase::core::logger::redacted_user_data<T>>::format(
482
+ couchbase::core::logger::redacted_user_data<T>{ redacted.value }, ctx);
483
+ }
484
+ };
485
+
486
+ /*
487
+ * The exclusion markers print their value and nothing else, whether or not redaction is enabled.
488
+ */
489
+ #define COUCHBASE_LOGGER_EXCLUSION_FORMATTER(wrapper) \
490
+ template<typename T> \
491
+ struct fmt::formatter<couchbase::core::logger::wrapper<T>> : fmt::formatter<T> { \
492
+ template<typename FormatContext> \
493
+ auto format(const couchbase::core::logger::wrapper<T>& marked, FormatContext& ctx) const \
494
+ { \
495
+ return fmt::formatter<T>::format(marked.value, ctx); \
496
+ } \
497
+ }
498
+
499
+ COUCHBASE_LOGGER_EXCLUSION_FORMATTER(not_sensitive_value);
500
+ COUCHBASE_LOGGER_EXCLUSION_FORMATTER(not_redacted_value);
501
+
502
+ #undef COUCHBASE_LOGGER_EXCLUSION_FORMATTER
503
+ #endif
@@ -54,6 +54,16 @@ enum class function_status {
54
54
  * The function is currently being paused.
55
55
  */
56
56
  pausing,
57
+
58
+ /**
59
+ * The function is currently being resumed, after having been paused.
60
+ */
61
+ resuming,
62
+
63
+ /**
64
+ * The server reported an unrecognized function status.
65
+ */
66
+ unknown,
57
67
  };
58
68
 
59
69
  enum class function_deployment_status {
@@ -72,6 +72,10 @@ struct traits<couchbase::core::management::eventing::status> {
72
72
  function.status = couchbase::core::management::eventing::function_status::paused;
73
73
  } else if (composite_status == "pausing") {
74
74
  function.status = couchbase::core::management::eventing::function_status::pausing;
75
+ } else if (composite_status == "resuming") {
76
+ function.status = couchbase::core::management::eventing::function_status::resuming;
77
+ } else {
78
+ function.status = couchbase::core::management::eventing::function_status::unknown;
75
79
  }
76
80
 
77
81
  if (const auto* function_scope = app.find("function_scope");
@@ -75,7 +75,7 @@ void
75
75
  put_uint64(gsl::span<std::byte> bytes, std::uint64_t value)
76
76
  {
77
77
  for (std::size_t i = 0; i < 8; ++i) {
78
- bytes[i] = static_cast<std::byte>(value >> (56 - i * 8));
78
+ bytes[i] = static_cast<std::byte>(value >> (56 - (i * 8)));
79
79
  }
80
80
  }
81
81
  } // namespace couchbase::core::mcbp::big_endian
@@ -76,8 +76,7 @@ codec::encode_packet(const couchbase::core::mcbp::packet& packet) const
76
76
  // It also doesn't expect the collection ID to be leb encoded.
77
77
  extras.resize(sizeof(std::uint32_t));
78
78
  big_endian::put_uint32(extras, packet.collection_id_);
79
- }
80
- if (packet.collection_id_ > 0) {
79
+ } else if (packet.collection_id_ > 0) {
81
80
  CB_LOG_DEBUG("cannot encode collection id with a non-collection command");
82
81
  return tl::unexpected(errc::common::invalid_argument);
83
82
  }
@@ -432,11 +431,11 @@ codec::decode_packet(gsl::span<std::byte> header, gsl::span<std::byte> body) con
432
431
  } else if (frame_type == mcbp::request_sync_durability &&
433
432
  (frame_len == 1 || frame_len == 3)) {
434
433
  pkt.durability_level_frame_ = mcbp::durability_level_frame{
435
- static_cast<mcbp::durability_level>(body[frame_offset])
434
+ static_cast<mcbp::durability_level>(body[frame_offset]),
436
435
  };
437
436
  if (frame_len == 3) {
438
437
  pkt.durability_timeout_frame_ = mcbp::durability_timeout_frame{
439
- std::chrono::milliseconds{ big_endian::read_uint16(body, frame_offset + 1) }
438
+ std::chrono::milliseconds{ big_endian::read_uint16(body, frame_offset + 1) },
440
439
  };
441
440
  } else {
442
441
  // We follow the semantic that duplicate frames overwrite previous ones, since the
@@ -445,39 +444,49 @@ codec::decode_packet(gsl::span<std::byte> header, gsl::span<std::byte> body) con
445
444
  pkt.durability_timeout_frame_.reset();
446
445
  }
447
446
  } else if (frame_type == mcbp::request_stream_id && frame_len == 2) {
448
- pkt.stream_id_frame_ =
449
- mcbp::stream_id_frame{ big_endian::read_uint16(body, frame_offset) };
447
+ pkt.stream_id_frame_ = mcbp::stream_id_frame{
448
+ big_endian::read_uint16(body, frame_offset),
449
+ };
450
450
  } else if (frame_type == mcbp::request_open_tracing && frame_len > 0) {
451
- pkt.open_tracing_frame_ =
452
- mcbp::open_tracing_frame{ big_endian::read(body, frame_offset, frame_len) };
451
+ pkt.open_tracing_frame_ = mcbp::open_tracing_frame{
452
+ big_endian::read(body, frame_offset, frame_len),
453
+ };
453
454
  } else if (frame_type == mcbp::request_preserve_expiry && frame_len == 0) {
454
455
  pkt.preserve_expiry_frame_ = mcbp::preserve_expiry_frame{};
455
456
  } else if (frame_type == mcbp::request_user_impersonation && frame_len > 0) {
456
- pkt.user_impersonation_frame_ =
457
- mcbp::user_impersonation_frame{ big_endian::read(body, frame_offset, frame_len) };
457
+ pkt.user_impersonation_frame_ = mcbp::user_impersonation_frame{
458
+ big_endian::read(body, frame_offset, frame_len),
459
+ };
458
460
  } else {
459
461
  // If we don't understand this frame type, we record it as an UnsupportedFrame (as
460
462
  // opposed to dropping it blindly)
461
463
  pkt.unsupported_frames_.emplace_back(mcbp::unsupported_frame{
462
- frame_type, big_endian::read(body, frame_offset, frame_len) });
464
+ frame_type,
465
+ big_endian::read(body, frame_offset, frame_len),
466
+ });
463
467
  }
464
468
  break;
465
469
 
466
470
  case protocol::magic::alt_client_response:
467
471
  if (frame_type == mcbp::response_server_duration && frame_len == 2) {
468
- pkt.server_duration_frame_ = mcbp::server_duration_frame{ mcbp::decode_server_duration(
469
- big_endian::read_uint16(body, frame_offset)) };
472
+ pkt.server_duration_frame_ = mcbp::server_duration_frame{
473
+ mcbp::decode_server_duration(big_endian::read_uint16(body, frame_offset)),
474
+ };
470
475
  } else if (frame_type == mcbp::response_read_units && frame_len == 2) {
471
- pkt.read_units_frame_ =
472
- mcbp::read_units_frame{ big_endian::read_uint16(body, frame_offset) };
476
+ pkt.read_units_frame_ = mcbp::read_units_frame{
477
+ big_endian::read_uint16(body, frame_offset),
478
+ };
473
479
  } else if (frame_type == mcbp::response_write_units && frame_len == 2) {
474
- pkt.write_units_frame_ =
475
- mcbp::write_units_frame{ big_endian::read_uint16(body, frame_offset) };
480
+ pkt.write_units_frame_ = mcbp::write_units_frame{
481
+ big_endian::read_uint16(body, frame_offset),
482
+ };
476
483
  } else {
477
484
  // If we don't understand this frame type, we record it as an UnsupportedFrame (as
478
485
  // opposed to dropping it blindly)
479
486
  pkt.unsupported_frames_.emplace_back(mcbp::unsupported_frame{
480
- frame_type, big_endian::read(body, frame_offset, frame_len) });
487
+ frame_type,
488
+ big_endian::read(body, frame_offset, frame_len),
489
+ });
481
490
  }
482
491
  break;
483
492
 
@@ -77,7 +77,7 @@ operation_queue::push(std::shared_ptr<queue_request> request,
77
77
  return errc::network::operation_queue_full;
78
78
  }
79
79
 
80
- if (operation_queue * no_queue{ nullptr };
80
+ if (operation_queue* no_queue{ nullptr };
81
81
  !request->queued_with_.compare_exchange_strong(no_queue, this)) {
82
82
  return errc::network::request_already_queued;
83
83
  }
@@ -102,7 +102,7 @@ operation_queue::remove(const std::shared_ptr<queue_request>& request) -> bool
102
102
  return false;
103
103
  }
104
104
 
105
- if (operation_queue * this_queue{ nullptr };
105
+ if (operation_queue* this_queue{ this };
106
106
  !request->queued_with_.compare_exchange_strong(this_queue, nullptr)) {
107
107
  return false;
108
108
  }
@@ -43,8 +43,8 @@ class packet
43
43
  public:
44
44
  [[nodiscard]] auto debug_string() const -> std::string;
45
45
 
46
- protocol::magic magic_;
47
- protocol::client_opcode command_;
46
+ protocol::magic magic_{ protocol::magic::invalid };
47
+ protocol::client_opcode command_{ protocol::client_opcode::invalid };
48
48
  std::byte datatype_{};
49
49
  std::uint16_t status_{ 0x00 };
50
50
  key_value_status_code status_code_{ key_value_status_code::success };