couchbase 3.4.2 → 3.4.4

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 (355) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/couchbase/CMakeLists.txt +71 -7
  4. data/ext/couchbase/cmake/Documentation.cmake +0 -1
  5. data/ext/couchbase/cmake/OpenSSL.cmake +98 -3
  6. data/ext/couchbase/cmake/Testing.cmake +12 -4
  7. data/ext/couchbase/cmake/build_config.hxx.in +3 -0
  8. data/ext/couchbase/core/bucket.cxx +183 -151
  9. data/ext/couchbase/core/bucket.hxx +23 -1
  10. data/ext/couchbase/core/cluster.hxx +51 -13
  11. data/ext/couchbase/core/cluster_options.cxx +2 -2
  12. data/ext/couchbase/core/cluster_options.hxx +7 -6
  13. data/ext/couchbase/core/cluster_options_fwd.hxx +26 -0
  14. data/ext/couchbase/core/config_profile.hxx +1 -54
  15. data/ext/couchbase/core/config_profiles.cxx +79 -0
  16. data/ext/couchbase/core/config_profiles.hxx +56 -0
  17. data/ext/couchbase/core/crud_component.cxx +51 -22
  18. data/ext/couchbase/core/error_context/key_value.cxx +2 -1
  19. data/ext/couchbase/core/error_context/key_value.hxx +10 -12
  20. data/ext/couchbase/core/error_context/search.hxx +1 -1
  21. data/ext/couchbase/core/impl/analytics.cxx +1 -0
  22. data/ext/couchbase/core/impl/boolean_field_query.cxx +40 -0
  23. data/ext/couchbase/core/impl/boolean_query.cxx +62 -0
  24. data/ext/couchbase/core/impl/build_deferred_query_indexes.cxx +115 -50
  25. data/ext/couchbase/core/impl/cluster.cxx +8 -0
  26. data/ext/couchbase/core/impl/conjunction_query.cxx +51 -0
  27. data/ext/couchbase/core/impl/create_bucket.cxx +155 -0
  28. data/ext/couchbase/core/impl/create_query_index.cxx +172 -59
  29. data/ext/couchbase/core/impl/date_range.cxx +89 -0
  30. data/ext/couchbase/core/impl/date_range_facet.cxx +54 -0
  31. data/ext/couchbase/core/impl/date_range_facet_result.cxx +64 -0
  32. data/ext/couchbase/core/impl/date_range_query.cxx +125 -0
  33. data/ext/couchbase/core/impl/disjunction_query.cxx +51 -0
  34. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +2 -1
  35. data/ext/couchbase/core/impl/drop_bucket.cxx +66 -0
  36. data/ext/couchbase/core/impl/drop_query_index.cxx +138 -59
  37. data/ext/couchbase/core/impl/encoded_search_facet.hxx +29 -0
  38. data/ext/couchbase/core/impl/encoded_search_query.hxx +29 -0
  39. data/ext/couchbase/core/impl/encoded_search_sort.hxx +29 -0
  40. data/ext/couchbase/core/impl/flush_bucket.cxx +66 -0
  41. data/ext/couchbase/core/impl/geo_bounding_box_query.cxx +46 -0
  42. data/ext/couchbase/core/impl/geo_distance_query.cxx +43 -0
  43. data/ext/couchbase/core/impl/geo_polygon_query.cxx +46 -0
  44. data/ext/couchbase/core/impl/get_all_buckets.cxx +163 -0
  45. data/ext/couchbase/core/impl/get_all_query_indexes.cxx +67 -37
  46. data/ext/couchbase/core/impl/get_bucket.cxx +153 -0
  47. data/ext/couchbase/core/impl/internal_date_range_facet_result.cxx +80 -0
  48. data/ext/couchbase/core/impl/internal_date_range_facet_result.hxx +48 -0
  49. data/ext/couchbase/core/impl/internal_manager_error_context.cxx +113 -0
  50. data/ext/couchbase/core/impl/internal_manager_error_context.hxx +60 -0
  51. data/ext/couchbase/core/impl/internal_numeric_range_facet_result.cxx +80 -0
  52. data/ext/couchbase/core/impl/internal_numeric_range_facet_result.hxx +48 -0
  53. data/ext/couchbase/core/impl/internal_search_error_context.cxx +141 -0
  54. data/ext/couchbase/core/impl/internal_search_error_context.hxx +61 -0
  55. data/ext/couchbase/core/impl/internal_search_meta_data.cxx +60 -0
  56. data/ext/couchbase/core/impl/internal_search_meta_data.hxx +41 -0
  57. data/ext/couchbase/core/impl/internal_search_result.cxx +84 -0
  58. data/ext/couchbase/core/impl/internal_search_result.hxx +43 -0
  59. data/ext/couchbase/core/impl/internal_search_row.cxx +82 -0
  60. data/ext/couchbase/core/impl/internal_search_row.hxx +56 -0
  61. data/ext/couchbase/core/impl/internal_search_row_location.hxx +32 -0
  62. data/ext/couchbase/core/impl/internal_search_row_locations.cxx +137 -0
  63. data/ext/couchbase/core/impl/internal_search_row_locations.hxx +45 -0
  64. data/ext/couchbase/core/impl/internal_term_facet_result.cxx +80 -0
  65. data/ext/couchbase/core/impl/internal_term_facet_result.hxx +48 -0
  66. data/ext/couchbase/core/impl/key_value_error_category.cxx +2 -4
  67. data/ext/couchbase/core/impl/key_value_error_context.cxx +98 -0
  68. data/ext/couchbase/core/impl/lookup_in.cxx +1 -0
  69. data/ext/couchbase/core/impl/lookup_in_all_replicas.cxx +176 -0
  70. data/ext/couchbase/core/impl/lookup_in_all_replicas.hxx +80 -0
  71. data/ext/couchbase/core/impl/lookup_in_any_replica.cxx +167 -0
  72. data/ext/couchbase/core/impl/lookup_in_any_replica.hxx +75 -0
  73. data/ext/couchbase/core/impl/lookup_in_replica.cxx +97 -0
  74. data/ext/couchbase/core/impl/lookup_in_replica.hxx +67 -0
  75. data/ext/couchbase/core/impl/manager_error_context.cxx +100 -0
  76. data/ext/couchbase/core/impl/match_all_query.cxx +35 -0
  77. data/ext/couchbase/core/impl/match_none_query.cxx +35 -0
  78. data/ext/couchbase/core/impl/match_phrase_query.cxx +43 -0
  79. data/ext/couchbase/core/impl/match_query.cxx +59 -0
  80. data/ext/couchbase/core/impl/numeric_range.cxx +49 -0
  81. data/ext/couchbase/core/impl/numeric_range_facet.cxx +54 -0
  82. data/ext/couchbase/core/impl/numeric_range_facet_result.cxx +64 -0
  83. data/ext/couchbase/core/impl/numeric_range_query.cxx +56 -0
  84. data/ext/couchbase/core/impl/phrase_query.cxx +42 -0
  85. data/ext/couchbase/core/impl/prefix_query.cxx +40 -0
  86. data/ext/couchbase/core/impl/query.cxx +1 -0
  87. data/ext/couchbase/core/impl/query_error_context.cxx +75 -0
  88. data/ext/couchbase/core/impl/query_string_query.cxx +37 -0
  89. data/ext/couchbase/core/impl/regexp_query.cxx +40 -0
  90. data/ext/couchbase/core/impl/search.cxx +191 -0
  91. data/ext/couchbase/core/impl/search_error_context.cxx +147 -0
  92. data/ext/couchbase/core/impl/search_meta_data.cxx +46 -0
  93. data/ext/couchbase/core/impl/search_result.cxx +66 -0
  94. data/ext/couchbase/core/impl/search_row.cxx +74 -0
  95. data/ext/couchbase/core/impl/search_row_location.cxx +64 -0
  96. data/ext/couchbase/core/impl/search_row_locations.cxx +66 -0
  97. data/ext/couchbase/core/impl/search_sort_field.cxx +104 -0
  98. data/ext/couchbase/core/impl/search_sort_id.cxx +43 -0
  99. data/ext/couchbase/core/impl/search_sort_score.cxx +43 -0
  100. data/ext/couchbase/core/impl/term_facet.cxx +36 -0
  101. data/ext/couchbase/core/impl/term_facet_result.cxx +64 -0
  102. data/ext/couchbase/core/impl/term_query.cxx +56 -0
  103. data/ext/couchbase/core/impl/term_range_query.cxx +57 -0
  104. data/ext/couchbase/core/impl/update_bucket.cxx +130 -0
  105. data/ext/couchbase/core/impl/watch_query_indexes.cxx +53 -29
  106. data/ext/couchbase/core/impl/wildcard_query.cxx +40 -0
  107. data/ext/couchbase/core/io/dns_client.cxx +111 -40
  108. data/ext/couchbase/core/io/dns_config.cxx +5 -4
  109. data/ext/couchbase/core/io/http_context.hxx +1 -1
  110. data/ext/couchbase/core/io/http_session.hxx +34 -1
  111. data/ext/couchbase/core/io/http_session_manager.hxx +5 -3
  112. data/ext/couchbase/core/io/mcbp_command.hxx +9 -2
  113. data/ext/couchbase/core/io/mcbp_session.cxx +106 -42
  114. data/ext/couchbase/core/io/mcbp_session.hxx +4 -3
  115. data/ext/couchbase/core/io/retry_orchestrator.hxx +3 -2
  116. data/ext/couchbase/core/json_string.hxx +5 -0
  117. data/ext/couchbase/core/logger/custom_rotating_file_sink.cxx +1 -1
  118. data/ext/couchbase/core/logger/logger.cxx +80 -20
  119. data/ext/couchbase/core/logger/logger.hxx +31 -0
  120. data/ext/couchbase/core/meta/features.hxx +25 -0
  121. data/ext/couchbase/core/meta/version.cxx +18 -4
  122. data/ext/couchbase/core/mozilla_ca_bundle.hxx +39 -0
  123. data/ext/couchbase/core/operations/document_analytics.cxx +1 -0
  124. data/ext/couchbase/core/operations/document_analytics.hxx +1 -0
  125. data/ext/couchbase/core/operations/document_append.hxx +1 -1
  126. data/ext/couchbase/core/operations/document_decrement.hxx +1 -1
  127. data/ext/couchbase/core/operations/document_exists.hxx +1 -1
  128. data/ext/couchbase/core/operations/document_get.hxx +1 -1
  129. data/ext/couchbase/core/operations/document_get_and_lock.hxx +1 -1
  130. data/ext/couchbase/core/operations/document_get_and_touch.hxx +1 -1
  131. data/ext/couchbase/core/operations/document_get_projected.hxx +1 -1
  132. data/ext/couchbase/core/operations/document_increment.hxx +1 -1
  133. data/ext/couchbase/core/operations/document_insert.hxx +1 -1
  134. data/ext/couchbase/core/operations/document_lookup_in.hxx +1 -1
  135. data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +192 -0
  136. data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +188 -0
  137. data/ext/couchbase/core/operations/document_mutate_in.hxx +1 -1
  138. data/ext/couchbase/core/operations/document_prepend.hxx +1 -1
  139. data/ext/couchbase/core/operations/document_query.cxx +13 -0
  140. data/ext/couchbase/core/operations/document_query.hxx +7 -0
  141. data/ext/couchbase/core/operations/document_remove.hxx +1 -1
  142. data/ext/couchbase/core/operations/document_replace.hxx +1 -1
  143. data/ext/couchbase/core/operations/document_search.cxx +4 -1
  144. data/ext/couchbase/core/operations/document_search.hxx +2 -1
  145. data/ext/couchbase/core/operations/document_touch.hxx +1 -1
  146. data/ext/couchbase/core/operations/document_unlock.hxx +1 -1
  147. data/ext/couchbase/core/operations/document_upsert.hxx +1 -1
  148. data/ext/couchbase/core/operations/document_view.hxx +1 -0
  149. data/ext/couchbase/core/operations.hxx +2 -0
  150. data/ext/couchbase/core/origin.cxx +270 -0
  151. data/ext/couchbase/core/origin.hxx +2 -0
  152. data/ext/couchbase/core/protocol/client_request.hxx +11 -2
  153. data/ext/couchbase/core/protocol/client_response.hxx +1 -0
  154. data/ext/couchbase/core/protocol/cmd_hello.hxx +1 -0
  155. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.cxx +107 -0
  156. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.hxx +137 -0
  157. data/ext/couchbase/core/protocol/hello_feature.hxx +6 -0
  158. data/ext/couchbase/core/protocol/hello_feature_fmt.hxx +3 -0
  159. data/ext/couchbase/core/protocol/status.cxx +2 -2
  160. data/ext/couchbase/core/public_fwd.hxx +21 -0
  161. data/ext/couchbase/core/range_scan_options.cxx +3 -27
  162. data/ext/couchbase/core/range_scan_options.hxx +13 -17
  163. data/ext/couchbase/core/range_scan_orchestrator.cxx +388 -170
  164. data/ext/couchbase/core/range_scan_orchestrator.hxx +13 -2
  165. data/ext/couchbase/core/range_scan_orchestrator_options.hxx +5 -3
  166. data/ext/couchbase/core/scan_options.hxx +0 -19
  167. data/ext/couchbase/core/scan_result.cxx +19 -5
  168. data/ext/couchbase/core/scan_result.hxx +5 -2
  169. data/ext/couchbase/core/timeout_defaults.hxx +2 -3
  170. data/ext/couchbase/core/tls_verify_mode.hxx +26 -0
  171. data/ext/couchbase/core/topology/capabilities.hxx +3 -0
  172. data/ext/couchbase/core/topology/capabilities_fmt.hxx +8 -0
  173. data/ext/couchbase/core/topology/collections_manifest_fmt.hxx +1 -1
  174. data/ext/couchbase/core/topology/configuration.cxx +15 -2
  175. data/ext/couchbase/core/topology/configuration.hxx +20 -1
  176. data/ext/couchbase/core/topology/configuration_json.hxx +6 -1
  177. data/ext/couchbase/core/transactions/attempt_context_testing_hooks.cxx +93 -0
  178. data/ext/couchbase/core/transactions/attempt_context_testing_hooks.hxx +48 -75
  179. data/ext/couchbase/core/transactions/cleanup_testing_hooks.cxx +52 -0
  180. data/ext/couchbase/core/transactions/cleanup_testing_hooks.hxx +17 -31
  181. data/ext/couchbase/core/transactions/exceptions.hxx +12 -9
  182. data/ext/couchbase/core/utils/connection_string.cxx +75 -43
  183. data/ext/couchbase/core/utils/connection_string.hxx +1 -0
  184. data/ext/couchbase/core/utils/json.cxx +4 -1
  185. data/ext/couchbase/couchbase/analytics_error_context.hxx +1 -1
  186. data/ext/couchbase/couchbase/behavior_options.hxx +27 -1
  187. data/ext/couchbase/couchbase/boolean_field_query.hxx +77 -0
  188. data/ext/couchbase/couchbase/boolean_query.hxx +223 -0
  189. data/ext/couchbase/couchbase/bucket_manager.hxx +135 -0
  190. data/ext/couchbase/couchbase/build_query_index_options.hxx +0 -30
  191. data/ext/couchbase/couchbase/cluster.hxx +56 -1
  192. data/ext/couchbase/couchbase/collection.hxx +111 -0
  193. data/ext/couchbase/couchbase/collection_query_index_manager.hxx +7 -48
  194. data/ext/couchbase/couchbase/conjunction_query.hxx +88 -0
  195. data/ext/couchbase/couchbase/create_bucket_options.hxx +41 -0
  196. data/ext/couchbase/couchbase/create_primary_query_index_options.hxx +0 -29
  197. data/ext/couchbase/couchbase/create_query_index_options.hxx +0 -33
  198. data/ext/couchbase/couchbase/date_range.hxx +69 -0
  199. data/ext/couchbase/couchbase/date_range_facet.hxx +56 -0
  200. data/ext/couchbase/couchbase/date_range_facet_result.hxx +55 -0
  201. data/ext/couchbase/couchbase/date_range_query.hxx +265 -0
  202. data/ext/couchbase/couchbase/disjunction_query.hxx +109 -0
  203. data/ext/couchbase/couchbase/doc_id_query.hxx +111 -0
  204. data/ext/couchbase/couchbase/drop_bucket_options.hxx +41 -0
  205. data/ext/couchbase/couchbase/drop_primary_query_index_options.hxx +0 -30
  206. data/ext/couchbase/couchbase/drop_query_index_options.hxx +0 -31
  207. data/ext/couchbase/couchbase/error_codes.hxx +1 -2
  208. data/ext/couchbase/couchbase/error_context.hxx +17 -8
  209. data/ext/couchbase/couchbase/flush_bucket_options.hxx +41 -0
  210. data/ext/couchbase/couchbase/fmt/analytics_scan_consistency.hxx +52 -0
  211. data/ext/couchbase/{core/topology/error_map_fmt.hxx → couchbase/fmt/key_value_error_map_attribute.hxx} +21 -21
  212. data/ext/couchbase/couchbase/fmt/search_scan_consistency.hxx +49 -0
  213. data/ext/couchbase/couchbase/geo_bounding_box_query.hxx +107 -0
  214. data/ext/couchbase/couchbase/geo_distance_query.hxx +109 -0
  215. data/ext/couchbase/couchbase/geo_point.hxx +32 -0
  216. data/ext/couchbase/couchbase/geo_polygon_query.hxx +85 -0
  217. data/ext/couchbase/couchbase/get_all_buckets_options.hxx +44 -0
  218. data/ext/couchbase/couchbase/get_all_query_indexes_options.hxx +0 -30
  219. data/ext/couchbase/couchbase/get_and_lock_options.hxx +2 -2
  220. data/ext/couchbase/couchbase/get_and_touch_options.hxx +2 -2
  221. data/ext/couchbase/couchbase/get_bucket_options.hxx +43 -0
  222. data/ext/couchbase/couchbase/get_options.hxx +2 -2
  223. data/ext/couchbase/couchbase/highlight_style.hxx +45 -0
  224. data/ext/couchbase/couchbase/insert_options.hxx +3 -3
  225. data/ext/couchbase/couchbase/key_value_error_context.hxx +7 -2
  226. data/ext/couchbase/couchbase/lookup_in_all_replicas_options.hxx +109 -0
  227. data/ext/couchbase/couchbase/lookup_in_any_replica_options.hxx +101 -0
  228. data/ext/couchbase/couchbase/lookup_in_options.hxx +2 -2
  229. data/ext/couchbase/couchbase/lookup_in_replica_result.hxx +74 -0
  230. data/ext/couchbase/couchbase/lookup_in_result.hxx +26 -0
  231. data/ext/couchbase/couchbase/management/bucket_settings.hxx +116 -0
  232. data/ext/couchbase/couchbase/manager_error_context.hxx +29 -53
  233. data/ext/couchbase/couchbase/match_all_query.hxx +43 -0
  234. data/ext/couchbase/couchbase/match_none_query.hxx +43 -0
  235. data/ext/couchbase/couchbase/match_operator.hxx +45 -0
  236. data/ext/couchbase/couchbase/match_phrase_query.hxx +108 -0
  237. data/ext/couchbase/couchbase/match_query.hxx +163 -0
  238. data/ext/couchbase/couchbase/mutate_in_options.hxx +2 -2
  239. data/ext/couchbase/couchbase/numeric_range.hxx +58 -0
  240. data/ext/couchbase/couchbase/numeric_range_facet.hxx +56 -0
  241. data/ext/couchbase/couchbase/numeric_range_facet_result.hxx +55 -0
  242. data/ext/couchbase/couchbase/numeric_range_query.hxx +143 -0
  243. data/ext/couchbase/couchbase/phrase_query.hxx +93 -0
  244. data/ext/couchbase/couchbase/prefix_query.hxx +82 -0
  245. data/ext/couchbase/couchbase/query_error_context.hxx +3 -1
  246. data/ext/couchbase/couchbase/query_index_manager.hxx +16 -83
  247. data/ext/couchbase/couchbase/query_options.hxx +18 -0
  248. data/ext/couchbase/couchbase/query_string_query.hxx +72 -0
  249. data/ext/couchbase/couchbase/regexp_query.hxx +82 -0
  250. data/ext/couchbase/couchbase/remove_options.hxx +2 -2
  251. data/ext/couchbase/couchbase/replace_options.hxx +3 -3
  252. data/ext/couchbase/couchbase/scope.hxx +40 -0
  253. data/ext/couchbase/couchbase/search_date_range.hxx +68 -0
  254. data/ext/couchbase/couchbase/search_error_context.hxx +138 -0
  255. data/ext/couchbase/couchbase/search_facet.hxx +60 -0
  256. data/ext/couchbase/couchbase/search_facet_result.hxx +50 -0
  257. data/ext/couchbase/couchbase/search_meta_data.hxx +85 -0
  258. data/ext/couchbase/couchbase/search_metrics.hxx +127 -0
  259. data/ext/couchbase/couchbase/search_numeric_range.hxx +69 -0
  260. data/ext/couchbase/couchbase/search_options.hxx +509 -0
  261. data/ext/couchbase/couchbase/search_query.hxx +69 -0
  262. data/ext/couchbase/couchbase/search_result.hxx +77 -0
  263. data/ext/couchbase/couchbase/search_row.hxx +104 -0
  264. data/ext/couchbase/couchbase/search_row_location.hxx +55 -0
  265. data/ext/couchbase/couchbase/search_row_locations.hxx +86 -0
  266. data/ext/couchbase/couchbase/search_scan_consistency.hxx +34 -0
  267. data/ext/couchbase/couchbase/search_sort.hxx +58 -0
  268. data/ext/couchbase/couchbase/search_sort_field.hxx +117 -0
  269. data/ext/couchbase/couchbase/search_sort_field_missing.hxx +26 -0
  270. data/ext/couchbase/couchbase/search_sort_field_mode.hxx +27 -0
  271. data/ext/couchbase/couchbase/search_sort_field_type.hxx +28 -0
  272. data/ext/couchbase/couchbase/search_sort_id.hxx +60 -0
  273. data/ext/couchbase/couchbase/search_sort_score.hxx +60 -0
  274. data/ext/couchbase/couchbase/search_term_range.hxx +51 -0
  275. data/ext/couchbase/couchbase/security_options.hxx +18 -0
  276. data/ext/couchbase/couchbase/subdocument_error_context.hxx +4 -2
  277. data/ext/couchbase/couchbase/term_facet.hxx +48 -0
  278. data/ext/couchbase/couchbase/term_facet_result.hxx +55 -0
  279. data/ext/couchbase/couchbase/term_query.hxx +151 -0
  280. data/ext/couchbase/couchbase/term_range_query.hxx +142 -0
  281. data/ext/couchbase/couchbase/touch_options.hxx +2 -2
  282. data/ext/couchbase/couchbase/tracing/request_span.hxx +63 -0
  283. data/ext/couchbase/couchbase/tracing/request_tracer.hxx +2 -40
  284. data/ext/couchbase/couchbase/transactions/async_attempt_context.hxx +83 -4
  285. data/ext/couchbase/couchbase/transactions/attempt_context.hxx +67 -0
  286. data/ext/couchbase/couchbase/transactions/transaction_get_result.hxx +2 -0
  287. data/ext/couchbase/couchbase/transactions/transaction_keyspace.hxx +11 -1
  288. data/ext/couchbase/couchbase/transactions/transaction_options.hxx +79 -8
  289. data/ext/couchbase/couchbase/transactions/transaction_query_options.hxx +128 -15
  290. data/ext/couchbase/couchbase/transactions/transaction_query_result.hxx +4 -0
  291. data/ext/couchbase/couchbase/transactions/transaction_result.hxx +1 -1
  292. data/ext/couchbase/couchbase/transactions/transactions_cleanup_config.hxx +5 -3
  293. data/ext/couchbase/couchbase/transactions/transactions_config.hxx +9 -5
  294. data/ext/couchbase/couchbase/transactions/transactions_query_config.hxx +6 -3
  295. data/ext/couchbase/couchbase/transactions.hxx +34 -1
  296. data/ext/couchbase/couchbase/unlock_options.hxx +2 -2
  297. data/ext/couchbase/couchbase/update_bucket_options.hxx +41 -0
  298. data/ext/couchbase/couchbase/upsert_options.hxx +3 -3
  299. data/ext/couchbase/couchbase/watch_query_indexes_options.hxx +0 -31
  300. data/ext/couchbase/couchbase/wildcard_query.hxx +83 -0
  301. data/ext/couchbase/test/CMakeLists.txt +8 -5
  302. data/ext/couchbase/test/benchmark_helper_integration.hxx +2 -2
  303. data/ext/couchbase/test/test_helper.hxx +5 -5
  304. data/ext/couchbase/test/test_integration_analytics.cxx +28 -6
  305. data/ext/couchbase/test/test_integration_collections.cxx +13 -3
  306. data/ext/couchbase/test/test_integration_connect.cxx +7 -3
  307. data/ext/couchbase/test/test_integration_crud.cxx +18 -3
  308. data/ext/couchbase/test/test_integration_diagnostics.cxx +11 -5
  309. data/ext/couchbase/test/test_integration_durability.cxx +12 -7
  310. data/ext/couchbase/test/test_integration_examples.cxx +419 -11
  311. data/ext/couchbase/test/test_integration_management.cxx +867 -368
  312. data/ext/couchbase/test/test_integration_query.cxx +87 -17
  313. data/ext/couchbase/test/test_integration_range_scan.cxx +363 -124
  314. data/ext/couchbase/test/test_integration_read_replica.cxx +48 -11
  315. data/ext/couchbase/test/test_integration_search.cxx +32 -3
  316. data/ext/couchbase/test/test_integration_subdoc.cxx +717 -11
  317. data/ext/couchbase/test/test_integration_tracer.cxx +5 -0
  318. data/ext/couchbase/test/test_integration_transcoders.cxx +13 -5
  319. data/ext/couchbase/test/{test_transaction_transaction_context.cxx → test_transaction_context.cxx} +1 -1
  320. data/ext/couchbase/test/test_transaction_examples.cxx +195 -0
  321. data/ext/couchbase/test/{test_transaction_transaction_public_async_api.cxx → test_transaction_public_async_api.cxx} +13 -12
  322. data/ext/couchbase/test/{test_transaction_transaction_public_blocking_api.cxx → test_transaction_public_blocking_api.cxx} +27 -21
  323. data/ext/couchbase/test/{test_transaction_transaction_simple.cxx → test_transaction_simple.cxx} +17 -5
  324. data/ext/couchbase/test/{test_transaction_transaction_simple_async.cxx → test_transaction_simple_async.cxx} +19 -21
  325. data/ext/couchbase/test/test_unit_config_profiles.cxx +1 -1
  326. data/ext/couchbase/test/test_unit_connection_string.cxx +29 -0
  327. data/ext/couchbase/test/test_unit_json_transcoder.cxx +4 -0
  328. data/ext/couchbase/test/test_unit_query.cxx +75 -0
  329. data/ext/couchbase/test/test_unit_search.cxx +427 -0
  330. data/ext/couchbase/test/test_unit_transaction_utils.cxx +10 -1
  331. data/ext/couchbase/test/test_unit_utils.cxx +8 -4
  332. data/ext/couchbase.cxx +641 -45
  333. data/ext/revisions.rb +3 -3
  334. data/lib/couchbase/authenticator.rb +0 -1
  335. data/lib/couchbase/cluster.rb +1 -5
  336. data/lib/couchbase/collection.rb +108 -0
  337. data/lib/couchbase/collection_options.rb +100 -0
  338. data/lib/couchbase/config_profiles.rb +1 -1
  339. data/lib/couchbase/errors.rb +5 -0
  340. data/lib/couchbase/json_transcoder.rb +12 -5
  341. data/lib/couchbase/key_value_scan.rb +125 -0
  342. data/lib/couchbase/management/collection_query_index_manager.rb +54 -15
  343. data/lib/couchbase/management/query_index_manager.rb +70 -5
  344. data/lib/couchbase/options.rb +151 -0
  345. data/lib/couchbase/raw_binary_transcoder.rb +37 -0
  346. data/lib/couchbase/raw_json_transcoder.rb +38 -0
  347. data/lib/couchbase/raw_string_transcoder.rb +40 -0
  348. data/lib/couchbase/scope.rb +1 -1
  349. data/lib/couchbase/search_options.rb +5 -0
  350. data/lib/couchbase/transcoder_flags.rb +62 -0
  351. data/lib/couchbase/utils/time.rb +14 -1
  352. data/lib/couchbase/version.rb +1 -1
  353. metadata +175 -13
  354. data/ext/couchbase/core/config_profile.cxx +0 -47
  355. data/ext/couchbase/core/impl/collection_query_index_manager.cxx +0 -93
