couchbase 3.5.1 → 3.5.2

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 (1166) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/ext/0001-fix-build-for-mingw-w64-ucrt-x86_64-toolchain.patch +40 -0
  4. data/ext/CMakeLists.txt +22 -2
  5. data/ext/cache/extconf_include.rb +3 -3
  6. data/ext/cache/mozilla-ca-bundle.crt +19 -32
  7. data/ext/cache/mozilla-ca-bundle.sha256 +1 -1
  8. data/ext/couchbase/CMakeLists.txt +16 -9
  9. data/ext/couchbase/cmake/0001-fix-build-for-mingw-w64-ucrt-x86_64-toolchain.patch +3 -4
  10. data/ext/couchbase/cmake/CompilerWarnings.cmake +2 -1
  11. data/ext/couchbase/cmake/Packaging.cmake +41 -0
  12. data/ext/couchbase/cmake/Sanitizers.cmake +1 -0
  13. data/ext/couchbase/cmake/VersionInfo.cmake +5 -5
  14. data/ext/couchbase/cmake/build_version.hxx.in +1 -0
  15. data/ext/couchbase/cmake/couchbase-cxx-client.pc.in +10 -0
  16. data/ext/couchbase/cmake/test_boringssl.cxx +1 -1
  17. data/ext/couchbase/cmake/test_openssl.cxx +1 -1
  18. data/ext/couchbase/core/agent.cxx +353 -304
  19. data/ext/couchbase/core/agent.hxx +94 -76
  20. data/ext/couchbase/core/agent_config.cxx +9 -8
  21. data/ext/couchbase/core/agent_config.hxx +7 -7
  22. data/ext/couchbase/core/agent_group.cxx +132 -120
  23. data/ext/couchbase/core/agent_group.hxx +26 -22
  24. data/ext/couchbase/core/agent_group_config.cxx +8 -7
  25. data/ext/couchbase/core/agent_group_config.hxx +6 -6
  26. data/ext/couchbase/core/agent_unit_test_api.hxx +6 -6
  27. data/ext/couchbase/core/analytics_query_options.cxx +21 -21
  28. data/ext/couchbase/core/analytics_query_options.hxx +19 -18
  29. data/ext/couchbase/core/analytics_scan_consistency.hxx +2 -2
  30. data/ext/couchbase/core/bucket.cxx +848 -776
  31. data/ext/couchbase/core/bucket.hxx +151 -139
  32. data/ext/couchbase/core/capella_ca.hxx +20 -19
  33. data/ext/couchbase/core/cluster.cxx +1240 -927
  34. data/ext/couchbase/core/cluster.hxx +254 -167
  35. data/ext/couchbase/core/cluster_agent.cxx +7 -7
  36. data/ext/couchbase/core/cluster_agent.hxx +4 -4
  37. data/ext/couchbase/core/cluster_agent_config.cxx +8 -7
  38. data/ext/couchbase/core/cluster_agent_config.hxx +6 -6
  39. data/ext/couchbase/core/cluster_options.cxx +17 -17
  40. data/ext/couchbase/core/cluster_options.hxx +50 -47
  41. data/ext/couchbase/core/cluster_state.hxx +3 -3
  42. data/ext/couchbase/core/collection_id_cache_entry.hxx +5 -4
  43. data/ext/couchbase/core/collections_component.cxx +372 -329
  44. data/ext/couchbase/core/collections_component.hxx +17 -13
  45. data/ext/couchbase/core/collections_component_unit_test_api.hxx +6 -6
  46. data/ext/couchbase/core/collections_options.hxx +29 -27
  47. data/ext/couchbase/core/config_listener.hxx +3 -3
  48. data/ext/couchbase/core/config_profile.hxx +3 -3
  49. data/ext/couchbase/core/config_profiles.cxx +31 -31
  50. data/ext/couchbase/core/config_profiles.hxx +19 -19
  51. data/ext/couchbase/core/core_sdk_shim.cxx +2 -1
  52. data/ext/couchbase/core/core_sdk_shim.hxx +2 -2
  53. data/ext/couchbase/core/crud_component.cxx +310 -276
  54. data/ext/couchbase/core/crud_component.hxx +21 -15
  55. data/ext/couchbase/core/crud_options.hxx +361 -354
  56. data/ext/couchbase/core/crypto/cbcrypto.cc +732 -627
  57. data/ext/couchbase/core/crypto/cbcrypto.h +12 -3
  58. data/ext/couchbase/core/design_document_namespace.hxx +2 -2
  59. data/ext/couchbase/core/design_document_namespace_fmt.hxx +18 -18
  60. data/ext/couchbase/core/diagnostics.hxx +44 -44
  61. data/ext/couchbase/core/diagnostics_fmt.hxx +76 -76
  62. data/ext/couchbase/core/diagnostics_json.hxx +61 -60
  63. data/ext/couchbase/core/diagntostics_options.hxx +14 -14
  64. data/ext/couchbase/core/dispatcher.cxx +4 -3
  65. data/ext/couchbase/core/dispatcher.hxx +8 -7
  66. data/ext/couchbase/core/document_id.cxx +37 -34
  67. data/ext/couchbase/core/document_id.hxx +87 -86
  68. data/ext/couchbase/core/document_id_fmt.hxx +10 -10
  69. data/ext/couchbase/core/durability_options.hxx +50 -49
  70. data/ext/couchbase/core/error_context/analytics.hxx +18 -18
  71. data/ext/couchbase/core/error_context/analytics_json.hxx +115 -0
  72. data/ext/couchbase/core/error_context/base_error_context.hxx +184 -0
  73. data/ext/couchbase/core/error_context/http.hxx +14 -14
  74. data/ext/couchbase/core/error_context/http_json.hxx +90 -0
  75. data/ext/couchbase/core/error_context/internal_tof_metadata_json.hxx +36 -0
  76. data/ext/couchbase/core/error_context/key_value.cxx +27 -27
  77. data/ext/couchbase/core/error_context/key_value.hxx +41 -38
  78. data/ext/couchbase/core/error_context/key_value_error_context.hxx +235 -0
  79. data/ext/couchbase/core/error_context/key_value_error_map_attribute.hxx +142 -0
  80. data/ext/couchbase/core/error_context/key_value_error_map_info.hxx +139 -0
  81. data/ext/couchbase/core/error_context/key_value_extended_error_info.hxx +86 -0
  82. data/ext/couchbase/core/error_context/key_value_json.hxx +83 -0
  83. data/ext/couchbase/core/error_context/key_value_status_code.hxx +109 -0
  84. data/ext/couchbase/core/error_context/query.hxx +18 -18
  85. data/ext/couchbase/core/error_context/query_error_context.hxx +150 -0
  86. data/ext/couchbase/core/error_context/query_json.hxx +114 -0
  87. data/ext/couchbase/core/error_context/query_public_json.hxx +84 -0
  88. data/ext/couchbase/core/error_context/search.hxx +17 -17
  89. data/ext/couchbase/core/error_context/search_json.hxx +101 -0
  90. data/ext/couchbase/core/error_context/subdocument_error_context.hxx +147 -0
  91. data/ext/couchbase/core/error_context/subdocument_json.hxx +48 -0
  92. data/ext/couchbase/{couchbase → core/error_context}/transaction_error_context.hxx +22 -22
  93. data/ext/couchbase/core/error_context/transaction_op_error_context.hxx +79 -0
  94. data/ext/couchbase/core/error_context/view.hxx +17 -17
  95. data/ext/couchbase/core/fmt/key_value_error_map_attribute.hxx +100 -0
  96. data/ext/couchbase/{couchbase → core}/fmt/key_value_extended_error_info.hxx +20 -20
  97. data/ext/couchbase/core/fmt/key_value_status_code.hxx +269 -0
  98. data/ext/couchbase/core/free_form_http_request.cxx +26 -26
  99. data/ext/couchbase/core/free_form_http_request.hxx +34 -33
  100. data/ext/couchbase/core/impl/analytics.cxx +111 -131
  101. data/ext/couchbase/core/impl/analytics.hxx +5 -7
  102. data/ext/couchbase/core/impl/analytics_error_category.cxx +29 -28
  103. data/ext/couchbase/core/impl/analytics_index_manager.cxx +615 -516
  104. data/ext/couchbase/core/impl/best_effort_retry_strategy.cxx +53 -50
  105. data/ext/couchbase/core/impl/binary_collection.cxx +346 -285
  106. data/ext/couchbase/core/impl/boolean_field_query.cxx +10 -10
  107. data/ext/couchbase/core/impl/boolean_query.cxx +27 -27
  108. data/ext/couchbase/core/impl/bootstrap_state_listener.hxx +6 -6
  109. data/ext/couchbase/core/impl/bucket.cxx +39 -34
  110. data/ext/couchbase/core/impl/bucket_manager.cxx +354 -313
  111. data/ext/couchbase/core/impl/cluster.cxx +430 -325
  112. data/ext/couchbase/core/impl/collection.cxx +1033 -1187
  113. data/ext/couchbase/core/impl/collection_manager.cxx +201 -170
  114. data/ext/couchbase/core/impl/common_error_category.cxx +58 -55
  115. data/ext/couchbase/core/impl/configuration_profiles_registry.cxx +46 -32
  116. data/ext/couchbase/core/impl/conjunction_query.cxx +17 -17
  117. data/ext/couchbase/core/impl/date_range.cxx +24 -20
  118. data/ext/couchbase/core/impl/date_range_facet.cxx +22 -22
  119. data/ext/couchbase/core/impl/date_range_facet_result.cxx +6 -6
  120. data/ext/couchbase/core/impl/date_range_query.cxx +50 -48
  121. data/ext/couchbase/core/impl/diagnostics.cxx +211 -198
  122. data/ext/couchbase/core/impl/diagnostics.hxx +7 -6
  123. data/ext/couchbase/core/impl/disjunction_query.cxx +18 -17
  124. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +92 -75
  125. data/ext/couchbase/core/impl/dns_srv_tracker.hxx +24 -20
  126. data/ext/couchbase/core/impl/doc_id_query.cxx +9 -9
  127. data/ext/couchbase/core/impl/encoded_search_facet.hxx +2 -2
  128. data/ext/couchbase/core/impl/encoded_search_query.hxx +2 -2
  129. data/ext/couchbase/core/impl/encoded_search_sort.hxx +2 -2
  130. data/ext/couchbase/core/impl/error.cxx +171 -0
  131. data/ext/couchbase/core/impl/error.hxx +64 -0
  132. data/ext/couchbase/core/impl/error_context.cxx +56 -0
  133. data/ext/couchbase/core/impl/expiry.cxx +66 -53
  134. data/ext/couchbase/core/impl/fail_fast_retry_strategy.cxx +5 -4
  135. data/ext/couchbase/core/impl/field_level_encryption_error_category.cxx +30 -28
  136. data/ext/couchbase/core/impl/geo_bounding_box_query.cxx +17 -17
  137. data/ext/couchbase/core/impl/geo_distance_query.cxx +14 -14
  138. data/ext/couchbase/core/impl/geo_polygon_query.cxx +17 -17
  139. data/ext/couchbase/core/impl/get_all_replicas.hxx +26 -22
  140. data/ext/couchbase/core/impl/get_any_replica.hxx +25 -23
  141. data/ext/couchbase/core/impl/get_replica.cxx +18 -15
  142. data/ext/couchbase/core/impl/get_replica.hxx +23 -18
  143. data/ext/couchbase/core/impl/internal_date_range_facet_result.cxx +16 -14
  144. data/ext/couchbase/core/impl/internal_date_range_facet_result.hxx +16 -15
  145. data/ext/couchbase/core/impl/internal_error_context.cxx +79 -0
  146. data/ext/couchbase/core/impl/internal_error_context.hxx +52 -0
  147. data/ext/couchbase/core/impl/internal_numeric_range_facet_result.cxx +18 -15
  148. data/ext/couchbase/core/impl/internal_numeric_range_facet_result.hxx +16 -15
  149. data/ext/couchbase/core/impl/internal_scan_result.hxx +7 -7
  150. data/ext/couchbase/core/impl/internal_search_error_context.cxx +25 -22
  151. data/ext/couchbase/core/impl/internal_search_error_context.hxx +32 -31
  152. data/ext/couchbase/core/impl/internal_search_meta_data.cxx +15 -13
  153. data/ext/couchbase/core/impl/internal_search_meta_data.hxx +10 -9
  154. data/ext/couchbase/core/impl/internal_search_result.cxx +30 -22
  155. data/ext/couchbase/core/impl/internal_search_result.hxx +10 -9
  156. data/ext/couchbase/core/impl/internal_search_row.cxx +10 -10
  157. data/ext/couchbase/core/impl/internal_search_row.hxx +16 -16
  158. data/ext/couchbase/core/impl/internal_search_row_location.hxx +2 -2
  159. data/ext/couchbase/core/impl/internal_search_row_locations.cxx +68 -65
  160. data/ext/couchbase/core/impl/internal_search_row_locations.hxx +16 -13
  161. data/ext/couchbase/core/impl/internal_term_facet_result.cxx +16 -14
  162. data/ext/couchbase/core/impl/internal_term_facet_result.hxx +15 -15
  163. data/ext/couchbase/core/impl/key_value_error_category.cxx +73 -72
  164. data/ext/couchbase/core/impl/key_value_error_context.cxx +65 -65
  165. data/ext/couchbase/core/impl/logger.cxx +91 -0
  166. data/ext/couchbase/core/impl/lookup_in_all_replicas.hxx +32 -29
  167. data/ext/couchbase/core/impl/lookup_in_any_replica.hxx +33 -29
  168. data/ext/couchbase/core/impl/lookup_in_replica.cxx +75 -68
  169. data/ext/couchbase/core/impl/lookup_in_replica.hxx +30 -26
  170. data/ext/couchbase/core/impl/management_error_category.cxx +41 -40
  171. data/ext/couchbase/core/impl/match_all_query.cxx +6 -6
  172. data/ext/couchbase/core/impl/match_none_query.cxx +6 -6
  173. data/ext/couchbase/core/impl/match_phrase_query.cxx +13 -13
  174. data/ext/couchbase/core/impl/match_query.cxx +28 -28
  175. data/ext/couchbase/core/impl/network_error_category.cxx +39 -38
  176. data/ext/couchbase/core/impl/numeric_range.cxx +6 -6
  177. data/ext/couchbase/core/impl/numeric_range_facet.cxx +22 -22
  178. data/ext/couchbase/core/impl/numeric_range_facet_result.cxx +6 -6
  179. data/ext/couchbase/core/impl/numeric_range_query.cxx +22 -22
  180. data/ext/couchbase/core/impl/observe_poll.cxx +294 -277
  181. data/ext/couchbase/core/impl/observe_poll.hxx +1 -1
  182. data/ext/couchbase/core/impl/observe_seqno.cxx +21 -18
  183. data/ext/couchbase/core/impl/observe_seqno.hxx +31 -26
  184. data/ext/couchbase/core/impl/phrase_query.cxx +10 -10
  185. data/ext/couchbase/core/impl/prefix_query.cxx +10 -10
  186. data/ext/couchbase/core/impl/query.cxx +163 -154
  187. data/ext/couchbase/core/impl/query.hxx +6 -7
  188. data/ext/couchbase/core/impl/query_error_category.cxx +22 -21
  189. data/ext/couchbase/core/impl/query_error_context.cxx +45 -45
  190. data/ext/couchbase/core/impl/query_index_manager.cxx +488 -408
  191. data/ext/couchbase/core/impl/query_string_query.cxx +7 -7
  192. data/ext/couchbase/core/impl/regexp_query.cxx +10 -10
  193. data/ext/couchbase/core/impl/replica_utils.cxx +66 -0
  194. data/ext/couchbase/core/impl/replica_utils.hxx +48 -0
  195. data/ext/couchbase/core/impl/retry_action.cxx +3 -3
  196. data/ext/couchbase/core/impl/retry_reason.cxx +129 -56
  197. data/ext/couchbase/core/impl/retry_reason.hxx +28 -0
  198. data/ext/couchbase/core/impl/scan_result.cxx +53 -49
  199. data/ext/couchbase/core/impl/scope.cxx +103 -94
  200. data/ext/couchbase/core/impl/search.cxx +139 -130
  201. data/ext/couchbase/core/impl/search.hxx +4 -4
  202. data/ext/couchbase/core/impl/search_error_category.cxx +18 -17
  203. data/ext/couchbase/core/impl/search_index_manager.cxx +492 -390
  204. data/ext/couchbase/core/impl/search_meta_data.cxx +3 -3
  205. data/ext/couchbase/core/impl/search_request.cxx +78 -78
  206. data/ext/couchbase/core/impl/search_result.cxx +5 -5
  207. data/ext/couchbase/core/impl/search_row.cxx +7 -7
  208. data/ext/couchbase/core/impl/search_row_location.cxx +9 -8
  209. data/ext/couchbase/core/impl/search_row_locations.cxx +8 -7
  210. data/ext/couchbase/core/impl/search_sort_field.cxx +53 -53
  211. data/ext/couchbase/core/impl/search_sort_geo_distance.cxx +49 -48
  212. data/ext/couchbase/core/impl/search_sort_id.cxx +10 -10
  213. data/ext/couchbase/core/impl/search_sort_score.cxx +10 -10
  214. data/ext/couchbase/core/impl/streaming_json_lexer_error_category.cxx +70 -68
  215. data/ext/couchbase/core/impl/subdoc/array_add_unique.cxx +6 -6
  216. data/ext/couchbase/core/impl/subdoc/array_append.cxx +6 -6
  217. data/ext/couchbase/core/impl/subdoc/array_insert.cxx +6 -6
  218. data/ext/couchbase/core/impl/subdoc/array_prepend.cxx +6 -6
  219. data/ext/couchbase/core/impl/subdoc/command.hxx +5 -5
  220. data/ext/couchbase/core/impl/subdoc/command_bundle.hxx +11 -11
  221. data/ext/couchbase/core/impl/subdoc/count.cxx +6 -6
  222. data/ext/couchbase/core/impl/subdoc/counter.cxx +6 -6
  223. data/ext/couchbase/core/impl/subdoc/exists.cxx +6 -6
  224. data/ext/couchbase/core/impl/subdoc/get.cxx +6 -6
  225. data/ext/couchbase/core/impl/subdoc/insert.cxx +6 -6
  226. data/ext/couchbase/core/impl/subdoc/join_values.cxx +25 -25
  227. data/ext/couchbase/core/impl/subdoc/lookup_in_macro.cxx +61 -60
  228. data/ext/couchbase/core/impl/subdoc/lookup_in_specs.cxx +9 -9
  229. data/ext/couchbase/core/impl/subdoc/mutate_in_macro.cxx +48 -39
  230. data/ext/couchbase/core/impl/subdoc/mutate_in_specs.cxx +9 -9
  231. data/ext/couchbase/core/impl/subdoc/opcode.hxx +16 -16
  232. data/ext/couchbase/core/impl/subdoc/path_flags.hxx +40 -17
  233. data/ext/couchbase/core/impl/subdoc/remove.cxx +6 -6
  234. data/ext/couchbase/core/impl/subdoc/replace.cxx +6 -6
  235. data/ext/couchbase/core/impl/subdoc/upsert.cxx +6 -6
  236. data/ext/couchbase/core/impl/term_facet.cxx +8 -8
  237. data/ext/couchbase/core/impl/term_facet_result.cxx +6 -6
  238. data/ext/couchbase/core/impl/term_query.cxx +25 -25
  239. data/ext/couchbase/core/impl/term_range_query.cxx +22 -22
  240. data/ext/couchbase/core/impl/transaction_error_category.cxx +21 -20
  241. data/ext/couchbase/core/impl/transaction_get_result.cxx +41 -30
  242. data/ext/couchbase/core/impl/transaction_op_error_category.cxx +55 -56
  243. data/ext/couchbase/core/impl/vector_query.cxx +15 -10
  244. data/ext/couchbase/core/impl/vector_search.cxx +9 -9
  245. data/ext/couchbase/core/impl/view_error_category.cxx +17 -16
  246. data/ext/couchbase/core/impl/wildcard_query.cxx +10 -10
  247. data/ext/couchbase/core/impl/with_legacy_durability.hxx +30 -29
  248. data/ext/couchbase/core/io/dns_client.cxx +257 -232
  249. data/ext/couchbase/core/io/dns_client.hxx +19 -18
  250. data/ext/couchbase/core/io/dns_codec.hxx +156 -154
  251. data/ext/couchbase/core/io/dns_config.cxx +114 -109
  252. data/ext/couchbase/core/io/dns_config.hxx +15 -13
  253. data/ext/couchbase/core/io/dns_message.hxx +365 -342
  254. data/ext/couchbase/core/io/http_command.hxx +155 -134
  255. data/ext/couchbase/core/io/http_context.hxx +5 -5
  256. data/ext/couchbase/core/io/http_message.hxx +75 -71
  257. data/ext/couchbase/core/io/http_parser.cxx +70 -67
  258. data/ext/couchbase/core/io/http_parser.hxx +18 -18
  259. data/ext/couchbase/core/io/http_session.hxx +620 -520
  260. data/ext/couchbase/core/io/http_session_manager.hxx +406 -315
  261. data/ext/couchbase/core/io/http_traits.hxx +7 -0
  262. data/ext/couchbase/core/io/ip_protocol.hxx +3 -3
  263. data/ext/couchbase/core/io/mcbp_command.hxx +298 -278
  264. data/ext/couchbase/core/io/mcbp_context.hxx +7 -6
  265. data/ext/couchbase/core/io/mcbp_message.cxx +8 -8
  266. data/ext/couchbase/core/io/mcbp_message.hxx +19 -19
  267. data/ext/couchbase/core/io/mcbp_parser.cxx +60 -51
  268. data/ext/couchbase/core/io/mcbp_parser.hxx +21 -17
  269. data/ext/couchbase/core/io/mcbp_session.cxx +1769 -1616
  270. data/ext/couchbase/core/io/mcbp_session.hxx +63 -57
  271. data/ext/couchbase/core/io/query_cache.hxx +34 -34
  272. data/ext/couchbase/core/io/retry_context.hxx +45 -45
  273. data/ext/couchbase/core/io/retry_orchestrator.hxx +52 -42
  274. data/ext/couchbase/core/io/streams.hxx +210 -193
  275. data/ext/couchbase/core/json_string.hxx +47 -47
  276. data/ext/couchbase/core/key_value_config.cxx +8 -8
  277. data/ext/couchbase/core/key_value_config.hxx +12 -11
  278. data/ext/couchbase/core/logger/configuration.hxx +35 -35
  279. data/ext/couchbase/core/logger/custom_rotating_file_sink.cxx +73 -72
  280. data/ext/couchbase/core/logger/custom_rotating_file_sink.hxx +20 -18
  281. data/ext/couchbase/core/logger/level.hxx +9 -1
  282. data/ext/couchbase/core/logger/logger.cxx +279 -252
  283. data/ext/couchbase/core/logger/logger.hxx +110 -58
  284. data/ext/couchbase/core/management/analytics_dataset.hxx +4 -4
  285. data/ext/couchbase/core/management/analytics_index.hxx +4 -4
  286. data/ext/couchbase/core/management/analytics_link_azure_blob_external.cxx +35 -33
  287. data/ext/couchbase/core/management/analytics_link_azure_blob_external.hxx +36 -35
  288. data/ext/couchbase/core/management/analytics_link_azure_blob_external_json.hxx +24 -20
  289. data/ext/couchbase/core/management/analytics_link_couchbase_remote.cxx +66 -65
  290. data/ext/couchbase/core/management/analytics_link_couchbase_remote.hxx +77 -70
  291. data/ext/couchbase/core/management/analytics_link_couchbase_remote_json.hxx +38 -32
  292. data/ext/couchbase/core/management/analytics_link_s3_external.cxx +26 -25
  293. data/ext/couchbase/core/management/analytics_link_s3_external.hxx +30 -30
  294. data/ext/couchbase/core/management/analytics_link_s3_external_json.hxx +18 -16
  295. data/ext/couchbase/core/management/bucket_settings.hxx +109 -91
  296. data/ext/couchbase/core/management/bucket_settings_json.hxx +112 -94
  297. data/ext/couchbase/core/management/design_document.hxx +9 -9
  298. data/ext/couchbase/core/management/eventing_function.hxx +124 -121
  299. data/ext/couchbase/core/management/eventing_function_json.hxx +228 -184
  300. data/ext/couchbase/core/management/eventing_status.hxx +41 -41
  301. data/ext/couchbase/core/management/eventing_status_json.hxx +53 -45
  302. data/ext/couchbase/core/management/rbac.hxx +33 -28
  303. data/ext/couchbase/core/management/rbac_fmt.hxx +21 -21
  304. data/ext/couchbase/core/management/rbac_json.hxx +132 -125
  305. data/ext/couchbase/core/management/search_index.cxx +79 -0
  306. data/ext/couchbase/core/management/search_index.hxx +11 -10
  307. data/ext/couchbase/core/management/search_index_json.hxx +27 -26
  308. data/ext/couchbase/core/mcbp/barrier_frame.hxx +4 -3
  309. data/ext/couchbase/core/mcbp/big_endian.cxx +22 -22
  310. data/ext/couchbase/core/mcbp/buffer_writer.cxx +22 -19
  311. data/ext/couchbase/core/mcbp/buffer_writer.hxx +9 -9
  312. data/ext/couchbase/core/mcbp/codec.cxx +419 -397
  313. data/ext/couchbase/core/mcbp/codec.hxx +14 -12
  314. data/ext/couchbase/core/mcbp/command_code.cxx +48 -48
  315. data/ext/couchbase/core/mcbp/completion_token.hxx +33 -33
  316. data/ext/couchbase/core/mcbp/datatype.hxx +3 -3
  317. data/ext/couchbase/core/mcbp/durability_level.hxx +8 -7
  318. data/ext/couchbase/core/mcbp/durability_level_frame.hxx +3 -2
  319. data/ext/couchbase/core/mcbp/durability_timeout_frame.hxx +4 -3
  320. data/ext/couchbase/core/mcbp/open_tracing_frame.hxx +3 -2
  321. data/ext/couchbase/core/mcbp/operation_consumer.cxx +3 -3
  322. data/ext/couchbase/core/mcbp/operation_consumer.hxx +9 -9
  323. data/ext/couchbase/core/mcbp/operation_queue.cxx +76 -70
  324. data/ext/couchbase/core/mcbp/operation_queue.hxx +18 -17
  325. data/ext/couchbase/core/mcbp/packet.cxx +65 -51
  326. data/ext/couchbase/core/mcbp/packet.hxx +25 -25
  327. data/ext/couchbase/core/mcbp/preserve_expiry_frame.hxx +4 -2
  328. data/ext/couchbase/core/mcbp/queue_callback.hxx +3 -2
  329. data/ext/couchbase/core/mcbp/queue_request.cxx +65 -62
  330. data/ext/couchbase/core/mcbp/queue_request.hxx +54 -52
  331. data/ext/couchbase/core/mcbp/queue_request_connection_info.hxx +3 -3
  332. data/ext/couchbase/core/mcbp/queue_response.hxx +7 -7
  333. data/ext/couchbase/core/mcbp/read_units_frame.hxx +3 -2
  334. data/ext/couchbase/core/mcbp/server_duration.cxx +7 -7
  335. data/ext/couchbase/core/mcbp/server_duration_frame.hxx +3 -2
  336. data/ext/couchbase/core/mcbp/stream_id_frame.hxx +3 -2
  337. data/ext/couchbase/core/mcbp/unsupported_frame.hxx +4 -3
  338. data/ext/couchbase/core/mcbp/user_impersonation_frame.hxx +1 -1
  339. data/ext/couchbase/core/mcbp/write_units_frame.hxx +3 -2
  340. data/ext/couchbase/core/meta/features.hxx +58 -0
  341. data/ext/couchbase/core/meta/version.cxx +255 -204
  342. data/ext/couchbase/core/meta/version.hxx +31 -20
  343. data/ext/couchbase/core/metrics/logging_meter.cxx +160 -154
  344. data/ext/couchbase/core/metrics/logging_meter.hxx +16 -15
  345. data/ext/couchbase/core/metrics/logging_meter_options.hxx +1 -1
  346. data/ext/couchbase/core/metrics/noop_meter.hxx +14 -13
  347. data/ext/couchbase/core/mozilla_ca_bundle.hxx +2 -2
  348. data/ext/couchbase/core/n1ql_query_options.cxx +31 -31
  349. data/ext/couchbase/core/n1ql_query_options.hxx +22 -21
  350. data/ext/couchbase/core/operation_map.hxx +3 -3
  351. data/ext/couchbase/core/operations/document_analytics.cxx +187 -176
  352. data/ext/couchbase/core/operations/document_analytics.hxx +79 -71
  353. data/ext/couchbase/core/operations/document_append.cxx +18 -15
  354. data/ext/couchbase/core/operations/document_append.hxx +18 -16
  355. data/ext/couchbase/core/operations/document_decrement.cxx +26 -23
  356. data/ext/couchbase/core/operations/document_decrement.hxx +24 -20
  357. data/ext/couchbase/core/operations/document_exists.cxx +23 -21
  358. data/ext/couchbase/core/operations/document_exists.hxx +25 -23
  359. data/ext/couchbase/core/operations/document_get.cxx +17 -15
  360. data/ext/couchbase/core/operations/document_get.hxx +17 -15
  361. data/ext/couchbase/core/operations/document_get_all_replicas.hxx +121 -92
  362. data/ext/couchbase/core/operations/document_get_and_lock.cxx +19 -16
  363. data/ext/couchbase/core/operations/document_get_and_lock.hxx +21 -17
  364. data/ext/couchbase/core/operations/document_get_and_touch.cxx +19 -16
  365. data/ext/couchbase/core/operations/document_get_and_touch.hxx +22 -18
  366. data/ext/couchbase/core/operations/document_get_any_replica.hxx +111 -82
  367. data/ext/couchbase/core/operations/document_get_projected.cxx +193 -184
  368. data/ext/couchbase/core/operations/document_get_projected.hxx +25 -21
  369. data/ext/couchbase/core/operations/document_increment.cxx +26 -23
  370. data/ext/couchbase/core/operations/document_increment.hxx +24 -20
  371. data/ext/couchbase/core/operations/document_insert.cxx +23 -20
  372. data/ext/couchbase/core/operations/document_insert.hxx +20 -18
  373. data/ext/couchbase/core/operations/document_lookup_in.cxx +80 -67
  374. data/ext/couchbase/core/operations/document_lookup_in.hxx +31 -27
  375. data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +187 -149
  376. data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +190 -145
  377. data/ext/couchbase/core/operations/document_mutate_in.cxx +98 -80
  378. data/ext/couchbase/core/operations/document_mutate_in.hxx +38 -33
  379. data/ext/couchbase/core/operations/document_prepend.cxx +18 -15
  380. data/ext/couchbase/core/operations/document_prepend.hxx +18 -16
  381. data/ext/couchbase/core/operations/document_query.cxx +367 -356
  382. data/ext/couchbase/core/operations/document_query.hxx +83 -79
  383. data/ext/couchbase/core/operations/document_remove.cxx +18 -15
  384. data/ext/couchbase/core/operations/document_remove.hxx +18 -16
  385. data/ext/couchbase/core/operations/document_replace.cxx +27 -24
  386. data/ext/couchbase/core/operations/document_replace.hxx +22 -20
  387. data/ext/couchbase/core/operations/document_search.cxx +322 -308
  388. data/ext/couchbase/core/operations/document_search.hxx +125 -121
  389. data/ext/couchbase/core/operations/document_touch.cxx +16 -14
  390. data/ext/couchbase/core/operations/document_touch.hxx +19 -17
  391. data/ext/couchbase/core/operations/document_unlock.cxx +16 -14
  392. data/ext/couchbase/core/operations/document_unlock.hxx +19 -17
  393. data/ext/couchbase/core/operations/document_upsert.cxx +26 -23
  394. data/ext/couchbase/core/operations/document_upsert.hxx +21 -19
  395. data/ext/couchbase/core/operations/document_view.cxx +169 -159
  396. data/ext/couchbase/core/operations/document_view.hxx +68 -65
  397. data/ext/couchbase/core/operations/http_noop.cxx +38 -35
  398. data/ext/couchbase/core/operations/http_noop.hxx +12 -10
  399. data/ext/couchbase/core/operations/management/analytics_dataset_create.cxx +58 -56
  400. data/ext/couchbase/core/operations/management/analytics_dataset_create.hxx +20 -17
  401. data/ext/couchbase/core/operations/management/analytics_dataset_drop.cxx +49 -44
  402. data/ext/couchbase/core/operations/management/analytics_dataset_drop.hxx +18 -15
  403. data/ext/couchbase/core/operations/management/analytics_dataset_get_all.cxx +46 -43
  404. data/ext/couchbase/core/operations/management/analytics_dataset_get_all.hxx +16 -13
  405. data/ext/couchbase/core/operations/management/analytics_dataverse_create.cxx +48 -43
  406. data/ext/couchbase/core/operations/management/analytics_dataverse_create.hxx +17 -14
  407. data/ext/couchbase/core/operations/management/analytics_dataverse_drop.cxx +48 -43
  408. data/ext/couchbase/core/operations/management/analytics_dataverse_drop.hxx +17 -14
  409. data/ext/couchbase/core/operations/management/analytics_get_pending_mutations.cxx +38 -35
  410. data/ext/couchbase/core/operations/management/analytics_get_pending_mutations.hxx +16 -14
  411. data/ext/couchbase/core/operations/management/analytics_index_create.cxx +68 -66
  412. data/ext/couchbase/core/operations/management/analytics_index_create.hxx +20 -17
  413. data/ext/couchbase/core/operations/management/analytics_index_drop.cxx +56 -51
  414. data/ext/couchbase/core/operations/management/analytics_index_drop.hxx +19 -16
  415. data/ext/couchbase/core/operations/management/analytics_index_get_all.cxx +44 -42
  416. data/ext/couchbase/core/operations/management/analytics_index_get_all.hxx +16 -13
  417. data/ext/couchbase/core/operations/management/analytics_link_connect.cxx +49 -43
  418. data/ext/couchbase/core/operations/management/analytics_link_connect.hxx +23 -20
  419. data/ext/couchbase/core/operations/management/analytics_link_create.cxx +52 -51
  420. data/ext/couchbase/core/operations/management/analytics_link_create.hxx +33 -30
  421. data/ext/couchbase/core/operations/management/analytics_link_disconnect.cxx +46 -42
  422. data/ext/couchbase/core/operations/management/analytics_link_disconnect.hxx +22 -19
  423. data/ext/couchbase/core/operations/management/analytics_link_drop.cxx +70 -67
  424. data/ext/couchbase/core/operations/management/analytics_link_drop.hxx +22 -19
  425. data/ext/couchbase/core/operations/management/analytics_link_get_all.cxx +92 -85
  426. data/ext/couchbase/core/operations/management/analytics_link_get_all.hxx +27 -24
  427. data/ext/couchbase/core/operations/management/analytics_link_replace.cxx +52 -51
  428. data/ext/couchbase/core/operations/management/analytics_link_replace.hxx +33 -30
  429. data/ext/couchbase/core/operations/management/analytics_link_utils.hxx +6 -4
  430. data/ext/couchbase/core/operations/management/analytics_problem.hxx +2 -2
  431. data/ext/couchbase/core/operations/management/bucket_create.cxx +158 -149
  432. data/ext/couchbase/core/operations/management/bucket_create.hxx +14 -12
  433. data/ext/couchbase/core/operations/management/bucket_describe.cxx +118 -42
  434. data/ext/couchbase/core/operations/management/bucket_describe.hxx +47 -22
  435. data/ext/couchbase/core/operations/management/bucket_drop.cxx +19 -18
  436. data/ext/couchbase/core/operations/management/bucket_drop.hxx +13 -11
  437. data/ext/couchbase/core/operations/management/bucket_flush.cxx +25 -24
  438. data/ext/couchbase/core/operations/management/bucket_flush.hxx +13 -11
  439. data/ext/couchbase/core/operations/management/bucket_get.cxx +24 -22
  440. data/ext/couchbase/core/operations/management/bucket_get.hxx +14 -12
  441. data/ext/couchbase/core/operations/management/bucket_get_all.cxx +25 -23
  442. data/ext/couchbase/core/operations/management/bucket_get_all.hxx +13 -11
  443. data/ext/couchbase/core/operations/management/bucket_update.cxx +112 -107
  444. data/ext/couchbase/core/operations/management/bucket_update.hxx +15 -13
  445. data/ext/couchbase/core/operations/management/change_password.cxx +22 -20
  446. data/ext/couchbase/core/operations/management/change_password.hxx +13 -11
  447. data/ext/couchbase/core/operations/management/cluster_describe.cxx +52 -50
  448. data/ext/couchbase/core/operations/management/cluster_describe.hxx +31 -29
  449. data/ext/couchbase/core/operations/management/cluster_developer_preview_enable.cxx +14 -12
  450. data/ext/couchbase/core/operations/management/cluster_developer_preview_enable.hxx +13 -11
  451. data/ext/couchbase/core/operations/management/collection_create.cxx +48 -46
  452. data/ext/couchbase/core/operations/management/collection_create.hxx +19 -16
  453. data/ext/couchbase/core/operations/management/collection_drop.cxx +37 -35
  454. data/ext/couchbase/core/operations/management/collection_drop.hxx +16 -14
  455. data/ext/couchbase/core/operations/management/collection_update.cxx +49 -47
  456. data/ext/couchbase/core/operations/management/collection_update.hxx +19 -16
  457. data/ext/couchbase/core/operations/management/collections_manifest_get.cxx +11 -9
  458. data/ext/couchbase/core/operations/management/collections_manifest_get.hxx +17 -13
  459. data/ext/couchbase/core/operations/management/error_utils.cxx +210 -198
  460. data/ext/couchbase/core/operations/management/error_utils.hxx +3 -1
  461. data/ext/couchbase/core/operations/management/eventing_deploy_function.cxx +30 -28
  462. data/ext/couchbase/core/operations/management/eventing_deploy_function.hxx +17 -14
  463. data/ext/couchbase/core/operations/management/eventing_drop_function.cxx +31 -29
  464. data/ext/couchbase/core/operations/management/eventing_drop_function.hxx +17 -14
  465. data/ext/couchbase/core/operations/management/eventing_get_all_functions.cxx +49 -43
  466. data/ext/couchbase/core/operations/management/eventing_get_all_functions.hxx +17 -14
  467. data/ext/couchbase/core/operations/management/eventing_get_function.cxx +29 -27
  468. data/ext/couchbase/core/operations/management/eventing_get_function.hxx +18 -15
  469. data/ext/couchbase/core/operations/management/eventing_get_status.cxx +45 -39
  470. data/ext/couchbase/core/operations/management/eventing_get_status.hxx +17 -14
  471. data/ext/couchbase/core/operations/management/eventing_pause_function.cxx +30 -28
  472. data/ext/couchbase/core/operations/management/eventing_pause_function.hxx +17 -14
  473. data/ext/couchbase/core/operations/management/eventing_problem.hxx +3 -3
  474. data/ext/couchbase/core/operations/management/eventing_resume_function.cxx +30 -28
  475. data/ext/couchbase/core/operations/management/eventing_resume_function.hxx +17 -14
  476. data/ext/couchbase/core/operations/management/eventing_undeploy_function.cxx +30 -28
  477. data/ext/couchbase/core/operations/management/eventing_undeploy_function.hxx +17 -14
  478. data/ext/couchbase/core/operations/management/eventing_upsert_function.cxx +328 -318
  479. data/ext/couchbase/core/operations/management/eventing_upsert_function.hxx +17 -14
  480. data/ext/couchbase/core/operations/management/freeform.cxx +23 -22
  481. data/ext/couchbase/core/operations/management/freeform.hxx +19 -17
  482. data/ext/couchbase/core/operations/management/group_drop.cxx +18 -17
  483. data/ext/couchbase/core/operations/management/group_drop.hxx +13 -11
  484. data/ext/couchbase/core/operations/management/group_get.cxx +25 -23
  485. data/ext/couchbase/core/operations/management/group_get.hxx +14 -12
  486. data/ext/couchbase/core/operations/management/group_get_all.cxx +23 -22
  487. data/ext/couchbase/core/operations/management/group_get_all.hxx +13 -11
  488. data/ext/couchbase/core/operations/management/group_upsert.cxx +58 -55
  489. data/ext/couchbase/core/operations/management/group_upsert.hxx +14 -12
  490. data/ext/couchbase/core/operations/management/query_index_build.cxx +53 -48
  491. data/ext/couchbase/core/operations/management/query_index_build.hxx +25 -22
  492. data/ext/couchbase/core/operations/management/query_index_build_deferred.hxx +75 -67
  493. data/ext/couchbase/core/operations/management/query_index_create.cxx +128 -122
  494. data/ext/couchbase/core/operations/management/query_index_create.hxx +31 -28
  495. data/ext/couchbase/core/operations/management/query_index_drop.cxx +95 -93
  496. data/ext/couchbase/core/operations/management/query_index_drop.hxx +26 -24
  497. data/ext/couchbase/core/operations/management/query_index_get_all.cxx +97 -93
  498. data/ext/couchbase/core/operations/management/query_index_get_all.hxx +24 -21
  499. data/ext/couchbase/core/operations/management/query_index_get_all_deferred.cxx +66 -62
  500. data/ext/couchbase/core/operations/management/query_index_get_all_deferred.hxx +24 -22
  501. data/ext/couchbase/core/operations/management/role_get_all.cxx +24 -22
  502. data/ext/couchbase/core/operations/management/role_get_all.hxx +13 -11
  503. data/ext/couchbase/core/operations/management/scope_create.cxx +38 -36
  504. data/ext/couchbase/core/operations/management/scope_create.hxx +15 -13
  505. data/ext/couchbase/core/operations/management/scope_drop.cxx +33 -32
  506. data/ext/couchbase/core/operations/management/scope_drop.hxx +15 -13
  507. data/ext/couchbase/core/operations/management/scope_get_all.cxx +27 -25
  508. data/ext/couchbase/core/operations/management/scope_get_all.hxx +14 -12
  509. data/ext/couchbase/core/operations/management/search_get_stats.cxx +12 -10
  510. data/ext/couchbase/core/operations/management/search_get_stats.hxx +13 -11
  511. data/ext/couchbase/core/operations/management/search_index_analyze_document.cxx +72 -67
  512. data/ext/couchbase/core/operations/management/search_index_analyze_document.hxx +20 -18
  513. data/ext/couchbase/core/operations/management/search_index_control_ingest.cxx +62 -59
  514. data/ext/couchbase/core/operations/management/search_index_control_ingest.hxx +19 -16
  515. data/ext/couchbase/core/operations/management/search_index_control_plan_freeze.cxx +62 -59
  516. data/ext/couchbase/core/operations/management/search_index_control_plan_freeze.hxx +19 -17
  517. data/ext/couchbase/core/operations/management/search_index_control_query.cxx +62 -59
  518. data/ext/couchbase/core/operations/management/search_index_control_query.hxx +19 -16
  519. data/ext/couchbase/core/operations/management/search_index_drop.cxx +58 -55
  520. data/ext/couchbase/core/operations/management/search_index_drop.hxx +18 -15
  521. data/ext/couchbase/core/operations/management/search_index_get.cxx +59 -56
  522. data/ext/couchbase/core/operations/management/search_index_get.hxx +18 -16
  523. data/ext/couchbase/core/operations/management/search_index_get_all.cxx +51 -46
  524. data/ext/couchbase/core/operations/management/search_index_get_all.hxx +18 -15
  525. data/ext/couchbase/core/operations/management/search_index_get_documents_count.cxx +66 -61
  526. data/ext/couchbase/core/operations/management/search_index_get_documents_count.hxx +19 -17
  527. data/ext/couchbase/core/operations/management/search_index_get_stats.cxx +38 -36
  528. data/ext/couchbase/core/operations/management/search_index_get_stats.hxx +17 -14
  529. data/ext/couchbase/core/operations/management/search_index_upsert.cxx +98 -95
  530. data/ext/couchbase/core/operations/management/search_index_upsert.hxx +20 -17
  531. data/ext/couchbase/core/operations/management/user_drop.cxx +18 -17
  532. data/ext/couchbase/core/operations/management/user_drop.hxx +16 -12
  533. data/ext/couchbase/core/operations/management/user_get.cxx +25 -23
  534. data/ext/couchbase/core/operations/management/user_get.hxx +17 -13
  535. data/ext/couchbase/core/operations/management/user_get_all.cxx +24 -22
  536. data/ext/couchbase/core/operations/management/user_get_all.hxx +16 -12
  537. data/ext/couchbase/core/operations/management/user_upsert.cxx +63 -60
  538. data/ext/couchbase/core/operations/management/user_upsert.hxx +17 -13
  539. data/ext/couchbase/core/operations/management/view_index_drop.cxx +16 -12
  540. data/ext/couchbase/core/operations/management/view_index_drop.hxx +15 -13
  541. data/ext/couchbase/core/operations/management/view_index_get.cxx +40 -35
  542. data/ext/couchbase/core/operations/management/view_index_get.hxx +16 -14
  543. data/ext/couchbase/core/operations/management/view_index_get_all.cxx +73 -69
  544. data/ext/couchbase/core/operations/management/view_index_get_all.hxx +16 -13
  545. data/ext/couchbase/core/operations/management/view_index_upsert.cxx +39 -35
  546. data/ext/couchbase/core/operations/management/view_index_upsert.hxx +15 -12
  547. data/ext/couchbase/core/origin.cxx +259 -249
  548. data/ext/couchbase/core/origin.hxx +55 -49
  549. data/ext/couchbase/core/pending_operation.hxx +3 -3
  550. data/ext/couchbase/core/ping_collector.hxx +3 -3
  551. data/ext/couchbase/core/ping_options.hxx +30 -30
  552. data/ext/couchbase/core/ping_reporter.hxx +3 -3
  553. data/ext/couchbase/core/platform/backtrace.c +100 -91
  554. data/ext/couchbase/core/platform/base64.cc +135 -134
  555. data/ext/couchbase/core/platform/dirutils.cc +66 -63
  556. data/ext/couchbase/core/platform/random.cc +43 -42
  557. data/ext/couchbase/core/platform/random.h +4 -4
  558. data/ext/couchbase/core/platform/string_hex.cc +42 -40
  559. data/ext/couchbase/core/platform/terminate_handler.cc +54 -52
  560. data/ext/couchbase/core/platform/uuid.cc +47 -47
  561. data/ext/couchbase/core/protocol/client_opcode.hxx +336 -327
  562. data/ext/couchbase/core/protocol/client_opcode_fmt.hxx +291 -291
  563. data/ext/couchbase/core/protocol/client_request.cxx +13 -10
  564. data/ext/couchbase/core/protocol/client_request.hxx +133 -130
  565. data/ext/couchbase/core/protocol/client_response.cxx +40 -40
  566. data/ext/couchbase/core/protocol/client_response.hxx +153 -150
  567. data/ext/couchbase/core/protocol/cmd_append.cxx +24 -23
  568. data/ext/couchbase/core/protocol/cmd_append.hxx +65 -65
  569. data/ext/couchbase/core/protocol/cmd_cluster_map_change_notification.cxx +25 -21
  570. data/ext/couchbase/core/protocol/cmd_cluster_map_change_notification.hxx +33 -25
  571. data/ext/couchbase/core/protocol/cmd_decrement.cxx +38 -38
  572. data/ext/couchbase/core/protocol/cmd_decrement.hxx +87 -87
  573. data/ext/couchbase/core/protocol/cmd_get.cxx +17 -17
  574. data/ext/couchbase/core/protocol/cmd_get.hxx +59 -59
  575. data/ext/couchbase/core/protocol/cmd_get_and_lock.cxx +20 -20
  576. data/ext/couchbase/core/protocol/cmd_get_and_lock.hxx +72 -72
  577. data/ext/couchbase/core/protocol/cmd_get_and_touch.cxx +20 -20
  578. data/ext/couchbase/core/protocol/cmd_get_and_touch.hxx +72 -72
  579. data/ext/couchbase/core/protocol/cmd_get_cluster_config.cxx +46 -39
  580. data/ext/couchbase/core/protocol/cmd_get_cluster_config.hxx +57 -49
  581. data/ext/couchbase/core/protocol/cmd_get_collection_id.cxx +17 -17
  582. data/ext/couchbase/core/protocol/cmd_get_collection_id.hxx +59 -59
  583. data/ext/couchbase/core/protocol/cmd_get_collections_manifest.cxx +16 -14
  584. data/ext/couchbase/core/protocol/cmd_get_collections_manifest.hxx +39 -39
  585. data/ext/couchbase/core/protocol/cmd_get_error_map.cxx +18 -17
  586. data/ext/couchbase/core/protocol/cmd_get_error_map.hxx +62 -62
  587. data/ext/couchbase/core/protocol/cmd_get_meta.cxx +24 -23
  588. data/ext/couchbase/core/protocol/cmd_get_meta.hxx +81 -79
  589. data/ext/couchbase/core/protocol/cmd_get_replica.cxx +23 -23
  590. data/ext/couchbase/core/protocol/cmd_get_replica.hxx +44 -44
  591. data/ext/couchbase/core/protocol/cmd_hello.cxx +28 -27
  592. data/ext/couchbase/core/protocol/cmd_hello.hxx +106 -105
  593. data/ext/couchbase/core/protocol/cmd_increment.cxx +38 -38
  594. data/ext/couchbase/core/protocol/cmd_increment.hxx +87 -87
  595. data/ext/couchbase/core/protocol/cmd_info.hxx +3 -3
  596. data/ext/couchbase/core/protocol/cmd_insert.cxx +27 -27
  597. data/ext/couchbase/core/protocol/cmd_insert.hxx +81 -81
  598. data/ext/couchbase/core/protocol/cmd_lookup_in.cxx +54 -51
  599. data/ext/couchbase/core/protocol/cmd_lookup_in.hxx +90 -90
  600. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.cxx +54 -51
  601. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.hxx +88 -88
  602. data/ext/couchbase/core/protocol/cmd_mutate_in.cxx +105 -97
  603. data/ext/couchbase/core/protocol/cmd_mutate_in.hxx +161 -153
  604. data/ext/couchbase/core/protocol/cmd_noop.cxx +4 -4
  605. data/ext/couchbase/core/protocol/cmd_noop.hxx +32 -32
  606. data/ext/couchbase/core/protocol/cmd_observe_seqno.cxx +36 -34
  607. data/ext/couchbase/core/protocol/cmd_observe_seqno.hxx +89 -89
  608. data/ext/couchbase/core/protocol/cmd_prepend.cxx +22 -22
  609. data/ext/couchbase/core/protocol/cmd_prepend.hxx +63 -63
  610. data/ext/couchbase/core/protocol/cmd_remove.cxx +23 -23
  611. data/ext/couchbase/core/protocol/cmd_remove.hxx +54 -54
  612. data/ext/couchbase/core/protocol/cmd_replace.cxx +28 -28
  613. data/ext/couchbase/core/protocol/cmd_replace.hxx +88 -88
  614. data/ext/couchbase/core/protocol/cmd_sasl_auth.cxx +17 -15
  615. data/ext/couchbase/core/protocol/cmd_sasl_auth.hxx +56 -56
  616. data/ext/couchbase/core/protocol/cmd_sasl_list_mechs.cxx +24 -19
  617. data/ext/couchbase/core/protocol/cmd_sasl_list_mechs.hxx +39 -39
  618. data/ext/couchbase/core/protocol/cmd_sasl_step.cxx +17 -15
  619. data/ext/couchbase/core/protocol/cmd_sasl_step.hxx +56 -56
  620. data/ext/couchbase/core/protocol/cmd_select_bucket.cxx +6 -6
  621. data/ext/couchbase/core/protocol/cmd_select_bucket.hxx +36 -36
  622. data/ext/couchbase/core/protocol/cmd_touch.cxx +8 -8
  623. data/ext/couchbase/core/protocol/cmd_touch.hxx +38 -38
  624. data/ext/couchbase/core/protocol/cmd_unlock.cxx +5 -5
  625. data/ext/couchbase/core/protocol/cmd_unlock.hxx +36 -36
  626. data/ext/couchbase/core/protocol/cmd_upsert.cxx +28 -28
  627. data/ext/couchbase/core/protocol/cmd_upsert.hxx +83 -83
  628. data/ext/couchbase/core/protocol/datatype.hxx +19 -18
  629. data/ext/couchbase/core/protocol/frame_info_id.hxx +108 -103
  630. data/ext/couchbase/core/protocol/frame_info_id_fmt.hxx +45 -45
  631. data/ext/couchbase/core/protocol/frame_info_utils.cxx +24 -21
  632. data/ext/couchbase/core/protocol/frame_info_utils.hxx +3 -1
  633. data/ext/couchbase/core/protocol/hello_feature.hxx +211 -175
  634. data/ext/couchbase/core/protocol/hello_feature_fmt.hxx +93 -90
  635. data/ext/couchbase/core/protocol/magic.hxx +24 -24
  636. data/ext/couchbase/core/protocol/magic_fmt.hxx +30 -30
  637. data/ext/couchbase/core/protocol/server_opcode.hxx +11 -11
  638. data/ext/couchbase/core/protocol/server_opcode_fmt.hxx +18 -18
  639. data/ext/couchbase/core/protocol/server_request.hxx +90 -86
  640. data/ext/couchbase/core/protocol/status.cxx +138 -138
  641. data/ext/couchbase/core/protocol/status.hxx +86 -86
  642. data/ext/couchbase/core/query_context.hxx +44 -43
  643. data/ext/couchbase/core/range_scan_load_balancer.cxx +51 -50
  644. data/ext/couchbase/core/range_scan_load_balancer.hxx +26 -25
  645. data/ext/couchbase/core/range_scan_options.cxx +2 -2
  646. data/ext/couchbase/core/range_scan_options.hxx +62 -59
  647. data/ext/couchbase/core/range_scan_orchestrator.cxx +515 -470
  648. data/ext/couchbase/core/range_scan_orchestrator.hxx +23 -18
  649. data/ext/couchbase/core/range_scan_orchestrator_options.hxx +10 -10
  650. data/ext/couchbase/core/resource_units.hxx +2 -2
  651. data/ext/couchbase/core/response_handler.hxx +8 -8
  652. data/ext/couchbase/core/retry_orchestrator.cxx +27 -19
  653. data/ext/couchbase/core/retry_orchestrator.hxx +3 -2
  654. data/ext/couchbase/core/sasl/client.cc +22 -18
  655. data/ext/couchbase/core/sasl/client.h +66 -62
  656. data/ext/couchbase/core/sasl/context.cc +4 -4
  657. data/ext/couchbase/core/sasl/context.h +19 -19
  658. data/ext/couchbase/core/sasl/error.h +12 -1
  659. data/ext/couchbase/core/sasl/error_fmt.h +42 -42
  660. data/ext/couchbase/core/sasl/mechanism.cc +13 -10
  661. data/ext/couchbase/core/sasl/mechanism.h +8 -3
  662. data/ext/couchbase/core/sasl/plain/plain.cc +8 -8
  663. data/ext/couchbase/core/sasl/plain/plain.h +25 -24
  664. data/ext/couchbase/core/sasl/scram-sha/scram-sha.cc +225 -218
  665. data/ext/couchbase/core/sasl/scram-sha/scram-sha.h +133 -115
  666. data/ext/couchbase/core/sasl/scram-sha/stringutils.cc +20 -20
  667. data/ext/couchbase/core/scan_result.cxx +38 -38
  668. data/ext/couchbase/core/scan_result.hxx +16 -16
  669. data/ext/couchbase/core/search_highlight_style.hxx +4 -1
  670. data/ext/couchbase/core/search_query_options.cxx +21 -21
  671. data/ext/couchbase/core/search_query_options.hxx +19 -18
  672. data/ext/couchbase/core/search_scan_consistency.hxx +3 -1
  673. data/ext/couchbase/core/seed_config.cxx +10 -7
  674. data/ext/couchbase/core/seed_config.hxx +8 -8
  675. data/ext/couchbase/core/service_type.hxx +7 -7
  676. data/ext/couchbase/core/service_type_fmt.hxx +33 -33
  677. data/ext/couchbase/core/stats_options.hxx +13 -13
  678. data/ext/couchbase/core/subdoc_options.hxx +60 -58
  679. data/ext/couchbase/core/tls_verify_mode.hxx +2 -2
  680. data/ext/couchbase/core/topology/capabilities.hxx +83 -83
  681. data/ext/couchbase/core/topology/capabilities_fmt.hxx +111 -111
  682. data/ext/couchbase/core/topology/collections_manifest.hxx +14 -14
  683. data/ext/couchbase/core/topology/collections_manifest_fmt.hxx +23 -21
  684. data/ext/couchbase/core/topology/collections_manifest_json.hxx +26 -25
  685. data/ext/couchbase/core/topology/configuration.cxx +213 -192
  686. data/ext/couchbase/core/topology/configuration.hxx +104 -91
  687. data/ext/couchbase/core/topology/configuration_fmt.hxx +131 -128
  688. data/ext/couchbase/core/topology/configuration_json.hxx +276 -242
  689. data/ext/couchbase/core/topology/error_map.hxx +5 -5
  690. data/ext/couchbase/core/topology/error_map_json.hxx +65 -60
  691. data/ext/couchbase/core/tracing/constants.hxx +153 -153
  692. data/ext/couchbase/core/tracing/noop_tracer.hxx +29 -28
  693. data/ext/couchbase/core/tracing/threshold_logging_options.hxx +30 -30
  694. data/ext/couchbase/core/tracing/threshold_logging_tracer.cxx +354 -344
  695. data/ext/couchbase/core/tracing/threshold_logging_tracer.hxx +12 -12
  696. data/ext/couchbase/core/transactions/active_transaction_record.cxx +153 -33
  697. data/ext/couchbase/core/transactions/active_transaction_record.hxx +30 -118
  698. data/ext/couchbase/core/transactions/async_attempt_context.cxx +8 -2
  699. data/ext/couchbase/core/transactions/async_attempt_context.hxx +163 -127
  700. data/ext/couchbase/core/transactions/atr_cleanup_entry.cxx +358 -334
  701. data/ext/couchbase/core/transactions/atr_ids.cxx +270 -185
  702. data/ext/couchbase/core/transactions/atr_ids.hxx +4 -4
  703. data/ext/couchbase/core/transactions/attempt_context.cxx +9 -5
  704. data/ext/couchbase/core/transactions/attempt_context.hxx +194 -154
  705. data/ext/couchbase/core/transactions/attempt_context_impl.cxx +3278 -2159
  706. data/ext/couchbase/core/transactions/attempt_context_impl.hxx +446 -573
  707. data/ext/couchbase/core/transactions/attempt_context_testing_hooks.cxx +15 -10
  708. data/ext/couchbase/core/transactions/attempt_context_testing_hooks.hxx +58 -49
  709. data/ext/couchbase/core/transactions/attempt_state.hxx +72 -72
  710. data/ext/couchbase/core/transactions/binary.cxx +3 -3
  711. data/ext/couchbase/core/transactions/cleanup_testing_hooks.cxx +2 -2
  712. data/ext/couchbase/core/transactions/cleanup_testing_hooks.hxx +28 -24
  713. data/ext/couchbase/core/transactions/document_metadata.hxx +68 -68
  714. data/ext/couchbase/core/transactions/durability_level.hxx +53 -53
  715. data/ext/couchbase/core/transactions/error_class.hxx +12 -12
  716. data/ext/couchbase/core/transactions/error_list.hxx +22 -22
  717. data/ext/couchbase/core/transactions/exceptions.cxx +167 -114
  718. data/ext/couchbase/core/transactions/exceptions.hxx +170 -139
  719. data/ext/couchbase/core/transactions/exceptions_fmt.hxx +105 -0
  720. data/ext/couchbase/core/transactions/forward_compat.cxx +220 -0
  721. data/ext/couchbase/core/transactions/forward_compat.hxx +63 -207
  722. data/ext/couchbase/core/transactions/internal/atr_cleanup_entry.hxx +110 -102
  723. data/ext/couchbase/core/transactions/internal/atr_entry.hxx +144 -144
  724. data/ext/couchbase/core/transactions/internal/client_record.hxx +53 -50
  725. data/ext/couchbase/core/transactions/internal/doc_record.cxx +5 -5
  726. data/ext/couchbase/core/transactions/internal/doc_record.hxx +38 -35
  727. data/ext/couchbase/core/transactions/internal/doc_record_fmt.hxx +17 -16
  728. data/ext/couchbase/core/transactions/internal/exceptions_internal.hxx +238 -281
  729. data/ext/couchbase/core/transactions/internal/exceptions_internal_fmt.hxx +103 -0
  730. data/ext/couchbase/core/transactions/internal/logging.hxx +52 -29
  731. data/ext/couchbase/core/transactions/internal/transaction_attempt.hxx +3 -3
  732. data/ext/couchbase/core/transactions/internal/transaction_context.hxx +136 -120
  733. data/ext/couchbase/core/transactions/internal/transaction_fields.hxx +2 -1
  734. data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +127 -122
  735. data/ext/couchbase/core/transactions/internal/utils.hxx +244 -219
  736. data/ext/couchbase/core/transactions/result.cxx +41 -40
  737. data/ext/couchbase/core/transactions/result.hxx +143 -141
  738. data/ext/couchbase/core/transactions/result_fmt.hxx +21 -20
  739. data/ext/couchbase/core/transactions/staged_mutation.cxx +759 -627
  740. data/ext/couchbase/core/transactions/staged_mutation.hxx +175 -156
  741. data/ext/couchbase/core/transactions/transaction_context.cxx +231 -179
  742. data/ext/couchbase/core/transactions/transaction_get_result.cxx +185 -198
  743. data/ext/couchbase/core/transactions/transaction_get_result.hxx +207 -222
  744. data/ext/couchbase/core/transactions/transaction_keyspace.cxx +15 -11
  745. data/ext/couchbase/core/transactions/transaction_links.cxx +11 -7
  746. data/ext/couchbase/core/transactions/transaction_links.hxx +222 -201
  747. data/ext/couchbase/core/transactions/transaction_options.cxx +44 -41
  748. data/ext/couchbase/core/transactions/transactions.cxx +167 -125
  749. data/ext/couchbase/core/transactions/transactions_cleanup.cxx +491 -424
  750. data/ext/couchbase/core/transactions/transactions_config.cxx +25 -19
  751. data/ext/couchbase/core/transactions/uid_generator.cxx +3 -3
  752. data/ext/couchbase/core/transactions/uid_generator.hxx +2 -2
  753. data/ext/couchbase/core/transactions/utils.cxx +82 -69
  754. data/ext/couchbase/core/transactions/waitable_op_list.hxx +154 -140
  755. data/ext/couchbase/core/transactions.hxx +184 -180
  756. data/ext/couchbase/core/utils/binary.cxx +3 -3
  757. data/ext/couchbase/core/utils/binary.hxx +19 -15
  758. data/ext/couchbase/core/utils/byteswap.hxx +17 -17
  759. data/ext/couchbase/core/utils/connection_string.cxx +395 -328
  760. data/ext/couchbase/core/utils/connection_string.hxx +37 -36
  761. data/ext/couchbase/core/utils/crc32.hxx +42 -34
  762. data/ext/couchbase/core/utils/duration_parser.cxx +142 -133
  763. data/ext/couchbase/core/utils/duration_parser.hxx +9 -9
  764. data/ext/couchbase/core/utils/join_strings.hxx +24 -24
  765. data/ext/couchbase/core/utils/json.cxx +234 -228
  766. data/ext/couchbase/core/utils/json.hxx +12 -12
  767. data/ext/couchbase/core/utils/json_stream_control.hxx +8 -8
  768. data/ext/couchbase/core/utils/json_streaming_lexer.cxx +288 -263
  769. data/ext/couchbase/core/utils/json_streaming_lexer.hxx +20 -17
  770. data/ext/couchbase/core/utils/keyspace.hxx +22 -21
  771. data/ext/couchbase/core/utils/movable_function.hxx +78 -76
  772. data/ext/couchbase/core/utils/mutation_token.cxx +7 -3
  773. data/ext/couchbase/core/utils/mutation_token.hxx +3 -1
  774. data/ext/couchbase/core/utils/name_codec.hxx +13 -13
  775. data/ext/couchbase/core/utils/split_string.cxx +9 -9
  776. data/ext/couchbase/core/utils/split_string.hxx +2 -2
  777. data/ext/couchbase/core/utils/unsigned_leb128.hxx +92 -88
  778. data/ext/couchbase/core/utils/url_codec.cxx +301 -297
  779. data/ext/couchbase/core/utils/url_codec.hxx +35 -35
  780. data/ext/couchbase/core/vector_query_combination.hxx +4 -1
  781. data/ext/couchbase/core/view_on_error.hxx +4 -3
  782. data/ext/couchbase/core/view_query_options.cxx +21 -21
  783. data/ext/couchbase/core/view_query_options.hxx +23 -22
  784. data/ext/couchbase/core/view_scan_consistency.hxx +3 -3
  785. data/ext/couchbase/core/view_sort_order.hxx +4 -1
  786. data/ext/couchbase/core/wait_until_ready_options.hxx +11 -10
  787. data/ext/couchbase/couchbase/allow_querying_search_index_options.hxx +11 -11
  788. data/ext/couchbase/couchbase/analytics_index_manager.hxx +423 -405
  789. data/ext/couchbase/couchbase/analytics_meta_data.hxx +105 -105
  790. data/ext/couchbase/couchbase/analytics_metrics.hxx +120 -118
  791. data/ext/couchbase/couchbase/analytics_options.hxx +318 -292
  792. data/ext/couchbase/couchbase/analytics_result.hxx +56 -55
  793. data/ext/couchbase/couchbase/analytics_scan_consistency.hxx +24 -21
  794. data/ext/couchbase/couchbase/analytics_status.hxx +10 -10
  795. data/ext/couchbase/couchbase/analytics_warning.hxx +44 -43
  796. data/ext/couchbase/couchbase/analyze_document_options.hxx +9 -9
  797. data/ext/couchbase/couchbase/append_options.hxx +51 -47
  798. data/ext/couchbase/couchbase/behavior_options.hxx +75 -69
  799. data/ext/couchbase/couchbase/best_effort_retry_strategy.hxx +12 -10
  800. data/ext/couchbase/couchbase/binary_collection.hxx +213 -183
  801. data/ext/couchbase/couchbase/boolean_field_query.hxx +38 -38
  802. data/ext/couchbase/couchbase/boolean_query.hxx +166 -157
  803. data/ext/couchbase/couchbase/bucket.hxx +69 -68
  804. data/ext/couchbase/couchbase/bucket_manager.hxx +97 -88
  805. data/ext/couchbase/couchbase/build_query_index_options.hxx +22 -21
  806. data/ext/couchbase/couchbase/cas.hxx +74 -73
  807. data/ext/couchbase/couchbase/certificate_authenticator.hxx +10 -10
  808. data/ext/couchbase/couchbase/cluster.hxx +266 -310
  809. data/ext/couchbase/couchbase/cluster_options.hxx +235 -241
  810. data/ext/couchbase/couchbase/codec/binary_noop_serializer.hxx +11 -11
  811. data/ext/couchbase/couchbase/codec/codec_flags.hxx +39 -35
  812. data/ext/couchbase/couchbase/codec/encoded_value.hxx +15 -2
  813. data/ext/couchbase/couchbase/codec/json_transcoder.hxx +17 -15
  814. data/ext/couchbase/couchbase/codec/raw_binary_transcoder.hxx +19 -17
  815. data/ext/couchbase/couchbase/codec/raw_json_transcoder.hxx +31 -24
  816. data/ext/couchbase/couchbase/codec/raw_string_transcoder.hxx +20 -18
  817. data/ext/couchbase/couchbase/codec/tao_json_serializer.hxx +38 -30
  818. data/ext/couchbase/couchbase/collection.hxx +1007 -902
  819. data/ext/couchbase/couchbase/collection_manager.hxx +115 -107
  820. data/ext/couchbase/couchbase/collection_query_index_manager.hxx +200 -188
  821. data/ext/couchbase/couchbase/common_durability_options.hxx +68 -62
  822. data/ext/couchbase/couchbase/common_options.hxx +67 -67
  823. data/ext/couchbase/couchbase/compression_options.hxx +33 -33
  824. data/ext/couchbase/couchbase/configuration_profile.hxx +12 -11
  825. data/ext/couchbase/couchbase/configuration_profiles_registry.hxx +24 -22
  826. data/ext/couchbase/couchbase/conjunction_query.hxx +47 -45
  827. data/ext/couchbase/couchbase/connect_link_analytics_options.hxx +74 -72
  828. data/ext/couchbase/couchbase/counter_result.hxx +32 -32
  829. data/ext/couchbase/couchbase/create_bucket_options.hxx +9 -10
  830. data/ext/couchbase/couchbase/create_collection_options.hxx +35 -34
  831. data/ext/couchbase/couchbase/create_dataset_analytics_options.hxx +76 -76
  832. data/ext/couchbase/couchbase/create_dataverse_analytics_options.hxx +44 -44
  833. data/ext/couchbase/couchbase/create_index_analytics_options.hxx +60 -60
  834. data/ext/couchbase/couchbase/create_link_analytics_options.hxx +25 -25
  835. data/ext/couchbase/couchbase/create_primary_query_index_options.hxx +95 -94
  836. data/ext/couchbase/couchbase/create_query_index_options.hxx +97 -96
  837. data/ext/couchbase/couchbase/create_scope_options.hxx +9 -9
  838. data/ext/couchbase/couchbase/date_range.hxx +29 -27
  839. data/ext/couchbase/couchbase/date_range_facet.hxx +20 -20
  840. data/ext/couchbase/couchbase/date_range_facet_result.hxx +14 -14
  841. data/ext/couchbase/couchbase/date_range_query.hxx +219 -205
  842. data/ext/couchbase/couchbase/decrement_options.hxx +93 -91
  843. data/ext/couchbase/couchbase/diagnostics_options.hxx +42 -41
  844. data/ext/couchbase/couchbase/diagnostics_result.hxx +82 -83
  845. data/ext/couchbase/couchbase/disallow_querying_search_index_options.hxx +11 -10
  846. data/ext/couchbase/couchbase/disconnect_link_analytics_options.hxx +62 -62
  847. data/ext/couchbase/couchbase/disjunction_query.hxx +61 -60
  848. data/ext/couchbase/couchbase/dns_options.hxx +30 -30
  849. data/ext/couchbase/couchbase/doc_id_query.hxx +69 -69
  850. data/ext/couchbase/couchbase/drop_bucket_options.hxx +9 -9
  851. data/ext/couchbase/couchbase/drop_collection_options.hxx +9 -9
  852. data/ext/couchbase/couchbase/drop_dataset_analytics_options.hxx +60 -60
  853. data/ext/couchbase/couchbase/drop_dataverse_analytics_options.hxx +44 -44
  854. data/ext/couchbase/couchbase/drop_index_analytics_options.hxx +60 -60
  855. data/ext/couchbase/couchbase/drop_link_analytics_options.hxx +25 -25
  856. data/ext/couchbase/couchbase/drop_primary_query_index_options.hxx +58 -58
  857. data/ext/couchbase/couchbase/drop_query_index_options.hxx +44 -44
  858. data/ext/couchbase/couchbase/drop_scope_options.hxx +9 -9
  859. data/ext/couchbase/couchbase/drop_search_index_options.hxx +9 -9
  860. data/ext/couchbase/couchbase/durability_level.hxx +32 -29
  861. data/ext/couchbase/couchbase/endpoint_diagnostics.hxx +171 -171
  862. data/ext/couchbase/couchbase/endpoint_ping_report.hxx +166 -169
  863. data/ext/couchbase/couchbase/error.hxx +51 -0
  864. data/ext/couchbase/couchbase/error_codes.hxx +975 -940
  865. data/ext/couchbase/couchbase/error_context.hxx +19 -152
  866. data/ext/couchbase/couchbase/exists_options.hxx +25 -24
  867. data/ext/couchbase/couchbase/exists_result.hxx +32 -32
  868. data/ext/couchbase/couchbase/fail_fast_retry_strategy.hxx +4 -4
  869. data/ext/couchbase/couchbase/flush_bucket_options.hxx +9 -9
  870. data/ext/couchbase/couchbase/fmt/analytics_scan_consistency.hxx +18 -18
  871. data/ext/couchbase/couchbase/fmt/analytics_status.hxx +42 -42
  872. data/ext/couchbase/couchbase/fmt/cas.hxx +10 -10
  873. data/ext/couchbase/couchbase/fmt/durability_level.hxx +24 -24
  874. data/ext/couchbase/couchbase/fmt/error.hxx +53 -0
  875. data/ext/couchbase/couchbase/fmt/error_context.hxx +43 -0
  876. data/ext/couchbase/couchbase/fmt/mutation_token.hxx +15 -11
  877. data/ext/couchbase/couchbase/fmt/query_profile.hxx +21 -21
  878. data/ext/couchbase/couchbase/fmt/query_scan_consistency.hxx +18 -18
  879. data/ext/couchbase/couchbase/fmt/query_status.hxx +42 -42
  880. data/ext/couchbase/couchbase/fmt/retry_reason.hxx +75 -75
  881. data/ext/couchbase/couchbase/fmt/search_scan_consistency.hxx +15 -15
  882. data/ext/couchbase/couchbase/fmt/tls_verify_mode.hxx +18 -18
  883. data/ext/couchbase/couchbase/fmt/transaction_keyspace.hxx +15 -11
  884. data/ext/couchbase/couchbase/fork_event.hxx +12 -12
  885. data/ext/couchbase/couchbase/freeze_plan_search_index_options.hxx +9 -9
  886. data/ext/couchbase/couchbase/geo_bounding_box_query.hxx +71 -64
  887. data/ext/couchbase/couchbase/geo_distance_query.hxx +73 -66
  888. data/ext/couchbase/couchbase/geo_point.hxx +2 -2
  889. data/ext/couchbase/couchbase/geo_polygon_query.hxx +40 -39
  890. data/ext/couchbase/couchbase/get_all_buckets_options.hxx +9 -9
  891. data/ext/couchbase/couchbase/get_all_datasets_analytics_options.hxx +25 -25
  892. data/ext/couchbase/couchbase/get_all_indexes_analytics_options.hxx +26 -25
  893. data/ext/couchbase/couchbase/get_all_query_indexes_options.hxx +27 -25
  894. data/ext/couchbase/couchbase/get_all_replicas_options.hxx +49 -26
  895. data/ext/couchbase/couchbase/get_all_scopes_options.hxx +9 -9
  896. data/ext/couchbase/couchbase/get_all_search_indexes_options.hxx +9 -9
  897. data/ext/couchbase/couchbase/get_and_lock_options.hxx +25 -24
  898. data/ext/couchbase/couchbase/get_and_touch_options.hxx +25 -24
  899. data/ext/couchbase/couchbase/get_any_replica_options.hxx +49 -26
  900. data/ext/couchbase/couchbase/get_bucket_options.hxx +9 -9
  901. data/ext/couchbase/couchbase/get_indexed_search_index_options.hxx +9 -9
  902. data/ext/couchbase/couchbase/get_links_analytics_options.hxx +74 -74
  903. data/ext/couchbase/couchbase/get_options.hxx +63 -60
  904. data/ext/couchbase/couchbase/get_pending_mutations_analytics_options.hxx +30 -28
  905. data/ext/couchbase/couchbase/get_replica_result.hxx +79 -75
  906. data/ext/couchbase/couchbase/get_result.hxx +86 -80
  907. data/ext/couchbase/couchbase/get_search_index_options.hxx +9 -9
  908. data/ext/couchbase/couchbase/highlight_style.hxx +14 -14
  909. data/ext/couchbase/couchbase/increment_options.hxx +94 -91
  910. data/ext/couchbase/couchbase/insert_options.hxx +62 -59
  911. data/ext/couchbase/couchbase/ip_protocol.hxx +3 -3
  912. data/ext/couchbase/couchbase/logger.hxx +51 -0
  913. data/ext/couchbase/couchbase/lookup_in_all_replicas_options.hxx +54 -43
  914. data/ext/couchbase/couchbase/lookup_in_any_replica_options.hxx +54 -44
  915. data/ext/couchbase/couchbase/lookup_in_options.hxx +40 -40
  916. data/ext/couchbase/couchbase/lookup_in_replica_result.hxx +38 -35
  917. data/ext/couchbase/couchbase/lookup_in_result.hxx +222 -216
  918. data/ext/couchbase/couchbase/lookup_in_specs.hxx +101 -101
  919. data/ext/couchbase/couchbase/management/analytics_dataset.hxx +16 -16
  920. data/ext/couchbase/couchbase/management/analytics_index.hxx +16 -16
  921. data/ext/couchbase/couchbase/management/analytics_link.hxx +193 -189
  922. data/ext/couchbase/couchbase/management/bucket_settings.hxx +91 -75
  923. data/ext/couchbase/couchbase/management/collection_spec.hxx +4 -4
  924. data/ext/couchbase/couchbase/management/query_index.hxx +10 -10
  925. data/ext/couchbase/couchbase/management/scope_spec.hxx +2 -2
  926. data/ext/couchbase/couchbase/management/search_index.hxx +9 -9
  927. data/ext/couchbase/couchbase/match_all_query.hxx +10 -9
  928. data/ext/couchbase/couchbase/match_none_query.hxx +10 -9
  929. data/ext/couchbase/couchbase/match_operator.hxx +15 -14
  930. data/ext/couchbase/couchbase/match_phrase_query.hxx +70 -65
  931. data/ext/couchbase/couchbase/match_query.hxx +115 -114
  932. data/ext/couchbase/couchbase/metrics/meter.hxx +33 -30
  933. data/ext/couchbase/couchbase/metrics/otel_meter.hxx +86 -74
  934. data/ext/couchbase/couchbase/metrics_options.hxx +34 -34
  935. data/ext/couchbase/couchbase/mutate_in_options.hxx +160 -149
  936. data/ext/couchbase/couchbase/mutate_in_result.hxx +130 -123
  937. data/ext/couchbase/couchbase/mutate_in_specs.hxx +473 -454
  938. data/ext/couchbase/couchbase/mutation_result.hxx +32 -32
  939. data/ext/couchbase/couchbase/mutation_state.hxx +35 -34
  940. data/ext/couchbase/couchbase/mutation_token.hxx +78 -78
  941. data/ext/couchbase/couchbase/network_options.hxx +101 -72
  942. data/ext/couchbase/couchbase/numeric_range.hxx +26 -26
  943. data/ext/couchbase/couchbase/numeric_range_facet.hxx +20 -20
  944. data/ext/couchbase/couchbase/numeric_range_facet_result.hxx +14 -14
  945. data/ext/couchbase/couchbase/numeric_range_query.hxx +97 -95
  946. data/ext/couchbase/couchbase/password_authenticator.hxx +17 -17
  947. data/ext/couchbase/couchbase/pause_ingest_search_index_options.hxx +11 -10
  948. data/ext/couchbase/couchbase/persist_to.hxx +45 -44
  949. data/ext/couchbase/couchbase/phrase_query.hxx +69 -65
  950. data/ext/couchbase/couchbase/ping_options.hxx +55 -54
  951. data/ext/couchbase/couchbase/ping_result.hxx +79 -77
  952. data/ext/couchbase/couchbase/prefix_query.hxx +43 -40
  953. data/ext/couchbase/couchbase/prepend_options.hxx +51 -47
  954. data/ext/couchbase/couchbase/query_index_manager.hxx +207 -199
  955. data/ext/couchbase/couchbase/query_meta_data.hxx +120 -120
  956. data/ext/couchbase/couchbase/query_metrics.hxx +135 -133
  957. data/ext/couchbase/couchbase/query_options.hxx +518 -493
  958. data/ext/couchbase/couchbase/query_profile.hxx +29 -26
  959. data/ext/couchbase/couchbase/query_result.hxx +56 -55
  960. data/ext/couchbase/couchbase/query_scan_consistency.hxx +24 -21
  961. data/ext/couchbase/couchbase/query_status.hxx +10 -10
  962. data/ext/couchbase/couchbase/query_string_query.hxx +34 -29
  963. data/ext/couchbase/couchbase/query_warning.hxx +75 -71
  964. data/ext/couchbase/couchbase/read_preference.hxx +58 -0
  965. data/ext/couchbase/couchbase/regexp_query.hxx +40 -39
  966. data/ext/couchbase/couchbase/remove_options.hxx +51 -47
  967. data/ext/couchbase/couchbase/replace_link_analytics_options.hxx +25 -25
  968. data/ext/couchbase/couchbase/replace_options.hxx +112 -104
  969. data/ext/couchbase/couchbase/replicate_to.hxx +28 -28
  970. data/ext/couchbase/couchbase/result.hxx +28 -28
  971. data/ext/couchbase/couchbase/resume_ingest_search_index_options.hxx +11 -10
  972. data/ext/couchbase/couchbase/retry_action.hxx +10 -10
  973. data/ext/couchbase/couchbase/retry_reason.hxx +53 -51
  974. data/ext/couchbase/couchbase/retry_request.hxx +7 -7
  975. data/ext/couchbase/couchbase/retry_strategy.hxx +4 -4
  976. data/ext/couchbase/couchbase/scan_options.hxx +114 -108
  977. data/ext/couchbase/couchbase/scan_result.hxx +97 -96
  978. data/ext/couchbase/couchbase/scan_result_item.hxx +120 -118
  979. data/ext/couchbase/couchbase/scan_type.hxx +237 -232
  980. data/ext/couchbase/couchbase/scope.hxx +164 -157
  981. data/ext/couchbase/couchbase/scope_search_index_manager.hxx +263 -238
  982. data/ext/couchbase/couchbase/search_date_range.hxx +32 -29
  983. data/ext/couchbase/couchbase/search_facet.hxx +25 -25
  984. data/ext/couchbase/couchbase/search_facet_result.hxx +11 -11
  985. data/ext/couchbase/couchbase/search_geo_distance_units.hxx +11 -1
  986. data/ext/couchbase/couchbase/search_index_manager.hxx +261 -238
  987. data/ext/couchbase/couchbase/search_meta_data.hxx +37 -37
  988. data/ext/couchbase/couchbase/search_metrics.hxx +84 -83
  989. data/ext/couchbase/couchbase/search_numeric_range.hxx +32 -32
  990. data/ext/couchbase/couchbase/search_options.hxx +449 -435
  991. data/ext/couchbase/couchbase/search_query.hxx +32 -30
  992. data/ext/couchbase/couchbase/search_request.hxx +69 -68
  993. data/ext/couchbase/couchbase/search_result.hxx +29 -26
  994. data/ext/couchbase/couchbase/search_row.hxx +52 -52
  995. data/ext/couchbase/couchbase/search_row_location.hxx +20 -20
  996. data/ext/couchbase/couchbase/search_row_locations.hxx +39 -38
  997. data/ext/couchbase/couchbase/search_scan_consistency.hxx +11 -10
  998. data/ext/couchbase/couchbase/search_sort.hxx +20 -20
  999. data/ext/couchbase/couchbase/search_sort_field.hxx +77 -71
  1000. data/ext/couchbase/couchbase/search_sort_field_missing.hxx +2 -2
  1001. data/ext/couchbase/couchbase/search_sort_field_mode.hxx +3 -3
  1002. data/ext/couchbase/couchbase/search_sort_field_type.hxx +4 -4
  1003. data/ext/couchbase/couchbase/search_sort_geo_distance.hxx +41 -41
  1004. data/ext/couchbase/couchbase/search_sort_id.hxx +23 -23
  1005. data/ext/couchbase/couchbase/search_sort_score.hxx +23 -23
  1006. data/ext/couchbase/couchbase/search_term_range.hxx +17 -17
  1007. data/ext/couchbase/couchbase/security_options.hxx +50 -50
  1008. data/ext/couchbase/couchbase/service_type.hxx +34 -34
  1009. data/ext/couchbase/couchbase/store_semantics.hxx +28 -28
  1010. data/ext/couchbase/couchbase/subdoc/array_add_unique.hxx +54 -54
  1011. data/ext/couchbase/couchbase/subdoc/array_append.hxx +40 -40
  1012. data/ext/couchbase/couchbase/subdoc/array_insert.hxx +41 -41
  1013. data/ext/couchbase/couchbase/subdoc/array_prepend.hxx +41 -41
  1014. data/ext/couchbase/couchbase/subdoc/count.hxx +24 -24
  1015. data/ext/couchbase/couchbase/subdoc/counter.hxx +41 -41
  1016. data/ext/couchbase/couchbase/subdoc/exists.hxx +24 -24
  1017. data/ext/couchbase/couchbase/subdoc/get.hxx +45 -29
  1018. data/ext/couchbase/couchbase/subdoc/insert.hxx +70 -54
  1019. data/ext/couchbase/couchbase/subdoc/lookup_in_macro.hxx +13 -12
  1020. data/ext/couchbase/couchbase/subdoc/mutate_in_macro.hxx +7 -2
  1021. data/ext/couchbase/couchbase/subdoc/remove.hxx +24 -24
  1022. data/ext/couchbase/couchbase/subdoc/replace.hxx +55 -39
  1023. data/ext/couchbase/couchbase/subdoc/upsert.hxx +70 -54
  1024. data/ext/couchbase/couchbase/term_facet.hxx +16 -16
  1025. data/ext/couchbase/couchbase/term_facet_result.hxx +14 -14
  1026. data/ext/couchbase/couchbase/term_query.hxx +107 -104
  1027. data/ext/couchbase/couchbase/term_range_query.hxx +99 -96
  1028. data/ext/couchbase/couchbase/timeout_options.hxx +118 -112
  1029. data/ext/couchbase/couchbase/tls_verify_mode.hxx +2 -2
  1030. data/ext/couchbase/couchbase/touch_options.hxx +25 -24
  1031. data/ext/couchbase/couchbase/tracing/otel_tracer.hxx +45 -44
  1032. data/ext/couchbase/couchbase/tracing/request_span.hxx +34 -34
  1033. data/ext/couchbase/couchbase/tracing/request_tracer.hxx +27 -25
  1034. data/ext/couchbase/couchbase/tracing_options.hxx +147 -142
  1035. data/ext/couchbase/couchbase/transactions/async_attempt_context.hxx +149 -115
  1036. data/ext/couchbase/couchbase/transactions/attempt_context.hxx +146 -95
  1037. data/ext/couchbase/couchbase/transactions/transaction_get_result.hxx +52 -80
  1038. data/ext/couchbase/couchbase/transactions/transaction_keyspace.hxx +33 -29
  1039. data/ext/couchbase/couchbase/transactions/transaction_options.hxx +101 -96
  1040. data/ext/couchbase/couchbase/transactions/transaction_query_options.hxx +228 -223
  1041. data/ext/couchbase/couchbase/transactions/transaction_query_result.hxx +11 -12
  1042. data/ext/couchbase/couchbase/transactions/transaction_result.hxx +2 -3
  1043. data/ext/couchbase/couchbase/transactions/transactions_cleanup_config.hxx +105 -104
  1044. data/ext/couchbase/couchbase/transactions/transactions_config.hxx +191 -187
  1045. data/ext/couchbase/couchbase/transactions/transactions_query_config.hxx +32 -32
  1046. data/ext/couchbase/couchbase/transactions.hxx +56 -37
  1047. data/ext/couchbase/couchbase/unfreeze_plan_search_index_options.hxx +11 -10
  1048. data/ext/couchbase/couchbase/unlock_options.hxx +25 -24
  1049. data/ext/couchbase/couchbase/update_bucket_options.hxx +9 -9
  1050. data/ext/couchbase/couchbase/update_collection_options.hxx +35 -34
  1051. data/ext/couchbase/couchbase/upsert_options.hxx +85 -80
  1052. data/ext/couchbase/couchbase/upsert_search_index_options.hxx +9 -9
  1053. data/ext/couchbase/couchbase/vector_query.hxx +82 -62
  1054. data/ext/couchbase/couchbase/vector_search.hxx +51 -47
  1055. data/ext/couchbase/couchbase/vector_search_options.hxx +45 -41
  1056. data/ext/couchbase/couchbase/wan_development_configuration_profile.hxx +13 -13
  1057. data/ext/couchbase/couchbase/watch_query_indexes_options.hxx +41 -41
  1058. data/ext/couchbase/couchbase/wildcard_query.hxx +42 -41
  1059. data/ext/couchbase/third_party/expected/include/tl/expected.hpp +1746 -1584
  1060. data/ext/couchbase/third_party/jsonsl/jsonsl.c +2664 -2638
  1061. data/ext/couchbase/third_party/jsonsl/jsonsl.h +359 -342
  1062. data/ext/couchbase.cxx +43 -9568
  1063. data/ext/extconf.rb +5 -0
  1064. data/ext/rcb_analytics.cxx +1195 -0
  1065. data/ext/rcb_analytics.hxx +29 -0
  1066. data/ext/rcb_backend.cxx +530 -0
  1067. data/ext/rcb_backend.hxx +46 -0
  1068. data/ext/rcb_buckets.cxx +624 -0
  1069. data/ext/rcb_buckets.hxx +29 -0
  1070. data/ext/rcb_collections.cxx +377 -0
  1071. data/ext/rcb_collections.hxx +29 -0
  1072. data/ext/rcb_crud.cxx +1544 -0
  1073. data/ext/rcb_crud.hxx +29 -0
  1074. data/ext/rcb_diagnostics.cxx +264 -0
  1075. data/ext/rcb_diagnostics.hxx +29 -0
  1076. data/ext/rcb_exceptions.cxx +963 -0
  1077. data/ext/rcb_exceptions.hxx +111 -0
  1078. data/ext/rcb_extras.cxx +394 -0
  1079. data/ext/rcb_extras.hxx +29 -0
  1080. data/ext/rcb_logger.cxx +319 -0
  1081. data/ext/rcb_logger.hxx +36 -0
  1082. data/ext/rcb_multi.cxx +343 -0
  1083. data/ext/rcb_multi.hxx +29 -0
  1084. data/ext/rcb_query.cxx +1316 -0
  1085. data/ext/rcb_query.hxx +29 -0
  1086. data/ext/rcb_range_scan.cxx +358 -0
  1087. data/ext/rcb_range_scan.hxx +29 -0
  1088. data/ext/rcb_search.cxx +1216 -0
  1089. data/ext/rcb_search.hxx +29 -0
  1090. data/ext/rcb_users.cxx +636 -0
  1091. data/ext/rcb_users.hxx +29 -0
  1092. data/ext/rcb_utils.cxx +590 -0
  1093. data/ext/rcb_utils.hxx +564 -0
  1094. data/ext/rcb_version.cxx +137 -0
  1095. data/ext/rcb_version.hxx +34 -0
  1096. data/ext/rcb_views.cxx +485 -0
  1097. data/ext/rcb_views.hxx +29 -0
  1098. data/lib/active_support/cache/couchbase_store.rb +4 -1
  1099. data/lib/couchbase/analytics_options.rb +2 -0
  1100. data/lib/couchbase/authenticator.rb +2 -0
  1101. data/lib/couchbase/binary_collection.rb +2 -0
  1102. data/lib/couchbase/binary_collection_options.rb +2 -0
  1103. data/lib/couchbase/bucket.rb +2 -0
  1104. data/lib/couchbase/cluster.rb +2 -0
  1105. data/lib/couchbase/collection.rb +3 -1
  1106. data/lib/couchbase/collection_options.rb +2 -0
  1107. data/lib/couchbase/config_profiles.rb +2 -0
  1108. data/lib/couchbase/configuration.rb +2 -0
  1109. data/lib/couchbase/datastructures/couchbase_list.rb +4 -4
  1110. data/lib/couchbase/datastructures/couchbase_map.rb +4 -4
  1111. data/lib/couchbase/datastructures/couchbase_queue.rb +4 -4
  1112. data/lib/couchbase/datastructures/couchbase_set.rb +4 -4
  1113. data/lib/couchbase/datastructures.rb +2 -0
  1114. data/lib/couchbase/diagnostics.rb +2 -0
  1115. data/lib/couchbase/errors.rb +46 -8
  1116. data/lib/couchbase/json_transcoder.rb +2 -0
  1117. data/lib/couchbase/key_value_scan.rb +2 -0
  1118. data/lib/couchbase/logger.rb +2 -0
  1119. data/lib/couchbase/management/analytics_index_manager.rb +2 -0
  1120. data/lib/couchbase/management/bucket_manager.rb +2 -0
  1121. data/lib/couchbase/management/collection_manager.rb +2 -0
  1122. data/lib/couchbase/management/collection_query_index_manager.rb +2 -0
  1123. data/lib/couchbase/management/query_index_manager.rb +2 -0
  1124. data/lib/couchbase/management/scope_search_index_manager.rb +2 -0
  1125. data/lib/couchbase/management/search_index_manager.rb +2 -0
  1126. data/lib/couchbase/management/user_manager.rb +2 -0
  1127. data/lib/couchbase/management/view_index_manager.rb +2 -0
  1128. data/lib/couchbase/management.rb +2 -0
  1129. data/lib/couchbase/mutation_state.rb +2 -0
  1130. data/lib/couchbase/options.rb +2 -0
  1131. data/lib/couchbase/protostellar/request_generator/kv.rb +1 -1
  1132. data/lib/couchbase/query_options.rb +2 -0
  1133. data/lib/couchbase/railtie.rb +2 -0
  1134. data/lib/couchbase/raw_binary_transcoder.rb +2 -0
  1135. data/lib/couchbase/raw_json_transcoder.rb +2 -0
  1136. data/lib/couchbase/raw_string_transcoder.rb +2 -0
  1137. data/lib/couchbase/scope.rb +2 -0
  1138. data/lib/couchbase/search_options.rb +91 -63
  1139. data/lib/couchbase/subdoc.rb +5 -3
  1140. data/lib/couchbase/transcoder_flags.rb +2 -0
  1141. data/lib/couchbase/utils/generic_logger_adapter.rb +3 -1
  1142. data/lib/couchbase/utils/stdlib_logger_adapter.rb +2 -0
  1143. data/lib/couchbase/utils/time.rb +3 -1
  1144. data/lib/couchbase/utils.rb +2 -0
  1145. data/lib/couchbase/version.rb +3 -1
  1146. data/lib/couchbase/view_options.rb +2 -0
  1147. data/lib/couchbase.rb +2 -0
  1148. data/lib/rails/generators/couchbase/config/config_generator.rb +2 -0
  1149. metadata +83 -26
  1150. data/ext/couchbase/core/impl/internal_manager_error_context.cxx +0 -113
  1151. data/ext/couchbase/core/impl/internal_manager_error_context.hxx +0 -60
  1152. data/ext/couchbase/core/impl/manager_error_context.cxx +0 -100
  1153. data/ext/couchbase/core/impl/search_error_context.cxx +0 -147
  1154. data/ext/couchbase/couchbase/analytics_error_context.hxx +0 -143
  1155. data/ext/couchbase/couchbase/fmt/key_value_error_map_attribute.hxx +0 -100
  1156. data/ext/couchbase/couchbase/fmt/key_value_status_code.hxx +0 -269
  1157. data/ext/couchbase/couchbase/key_value_error_context.hxx +0 -229
  1158. data/ext/couchbase/couchbase/key_value_error_map_attribute.hxx +0 -136
  1159. data/ext/couchbase/couchbase/key_value_error_map_info.hxx +0 -138
  1160. data/ext/couchbase/couchbase/key_value_extended_error_info.hxx +0 -86
  1161. data/ext/couchbase/couchbase/key_value_status_code.hxx +0 -109
  1162. data/ext/couchbase/couchbase/manager_error_context.hxx +0 -111
  1163. data/ext/couchbase/couchbase/query_error_context.hxx +0 -145
  1164. data/ext/couchbase/couchbase/search_error_context.hxx +0 -138
  1165. data/ext/couchbase/couchbase/subdocument_error_context.hxx +0 -147
  1166. data/ext/couchbase/couchbase/transaction_op_error_context.hxx +0 -76
