couchbase 3.4.2 → 3.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (355) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/couchbase/CMakeLists.txt +71 -7
  4. data/ext/couchbase/cmake/Documentation.cmake +0 -1
  5. data/ext/couchbase/cmake/OpenSSL.cmake +98 -3
  6. data/ext/couchbase/cmake/Testing.cmake +12 -4
  7. data/ext/couchbase/cmake/build_config.hxx.in +3 -0
  8. data/ext/couchbase/core/bucket.cxx +183 -151
  9. data/ext/couchbase/core/bucket.hxx +23 -1
  10. data/ext/couchbase/core/cluster.hxx +51 -13
  11. data/ext/couchbase/core/cluster_options.cxx +2 -2
  12. data/ext/couchbase/core/cluster_options.hxx +7 -6
  13. data/ext/couchbase/core/cluster_options_fwd.hxx +26 -0
  14. data/ext/couchbase/core/config_profile.hxx +1 -54
  15. data/ext/couchbase/core/config_profiles.cxx +79 -0
  16. data/ext/couchbase/core/config_profiles.hxx +56 -0
  17. data/ext/couchbase/core/crud_component.cxx +51 -22
  18. data/ext/couchbase/core/error_context/key_value.cxx +2 -1
  19. data/ext/couchbase/core/error_context/key_value.hxx +10 -12
  20. data/ext/couchbase/core/error_context/search.hxx +1 -1
  21. data/ext/couchbase/core/impl/analytics.cxx +1 -0
  22. data/ext/couchbase/core/impl/boolean_field_query.cxx +40 -0
  23. data/ext/couchbase/core/impl/boolean_query.cxx +62 -0
  24. data/ext/couchbase/core/impl/build_deferred_query_indexes.cxx +115 -50
  25. data/ext/couchbase/core/impl/cluster.cxx +8 -0
  26. data/ext/couchbase/core/impl/conjunction_query.cxx +51 -0
  27. data/ext/couchbase/core/impl/create_bucket.cxx +155 -0
  28. data/ext/couchbase/core/impl/create_query_index.cxx +172 -59
  29. data/ext/couchbase/core/impl/date_range.cxx +89 -0
  30. data/ext/couchbase/core/impl/date_range_facet.cxx +54 -0
  31. data/ext/couchbase/core/impl/date_range_facet_result.cxx +64 -0
  32. data/ext/couchbase/core/impl/date_range_query.cxx +125 -0
  33. data/ext/couchbase/core/impl/disjunction_query.cxx +51 -0
  34. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +2 -1
  35. data/ext/couchbase/core/impl/drop_bucket.cxx +66 -0
  36. data/ext/couchbase/core/impl/drop_query_index.cxx +138 -59
  37. data/ext/couchbase/core/impl/encoded_search_facet.hxx +29 -0
  38. data/ext/couchbase/core/impl/encoded_search_query.hxx +29 -0
  39. data/ext/couchbase/core/impl/encoded_search_sort.hxx +29 -0
  40. data/ext/couchbase/core/impl/flush_bucket.cxx +66 -0
  41. data/ext/couchbase/core/impl/geo_bounding_box_query.cxx +46 -0
  42. data/ext/couchbase/core/impl/geo_distance_query.cxx +43 -0
  43. data/ext/couchbase/core/impl/geo_polygon_query.cxx +46 -0
  44. data/ext/couchbase/core/impl/get_all_buckets.cxx +163 -0
  45. data/ext/couchbase/core/impl/get_all_query_indexes.cxx +67 -37
  46. data/ext/couchbase/core/impl/get_bucket.cxx +153 -0
  47. data/ext/couchbase/core/impl/internal_date_range_facet_result.cxx +80 -0
  48. data/ext/couchbase/core/impl/internal_date_range_facet_result.hxx +48 -0
  49. data/ext/couchbase/core/impl/internal_manager_error_context.cxx +113 -0
  50. data/ext/couchbase/core/impl/internal_manager_error_context.hxx +60 -0
  51. data/ext/couchbase/core/impl/internal_numeric_range_facet_result.cxx +80 -0
  52. data/ext/couchbase/core/impl/internal_numeric_range_facet_result.hxx +48 -0
  53. data/ext/couchbase/core/impl/internal_search_error_context.cxx +141 -0
  54. data/ext/couchbase/core/impl/internal_search_error_context.hxx +61 -0
  55. data/ext/couchbase/core/impl/internal_search_meta_data.cxx +60 -0
  56. data/ext/couchbase/core/impl/internal_search_meta_data.hxx +41 -0
  57. data/ext/couchbase/core/impl/internal_search_result.cxx +84 -0
  58. data/ext/couchbase/core/impl/internal_search_result.hxx +43 -0
  59. data/ext/couchbase/core/impl/internal_search_row.cxx +82 -0
  60. data/ext/couchbase/core/impl/internal_search_row.hxx +56 -0
  61. data/ext/couchbase/core/impl/internal_search_row_location.hxx +32 -0
  62. data/ext/couchbase/core/impl/internal_search_row_locations.cxx +137 -0
  63. data/ext/couchbase/core/impl/internal_search_row_locations.hxx +45 -0
  64. data/ext/couchbase/core/impl/internal_term_facet_result.cxx +80 -0
  65. data/ext/couchbase/core/impl/internal_term_facet_result.hxx +48 -0
  66. data/ext/couchbase/core/impl/key_value_error_category.cxx +2 -4
  67. data/ext/couchbase/core/impl/key_value_error_context.cxx +98 -0
  68. data/ext/couchbase/core/impl/lookup_in.cxx +1 -0
  69. data/ext/couchbase/core/impl/lookup_in_all_replicas.cxx +176 -0
  70. data/ext/couchbase/core/impl/lookup_in_all_replicas.hxx +80 -0
  71. data/ext/couchbase/core/impl/lookup_in_any_replica.cxx +167 -0
  72. data/ext/couchbase/core/impl/lookup_in_any_replica.hxx +75 -0
  73. data/ext/couchbase/core/impl/lookup_in_replica.cxx +97 -0
  74. data/ext/couchbase/core/impl/lookup_in_replica.hxx +67 -0
  75. data/ext/couchbase/core/impl/manager_error_context.cxx +100 -0
  76. data/ext/couchbase/core/impl/match_all_query.cxx +35 -0
  77. data/ext/couchbase/core/impl/match_none_query.cxx +35 -0
  78. data/ext/couchbase/core/impl/match_phrase_query.cxx +43 -0
  79. data/ext/couchbase/core/impl/match_query.cxx +59 -0
  80. data/ext/couchbase/core/impl/numeric_range.cxx +49 -0
  81. data/ext/couchbase/core/impl/numeric_range_facet.cxx +54 -0
  82. data/ext/couchbase/core/impl/numeric_range_facet_result.cxx +64 -0
  83. data/ext/couchbase/core/impl/numeric_range_query.cxx +56 -0
  84. data/ext/couchbase/core/impl/phrase_query.cxx +42 -0
  85. data/ext/couchbase/core/impl/prefix_query.cxx +40 -0
  86. data/ext/couchbase/core/impl/query.cxx +1 -0
  87. data/ext/couchbase/core/impl/query_error_context.cxx +75 -0
  88. data/ext/couchbase/core/impl/query_string_query.cxx +37 -0
  89. data/ext/couchbase/core/impl/regexp_query.cxx +40 -0
  90. data/ext/couchbase/core/impl/search.cxx +191 -0
  91. data/ext/couchbase/core/impl/search_error_context.cxx +147 -0
  92. data/ext/couchbase/core/impl/search_meta_data.cxx +46 -0
  93. data/ext/couchbase/core/impl/search_result.cxx +66 -0
  94. data/ext/couchbase/core/impl/search_row.cxx +74 -0
  95. data/ext/couchbase/core/impl/search_row_location.cxx +64 -0
  96. data/ext/couchbase/core/impl/search_row_locations.cxx +66 -0
  97. data/ext/couchbase/core/impl/search_sort_field.cxx +104 -0
  98. data/ext/couchbase/core/impl/search_sort_id.cxx +43 -0
  99. data/ext/couchbase/core/impl/search_sort_score.cxx +43 -0
  100. data/ext/couchbase/core/impl/term_facet.cxx +36 -0
  101. data/ext/couchbase/core/impl/term_facet_result.cxx +64 -0
  102. data/ext/couchbase/core/impl/term_query.cxx +56 -0
  103. data/ext/couchbase/core/impl/term_range_query.cxx +57 -0
  104. data/ext/couchbase/core/impl/update_bucket.cxx +130 -0
  105. data/ext/couchbase/core/impl/watch_query_indexes.cxx +53 -29
  106. data/ext/couchbase/core/impl/wildcard_query.cxx +40 -0
  107. data/ext/couchbase/core/io/dns_client.cxx +111 -40
  108. data/ext/couchbase/core/io/dns_config.cxx +5 -4
  109. data/ext/couchbase/core/io/http_context.hxx +1 -1
  110. data/ext/couchbase/core/io/http_session.hxx +34 -1
  111. data/ext/couchbase/core/io/http_session_manager.hxx +5 -3
  112. data/ext/couchbase/core/io/mcbp_command.hxx +9 -2
  113. data/ext/couchbase/core/io/mcbp_session.cxx +106 -42
  114. data/ext/couchbase/core/io/mcbp_session.hxx +4 -3
  115. data/ext/couchbase/core/io/retry_orchestrator.hxx +3 -2
  116. data/ext/couchbase/core/json_string.hxx +5 -0
  117. data/ext/couchbase/core/logger/custom_rotating_file_sink.cxx +1 -1
  118. data/ext/couchbase/core/logger/logger.cxx +80 -20
  119. data/ext/couchbase/core/logger/logger.hxx +31 -0
  120. data/ext/couchbase/core/meta/features.hxx +25 -0
  121. data/ext/couchbase/core/meta/version.cxx +18 -4
  122. data/ext/couchbase/core/mozilla_ca_bundle.hxx +39 -0
  123. data/ext/couchbase/core/operations/document_analytics.cxx +1 -0
  124. data/ext/couchbase/core/operations/document_analytics.hxx +1 -0
  125. data/ext/couchbase/core/operations/document_append.hxx +1 -1
  126. data/ext/couchbase/core/operations/document_decrement.hxx +1 -1
  127. data/ext/couchbase/core/operations/document_exists.hxx +1 -1
  128. data/ext/couchbase/core/operations/document_get.hxx +1 -1
  129. data/ext/couchbase/core/operations/document_get_and_lock.hxx +1 -1
  130. data/ext/couchbase/core/operations/document_get_and_touch.hxx +1 -1
  131. data/ext/couchbase/core/operations/document_get_projected.hxx +1 -1
  132. data/ext/couchbase/core/operations/document_increment.hxx +1 -1
  133. data/ext/couchbase/core/operations/document_insert.hxx +1 -1
  134. data/ext/couchbase/core/operations/document_lookup_in.hxx +1 -1
  135. data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +192 -0
  136. data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +188 -0
  137. data/ext/couchbase/core/operations/document_mutate_in.hxx +1 -1
  138. data/ext/couchbase/core/operations/document_prepend.hxx +1 -1
  139. data/ext/couchbase/core/operations/document_query.cxx +13 -0
  140. data/ext/couchbase/core/operations/document_query.hxx +7 -0
  141. data/ext/couchbase/core/operations/document_remove.hxx +1 -1
  142. data/ext/couchbase/core/operations/document_replace.hxx +1 -1
  143. data/ext/couchbase/core/operations/document_search.cxx +4 -1
  144. data/ext/couchbase/core/operations/document_search.hxx +2 -1
  145. data/ext/couchbase/core/operations/document_touch.hxx +1 -1
  146. data/ext/couchbase/core/operations/document_unlock.hxx +1 -1
  147. data/ext/couchbase/core/operations/document_upsert.hxx +1 -1
  148. data/ext/couchbase/core/operations/document_view.hxx +1 -0
  149. data/ext/couchbase/core/operations.hxx +2 -0
  150. data/ext/couchbase/core/origin.cxx +270 -0
  151. data/ext/couchbase/core/origin.hxx +2 -0
  152. data/ext/couchbase/core/protocol/client_request.hxx +11 -2
  153. data/ext/couchbase/core/protocol/client_response.hxx +1 -0
  154. data/ext/couchbase/core/protocol/cmd_hello.hxx +1 -0
  155. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.cxx +107 -0
  156. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.hxx +137 -0
  157. data/ext/couchbase/core/protocol/hello_feature.hxx +6 -0
  158. data/ext/couchbase/core/protocol/hello_feature_fmt.hxx +3 -0
  159. data/ext/couchbase/core/protocol/status.cxx +2 -2
  160. data/ext/couchbase/core/public_fwd.hxx +21 -0
  161. data/ext/couchbase/core/range_scan_options.cxx +3 -27
  162. data/ext/couchbase/core/range_scan_options.hxx +13 -17
  163. data/ext/couchbase/core/range_scan_orchestrator.cxx +388 -170
  164. data/ext/couchbase/core/range_scan_orchestrator.hxx +13 -2
  165. data/ext/couchbase/core/range_scan_orchestrator_options.hxx +5 -3
  166. data/ext/couchbase/core/scan_options.hxx +0 -19
  167. data/ext/couchbase/core/scan_result.cxx +19 -5
  168. data/ext/couchbase/core/scan_result.hxx +5 -2
  169. data/ext/couchbase/core/timeout_defaults.hxx +2 -3
  170. data/ext/couchbase/core/tls_verify_mode.hxx +26 -0
  171. data/ext/couchbase/core/topology/capabilities.hxx +3 -0
  172. data/ext/couchbase/core/topology/capabilities_fmt.hxx +8 -0
  173. data/ext/couchbase/core/topology/collections_manifest_fmt.hxx +1 -1
  174. data/ext/couchbase/core/topology/configuration.cxx +15 -2
  175. data/ext/couchbase/core/topology/configuration.hxx +20 -1
  176. data/ext/couchbase/core/topology/configuration_json.hxx +6 -1
  177. data/ext/couchbase/core/transactions/attempt_context_testing_hooks.cxx +93 -0
  178. data/ext/couchbase/core/transactions/attempt_context_testing_hooks.hxx +48 -75
  179. data/ext/couchbase/core/transactions/cleanup_testing_hooks.cxx +52 -0
  180. data/ext/couchbase/core/transactions/cleanup_testing_hooks.hxx +17 -31
  181. data/ext/couchbase/core/transactions/exceptions.hxx +12 -9
  182. data/ext/couchbase/core/utils/connection_string.cxx +75 -43
  183. data/ext/couchbase/core/utils/connection_string.hxx +1 -0
  184. data/ext/couchbase/core/utils/json.cxx +4 -1
  185. data/ext/couchbase/couchbase/analytics_error_context.hxx +1 -1
  186. data/ext/couchbase/couchbase/behavior_options.hxx +27 -1
  187. data/ext/couchbase/couchbase/boolean_field_query.hxx +77 -0
  188. data/ext/couchbase/couchbase/boolean_query.hxx +223 -0
  189. data/ext/couchbase/couchbase/bucket_manager.hxx +135 -0
  190. data/ext/couchbase/couchbase/build_query_index_options.hxx +0 -30
  191. data/ext/couchbase/couchbase/cluster.hxx +56 -1
  192. data/ext/couchbase/couchbase/collection.hxx +111 -0
  193. data/ext/couchbase/couchbase/collection_query_index_manager.hxx +7 -48
  194. data/ext/couchbase/couchbase/conjunction_query.hxx +88 -0
  195. data/ext/couchbase/couchbase/create_bucket_options.hxx +41 -0
  196. data/ext/couchbase/couchbase/create_primary_query_index_options.hxx +0 -29
  197. data/ext/couchbase/couchbase/create_query_index_options.hxx +0 -33
  198. data/ext/couchbase/couchbase/date_range.hxx +69 -0
  199. data/ext/couchbase/couchbase/date_range_facet.hxx +56 -0
  200. data/ext/couchbase/couchbase/date_range_facet_result.hxx +55 -0
  201. data/ext/couchbase/couchbase/date_range_query.hxx +265 -0
  202. data/ext/couchbase/couchbase/disjunction_query.hxx +109 -0
  203. data/ext/couchbase/couchbase/doc_id_query.hxx +111 -0
  204. data/ext/couchbase/couchbase/drop_bucket_options.hxx +41 -0
  205. data/ext/couchbase/couchbase/drop_primary_query_index_options.hxx +0 -30
  206. data/ext/couchbase/couchbase/drop_query_index_options.hxx +0 -31
  207. data/ext/couchbase/couchbase/error_codes.hxx +1 -2
  208. data/ext/couchbase/couchbase/error_context.hxx +17 -8
  209. data/ext/couchbase/couchbase/flush_bucket_options.hxx +41 -0
  210. data/ext/couchbase/couchbase/fmt/analytics_scan_consistency.hxx +52 -0
  211. data/ext/couchbase/{core/topology/error_map_fmt.hxx → couchbase/fmt/key_value_error_map_attribute.hxx} +21 -21
  212. data/ext/couchbase/couchbase/fmt/search_scan_consistency.hxx +49 -0
  213. data/ext/couchbase/couchbase/geo_bounding_box_query.hxx +107 -0
  214. data/ext/couchbase/couchbase/geo_distance_query.hxx +109 -0
  215. data/ext/couchbase/couchbase/geo_point.hxx +32 -0
  216. data/ext/couchbase/couchbase/geo_polygon_query.hxx +85 -0
  217. data/ext/couchbase/couchbase/get_all_buckets_options.hxx +44 -0
  218. data/ext/couchbase/couchbase/get_all_query_indexes_options.hxx +0 -30
  219. data/ext/couchbase/couchbase/get_and_lock_options.hxx +2 -2
  220. data/ext/couchbase/couchbase/get_and_touch_options.hxx +2 -2
  221. data/ext/couchbase/couchbase/get_bucket_options.hxx +43 -0
  222. data/ext/couchbase/couchbase/get_options.hxx +2 -2
  223. data/ext/couchbase/couchbase/highlight_style.hxx +45 -0
  224. data/ext/couchbase/couchbase/insert_options.hxx +3 -3
  225. data/ext/couchbase/couchbase/key_value_error_context.hxx +7 -2
  226. data/ext/couchbase/couchbase/lookup_in_all_replicas_options.hxx +109 -0
  227. data/ext/couchbase/couchbase/lookup_in_any_replica_options.hxx +101 -0
  228. data/ext/couchbase/couchbase/lookup_in_options.hxx +2 -2
  229. data/ext/couchbase/couchbase/lookup_in_replica_result.hxx +74 -0
  230. data/ext/couchbase/couchbase/lookup_in_result.hxx +26 -0
  231. data/ext/couchbase/couchbase/management/bucket_settings.hxx +116 -0
  232. data/ext/couchbase/couchbase/manager_error_context.hxx +29 -53
  233. data/ext/couchbase/couchbase/match_all_query.hxx +43 -0
  234. data/ext/couchbase/couchbase/match_none_query.hxx +43 -0
  235. data/ext/couchbase/couchbase/match_operator.hxx +45 -0
  236. data/ext/couchbase/couchbase/match_phrase_query.hxx +108 -0
  237. data/ext/couchbase/couchbase/match_query.hxx +163 -0
  238. data/ext/couchbase/couchbase/mutate_in_options.hxx +2 -2
  239. data/ext/couchbase/couchbase/numeric_range.hxx +58 -0
  240. data/ext/couchbase/couchbase/numeric_range_facet.hxx +56 -0
  241. data/ext/couchbase/couchbase/numeric_range_facet_result.hxx +55 -0
  242. data/ext/couchbase/couchbase/numeric_range_query.hxx +143 -0
  243. data/ext/couchbase/couchbase/phrase_query.hxx +93 -0
  244. data/ext/couchbase/couchbase/prefix_query.hxx +82 -0
  245. data/ext/couchbase/couchbase/query_error_context.hxx +3 -1
  246. data/ext/couchbase/couchbase/query_index_manager.hxx +16 -83
  247. data/ext/couchbase/couchbase/query_options.hxx +18 -0
  248. data/ext/couchbase/couchbase/query_string_query.hxx +72 -0
  249. data/ext/couchbase/couchbase/regexp_query.hxx +82 -0
  250. data/ext/couchbase/couchbase/remove_options.hxx +2 -2
  251. data/ext/couchbase/couchbase/replace_options.hxx +3 -3
  252. data/ext/couchbase/couchbase/scope.hxx +40 -0
  253. data/ext/couchbase/couchbase/search_date_range.hxx +68 -0
  254. data/ext/couchbase/couchbase/search_error_context.hxx +138 -0
  255. data/ext/couchbase/couchbase/search_facet.hxx +60 -0
  256. data/ext/couchbase/couchbase/search_facet_result.hxx +50 -0
  257. data/ext/couchbase/couchbase/search_meta_data.hxx +85 -0
  258. data/ext/couchbase/couchbase/search_metrics.hxx +127 -0
  259. data/ext/couchbase/couchbase/search_numeric_range.hxx +69 -0
  260. data/ext/couchbase/couchbase/search_options.hxx +509 -0
  261. data/ext/couchbase/couchbase/search_query.hxx +69 -0
  262. data/ext/couchbase/couchbase/search_result.hxx +77 -0
  263. data/ext/couchbase/couchbase/search_row.hxx +104 -0
  264. data/ext/couchbase/couchbase/search_row_location.hxx +55 -0
  265. data/ext/couchbase/couchbase/search_row_locations.hxx +86 -0
  266. data/ext/couchbase/couchbase/search_scan_consistency.hxx +34 -0
  267. data/ext/couchbase/couchbase/search_sort.hxx +58 -0
  268. data/ext/couchbase/couchbase/search_sort_field.hxx +117 -0
  269. data/ext/couchbase/couchbase/search_sort_field_missing.hxx +26 -0
  270. data/ext/couchbase/couchbase/search_sort_field_mode.hxx +27 -0
  271. data/ext/couchbase/couchbase/search_sort_field_type.hxx +28 -0
  272. data/ext/couchbase/couchbase/search_sort_id.hxx +60 -0
  273. data/ext/couchbase/couchbase/search_sort_score.hxx +60 -0
  274. data/ext/couchbase/couchbase/search_term_range.hxx +51 -0
  275. data/ext/couchbase/couchbase/security_options.hxx +18 -0
  276. data/ext/couchbase/couchbase/subdocument_error_context.hxx +4 -2
  277. data/ext/couchbase/couchbase/term_facet.hxx +48 -0
  278. data/ext/couchbase/couchbase/term_facet_result.hxx +55 -0
  279. data/ext/couchbase/couchbase/term_query.hxx +151 -0
  280. data/ext/couchbase/couchbase/term_range_query.hxx +142 -0
  281. data/ext/couchbase/couchbase/touch_options.hxx +2 -2
  282. data/ext/couchbase/couchbase/tracing/request_span.hxx +63 -0
  283. data/ext/couchbase/couchbase/tracing/request_tracer.hxx +2 -40
  284. data/ext/couchbase/couchbase/transactions/async_attempt_context.hxx +83 -4
  285. data/ext/couchbase/couchbase/transactions/attempt_context.hxx +67 -0
  286. data/ext/couchbase/couchbase/transactions/transaction_get_result.hxx +2 -0
  287. data/ext/couchbase/couchbase/transactions/transaction_keyspace.hxx +11 -1
  288. data/ext/couchbase/couchbase/transactions/transaction_options.hxx +79 -8
  289. data/ext/couchbase/couchbase/transactions/transaction_query_options.hxx +128 -15
  290. data/ext/couchbase/couchbase/transactions/transaction_query_result.hxx +4 -0
  291. data/ext/couchbase/couchbase/transactions/transaction_result.hxx +1 -1
  292. data/ext/couchbase/couchbase/transactions/transactions_cleanup_config.hxx +5 -3
  293. data/ext/couchbase/couchbase/transactions/transactions_config.hxx +9 -5
  294. data/ext/couchbase/couchbase/transactions/transactions_query_config.hxx +6 -3
  295. data/ext/couchbase/couchbase/transactions.hxx +34 -1
  296. data/ext/couchbase/couchbase/unlock_options.hxx +2 -2
  297. data/ext/couchbase/couchbase/update_bucket_options.hxx +41 -0
  298. data/ext/couchbase/couchbase/upsert_options.hxx +3 -3
  299. data/ext/couchbase/couchbase/watch_query_indexes_options.hxx +0 -31
  300. data/ext/couchbase/couchbase/wildcard_query.hxx +83 -0
  301. data/ext/couchbase/test/CMakeLists.txt +8 -5
  302. data/ext/couchbase/test/benchmark_helper_integration.hxx +2 -2
  303. data/ext/couchbase/test/test_helper.hxx +5 -5
  304. data/ext/couchbase/test/test_integration_analytics.cxx +28 -6
  305. data/ext/couchbase/test/test_integration_collections.cxx +13 -3
  306. data/ext/couchbase/test/test_integration_connect.cxx +7 -3
  307. data/ext/couchbase/test/test_integration_crud.cxx +18 -3
  308. data/ext/couchbase/test/test_integration_diagnostics.cxx +11 -5
  309. data/ext/couchbase/test/test_integration_durability.cxx +12 -7
  310. data/ext/couchbase/test/test_integration_examples.cxx +419 -11
  311. data/ext/couchbase/test/test_integration_management.cxx +867 -368
  312. data/ext/couchbase/test/test_integration_query.cxx +87 -17
  313. data/ext/couchbase/test/test_integration_range_scan.cxx +363 -124
  314. data/ext/couchbase/test/test_integration_read_replica.cxx +48 -11
  315. data/ext/couchbase/test/test_integration_search.cxx +32 -3
  316. data/ext/couchbase/test/test_integration_subdoc.cxx +717 -11
  317. data/ext/couchbase/test/test_integration_tracer.cxx +5 -0
  318. data/ext/couchbase/test/test_integration_transcoders.cxx +13 -5
  319. data/ext/couchbase/test/{test_transaction_transaction_context.cxx → test_transaction_context.cxx} +1 -1
  320. data/ext/couchbase/test/test_transaction_examples.cxx +195 -0
  321. data/ext/couchbase/test/{test_transaction_transaction_public_async_api.cxx → test_transaction_public_async_api.cxx} +13 -12
  322. data/ext/couchbase/test/{test_transaction_transaction_public_blocking_api.cxx → test_transaction_public_blocking_api.cxx} +27 -21
  323. data/ext/couchbase/test/{test_transaction_transaction_simple.cxx → test_transaction_simple.cxx} +17 -5
  324. data/ext/couchbase/test/{test_transaction_transaction_simple_async.cxx → test_transaction_simple_async.cxx} +19 -21
  325. data/ext/couchbase/test/test_unit_config_profiles.cxx +1 -1
  326. data/ext/couchbase/test/test_unit_connection_string.cxx +29 -0
  327. data/ext/couchbase/test/test_unit_json_transcoder.cxx +4 -0
  328. data/ext/couchbase/test/test_unit_query.cxx +75 -0
  329. data/ext/couchbase/test/test_unit_search.cxx +427 -0
  330. data/ext/couchbase/test/test_unit_transaction_utils.cxx +10 -1
  331. data/ext/couchbase/test/test_unit_utils.cxx +8 -4
  332. data/ext/couchbase.cxx +641 -45
  333. data/ext/revisions.rb +3 -3
  334. data/lib/couchbase/authenticator.rb +0 -1
  335. data/lib/couchbase/cluster.rb +1 -5
  336. data/lib/couchbase/collection.rb +108 -0
  337. data/lib/couchbase/collection_options.rb +100 -0
  338. data/lib/couchbase/config_profiles.rb +1 -1
  339. data/lib/couchbase/errors.rb +5 -0
  340. data/lib/couchbase/json_transcoder.rb +12 -5
  341. data/lib/couchbase/key_value_scan.rb +125 -0
  342. data/lib/couchbase/management/collection_query_index_manager.rb +54 -15
  343. data/lib/couchbase/management/query_index_manager.rb +70 -5
  344. data/lib/couchbase/options.rb +151 -0
  345. data/lib/couchbase/raw_binary_transcoder.rb +37 -0
  346. data/lib/couchbase/raw_json_transcoder.rb +38 -0
  347. data/lib/couchbase/raw_string_transcoder.rb +40 -0
  348. data/lib/couchbase/scope.rb +1 -1
  349. data/lib/couchbase/search_options.rb +5 -0
  350. data/lib/couchbase/transcoder_flags.rb +62 -0
  351. data/lib/couchbase/utils/time.rb +14 -1
  352. data/lib/couchbase/version.rb +1 -1
  353. metadata +175 -13
  354. data/ext/couchbase/core/config_profile.cxx +0 -47
  355. data/ext/couchbase/core/impl/collection_query_index_manager.cxx +0 -93