@@ -22,7 +22,6 @@
22
22
  #include "core/mcbp/codec.hxx"
23
23
  #include "dispatcher.hxx"
24
24
  #include "impl/bootstrap_state_listener.hxx"
25
- #include "mcbp/completion_token.hxx"
26
25
  #include "mcbp/operation_queue.hxx"
27
26
  #include "mcbp/queue_request.hxx"
28
27
  #include "mcbp/queue_response.hxx"
@@ -41,28 +40,6 @@
41
40
 
42
41
  namespace couchbase::core
43
42
  {
44
- /**
45
- * copies nodes from rhs that are not in lhs to output vector
46
- */
47
- static void
48
- diff_nodes(const std::vector<topology::configuration::node>& lhs,
49
- const std::vector<topology::configuration::node>& rhs,
50
- std::vector<topology::configuration::node>& output)
51
- {
52
- for (const auto& re : rhs) {
53
- bool known = false;
54
- for (const auto& le : lhs) {
55
- if (le.hostname == re.hostname && le.services_plain.management.value_or(0) == re.services_plain.management.value_or(0)) {
56
- known = true;
57
- break;
58
- }
59
- }
60
- if (!known) {
61
- output.push_back(re);
62
- }
63
- }
64
- }
65
-
66
43
  class bucket_impl
67
44
  : public std::enable_shared_from_this<bucket_impl>
68
45
  , public config_listener
@@ -303,81 +280,111 @@ class bucket_impl
303
280
  return config_->map_key(key, node_index);
304
281
  }