@@ -64,1682 +64,1829 @@ namespace
64
64
  {
65
65
  template<typename Container>
66
66
  struct mcbp_header_view {
67
- const Container& buf_;
67
+ const Container& buf_;
68
68
 
69
- mcbp_header_view(const Container& buf)
70
- : buf_{ buf }
71
- {
72
- }
69
+ mcbp_header_view(const Container& buf)
70
+ : buf_{ buf }
71
+ {
72
+ }
73
73
  };
74
74
 
75
75
  struct mcbp_header_layout {
76
- std::uint8_t magic;
77
- std::uint8_t opcode;
78
- union {
79
- std::uint16_t normal;
80
- struct {
81
- std::uint8_t framing_extras;
82
- std::uint8_t key;
83
- } alt;
84
- } keylen;
85
- std::uint8_t extlen;
86
- std::uint8_t datatype;
87
- std::uint16_t specific;
88
- std::uint32_t bodylen;
89
- std::uint32_t opaque;
90
- std::uint64_t cas;
91
-
92
- [[nodiscard]] constexpr auto specific_name() const -> std::string_view
93
- {
94
- if (magic == 0x18 || magic == 0x81) {
95
- return "status";
96
- }
97
- return "vbucket";
76
+ std::uint8_t magic;
77
+ std::uint8_t opcode;
78
+ union {
79
+ std::uint16_t normal;
80
+ struct {
81
+ std::uint8_t framing_extras;
82
+ std::uint8_t key;
83
+ } alt;
84
+ } keylen;
85
+ std::uint8_t extlen;
86
+ std::uint8_t datatype;
87
+ std::uint16_t specific;
88
+ std::uint32_t bodylen;
89
+ std::uint32_t opaque;
90
+ std::uint64_t cas;
91
+
92
+ [[nodiscard]] constexpr auto specific_name() const -> std::string_view
93
+ {
94
+ if (magic == 0x18 || magic == 0x81) {
95
+ return "status";
98
96
  }
97
+ return "vbucket";
98
+ }
99
99
 
100
- [[nodiscard]] constexpr auto key_length() const -> std::uint16_t
101
- {
102
- if (magic == 0x18 || magic == 0x08) {
103
- return keylen.alt.key;
104
- }
105
- return couchbase::core::utils::byte_swap(keylen.normal);
100
+ [[nodiscard]] constexpr auto key_length() const -> std::uint16_t
101
+ {
102
+ if (magic == 0x18 || magic == 0x08) {
103
+ return keylen.alt.key;
106
104
  }
105
+ return couchbase::core::utils::byte_swap(keylen.normal);
106
+ }
107
107
 
108
- [[nodiscard]] constexpr auto framing_extras_length() const -> std::uint8_t
109
- {
110
- if (magic == 0x18 || magic == 0x08) {
111
- return keylen.alt.framing_extras;
112
- }
113
- return 0;
108
+ [[nodiscard]] constexpr auto framing_extras_length() const -> std::uint8_t
109
+ {
110
+ if (magic == 0x18 || magic == 0x08) {
111
+ return keylen.alt.framing_extras;
114
112
  }
113
+ return 0;
114
+ }
115
115
  };
116
116
  } // namespace
117
117
 
118
118
  template<typename Container>
119
119
  struct fmt::formatter<mcbp_header_view<Container>> {
120
- template<typename ParseContext>
121
- constexpr auto parse(ParseContext& ctx)
122
- {
123
- return ctx.begin();
120
+ template<typename ParseContext>
121
+ constexpr auto parse(ParseContext& ctx)
122
+ {
123
+ return ctx.begin();
124
+ }
125
+
126
+ template<typename FormatContext>
127
+ auto format(const mcbp_header_view<Container>& view, FormatContext& ctx) const
128
+ {
129
+ if (view.buf_.size() < sizeof(couchbase::core::io::binary_header)) {
130
+ return format_to(ctx.out(), "{:n}", spdlog::to_hex(view.buf_));
124
131
  }
125
132
 
126
- template<typename FormatContext>
127
- auto format(const mcbp_header_view<Container>& view, FormatContext& ctx) const
128
- {
129
- if (view.buf_.size() < sizeof(couchbase::core::io::binary_header)) {
130
- return format_to(ctx.out(), "{:n}", spdlog::to_hex(view.buf_));
131
- }
132
-
133
- const auto* header = reinterpret_cast<const mcbp_header_layout*>(view.buf_.data());
134
- return format_to(
135
- ctx.out(),
136
- "{{magic=0x{:x}, opcode=0x{:x}, fextlen={}, keylen={}, extlen={}, datatype={}, {}={}, bodylen={}, opaque={}, cas={}}}",
137
- header->magic,
138
- header->opcode,
139
- header->framing_extras_length(),
140
- header->key_length(),
141
- header->extlen,
142
- header->datatype,
143
- header->specific_name(),
144
- couchbase::core::utils::byte_swap(header->specific),
145
- couchbase::core::utils::byte_swap(header->bodylen),
146
- couchbase::core::utils::byte_swap(header->opaque),
147
- couchbase::core::utils::byte_swap(header->cas));
148
- }
133
+ const auto* header = reinterpret_cast<const mcbp_header_layout*>(view.buf_.data());
134
+ return format_to(ctx.out(),
135
+ "{{magic=0x{:x}, opcode=0x{:x}, fextlen={}, keylen={}, extlen={}, "
136
+ "datatype={}, {}={}, bodylen={}, "
137
+ "opaque={}, cas={}}}",
138
+ header->magic,
139
+ header->opcode,
140
+ header->framing_extras_length(),
141
+ header->key_length(),
142
+ header->extlen,
143
+ header->datatype,
144
+ header->specific_name(),
145
+ couchbase::core::utils::byte_swap(header->specific),
146
+ couchbase::core::utils::byte_swap(header->bodylen),
147
+ couchbase::core::utils::byte_swap(header->opaque),
148
+ couchbase::core::utils::byte_swap(header->cas));
149
+ }
149
150
  };
150
151
 
151
152
  namespace couchbase::core::io
152
153
  {
153
154
  struct connection_endpoints {
154
- connection_endpoints(asio::ip::tcp::endpoint remote_endpoint, asio::ip::tcp::endpoint local_endpoint)
155
- : remote{ std::move(remote_endpoint) }
156
- , remote_address{ remote.address().to_string() }
157
- , remote_address_with_port{ remote.protocol() == asio::ip::tcp::v6() ? fmt::format("[{}]:{}", remote_address, remote.port())
158
- : fmt::format("{}:{}", remote_address, remote.port()) }
159
- , local{ std::move(local_endpoint) }
160
- , local_address{ local.address().to_string() }
161
- , local_address_with_port{ local.protocol() == asio::ip::tcp::v6() ? fmt::format("[{}]:{}", local_address, local.port())
162
- : fmt::format("{}:{}", local_address, local.port()) }
163
- {
164
- }
165
-
166
- asio::ip::tcp::endpoint remote;
167
- std::string remote_address{};
168
- std::string remote_address_with_port{};
169
-
170
- asio::ip::tcp::endpoint local;
171
- std::string local_address{};
172
- std::string local_address_with_port{};
155
+ connection_endpoints(asio::ip::tcp::endpoint remote_endpoint,
156
+ asio::ip::tcp::endpoint local_endpoint)
157
+ : remote{ std::move(remote_endpoint) }
158
+ , remote_address{ remote.address().to_string() }
159
+ , remote_address_with_port{ remote.protocol() == asio::ip::tcp::v6()
160
+ ? fmt::format("[{}]:{}", remote_address, remote.port())
161
+ : fmt::format("{}:{}", remote_address, remote.port()) }
162
+ , local{ std::move(local_endpoint) }
163
+ , local_address{ local.address().to_string() }
164
+ , local_address_with_port{ local.protocol() == asio::ip::tcp::v6()
165
+ ? fmt::format("[{}]:{}", local_address, local.port())
166
+ : fmt::format("{}:{}", local_address, local.port()) }
167
+ {
168
+ }
169
+
170
+ asio::ip::tcp::endpoint remote;
171
+ std::string remote_address{};
172
+ std::string remote_address_with_port{};
173
+
174
+ asio::ip::tcp::endpoint local;
175
+ std::string local_address{};
176
+ std::string local_address_with_port{};
173
177
  };
174
178
 
175
179
  class collection_cache
176
180
  {
177
- private:
178
- std::map<std::string, std::uint32_t> cid_map_{ { "_default._default", 0 } };
179
-
180
- public:
181
- [[nodiscard]] std::optional<std::uint32_t> get(const std::string& path)
182
- {
183
- Expects(!path.empty());
184
- if (auto ptr = cid_map_.find(path); ptr != cid_map_.end()) {
185
- return ptr->second;
186
- }
187
- return std::nullopt;
188
- }
189
-
190
- void update(const std::string& path, std::uint32_t id)
191
- {
192
- Expects(!path.empty());
193
- cid_map_[path] = id;
194
- }
195
-
196
- void reset()
197
- {
198
- cid_map_.clear();
199
- cid_map_["_default._default"] = 0;
181
+ private:
182
+ std::map<std::string, std::uint32_t> cid_map_{ { "_default._default", 0 } };
183
+
184
+ public:
185
+ [[nodiscard]] auto get(const std::string& path) -> std::optional<std::uint32_t>
186
+ {
187
+ Expects(!path.empty());
188
+ if (auto ptr = cid_map_.find(path); ptr != cid_map_.end()) {
189
+ return ptr->second;
200
190
  }
191
+ return std::nullopt;
192
+ }
193
+
194
+ void update(const std::string& path, std::uint32_t id)
195
+ {
196
+ Expects(!path.empty());
197
+ cid_map_[path] = id;
198
+ }
199
+
200
+ void reset()
201
+ {
202
+ cid_map_.clear();
203
+ cid_map_["_default._default"] = 0;
204
+ }
201
205
  };
202
206
 
203
207
  class mcbp_session_impl
204
208
  : public std::enable_shared_from_this<mcbp_session_impl>
205
209
  , public operation_map
206
210
  {
207
- class bootstrap_handler : public std::enable_shared_from_this<bootstrap_handler>
208
- {
209
- private:
210
- std::shared_ptr<mcbp_session_impl> session_;
211
- sasl::ClientContext sasl_;
212
- std::atomic_bool stopped_{ false };
213
- std::string last_error_message_;
214
-
215
- public:
216
- ~bootstrap_handler()
217
- {
218
- stop();
219
- }
220
-
221
- void stop()
222
- {
223
- bool expected_state{ false };
224
- stopped_.compare_exchange_strong(expected_state, true);
225
- }
226
-
227
- static auto sasl_mechanisms(const std::shared_ptr<mcbp_session_impl>& session) -> std::vector<std::string>
228
- {
229
- if (const auto user_mechanisms = session->origin_.credentials().allowed_sasl_mechanisms; user_mechanisms.has_value()) {
230
- return user_mechanisms.value();
231
- }
232
- if (session->is_tls_) {
233
- return { "PLAIN" };
234
- }
235
- return { "SCRAM-SHA512", "SCRAM-SHA256", "SCRAM-SHA1" };
236
- }
237
-
238
- std::string last_error_message() &&
239
- {
240
- return std::move(last_error_message_);
241
- }
242
-
243
- [[nodiscard]] const std::string& last_error_message() const&
244
- {
245
- return last_error_message_;
246
- }
247
-
248
- explicit bootstrap_handler(std::shared_ptr<mcbp_session_impl> session)
249
- : session_(std::move(session))
250
- , sasl_([origin = session_->origin_]() { return origin.username(); },
251
- [origin = session_->origin_]() { return origin.password(); },
252
- sasl_mechanisms(session_))
253
- {
254
- protocol::client_request<protocol::hello_request_body> hello_req;
255
- if (session_->origin_.options().enable_unordered_execution) {
256
- hello_req.body().enable_unordered_execution();
257
- }
258
- if (session_->origin_.options().enable_clustermap_notification) {
259
- hello_req.body().enable_clustermap_change_notification();
260
- hello_req.body().enable_deduplicate_not_my_vbucket_clustermap();
261
- }
262
- if (session_->origin_.options().enable_compression) {
263
- hello_req.body().enable_compression();
264
- }
265
- if (session_->origin_.options().enable_mutation_tokens) {
266
- hello_req.body().enable_mutation_tokens();
267
- }
268
- hello_req.opaque(session_->next_opaque());
269
- auto user_agent =
270
- meta::user_agent_for_mcbp(session_->client_id_, session_->id_, session_->origin_.options().user_agent_extra, 250);
271
- hello_req.body().user_agent(user_agent);
272
- CB_LOG_DEBUG("{} user_agent={}, requested_features=[{}]",
273
- session_->log_prefix_,
274
- user_agent,
275
- utils::join_strings_fmt(hello_req.body().features(), ", "));
276
- session_->write(hello_req.data());
277
-
278
- if (!session_->origin_.credentials().uses_certificate()) {
279
- protocol::client_request<protocol::sasl_list_mechs_request_body> list_req;
280
- list_req.opaque(session_->next_opaque());
281
- session_->write(list_req.data());
282
-
283
- protocol::client_request<protocol::sasl_auth_request_body> auth_req;
284
- auto [sasl_code, sasl_payload] = sasl_.start();
285
- auth_req.opaque(session_->next_opaque());
286
- auth_req.body().mechanism(sasl_.get_name());
287
- auth_req.body().sasl_data(sasl_payload);
288
- session_->write(auth_req.data());
289
- }
290
-
291
- session_->flush();
292
- }
293
-
294
- void complete(std::error_code ec)
295
- {
296
- if (bool expected_state{ false }; stopped_.compare_exchange_strong(expected_state, true)) {
297
- session_->invoke_bootstrap_handler(ec);
298
- }
299
- }
300
-
301
- void auth_success()
302
- {
303
- session_->authenticated_ = true;
304
- if (session_->supports_feature(protocol::hello_feature::xerror)) {
305
- protocol::client_request<protocol::get_error_map_request_body> errmap_req;
306
- errmap_req.opaque(session_->next_opaque());
307
- session_->write(errmap_req.data());
308
- }
309
- if (session_->bucket_name_) {
310
- protocol::client_request<protocol::select_bucket_request_body> sb_req;
311
- sb_req.opaque(session_->next_opaque());
312
- sb_req.body().bucket_name(session_->bucket_name_.value());
313
- session_->write(sb_req.data());
314
- }
315
- protocol::client_request<protocol::get_cluster_config_request_body> cfg_req;
316
- cfg_req.opaque(session_->next_opaque());
317
- session_->write(cfg_req.data());
318
- session_->flush();
319
- }
320
-
321
- void handle(mcbp_message&& msg)
322
- {
323
- if (stopped_ || !session_) {
324
- return;
325
- }
326
- Expects(protocol::is_valid_magic(msg.header.magic));
327
- switch (auto magic = static_cast<protocol::magic>(msg.header.magic)) {
328
- case protocol::magic::client_response:
329
- case protocol::magic::alt_client_response:
330
- Expects(protocol::is_valid_client_opcode(msg.header.opcode));
331
- switch (auto status = static_cast<key_value_status_code>(msg.header.status())) {
332
- case key_value_status_code::rate_limited_max_commands:
333
- case key_value_status_code::rate_limited_max_connections:
334
- case key_value_status_code::rate_limited_network_egress:
335
- case key_value_status_code::rate_limited_network_ingress:
336
- last_error_message_ = fmt::format(
337
- "unable to bootstrap MCBP session (bucket={}, opcode={}, status={}), the user has reached rate limit",
338
- session_->bucket_name_.value_or(""),
339
- protocol::client_opcode(msg.header.opcode),
340
- status);
341
- CB_LOG_DEBUG("{} {}", session_->log_prefix_, last_error_message_);
342
- return complete(errc::common::rate_limited);
343
-
344
- case key_value_status_code::scope_size_limit_exceeded:
345
- last_error_message_ = fmt::format(
346
- "unable to bootstrap MCBP session (bucket={}, opcode={}, status={}), the user has reached quota limit",
347
- session_->bucket_name_.value_or(""),
348
- protocol::client_opcode(msg.header.opcode),
349
- status);
350
- CB_LOG_DEBUG("{} {}", session_->log_prefix_, last_error_message_);
351
- return complete(errc::common::quota_limited);
352
-
353
- default:
354
- break;
355
- }
356
- switch (auto opcode = static_cast<protocol::client_opcode>(msg.header.opcode)) {
357
- case protocol::client_opcode::hello: {
358
- protocol::client_response<protocol::hello_response_body> resp(std::move(msg));
359
- if (resp.status() == key_value_status_code::success) {
360
- session_->supported_features_ = resp.body().supported_features();
361
- CB_LOG_DEBUG("{} supported_features=[{}]",
362
- session_->log_prefix_,
363
- utils::join_strings_fmt(session_->supported_features_, ", "));
364
- if (session_->origin_.credentials().uses_certificate()) {
365
- CB_LOG_DEBUG("{} skip SASL authentication, because TLS certificate was specified",
366
- session_->log_prefix_);
367
- return auth_success();
368
- }
369
- } else {
370
- last_error_message_ = fmt::format(
371
- "unexpected message status during bootstrap: {} (opaque={})", resp.error_message(), resp.opaque());
372
- CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
373
- return complete(errc::network::handshake_failure);
374
- }
375
- } break;
376
- case protocol::client_opcode::sasl_list_mechs: {
377
- protocol::client_response<protocol::sasl_list_mechs_response_body> resp(std::move(msg));
378
- if (resp.status() != key_value_status_code::success) {
379
- last_error_message_ = fmt::format(
380
- "unexpected message status during bootstrap: {} (opaque={})", resp.error_message(), resp.opaque());
381
- CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
382
- return complete(errc::common::authentication_failure);
383
- }
384
- } break;
385
- case protocol::client_opcode::sasl_auth: {
386
- protocol::client_response<protocol::sasl_auth_response_body> resp(std::move(msg));
387
- if (resp.status() == key_value_status_code::success) {
388
- return auth_success();
389
- }
390
- if (resp.status() == key_value_status_code::auth_continue) {
391
- auto [sasl_code, sasl_payload] = sasl_.step(resp.body().value());
392
- if (sasl_code == sasl::error::OK) {
393
- return auth_success();
394
- }
395
- if (sasl_code == sasl::error::CONTINUE) {
396
- protocol::client_request<protocol::sasl_step_request_body> req;
397
- req.opaque(session_->next_opaque());
398
- req.body().mechanism(sasl_.get_name());
399
- req.body().sasl_data(sasl_payload);
400
- session_->write_and_flush(req.data());
401
- } else {
402
- last_error_message_ =
403
- fmt::format("unable to authenticate: (sasl_code={}, opaque={})", sasl_code, resp.opaque());
404
- CB_LOG_ERROR("{} {}", session_->log_prefix_, last_error_message_);
405
- return complete(errc::common::authentication_failure);
406
- }
407
- } else {
408
- last_error_message_ = fmt::format("{} unexpected message status during bootstrap: {} (opaque={})",
409
- session_->log_prefix_,
410
- resp.error_message(),
411
- resp.opaque());
412
- CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
413
- return complete(errc::common::authentication_failure);
414
- }
415
- } break;
416
- case protocol::client_opcode::sasl_step: {
417
- protocol::client_response<protocol::sasl_step_response_body> resp(std::move(msg));
418
- if (resp.status() == key_value_status_code::success) {
419
- return auth_success();
420
- }
421
- last_error_message_ =
422
- fmt::format("unable to authenticate (opcode={}, status={}, opaque={})", opcode, resp.status(), resp.opaque());
423
- CB_LOG_ERROR("{} {}", session_->log_prefix_, last_error_message_);
424
- return complete(errc::common::authentication_failure);
425
- }
426
- case protocol::client_opcode::get_error_map: {
427
- protocol::client_response<protocol::get_error_map_response_body> resp(std::move(msg));
428
- if (resp.status() == key_value_status_code::success) {
429
- session_->error_map_.emplace(resp.body().errmap());
430
- } else {
431
- last_error_message_ = fmt::format("unexpected message status during bootstrap: {} (opaque={}, {:n})",
432
- resp.error_message(),
433
- resp.opaque(),
434
- spdlog::to_hex(resp.header()));
435
- CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
436
- return complete(errc::network::protocol_error);
437
- }
438
- } break;
439
- case protocol::client_opcode::select_bucket: {
440
- protocol::client_response<protocol::select_bucket_response_body> resp(std::move(msg));
441
- if (resp.status() == key_value_status_code::success) {
442
- CB_LOG_DEBUG("{} selected bucket: {}", session_->log_prefix_, session_->bucket_name_.value_or(""));
443
- session_->bucket_selected_ = true;
444
- } else if (resp.status() == key_value_status_code::not_found) {
445
- last_error_message_ =
446
- fmt::format("kv_engine node does not have configuration propagated yet (opcode={}, status={}, opaque={})",
447
- opcode,
448
- resp.status(),
449
- resp.opaque());
450
- CB_LOG_DEBUG("{} {}", session_->log_prefix_, last_error_message_);
451
- return complete(errc::network::configuration_not_available);
452
- } else if (resp.status() == key_value_status_code::no_access) {
453
- last_error_message_ = fmt::format("unable to select bucket: {}, probably the bucket does not exist",
454
- session_->bucket_name_.value_or(""));
455
- CB_LOG_DEBUG("{} {}", session_->log_prefix_, last_error_message_);
456
- session_->bucket_selected_ = false;
457
- return complete(errc::common::bucket_not_found);
458
- } else {
459
- last_error_message_ = fmt::format("unexpected message status during bootstrap: {} (opaque={}, {:n})",
460
- resp.error_message(),
461
- resp.opaque(),
462
- spdlog::to_hex(resp.header()));
463
- CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
464
- return complete(errc::common::bucket_not_found);
465
- }
466
- } break;
467
- case protocol::client_opcode::get_cluster_config: {
468
- protocol::cmd_info info{ session_->connection_endpoints_.remote_address,
469
- session_->connection_endpoints_.remote.port() };
470
- if (session_->origin_.options().dump_configuration) {
471
- std::string_view config_text{ reinterpret_cast<const char*>(msg.body.data()), msg.body.size() };
472
- CB_LOG_TRACE(
473
- "{} configuration from get_cluster_config request (bootstrap, size={}, endpoint=\"{}:{}\"), {}",
474
- session_->log_prefix_,
475
- config_text.size(),
476
- info.endpoint_address,
477
- info.endpoint_port,
478
- config_text);
479
- }
480
- protocol::client_response<protocol::get_cluster_config_response_body> resp(std::move(msg), info);
481
- if (resp.status() == key_value_status_code::success) {
482
- // MB-60405 fixes this for 7.6.2, but for earlier versions we need to protect against using a
483
- // config that has an empty vbucket map. Ideally we don't timeout if we retry here, but a timeout
484
- // would be more acceptable than a crash and if we do timeout, we have a clear indication of the
485
- // problem (i.e. it is a server bug and we cannot use a config w/ an empty vbucket map).
486
- if (resp.body().config().vbmap && resp.body().config().vbmap->size() == 0) {
487
- CB_LOG_WARNING("{} received a configuration with an empty vbucket map, retrying",
488
- session_->log_prefix_);
489
- return complete(errc::network::configuration_not_available);
490
- }
491
- session_->update_configuration(resp.body().config());
492
- complete({});
493
- } else if (resp.status() == key_value_status_code::not_found) {
494
- last_error_message_ =
495
- fmt::format("kv_engine node does not have configuration propagated yet (opcode={}, status={}, opaque={})",
496
- opcode,
497
- resp.status(),
498
- resp.opaque());
499
- CB_LOG_DEBUG("{} {}", session_->log_prefix_, last_error_message_);
500
- return complete(errc::network::configuration_not_available);
501
- } else if (resp.status() == key_value_status_code::no_bucket && !session_->bucket_name_) {
502
- // bucket-less session, but the server wants bucket
503
- session_->supports_gcccp_ = false;
504
- CB_LOG_WARNING("{} this server does not support GCCCP, open bucket before making any cluster-level command",
505
- session_->log_prefix_);
506
- session_->update_configuration(topology::make_blank_configuration(
507
- session_->connection_endpoints_.remote_address, session_->connection_endpoints_.remote.port(), 0));
508
- complete({});
509
- } else {
510
- last_error_message_ = fmt::format("unexpected message status during bootstrap: {} (opaque={}, {:n})",
511
- resp.error_message(),
512
- resp.opaque(),
513
- spdlog::to_hex(resp.header()));
514
- CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
515
- return complete(errc::network::protocol_error);
516
- }
517
- } break;
518
- default:
519
- last_error_message_ = fmt::format("unexpected message during bootstrap: {}", opcode);
520
- CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
521
- return complete(errc::network::protocol_error);
522
- }
523
- break;
524
- case protocol::magic::server_request:
525
- Expects(protocol::is_valid_server_request_opcode(msg.header.opcode));
526
- switch (static_cast<protocol::server_opcode>(msg.header.opcode)) {
527
- case protocol::server_opcode::cluster_map_change_notification: {
528
- protocol::cmd_info info{ session_->bootstrap_hostname_, session_->bootstrap_port_number_ };
529
- if (session_->origin_.options().dump_configuration) {
530
- std::string_view config_text{ reinterpret_cast<const char*>(msg.body.data()), msg.body.size() };
531
- CB_LOG_TRACE(
532
- "{} configuration from cluster_map_change_notification request (size={}, endpoint=\"{}:{}\"), {}",
533
- session_->log_prefix_,
534
- config_text.size(),
535
- info.endpoint_address,
536
- info.endpoint_port,
537
- config_text);
538
- }
539
- protocol::server_request<protocol::cluster_map_change_notification_request_body> req(std::move(msg), info);
540
- std::optional<topology::configuration> config = req.body().config();
541
- if (session_ && config.has_value()) {
542
- if ((!config->bucket.has_value() && req.body().bucket().empty()) ||
543
- (session_->bucket_name_.has_value() && !req.body().bucket().empty() &&
544
- session_->bucket_name_.value() == req.body().bucket())) {
545
- session_->update_configuration(std::move(config.value()));
546
- }
547
- }
548
- } break;
549
- default:
550
- CB_LOG_WARNING("{} unexpected server request: opcode={:x}, opaque={}{:a}{:a}",
551
- session_->log_prefix_,
552
- msg.header.opcode,
553
- utils::byte_swap(msg.header.opaque),
554
- spdlog::to_hex(msg.header_data()),
555
- spdlog::to_hex(msg.body));
556
- }
557
- break;
558
- case protocol::magic::client_request:
559
- case protocol::magic::alt_client_request:
560
- case protocol::magic::server_response:
561
- CB_LOG_WARNING("{} unexpected magic: {} (opcode={:x}, opaque={}){:a}{:a}",
562
- session_->log_prefix_,
563
- magic,
564
- msg.header.opcode,
565
- utils::byte_swap(msg.header.opaque),
566
- spdlog::to_hex(msg.header_data()),
567
- spdlog::to_hex(msg.body));
568
- break;
569
- }
570
- }
571
- };
572
-
573
- class message_handler : public std::enable_shared_from_this<message_handler>
574
- {
575
- private:
576
- std::shared_ptr<mcbp_session_impl> session_;
577
- std::atomic_bool stopped_{ false };
578
-
579
- public:
580
- explicit message_handler(std::shared_ptr<mcbp_session_impl> session)
581
- : session_(std::move(session))
582
- {
583
- }
584
-
585
- ~message_handler()
586
- {
587
- stop();
588
- }
589
-
590
- void start()
591
- {
592
- }
593
-
594
- void stop()
595
- {
596
- }
597
-
598
- void handle(mcbp_message&& msg)
599
- {
600
- if (stopped_ || !session_) {
601
- return;
602
- }
603
- Expects(protocol::is_valid_magic(msg.header.magic));
604
- switch (auto magic = static_cast<protocol::magic>(msg.header.magic)) {
605
- case protocol::magic::client_response:
606
- case protocol::magic::alt_client_response:
607
- Expects(protocol::is_valid_client_opcode(msg.header.opcode));
608
- switch (auto opcode = static_cast<protocol::client_opcode>(msg.header.opcode)) {
609
- case protocol::client_opcode::get_cluster_config: {
610
- protocol::cmd_info info{ session_->bootstrap_hostname_, session_->bootstrap_port_number_ };
611
- if (session_->origin_.options().dump_configuration) {
612
- std::string_view config_text{ reinterpret_cast<const char*>(msg.body.data()), msg.body.size() };
613
- CB_LOG_TRACE("{} configuration from get_cluster_config response (size={}, endpoint=\"{}:{}\"), {}",
614
- session_->log_prefix_,
615
- config_text.size(),
616
- info.endpoint_address,
617
- info.endpoint_port,
618
- config_text);
619
- }
620
- protocol::client_response<protocol::get_cluster_config_response_body> resp(std::move(msg), info);
621
- if (resp.status() == key_value_status_code::success) {
622
- if (session_) {
623
- session_->update_configuration(resp.body().config());
624
- }
625
- } else {
626
- CB_LOG_WARNING("{} unexpected message status: {} (opaque={})",
627
- session_->log_prefix_,
628
- resp.error_message(),
629
- resp.opaque());
630
- }
631
- } break;
632
- case protocol::client_opcode::noop:
633
- case protocol::client_opcode::get_collections_manifest:
634
- case protocol::client_opcode::get_collection_id:
635
- case protocol::client_opcode::get:
636
- case protocol::client_opcode::get_and_lock:
637
- case protocol::client_opcode::get_and_touch:
638
- case protocol::client_opcode::get_meta:
639
- case protocol::client_opcode::get_replica:
640
- case protocol::client_opcode::touch:
641
- case protocol::client_opcode::insert:
642
- case protocol::client_opcode::replace:
643
- case protocol::client_opcode::upsert:
644
- case protocol::client_opcode::append:
645
- case protocol::client_opcode::prepend:
646
- case protocol::client_opcode::remove:
647
- case protocol::client_opcode::observe_seqno:
648
- case protocol::client_opcode::unlock:
649
- case protocol::client_opcode::increment:
650
- case protocol::client_opcode::range_scan_create:
651
- case protocol::client_opcode::range_scan_continue:
652
- case protocol::client_opcode::range_scan_cancel:
653
- case protocol::client_opcode::decrement:
654
- case protocol::client_opcode::subdoc_multi_lookup:
655
- case protocol::client_opcode::subdoc_multi_mutation: {
656
- std::uint16_t status = utils::byte_swap(msg.header.specific);
657
- if (status == static_cast<std::uint16_t>(key_value_status_code::not_my_vbucket)) {
658
- session_->handle_not_my_vbucket(msg);
659
- }
660
-
661
- std::uint32_t opaque = utils::byte_swap(msg.header.opaque);
662
- if (session_->handle_request(opcode, status, opaque, std::move(msg))) {
663
- CB_LOG_TRACE("{} MCBP invoked operation handler: opcode={}, opaque={}, status={}",
664
- session_->log_prefix_,
665
- opcode,
666
- opaque,
667
- protocol::status_to_string(status));
668
- } else {
669
- CB_LOG_DEBUG("{} unexpected orphan response: opcode={}, opaque={}, status={}",
670
- session_->log_prefix_,
671
- opcode,
672
- opaque,
673
- protocol::status_to_string(status));
674
- }
675
- } break;
676
- default:
677
- CB_LOG_WARNING("{} unexpected client response: opcode={}, opaque={}{:a}{:a})",
678
- session_->log_prefix_,
679
- opcode,
680
- msg.header.opaque,
681
- spdlog::to_hex(msg.header_data()),
682
- spdlog::to_hex(msg.body));
683
- }
684
- break;
685
- case protocol::magic::server_request:
686
- Expects(protocol::is_valid_server_request_opcode(msg.header.opcode));
687
- switch (static_cast<protocol::server_opcode>(msg.header.opcode)) {
688
- case protocol::server_opcode::cluster_map_change_notification: {
689
- protocol::cmd_info info{ session_->bootstrap_hostname_, session_->bootstrap_port_number_ };
690
- if (session_->origin_.options().dump_configuration) {
691
- std::string_view config_text{ reinterpret_cast<const char*>(msg.body.data()), msg.body.size() };
692
- CB_LOG_TRACE(
693
- "{} configuration from cluster_map_change_notification request (size={}, endpoint=\"{}:{}\"), {}",
694
- session_->log_prefix_,
695
- config_text.size(),
696
- info.endpoint_address,
697
- info.endpoint_port,
698
- config_text);
699
- }
700
- protocol::server_request<protocol::cluster_map_change_notification_request_body> req(std::move(msg), info);
701
- std::optional<topology::configuration> config = req.body().config();
702
- if (session_ && config.has_value()) {
703
- if ((!config->bucket.has_value() && req.body().bucket().empty()) ||
704
- (session_->bucket_name_.has_value() && !req.body().bucket().empty() &&
705
- session_->bucket_name_.value() == req.body().bucket())) {
706
- session_->update_configuration(std::move(config.value()));
707
- }
708
- }
709
- } break;
710
- default:
711
- CB_LOG_WARNING("{} unexpected server request: opcode={:x}, opaque={}{:a}{:a}",
712
- session_->log_prefix_,
713
- msg.header.opcode,
714
- msg.header.opaque,
715
- spdlog::to_hex(msg.header_data()),
716
- spdlog::to_hex(msg.body));
717
- }
718
- break;
719
- case protocol::magic::client_request:
720
- case protocol::magic::alt_client_request:
721
- case protocol::magic::server_response:
722
- CB_LOG_WARNING("{} unexpected magic: {} (opcode={:x}, opaque={}){:a}{:a}",
723
- session_->log_prefix_,
724
- magic,
725
- msg.header.opcode,
726
- msg.header.opaque,
727
- spdlog::to_hex(msg.header_data()),
728
- spdlog::to_hex(msg.body));
729
- break;
730
- }
731
- }
732
- };
211
+ class bootstrap_handler : public std::enable_shared_from_this<bootstrap_handler>
212
+ {
213
+ private:
214
+ std::shared_ptr<mcbp_session_impl> session_;
215
+ sasl::ClientContext sasl_;
216
+ std::atomic_bool stopped_{ false };
217
+ std::string last_error_message_;
733
218
 
734
219
  public:
735
- mcbp_session_impl() = delete;
736
- mcbp_session_impl(std::string_view client_id,
737
- asio::io_context& ctx,
738
- couchbase::core::origin origin,
739
- std::shared_ptr<impl::bootstrap_state_listener> state_listener,
740
- std::optional<std::string> bucket_name = {},
741
- std::vector<protocol::hello_feature> known_features = {})
742
- : client_id_(client_id)
743
- , ctx_(ctx)
744
- , resolver_(ctx_)
745
- , stream_(std::make_unique<plain_stream_impl>(ctx_))
746
- , bootstrap_deadline_(ctx_)
747
- , connection_deadline_(ctx_)
748
- , retry_backoff_(ctx_)
749
- , ping_deadline_(ctx_)
750
- , origin_{ std::move(origin) }
751
- , bucket_name_{ std::move(bucket_name) }
752
- , supported_features_{ std::move(known_features) }
753
- , is_tls_{ false }
754
- , state_listener_{ std::move(state_listener) }
755
- , codec_{ { supported_features_.begin(), supported_features_.end() } }
220
+ ~bootstrap_handler()
756
221
  {
757
- log_prefix_ = fmt::format("[{}/{}/{}/{}]", client_id_, id_, stream_->log_prefix(), bucket_name_.value_or("-"));
758
- }
759
-
760
- mcbp_session_impl(std::string_view client_id,
761
- asio::io_context& ctx,
762
- asio::ssl::context& tls,
763
- couchbase::core::origin origin,
764
- std::shared_ptr<impl::bootstrap_state_listener> state_listener,
765
- std::optional<std::string> bucket_name = {},
766
- std::vector<protocol::hello_feature> known_features = {})
767
- : client_id_(client_id)
768
- , ctx_(ctx)
769
- , resolver_(ctx_)
770
- , stream_(std::make_unique<tls_stream_impl>(ctx_, tls))
771
- , bootstrap_deadline_(ctx_)
772
- , connection_deadline_(ctx_)
773
- , retry_backoff_(ctx_)
774
- , ping_deadline_(ctx_)
775
- , origin_(std::move(origin))
776
- , bucket_name_(std::move(bucket_name))
777
- , supported_features_(std::move(known_features))
778
- , is_tls_{ true }
779
- , state_listener_{ std::move(state_listener) }
780
- , codec_{ { supported_features_.begin(), supported_features_.end() } }
781
- {
782
- log_prefix_ = fmt::format("[{}/{}/{}/{}]", client_id_, id_, stream_->log_prefix(), bucket_name_.value_or("-"));
222
+ stop();
783
223
  }
784
224
 
785
- ~mcbp_session_impl()
225
+ void stop()
786
226
  {
787
- CB_LOG_DEBUG("{} destroy MCBP connection", log_prefix_);
788
- stop(retry_reason::do_not_retry);
227
+ bool expected_state{ false };
228
+ stopped_.compare_exchange_strong(expected_state, true);
789
229
  }
790
230
 
791
- [[nodiscard]] const std::string& log_prefix() const
231
+ static auto sasl_mechanisms(const std::shared_ptr<mcbp_session_impl>& session)
232
+ -> std::vector<std::string>
792
233
  {
793
- return log_prefix_;
234
+ if (const auto user_mechanisms = session->origin_.credentials().allowed_sasl_mechanisms;
235
+ user_mechanisms.has_value()) {
236
+ return user_mechanisms.value();
237
+ }
238
+ if (session->is_tls_) {
239
+ return { "PLAIN" };
240
+ }
241
+ return { "SCRAM-SHA512", "SCRAM-SHA256", "SCRAM-SHA1" };
794
242
  }
795
243
 
796
- std::string remote_address() const
244
+ auto last_error_message() && -> std::string
797
245
  {
798
- return connection_endpoints_.remote_address_with_port;
246
+ return std::move(last_error_message_);
799
247
  }
800
248
 
801
- std::string local_address() const
249
+ [[nodiscard]] auto last_error_message() const& -> const std::string&
802
250
  {
803
- return connection_endpoints_.local_address_with_port;
251
+ return last_error_message_;
804
252
  }
805
253
 
806
- [[nodiscard]] diag::endpoint_diag_info diag_info() const
807
- {
808
- return { service_type::key_value,
809
- id_,
810
- last_active_.time_since_epoch().count() == 0 ? std::nullopt
811
- : std::make_optional(std::chrono::duration_cast<std::chrono::microseconds>(
812
- std::chrono::steady_clock::now() - last_active_)),
813
- remote_address(),
814
- local_address(),
815
- state_,
816
- bucket_name_ };
817
- }
818
-
819
- void ping(std::shared_ptr<diag::ping_reporter> handler, std::optional<std::chrono::milliseconds> timeout)
254
+ explicit bootstrap_handler(std::shared_ptr<mcbp_session_impl> session)
255
+ : session_(std::move(session))
256
+ , sasl_(
257
+ [origin = session_->origin_]() {
258
+ return origin.username();
259
+ },
260
+ [origin = session_->origin_]() {
261
+ return origin.password();
262
+ },
263
+ sasl_mechanisms(session_))
820
264
  {
821
- if (!bootstrapped_) {
822
- handler->report({
823
- service_type::key_value,
824
- id_,
825
- std::chrono::microseconds(0),
826
- remote_address(),
827
- local_address(),
828
- diag::ping_state::error,
829
- bucket_name_,
830
- last_bootstrap_error_message_.has_value() ? last_bootstrap_error_message_.value()
831
- : "Bootstrap incomplete, cannot perform ping.",
832
- });
833
- return;
834
- }
835
- protocol::client_request<protocol::mcbp_noop_request_body> req;
836
- req.opaque(next_opaque());
837
- write_and_subscribe(req.opaque(),
838
- req.data(false),
839
- [start = std::chrono::steady_clock::now(), self = shared_from_this(), handler](
840
- std::error_code ec,
841
- retry_reason reason,
842
- io::mcbp_message&& /* msg */,
843
- std::optional<key_value_error_map_info> /* error_info */) {
844
- diag::ping_state state = diag::ping_state::ok;
845
- std::optional<std::string> error{};
846
- if (ec) {
847
- if (ec == errc::common::unambiguous_timeout || ec == errc::common::ambiguous_timeout) {
848
- state = diag::ping_state::timeout;
849
- } else {
850
- state = diag::ping_state::error;
851
- }
852
- error.emplace(fmt::format("code={}, message={}, reason={}", ec.value(), ec.message(), reason));
853
- }
854
- handler->report({
855
- service_type::key_value,
856
- self->id_,
857
- std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - start),
858
- self->remote_address(),
859
- self->local_address(),
860
- state,
861
- self->bucket_name_,
862
- error,
863
- });
864
- });
865
- ping_deadline_.expires_after(timeout.value_or(origin_.options().key_value_timeout));
866
- ping_deadline_.async_wait([self = this->shared_from_this(), opaque = req.opaque()](std::error_code ec) {
867
- if (ec == asio::error::operation_aborted) {
868
- return;
869
- }
870
- static_cast<void>(self->cancel(opaque, errc::common::unambiguous_timeout, retry_reason::do_not_retry));
871
- });
265
+ protocol::client_request<protocol::hello_request_body> hello_req;
266
+ if (session_->origin_.options().enable_unordered_execution) {
267
+ hello_req.body().enable_unordered_execution();
268
+ }
269
+ if (session_->origin_.options().enable_clustermap_notification) {
270
+ hello_req.body().enable_clustermap_change_notification();
271
+ hello_req.body().enable_deduplicate_not_my_vbucket_clustermap();
272
+ }
273
+ if (session_->origin_.options().enable_compression) {
274
+ hello_req.body().enable_compression();
275
+ }
276
+ if (session_->origin_.options().enable_mutation_tokens) {
277
+ hello_req.body().enable_mutation_tokens();
278
+ }
279
+ hello_req.opaque(session_->next_opaque());
280
+ auto user_agent = meta::user_agent_for_mcbp(
281
+ session_->client_id_, session_->id_, session_->origin_.options().user_agent_extra, 250);
282
+ hello_req.body().user_agent(user_agent);
283
+ CB_LOG_DEBUG("{} user_agent={}, requested_features=[{}]",
284
+ session_->log_prefix_,
285
+ user_agent,
286
+ utils::join_strings_fmt(hello_req.body().features(), ", "));
287
+ session_->write(hello_req.data());
288
+
289
+ if (!session_->origin_.credentials().uses_certificate()) {
290
+ protocol::client_request<protocol::sasl_list_mechs_request_body> list_req;
291
+ list_req.opaque(session_->next_opaque());
292
+ session_->write(list_req.data());
293
+
294
+ protocol::client_request<protocol::sasl_auth_request_body> auth_req;
295
+ auto [sasl_code, sasl_payload] = sasl_.start();
296
+ auth_req.opaque(session_->next_opaque());
297
+ auth_req.body().mechanism(sasl_.get_name());
298
+ auth_req.body().sasl_data(sasl_payload);
299
+ session_->write(auth_req.data());
300
+ }
301
+
302
+ session_->flush();
872
303
  }
873
304
 
874
- [[nodiscard]] mcbp_context context() const
305
+ void complete(std::error_code ec)
875
306
  {
876
- return { config_, supported_features_ };
307
+ if (bool expected_state{ false }; stopped_.compare_exchange_strong(expected_state, true)) {
308
+ session_->invoke_bootstrap_handler(ec);
309
+ }
877
310
  }
878
311
 
879
- void bootstrap(utils::movable_function<void(std::error_code, topology::configuration)>&& callback,
880
- bool retry_on_bucket_not_found = false)
312
+ void auth_success()
881
313
  {
882
- retry_bootstrap_on_bucket_not_found_ = retry_on_bucket_not_found;
883
- bootstrap_callback_ = std::move(callback);
884
- bootstrap_deadline_.expires_after(origin_.options().bootstrap_timeout);
885
- bootstrap_deadline_.async_wait([self = shared_from_this()](std::error_code ec) {
886
- if (ec == asio::error::operation_aborted || self->stopped_) {
887
- return;
888
- }
889
- if (!ec) {
890
- ec = errc::common::unambiguous_timeout;
891
- }
892
- if (self->state_listener_) {
893
- self->state_listener_->report_bootstrap_error(fmt::format("{}:{}", self->bootstrap_hostname_, self->bootstrap_port_), ec);
894
- }
895
- CB_LOG_WARNING("{} unable to bootstrap in time", self->log_prefix_);
896
- if (auto h = std::move(self->bootstrap_callback_); h) {
897
- h(ec, {});
898
- }
899
- self->stop(retry_reason::do_not_retry);
900
- });
901
- initiate_bootstrap();
314
+ session_->authenticated_ = true;
315
+ if (session_->supports_feature(protocol::hello_feature::xerror)) {
316
+ protocol::client_request<protocol::get_error_map_request_body> errmap_req;
317
+ errmap_req.opaque(session_->next_opaque());
318
+ session_->write(errmap_req.data());
319
+ }
320
+ if (session_->bucket_name_) {
321
+ protocol::client_request<protocol::select_bucket_request_body> sb_req;
322
+ sb_req.opaque(session_->next_opaque());
323
+ sb_req.body().bucket_name(session_->bucket_name_.value());
324
+ session_->write(sb_req.data());
325
+ }
326
+ protocol::client_request<protocol::get_cluster_config_request_body> cfg_req;
327
+ cfg_req.opaque(session_->next_opaque());
328
+ session_->write(cfg_req.data());
329
+ session_->flush();
902
330
  }
903
331
 
904
- void initiate_bootstrap()
332
+ void handle(mcbp_message&& msg)
905
333
  {
906
- if (stopped_) {
907
- return;
908
- }
909
- bootstrapped_ = false;
910
- if (bootstrap_handler_) {
911
- last_bootstrap_error_message_ = std::move(bootstrap_handler_)->last_error_message();
912
- }
913
- bootstrap_handler_ = nullptr;
914
- state_ = diag::endpoint_state::connecting;
915
- if (stream_->is_open()) {
916
- std::string old_id = stream_->id();
917
- stream_->reopen();
918
- CB_LOG_TRACE(R"({} reopen socket connection "{}" -> "{}", host="{}", port={})",
919
- log_prefix_,
920
- old_id,
921
- stream_->id(),
922
- bootstrap_hostname_,
923
- bootstrap_port_);
924
- }
925
- if (origin_.exhausted()) {
926
- auto backoff = std::chrono::milliseconds(500);
927
- CB_LOG_DEBUG("{} reached the end of list of bootstrap nodes, waiting for {}ms before restart", log_prefix_, backoff.count());
928
- retry_backoff_.expires_after(backoff);
929
- retry_backoff_.async_wait([self = shared_from_this()](std::error_code ec) mutable {
930
- if (ec == asio::error::operation_aborted || self->stopped_) {
931
- return;
334
+ if (stopped_ || !session_) {
335
+ return;
336
+ }
337
+ Expects(protocol::is_valid_magic(msg.header.magic));
338
+ switch (auto magic = static_cast<protocol::magic>(msg.header.magic)) {
339
+ case protocol::magic::client_response:
340
+ case protocol::magic::alt_client_response:
341
+ Expects(protocol::is_valid_client_opcode(msg.header.opcode));
342
+ switch (auto status = static_cast<key_value_status_code>(msg.header.status())) {
343
+ case key_value_status_code::rate_limited_max_commands:
344
+ case key_value_status_code::rate_limited_max_connections:
345
+ case key_value_status_code::rate_limited_network_egress:
346
+ case key_value_status_code::rate_limited_network_ingress:
347
+ last_error_message_ =
348
+ fmt::format("unable to bootstrap MCBP session (bucket={}, opcode={}, status={}), "
349
+ "the user has reached rate limit",
350
+ session_->bucket_name_.value_or(""),
351
+ protocol::client_opcode(msg.header.opcode),
352
+ status);
353
+ CB_LOG_DEBUG("{} {}", session_->log_prefix_, last_error_message_);
354
+ return complete(errc::common::rate_limited);
355
+
356
+ case key_value_status_code::scope_size_limit_exceeded:
357
+ last_error_message_ =
358
+ fmt::format("unable to bootstrap MCBP session (bucket={}, opcode={}, status={}), "
359
+ "the user has reached quota limit",
360
+ session_->bucket_name_.value_or(""),
361
+ protocol::client_opcode(msg.header.opcode),
362
+ status);
363
+ CB_LOG_DEBUG("{} {}", session_->log_prefix_, last_error_message_);
364
+ return complete(errc::common::quota_limited);
365
+
366
+ default:
367
+ break;
368
+ }
369
+ switch (auto opcode = static_cast<protocol::client_opcode>(msg.header.opcode)) {
370
+ case protocol::client_opcode::hello: {
371
+ protocol::client_response<protocol::hello_response_body> resp(std::move(msg));
372
+ if (resp.status() == key_value_status_code::success) {
373
+ session_->supported_features_ = resp.body().supported_features();
374
+ CB_LOG_DEBUG("{} supported_features=[{}]",
375
+ session_->log_prefix_,
376
+ utils::join_strings_fmt(session_->supported_features_, ", "));
377
+ if (session_->origin_.credentials().uses_certificate()) {
378
+ CB_LOG_DEBUG("{} skip SASL authentication, because TLS certificate was specified",
379
+ session_->log_prefix_);
380
+ return auth_success();
932
381
  }
933
- self->origin_.restart();
934
- self->initiate_bootstrap();
935
- });
936
- return;
937
- }
938
- std::tie(bootstrap_hostname_, bootstrap_port_) = origin_.next_address();
939
- bootstrap_port_number_ = gsl::narrow_cast<std::uint16_t>(std::stoul(bootstrap_port_, nullptr, 10));
940
- bootstrap_address_ = fmt::format("{}:{}", bootstrap_hostname_, bootstrap_port_);
941
- log_prefix_ =
942
- fmt::format("[{}/{}/{}/{}] <{}>", client_id_, id_, stream_->log_prefix(), bucket_name_.value_or("-"), bootstrap_address_);
943
- CB_LOG_DEBUG("{} attempt to establish MCBP connection", log_prefix_);
944
-
945
- async_resolve(origin_.options().use_ip_protocol,
946
- resolver_,
947
- bootstrap_hostname_,
948
- bootstrap_port_,
949
- std::bind(&mcbp_session_impl::on_resolve, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
382
+ } else {
383
+ last_error_message_ =
384
+ fmt::format("unexpected message status during bootstrap: {} (opaque={})",
385
+ resp.error_message(),
386
+ resp.opaque());
387
+ CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
388
+ return complete(errc::network::handshake_failure);
389
+ }
390
+ } break;
391
+ case protocol::client_opcode::sasl_list_mechs: {
392
+ protocol::client_response<protocol::sasl_list_mechs_response_body> resp(
393
+ std::move(msg));
394
+ if (resp.status() != key_value_status_code::success) {
395
+ last_error_message_ =
396
+ fmt::format("unexpected message status during bootstrap: {} (opaque={})",
397
+ resp.error_message(),
398
+ resp.opaque());
399
+ CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
400
+ return complete(errc::common::authentication_failure);
401
+ }
402
+ } break;
403
+ case protocol::client_opcode::sasl_auth: {
404
+ protocol::client_response<protocol::sasl_auth_response_body> resp(std::move(msg));
405
+ if (resp.status() == key_value_status_code::success) {
406
+ return auth_success();
407
+ }
408
+ if (resp.status() == key_value_status_code::auth_continue) {
409
+ auto [sasl_code, sasl_payload] = sasl_.step(resp.body().value());
410
+ if (sasl_code == sasl::error::OK) {
411
+ return auth_success();
412
+ }
413
+ if (sasl_code == sasl::error::CONTINUE) {
414
+ protocol::client_request<protocol::sasl_step_request_body> req;
415
+ req.opaque(session_->next_opaque());
416
+ req.body().mechanism(sasl_.get_name());
417
+ req.body().sasl_data(sasl_payload);
418
+ session_->write_and_flush(req.data());
419
+ } else {
420
+ last_error_message_ = fmt::format(
421
+ "unable to authenticate: (sasl_code={}, opaque={})", sasl_code, resp.opaque());
422
+ CB_LOG_ERROR("{} {}", session_->log_prefix_, last_error_message_);
423
+ return complete(errc::common::authentication_failure);
424
+ }
425
+ } else {
426
+ last_error_message_ =
427
+ fmt::format("{} unexpected message status during bootstrap: {} (opaque={})",
428
+ session_->log_prefix_,
429
+ resp.error_message(),
430
+ resp.opaque());
431
+ CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
432
+ return complete(errc::common::authentication_failure);
433
+ }
434
+ } break;
435
+ case protocol::client_opcode::sasl_step: {
436
+ protocol::client_response<protocol::sasl_step_response_body> resp(std::move(msg));
437
+ if (resp.status() == key_value_status_code::success) {
438
+ return auth_success();
439
+ }
440
+ last_error_message_ =
441
+ fmt::format("unable to authenticate (opcode={}, status={}, opaque={})",
442
+ opcode,
443
+ resp.status(),
444
+ resp.opaque());
445
+ CB_LOG_ERROR("{} {}", session_->log_prefix_, last_error_message_);
446
+ return complete(errc::common::authentication_failure);
447
+ }
448
+ case protocol::client_opcode::get_error_map: {
449
+ protocol::client_response<protocol::get_error_map_response_body> resp(std::move(msg));
450
+ if (resp.status() == key_value_status_code::success) {
451
+ session_->error_map_.emplace(resp.body().errmap());
452
+ } else {
453
+ last_error_message_ =
454
+ fmt::format("unexpected message status during bootstrap: {} (opaque={}, {:n})",
455
+ resp.error_message(),
456
+ resp.opaque(),
457
+ spdlog::to_hex(resp.header()));
458
+ CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
459
+ return complete(errc::network::protocol_error);
460
+ }
461
+ } break;
462
+ case protocol::client_opcode::select_bucket: {
463
+ protocol::client_response<protocol::select_bucket_response_body> resp(std::move(msg));
464
+ if (resp.status() == key_value_status_code::success) {
465
+ CB_LOG_DEBUG("{} selected bucket: {}",
466
+ session_->log_prefix_,
467
+ session_->bucket_name_.value_or(""));
468
+ session_->bucket_selected_ = true;
469
+ } else if (resp.status() == key_value_status_code::not_found) {
470
+ last_error_message_ =
471
+ fmt::format("kv_engine node does not have configuration propagated yet "
472
+ "(opcode={}, status={}, opaque={})",
473
+ opcode,
474
+ resp.status(),
475
+ resp.opaque());
476
+ CB_LOG_DEBUG("{} {}", session_->log_prefix_, last_error_message_);
477
+ return complete(errc::network::configuration_not_available);
478
+ } else if (resp.status() == key_value_status_code::no_access) {
479
+ last_error_message_ =
480
+ fmt::format("unable to select bucket: {}, probably the bucket does not exist",
481
+ session_->bucket_name_.value_or(""));
482
+ CB_LOG_DEBUG("{} {}", session_->log_prefix_, last_error_message_);
483
+ session_->bucket_selected_ = false;
484
+ return complete(errc::common::bucket_not_found);
485
+ } else {
486
+ last_error_message_ =
487
+ fmt::format("unexpected message status during bootstrap: {} (opaque={}, {:n})",
488
+ resp.error_message(),
489
+ resp.opaque(),
490
+ spdlog::to_hex(resp.header()));
491
+ CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
492
+ return complete(errc::common::bucket_not_found);
493
+ }
494
+ } break;
495
+ case protocol::client_opcode::get_cluster_config: {
496
+ protocol::cmd_info info{ session_->connection_endpoints_.remote_address,
497
+ session_->connection_endpoints_.remote.port() };
498
+ protocol::client_response<protocol::get_cluster_config_response_body> resp(
499
+ std::move(msg), info);
500
+ if (session_->origin_.options().dump_configuration &&
501
+ resp.body().config_text().has_value()) {
502
+ CB_LOG_TRACE("{} configuration from get_cluster_config request (bootstrap, "
503
+ "size={}, endpoint=\"{}:{}\"), {}",
504
+ session_->log_prefix_,
505
+ resp.body().config_text().value().size(),
506
+ info.endpoint_address,
507
+ info.endpoint_port,
508
+ resp.body().config_text().value());
509
+ }
510
+ if (resp.status() == key_value_status_code::success) {
511
+ // MB-60405 fixes this for 7.6.2, but for earlier versions we need to protect
512
+ // against using a config that has an empty vbucket map. Ideally we don't timeout
513
+ // if we retry here, but a timeout would be more acceptable than a crash and if we
514
+ // do timeout, we have a clear indication of the problem (i.e. it is a server bug
515
+ // and we cannot use a config w/ an empty vbucket map).
516
+ if (resp.body().config().vbmap && resp.body().config().vbmap->size() == 0) {
517
+ CB_LOG_WARNING("{} received a configuration with an empty vbucket map, retrying",
518
+ session_->log_prefix_);
519
+ return complete(errc::network::configuration_not_available);
520
+ }
521
+ session_->update_configuration(resp.body().config());
522
+ complete({});
523
+ } else if (resp.status() == key_value_status_code::not_found) {
524
+ last_error_message_ =
525
+ fmt::format("kv_engine node does not have configuration propagated yet "
526
+ "(opcode={}, status={}, opaque={})",
527
+ opcode,
528
+ resp.status(),
529
+ resp.opaque());
530
+ CB_LOG_DEBUG("{} {}", session_->log_prefix_, last_error_message_);
531
+ return complete(errc::network::configuration_not_available);
532
+ } else if (resp.status() == key_value_status_code::no_bucket &&
533
+ !session_->bucket_name_) {
534
+ // bucket-less session, but the server wants bucket
535
+ session_->supports_gcccp_ = false;
536
+ CB_LOG_WARNING("{} this server does not support GCCCP, open bucket before making "
537
+ "any cluster-level command",
538
+ session_->log_prefix_);
539
+ session_->update_configuration(
540
+ topology::make_blank_configuration(session_->connection_endpoints_.remote_address,
541
+ session_->connection_endpoints_.remote.port(),
542
+ 0));
543
+ complete({});
544
+ } else {
545
+ last_error_message_ =
546
+ fmt::format("unexpected message status during bootstrap: {} (opaque={}, {:n})",
547
+ resp.error_message(),
548
+ resp.opaque(),
549
+ spdlog::to_hex(resp.header()));
550
+ CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
551
+ return complete(errc::network::protocol_error);
552
+ }
553
+ } break;
554
+ default:
555
+ last_error_message_ = fmt::format("unexpected message during bootstrap: {}", opcode);
556
+ CB_LOG_WARNING("{} {}", session_->log_prefix_, last_error_message_);
557
+ return complete(errc::network::protocol_error);
558
+ }
559
+ break;
560
+ case protocol::magic::server_request:
561
+ Expects(protocol::is_valid_server_request_opcode(msg.header.opcode));
562
+ switch (static_cast<protocol::server_opcode>(msg.header.opcode)) {
563
+ case protocol::server_opcode::cluster_map_change_notification: {
564
+ protocol::cmd_info info{ session_->bootstrap_hostname_,
565
+ session_->bootstrap_port_number_ };
566
+ protocol::server_request<protocol::cluster_map_change_notification_request_body> req(
567
+ std::move(msg), info);
568
+ if (session_->origin_.options().dump_configuration &&
569
+ req.body().config_text().has_value()) {
570
+ CB_LOG_TRACE("{} configuration from cluster_map_change_notification request "
571
+ "(size={}, endpoint=\"{}:{}\"), {}",
572
+ session_->log_prefix_,
573
+ req.body().config_text().value().size(),
574
+ info.endpoint_address,
575
+ info.endpoint_port,
576
+ req.body().config_text().value());
577
+ }
578
+ std::optional<topology::configuration> config = req.body().config();
579
+ if (session_ && config.has_value()) {
580
+ if ((!config->bucket.has_value() && req.body().bucket().empty()) ||
581
+ (session_->bucket_name_.has_value() && !req.body().bucket().empty() &&
582
+ session_->bucket_name_.value() == req.body().bucket())) {
583
+ session_->update_configuration(std::move(config.value()));
584
+ }
585
+ }
586
+ } break;
587
+ default:
588
+ CB_LOG_WARNING("{} unexpected server request: opcode={:x}, opaque={}{:a}{:a}",
589
+ session_->log_prefix_,
590
+ msg.header.opcode,
591
+ utils::byte_swap(msg.header.opaque),
592
+ spdlog::to_hex(msg.header_data()),
593
+ spdlog::to_hex(msg.body));
594
+ }
595
+ break;
596
+ case protocol::magic::client_request:
597
+ case protocol::magic::alt_client_request:
598
+ case protocol::magic::server_response:
599
+ CB_LOG_WARNING("{} unexpected magic: {} (opcode={:x}, opaque={}){:a}{:a}",
600
+ session_->log_prefix_,
601
+ magic,
602
+ msg.header.opcode,
603
+ utils::byte_swap(msg.header.opaque),
604
+ spdlog::to_hex(msg.header_data()),
605
+ spdlog::to_hex(msg.body));
606
+ break;
607
+ }
950
608
  }
609
+ };
610
+
611
+ class message_handler : public std::enable_shared_from_this<message_handler>
612
+ {
613
+ private:
614
+ std::shared_ptr<mcbp_session_impl> session_;
615
+ std::atomic_bool stopped_{ false };
951
616
 
952
- [[nodiscard]] const std::string& id() const
617
+ public:
618
+ explicit message_handler(std::shared_ptr<mcbp_session_impl> session)
619
+ : session_(std::move(session))
953
620
  {
954
- return id_;
955
621
  }
956
622
 
957
- [[nodiscard]] bool is_stopped() const
623
+ ~message_handler()
958
624
  {
959
- return stopped_;
625
+ stop();
960
626
  }
961
627
 
962
- [[nodiscard]] bool is_bootstrapped() const
628
+ void start()
963
629
  {
964
- return bootstrapped_;
965
630
  }
966
631
 
967
- void on_stop(utils::movable_function<void()> handler)
632
+ void stop()
968
633
  {
969
- on_stop_handler_ = std::move(handler);
970
634
  }
971
635
 
972
- void stop(retry_reason reason)
636
+ void handle(mcbp_message&& msg)
973
637
  {
974
- if (stopped_) {
975
- return;
976
- }
977
- state_ = diag::endpoint_state::disconnecting;
978
- CB_LOG_DEBUG("{} stop MCBP connection, reason={}", log_prefix_, reason);
979
- stopped_ = true;
980
- bootstrap_deadline_.cancel();
981
- connection_deadline_.cancel();
982
- retry_backoff_.cancel();
983
- ping_deadline_.cancel();
984
- resolver_.cancel();
985
- stream_->close([](std::error_code) {});
986
- if (auto h = std::move(bootstrap_handler_); h) {
987
- h->stop();
988
- }
989
- if (auto h = std::move(handler_); h) {
990
- h->stop();
991
- }
992
- std::error_code ec = errc::common::request_canceled;
993
- if (!bootstrapped_) {
994
- if (auto h = std::move(bootstrap_callback_); h) {
995
- h(ec, {});
996
- }
997
- }
998
- {
999
- std::scoped_lock lock(command_handlers_mutex_);
1000
- for (auto& [opaque, handler] : command_handlers_) {
1001
- if (handler) {
1002
- CB_LOG_DEBUG("{} MCBP cancel operation during session close, opaque={}, ec={}", log_prefix_, opaque, ec.message());
1003
- auto fun = std::move(handler);
1004
- fun(ec, reason, {}, {});
638
+ if (stopped_ || !session_) {
639
+ return;
640
+ }
641
+ Expects(protocol::is_valid_magic(msg.header.magic));
642
+ switch (auto magic = static_cast<protocol::magic>(msg.header.magic)) {
643
+ case protocol::magic::client_response:
644
+ case protocol::magic::alt_client_response:
645
+ Expects(protocol::is_valid_client_opcode(msg.header.opcode));
646
+ switch (auto opcode = static_cast<protocol::client_opcode>(msg.header.opcode)) {
647
+ case protocol::client_opcode::get_cluster_config: {
648
+ protocol::cmd_info info{ session_->bootstrap_hostname_,
649
+ session_->bootstrap_port_number_ };
650
+ protocol::client_response<protocol::get_cluster_config_response_body> resp(
651
+ std::move(msg), info);
652
+ if (session_->origin_.options().dump_configuration &&
653
+ resp.body().config_text().has_value()) {
654
+ CB_LOG_TRACE("{} configuration from get_cluster_config response (size={}, "
655
+ "endpoint=\"{}:{}\"), {}",
656
+ session_->log_prefix_,
657
+ resp.body().config_text().value().size(),
658
+ info.endpoint_address,
659
+ info.endpoint_port,
660
+ resp.body().config_text().value());
661
+ }
662
+ if (resp.status() == key_value_status_code::success) {
663
+ if (session_) {
664
+ session_->update_configuration(resp.body().config());
1005
665
  }
1006
- }
1007
- command_handlers_.clear();
1008
- }
1009
- {
1010
- std::scoped_lock lock(operations_mutex_);
1011
- auto operations = std::move(operations_);
1012
- for (auto& [opaque, operation] : operations) {
1013
- auto& [request, handler] = operation;
1014
- if (handler) {
1015
- CB_LOG_DEBUG("{} MCBP cancel operation during session close, opaque={}, ec={}", log_prefix_, opaque, ec.message());
1016
- handler->handle_response(std::move(request), {}, reason, {}, {});
666
+ } else {
667
+ CB_LOG_WARNING("{} unexpected message status: {} (opaque={})",
668
+ session_->log_prefix_,
669
+ resp.error_message(),
670
+ resp.opaque());
671
+ }
672
+ } break;
673
+ case protocol::client_opcode::noop:
674
+ case protocol::client_opcode::get_collections_manifest:
675
+ case protocol::client_opcode::get_collection_id:
676
+ case protocol::client_opcode::get:
677
+ case protocol::client_opcode::get_and_lock:
678
+ case protocol::client_opcode::get_and_touch:
679
+ case protocol::client_opcode::get_meta:
680
+ case protocol::client_opcode::get_replica:
681
+ case protocol::client_opcode::touch:
682
+ case protocol::client_opcode::insert:
683
+ case protocol::client_opcode::replace:
684
+ case protocol::client_opcode::upsert:
685
+ case protocol::client_opcode::append:
686
+ case protocol::client_opcode::prepend:
687
+ case protocol::client_opcode::remove:
688
+ case protocol::client_opcode::observe_seqno:
689
+ case protocol::client_opcode::unlock:
690
+ case protocol::client_opcode::increment:
691
+ case protocol::client_opcode::range_scan_create:
692
+ case protocol::client_opcode::range_scan_continue:
693
+ case protocol::client_opcode::range_scan_cancel:
694
+ case protocol::client_opcode::decrement:
695
+ case protocol::client_opcode::subdoc_multi_lookup:
696
+ case protocol::client_opcode::subdoc_multi_mutation: {
697
+ std::uint16_t status = utils::byte_swap(msg.header.specific);
698
+ if (status == static_cast<std::uint16_t>(key_value_status_code::not_my_vbucket)) {
699
+ session_->handle_not_my_vbucket(msg);
700
+ }
701
+
702
+ std::uint32_t opaque = utils::byte_swap(msg.header.opaque);
703
+ if (session_->handle_request(opcode, status, opaque, std::move(msg))) {
704
+ CB_LOG_TRACE("{} MCBP invoked operation handler: opcode={}, opaque={}, status={}",
705
+ session_->log_prefix_,
706
+ opcode,
707
+ opaque,
708
+ protocol::status_to_string(status));
709
+ } else {
710
+ CB_LOG_DEBUG("{} unexpected orphan response: opcode={}, opaque={}, status={}",
711
+ session_->log_prefix_,
712
+ opcode,
713
+ opaque,
714
+ protocol::status_to_string(status));
715
+ }
716
+ } break;
717
+ default:
718
+ CB_LOG_WARNING("{} unexpected client response: opcode={}, opaque={}{:a}{:a})",
719
+ session_->log_prefix_,
720
+ opcode,
721
+ msg.header.opaque,
722
+ spdlog::to_hex(msg.header_data()),
723
+ spdlog::to_hex(msg.body));
724
+ }
725
+ break;
726
+ case protocol::magic::server_request:
727
+ Expects(protocol::is_valid_server_request_opcode(msg.header.opcode));
728
+ switch (static_cast<protocol::server_opcode>(msg.header.opcode)) {
729
+ case protocol::server_opcode::cluster_map_change_notification: {
730
+ protocol::cmd_info info{ session_->bootstrap_hostname_,
731
+ session_->bootstrap_port_number_ };
732
+ protocol::server_request<protocol::cluster_map_change_notification_request_body> req(
733
+ std::move(msg), info);
734
+ if (session_->origin_.options().dump_configuration &&
735
+ req.body().config_text().has_value()) {
736
+ CB_LOG_TRACE("{} configuration from cluster_map_change_notification request "
737
+ "(size={}, endpoint=\"{}:{}\"), {}",
738
+ session_->log_prefix_,
739
+ req.body().config_text().value().size(),
740
+ info.endpoint_address,
741
+ info.endpoint_port,
742
+ req.body().config_text().value());
743
+ }
744
+ std::optional<topology::configuration> config = req.body().config();
745
+ if (session_ && config.has_value()) {
746
+ if ((!config->bucket.has_value() && req.body().bucket().empty()) ||
747
+ (session_->bucket_name_.has_value() && !req.body().bucket().empty() &&
748
+ session_->bucket_name_.value() == req.body().bucket())) {
749
+ session_->update_configuration(std::move(config.value()));
1017
750
  }
1018
- }
1019
- operations_.clear();
1020
- }
1021
- config_listeners_.clear();
1022
- state_ = diag::endpoint_state::disconnected;
1023
- if (auto on_stop = std::move(on_stop_handler_); on_stop) {
1024
- on_stop();
1025
- }
751
+ }
752
+ } break;
753
+ default:
754
+ CB_LOG_WARNING("{} unexpected server request: opcode={:x}, opaque={}{:a}{:a}",
755
+ session_->log_prefix_,
756
+ msg.header.opcode,
757
+ msg.header.opaque,
758
+ spdlog::to_hex(msg.header_data()),
759
+ spdlog::to_hex(msg.body));
760
+ }
761
+ break;
762
+ case protocol::magic::client_request:
763
+ case protocol::magic::alt_client_request:
764
+ case protocol::magic::server_response:
765
+ CB_LOG_WARNING("{} unexpected magic: {} (opcode={:x}, opaque={}){:a}{:a}",
766
+ session_->log_prefix_,
767
+ magic,
768
+ msg.header.opcode,
769
+ msg.header.opaque,
770
+ spdlog::to_hex(msg.header_data()),
771
+ spdlog::to_hex(msg.body));
772
+ break;
773
+ }
1026
774
  }
1027
-
1028
- void write(std::vector<std::byte>&& buf)
1029
- {
1030
- if (stopped_) {
1031
- return;
1032
- }
1033
- CB_LOG_TRACE("{} MCBP send {}", log_prefix_, mcbp_header_view(buf));
1034
- std::scoped_lock lock(output_buffer_mutex_);
1035
- output_buffer_.emplace_back(std::move(buf));
775
+ };
776
+
777
+ public:
778
+ mcbp_session_impl() = delete;
779
+ mcbp_session_impl(std::string_view client_id,
780
+ asio::io_context& ctx,
781
+ couchbase::core::origin origin,
782
+ std::shared_ptr<impl::bootstrap_state_listener> state_listener,
783
+ std::optional<std::string> bucket_name = {},
784
+ std::vector<protocol::hello_feature> known_features = {})
785
+ : client_id_(client_id)
786
+ , ctx_(ctx)
787
+ , resolver_(ctx_)
788
+ , stream_(std::make_unique<plain_stream_impl>(ctx_))
789
+ , bootstrap_deadline_(ctx_)
790
+ , connection_deadline_(ctx_)
791
+ , retry_backoff_(ctx_)
792
+ , ping_deadline_(ctx_)
793
+ , origin_{ std::move(origin) }
794
+ , bucket_name_{ std::move(bucket_name) }
795
+ , supported_features_{ std::move(known_features) }
796
+ , is_tls_{ false }
797
+ , state_listener_{ std::move(state_listener) }
798
+ , codec_{ { supported_features_.begin(), supported_features_.end() } }
799
+ {
800
+ log_prefix_ = fmt::format(
801
+ "[{}/{}/{}/{}]", client_id_, id_, stream_->log_prefix(), bucket_name_.value_or("-"));
802
+ }
803
+
804
+ mcbp_session_impl(std::string_view client_id,
805
+ asio::io_context& ctx,
806
+ asio::ssl::context& tls,
807
+ couchbase::core::origin origin,
808
+ std::shared_ptr<impl::bootstrap_state_listener> state_listener,
809
+ std::optional<std::string> bucket_name = {},
810
+ std::vector<protocol::hello_feature> known_features = {})
811
+ : client_id_(client_id)
812
+ , ctx_(ctx)
813
+ , resolver_(ctx_)
814
+ , stream_(std::make_unique<tls_stream_impl>(ctx_, tls))
815
+ , bootstrap_deadline_(ctx_)
816
+ , connection_deadline_(ctx_)
817
+ , retry_backoff_(ctx_)
818
+ , ping_deadline_(ctx_)
819
+ , origin_(std::move(origin))
820
+ , bucket_name_(std::move(bucket_name))
821
+ , supported_features_(std::move(known_features))
822
+ , is_tls_{ true }
823
+ , state_listener_{ std::move(state_listener) }
824
+ , codec_{ { supported_features_.begin(), supported_features_.end() } }
825
+ {
826
+ log_prefix_ = fmt::format(
827
+ "[{}/{}/{}/{}]", client_id_, id_, stream_->log_prefix(), bucket_name_.value_or("-"));
828
+ }
829
+
830
+ ~mcbp_session_impl()
831
+ {
832
+ CB_LOG_DEBUG("{} destroy MCBP connection", log_prefix_);
833
+ stop(retry_reason::do_not_retry);
834
+ }
835
+
836
+ [[nodiscard]] auto log_prefix() const -> const std::string&
837
+ {
838
+ return log_prefix_;
839
+ }
840
+
841
+ auto remote_address() const -> std::string
842
+ {
843
+ return connection_endpoints_.remote_address_with_port;
844
+ }
845
+
846
+ auto local_address() const -> std::string
847
+ {
848
+ return connection_endpoints_.local_address_with_port;
849
+ }
850
+
851
+ [[nodiscard]] auto diag_info() const -> diag::endpoint_diag_info
852
+ {
853
+ return { service_type::key_value,
854
+ id_,
855
+ last_active_.time_since_epoch().count() == 0
856
+ ? std::nullopt
857
+ : std::make_optional(std::chrono::duration_cast<std::chrono::microseconds>(
858
+ std::chrono::steady_clock::now() - last_active_)),
859
+ remote_address(),
860
+ local_address(),
861
+ state_,
862
+ bucket_name_ };
863
+ }
864
+
865
+ void ping(std::shared_ptr<diag::ping_reporter> handler,
866
+ std::optional<std::chrono::milliseconds> timeout)
867
+ {
868
+ if (!bootstrapped_) {
869
+ handler->report({
870
+ service_type::key_value,
871
+ id_,
872
+ std::chrono::microseconds(0),
873
+ remote_address(),
874
+ local_address(),
875
+ diag::ping_state::error,
876
+ bucket_name_,
877
+ last_bootstrap_error_message_.has_value() ? last_bootstrap_error_message_.value()
878
+ : "Bootstrap incomplete, cannot perform ping.",
879
+ });
880
+ return;
1036
881
  }
1037
-
1038
- void flush()
1039
- {
1040
- if (stopped_) {
1041
- return;
1042
- }
1043
- asio::post(asio::bind_executor(ctx_, [self = shared_from_this()]() { self->do_write(); }));
882
+ protocol::client_request<protocol::mcbp_noop_request_body> req;
883
+ req.opaque(next_opaque());
884
+ write_and_subscribe(
885
+ req.opaque(),
886
+ req.data(false),
887
+ [start = std::chrono::steady_clock::now(), self = shared_from_this(), handler](
888
+ std::error_code ec,
889
+ retry_reason reason,
890
+ io::mcbp_message&& /* msg */,
891
+ std::optional<key_value_error_map_info> /* error_info */) {
892
+ diag::ping_state state = diag::ping_state::ok;
893
+ std::optional<std::string> error{};
894
+ if (ec) {
895
+ if (ec == errc::common::unambiguous_timeout || ec == errc::common::ambiguous_timeout) {
896
+ state = diag::ping_state::timeout;
897
+ } else {
898
+ state = diag::ping_state::error;
899
+ }
900
+ error.emplace(
901
+ fmt::format("code={}, message={}, reason={}", ec.value(), ec.message(), reason));
902
+ }
903
+ handler->report({
904
+ service_type::key_value,
905
+ self->id_,
906
+ std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() -
907
+ start),
908
+ self->remote_address(),
909
+ self->local_address(),
910
+ state,
911
+ self->bucket_name_,
912
+ error,
913
+ });
914
+ });
915
+ ping_deadline_.expires_after(timeout.value_or(origin_.options().key_value_timeout));
916
+ ping_deadline_.async_wait(
917
+ [self = this->shared_from_this(), opaque = req.opaque()](std::error_code ec) {
918
+ if (ec == asio::error::operation_aborted) {
919
+ return;
920
+ }
921
+ static_cast<void>(
922
+ self->cancel(opaque, errc::common::unambiguous_timeout, retry_reason::do_not_retry));
923
+ });
924
+ }
925
+
926
+ [[nodiscard]] auto context() const -> mcbp_context
927
+ {
928
+ return { config_, supported_features_ };
929
+ }
930
+
931
+ void bootstrap(utils::movable_function<void(std::error_code, topology::configuration)>&& callback,
932
+ bool retry_on_bucket_not_found = false)
933
+ {
934
+ retry_bootstrap_on_bucket_not_found_ = retry_on_bucket_not_found;
935
+ bootstrap_callback_ = std::move(callback);
936
+ bootstrap_deadline_.expires_after(origin_.options().bootstrap_timeout);
937
+ bootstrap_deadline_.async_wait([self = shared_from_this()](std::error_code ec) {
938
+ if (ec == asio::error::operation_aborted || self->stopped_) {
939
+ return;
940
+ }
941
+ if (!ec) {
942
+ ec = errc::common::unambiguous_timeout;
943
+ }
944
+ if (self->state_listener_) {
945
+ self->state_listener_->report_bootstrap_error(
946
+ fmt::format("{}:{}", self->bootstrap_hostname_, self->bootstrap_port_), ec);
947
+ }
948
+ CB_LOG_WARNING("{} unable to bootstrap in time", self->log_prefix_);
949
+ if (auto h = std::move(self->bootstrap_callback_); h) {
950
+ h(ec, {});
951
+ }
952
+ self->stop(retry_reason::do_not_retry);
953
+ });
954
+ initiate_bootstrap();
955
+ }
956
+
957
+ void initiate_bootstrap()
958
+ {
959
+ if (stopped_) {
960
+ return;
1044
961
  }
1045
-
1046
- void write_and_flush(std::vector<std::byte>&& buf)
1047
- {
1048
- if (stopped_) {
1049
- return;
1050
- }
1051
- write(std::move(buf));
1052
- flush();
962
+ bootstrapped_ = false;
963
+ if (bootstrap_handler_) {
964
+ last_bootstrap_error_message_ = std::move(bootstrap_handler_)->last_error_message();
1053
965
  }
1054
-
1055
- void remove_request(std::shared_ptr<mcbp::queue_request> request) override
1056
- {
1057
- std::scoped_lock lock(operations_mutex_);
1058
- if (auto iter = operations_.find(request->opaque_); iter != operations_.end()) {
1059
- operations_.erase(iter);
1060
- }
966
+ bootstrap_handler_ = nullptr;
967
+ state_ = diag::endpoint_state::connecting;
968
+ if (stream_->is_open()) {
969
+ std::string old_id = stream_->id();
970
+ stream_->reopen();
971
+ CB_LOG_TRACE(R"({} reopen socket connection "{}" -> "{}", host="{}", port={})",
972
+ log_prefix_,
973
+ old_id,
974
+ stream_->id(),
975
+ bootstrap_hostname_,
976
+ bootstrap_port_);
1061
977
  }
1062
-
1063
- void enqueue_request(std::uint32_t opaque, std::shared_ptr<mcbp::queue_request> request, std::shared_ptr<response_handler> handler)
1064
- {
1065
- std::scoped_lock lock(operations_mutex_);
1066
- request->waiting_in_ = this;
1067
- operations_.try_emplace(opaque, std::move(request), std::move(handler));
978
+ if (origin_.exhausted()) {
979
+ auto backoff = std::chrono::milliseconds(500);
980
+ CB_LOG_DEBUG("{} reached the end of list of bootstrap nodes, waiting for {}ms before restart",
981
+ log_prefix_,
982
+ backoff.count());
983
+ retry_backoff_.expires_after(backoff);
984
+ retry_backoff_.async_wait([self = shared_from_this()](std::error_code ec) mutable {
985
+ if (ec == asio::error::operation_aborted || self->stopped_) {
986
+ return;
987
+ }
988
+ self->origin_.restart();
989
+ self->initiate_bootstrap();
990
+ });
991
+ return;
1068
992
  }
1069
-
1070
- auto handle_request(protocol::client_opcode opcode, std::uint16_t status, std::uint32_t opaque, mcbp_message&& msg) -> bool
1071
- {
1072
- // handle request old style
1073
- command_handler fun{};
1074
- {
1075
- std::scoped_lock lock(command_handlers_mutex_);
1076
- if (auto handler = command_handlers_.find(opaque); handler != command_handlers_.end() && handler->second) {
1077
- fun = std::move(handler->second);
1078
- command_handlers_.erase(handler);
1079
- }
1080
- }
1081
-
1082
- auto reason = status == static_cast<std::uint16_t>(key_value_status_code::not_my_vbucket) ? retry_reason::key_value_not_my_vbucket
1083
- : retry_reason::do_not_retry;
1084
- if (fun) {
1085
- fun(protocol::map_status_code(opcode, status), reason, std::move(msg), decode_error_code(status));
1086
- return true;
1087
- }
1088
-
1089
- // handle request new style
1090
- std::shared_ptr<mcbp::queue_request> request{};
1091
- std::shared_ptr<response_handler> handler{};
1092
- std::scoped_lock lock(operations_mutex_);
1093
- {
1094
- if (auto pair = operations_.find(opaque); pair != operations_.end() && pair->second.first) {
1095
- request = pair->second.first;
1096
- handler = pair->second.second;
1097
- if (!request->persistent_) {
1098
- operations_.erase(pair);
1099
- }
1100
- }
1101
- }
1102
- if (request) {
1103
- handler->handle_response(
1104
- std::move(request), protocol::map_status_code(opcode, status), reason, std::move(msg), decode_error_code(status));
1105
- return true;
1106
- }
1107
- return false;
993
+ std::tie(bootstrap_hostname_, bootstrap_port_) = origin_.next_address();
994
+ bootstrap_port_number_ =
995
+ gsl::narrow_cast<std::uint16_t>(std::stoul(bootstrap_port_, nullptr, 10));
996
+ bootstrap_address_ = fmt::format("{}:{}", bootstrap_hostname_, bootstrap_port_);
997
+ log_prefix_ = fmt::format("[{}/{}/{}/{}] <{}>",
998
+ client_id_,
999
+ id_,
1000
+ stream_->log_prefix(),
1001
+ bucket_name_.value_or("-"),
1002
+ bootstrap_address_);
1003
+ CB_LOG_DEBUG("{} attempt to establish MCBP connection", log_prefix_);
1004
+
1005
+ async_resolve(origin_.options().use_ip_protocol,
1006
+ resolver_,
1007
+ bootstrap_hostname_,
1008
+ bootstrap_port_,
1009
+ std::bind(&mcbp_session_impl::on_resolve,
1010
+ shared_from_this(),
1011
+ std::placeholders::_1,
1012
+ std::placeholders::_2));
1013
+ }
1014
+
1015
+ [[nodiscard]] auto id() const -> const std::string&
1016
+ {
1017
+ return id_;
1018
+ }
1019
+
1020
+ [[nodiscard]] auto is_stopped() const -> bool
1021
+ {
1022
+ return stopped_;
1023
+ }
1024
+
1025
+ [[nodiscard]] auto is_bootstrapped() const -> bool
1026
+ {
1027
+ return bootstrapped_;
1028
+ }
1029
+
1030
+ void on_stop(utils::movable_function<void()> handler)
1031
+ {
1032
+ on_stop_handler_ = std::move(handler);
1033
+ }
1034
+
1035
+ void stop(retry_reason reason)
1036
+ {
1037
+ if (stopped_) {
1038
+ return;
1108
1039
  }
1109
-
1110
- void write_and_subscribe(std::shared_ptr<mcbp::queue_request> request, std::shared_ptr<response_handler> handler)
1111
- {
1112
- auto opaque = request->opaque_;
1113
- auto data = codec_.encode_packet(*request);
1114
- if (!data) {
1115
- CB_LOG_DEBUG("unable to encode packet. opaque={}, ec={}", opaque, data.error().message());
1116
- request->try_callback({}, data.error());
1117
- return;
1118
- }
1119
-
1120
- if (stopped_) {
1121
- CB_LOG_WARNING("cancel operation while trying to write to closed mcbp session, opaque={}", opaque);
1122
- handler->handle_response(request, errc::common::request_canceled, retry_reason::socket_closed_while_in_flight, {}, {});
1123
- return;
1124
- }
1125
- enqueue_request(opaque, std::move(request), std::move(handler));
1126
- if (bootstrapped_ && stream_->is_open()) {
1127
- write_and_flush(std::move(data.value()));
1128
- } else {
1129
- CB_LOG_DEBUG("{} the stream is not ready yet, put the message into pending buffer, opaque={}", log_prefix_, opaque);
1130
- std::scoped_lock lock(pending_buffer_mutex_);
1131
- if (bootstrapped_ && stream_->is_open()) {
1132
- write_and_flush(std::move(data.value()));
1133
- } else {
1134
- pending_buffer_.emplace_back(data.value());
1135
- }
1136
- }
1040
+ state_ = diag::endpoint_state::disconnecting;
1041
+ CB_LOG_DEBUG("{} stop MCBP connection, reason={}", log_prefix_, reason);
1042
+ stopped_ = true;
1043
+ bootstrap_deadline_.cancel();
1044
+ connection_deadline_.cancel();
1045
+ retry_backoff_.cancel();
1046
+ ping_deadline_.cancel();
1047
+ resolver_.cancel();
1048
+ stream_->close([](std::error_code) {
1049
+ });
1050
+ if (auto h = std::move(bootstrap_handler_); h) {
1051
+ h->stop();
1137
1052
  }
1138
-
1139
- void write_and_subscribe(std::uint32_t opaque, std::vector<std::byte>&& data, command_handler&& handler)
1140
- {
1141
- if (stopped_) {
1142
- CB_LOG_WARNING("{} MCBP cancel operation, while trying to write to closed session, opaque={}", log_prefix_, opaque);
1143
- handler(errc::common::request_canceled, retry_reason::socket_closed_while_in_flight, {}, {});
1144
- return;
1145
- }
1146
- {
1147
- std::scoped_lock lock(command_handlers_mutex_);
1148
- command_handlers_.try_emplace(opaque, std::move(handler));
1149
- }
1150
- if (bootstrapped_ && stream_->is_open()) {
1151
- write_and_flush(std::move(data));
1152
- } else {
1153
- CB_LOG_DEBUG("{} the stream is not ready yet, put the message into pending buffer, opaque={}", log_prefix_, opaque);
1154
- std::scoped_lock lock(pending_buffer_mutex_);
1155
- if (bootstrapped_ && stream_->is_open()) {
1156
- write_and_flush(std::move(data));
1157
- } else {
1158
- pending_buffer_.emplace_back(data);
1159
- }
1160
- }
1053
+ if (auto h = std::move(handler_); h) {
1054
+ h->stop();
1161
1055
  }
1162
-
1163
- [[nodiscard]] bool cancel(std::uint32_t opaque, std::error_code ec, retry_reason reason)
1164
- {
1165
- if (stopped_) {
1166
- return false;
1167
- }
1168
- command_handlers_mutex_.lock();
1169
- if (auto handler = command_handlers_.find(opaque); handler != command_handlers_.end()) {
1170
- CB_LOG_DEBUG("{} MCBP cancel operation, opaque={}, ec={} ({})", log_prefix_, opaque, ec.value(), ec.message());
1171
- if (handler->second) {
1172
- auto fun = std::move(handler->second);
1173
- command_handlers_.erase(handler);
1174
- command_handlers_mutex_.unlock();
1175
- fun(ec, reason, {}, {});
1176
- return true;
1177
- }
1178
- }
1179
- command_handlers_mutex_.unlock();
1180
- return false;
1056
+ std::error_code ec = errc::common::request_canceled;
1057
+ if (!bootstrapped_) {
1058
+ if (auto h = std::move(bootstrap_callback_); h) {
1059
+ h(ec, {});
1060
+ }
1181
1061
  }
1182
-
1183
- [[nodiscard]] bool supports_feature(protocol::hello_feature feature)
1184
1062
  {
1185
- return std::find(supported_features_.begin(), supported_features_.end(), feature) != supported_features_.end();
1063
+ std::scoped_lock lock(command_handlers_mutex_);
1064
+ for (auto& [opaque, handler] : command_handlers_) {
1065
+ if (handler) {
1066
+ CB_LOG_DEBUG("{} MCBP cancel operation during session close, opaque={}, ec={}",
1067
+ log_prefix_,
1068
+ opaque,
1069
+ ec.message());
1070
+ auto fun = std::move(handler);
1071
+ fun(ec, reason, {}, {});
1072
+ }
1073
+ }
1074
+ command_handlers_.clear();
1186
1075
  }
1187
-
1188
- [[nodiscard]] std::vector<protocol::hello_feature> supported_features() const
1189
1076
  {
1190
- return supported_features_;
1077
+ std::scoped_lock lock(operations_mutex_);
1078
+ auto operations = std::move(operations_);
1079
+ for (auto& [opaque, operation] : operations) {
1080
+ auto& [request, handler] = operation;
1081
+ if (handler) {
1082
+ CB_LOG_DEBUG("{} MCBP cancel operation during session close, opaque={}, ec={}",
1083
+ log_prefix_,
1084
+ opaque,
1085
+ ec.message());
1086
+ handler->handle_response(std::move(request), {}, reason, {}, {});
1087
+ }
1088
+ }
1089
+ operations_.clear();
1191
1090
  }
1192
-
1193
- [[nodiscard]] bool supports_gcccp() const
1194
- {
1195
- return supports_gcccp_;
1091
+ config_listeners_.clear();
1092
+ state_ = diag::endpoint_state::disconnected;
1093
+ if (auto on_stop = std::move(on_stop_handler_); on_stop) {
1094
+ on_stop();
1196
1095
  }
1096
+ }
1197
1097
 
1198
- std::optional<topology::configuration> config() const
1199
- {
1200
- return config_;
1098
+ void write(std::vector<std::byte>&& buf)
1099
+ {
1100
+ if (stopped_) {
1101
+ return;
1201
1102
  }
1202
-
1203
- [[nodiscard]] bool has_config() const
1204
- {
1205
- return configured_;
1103
+ CB_LOG_TRACE("{} MCBP send {}", log_prefix_, mcbp_header_view(buf));
1104
+ std::scoped_lock lock(output_buffer_mutex_);
1105
+ output_buffer_.emplace_back(std::move(buf));
1106
+ }
1107
+
1108
+ void flush()
1109
+ {
1110
+ if (stopped_) {
1111
+ return;
1206
1112
  }
1207
-
1208
- [[nodiscard]] topology::configuration config()
1209
- {
1210
- std::scoped_lock lock(config_mutex_);
1211
- return config_.value();
1113
+ asio::post(asio::bind_executor(ctx_, [self = shared_from_this()]() {
1114
+ self->do_write();
1115
+ }));
1116
+ }
1117
+
1118
+ void write_and_flush(std::vector<std::byte>&& buf)
1119
+ {
1120
+ if (stopped_) {
1121
+ return;
1212
1122
  }
1213
-
1214
- [[nodiscard]] std::size_t index() const
1215
- {
1216
- std::scoped_lock lock(config_mutex_);
1217
- Expects(config_.has_value());
1218
- return config_->index_for_this_node();
1123
+ write(std::move(buf));
1124
+ flush();
1125
+ }
1126
+
1127
+ void remove_request(std::shared_ptr<mcbp::queue_request> request) override
1128
+ {
1129
+ std::scoped_lock lock(operations_mutex_);
1130
+ if (auto iter = operations_.find(request->opaque_); iter != operations_.end()) {
1131
+ operations_.erase(iter);
1219
1132
  }
1220
-
1221
- [[nodiscard]] const std::string& bootstrap_address() const
1133
+ }
1134
+
1135
+ void enqueue_request(std::uint32_t opaque,
1136
+ std::shared_ptr<mcbp::queue_request> request,
1137
+ std::shared_ptr<response_handler> handler)
1138
+ {
1139
+ std::scoped_lock lock(operations_mutex_);
1140
+ request->waiting_in_ = this;
1141
+ operations_.try_emplace(opaque, std::move(request), std::move(handler));
1142
+ }
1143
+
1144
+ auto handle_request(protocol::client_opcode opcode,
1145
+ std::uint16_t status,
1146
+ std::uint32_t opaque,
1147
+ mcbp_message&& msg) -> bool
1148
+ {
1149
+ // handle request old style
1150
+ command_handler fun{};
1222
1151
  {
1223
- return bootstrap_address_;
1152
+ std::scoped_lock lock(command_handlers_mutex_);
1153
+ if (auto handler = command_handlers_.find(opaque);
1154
+ handler != command_handlers_.end() && handler->second) {
1155
+ fun = std::move(handler->second);
1156
+ command_handlers_.erase(handler);
1157
+ }
1224
1158
  }
1225
1159
 
1226
- [[nodiscard]] const std::string& bootstrap_hostname() const
1227
- {
1228
- return bootstrap_hostname_;
1160
+ auto reason = status == static_cast<std::uint16_t>(key_value_status_code::not_my_vbucket)
1161
+ ? retry_reason::key_value_not_my_vbucket
1162
+ : retry_reason::do_not_retry;
1163
+ if (fun) {
1164
+ fun(protocol::map_status_code(opcode, status),
1165
+ reason,
1166
+ std::move(msg),
1167
+ decode_error_code(status));
1168
+ return true;
1229
1169
  }
1230
1170
 
1231
- [[nodiscard]] const std::string& bootstrap_port() const
1171
+ // handle request new style
1172
+ std::shared_ptr<mcbp::queue_request> request{};
1173
+ std::shared_ptr<response_handler> handler{};
1232
1174
  {
1233
- return bootstrap_port_;
1175
+ std::scoped_lock lock(operations_mutex_);
1176
+ if (auto pair = operations_.find(opaque); pair != operations_.end() && pair->second.first) {
1177
+ request = pair->second.first;
1178
+ handler = pair->second.second;
1179
+ if (!request->persistent_) {
1180
+ operations_.erase(pair);
1181
+ }
1182
+ }
1234
1183
  }
1235
-
1236
- [[nodiscard]] std::uint16_t bootstrap_port_number() const
1237
- {
1238
- return bootstrap_port_number_;
1184
+ if (request) {
1185
+ handler->handle_response(std::move(request),
1186
+ protocol::map_status_code(opcode, status),
1187
+ reason,
1188
+ std::move(msg),
1189
+ decode_error_code(status));
1190
+ return true;
1239
1191
  }
1240
-
1241
- [[nodiscard]] std::uint32_t next_opaque()
1242
- {
1243
- return ++opaque_;
1192
+ return false;
1193
+ }
1194
+
1195
+ void write_and_subscribe(std::shared_ptr<mcbp::queue_request> request,
1196
+ std::shared_ptr<response_handler> handler)
1197
+ {
1198
+ auto opaque = request->opaque_;
1199
+ auto data = codec_.encode_packet(*request);
1200
+ if (!data) {
1201
+ CB_LOG_DEBUG("unable to encode packet. opaque={}, ec={}", opaque, data.error().message());
1202
+ request->try_callback({}, data.error());
1203
+ return;
1244
1204
  }
1245
1205
 
1246
- std::optional<key_value_error_map_info> decode_error_code(std::uint16_t code)
1247
- {
1248
- if (error_map_) {
1249
- auto info = error_map_->errors.find(code);
1250
- if (info != error_map_->errors.end()) {
1251
- return info->second;
1252
- }
1253
- }
1254
- return {};
1206
+ if (stopped_) {
1207
+ CB_LOG_WARNING("cancel operation while trying to write to closed mcbp session, opaque={}",
1208
+ opaque);
1209
+ handler->handle_response(request,
1210
+ errc::common::request_canceled,
1211
+ retry_reason::socket_closed_while_in_flight,
1212
+ {},
1213
+ {});
1214
+ return;
1255
1215
  }
1256
-
1257
- void on_configuration_update(std::shared_ptr<config_listener> handler)
1258
- {
1259
- config_listeners_.emplace_back(std::move(handler));
1216
+ enqueue_request(opaque, std::move(request), std::move(handler));
1217
+ if (bootstrapped_ && stream_->is_open()) {
1218
+ write_and_flush(std::move(data.value()));
1219
+ } else {
1220
+ CB_LOG_DEBUG("{} the stream is not ready yet, put the message into pending buffer, opaque={}",
1221
+ log_prefix_,
1222
+ opaque);
1223
+ std::scoped_lock lock(pending_buffer_mutex_);
1224
+ if (bootstrapped_ && stream_->is_open()) {
1225
+ write_and_flush(std::move(data.value()));
1226
+ } else {
1227
+ pending_buffer_.emplace_back(data.value());
1228
+ }
1260
1229
  }
1261
-
1262
- void update_configuration(topology::configuration&& config)
1263
- {
1264
- if (stopped_) {
1265
- return;
1266
- }
1267
- std::scoped_lock lock(config_mutex_);
1268
- // MB-60405 fixes this for 7.6.2, but for earlier versions we need to protect against using a
1269
- // config that has an empty vbucket map. We should be okay to ignore at this point b/c we should
1270
- // already have a config w/ a non-empty vbucket map (bootstrap will not complete successfully
1271
- // unless we have a config w/ a non-empty vbucket map).
1272
- if (config.vbmap && config.vbmap->size() == 0) {
1273
- CB_LOG_DEBUG("{} received a configuration with an empty vbucket map, ignoring", log_prefix_);
1274
- return;
1275
- }
1276
- if (config_) {
1277
- if (config_->vbmap && config.vbmap && config_->vbmap->size() != config.vbmap->size()) {
1278
- CB_LOG_DEBUG("{} received a configuration with a different number of vbuckets, ignoring", log_prefix_);
1279
- return;
1280
- }
1281
- if (config == config_) {
1282
- CB_LOG_TRACE("{} received a configuration with identical revision (new={}, old={}), ignoring",
1283
- log_prefix_,
1284
- config.rev_str(),
1285
- config_->rev_str());
1286
- return;
1287
- }
1288
- if (config < config_) {
1289
- CB_LOG_DEBUG("{} received a configuration with older revision (new={}, old={}), ignoring",
1290
- log_prefix_,
1291
- config.rev_str(),
1292
- config_->rev_str());
1293
- return;
1294
- }
1295
- }
1296
- bool this_node_found = false;
1297
- for (auto& node : config.nodes) {
1298
- if (node.hostname.empty()) {
1299
- node.hostname = bootstrap_hostname_;
1300
- }
1301
- if (node.this_node) {
1302
- this_node_found = true;
1303
- }
1304
- }
1305
- if (!this_node_found) {
1306
- for (auto& node : config.nodes) {
1307
- if (node.hostname == bootstrap_hostname_) {
1308
- if ((node.services_plain.key_value && std::to_string(node.services_plain.key_value.value()) == bootstrap_port_) ||
1309
- (node.services_tls.key_value && std::to_string(node.services_tls.key_value.value()) == bootstrap_port_)) {
1310
- node.this_node = true;
1311
- }
1312
- }
1313
- }
1314
- }
1315
- config_.reset();
1316
- config_.emplace(std::move(config));
1317
- configured_ = true;
1318
- for (const auto& listener : config_listeners_) {
1319
- asio::post(
1320
- asio::bind_executor(ctx_, [listener, c = config_.value()]() mutable { return listener->update_config(std::move(c)); }));
1321
- }
1230
+ }
1231
+
1232
+ void write_and_subscribe(std::uint32_t opaque,
1233
+ std::vector<std::byte>&& data,
1234
+ command_handler&& handler)
1235
+ {
1236
+ if (stopped_) {
1237
+ CB_LOG_WARNING("{} MCBP cancel operation, while trying to write to closed session, opaque={}",
1238
+ log_prefix_,
1239
+ opaque);
1240
+ handler(errc::common::request_canceled, retry_reason::socket_closed_while_in_flight, {}, {});
1241
+ return;
1322
1242
  }
1323
-
1324
- void handle_not_my_vbucket(const io::mcbp_message& msg)
1325
1243
  {
1326
- if (stopped_) {
1327
- return;
1328
- }
1329
- Expects(msg.header.magic == static_cast<std::uint8_t>(protocol::magic::alt_client_response) ||
1330
- msg.header.magic == static_cast<std::uint8_t>(protocol::magic::client_response));
1331
- if (protocol::has_json_datatype(msg.header.datatype)) {
1332
- auto magic = static_cast<protocol::magic>(msg.header.magic);
1333
- std::uint8_t extras_size = msg.header.extlen;
1334
- std::uint8_t framing_extras_size = 0;
1335
- std::uint16_t key_size = utils::byte_swap(msg.header.keylen);
1336
- if (magic == protocol::magic::alt_client_response) {
1337
- framing_extras_size = static_cast<std::uint8_t>(msg.header.keylen >> 8U);
1338
- key_size = msg.header.keylen & 0xffU;
1339
- }
1244
+ std::scoped_lock lock(command_handlers_mutex_);
1245
+ command_handlers_.try_emplace(opaque, std::move(handler));
1246
+ }
1247
+ if (bootstrapped_ && stream_->is_open()) {
1248
+ write_and_flush(std::move(data));
1249
+ } else {
1250
+ CB_LOG_DEBUG("{} the stream is not ready yet, put the message into pending buffer, opaque={}",
1251
+ log_prefix_,
1252
+ opaque);
1253
+ std::scoped_lock lock(pending_buffer_mutex_);
1254
+ if (bootstrapped_ && stream_->is_open()) {
1255
+ write_and_flush(std::move(data));
1256
+ } else {
1257
+ pending_buffer_.emplace_back(data);
1258
+ }
1259
+ }
1260
+ }
1340
1261
 
1341
- std::vector<std::uint8_t>::difference_type offset = framing_extras_size + key_size + extras_size;
1342
- if (utils::byte_swap(msg.header.bodylen) - offset > 0) {
1343
- std::string_view config_text{ reinterpret_cast<const char*>(msg.body.data()) + offset,
1344
- msg.body.size() - static_cast<std::size_t>(offset) };
1345
- if (origin_.options().dump_configuration) {
1346
- CB_LOG_TRACE("{} configuration from not_my_vbucket response (size={}, endpoint=\"{}:{}\"), {}",
1347
- log_prefix_,
1348
- config_text.size(),
1349
- bootstrap_hostname_,
1350
- bootstrap_port_number_,
1351
- config_text);
1352
- }
1353
- auto config = protocol::parse_config(config_text, bootstrap_hostname_, bootstrap_port_number_);
1354
- CB_LOG_DEBUG("{} received not_my_vbucket status for {}, opaque={} with config rev={} in the payload",
1355
- log_prefix_,
1356
- protocol::client_opcode(msg.header.opcode),
1357
- utils::byte_swap(msg.header.opaque),
1358
- config.rev_str());
1359
- update_configuration(std::move(config));
1360
- }
1361
- }
1262
+ [[nodiscard]] auto cancel(std::uint32_t opaque, std::error_code ec, retry_reason reason) -> bool
1263
+ {
1264
+ if (stopped_) {
1265
+ return false;
1266
+ }
1267
+ command_handlers_mutex_.lock();
1268
+ if (auto handler = command_handlers_.find(opaque); handler != command_handlers_.end()) {
1269
+ CB_LOG_DEBUG("{} MCBP cancel operation, opaque={}, ec={} ({})",
1270
+ log_prefix_,
1271
+ opaque,
1272
+ ec.value(),
1273
+ ec.message());
1274
+ if (handler->second) {
1275
+ auto fun = std::move(handler->second);
1276
+ command_handlers_.erase(handler);
1277
+ command_handlers_mutex_.unlock();
1278
+ fun(ec, reason, {}, {});
1279
+ return true;
1280
+ }
1281
+ }
1282
+ command_handlers_mutex_.unlock();
1283
+ return false;
1284
+ }
1285
+
1286
+ [[nodiscard]] auto supports_feature(protocol::hello_feature feature) -> bool
1287
+ {
1288
+ return std::find(supported_features_.begin(), supported_features_.end(), feature) !=
1289
+ supported_features_.end();
1290
+ }
1291
+
1292
+ [[nodiscard]] auto supported_features() const -> std::vector<protocol::hello_feature>
1293
+ {
1294
+ return supported_features_;
1295
+ }
1296
+
1297
+ [[nodiscard]] auto supports_gcccp() const -> bool
1298
+ {
1299
+ return supports_gcccp_;
1300
+ }
1301
+
1302
+ auto config() const -> std::optional<topology::configuration>
1303
+ {
1304
+ return config_;
1305
+ }
1306
+
1307
+ [[nodiscard]] auto has_config() const -> bool
1308
+ {
1309
+ return configured_;
1310
+ }
1311
+
1312
+ [[nodiscard]] auto config() -> topology::configuration
1313
+ {
1314
+ std::scoped_lock lock(config_mutex_);
1315
+ return config_.value();
1316
+ }
1317
+
1318
+ [[nodiscard]] auto index() const -> std::size_t
1319
+ {
1320
+ std::scoped_lock lock(config_mutex_);
1321
+ Expects(config_.has_value());
1322
+ return config_->index_for_this_node();
1323
+ }
1324
+
1325
+ [[nodiscard]] auto bootstrap_address() const -> const std::string&
1326
+ {
1327
+ return bootstrap_address_;
1328
+ }
1329
+
1330
+ [[nodiscard]] auto bootstrap_hostname() const -> const std::string&
1331
+ {
1332
+ return bootstrap_hostname_;
1333
+ }
1334
+
1335
+ [[nodiscard]] auto bootstrap_port() const -> const std::string&
1336
+ {
1337
+ return bootstrap_port_;
1338
+ }
1339
+
1340
+ [[nodiscard]] auto bootstrap_port_number() const -> std::uint16_t
1341
+ {
1342
+ return bootstrap_port_number_;
1343
+ }
1344
+
1345
+ [[nodiscard]] auto next_opaque() -> std::uint32_t
1346
+ {
1347
+ return ++opaque_;
1348
+ }
1349
+
1350
+ auto decode_error_code(std::uint16_t code) -> std::optional<key_value_error_map_info>
1351
+ {
1352
+ if (error_map_) {
1353
+ auto info = error_map_->errors.find(code);
1354
+ if (info != error_map_->errors.end()) {
1355
+ return info->second;
1356
+ }
1362
1357
  }
1358
+ return {};
1359
+ }
1360
+
1361
+ void on_configuration_update(std::shared_ptr<config_listener> handler)
1362
+ {
1363
+ config_listeners_.emplace_back(std::move(handler));
1364
+ }
1365
+
1366
+ void update_configuration(topology::configuration&& config)
1367
+ {
1368
+ if (stopped_) {
1369
+ return;
1370
+ }
1371
+ std::scoped_lock lock(config_mutex_);
1372
+ // MB-60405 fixes this for 7.6.2, but for earlier versions we need to protect against using a
1373
+ // config that has an empty vbucket map. We should be okay to ignore at this point b/c we
1374
+ // should already have a config w/ a non-empty vbucket map (bootstrap will not complete
1375
+ // successfully unless we have a config w/ a non-empty vbucket map).
1376
+ if (config.vbmap && config.vbmap->size() == 0) {
1377
+ CB_LOG_DEBUG("{} received a configuration with an empty vbucket map, ignoring", log_prefix_);
1378
+ return;
1379
+ }
1380
+ if (config_) {
1381
+ if (config_->vbmap && config.vbmap && config_->vbmap->size() != config.vbmap->size()) {
1382
+ CB_LOG_DEBUG("{} received a configuration with a different number of vbuckets, ignoring",
1383
+ log_prefix_);
1384
+ return;
1385
+ }
1386
+ if (config == config_) {
1387
+ CB_LOG_TRACE(
1388
+ "{} received a configuration with identical revision (new={}, old={}), ignoring",
1389
+ log_prefix_,
1390
+ config.rev_str(),
1391
+ config_->rev_str());
1392
+ return;
1393
+ }
1394
+ if (config < config_) {
1395
+ CB_LOG_DEBUG("{} received a configuration with older revision (new={}, old={}), ignoring",
1396
+ log_prefix_,
1397
+ config.rev_str(),
1398
+ config_->rev_str());
1399
+ return;
1400
+ }
1401
+ }
1402
+ bool this_node_found = false;
1403
+ for (auto& node : config.nodes) {
1404
+ if (node.hostname.empty()) {
1405
+ node.hostname = bootstrap_hostname_;
1406
+ }
1407
+ if (node.this_node) {
1408
+ this_node_found = true;
1409
+ }
1410
+ }
1411
+ if (!this_node_found) {
1412
+ for (auto& node : config.nodes) {
1413
+ if (node.hostname == bootstrap_hostname_) {
1414
+ if ((node.services_plain.key_value &&
1415
+ std::to_string(node.services_plain.key_value.value()) == bootstrap_port_) ||
1416
+ (node.services_tls.key_value &&
1417
+ std::to_string(node.services_tls.key_value.value()) == bootstrap_port_)) {
1418
+ node.this_node = true;
1419
+ }
1420
+ }
1421
+ }
1422
+ }
1423
+ config_.reset();
1424
+ config_.emplace(std::move(config));
1425
+ configured_ = true;
1426
+ for (const auto& listener : config_listeners_) {
1427
+ asio::post(asio::bind_executor(ctx_, [listener, c = config_.value()]() mutable {
1428
+ return listener->update_config(std::move(c));
1429
+ }));
1430
+ }
1431
+ }
1363
1432
 
1364
- std::optional<std::uint32_t> get_collection_uid(const std::string& collection_path)
1365
- {
1366
- return collection_cache_.get(collection_path);
1433
+ void handle_not_my_vbucket(const io::mcbp_message& msg)
1434
+ {
1435
+ if (stopped_) {
1436
+ return;
1437
+ }
1438
+ Expects(msg.header.magic == static_cast<std::uint8_t>(protocol::magic::alt_client_response) ||
1439
+ msg.header.magic == static_cast<std::uint8_t>(protocol::magic::client_response));
1440
+ if (protocol::has_json_datatype(msg.header.datatype)) {
1441
+ auto magic = static_cast<protocol::magic>(msg.header.magic);
1442
+ std::uint8_t extras_size = msg.header.extlen;
1443
+ std::uint8_t framing_extras_size = 0;
1444
+ std::uint16_t key_size = utils::byte_swap(msg.header.keylen);
1445
+ if (magic == protocol::magic::alt_client_response) {
1446
+ framing_extras_size = static_cast<std::uint8_t>(msg.header.keylen >> 8U);
1447
+ key_size = msg.header.keylen & 0xffU;
1448
+ }
1449
+
1450
+ std::vector<std::uint8_t>::difference_type offset =
1451
+ framing_extras_size + key_size + extras_size;
1452
+ if (utils::byte_swap(msg.header.bodylen) - offset > 0) {
1453
+ std::string_view config_text{ reinterpret_cast<const char*>(msg.body.data()) + offset,
1454
+ msg.body.size() - static_cast<std::size_t>(offset) };
1455
+ if (origin_.options().dump_configuration) {
1456
+ CB_LOG_TRACE(
1457
+ "{} configuration from not_my_vbucket response (size={}, endpoint=\"{}:{}\"), {}",
1458
+ log_prefix_,
1459
+ config_text.size(),
1460
+ bootstrap_hostname_,
1461
+ bootstrap_port_number_,
1462
+ config_text);
1463
+ }
1464
+ auto config =
1465
+ protocol::parse_config(config_text, bootstrap_hostname_, bootstrap_port_number_);
1466
+ CB_LOG_DEBUG(
1467
+ "{} received not_my_vbucket status for {}, opaque={} with config rev={} in the payload",
1468
+ log_prefix_,
1469
+ protocol::client_opcode(msg.header.opcode),
1470
+ utils::byte_swap(msg.header.opaque),
1471
+ config.rev_str());
1472
+ update_configuration(std::move(config));
1473
+ }
1367
1474
  }
1475
+ }
1368
1476
 
1369
- void update_collection_uid(const std::string& path, std::uint32_t uid)
1370
- {
1371
- if (stopped_) {
1372
- return;
1373
- }
1374
- collection_cache_.update(path, uid);
1477
+ auto get_collection_uid(const std::string& collection_path) -> std::optional<std::uint32_t>
1478
+ {
1479
+ return collection_cache_.get(collection_path);
1480
+ }
1481
+
1482
+ void update_collection_uid(const std::string& path, std::uint32_t uid)
1483
+ {
1484
+ if (stopped_) {
1485
+ return;
1375
1486
  }
1487
+ collection_cache_.update(path, uid);
1488
+ }
1376
1489
 
1377
- private:
1378
- void invoke_bootstrap_handler(std::error_code ec)
1379
- {
1380
- retry_backoff_.cancel();
1490
+ private:
1491
+ void invoke_bootstrap_handler(std::error_code ec)
1492
+ {
1493
+ retry_backoff_.cancel();
1381
1494
 
1382
- if (ec && state_listener_) {
1383
- state_listener_->report_bootstrap_error(fmt::format("{}:{}", bootstrap_hostname_, bootstrap_port_), ec);
1384
- }
1385
- if (ec == errc::network::configuration_not_available) {
1386
- return initiate_bootstrap();
1387
- }
1388
- if (retry_bootstrap_on_bucket_not_found_ && ec == errc::common::bucket_not_found) {
1389
- CB_LOG_DEBUG(R"({} server returned {} ({}), it must be transient condition, retrying)", log_prefix_, ec.value(), ec.message());
1390
- return initiate_bootstrap();
1391
- }
1392
- if (!origin_.exhausted() && ec == errc::common::authentication_failure) {
1393
- CB_LOG_DEBUG(
1394
- R"({} server returned authentication_failure, but the bootstrap list is not exhausted yet. It must be transient condition, retrying)",
1395
- log_prefix_);
1396
- return initiate_bootstrap();
1397
- }
1495
+ if (ec && state_listener_) {
1496
+ state_listener_->report_bootstrap_error(
1497
+ fmt::format("{}:{}", bootstrap_hostname_, bootstrap_port_), ec);
1498
+ }
1499
+ if (ec == errc::network::configuration_not_available) {
1500
+ return initiate_bootstrap();
1501
+ }
1502
+ if (retry_bootstrap_on_bucket_not_found_ && ec == errc::common::bucket_not_found) {
1503
+ CB_LOG_DEBUG(R"({} server returned {} ({}), it must be transient condition, retrying)",
1504
+ log_prefix_,
1505
+ ec.value(),
1506
+ ec.message());
1507
+ return initiate_bootstrap();
1508
+ }
1509
+ if (!origin_.exhausted() && ec == errc::common::authentication_failure) {
1510
+ CB_LOG_DEBUG(
1511
+ R"({} server returned authentication_failure, but the bootstrap list is not exhausted yet. It must be transient condition, retrying)",
1512
+ log_prefix_);
1513
+ return initiate_bootstrap();
1514
+ }
1398
1515
 
1399
- if (!bootstrapped_ && bootstrap_callback_) {
1400
- bootstrap_deadline_.cancel();
1401
- if (config_ && state_listener_) {
1402
- std::vector<std::string> endpoints;
1403
- endpoints.reserve(config_.value().nodes.size());
1404
- for (const auto& node : config_.value().nodes) {
1405
- if (auto endpoint = node.endpoint(origin_.options().network, service_type::key_value, is_tls_); endpoint) {
1406
- endpoints.push_back(endpoint.value());
1407
- }
1408
- }
1409
- state_listener_->report_bootstrap_success(endpoints);
1410
- }
1411
- auto h = std::move(bootstrap_callback_);
1412
- h(ec, config_.value_or(topology::configuration{}));
1413
- }
1414
- if (ec) {
1415
- return stop(retry_reason::node_not_available);
1416
- }
1417
- state_ = diag::endpoint_state::connected;
1418
- std::scoped_lock lock(pending_buffer_mutex_);
1419
- bootstrapped_ = true;
1420
- bootstrap_handler_->stop();
1421
- handler_ = std::make_shared<message_handler>(shared_from_this());
1422
- handler_->start();
1423
- if (!pending_buffer_.empty()) {
1424
- for (auto& buf : pending_buffer_) {
1425
- write(std::move(buf));
1426
- }
1427
- pending_buffer_.clear();
1428
- flush();
1429
- }
1516
+ if (!bootstrapped_ && bootstrap_callback_) {
1517
+ bootstrap_deadline_.cancel();
1518
+ if (config_ && state_listener_) {
1519
+ std::vector<std::string> endpoints;
1520
+ endpoints.reserve(config_.value().nodes.size());
1521
+ for (const auto& node : config_.value().nodes) {
1522
+ if (auto endpoint =
1523
+ node.endpoint(origin_.options().network, service_type::key_value, is_tls_);
1524
+ endpoint) {
1525
+ endpoints.push_back(endpoint.value());
1526
+ }
1527
+ }
1528
+ state_listener_->report_bootstrap_success(endpoints);
1529
+ }
1530
+ auto h = std::move(bootstrap_callback_);
1531
+ h(ec, config_.value_or(topology::configuration{}));
1430
1532
  }
1533
+ if (ec) {
1534
+ return stop(retry_reason::node_not_available);
1535
+ }
1536
+ state_ = diag::endpoint_state::connected;
1537
+ std::scoped_lock lock(pending_buffer_mutex_);
1538
+ bootstrapped_ = true;
1539
+ bootstrap_handler_->stop();
1540
+ handler_ = std::make_shared<message_handler>(shared_from_this());
1541
+ handler_->start();
1542
+ if (!pending_buffer_.empty()) {
1543
+ for (auto& buf : pending_buffer_) {
1544
+ write(std::move(buf));
1545
+ }
1546
+ pending_buffer_.clear();
1547
+ flush();
1548
+ }
1549
+ }
1431
1550
 
1432
- void on_resolve(std::error_code ec, const asio::ip::tcp::resolver::results_type& endpoints)
1433
- {
1434
- if (ec == asio::error::operation_aborted || stopped_) {
1551
+ void on_resolve(std::error_code ec, const asio::ip::tcp::resolver::results_type& endpoints)
1552
+ {
1553
+ if (ec == asio::error::operation_aborted || stopped_) {
1554
+ return;
1555
+ }
1556
+ last_active_ = std::chrono::steady_clock::now();
1557
+ if (ec) {
1558
+ CB_LOG_ERROR("{} error on resolve: {} ({})", log_prefix_, ec.value(), ec.message());
1559
+ return initiate_bootstrap();
1560
+ }
1561
+ endpoints_ = endpoints;
1562
+ CB_LOG_TRACE("{} resolved \"{}:{}\" to {} endpoint(s)",
1563
+ log_prefix_,
1564
+ bootstrap_hostname_,
1565
+ bootstrap_port_,
1566
+ endpoints_.size());
1567
+ do_connect(endpoints_.begin());
1568
+ connection_deadline_.expires_after(origin_.options().resolve_timeout);
1569
+ connection_deadline_.async_wait([self = shared_from_this()](const auto timer_ec) {
1570
+ if (timer_ec == asio::error::operation_aborted || self->stopped_) {
1571
+ return;
1572
+ }
1573
+ return self->stream_->close([self](std::error_code) {
1574
+ self->initiate_bootstrap();
1575
+ });
1576
+ });
1577
+ }
1578
+
1579
+ void do_connect(asio::ip::tcp::resolver::results_type::iterator it)
1580
+ {
1581
+ if (stopped_) {
1582
+ return;
1583
+ }
1584
+ last_active_ = std::chrono::steady_clock::now();
1585
+ if (it != endpoints_.end()) {
1586
+ auto hostname = it->endpoint().address().to_string();
1587
+ auto port = it->endpoint().port();
1588
+ CB_LOG_DEBUG("{} connecting to {}:{} (\"{}:{}\"), timeout={}ms",
1589
+ log_prefix_,
1590
+ hostname,
1591
+ port,
1592
+ bootstrap_hostname_,
1593
+ bootstrap_port_,
1594
+ origin_.options().connect_timeout.count());
1595
+ connection_deadline_.expires_after(origin_.options().connect_timeout);
1596
+ connection_deadline_.async_wait(
1597
+ [self = shared_from_this(), hostname, port](const auto timer_ec) {
1598
+ if (timer_ec == asio::error::operation_aborted || self->stopped_) {
1435
1599
  return;
1436
- }
1437
- last_active_ = std::chrono::steady_clock::now();
1438
- if (ec) {
1439
- CB_LOG_ERROR("{} error on resolve: {} ({})", log_prefix_, ec.value(), ec.message());
1440
- return initiate_bootstrap();
1441
- }
1442
- endpoints_ = endpoints;
1443
- CB_LOG_TRACE("{} resolved \"{}:{}\" to {} endpoint(s)", log_prefix_, bootstrap_hostname_, bootstrap_port_, endpoints_.size());
1444
- do_connect(endpoints_.begin());
1445
- connection_deadline_.expires_after(origin_.options().resolve_timeout);
1446
- connection_deadline_.async_wait([self = shared_from_this()](const auto timer_ec) {
1447
- if (timer_ec == asio::error::operation_aborted || self->stopped_) {
1448
- return;
1449
- }
1450
- return self->stream_->close([self](std::error_code) { self->initiate_bootstrap(); });
1600
+ }
1601
+ CB_LOG_DEBUG("{} unable to connect to {}:{} (\"{}:{}\") in time, reconnecting",
1602
+ self->log_prefix_,
1603
+ hostname,
1604
+ port,
1605
+ self->bootstrap_hostname_,
1606
+ self->bootstrap_port_);
1607
+ return self->stream_->close([self](std::error_code) {
1608
+ self->initiate_bootstrap();
1609
+ });
1451
1610
  });
1611
+ stream_->async_connect(
1612
+ it->endpoint(),
1613
+ std::bind(&mcbp_session_impl::on_connect, shared_from_this(), std::placeholders::_1, it));
1614
+ } else {
1615
+ CB_LOG_ERROR("{} no more endpoints left to connect to \"{}:{}\", will try another address",
1616
+ log_prefix_,
1617
+ bootstrap_hostname_,
1618
+ bootstrap_port_);
1619
+ if (state_listener_) {
1620
+ state_listener_->report_bootstrap_error(
1621
+ fmt::format("{}:{}", bootstrap_hostname_, bootstrap_port_),
1622
+ errc::network::no_endpoints_left);
1623
+ }
1624
+ return initiate_bootstrap();
1452
1625
  }
1626
+ }
1453
1627
 
1454
- void do_connect(asio::ip::tcp::resolver::results_type::iterator it)
1455
- {
1456
- if (stopped_) {
1457
- return;
1458
- }
1459
- last_active_ = std::chrono::steady_clock::now();
1460
- if (it != endpoints_.end()) {
1461
- auto hostname = it->endpoint().address().to_string();
1462
- auto port = it->endpoint().port();
1463
- CB_LOG_DEBUG("{} connecting to {}:{} (\"{}:{}\"), timeout={}ms",
1464
- log_prefix_,
1465
- hostname,
1466
- port,
1467
- bootstrap_hostname_,
1468
- bootstrap_port_,
1469
- origin_.options().connect_timeout.count());
1470
- connection_deadline_.expires_after(origin_.options().connect_timeout);
1471
- connection_deadline_.async_wait([self = shared_from_this(), hostname, port](const auto timer_ec) {
1472
- if (timer_ec == asio::error::operation_aborted || self->stopped_) {
1473
- return;
1474
- }
1475
- CB_LOG_DEBUG("{} unable to connect to {}:{} (\"{}:{}\") in time, reconnecting",
1476
- self->log_prefix_,
1477
- hostname,
1478
- port,
1479
- self->bootstrap_hostname_,
1480
- self->bootstrap_port_);
1481
- return self->stream_->close([self](std::error_code) { self->initiate_bootstrap(); });
1482
- });
1483
- stream_->async_connect(it->endpoint(),
1484
- std::bind(&mcbp_session_impl::on_connect, shared_from_this(), std::placeholders::_1, it));
1485
- } else {
1486
- CB_LOG_ERROR("{} no more endpoints left to connect to \"{}:{}\", will try another address",
1487
- log_prefix_,
1488
- bootstrap_hostname_,
1489
- bootstrap_port_);
1490
- if (state_listener_) {
1491
- state_listener_->report_bootstrap_error(fmt::format("{}:{}", bootstrap_hostname_, bootstrap_port_),
1492
- errc::network::no_endpoints_left);
1493
- }
1494
- return initiate_bootstrap();
1495
- }
1628
+ void on_connect(const std::error_code& ec, asio::ip::tcp::resolver::results_type::iterator it)
1629
+ {
1630
+ if (ec == asio::error::operation_aborted || stopped_) {
1631
+ return;
1496
1632
  }
1497
-
1498
- void on_connect(const std::error_code& ec, asio::ip::tcp::resolver::results_type::iterator it)
1499
- {
1500
- if (ec == asio::error::operation_aborted || stopped_) {
1501
- return;
1502
- }
1503
- last_active_ = std::chrono::steady_clock::now();
1504
- if (!stream_->is_open() || ec) {
1633
+ last_active_ = std::chrono::steady_clock::now();
1634
+ if (!stream_->is_open() || ec) {
1505
1635
  #ifdef COUCHBASE_CXX_CLIENT_STATIC_BORINGSSL
1506
- auto error_message = (ec.category() == asio::error::ssl_category)
1507
- ? ERR_error_string(static_cast<std::uint32_t>(ec.value()), nullptr)
1508
- : ec.message();
1636
+ auto error_message = (ec.category() == asio::error::ssl_category)
1637
+ ? ERR_error_string(static_cast<std::uint32_t>(ec.value()), nullptr)
1638
+ : ec.message();
1509
1639
  #else
1510
- auto error_message = (ec.category() == asio::error::ssl_category)
1511
- ? ERR_error_string(static_cast<unsigned long>(ec.value()), nullptr)
1512
- : ec.message();
1640
+ auto error_message = (ec.category() == asio::error::ssl_category)
1641
+ ? ERR_error_string(static_cast<unsigned long>(ec.value()), nullptr)
1642
+ : ec.message();
1513
1643
  #endif
1514
- CB_LOG_WARNING("{} unable to connect to {}:{}: {} ({}){}. is_open={}",
1515
- log_prefix_,
1516
- it->endpoint().address().to_string(),
1517
- it->endpoint().port(),
1518
- ec.value(),
1519
- error_message,
1520
- (ec == asio::error::connection_refused) ? ", check server ports and cluster encryption setting" : "",
1521
- stream_->is_open());
1522
- if (stream_->is_open()) {
1523
- stream_->close(std::bind(&mcbp_session_impl::do_connect, shared_from_this(), ++it));
1524
- } else {
1525
- do_connect(++it);
1526
- }
1527
- } else {
1528
- stream_->set_options();
1529
- connection_endpoints_ = { it->endpoint(), stream_->local_endpoint() };
1530
- CB_LOG_DEBUG("{} connected to {}:{}", log_prefix_, connection_endpoints_.remote_address, connection_endpoints_.remote.port());
1531
- log_prefix_ = fmt::format("[{}/{}/{}/{}] <{}/{}:{}>",
1532
- client_id_,
1533
- id_,
1534
- stream_->log_prefix(),
1535
- bucket_name_.value_or("-"),
1536
- bootstrap_hostname_,
1537
- connection_endpoints_.remote_address,
1538
- connection_endpoints_.remote.port());
1539
- parser_.reset();
1540
- bootstrap_handler_ = std::make_shared<bootstrap_handler>(shared_from_this());
1541
- connection_deadline_.cancel();
1542
- }
1644
+ CB_LOG_WARNING("{} unable to connect to {}:{}: {} ({}){}. is_open={}",
1645
+ log_prefix_,
1646
+ it->endpoint().address().to_string(),
1647
+ it->endpoint().port(),
1648
+ ec.value(),
1649
+ error_message,
1650
+ (ec == asio::error::connection_refused)
1651
+ ? ", check server ports and cluster encryption setting"
1652
+ : "",
1653
+ stream_->is_open());
1654
+ if (stream_->is_open()) {
1655
+ stream_->close(std::bind(&mcbp_session_impl::do_connect, shared_from_this(), ++it));
1656
+ } else {
1657
+ do_connect(++it);
1658
+ }
1659
+ } else {
1660
+ stream_->set_options();
1661
+ connection_endpoints_ = { it->endpoint(), stream_->local_endpoint() };
1662
+ CB_LOG_DEBUG("{} connected to {}:{}",
1663
+ log_prefix_,
1664
+ connection_endpoints_.remote_address,
1665
+ connection_endpoints_.remote.port());
1666
+ log_prefix_ = fmt::format("[{}/{}/{}/{}] <{}/{}:{}>",
1667
+ client_id_,
1668
+ id_,
1669
+ stream_->log_prefix(),
1670
+ bucket_name_.value_or("-"),
1671
+ bootstrap_hostname_,
1672
+ connection_endpoints_.remote_address,
1673
+ connection_endpoints_.remote.port());
1674
+ parser_.reset();
1675
+ bootstrap_handler_ = std::make_shared<bootstrap_handler>(shared_from_this());
1676
+ connection_deadline_.cancel();
1543
1677
  }
1678
+ }
1544
1679
 
1545
- void check_deadline(std::error_code ec)
1546
- {
1547
- if (ec == asio::error::operation_aborted || stopped_) {
1548
- return;
1549
- }
1550
- if (connection_deadline_.expiry() <= asio::steady_timer::clock_type::now()) {
1551
- stream_->close([](std::error_code) {});
1552
- }
1553
- connection_deadline_.async_wait(std::bind(&mcbp_session_impl::check_deadline, shared_from_this(), std::placeholders::_1));
1680
+ void check_deadline(std::error_code ec)
1681
+ {
1682
+ if (ec == asio::error::operation_aborted || stopped_) {
1683
+ return;
1554
1684
  }
1555
-
1556
- void do_read()
1557
- {
1558
- if (stopped_ || reading_ || !stream_->is_open()) {
1685
+ if (connection_deadline_.expiry() <= asio::steady_timer::clock_type::now()) {
1686
+ stream_->close([](std::error_code) {
1687
+ });
1688
+ }
1689
+ connection_deadline_.async_wait(
1690
+ std::bind(&mcbp_session_impl::check_deadline, shared_from_this(), std::placeholders::_1));
1691
+ }
1692
+
1693
+ void do_read()
1694
+ {
1695
+ if (stopped_ || reading_ || !stream_->is_open()) {
1696
+ return;
1697
+ }
1698
+ reading_ = true;
1699
+ stream_->async_read_some(
1700
+ asio::buffer(input_buffer_),
1701
+ [self = shared_from_this(), stream_id = stream_->id()](std::error_code ec,
1702
+ std::size_t bytes_transferred) {
1703
+ if (ec == asio::error::operation_aborted || self->stopped_) {
1704
+ CB_LOG_PROTOCOL("[MCBP, IN] host=\"{}\", port={}, rc={}, bytes_received={}",
1705
+ self->connection_endpoints_.remote_address,
1706
+ self->connection_endpoints_.remote.port(),
1707
+ ec ? ec.message() : "ok",
1708
+ bytes_transferred);
1709
+ return;
1710
+ } else {
1711
+ CB_LOG_PROTOCOL("[MCBP, IN] host=\"{}\", port={}, rc={}, bytes_received={}{:a}",
1712
+ self->connection_endpoints_.remote_address,
1713
+ self->connection_endpoints_.remote.port(),
1714
+ ec ? ec.message() : "ok",
1715
+ bytes_transferred,
1716
+ spdlog::to_hex(self->input_buffer_.data(),
1717
+ self->input_buffer_.data() +
1718
+ static_cast<std::ptrdiff_t>(bytes_transferred)));
1719
+ }
1720
+ self->last_active_ = std::chrono::steady_clock::now();
1721
+ if (ec) {
1722
+ if (stream_id != self->stream_->id()) {
1723
+ CB_LOG_ERROR(
1724
+ R"({} ignore IO error while reading from the socket: {} ({}), old_id="{}", new_id="{}")",
1725
+ self->log_prefix_,
1726
+ ec.value(),
1727
+ ec.message(),
1728
+ stream_id,
1729
+ self->stream_->id());
1559
1730
  return;
1560
- }
1561
- reading_ = true;
1562
- stream_->async_read_some(
1563
- asio::buffer(input_buffer_),
1564
- [self = shared_from_this(), stream_id = stream_->id()](std::error_code ec, std::size_t bytes_transferred) {
1565
- if (ec == asio::error::operation_aborted || self->stopped_) {
1566
- CB_LOG_PROTOCOL("[MCBP, IN] host=\"{}\", port={}, rc={}, bytes_received={}",
1567
- self->connection_endpoints_.remote_address,
1568
- self->connection_endpoints_.remote.port(),
1569
- ec ? ec.message() : "ok",
1570
- bytes_transferred);
1571
- return;
1572
- } else {
1573
- CB_LOG_PROTOCOL("[MCBP, IN] host=\"{}\", port={}, rc={}, bytes_received={}{:a}",
1574
- self->connection_endpoints_.remote_address,
1575
- self->connection_endpoints_.remote.port(),
1576
- ec ? ec.message() : "ok",
1577
- bytes_transferred,
1578
- spdlog::to_hex(self->input_buffer_.data(),
1579
- self->input_buffer_.data() + static_cast<std::ptrdiff_t>(bytes_transferred)));
1580
- }
1581
- self->last_active_ = std::chrono::steady_clock::now();
1582
- if (ec) {
1583
- if (stream_id != self->stream_->id()) {
1584
- CB_LOG_ERROR(R"({} ignore IO error while reading from the socket: {} ({}), old_id="{}", new_id="{}")",
1585
- self->log_prefix_,
1586
- ec.value(),
1587
- ec.message(),
1588
- stream_id,
1589
- self->stream_->id());
1590
- return;
1591
- }
1592
- CB_LOG_ERROR(R"({} IO error while reading from the socket("{}"): {} ({}))",
1593
- self->log_prefix_,
1594
- self->stream_->id(),
1595
- ec.value(),
1596
- ec.message());
1597
- return self->stop(retry_reason::socket_closed_while_in_flight);
1731
+ }
1732
+ CB_LOG_ERROR(R"({} IO error while reading from the socket("{}"): {} ({}))",
1733
+ self->log_prefix_,
1734
+ self->stream_->id(),
1735
+ ec.value(),
1736
+ ec.message());
1737
+ return self->stop(retry_reason::socket_closed_while_in_flight);
1738
+ }
1739
+ self->parser_.feed(self->input_buffer_.data(),
1740
+ self->input_buffer_.data() +
1741
+ static_cast<std::ptrdiff_t>(bytes_transferred));
1742
+
1743
+ for (;;) {
1744
+ mcbp_message msg{};
1745
+ switch (self->parser_.next(msg)) {
1746
+ case mcbp_parser::result::ok: {
1747
+ if (self->stopped_) {
1748
+ return;
1598
1749
  }
1599
- self->parser_.feed(self->input_buffer_.data(), self->input_buffer_.data() + static_cast<std::ptrdiff_t>(bytes_transferred));
1600
-
1601
- for (;;) {
1602
- mcbp_message msg{};
1603
- switch (self->parser_.next(msg)) {
1604
- case mcbp_parser::result::ok: {
1605
- if (self->stopped_) {
1606
- return;
1607
- }
1608
- CB_LOG_TRACE("{} MCBP recv {}", self->log_prefix_, mcbp_header_view(msg.header_data()));
1609
- if (self->bootstrapped_) {
1610
- self->handler_->handle(std::move(msg));
1611
- } else if (self->bootstrap_handler_) {
1612
- self->bootstrap_handler_->handle(std::move(msg));
1613
- }
1614
- if (self->stopped_) {
1615
- return;
1616
- }
1617
- } break;
1618
- case mcbp_parser::result::need_data:
1619
- self->reading_ = false;
1620
- if (!self->stopped_ && self->stream_->is_open()) {
1621
- self->do_read();
1622
- }
1623
- return;
1624
- case mcbp_parser::result::failure:
1625
- return self->stop(retry_reason::key_value_temporary_failure);
1626
- }
1750
+ CB_LOG_TRACE(
1751
+ "{} MCBP recv {}", self->log_prefix_, mcbp_header_view(msg.header_data()));
1752
+ if (self->bootstrapped_) {
1753
+ self->handler_->handle(std::move(msg));
1754
+ } else if (self->bootstrap_handler_) {
1755
+ self->bootstrap_handler_->handle(std::move(msg));
1627
1756
  }
1628
- });
1629
- }
1630
-
1631
- void do_write()
1632
- {
1633
- if (stopped_ || !stream_->is_open()) {
1634
- return;
1635
- }
1636
- std::scoped_lock lock(writing_buffer_mutex_, output_buffer_mutex_);
1637
- if (!writing_buffer_.empty() || output_buffer_.empty()) {
1638
- return;
1639
- }
1640
- std::swap(writing_buffer_, output_buffer_);
1641
- std::vector<asio::const_buffer> buffers;
1642
- buffers.reserve(writing_buffer_.size());
1643
- for (auto& buf : writing_buffer_) {
1644
- CB_LOG_PROTOCOL("[MCBP, OUT] host=\"{}\", port={}, buffer_size={}{:a}",
1645
- connection_endpoints_.remote_address,
1646
- connection_endpoints_.remote.port(),
1647
- buf.size(),
1648
- spdlog::to_hex(buf));
1649
- buffers.emplace_back(asio::buffer(buf));
1650
- }
1651
- stream_->async_write(buffers, [self = shared_from_this()](std::error_code ec, std::size_t bytes_transferred) {
1652
- CB_LOG_PROTOCOL("[MCBP, OUT] host=\"{}\", port={}, rc={}, bytes_sent={}",
1653
- self->connection_endpoints_.remote_address,
1654
- self->connection_endpoints_.remote.port(),
1655
- ec ? ec.message() : "ok",
1656
- bytes_transferred);
1657
- if (ec == asio::error::operation_aborted || self->stopped_) {
1757
+ if (self->stopped_) {
1658
1758
  return;
1659
- }
1660
- self->last_active_ = std::chrono::steady_clock::now();
1661
-
1662
- if (ec) {
1663
- CB_LOG_ERROR(R"({} IO error while writing to the socket("{}"): {} ({}))",
1664
- self->log_prefix_,
1665
- self->stream_->id(),
1666
- ec.value(),
1667
- ec.message());
1668
- return self->stop(retry_reason::socket_closed_while_in_flight);
1669
- }
1670
- {
1671
- std::scoped_lock inner_lock(self->writing_buffer_mutex_);
1672
- self->writing_buffer_.clear();
1673
- }
1674
- asio::post(asio::bind_executor(self->ctx_, [self]() {
1675
- self->do_write();
1759
+ }
1760
+ } break;
1761
+ case mcbp_parser::result::need_data:
1762
+ self->reading_ = false;
1763
+ if (!self->stopped_ && self->stream_->is_open()) {
1676
1764
  self->do_read();
1677
- }));
1678
- });
1765
+ }
1766
+ return;
1767
+ case mcbp_parser::result::failure:
1768
+ return self->stop(retry_reason::key_value_temporary_failure);
1769
+ }
1770
+ }
1771
+ });
1772
+ }
1773
+
1774
+ void do_write()
1775
+ {
1776
+ if (stopped_ || !stream_->is_open()) {
1777
+ return;
1778
+ }
1779
+ std::scoped_lock lock(writing_buffer_mutex_, output_buffer_mutex_);
1780
+ if (!writing_buffer_.empty() || output_buffer_.empty()) {
1781
+ return;
1679
1782
  }
1783
+ std::swap(writing_buffer_, output_buffer_);
1784
+ std::vector<asio::const_buffer> buffers;
1785
+ buffers.reserve(writing_buffer_.size());
1786
+ for (auto& buf : writing_buffer_) {
1787
+ CB_LOG_PROTOCOL("[MCBP, OUT] host=\"{}\", port={}, buffer_size={}{:a}",
1788
+ connection_endpoints_.remote_address,
1789
+ connection_endpoints_.remote.port(),
1790
+ buf.size(),
1791
+ spdlog::to_hex(buf));
1792
+ buffers.emplace_back(asio::buffer(buf));
1793
+ }
1794
+ stream_->async_write(
1795
+ buffers, [self = shared_from_this()](std::error_code ec, std::size_t bytes_transferred) {
1796
+ CB_LOG_PROTOCOL("[MCBP, OUT] host=\"{}\", port={}, rc={}, bytes_sent={}",
1797
+ self->connection_endpoints_.remote_address,
1798
+ self->connection_endpoints_.remote.port(),
1799
+ ec ? ec.message() : "ok",
1800
+ bytes_transferred);
1801
+ if (ec == asio::error::operation_aborted || self->stopped_) {
1802
+ return;
1803
+ }
1804
+ self->last_active_ = std::chrono::steady_clock::now();
1680
1805
 
1681
- const std::string client_id_;
1682
- const std::string id_{ uuid::to_string(uuid::random()) };
1683
- asio::io_context& ctx_;
1684
- asio::ip::tcp::resolver resolver_;
1685
- std::unique_ptr<stream_impl> stream_;
1686
- asio::steady_timer bootstrap_deadline_;
1687
- asio::steady_timer connection_deadline_;
1688
- asio::steady_timer retry_backoff_;
1689
- asio::steady_timer ping_deadline_;
1690
- couchbase::core::origin origin_;
1691
- std::optional<std::string> bucket_name_;
1692
- mcbp_parser parser_;
1693
- std::shared_ptr<bootstrap_handler> bootstrap_handler_{ nullptr };
1694
- std::optional<std::string> last_bootstrap_error_message_;
1695
- std::shared_ptr<message_handler> handler_{ nullptr };
1696
- utils::movable_function<void(std::error_code, const topology::configuration&)> bootstrap_callback_{};
1697
- std::mutex command_handlers_mutex_{};
1698
- std::map<std::uint32_t, command_handler> command_handlers_{};
1699
- std::vector<std::shared_ptr<config_listener>> config_listeners_{};
1700
- utils::movable_function<void()> on_stop_handler_{};
1701
-
1702
- std::atomic_bool bootstrapped_{ false };
1703
- std::atomic_bool stopped_{ false };
1704
- bool authenticated_{ false };
1705
- bool bucket_selected_{ false };
1706
- bool supports_gcccp_{ true };
1707
- bool retry_bootstrap_on_bucket_not_found_{ false };
1708
-
1709
- std::atomic<std::uint32_t> opaque_{ 0 };
1710
-
1711
- std::array<std::byte, 16384> input_buffer_{};
1712
- std::vector<std::vector<std::byte>> output_buffer_{};
1713
- std::vector<std::vector<std::byte>> pending_buffer_{};
1714
- std::vector<std::vector<std::byte>> writing_buffer_{};
1715
- std::mutex output_buffer_mutex_{};
1716
- std::mutex pending_buffer_mutex_{};
1717
- std::mutex writing_buffer_mutex_{};
1718
- std::string bootstrap_hostname_{};
1719
- std::string bootstrap_port_{};
1720
- std::string bootstrap_address_{};
1721
- std::uint16_t bootstrap_port_number_{};
1722
- connection_endpoints connection_endpoints_{ {}, {} };
1723
- asio::ip::tcp::resolver::results_type endpoints_;
1724
- std::vector<protocol::hello_feature> supported_features_;
1725
- std::optional<topology::configuration> config_;
1726
- mutable std::mutex config_mutex_{};
1727
- std::atomic_bool configured_{ false };
1728
- std::optional<error_map> error_map_;
1729
- collection_cache collection_cache_;
1730
-
1731
- const bool is_tls_;
1732
- std::shared_ptr<impl::bootstrap_state_listener> state_listener_{ nullptr };
1733
-
1734
- mcbp::codec codec_;
1735
- std::recursive_mutex operations_mutex_{};
1736
- std::map<std::uint32_t, std::pair<std::shared_ptr<mcbp::queue_request>, std::shared_ptr<response_handler>>> operations_{};
1737
-
1738
- std::atomic_bool reading_{ false };
1739
-
1740
- std::string log_prefix_{};
1741
- std::chrono::time_point<std::chrono::steady_clock> last_active_{};
1742
- std::atomic<diag::endpoint_state> state_{ diag::endpoint_state::disconnected };
1806
+ if (ec) {
1807
+ CB_LOG_ERROR(R"({} IO error while writing to the socket("{}"): {} ({}))",
1808
+ self->log_prefix_,
1809
+ self->stream_->id(),
1810
+ ec.value(),
1811
+ ec.message());
1812
+ return self->stop(retry_reason::socket_closed_while_in_flight);
1813
+ }
1814
+ {
1815
+ std::scoped_lock inner_lock(self->writing_buffer_mutex_);
1816
+ self->writing_buffer_.clear();
1817
+ }
1818
+ asio::post(asio::bind_executor(self->ctx_, [self]() {
1819
+ self->do_write();
1820
+ self->do_read();
1821
+ }));
1822
+ });
1823
+ }
1824
+
1825
+ const std::string client_id_;
1826
+ const std::string id_{ uuid::to_string(uuid::random()) };
1827
+ asio::io_context& ctx_;
1828
+ asio::ip::tcp::resolver resolver_;
1829
+ std::unique_ptr<stream_impl> stream_;
1830
+ asio::steady_timer bootstrap_deadline_;
1831
+ asio::steady_timer connection_deadline_;
1832
+ asio::steady_timer retry_backoff_;
1833
+ asio::steady_timer ping_deadline_;
1834
+ couchbase::core::origin origin_;
1835
+ std::optional<std::string> bucket_name_;
1836
+ mcbp_parser parser_;
1837
+ std::shared_ptr<bootstrap_handler> bootstrap_handler_{ nullptr };
1838
+ std::optional<std::string> last_bootstrap_error_message_;
1839
+ std::shared_ptr<message_handler> handler_{ nullptr };
1840
+ utils::movable_function<void(std::error_code, const topology::configuration&)>
1841
+ bootstrap_callback_{};
1842
+ std::mutex command_handlers_mutex_{};
1843
+ std::map<std::uint32_t, command_handler> command_handlers_{};
1844
+ std::vector<std::shared_ptr<config_listener>> config_listeners_{};
1845
+ utils::movable_function<void()> on_stop_handler_{};
1846
+
1847
+ std::atomic_bool bootstrapped_{ false };
1848
+ std::atomic_bool stopped_{ false };
1849
+ bool authenticated_{ false };
1850
+ bool bucket_selected_{ false };
1851
+ bool supports_gcccp_{ true };
1852
+ bool retry_bootstrap_on_bucket_not_found_{ false };
1853
+
1854
+ std::atomic<std::uint32_t> opaque_{ 0 };
1855
+
1856
+ std::array<std::byte, 16384> input_buffer_{};
1857
+ std::vector<std::vector<std::byte>> output_buffer_{};
1858
+ std::vector<std::vector<std::byte>> pending_buffer_{};
1859
+ std::vector<std::vector<std::byte>> writing_buffer_{};
1860
+ std::mutex output_buffer_mutex_{};
1861
+ std::mutex pending_buffer_mutex_{};
1862
+ std::mutex writing_buffer_mutex_{};
1863
+ std::string bootstrap_hostname_{};
1864
+ std::string bootstrap_port_{};
1865
+ std::string bootstrap_address_{};
1866
+ std::uint16_t bootstrap_port_number_{};
1867
+ connection_endpoints connection_endpoints_{ {}, {} };
1868
+ asio::ip::tcp::resolver::results_type endpoints_;
1869
+ std::vector<protocol::hello_feature> supported_features_;
1870
+ std::optional<topology::configuration> config_;
1871
+ mutable std::mutex config_mutex_{};
1872
+ std::atomic_bool configured_{ false };
1873
+ std::optional<error_map> error_map_;
1874
+ collection_cache collection_cache_;
1875
+
1876
+ const bool is_tls_;
1877
+ std::shared_ptr<impl::bootstrap_state_listener> state_listener_{ nullptr };
1878
+
1879
+ mcbp::codec codec_;
1880
+ std::recursive_mutex operations_mutex_{};
1881
+ std::map<std::uint32_t,
1882
+ std::pair<std::shared_ptr<mcbp::queue_request>, std::shared_ptr<response_handler>>>
1883
+ operations_{};
1884
+
1885
+ std::atomic_bool reading_{ false };
1886
+
1887
+ std::string log_prefix_{};
1888
+ std::chrono::time_point<std::chrono::steady_clock> last_active_{};
1889
+ std::atomic<diag::endpoint_state> state_{ diag::endpoint_state::disconnected };
1743
1890
  };
1744
1891
 
1745
1892
  mcbp_session::mcbp_session(std::string client_id,
@@ -1774,196 +1921,202 @@ mcbp_session::mcbp_session(std::string client_id,
1774
1921
  {
1775
1922
  }
1776
1923
 
1777
- const std::string&
1778
- mcbp_session::log_prefix() const
1924
+ auto
1925
+ mcbp_session::log_prefix() const -> const std::string&
1779
1926
  {
1780
- return impl_->log_prefix();
1927
+ return impl_->log_prefix();
1781
1928
  }
1782
1929
 
1783
- bool
1784
- mcbp_session::cancel(std::uint32_t opaque, std::error_code ec, retry_reason reason)
1930
+ auto
1931
+ mcbp_session::cancel(std::uint32_t opaque, std::error_code ec, retry_reason reason) -> bool
1785
1932
  {
1786
- return impl_->cancel(opaque, ec, reason);
1933
+ return impl_->cancel(opaque, ec, reason);
1787
1934
  }
1788
1935
 
1789
- bool
1790
- mcbp_session::is_stopped() const
1936
+ auto
1937
+ mcbp_session::is_stopped() const -> bool
1791
1938
  {
1792
- return impl_->is_stopped();
1939
+ return impl_->is_stopped();
1793
1940
  }
1794
1941
 
1795
- bool
1796
- mcbp_session::is_bootstrapped() const
1942
+ auto
1943
+ mcbp_session::is_bootstrapped() const -> bool
1797
1944
  {
1798
- return impl_->is_bootstrapped();
1945
+ return impl_->is_bootstrapped();
1799
1946
  }
1800
1947
 
1801
- std::uint32_t
1802
- mcbp_session::next_opaque()
1948
+ auto
1949
+ mcbp_session::next_opaque() -> std::uint32_t
1803
1950
  {
1804
- return impl_->next_opaque();
1951
+ return impl_->next_opaque();
1805
1952
  }
1806
1953
 
1807
- std::optional<std::uint32_t>
1808
- mcbp_session::get_collection_uid(const std::string& collection_path)
1954
+ auto
1955
+ mcbp_session::get_collection_uid(const std::string& collection_path) -> std::optional<std::uint32_t>
1809
1956
  {
1810
- return impl_->get_collection_uid(collection_path);
1957
+ return impl_->get_collection_uid(collection_path);
1811
1958
  }
1812
1959
 
1813
- mcbp_context
1814
- mcbp_session::context() const
1960
+ auto
1961
+ mcbp_session::context() const -> mcbp_context
1815
1962
  {
1816
- return impl_->context();
1963
+ return impl_->context();
1817
1964
  }
1818
1965
 
1819
- bool
1820
- mcbp_session::supports_feature(protocol::hello_feature feature)
1966
+ auto
1967
+ mcbp_session::supports_feature(protocol::hello_feature feature) -> bool
1821
1968
  {
1822
- return impl_->supports_feature(feature);
1969
+ return impl_->supports_feature(feature);
1823
1970
  }
1824
1971
 
1825
- const std::string&
1826
- mcbp_session::id() const
1972
+ auto
1973
+ mcbp_session::id() const -> const std::string&
1827
1974
  {
1828
- return impl_->id();
1975
+ return impl_->id();
1829
1976
  }
1830
1977
 
1831
- const std::string&
1832
- mcbp_session::bootstrap_address() const
1978
+ auto
1979
+ mcbp_session::bootstrap_address() const -> const std::string&
1833
1980
  {
1834
- return impl_->bootstrap_address();
1981
+ return impl_->bootstrap_address();
1835
1982
  }
1836
1983
 
1837
- std::string
1838
- mcbp_session::remote_address() const
1984
+ auto
1985
+ mcbp_session::remote_address() const -> std::string
1839
1986
  {
1840
- return impl_->remote_address();
1987
+ return impl_->remote_address();
1841
1988
  }
1842
1989
 
1843
- std::string
1844
- mcbp_session::local_address() const
1990
+ auto
1991
+ mcbp_session::local_address() const -> std::string
1845
1992
  {
1846
- return impl_->local_address();
1993
+ return impl_->local_address();
1847
1994
  }
1848
1995
 
1849
- const std::string&
1850
- mcbp_session::bootstrap_hostname() const
1996
+ auto
1997
+ mcbp_session::bootstrap_hostname() const -> const std::string&
1851
1998
  {
1852
- return impl_->bootstrap_hostname();
1999
+ return impl_->bootstrap_hostname();
1853
2000
  }
1854
2001
 
1855
- const std::string&
1856
- mcbp_session::bootstrap_port() const
2002
+ auto
2003
+ mcbp_session::bootstrap_port() const -> const std::string&
1857
2004
  {
1858
- return impl_->bootstrap_port();
2005
+ return impl_->bootstrap_port();
1859
2006
  }
1860
2007
 
1861
- std::uint16_t
1862
- mcbp_session::bootstrap_port_number() const
2008
+ auto
2009
+ mcbp_session::bootstrap_port_number() const -> std::uint16_t
1863
2010
  {
1864
- return impl_->bootstrap_port_number();
2011
+ return impl_->bootstrap_port_number();
1865
2012
  }
1866
2013
 
1867
2014
  void
1868
- mcbp_session::write_and_subscribe(std::uint32_t opaque, std::vector<std::byte>&& data, command_handler&& handler)
2015
+ mcbp_session::write_and_subscribe(std::uint32_t opaque,
2016
+ std::vector<std::byte>&& data,
2017
+ command_handler&& handler)
1869
2018
  {
1870
- return impl_->write_and_subscribe(opaque, std::move(data), std::move(handler));
2019
+ return impl_->write_and_subscribe(opaque, std::move(data), std::move(handler));
1871
2020
  }
1872
2021
 
1873
2022
  void
1874
- mcbp_session::bootstrap(utils::movable_function<void(std::error_code, topology::configuration)>&& handler, bool retry_on_bucket_not_found)
2023
+ mcbp_session::bootstrap(
2024
+ utils::movable_function<void(std::error_code, topology::configuration)>&& handler,
2025
+ bool retry_on_bucket_not_found)
1875
2026
  {
1876
- return impl_->bootstrap(std::move(handler), retry_on_bucket_not_found);
2027
+ return impl_->bootstrap(std::move(handler), retry_on_bucket_not_found);
1877
2028
  }
1878
2029
 
1879
2030
  void
1880
2031
  mcbp_session::on_stop(utils::movable_function<void()> handler)
1881
2032
  {
1882
- return impl_->on_stop(std::move(handler));
2033
+ return impl_->on_stop(std::move(handler));
1883
2034
  }
1884
2035
 
1885
2036
  void
1886
2037
  mcbp_session::stop(retry_reason reason)
1887
2038
  {
1888
- return impl_->stop(reason);
2039
+ return impl_->stop(reason);
1889
2040
  }
1890
2041
 
1891
- std::size_t
1892
- mcbp_session::index() const
2042
+ auto
2043
+ mcbp_session::index() const -> std::size_t
1893
2044
  {
1894
- return impl_->index();
2045
+ return impl_->index();
1895
2046
  }
1896
2047
 
1897
- std::optional<topology::configuration>
1898
- mcbp_session::config() const
2048
+ auto
2049
+ mcbp_session::config() const -> std::optional<topology::configuration>
1899
2050
  {
1900
- return impl_->config();
2051
+ return impl_->config();
1901
2052
  }
1902
2053
 
1903
- bool
1904
- mcbp_session::has_config() const
2054
+ auto
2055
+ mcbp_session::has_config() const -> bool
1905
2056
  {
1906
- return impl_->has_config();
2057
+ return impl_->has_config();
1907
2058
  }
1908
2059
 
1909
- diag::endpoint_diag_info
1910
- mcbp_session::diag_info() const
2060
+ auto
2061
+ mcbp_session::diag_info() const -> diag::endpoint_diag_info
1911
2062
  {
1912
- return impl_->diag_info();
2063
+ return impl_->diag_info();
1913
2064
  }
1914
2065
 
1915
2066
  void
1916
2067
  mcbp_session::on_configuration_update(std::shared_ptr<config_listener> handler)
1917
2068
  {
1918
- return impl_->on_configuration_update(std::move(handler));
2069
+ return impl_->on_configuration_update(std::move(handler));
1919
2070
  }
1920
2071
 
1921
- std::vector<protocol::hello_feature>
1922
- mcbp_session::supported_features() const
2072
+ auto
2073
+ mcbp_session::supported_features() const -> std::vector<protocol::hello_feature>
1923
2074
  {
1924
- return impl_->supported_features();
2075
+ return impl_->supported_features();
1925
2076
  }
1926
2077
 
1927
2078
  void
1928
- mcbp_session::ping(std::shared_ptr<diag::ping_reporter> handler, std::optional<std::chrono::milliseconds> timeout) const
2079
+ mcbp_session::ping(std::shared_ptr<diag::ping_reporter> handler,
2080
+ std::optional<std::chrono::milliseconds> timeout) const
1929
2081
  {
1930
- return impl_->ping(std::move(handler), std::move(timeout));
2082
+ return impl_->ping(std::move(handler), std::move(timeout));
1931
2083
  }
1932
2084
 
1933
- bool
1934
- mcbp_session::supports_gcccp() const
2085
+ auto
2086
+ mcbp_session::supports_gcccp() const -> bool
1935
2087
  {
1936
- return impl_->supports_gcccp();
2088
+ return impl_->supports_gcccp();
1937
2089
  }
1938
2090
 
1939
- std::optional<key_value_error_map_info>
1940
- mcbp_session::decode_error_code(std::uint16_t code)
2091
+ auto
2092
+ mcbp_session::decode_error_code(std::uint16_t code) -> std::optional<key_value_error_map_info>
1941
2093
  {
1942
- return impl_->decode_error_code(code);
2094
+ return impl_->decode_error_code(code);
1943
2095
  }
1944
2096
 
1945
2097
  void
1946
2098
  mcbp_session::handle_not_my_vbucket(const mcbp_message& msg) const
1947
2099
  {
1948
- return impl_->handle_not_my_vbucket(msg);
2100
+ return impl_->handle_not_my_vbucket(msg);
1949
2101
  }
1950
2102
 
1951
2103
  void
1952
2104
  mcbp_session::update_collection_uid(const std::string& path, std::uint32_t uid)
1953
2105
  {
1954
- return impl_->update_collection_uid(path, uid);
2106
+ return impl_->update_collection_uid(path, uid);
1955
2107
  }
1956
2108
 
1957
2109
  void
1958
- mcbp_session::write_and_subscribe(std::shared_ptr<mcbp::queue_request> request, std::shared_ptr<response_handler> handler)
2110
+ mcbp_session::write_and_subscribe(std::shared_ptr<mcbp::queue_request> request,
2111
+ std::shared_ptr<response_handler> handler)
1959
2112
  {
1960
- return impl_->write_and_subscribe(std::move(request), std::move(handler));
2113
+ return impl_->write_and_subscribe(std::move(request), std::move(handler));
1961
2114
  }
1962
2115
 
1963
2116
  void
1964
2117
  mcbp_session::write_and_flush(std::vector<std::byte>&& buffer)
1965
2118
  {
1966
- return impl_->write_and_flush(std::move(buffer));
2119
+ return impl_->write_and_flush(std::move(buffer));
1967
2120
  }
1968
2121
 
1969
2122
  } // namespace couchbase::core::io