@@ -40,12 +40,12 @@ populate_documents_for_range_scan(const couchbase::collection& collection,
40
40
  options.expiry(expiry.value());
41
41
  }
42
42
 
43
- std::map<std::vector<std::byte>, couchbase::mutation_token> mutations;
43
+ std::map<std::string, couchbase::mutation_token> mutations;
44
44
  for (const auto& id : ids) {
45
45
  auto [ctx, resp] = collection.upsert<couchbase::codec::raw_binary_transcoder>(id, value, options).get();
46
46
  REQUIRE_SUCCESS(ctx.ec());
47
47
  REQUIRE(resp.mutation_token().has_value());
48
- mutations[couchbase::core::utils::to_binary(id)] = resp.mutation_token().value();
48
+ mutations[id] = resp.mutation_token().value();
49
49
  }
50
50
  return mutations;
51
51
  }
@@ -76,7 +76,6 @@ do_range_scan(couchbase::core::agent agent,
76
76
  std::vector<couchbase::core::range_scan_item> data;
77
77
 
78
78
  auto options = continue_options;
79
- options.ids_only = create_options.ids_only; // support servers before MB-54267. TODO: remove after server GA
80
79
 
81
80
  do {
82
81
  auto barrier = std::make_shared<std::promise<std::pair<couchbase::core::range_scan_continue_result, std::error_code>>>();
@@ -115,12 +114,32 @@ make_binary_value(std::size_t number_of_bytes)
115
114
  return value;
116
115
  }
117
116
 
117
+ static couchbase::core::topology::configuration::vbucket_map
118
+ get_vbucket_map(test::utils::integration_test_guard& integration)
119
+ {
120
+ auto barrier = std::make_shared<std::promise<tl::expected<couchbase::core::topology::configuration::vbucket_map, std::error_code>>>();
121
+ auto f = barrier->get_future();
122
+ integration.cluster->with_bucket_configuration(
123
+ integration.ctx.bucket, [barrier](std::error_code ec, const couchbase::core::topology::configuration& config) mutable {
124
+ if (ec) {
125
+ return barrier->set_value(tl::unexpected(ec));
126
+ }
127
+ if (!config.vbmap || config.vbmap->empty()) {
128
+ return barrier->set_value(tl::unexpected(couchbase::errc::common::feature_not_available));
129
+ }
130
+ barrier->set_value(config.vbmap.value());
131
+ });
132
+ auto vbucket_map = f.get();
133
+ EXPECT_SUCCESS(vbucket_map);
134
+ return vbucket_map.value();
135
+ }
136
+
118
137
  TEST_CASE("integration: range scan large values", "[integration]")
119
138
  {
120
139
  test::utils::integration_test_guard integration;
121
140
 
122
141
  if (!integration.has_bucket_capability("range_scan")) {
123
- return;
142
+ SKIP("cluster does not support range_scan");
124
143
  }
125
144
 
126
145
  auto collection = couchbase::cluster(integration.cluster)
@@ -148,8 +167,8 @@ TEST_CASE("integration: range scan large values", "[integration]")
148
167
  couchbase::scope::default_name,
149
168
  couchbase::collection::default_name,
150
169
  couchbase::core::range_scan{
151
- { couchbase::core::utils::to_binary("largevalues") },
152
- { couchbase::core::utils::to_binary("largevalues\xff") },
170
+ couchbase::core::scan_term{ "largevalues" },
171
+ couchbase::core::scan_term{ "largevalues\xff" },
153
172
  },
154
173
  };
155
174
  create_options.snapshot_requirements = couchbase::core::range_snapshot_requirements{
@@ -176,7 +195,7 @@ TEST_CASE("integration: range scan small values", "[integration]")
176
195
  test::utils::integration_test_guard integration;
177
196
 
178
197
  if (!integration.has_bucket_capability("range_scan")) {
179
- return;
198
+ SKIP("cluster does not support range_scan");
180
199
  }
181
200
 
182
201
  auto collection = couchbase::cluster(integration.cluster)
@@ -208,8 +227,8 @@ TEST_CASE("integration: range scan small values", "[integration]")
208
227
  couchbase::scope::default_name,
209
228
  couchbase::collection::default_name,
210
229
  couchbase::core::range_scan{
211
- { couchbase::core::utils::to_binary("rangesmallvalues") },
212
- { couchbase::core::utils::to_binary("rangesmallvalues\xff") },
230
+ couchbase::core::scan_term{ "rangesmallvalues" },
231
+ couchbase::core::scan_term{ "rangesmallvalues\xff" },
213
232
  },
214
233
  };
215
234
  create_options.snapshot_requirements = couchbase::core::range_snapshot_requirements{
@@ -274,7 +293,7 @@ TEST_CASE("integration: range scan collection retry", "[integration]")
274
293
  test::utils::integration_test_guard integration;
275
294
 
276
295
  if (!integration.has_bucket_capability("range_scan")) {
277
- return;
296
+ SKIP("cluster does not support range_scan");
278
297
  }
279
298
 
280
299
  collection_guard new_collection(integration);
@@ -312,8 +331,8 @@ TEST_CASE("integration: range scan collection retry", "[integration]")
312
331
  couchbase::scope::default_name,
313
332
  new_collection.name(),
314
333
  couchbase::core::range_scan{
315
- { couchbase::core::utils::to_binary("rangecollectionretry") },
316
- { couchbase::core::utils::to_binary("rangecollectionretry\xff") },
334
+ couchbase::core::scan_term{ "rangecollectionretry" },
335
+ couchbase::core::scan_term{ "rangecollectionretry\xff" },
317
336
  },
318
337
  };
319
338
  create_options.snapshot_requirements = couchbase::core::range_snapshot_requirements{
@@ -340,7 +359,7 @@ TEST_CASE("integration: range scan only keys", "[integration]")
340
359
  test::utils::integration_test_guard integration;
341
360
 
342
361
  if (!integration.has_bucket_capability("range_scan")) {
343
- return;
362
+ SKIP("cluster does not support range_scan");
344
363
  }
345
364
 
346
365
  auto collection = couchbase::cluster(integration.cluster)
@@ -372,8 +391,8 @@ TEST_CASE("integration: range scan only keys", "[integration]")
372
391
  couchbase::scope::default_name,
373
392
  couchbase::collection::default_name,
374
393
  couchbase::core::range_scan{
375
- { couchbase::core::utils::to_binary("rangekeysonly") },
376
- { couchbase::core::utils::to_binary("rangekeysonly\xff") },
394
+ couchbase::core::scan_term{ "rangekeysonly" },
395
+ couchbase::core::scan_term{ "rangekeysonly\xff" },
377
396
  },
378
397
  };
379
398
  create_options.ids_only = true;
@@ -399,7 +418,7 @@ TEST_CASE("integration: range scan cancellation before continue", "[integration]
399
418
  test::utils::integration_test_guard integration;
400
419
 
401
420
  if (!integration.has_bucket_capability("range_scan")) {
402
- return;
421
+ SKIP("cluster does not support range_scan");
403
422
  }
404
423
 
405
424
  auto collection = couchbase::cluster(integration.cluster)
@@ -435,8 +454,8 @@ TEST_CASE("integration: range scan cancellation before continue", "[integration]
435
454
  couchbase::scope::default_name,
436
455
  couchbase::collection::default_name,
437
456
  couchbase::core::range_scan{
438
- { couchbase::core::utils::to_binary("rangescancancel") },
439
- { couchbase::core::utils::to_binary("rangescancancel\xff") },
457
+ couchbase::core::scan_term{ "rangescancancel" },
458
+ couchbase::core::scan_term{ "rangescancancel\xff" },
440
459
  },
441
460
  };
442
461
  options.ids_only = true;
@@ -474,7 +493,6 @@ TEST_CASE("integration: range scan cancellation before continue", "[integration]
474
493
 
475
494
  couchbase::core::range_scan_continue_options options{};
476
495
  options.batch_time_limit = std::chrono::seconds{ 10 };
477
- options.ids_only = true; // support servers before MB-54267. TODO: remove after server GA
478
496
 
479
497
  bool items_callback_invoked{ false };
480
498
  {
@@ -503,7 +521,7 @@ TEST_CASE("integration: range scan cancel during streaming using protocol cancel
503
521
  test::utils::integration_test_guard integration;
504
522
 
505
523
  if (!integration.has_bucket_capability("range_scan")) {
506
- return;
524
+ SKIP("cluster does not support range_scan");
507
525
  }
508
526
 
509
527
  auto collection = couchbase::cluster(integration.cluster)
@@ -539,8 +557,8 @@ TEST_CASE("integration: range scan cancel during streaming using protocol cancel
539
557
  couchbase::scope::default_name,
540
558
  couchbase::collection::default_name,
541
559
  couchbase::core::range_scan{
542
- { couchbase::core::utils::to_binary("rangescancancel") },
543
- { couchbase::core::utils::to_binary("rangescancancel\xff") },
560
+ couchbase::core::scan_term{ "rangescancancel" },
561
+ couchbase::core::scan_term{ "rangescancancel\xff" },
544
562
  },
545
563
  };
546
564
  options.ids_only = true;
@@ -577,7 +595,6 @@ TEST_CASE("integration: range scan cancel during streaming using protocol cancel
577
595
  couchbase::core::range_scan_continue_options options{};
578
596
  options.batch_time_limit = std::chrono::seconds{ 10 };
579
597
  options.batch_item_limit = 3; // limit batch to 3 items, while range expected to be larger
580
- options.ids_only = true; // support servers before MB-54267. TODO: remove after server GA
581
598
 
582
599
  auto barrier = std::make_shared<std::promise<std::pair<couchbase::core::range_scan_continue_result, std::error_code>>>();
583
600
  auto f = barrier->get_future();
@@ -615,7 +632,7 @@ TEST_CASE("integration: range scan cancel during streaming using pending_operati
615
632
  test::utils::integration_test_guard integration;
616
633
 
617
634
  if (!integration.has_bucket_capability("range_scan")) {
618
- return;
635
+ SKIP("cluster does not support range_scan");
619
636
  }
620
637
 
621
638
  auto collection = couchbase::cluster(integration.cluster)
@@ -651,8 +668,8 @@ TEST_CASE("integration: range scan cancel during streaming using pending_operati
651
668
  couchbase::scope::default_name,
652
669
  couchbase::collection::default_name,
653
670
  couchbase::core::range_scan{
654
- { couchbase::core::utils::to_binary("rangescancancel") },
655
- { couchbase::core::utils::to_binary("rangescancancel\xff") },
671
+ couchbase::core::scan_term{ "rangescancancel" },
672
+ couchbase::core::scan_term{ "rangescancancel\xff" },
656
673
  },
657
674
  };
658
675
  options.ids_only = true;
@@ -685,7 +702,6 @@ TEST_CASE("integration: range scan cancel during streaming using pending_operati
685
702
  couchbase::core::range_scan_continue_options options{};
686
703
  options.batch_time_limit = std::chrono::seconds{ 10 };
687
704
  options.batch_item_limit = 3; // limit batch to 3 items, while range expected to be larger
688
- options.ids_only = true; // support servers before MB-54267. TODO: remove after server GA
689
705
 
690
706
  auto barrier = std::make_shared<std::promise<std::pair<couchbase::core::range_scan_continue_result, std::error_code>>>();
691
707
  auto f = barrier->get_future();
@@ -717,7 +733,7 @@ TEST_CASE("integration: sampling scan keys only", "[integration]")
717
733
  test::utils::integration_test_guard integration;
718
734
 
719
735
  if (!integration.has_bucket_capability("range_scan")) {
720
- return;
736
+ SKIP("cluster does not support range_scan");
721
737
  }
722
738
 
723
739
  auto collection = couchbase::cluster(integration.cluster)
@@ -774,7 +790,7 @@ make_doc_ids(std::size_t number_of_keys, const std::string& prefix)
774
790
  }
775
791
 
776
792
  static auto
777
- mutations_to_mutation_state(std::map<std::vector<std::byte>, couchbase::mutation_token> mutations)
793
+ mutations_to_mutation_state(std::map<std::string, couchbase::mutation_token> mutations)
778
794
  {
779
795
  couchbase::core::mutation_state state;
780
796
  for (const auto& [key, token] : mutations) {
@@ -788,7 +804,7 @@ TEST_CASE("integration: manager scan range without content", "[integration]")
788
804
  test::utils::integration_test_guard integration;
789
805
 
790
806
  if (!integration.has_bucket_capability("range_scan")) {
791
- return;
807
+ SKIP("cluster does not support range_scan");
792
808
  }
793
809
 
794
810
  auto collection = couchbase::cluster(integration.cluster)
@@ -800,42 +816,27 @@ TEST_CASE("integration: manager scan range without content", "[integration]")
800
816
  auto value = make_binary_value(1);
801
817
  auto mutations = populate_documents_for_range_scan(collection, ids, value, std::chrono::seconds{ 30 });
802
818
 
803
- auto barrier = std::make_shared<std::promise<tl::expected<std::size_t, std::error_code>>>();
804
- auto f = barrier->get_future();
805
- integration.cluster->with_bucket_configuration(
806
- integration.ctx.bucket, [barrier](std::error_code ec, const couchbase::core::topology::configuration& config) mutable {
807
- if (ec) {
808
- return barrier->set_value(tl::unexpected(ec));
809
- }
810
- if (!config.vbmap || config.vbmap->empty()) {
811
- return barrier->set_value(tl::unexpected(couchbase::errc::common::feature_not_available));
812
- }
813
- barrier->set_value(config.vbmap->size());
814
- });
815
- auto number_of_vbuckets = f.get();
816
- EXPECT_SUCCESS(number_of_vbuckets);
819
+ auto vbucket_map = get_vbucket_map(integration);
817
820
 
818
821
  auto ag = couchbase::core::agent_group(integration.io, { { integration.cluster } });
819
822
  ag.open_bucket(integration.ctx.bucket);
820
823
  auto agent = ag.get_agent(integration.ctx.bucket);
821
824
  REQUIRE(agent.has_value());
822
825
 
823
- couchbase::core::range_scan scan{ "rangescanwithoutcontent", "rangescanwithoutcontent\xff" };
826
+ couchbase::core::range_scan scan{
827
+ couchbase::core::scan_term{ "rangescanwithoutcontent" },
828
+ couchbase::core::scan_term{ "rangescanwithoutcontent\xff" },
829
+ };
824
830
  couchbase::core::range_scan_orchestrator_options options{};
825
831
  options.consistent_with = mutations_to_mutation_state(mutations);
826
832
  options.ids_only = true;
827
- couchbase::core::range_scan_orchestrator orchestrator(integration.io,
828
- agent.value(),
829
- number_of_vbuckets.value(),
830
- couchbase::scope::default_name,
831
- couchbase::collection::default_name,
832
- scan,
833
- options);
833
+ couchbase::core::range_scan_orchestrator orchestrator(
834
+ integration.io, agent.value(), vbucket_map, couchbase::scope::default_name, couchbase::collection::default_name, scan, options);
834
835
 
835
836
  auto result = orchestrator.scan();
836
837
  EXPECT_SUCCESS(result);
837
838
 
838
- std::set<std::vector<std::byte>> entry_ids{};
839
+ std::set<std::string> entry_ids{};
839
840
 
840
841
  do {
841
842
  auto entry = result->next();
@@ -848,10 +849,11 @@ TEST_CASE("integration: manager scan range without content", "[integration]")
848
849
  REQUIRE_FALSE(entry->body.has_value());
849
850
  } while (true);
850
851
 
852
+ REQUIRE(ids.size() == entry_ids.size());
853
+
851
854
  for (const auto& id : ids) {
852
- REQUIRE(entry_ids.count(couchbase::core::utils::to_binary(id)) == 1);
855
+ REQUIRE(entry_ids.count(id) == 1);
853
856
  }
854
- REQUIRE(ids.size() == entry_ids.size());
855
857
  }
856
858
 
857
859
  TEST_CASE("integration: manager scan range with content", "[integration]")
@@ -859,7 +861,7 @@ TEST_CASE("integration: manager scan range with content", "[integration]")
859
861
  test::utils::integration_test_guard integration;
860
862
 
861
863
  if (!integration.has_bucket_capability("range_scan")) {
862
- return;
864
+ SKIP("cluster does not support range_scan");
863
865
  }
864
866
 
865
867
  auto collection = couchbase::cluster(integration.cluster)
@@ -871,41 +873,26 @@ TEST_CASE("integration: manager scan range with content", "[integration]")
871
873
  auto value = make_binary_value(100);
872
874
  auto mutations = populate_documents_for_range_scan(collection, ids, value, std::chrono::seconds{ 30 });
873
875
 
874
- auto barrier = std::make_shared<std::promise<tl::expected<std::size_t, std::error_code>>>();
875
- auto f = barrier->get_future();
876
- integration.cluster->with_bucket_configuration(
877
- integration.ctx.bucket, [barrier](std::error_code ec, const couchbase::core::topology::configuration& config) mutable {
878
- if (ec) {
879
- return barrier->set_value(tl::unexpected(ec));
880
- }
881
- if (!config.vbmap || config.vbmap->empty()) {
882
- return barrier->set_value(tl::unexpected(couchbase::errc::common::feature_not_available));
883
- }
884
- barrier->set_value(config.vbmap->size());
885
- });
886
- auto number_of_vbuckets = f.get();
887
- EXPECT_SUCCESS(number_of_vbuckets);
876
+ auto vbucket_map = get_vbucket_map(integration);
888
877
 
889
878
  auto ag = couchbase::core::agent_group(integration.io, { { integration.cluster } });
890
879
  ag.open_bucket(integration.ctx.bucket);
891
880
  auto agent = ag.get_agent(integration.ctx.bucket);
892
881
  REQUIRE(agent.has_value());
893
882
 
894
- couchbase::core::range_scan scan{ "rangescanwithcontent", "rangescanwithcontent\xff" };
883
+ couchbase::core::range_scan scan{
884
+ couchbase::core::scan_term{ "rangescanwithcontent" },
885
+ couchbase::core::scan_term{ "rangescanwithcontent\xff" },
886
+ };
895
887
  couchbase::core::range_scan_orchestrator_options options{};
896
888
  options.consistent_with = mutations_to_mutation_state(mutations);
897
- couchbase::core::range_scan_orchestrator orchestrator(integration.io,
898
- agent.value(),
899
- number_of_vbuckets.value(),
900
- couchbase::scope::default_name,
901
- couchbase::collection::default_name,
902
- scan,
903
- options);
889
+ couchbase::core::range_scan_orchestrator orchestrator(
890
+ integration.io, agent.value(), vbucket_map, couchbase::scope::default_name, couchbase::collection::default_name, scan, options);
904
891
 
905
892
  auto result = orchestrator.scan();
906
893
  EXPECT_SUCCESS(result);
907
894
 
908
- std::set<std::vector<std::byte>> entry_ids{};
895
+ std::set<std::string> entry_ids{};
909
896
 
910
897
  do {
911
898
  auto entry = result->next();
@@ -918,11 +905,12 @@ TEST_CASE("integration: manager scan range with content", "[integration]")
918
905
  REQUIRE(entry->body.has_value());
919
906
  } while (true);
920
907
 
908
+ REQUIRE(ids.size() == entry_ids.size());
909
+
921
910
  for (const auto& id : ids) {
922
911
  INFO(id);
923
- REQUIRE(entry_ids.count(couchbase::core::utils::to_binary(id)) == 1);
912
+ REQUIRE(entry_ids.count(id) == 1);
924
913
  }
925
- REQUIRE(ids.size() == entry_ids.size());
926
914
  }
927
915
 
928
916
  TEST_CASE("integration: manager sampling scan with custom collection", "[integration]")
@@ -930,7 +918,7 @@ TEST_CASE("integration: manager sampling scan with custom collection", "[integra
930
918
  test::utils::integration_test_guard integration;
931
919
 
932
920
  if (!integration.has_bucket_capability("range_scan")) {
933
- return;
921
+ SKIP("cluster does not support range_scan");
934
922
  }
935
923
 
936
924
  collection_guard new_collection(integration);
@@ -944,20 +932,7 @@ TEST_CASE("integration: manager sampling scan with custom collection", "[integra
944
932
  auto value = make_binary_value(100);
945
933
  auto mutations = populate_documents_for_range_scan(collection, ids, value, std::chrono::seconds{ 300 });
946
934
 
947
- auto barrier = std::make_shared<std::promise<tl::expected<std::size_t, std::error_code>>>();
948
- auto f = barrier->get_future();
949
- integration.cluster->with_bucket_configuration(
950
- integration.ctx.bucket, [barrier](std::error_code ec, const couchbase::core::topology::configuration& config) mutable {
951
- if (ec) {
952
- return barrier->set_value(tl::unexpected(ec));
953
- }
954
- if (!config.vbmap || config.vbmap->empty()) {
955
- return barrier->set_value(tl::unexpected(couchbase::errc::common::feature_not_available));
956
- }
957
- barrier->set_value(config.vbmap->size());
958
- });
959
- auto number_of_vbuckets = f.get();
960
- EXPECT_SUCCESS(number_of_vbuckets);
935
+ auto vbucket_map = get_vbucket_map(integration);
961
936
 
962
937
  auto ag = couchbase::core::agent_group(integration.io, { { integration.cluster } });
963
938
  ag.open_bucket(integration.ctx.bucket);
@@ -968,12 +943,12 @@ TEST_CASE("integration: manager sampling scan with custom collection", "[integra
968
943
  couchbase::core::range_scan_orchestrator_options options{};
969
944
  options.consistent_with = mutations_to_mutation_state(mutations);
970
945
  couchbase::core::range_scan_orchestrator orchestrator(
971
- integration.io, agent.value(), number_of_vbuckets.value(), couchbase::scope::default_name, new_collection.name(), scan, options);
946
+ integration.io, agent.value(), vbucket_map, couchbase::scope::default_name, new_collection.name(), scan, options);
972
947
 
973
948
  auto result = orchestrator.scan();
974
949
  EXPECT_SUCCESS(result);
975
950
 
976
- std::set<std::vector<std::byte>> entry_ids{};
951
+ std::set<std::string> entry_ids{};
977
952
 
978
953
  auto now = std::chrono::system_clock::now();
979
954
  do {
@@ -994,16 +969,70 @@ TEST_CASE("integration: manager sampling scan with custom collection", "[integra
994
969
  REQUIRE(ids.size() >= 10);
995
970
 
996
971
  for (const auto& id : entry_ids) {
997
- REQUIRE(std::find(ids.begin(), ids.end(), std::string(reinterpret_cast<const char*>(id.data()), id.size())) != ids.end());
972
+ REQUIRE(std::find(ids.begin(), ids.end(), id) != ids.end());
998
973
  }
999
974
  }
1000
975
 
1001
- TEST_CASE("integration: manager range scan with sort", "[integration]")
976
+ TEST_CASE("integration: manager prefix scan without content", "[integration]")
1002
977
  {
1003
978
  test::utils::integration_test_guard integration;
1004
979
 
1005
980
  if (!integration.has_bucket_capability("range_scan")) {
1006
- return;
981
+ SKIP("cluster does not support range_scan");
982
+ }
983
+
984
+ auto collection = couchbase::cluster(integration.cluster)
985
+ .bucket(integration.ctx.bucket)
986
+ .scope(couchbase::scope::default_name)
987
+ .collection(couchbase::collection::default_name);
988
+
989
+ auto ids = make_doc_ids(100, "prefixscanwithoutcontent-");
990
+ auto value = make_binary_value(1);
991
+ auto mutations = populate_documents_for_range_scan(collection, ids, value, std::chrono::seconds{ 30 });
992
+
993
+ auto vbucket_map = get_vbucket_map(integration);
994
+
995
+ auto ag = couchbase::core::agent_group(integration.io, { { integration.cluster } });
996
+ ag.open_bucket(integration.ctx.bucket);
997
+ auto agent = ag.get_agent(integration.ctx.bucket);
998
+ REQUIRE(agent.has_value());
999
+
1000
+ couchbase::core::prefix_scan scan{ "prefixscanwithoutcontent" };
1001
+ couchbase::core::range_scan_orchestrator_options options{};
1002
+ options.consistent_with = mutations_to_mutation_state(mutations);
1003
+ options.ids_only = true;
1004
+ couchbase::core::range_scan_orchestrator orchestrator(
1005
+ integration.io, agent.value(), vbucket_map, couchbase::scope::default_name, couchbase::collection::default_name, scan, options);
1006
+
1007
+ auto result = orchestrator.scan();
1008
+ EXPECT_SUCCESS(result);
1009
+
1010
+ std::set<std::string> entry_ids{};
1011
+
1012
+ do {
1013
+ auto entry = result->next();
1014
+ if (!entry) {
1015
+ break;
1016
+ }
1017
+
1018
+ auto [_, inserted] = entry_ids.insert(entry->key);
1019
+ REQUIRE(inserted);
1020
+ REQUIRE_FALSE(entry->body.has_value());
1021
+ } while (true);
1022
+
1023
+ REQUIRE(ids.size() == entry_ids.size());
1024
+
1025
+ for (const auto& id : ids) {
1026
+ REQUIRE(entry_ids.count(id) == 1);
1027
+ }
1028
+ }
1029
+
1030
+ TEST_CASE("integration: manager sampling scan with custom collection and up to 10 concurrent streams", "[integration]")
1031
+ {
1032
+ test::utils::integration_test_guard integration;
1033
+
1034
+ if (!integration.has_bucket_capability("range_scan")) {
1035
+ SKIP("cluster does not support range_scan");
1007
1036
  }
1008
1037
 
1009
1038
  collection_guard new_collection(integration);
@@ -1013,43 +1042,151 @@ TEST_CASE("integration: manager range scan with sort", "[integration]")
1013
1042
  .scope(couchbase::scope::default_name)
1014
1043
  .collection(new_collection.name());
1015
1044
 
1016
- auto ids = make_doc_ids(100, "rangescansort-");
1045
+ auto ids = make_doc_ids(100, "samplingscan-");
1017
1046
  auto value = make_binary_value(100);
1018
1047
  auto mutations = populate_documents_for_range_scan(collection, ids, value, std::chrono::seconds{ 300 });
1019
1048
 
1020
- auto barrier = std::make_shared<std::promise<tl::expected<std::size_t, std::error_code>>>();
1021
- auto f = barrier->get_future();
1022
- integration.cluster->with_bucket_configuration(
1023
- integration.ctx.bucket, [barrier](std::error_code ec, const couchbase::core::topology::configuration& config) mutable {
1024
- if (ec) {
1025
- return barrier->set_value(tl::unexpected(ec));
1026
- }
1027
- if (!config.vbmap || config.vbmap->empty()) {
1028
- return barrier->set_value(tl::unexpected(couchbase::errc::common::feature_not_available));
1029
- }
1030
- barrier->set_value(config.vbmap->size());
1031
- });
1032
- auto number_of_vbuckets = f.get();
1033
- EXPECT_SUCCESS(number_of_vbuckets);
1049
+ auto vbucket_map = get_vbucket_map(integration);
1034
1050
 
1035
1051
  auto ag = couchbase::core::agent_group(integration.io, { { integration.cluster } });
1036
1052
  ag.open_bucket(integration.ctx.bucket);
1037
1053
  auto agent = ag.get_agent(integration.ctx.bucket);
1038
1054
  REQUIRE(agent.has_value());
1039
1055
 
1040
- couchbase::core::range_scan scan{ "rangescansort", "rangescansort\xff" };
1056
+ couchbase::core::sampling_scan scan{ 10, 50 };
1057
+ couchbase::core::range_scan_orchestrator_options options{};
1058
+ options.consistent_with = mutations_to_mutation_state(mutations);
1059
+ options.concurrency = 10;
1060
+ couchbase::core::range_scan_orchestrator orchestrator(
1061
+ integration.io, agent.value(), vbucket_map, couchbase::scope::default_name, new_collection.name(), scan, options);
1062
+
1063
+ auto result = orchestrator.scan();
1064
+ EXPECT_SUCCESS(result);
1065
+
1066
+ std::set<std::string> entry_ids{};
1067
+
1068
+ auto now = std::chrono::system_clock::now();
1069
+ do {
1070
+ auto entry = result->next();
1071
+ if (!entry) {
1072
+ break;
1073
+ }
1074
+
1075
+ REQUIRE(entry->body);
1076
+ REQUIRE_FALSE(entry->body->cas.empty());
1077
+ REQUIRE(entry->body->value == value);
1078
+ REQUIRE(entry->body->expiry_time() > now);
1079
+
1080
+ auto [_, inserted] = entry_ids.insert(entry->key);
1081
+ REQUIRE(inserted);
1082
+ } while (true);
1083
+
1084
+ REQUIRE(ids.size() >= 10);
1085
+
1086
+ for (const auto& id : entry_ids) {
1087
+ REQUIRE(std::find(ids.begin(), ids.end(), id) != ids.end());
1088
+ }
1089
+ }
1090
+
1091
+ TEST_CASE("integration: manager sampling scan with custom collection and up to 128 concurrent streams and batch item limit 0",
1092
+ "[integration]")
1093
+ {
1094
+ test::utils::integration_test_guard integration;
1095
+
1096
+ if (!integration.has_bucket_capability("range_scan")) {
1097
+ SKIP("cluster does not support range_scan");
1098
+ }
1099
+
1100
+ collection_guard new_collection(integration);
1101
+
1102
+ auto collection = couchbase::cluster(integration.cluster)
1103
+ .bucket(integration.ctx.bucket)
1104
+ .scope(couchbase::scope::default_name)
1105
+ .collection(new_collection.name());
1106
+
1107
+ auto ids = make_doc_ids(100, "samplingscan-");
1108
+ auto value = make_binary_value(100);
1109
+ auto mutations = populate_documents_for_range_scan(collection, ids, value, std::chrono::seconds{ 300 });
1110
+
1111
+ auto vbucket_map = get_vbucket_map(integration);
1112
+
1113
+ auto ag = couchbase::core::agent_group(integration.io, { { integration.cluster } });
1114
+ ag.open_bucket(integration.ctx.bucket);
1115
+ auto agent = ag.get_agent(integration.ctx.bucket);
1116
+ REQUIRE(agent.has_value());
1117
+
1118
+ couchbase::core::sampling_scan scan{ 10, 50 };
1119
+ couchbase::core::range_scan_orchestrator_options options{};
1120
+ options.consistent_with = mutations_to_mutation_state(mutations);
1121
+ options.concurrency = 128;
1122
+ options.batch_item_limit = 0;
1123
+ couchbase::core::range_scan_orchestrator orchestrator(
1124
+ integration.io, agent.value(), vbucket_map, couchbase::scope::default_name, new_collection.name(), scan, options);
1125
+
1126
+ auto result = orchestrator.scan();
1127
+ EXPECT_SUCCESS(result);
1128
+
1129
+ std::set<std::string> entry_ids{};
1130
+
1131
+ auto now = std::chrono::system_clock::now();
1132
+ do {
1133
+ auto entry = result->next();
1134
+ if (!entry) {
1135
+ break;
1136
+ }
1137
+
1138
+ REQUIRE(entry->body);
1139
+ REQUIRE_FALSE(entry->body->cas.empty());
1140
+ REQUIRE(entry->body->value == value);
1141
+ REQUIRE(entry->body->expiry_time() > now);
1142
+
1143
+ auto [_, inserted] = entry_ids.insert(entry->key);
1144
+ REQUIRE(inserted);
1145
+ } while (true);
1146
+
1147
+ REQUIRE(ids.size() >= 10);
1148
+
1149
+ for (const auto& id : entry_ids) {
1150
+ REQUIRE(std::find(ids.begin(), ids.end(), id) != ids.end());
1151
+ }
1152
+ }
1153
+
1154
+ TEST_CASE("integration: manager prefix scan without content and up to 5 concurrent streams", "[integration]")
1155
+ {
1156
+ test::utils::integration_test_guard integration;
1157
+
1158
+ if (!integration.has_bucket_capability("range_scan")) {
1159
+ SKIP("cluster does not support range_scan");
1160
+ }
1161
+
1162
+ auto collection = couchbase::cluster(integration.cluster)
1163
+ .bucket(integration.ctx.bucket)
1164
+ .scope(couchbase::scope::default_name)
1165
+ .collection(couchbase::collection::default_name);
1166
+
1167
+ auto ids = make_doc_ids(100, "prefixscanwithoutcontent-");
1168
+ auto value = make_binary_value(1);
1169
+ auto mutations = populate_documents_for_range_scan(collection, ids, value, std::chrono::seconds{ 30 });
1170
+
1171
+ auto vbucket_map = get_vbucket_map(integration);
1172
+
1173
+ auto ag = couchbase::core::agent_group(integration.io, { { integration.cluster } });
1174
+ ag.open_bucket(integration.ctx.bucket);
1175
+ auto agent = ag.get_agent(integration.ctx.bucket);
1176
+ REQUIRE(agent.has_value());
1177
+
1178
+ couchbase::core::prefix_scan scan{ "prefixscanwithoutcontent" };
1041
1179
  couchbase::core::range_scan_orchestrator_options options{};
1042
1180
  options.consistent_with = mutations_to_mutation_state(mutations);
1043
1181
  options.ids_only = true;
1044
- options.sort = couchbase::core::scan_sort::ascending;
1182
+ options.concurrency = 5;
1045
1183
  couchbase::core::range_scan_orchestrator orchestrator(
1046
- integration.io, agent.value(), number_of_vbuckets.value(), couchbase::scope::default_name, new_collection.name(), scan, options);
1184
+ integration.io, agent.value(), vbucket_map, couchbase::scope::default_name, couchbase::collection::default_name, scan, options);
1047
1185
 
1048
1186
  auto result = orchestrator.scan();
1049
1187
  EXPECT_SUCCESS(result);
1050
1188
 
1051
- std::vector<std::string> entry_ids{};
1052
- entry_ids.reserve(ids.size());
1189
+ std::set<std::string> entry_ids{};
1053
1190
 
1054
1191
  do {
1055
1192
  auto entry = result->next();
@@ -1057,11 +1194,113 @@ TEST_CASE("integration: manager range scan with sort", "[integration]")
1057
1194
  break;
1058
1195
  }
1059
1196
 
1060
- entry_ids.emplace_back(reinterpret_cast<const char*>(entry->key.data()), entry->key.size());
1197
+ auto [_, inserted] = entry_ids.insert(entry->key);
1198
+ REQUIRE(inserted);
1061
1199
  REQUIRE_FALSE(entry->body.has_value());
1062
1200
  } while (true);
1063
1201
 
1064
1202
  REQUIRE(ids.size() == entry_ids.size());
1065
- std::sort(ids.begin(), ids.end());
1066
- REQUIRE(ids == entry_ids);
1203
+
1204
+ for (const auto& id : ids) {
1205
+ REQUIRE(entry_ids.count(id) == 1);
1206
+ }
1207
+ }
1208
+
1209
+ TEST_CASE("integration: manager prefix scan, get 10 items and cancel", "[integration]")
1210
+ {
1211
+ test::utils::integration_test_guard integration;
1212
+
1213
+ if (!integration.has_bucket_capability("range_scan")) {
1214
+ SKIP("cluster does not support range_scan");
1215
+ }
1216
+
1217
+ auto collection = couchbase::cluster(integration.cluster)
1218
+ .bucket(integration.ctx.bucket)
1219
+ .scope(couchbase::scope::default_name)
1220
+ .collection(couchbase::collection::default_name);
1221
+
1222
+ auto ids = make_doc_ids(15, "rangescancancel-");
1223
+ auto value = make_binary_value(1);
1224
+ auto mutations = populate_documents_for_range_scan(collection, ids, value, std::chrono::seconds{ 30 });
1225
+
1226
+ auto vbucket_map = get_vbucket_map(integration);
1227
+
1228
+ auto ag = couchbase::core::agent_group(integration.io, { { integration.cluster } });
1229
+ ag.open_bucket(integration.ctx.bucket);
1230
+ auto agent = ag.get_agent(integration.ctx.bucket);
1231
+ REQUIRE(agent.has_value());
1232
+
1233
+ couchbase::core::prefix_scan scan{ "rangescancancel" };
1234
+ couchbase::core::range_scan_orchestrator_options options{};
1235
+ options.consistent_with = mutations_to_mutation_state(mutations);
1236
+ options.ids_only = true;
1237
+ couchbase::core::range_scan_orchestrator orchestrator(
1238
+ integration.io, agent.value(), vbucket_map, couchbase::scope::default_name, couchbase::collection::default_name, scan, options);
1239
+
1240
+ auto result = orchestrator.scan();
1241
+ EXPECT_SUCCESS(result);
1242
+
1243
+ std::set<std::string> entry_ids{};
1244
+ std::size_t const expected_id_count = 10;
1245
+
1246
+ for (std::size_t i = 0; i < expected_id_count; i++) {
1247
+ auto entry = result->next();
1248
+ if (!entry) {
1249
+ break;
1250
+ }
1251
+
1252
+ auto [_, inserted] = entry_ids.insert(entry->key);
1253
+ REQUIRE(inserted);
1254
+ REQUIRE_FALSE(entry->body.has_value());
1255
+ }
1256
+
1257
+ result->cancel();
1258
+
1259
+ REQUIRE(expected_id_count == entry_ids.size());
1260
+
1261
+ for (const auto& entry_id : entry_ids) {
1262
+ REQUIRE(std::count(ids.begin(), ids.end(), entry_id) == 0);
1263
+ }
1264
+
1265
+ auto next_item = result->next();
1266
+ REQUIRE(!next_item.has_value());
1267
+ REQUIRE(next_item.error() == couchbase::errc::key_value::range_scan_completed);
1268
+ REQUIRE(result->is_cancelled());
1269
+ }
1270
+
1271
+ TEST_CASE("integration: manager prefix scan with concurrency 0 (invalid argument)", "[integration]")
1272
+ {
1273
+ test::utils::integration_test_guard integration;
1274
+
1275
+ if (!integration.has_bucket_capability("range_scan")) {
1276
+ SKIP("cluster does not support range_scan");
1277
+ }
1278
+
1279
+ auto collection = couchbase::cluster(integration.cluster)
1280
+ .bucket(integration.ctx.bucket)
1281
+ .scope(couchbase::scope::default_name)
1282
+ .collection(couchbase::collection::default_name);
1283
+
1284
+ auto ids = make_doc_ids(100, "prefixscaninvalidconcurrency-");
1285
+ auto value = make_binary_value(1);
1286
+ auto mutations = populate_documents_for_range_scan(collection, ids, value, std::chrono::seconds{ 30 });
1287
+
1288
+ auto vbucket_map = get_vbucket_map(integration);
1289
+
1290
+ auto ag = couchbase::core::agent_group(integration.io, { { integration.cluster } });
1291
+ ag.open_bucket(integration.ctx.bucket);
1292
+ auto agent = ag.get_agent(integration.ctx.bucket);
1293
+ REQUIRE(agent.has_value());
1294
+
1295
+ couchbase::core::prefix_scan scan{ "prefixscaninvalidconcurrency" };
1296
+ couchbase::core::range_scan_orchestrator_options options{};
1297
+ options.consistent_with = mutations_to_mutation_state(mutations);
1298
+ options.ids_only = true;
1299
+ options.concurrency = 0;
1300
+ couchbase::core::range_scan_orchestrator orchestrator(
1301
+ integration.io, agent.value(), vbucket_map, couchbase::scope::default_name, couchbase::collection::default_name, scan, options);
1302
+
1303
+ auto result = orchestrator.scan();
1304
+ REQUIRE(!result.has_value());
1305
+ REQUIRE(result.error() == couchbase::errc::common::invalid_argument);
1067
1306
  }