305
282
 
306
- void restart_node(std::size_t index, const std::string& hostname, const std::string& port)
283
+ void restart_sessions()
307
284
  {
308
- if (closed_) {
309
- CB_LOG_DEBUG(R"({} requested to restart session, but the bucket has been closed already. idx={}, address="{}:{}")",
310
- log_prefix_,
311
- index,
312
- hostname,
313
- port);
285
+ const std::scoped_lock lock(config_mutex_, sessions_mutex_);
286
+ if (!config_.has_value()) {
314
287
  return;
315
288
  }
316
- {
317
- std::scoped_lock lock(config_mutex_);
318
- if (!config_->has_node_with_hostname(hostname)) {
319
- CB_LOG_TRACE(
320
- R"({} requested to restart session, but the node has been ejected from current configuration already. idx={}, address="{}:{}")",
321
- log_prefix_,
322
- index,
323
- hostname,
324
- port);
325
- return;
326
- }
327
- }
328
- couchbase::core::origin origin(origin_.credentials(), hostname, port, origin_.options());
329
289
 
330
- io::mcbp_session session = origin_.options().enable_tls
331
- ? io::mcbp_session(client_id_, ctx_, tls_, origin, state_listener_, name_, known_features_)
332
- : io::mcbp_session(client_id_, ctx_, origin, state_listener_, name_, known_features_);
290
+ std::size_t kv_node_index{ 0 };
291
+ for (std::size_t index = 0; index < config_->nodes.size(); ++index) {
292
+ const auto& node = config_->nodes[index];
333
293
 
334
- std::scoped_lock lock(sessions_mutex_);
335
- if (auto ptr = sessions_.find(index); ptr == sessions_.end()) {
336
- CB_LOG_DEBUG(R"({} requested to restart session idx={}, which does not exist yet, initiate new one id="{}", address="{}:{}")",
337
- log_prefix_,
338
- index,
339
- session.id(),
340
- hostname,
341
- port);
342
- } else {
343
- const auto& old_session = ptr->second;
344
- auto old_id = old_session.id();
345
- sessions_.erase(ptr);
346
- Expects(sessions_.count(index) == 0);
347
- CB_LOG_DEBUG(R"({} restarting session idx={}, id=("{}" -> "{}"), address="{}:{}")",
294
+ const auto& hostname = node.hostname_for(origin_.options().network);
295
+ auto port = node.port_or(origin_.options().network, service_type::key_value, origin_.options().enable_tls, 0);
296
+ if (port == 0) {
297
+ continue;
298
+ }
299
+
300
+ auto ptr = std::find_if(sessions_.begin(), sessions_.end(), [&hostname, &port](const auto& session) {
301
+ return session.second.bootstrap_hostname() == hostname && session.second.bootstrap_port_number() == port;
302
+ });
303
+ if (ptr != sessions_.end()) {
304
+
305
+ if (auto found_kv_node_index = ptr->first; found_kv_node_index != kv_node_index) {
306
+ if (auto current = sessions_.find(kv_node_index); current == sessions_.end()) {
307
+ CB_LOG_WARNING(R"({} KV node index mismatch: config rev={} states that address="{}:{}" should be at idx={}, )"
308
+ R"(but it is at idx={} ("{}"). Moving session to idx={}.)",
309
+ log_prefix_,
310
+ config_->rev_str(),
311
+ hostname,
312
+ port,
313
+ kv_node_index,
314
+ found_kv_node_index,
315
+ ptr->second.id(),
316
+ kv_node_index);
317
+ sessions_.insert_or_assign(kv_node_index, std::move(ptr->second));
318
+ sessions_.erase(ptr);
319
+ } else {
320
+ CB_LOG_WARNING(
321
+ R"({} KV node index mismatch: config rev={} states that address="{}:{}" should be at idx={}, )"
322
+ R"(but it is at idx={} ("{}"). Slot with idx={} is holds session with address="{}" ("{}"), swapping them.)",
323
+ log_prefix_,
324
+ config_->rev_str(),
325
+ hostname,
326
+ port,
327
+ kv_node_index,
328
+ found_kv_node_index,
329
+ ptr->second.id(),
330
+ kv_node_index,
331
+ current->second.bootstrap_address(),
332
+ current->second.id());
333
+ std::swap(current->second, ptr->second);
334
+ }
335
+ }
336
+ ++kv_node_index;
337
+ continue;
338
+ }
339
+ couchbase::core::origin origin(origin_.credentials(), hostname, port, origin_.options());
340
+ io::mcbp_session session = origin_.options().enable_tls
341
+ ? io::mcbp_session(client_id_, ctx_, tls_, origin, state_listener_, name_, known_features_)
342
+ : io::mcbp_session(client_id_, ctx_, origin, state_listener_, name_, known_features_);
343
+ CB_LOG_DEBUG(R"({} rev={}, restart idx={}, session="{}", address="{}:{}")",
348
344
  log_prefix_,
349
- index,
350
- old_id,
345
+ config_->rev_str(),
346
+ node.index,
351
347
  session.id(),
352
348
  hostname,
353
349
  port);
350
+ session.bootstrap(
351
+ [self = shared_from_this(), session](std::error_code err, topology::configuration cfg) mutable {
352
+ if (err) {
353
+ return self->remove_session(session.id());
354
+ }
355
+ self->update_config(std::move(cfg));
356
+ session.on_configuration_update(self);
357
+ session.on_stop([id = session.id(), self]() { self->remove_session(id); });
358
+ self->drain_deferred_queue();
359
+ },
360
+ true);
361
+ sessions_.insert_or_assign(index, std::move(session));
362
+ ++kv_node_index;
354
363
  }
364
+ }
355
365
 
356
- session.bootstrap(
357
- [self = shared_from_this(), session, this_index = index, hostname, port](std::error_code ec,
358
- const topology::configuration& config) mutable {
359
- if (self->closed_) {
360
- asio::post(asio::bind_executor(
361
- self->ctx_, [session = std::move(session)]() mutable { return session.stop(retry_reason::do_not_retry); }));
362
- return;
363
- }
364
- if (ec) {
365
- CB_LOG_WARNING(R"({} failed to restart session idx={}, ec={})", session.log_prefix(), this_index, ec.message());
366
- self->restart_node(this_index, hostname, port);
367
- return;
368
- }
369
- session.on_configuration_update(self);
370
- session.on_stop([this_index, hostname, port, self](retry_reason reason) {
371
- if (reason == retry_reason::socket_closed_while_in_flight) {
372
- self->restart_node(this_index, hostname, port);
373
- }
374
- });
366
+ void remove_session(const std::string& id)
367
+ {
368
+ bool found{ false };
369
+ const std::scoped_lock lock(sessions_mutex_);
370
+ for (auto ptr = sessions_.cbegin(); ptr != sessions_.cend();) {
371
+ if (ptr->second.id() == id) {
372
+ CB_LOG_DEBUG(R"({} removed session id="{}", address="{}", bootstrap_address="{}:{}")",
373
+ log_prefix_,
374
+ ptr->second.id(),
375
+ ptr->second.remote_address(),
376
+ ptr->second.bootstrap_hostname(),
377
+ ptr->second.bootstrap_port());
378
+ ptr = sessions_.erase(ptr);
379
+ found = true;
380
+ } else {
381
+ ptr = std::next(ptr);
382
+ }
383
+ }
375
384
 
376
- self->update_config(config);
377
- self->drain_deferred_queue();
378
- },
379
- true);
380
- sessions_.insert_or_assign(index, std::move(session));
385
+ if (found) {
386
+ asio::post(asio::bind_executor(ctx_, [self = shared_from_this()]() { return self->restart_sessions(); }));
387
+ }
381
388
  }
382
389
 
383
390
  void bootstrap(utils::movable_function<void(std::error_code, topology::configuration)>&& handler)
@@ -392,15 +399,11 @@ class bucket_impl
392
399
  topology::configuration cfg) mutable {
393
400
  if (ec) {
394
401
  CB_LOG_WARNING(R"({} failed to bootstrap session ec={}, bucket="{}")", new_session.log_prefix(), ec.message(), self->name_);
402
+ self->remove_session(new_session.id());
395
403
  } else {
396
404
  const std::size_t this_index = new_session.index();
397
405
  new_session.on_configuration_update(self);
398
- new_session.on_stop([this_index, hostname = new_session.bootstrap_hostname(), port = new_session.bootstrap_port(), self](
399
- retry_reason reason) {
400
- if (reason == retry_reason::socket_closed_while_in_flight) {
401
- self->restart_node(this_index, hostname, port);
402
- }
403
- });
406
+ new_session.on_stop([id = new_session.id(), self]() { self->remove_session(id); });
404
407
 
405
408
  {
406
409
  std::scoped_lock lock(self->sessions_mutex_);
@@ -454,6 +457,9 @@ class bucket_impl
454
457
  std::scoped_lock lock(deferred_commands_mutex_);
455
458
  std::swap(deferred_commands_, commands);
456
459
  }
460
+ if (!commands.empty()) {
461
+ CB_LOG_TRACE(R"({} draining deferred operation queue, size={})", log_prefix_, commands.size());
462
+ }
457
463
  while (!commands.empty()) {
458
464
  commands.front()();
459
465
  commands.pop();
@@ -488,9 +494,33 @@ class bucket_impl
488
494
  }
489
495
  }
490
496
 
497
+ /**
498
+ * copies nodes from rhs that are not in lhs to output vector
499
+ */
500
+ void diff_nodes(const std::vector<topology::configuration::node>& lhs,
501
+ const std::vector<topology::configuration::node>& rhs,
502
+ std::vector<topology::configuration::node>& output)
503
+ {
504
+ for (const auto& re : rhs) {
505
+ bool known = false;
506
+ const auto& rhost = re.hostname_for(origin_.options().network);
507
+ const auto rport = re.port_or(origin_.options().network, service_type::key_value, origin_.options().enable_tls, 0);
508
+ for (const auto& le : lhs) {
509
+ const auto& lhost = le.hostname_for(origin_.options().network);
510
+ const auto lport = le.port_or(origin_.options().network, service_type::key_value, origin_.options().enable_tls, 0);
511
+ if (rhost == lhost && rport == lport) {
512
+ known = true;
513
+ break;
514
+ }
515
+ }
516
+ if (!known) {
517
+ output.push_back(re);
518
+ }
519
+ }
520
+ }
521
+
491
522
  void update_config(topology::configuration config) override
492
523
  {
493
- bool forced_config = false;
494
524
  std::vector<topology::configuration::node> added{};
495
525
  std::vector<topology::configuration::node> removed{};
496
526
  {
@@ -499,7 +529,6 @@ class bucket_impl
499
529
  CB_LOG_DEBUG("{} initialize configuration rev={}", log_prefix_, config.rev_str());
500
530
  } else if (config.force) {
501
531
  CB_LOG_DEBUG("{} forced to accept configuration rev={}", log_prefix_, config.rev_str());
502
- forced_config = true;
503
532
  } else if (!config.vbmap) {
504
533
  CB_LOG_DEBUG("{} will not update the configuration old={} -> new={}, because new config does not have partition map",
505
534
  log_prefix_,
@@ -532,78 +561,81 @@ class bucket_impl
532
561
  std::scoped_lock lock(sessions_mutex_);
533
562
  std::map<size_t, io::mcbp_session> new_sessions{};
534
563
 
535
- for (auto& [index, session] : sessions_) {
536
- std::size_t new_index = config.nodes.size() + 1;
537
- for (const auto& node : config.nodes) {
538
- if (session.bootstrap_hostname() == node.hostname_for(origin_.options().network) &&
539
- session.bootstrap_port() ==
540
- std::to_string(
541
- node.port_or(origin_.options().network, service_type::key_value, origin_.options().enable_tls, 0))) {
542
- new_index = node.index;
543
- break;
544
- }
545
- }
546
- if (new_index < config.nodes.size()) {
547
- CB_LOG_DEBUG(R"({} rev={}, preserve session="{}", address="{}:{}", index={}->{})",
548
- log_prefix_,
549
- config.rev_str(),
550
- session.id(),
551
- session.bootstrap_hostname(),
552
- session.bootstrap_port(),
553
- index,
554
- new_index);
555
- new_sessions.insert_or_assign(new_index, std::move(session));
556
- } else {
557
- CB_LOG_DEBUG(R"({} rev={}, drop session="{}", address="{}:{}", index={})",
558
- log_prefix_,
559
- config.rev_str(),
560
- session.id(),
561
- session.bootstrap_hostname(),
562
- session.bootstrap_port(),
563
- index);
564
- asio::post(asio::bind_executor(
565
- ctx_, [session = std::move(session)]() mutable { return session.stop(retry_reason::do_not_retry); }));
566
- }
567
- }
568
-
564
+ std::size_t next_index{ 0 };
569
565
  for (const auto& node : config.nodes) {
570
- if (new_sessions.find(node.index) != new_sessions.end()) {
571
- continue;
572
- }
573
-
574
566
  const auto& hostname = node.hostname_for(origin_.options().network);
575
567
  auto port = node.port_or(origin_.options().network, service_type::key_value, origin_.options().enable_tls, 0);
576
568
  if (port == 0) {
577
569
  continue;
578
570
  }
571
+
572
+ bool reused_session{ false };
573
+ for (auto it = sessions_.begin(); it != sessions_.end(); ++it) {
574
+ if (it->second.bootstrap_hostname() == hostname && it->second.bootstrap_port_number() == port) {
575
+ CB_LOG_DEBUG(R"({} rev={}, preserve session="{}", address="{}:{}", index={}->{})",
576
+ log_prefix_,
577
+ config.rev_str(),
578
+ it->second.id(),
579
+ it->second.bootstrap_hostname(),
580
+ it->second.bootstrap_port(),
581
+ it->first,
582
+ next_index);
583
+ new_sessions.insert_or_assign(next_index, std::move(it->second));
584
+ reused_session = true;
585
+ ++next_index;
586
+ sessions_.erase(it);
587
+ break;
588
+ }
589
+ }
590
+ if (reused_session) {
591
+ continue;
592
+ }
593
+
579
594
  couchbase::core::origin origin(origin_.credentials(), hostname, port, origin_.options());
580
595
  io::mcbp_session session = origin_.options().enable_tls
581
596
  ? io::mcbp_session(client_id_, ctx_, tls_, origin, state_listener_, name_, known_features_)
582
597
  : io::mcbp_session(client_id_, ctx_, origin, state_listener_, name_, known_features_);
583
- CB_LOG_DEBUG(
584
- R"({} rev={}, add session="{}", address="{}:{}")", log_prefix_, config.rev_str(), session.id(), hostname, port);
598
+ CB_LOG_DEBUG(R"({} rev={}, add session="{}", address="{}:{}", index={})",
599
+ log_prefix_,
600
+ config.rev_str(),
601
+ session.id(),
602
+ hostname,
603
+ port,
604
+ node.index);
585
605
  session.bootstrap(
586
- [self = shared_from_this(), session, forced_config, idx = node.index](std::error_code err,
587
- topology::configuration cfg) mutable {
588
- if (!err) {
589
- self->update_config(std::move(cfg));
590
- session.on_configuration_update(self);
591
- session.on_stop(
592
- [index = session.index(), hostname = session.bootstrap_hostname(), port = session.bootstrap_port(), self](
593
- retry_reason reason) {
594
- if (reason == retry_reason::socket_closed_while_in_flight) {
595
- self->restart_node(index, hostname, port);
596
- }
597
- });
598
- self->drain_deferred_queue();
599
- } else if (err == errc::common::unambiguous_timeout && forced_config) {
600
- self->restart_node(idx, session.bootstrap_hostname(), session.bootstrap_port());
606
+ [self = shared_from_this(), session, idx = next_index](std::error_code err, topology::configuration cfg) mutable {
607
+ if (err) {
608
+ CB_LOG_WARNING(R"({} failed to bootstrap session="{}", address="{}:{}", index={}, ec={})",
609
+ session.log_prefix(),
610
+ session.id(),
611
+ session.bootstrap_hostname(),
612
+ session.bootstrap_port(),
613
+ idx,
614
+ err.message());
615
+ return self->remove_session(session.id());
601
616
  }
617
+ self->update_config(std::move(cfg));
618
+ session.on_configuration_update(self);
619
+ session.on_stop([id = session.id(), self]() { self->remove_session(id); });
620
+ self->drain_deferred_queue();
602
621
  },
603
622
  true);
604
- new_sessions.insert_or_assign(node.index, std::move(session));
623
+ new_sessions.insert_or_assign(next_index, std::move(session));
624
+ ++next_index;
625
+ }
626
+ std::swap(sessions_, new_sessions);
627
+
628
+ for (auto it = new_sessions.begin(); it != new_sessions.end(); ++it) {
629
+ CB_LOG_DEBUG(R"({} rev={}, drop session="{}", address="{}:{}", index={})",
630
+ log_prefix_,
631
+ config.rev_str(),
632
+ it->second.id(),
633
+ it->second.bootstrap_hostname(),
634
+ it->second.bootstrap_port(),
635
+ it->first);
636
+ asio::post(asio::bind_executor(
637
+ ctx_, [session = std::move(it->second)]() mutable { return session.stop(retry_reason::do_not_retry); }));
605
638
  }
606
- sessions_ = new_sessions;
607
639
  }
608
640
  }
609
641
 
@@ -83,7 +83,7 @@ class bucket
83
83
  auto cmd = std::make_shared<operations::mcbp_command<bucket, Request>>(ctx_, shared_from_this(), request, default_timeout());
84
84
  cmd->start([cmd, handler = std::forward<Handler>(handler)](std::error_code ec, std::optional<io::mcbp_message>&& msg) mutable {
85
85
  using encoded_response_type = typename Request::encoded_response_type;
86
- std::uint16_t status_code = msg ? msg->header.status() : 0U;
86
+ std::uint16_t status_code = msg ? msg->header.status() : 0xffffU;
87
87
  auto resp = msg ? encoded_response_type(std::move(*msg)) : encoded_response_type{};
88
88
  auto ctx = make_key_value_error_context(ec, status_code, cmd, resp);
89
89
  handler(cmd->request.make_response(std::move(ctx), std::move(resp)));
@@ -106,6 +106,8 @@ class bucket
106
106
  } else {
107
107
  auto [partition, server] = map_id(cmd->request.id);
108
108
  if (!server.has_value()) {
109
+ CB_LOG_TRACE(
110
+ R"({} unable to map key="{}" to the node, id={}, partition={})", log_prefix(), cmd->request.id, cmd->id_, partition);
109
111
  return io::retry_orchestrator::maybe_retry(
110
112
  cmd->manager_, cmd, retry_reason::node_not_available, errc::common::request_canceled);
111
113
  }
@@ -114,12 +116,32 @@ class bucket
114
116
  }
115
117
  auto session = find_session_by_index(index);
116
118
  if (!session || !session->has_config()) {
119
+ CB_LOG_TRACE(R"({} defer operation id={}, key="{}", partition={}, index={}, session={}, address="{}", has_config={})",
120
+ log_prefix(),
121
+ cmd->id_,
122
+ cmd->request.id,
123
+ cmd->request.partition,
124
+ index,
125
+ session.has_value(),
126
+ session.has_value() ? session->bootstrap_address() : "",
127
+ session.has_value() && session->has_config());
117
128
  return defer_command([self = shared_from_this(), cmd]() { self->map_and_send(cmd); });
118
129
  }
119
130
  if (session->is_stopped()) {
131
+ CB_LOG_TRACE(
132
+ R"({} the session has been found for idx={}, but it is stopped, retrying id={}, key="{}", partition={}, session={}, address="{}")",
133
+ log_prefix(),
134
+ index,
135
+ cmd->id_,
136
+ cmd->request.id,
137
+ cmd->request.partition,
138
+ session->id(),
139
+ session->bootstrap_address());
120
140
  return io::retry_orchestrator::maybe_retry(
121
141
  cmd->manager_, cmd, retry_reason::node_not_available, errc::common::request_canceled);
122
142
  }
143
+ cmd->last_dispatched_from_ = session->local_address();
144
+ cmd->last_dispatched_to_ = session->bootstrap_address();
123
145
  cmd->send_to(session.value());
124
146
  }
125
147
 
@@ -33,6 +33,7 @@
33
33
  #include "diagnostics.hxx"
34
34
  #include "dispatcher.hxx"
35
35
  #include "impl/dns_srv_tracker.hxx"
36
+ #include "mozilla_ca_bundle.hxx"
36
37
  #include "operations.hxx"
37
38
  #include "origin.hxx"
38
39
 
@@ -78,6 +79,7 @@ class cluster : public std::enable_shared_from_this<cluster>
78
79
  }
79
80
 
80
81
  origin_ = std::move(origin);
82
+ CB_LOG_DEBUG(R"(open cluster, id: "{}", core version: "{}", {})", id_, couchbase::core::meta::sdk_semver(), origin_.to_json());
81
83
  // ignore the enable_tracing flag if a tracer was passed in
82
84
  if (nullptr != origin_.options().tracer) {
83
85
  tracer_ = origin_.options().tracer;
@@ -110,10 +112,7 @@ class cluster : public std::enable_shared_from_this<cluster>
110
112
  return self->dns_srv_tracker_->get_srv_nodes(
111
113
  [self, hostname = std::move(hostname), handler = std::forward<Handler>(handler)](origin::node_list nodes,
112
114
  std::error_code ec) mutable {
113
- if (ec) {
114
- return self->close([ec, handler = std::forward<Handler>(handler)]() mutable { handler(ec); });
115
- }
116
- if (!nodes.empty()) {
115
+ if (!ec && !nodes.empty()) {
117
116
  self->origin_.set_nodes(std::move(nodes));
118
117
  CB_LOG_INFO("replace list of bootstrap nodes with addresses from DNS SRV of \"{}\": [{}]",
119
118
  hostname,
@@ -338,8 +337,8 @@ class cluster : public std::enable_shared_from_this<cluster>
338
337
  void do_open(Handler&& handler)
339
338
  {
340
339
  // Warn users if they attempt to use Capella without TLS being enabled.
340
+ bool has_capella_host = false;
341
341
  {
342
- bool has_capella_host = false;
343
342
  bool has_non_capella_host = false;
344
343
  static std::string suffix = "cloud.couchbase.com";
345
344
  for (const auto& node : origin_.get_hostnames()) {
@@ -358,6 +357,7 @@ class cluster : public std::enable_shared_from_this<cluster>
358
357
 
359
358
  if (origin_.options().enable_tls /* TLS is enabled */
360
359
  && origin_.options().trust_certificate.empty() /* No CA certificate (or other SDK-specific trust source) is specified */
360
+ && origin_.options().trust_certificate_value.empty() /* and certificate value has not been specified */
361
361
  && origin_.options().tls_verify != tls_verify_mode::none /* The user did not disable all TLS verification */
362
362
  && has_non_capella_host /* The connection string has a hostname that does NOT end in ".cloud.couchbase.com" */) {
363
363
  CB_LOG_WARNING("[{}] When TLS is enabled, the cluster options must specify certificate(s) to trust or ensure that they are "
@@ -367,7 +367,17 @@ class cluster : public std::enable_shared_from_this<cluster>
367
367
  }
368
368
 
369
369
  if (origin_.options().enable_tls) {
370
- tls_.set_options(asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
370
+ long tls_options = asio::ssl::context::default_workarounds | // various bug workarounds that should be rather harmless
371
+ asio::ssl::context::no_sslv2 | // published: 1995, deprecated: 2011
372
+ asio::ssl::context::no_sslv3; // published: 1996, deprecated: 2015
373
+ if (origin_.options().tls_disable_deprecated_protocols) {
374
+ tls_options |= asio::ssl::context::no_tlsv1 | // published: 1999, deprecated: 2021
375
+ asio::ssl::context::no_tlsv1_1; // published: 2006, deprecated: 2021
376
+ }
377
+ if (origin_.options().tls_disable_v1_2 || has_capella_host) {
378
+ tls_options |= asio::ssl::context::no_tlsv1_2; // published: 2008, still in use
379
+ }
380
+ tls_.set_options(tls_options);
371
381
  switch (origin_.options().tls_verify) {
372
382
  case tls_verify_mode::none:
373
383
  tls_.set_verify_mode(asio::ssl::verify_none);
@@ -377,7 +387,8 @@ class cluster : public std::enable_shared_from_this<cluster>
377
387
  tls_.set_verify_mode(asio::ssl::verify_peer);
378
388
  break;
379
389
  }
380
- if (origin_.options().trust_certificate.empty()) { // trust certificate is not explicitly specified
390
+ if (origin_.options().trust_certificate.empty() &&
391
+ origin_.options().trust_certificate_value.empty()) { // trust certificate is not explicitly specified
381
392
  CB_LOG_DEBUG(R"([{}]: use default CA for TLS verify)", id_);
382
393
  std::error_code ec{};
383
394
 
@@ -394,15 +405,41 @@ class cluster : public std::enable_shared_from_this<cluster>
394
405
  CB_LOG_WARNING("[{}]: unable to load default CAs: {}", id_, ec.message());
395
406
  // we don't consider this fatal and try to continue without it
396
407
  }
408
+
409
+ if (const auto certificates = default_ca::mozilla_ca_certs();
410
+ !origin_.options().disable_mozilla_ca_certificates && !certificates.empty()) {
411
+ CB_LOG_DEBUG("[{}]: loading {} CA certificates from Mozilla bundle. Update date: \"{}\", SHA256: \"{}\"",
412
+ id_,
413
+ certificates.size(),
414
+ default_ca::mozilla_ca_certs_date(),
415
+ default_ca::mozilla_ca_certs_sha256());
416
+ for (const auto& cert : certificates) {
417
+ tls_.add_certificate_authority(asio::const_buffer(cert.body.data(), cert.body.size()), ec);
418
+ if (ec) {
419
+ CB_LOG_WARNING("[{}]: unable to load CA \"{}\" from Mozilla bundle: {}", id_, cert.authority, ec.message());
420
+ }
421
+ }
422
+ }
397
423
  } else { // trust certificate is explicitly specified
398
424
  std::error_code ec{};
399
425
  // load only the explicit certificate
400
426
  // system and default capella certificates are not loaded
401
- CB_LOG_DEBUG(R"([{}]: use TLS verify file: "{}")", id_, origin_.options().trust_certificate);
402
- tls_.load_verify_file(origin_.options().trust_certificate, ec);
403
- if (ec) {
404
- CB_LOG_ERROR("[{}]: unable to load verify file \"{}\": {}", id_, origin_.options().trust_certificate, ec.message());
405
- return close([ec, handler = std::forward<Handler>(handler)]() mutable { return handler(ec); });
427
+ if (!origin_.options().trust_certificate_value.empty()) {
428
+ CB_LOG_DEBUG(R"([{}]: use TLS certificate passed through via options object)", id_);
429
+ tls_.add_certificate_authority(asio::const_buffer(origin_.options().trust_certificate_value.data(),
430
+ origin_.options().trust_certificate_value.size()),
431
+ ec);
432
+ if (ec) {
433
+ CB_LOG_WARNING("[{}]: unable to load CA passed via options object: {}", id_, ec.message());
434
+ }
435
+ }
436
+ if (!origin_.options().trust_certificate.empty()) {
437
+ CB_LOG_DEBUG(R"([{}]: use TLS verify file: "{}")", id_, origin_.options().trust_certificate);
438
+ tls_.load_verify_file(origin_.options().trust_certificate, ec);
439
+ if (ec) {
440
+ CB_LOG_ERROR("[{}]: unable to load verify file \"{}\": {}", id_, origin_.options().trust_certificate, ec.message());
441
+ return close([ec, handler = std::forward<Handler>(handler)]() mutable { return handler(ec); });
442
+ }
406
443
  }
407
444
  }
408
445
  #ifdef COUCHBASE_CXX_CLIENT_TLS_KEY_LOG_FILE
@@ -430,6 +467,7 @@ class cluster : public std::enable_shared_from_this<cluster>
430
467
  return close([ec, handler = std::forward<Handler>(handler)]() mutable { return handler(ec); });
431
468
  }
432
469
  }
470
+
433
471
  session_ = io::mcbp_session(id_, ctx_, tls_, origin_, dns_srv_tracker_);
434
472
  } else {
435
473
  session_ = io::mcbp_session(id_, ctx_, origin_, dns_srv_tracker_);
@@ -466,7 +504,7 @@ class cluster : public std::enable_shared_from_this<cluster>
466
504
  }
467
505
  self->session_manager_->set_configuration(config, self->origin_.options());
468
506
  self->session_->on_configuration_update(self->session_manager_);
469
- self->session_->on_stop([self](retry_reason) {
507
+ self->session_->on_stop([self]() {
470
508
  if (self->session_) {
471
509
  self->session_.reset();
472
510
  }
@@ -16,7 +16,7 @@
16
16
  */
17
17
 
18
18
  #include "cluster_options.hxx"
19
- #include "config_profile.hxx"
19
+ #include "config_profiles.hxx"
20
20
  #include <stdexcept>
21
21
 
22
22
  namespace couchbase::core
@@ -45,6 +45,6 @@ cluster_options::default_timeout_for(service_type type) const
45
45
  void
46
46
  cluster_options::apply_profile(std::string profile_name)
47
47
  {
48
- couchbase::core::known_profiles().apply(profile_name, *this);
48
+ known_profiles().apply(profile_name, *this);
49
49
  }
50
50
  } // namespace couchbase::core