mongo 2.15.0 → 2.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (393) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +1 -1
  4. data/lib/mongo/auth/aws/request.rb +0 -1
  5. data/lib/mongo/bulk_write.rb +2 -2
  6. data/lib/mongo/client.rb +49 -5
  7. data/lib/mongo/cluster/periodic_executor.rb +4 -3
  8. data/lib/mongo/cluster/reapers/cursor_reaper.rb +76 -43
  9. data/lib/mongo/cluster/sdam_flow.rb +9 -3
  10. data/lib/mongo/cluster/topology/base.rb +13 -9
  11. data/lib/mongo/cluster/topology/load_balanced.rb +102 -0
  12. data/lib/mongo/cluster/topology.rb +28 -8
  13. data/lib/mongo/cluster.rb +136 -51
  14. data/lib/mongo/collection/view/aggregation.rb +63 -23
  15. data/lib/mongo/collection/view/builder/aggregation.rb +16 -17
  16. data/lib/mongo/collection/view/builder/map_reduce.rb +12 -49
  17. data/lib/mongo/collection/view/builder.rb +0 -4
  18. data/lib/mongo/collection/view/change_stream.rb +7 -3
  19. data/lib/mongo/collection/view/iterable.rb +60 -27
  20. data/lib/mongo/collection/view/map_reduce.rb +41 -15
  21. data/lib/mongo/collection/view/readable.rb +84 -52
  22. data/lib/mongo/collection/view/writable.rb +201 -175
  23. data/lib/mongo/collection/view.rb +15 -21
  24. data/lib/mongo/collection.rb +34 -14
  25. data/lib/mongo/cursor/kill_spec.rb +38 -0
  26. data/lib/mongo/cursor.rb +72 -31
  27. data/lib/mongo/database/view.rb +5 -3
  28. data/lib/mongo/database.rb +6 -6
  29. data/lib/mongo/error/bad_load_balancer_target.rb +26 -0
  30. data/lib/mongo/error/missing_service_id.rb +26 -0
  31. data/lib/mongo/error/no_service_connection_available.rb +49 -0
  32. data/lib/mongo/error/notable.rb +7 -0
  33. data/lib/mongo/error/snapshot_session_invalid_server_version.rb +31 -0
  34. data/lib/mongo/error/snapshot_session_transaction_prohibited.rb +30 -0
  35. data/lib/mongo/error.rb +5 -0
  36. data/lib/mongo/grid/fs_bucket.rb +21 -2
  37. data/lib/mongo/id.rb +7 -5
  38. data/lib/mongo/index/view.rb +22 -41
  39. data/lib/mongo/monitoring/event/cmap/pool_cleared.rb +7 -4
  40. data/lib/mongo/monitoring/event/command_failed.rb +1 -1
  41. data/lib/mongo/monitoring/event/command_started.rb +2 -0
  42. data/lib/mongo/monitoring/publishable.rb +2 -2
  43. data/lib/mongo/operation/aggregate/command.rb +8 -0
  44. data/lib/mongo/operation/context.rb +19 -1
  45. data/lib/mongo/operation/count/command.rb +6 -0
  46. data/lib/mongo/operation/count/op_msg.rb +6 -0
  47. data/lib/mongo/operation/create/command.rb +7 -1
  48. data/lib/mongo/operation/create/op_msg.rb +7 -0
  49. data/lib/mongo/operation/create_index/command.rb +17 -1
  50. data/lib/mongo/operation/create_index/op_msg.rb +17 -4
  51. data/lib/mongo/operation/delete/command.rb +6 -3
  52. data/lib/mongo/operation/delete/legacy.rb +9 -2
  53. data/lib/mongo/operation/delete/op_msg.rb +9 -1
  54. data/lib/mongo/operation/distinct/command.rb +6 -0
  55. data/lib/mongo/operation/distinct/op_msg.rb +7 -0
  56. data/lib/mongo/operation/explain/command.rb +13 -1
  57. data/lib/mongo/operation/explain/legacy.rb +12 -5
  58. data/lib/mongo/operation/explain/op_msg.rb +9 -1
  59. data/lib/mongo/operation/find/builder/command.rb +111 -0
  60. data/lib/mongo/{collection/view → operation/find}/builder/flags.rb +10 -14
  61. data/lib/mongo/operation/find/builder/legacy.rb +123 -0
  62. data/lib/mongo/{collection/view → operation/find}/builder/modifiers.rb +31 -25
  63. data/lib/mongo/{cursor → operation/find}/builder.rb +4 -4
  64. data/lib/mongo/operation/find/command.rb +9 -0
  65. data/lib/mongo/operation/find/legacy.rb +10 -1
  66. data/lib/mongo/operation/find/op_msg.rb +12 -0
  67. data/lib/mongo/operation/find.rb +1 -0
  68. data/lib/mongo/operation/get_more/command.rb +1 -0
  69. data/lib/mongo/operation/get_more/command_builder.rb +38 -0
  70. data/lib/mongo/operation/get_more/op_msg.rb +1 -0
  71. data/lib/mongo/operation/get_more.rb +1 -0
  72. data/lib/mongo/operation/kill_cursors/command.rb +8 -0
  73. data/lib/mongo/operation/kill_cursors/command_builder.rb +35 -0
  74. data/lib/mongo/operation/kill_cursors/legacy.rb +2 -1
  75. data/lib/mongo/operation/kill_cursors/op_msg.rb +10 -0
  76. data/lib/mongo/operation/kill_cursors.rb +1 -0
  77. data/lib/mongo/operation/map_reduce/command.rb +8 -0
  78. data/lib/mongo/operation/map_reduce/op_msg.rb +1 -1
  79. data/lib/mongo/operation/result.rb +6 -0
  80. data/lib/mongo/operation/shared/executable.rb +19 -1
  81. data/lib/mongo/operation/shared/polymorphic_operation.rb +1 -1
  82. data/lib/mongo/operation/shared/read_preference_supported.rb +3 -1
  83. data/lib/mongo/operation/shared/response_handling.rb +1 -0
  84. data/lib/mongo/operation/shared/sessions_supported.rb +28 -12
  85. data/lib/mongo/operation/shared/specifiable.rb +11 -29
  86. data/lib/mongo/operation/shared/validatable.rb +87 -0
  87. data/lib/mongo/operation/shared/write.rb +1 -1
  88. data/lib/mongo/operation/update/command.rb +6 -3
  89. data/lib/mongo/operation/update/legacy.rb +19 -11
  90. data/lib/mongo/operation/update/op_msg.rb +8 -4
  91. data/lib/mongo/operation/write_command/command.rb +51 -0
  92. data/lib/mongo/operation/write_command/op_msg.rb +43 -0
  93. data/lib/mongo/operation/write_command.rb +32 -0
  94. data/lib/mongo/operation.rb +10 -0
  95. data/lib/mongo/protocol/query.rb +35 -18
  96. data/lib/mongo/server/connection.rb +25 -3
  97. data/lib/mongo/server/connection_base.rb +12 -1
  98. data/lib/mongo/server/connection_common.rb +38 -1
  99. data/lib/mongo/server/connection_pool/generation_manager.rb +71 -0
  100. data/lib/mongo/server/connection_pool.rb +100 -27
  101. data/lib/mongo/server/description/features.rb +20 -17
  102. data/lib/mongo/server/description/load_balancer.rb +33 -0
  103. data/lib/mongo/server/description.rb +85 -6
  104. data/lib/mongo/server/monitor/connection.rb +5 -6
  105. data/lib/mongo/server/monitor.rb +2 -1
  106. data/lib/mongo/server/pending_connection.rb +47 -31
  107. data/lib/mongo/server/push_monitor.rb +10 -1
  108. data/lib/mongo/server.rb +73 -26
  109. data/lib/mongo/server_selector/base.rb +31 -5
  110. data/lib/mongo/session/session_pool.rb +11 -0
  111. data/lib/mongo/session.rb +40 -1
  112. data/lib/mongo/socket/ocsp_cache.rb +2 -3
  113. data/lib/mongo/socket/ocsp_verifier.rb +6 -37
  114. data/lib/mongo/socket.rb +1 -5
  115. data/lib/mongo/uri/options_mapper.rb +1 -0
  116. data/lib/mongo/uri/srv_protocol.rb +6 -8
  117. data/lib/mongo/uri.rb +18 -0
  118. data/lib/mongo/utils.rb +0 -13
  119. data/lib/mongo/version.rb +1 -1
  120. data/mongo.gemspec +1 -1
  121. data/spec/integration/auth_spec.rb +31 -1
  122. data/spec/integration/awaited_ismaster_spec.rb +1 -1
  123. data/spec/integration/bulk_write_spec.rb +1 -1
  124. data/spec/integration/change_stream_spec.rb +3 -3
  125. data/spec/integration/client_construction_spec.rb +54 -0
  126. data/spec/integration/client_side_encryption/auto_encryption_bulk_writes_spec.rb +1 -1
  127. data/spec/integration/client_side_encryption/auto_encryption_command_monitoring_spec.rb +1 -1
  128. data/spec/integration/client_side_encryption/bson_size_limit_spec.rb +1 -1
  129. data/spec/integration/client_side_encryption/data_key_spec.rb +1 -1
  130. data/spec/integration/client_spec.rb +2 -0
  131. data/spec/integration/command_monitoring_spec.rb +1 -1
  132. data/spec/integration/command_spec.rb +1 -1
  133. data/spec/integration/connection_spec.rb +52 -35
  134. data/spec/integration/crud_spec.rb +174 -1
  135. data/spec/integration/cursor_pinning_spec.rb +121 -0
  136. data/spec/integration/cursor_reaping_spec.rb +8 -4
  137. data/spec/integration/fork_reconnect_spec.rb +1 -5
  138. data/spec/integration/get_more_spec.rb +1 -1
  139. data/spec/integration/heartbeat_events_spec.rb +1 -1
  140. data/spec/integration/map_reduce_spec.rb +77 -0
  141. data/spec/integration/query_cache_spec.rb +47 -2
  142. data/spec/integration/query_cache_transactions_spec.rb +1 -1
  143. data/spec/integration/read_concern_spec.rb +1 -1
  144. data/spec/integration/read_preference_spec.rb +17 -13
  145. data/spec/integration/reconnect_spec.rb +30 -12
  146. data/spec/integration/retryable_errors_spec.rb +1 -1
  147. data/spec/integration/retryable_writes/retryable_writes_36_and_older_spec.rb +1 -1
  148. data/spec/integration/retryable_writes/retryable_writes_40_and_newer_spec.rb +1 -1
  149. data/spec/integration/sdam_error_handling_spec.rb +5 -3
  150. data/spec/integration/sdam_events_spec.rb +35 -19
  151. data/spec/integration/sdam_prose_spec.rb +1 -1
  152. data/spec/integration/server_monitor_spec.rb +1 -0
  153. data/spec/integration/server_selector_spec.rb +22 -5
  154. data/spec/integration/server_spec.rb +2 -0
  155. data/spec/integration/srv_monitoring_spec.rb +1 -1
  156. data/spec/integration/step_down_spec.rb +1 -1
  157. data/spec/integration/transaction_pinning_spec.rb +120 -0
  158. data/spec/integration/versioned_api_examples_spec.rb +45 -0
  159. data/spec/integration/x509_auth_spec.rb +1 -1
  160. data/spec/lite_spec_helper.rb +1 -2
  161. data/spec/mongo/address/unix_spec.rb +1 -0
  162. data/spec/mongo/auth/cr_spec.rb +2 -3
  163. data/spec/mongo/auth/ldap_spec.rb +2 -3
  164. data/spec/mongo/auth/scram_spec.rb +2 -3
  165. data/spec/mongo/auth/user/view_spec.rb +1 -1
  166. data/spec/mongo/auth/x509_spec.rb +2 -3
  167. data/spec/mongo/bulk_write_spec.rb +3 -3
  168. data/spec/mongo/client_construction_spec.rb +259 -28
  169. data/spec/mongo/client_spec.rb +6 -4
  170. data/spec/mongo/cluster/cursor_reaper_spec.rb +36 -21
  171. data/spec/mongo/cluster/periodic_executor_spec.rb +3 -1
  172. data/spec/mongo/cluster_spec.rb +44 -3
  173. data/spec/mongo/collection/view/aggregation_spec.rb +72 -96
  174. data/spec/mongo/collection/view/builder/find_command_spec.rb +4 -0
  175. data/spec/mongo/collection/view/builder/op_query_spec.rb +4 -0
  176. data/spec/mongo/collection/view/change_stream_spec.rb +1 -1
  177. data/spec/mongo/collection/view/map_reduce_spec.rb +15 -2
  178. data/spec/mongo/collection_crud_spec.rb +7 -2
  179. data/spec/mongo/collection_ddl_spec.rb +1 -1
  180. data/spec/mongo/collection_spec.rb +1 -1
  181. data/spec/mongo/cursor/builder/get_more_command_spec.rb +4 -0
  182. data/spec/mongo/cursor/builder/op_get_more_spec.rb +4 -0
  183. data/spec/mongo/cursor_spec.rb +15 -5
  184. data/spec/mongo/database_spec.rb +15 -15
  185. data/spec/mongo/error/operation_failure_heavy_spec.rb +1 -1
  186. data/spec/mongo/grid/fs_bucket_spec.rb +18 -12
  187. data/spec/mongo/grid/stream/write_spec.rb +3 -9
  188. data/spec/mongo/grid/stream_spec.rb +1 -1
  189. data/spec/mongo/index/view_spec.rb +2 -2
  190. data/spec/mongo/operation/delete/op_msg_spec.rb +1 -1
  191. data/spec/mongo/{collection/view → operation/find}/builder/flags_spec.rb +2 -2
  192. data/spec/mongo/{collection/view → operation/find}/builder/modifiers_spec.rb +2 -2
  193. data/spec/mongo/operation/find/legacy_spec.rb +1 -0
  194. data/spec/mongo/operation/insert/bulk_spec.rb +1 -1
  195. data/spec/mongo/operation/insert/op_msg_spec.rb +1 -1
  196. data/spec/mongo/operation/kill_cursors_spec.rb +4 -1
  197. data/spec/mongo/operation/read_preference_legacy_spec.rb +4 -0
  198. data/spec/mongo/operation/read_preference_op_msg_spec.rb +26 -1
  199. data/spec/mongo/operation/update/bulk_spec.rb +1 -1
  200. data/spec/mongo/operation/update/op_msg_spec.rb +1 -1
  201. data/spec/mongo/query_cache_spec.rb +6 -2
  202. data/spec/mongo/server/connection_common_spec.rb +62 -11
  203. data/spec/mongo/server/connection_pool_spec.rb +73 -7
  204. data/spec/mongo/server/connection_spec.rb +138 -43
  205. data/spec/mongo/server/description_spec.rb +1 -1
  206. data/spec/mongo/server/monitor/connection_spec.rb +22 -0
  207. data/spec/mongo/server/monitor_spec.rb +4 -3
  208. data/spec/mongo/server/push_monitor_spec.rb +101 -0
  209. data/spec/mongo/server_selector_spec.rb +136 -15
  210. data/spec/mongo/session/session_pool_spec.rb +42 -10
  211. data/spec/mongo/session_transaction_spec.rb +15 -30
  212. data/spec/mongo/socket/ssl_spec.rb +26 -58
  213. data/spec/mongo/socket/unix_spec.rb +1 -0
  214. data/spec/mongo/uri_option_parsing_spec.rb +38 -5
  215. data/spec/mongo/utils_spec.rb +0 -14
  216. data/spec/runners/change_streams/test.rb +1 -1
  217. data/spec/runners/cmap.rb +1 -1
  218. data/spec/runners/connection_string.rb +7 -3
  219. data/spec/runners/crud/operation.rb +5 -3
  220. data/spec/runners/crud/requirement.rb +1 -0
  221. data/spec/runners/crud/verifier.rb +1 -2
  222. data/spec/runners/crud.rb +1 -1
  223. data/spec/runners/sdam.rb +2 -1
  224. data/spec/runners/transactions/test.rb +2 -2
  225. data/spec/runners/unified/assertions.rb +5 -4
  226. data/spec/runners/unified/crud_operations.rb +77 -23
  227. data/spec/runners/unified/ddl_operations.rb +29 -1
  228. data/spec/runners/unified/entity_map.rb +3 -3
  229. data/spec/runners/unified/event_subscriber.rb +2 -2
  230. data/spec/runners/unified/support_operations.rb +16 -3
  231. data/spec/runners/unified/test.rb +18 -3
  232. data/spec/runners/unified.rb +1 -1
  233. data/spec/shared/lib/mrss/cluster_config.rb +6 -1
  234. data/spec/shared/lib/mrss/constraints.rb +11 -5
  235. data/spec/shared/lib/mrss/event_subscriber.rb +200 -0
  236. data/spec/shared/lib/mrss/server_version_registry.rb +17 -12
  237. data/spec/shared/share/Dockerfile.erb +5 -4
  238. data/spec/shared/shlib/server.sh +70 -20
  239. data/spec/spec_tests/change_streams_spec.rb +1 -1
  240. data/spec/spec_tests/cmap_spec.rb +4 -1
  241. data/spec/spec_tests/command_monitoring_spec.rb +2 -2
  242. data/spec/spec_tests/data/command_monitoring/find.yml +9 -9
  243. data/spec/spec_tests/data/crud/read/aggregate-collation.yml +2 -1
  244. data/spec/spec_tests/data/crud/read/aggregate-out.yml +1 -0
  245. data/spec/spec_tests/data/crud/read/count-collation.yml +2 -1
  246. data/spec/spec_tests/data/crud/read/distinct-collation.yml +2 -1
  247. data/spec/spec_tests/data/crud/read/find-collation.yml +2 -1
  248. data/spec/spec_tests/data/crud/write/bulkWrite-collation.yml +2 -1
  249. data/spec/spec_tests/data/crud/write/deleteMany-collation.yml +2 -1
  250. data/spec/spec_tests/data/crud/write/deleteOne-collation.yml +2 -1
  251. data/spec/spec_tests/data/crud/write/findOneAndDelete-collation.yml +3 -2
  252. data/spec/spec_tests/data/crud/write/findOneAndReplace-collation.yml +2 -1
  253. data/spec/spec_tests/data/crud/write/findOneAndUpdate-collation.yml +3 -2
  254. data/spec/spec_tests/data/crud/write/replaceOne-collation.yml +3 -2
  255. data/spec/spec_tests/data/crud/write/updateMany-collation.yml +2 -1
  256. data/spec/spec_tests/data/crud/write/updateOne-collation.yml +2 -1
  257. data/spec/spec_tests/data/crud_unified/aggregate-let.yml +138 -0
  258. data/spec/spec_tests/data/crud_unified/aggregate-write-readPreference.yml +155 -0
  259. data/spec/spec_tests/data/crud_unified/db-aggregate-write-readPreference.yml +151 -0
  260. data/spec/spec_tests/data/crud_unified/deleteMany-let.yml +91 -0
  261. data/spec/spec_tests/data/crud_unified/deleteOne-let.yml +89 -0
  262. data/spec/spec_tests/data/crud_unified/find-let.yml +71 -0
  263. data/spec/spec_tests/data/crud_unified/findOneAndDelete-let.yml +88 -0
  264. data/spec/spec_tests/data/crud_unified/findOneAndReplace-let.yml +94 -0
  265. data/spec/spec_tests/data/crud_unified/findOneAndUpdate-let.yml +96 -0
  266. data/spec/spec_tests/data/crud_unified/updateMany-let.yml +103 -0
  267. data/spec/spec_tests/data/crud_unified/updateOne-let.yml +98 -0
  268. data/spec/spec_tests/data/load_balancers/event-monitoring.yml +99 -0
  269. data/spec/spec_tests/data/load_balancers/lb-connection-establishment.yml +36 -0
  270. data/spec/spec_tests/data/load_balancers/non-lb-connection-establishment.yml +56 -0
  271. data/spec/spec_tests/data/load_balancers/server-selection.yml +50 -0
  272. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/DefaultNoMaxStaleness.yml +2 -2
  273. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/LastUpdateTime.yml +3 -3
  274. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Nearest.yml +3 -3
  275. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Nearest2.yml +3 -3
  276. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred.yml +2 -2
  277. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred_tags.yml +2 -2
  278. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Secondary.yml +4 -4
  279. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred.yml +2 -2
  280. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred_tags.yml +4 -4
  281. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/ZeroMaxStaleness.yml +2 -2
  282. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/DefaultNoMaxStaleness.yml +2 -2
  283. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LastUpdateTime.yml +3 -3
  284. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LongHeartbeat.yml +2 -2
  285. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LongHeartbeat2.yml +2 -2
  286. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/MaxStalenessTooSmall.yml +2 -2
  287. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/MaxStalenessWithModePrimary.yml +2 -2
  288. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest.yml +3 -3
  289. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest2.yml +3 -3
  290. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest_tags.yml +2 -2
  291. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/PrimaryPreferred.yml +2 -2
  292. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred.yml +2 -2
  293. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags.yml +5 -5
  294. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags2.yml +3 -3
  295. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Secondary_tags.yml +5 -5
  296. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Secondary_tags2.yml +3 -3
  297. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/ZeroMaxStaleness.yml +2 -2
  298. data/spec/spec_tests/data/max_staleness/Sharded/SmallMaxStaleness.yml +2 -2
  299. data/spec/spec_tests/data/max_staleness/Single/SmallMaxStaleness.yml +1 -1
  300. data/spec/spec_tests/data/max_staleness/Unknown/SmallMaxStaleness.yml +1 -1
  301. data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch-serverErrors.yml +1 -1
  302. data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch.yml +1 -1
  303. data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch-serverErrors.yml +1 -1
  304. data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch.yml +1 -1
  305. data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch-serverErrors.yml +1 -1
  306. data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch.yml +1 -1
  307. data/spec/spec_tests/data/retryable_reads/mapReduce.yml +3 -1
  308. data/spec/spec_tests/data/sdam/load-balanced/discover_load_balancer.yml +25 -0
  309. data/spec/spec_tests/data/sdam_integration/find-network-error.yml +2 -0
  310. data/spec/spec_tests/data/sdam_integration/find-shutdown-error.yml +2 -0
  311. data/spec/spec_tests/data/sdam_integration/hello-command-error.yml +3 -1
  312. data/spec/spec_tests/data/sdam_integration/hello-network-error.yml +3 -1
  313. data/spec/spec_tests/data/sdam_integration/hello-timeout.yml +2 -0
  314. data/spec/spec_tests/data/sdam_integration/insert-network-error.yml +2 -0
  315. data/spec/spec_tests/data/sdam_integration/insert-shutdown-error.yml +2 -0
  316. data/spec/spec_tests/data/sdam_monitoring/load_balancer.yml +65 -0
  317. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-directConnection.yml +13 -0
  318. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-replicaSet-errors.yml +6 -0
  319. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-true-multiple-hosts.yml +5 -0
  320. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-true-txt.yml +10 -0
  321. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/direct-connection-false.yml +0 -0
  322. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/direct-connection-true.yml +0 -0
  323. data/spec/spec_tests/data/seed_list_discovery/replica-set/encoded-userinfo-and-db.yml +15 -0
  324. data/spec/spec_tests/data/seed_list_discovery/replica-set/loadBalanced-false-txt.yml +10 -0
  325. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/longer-parent-in-return.yml +0 -0
  326. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/misformatted-option.yml +0 -0
  327. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/no-results.yml +0 -0
  328. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/not-enough-parts.yml +0 -0
  329. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-result-default-port.yml +0 -0
  330. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-txt-record-multiple-strings.yml +0 -0
  331. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-txt-record.yml +0 -0
  332. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch1.yml +0 -0
  333. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch2.yml +0 -0
  334. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch3.yml +0 -0
  335. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch4.yml +0 -0
  336. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch5.yml +0 -0
  337. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/returned-parent-too-short.yml +0 -0
  338. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/returned-parent-wrong.yml +0 -0
  339. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-results-default-port.yml +0 -0
  340. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-results-nonstandard-port.yml +0 -0
  341. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-txt-records.yml +0 -0
  342. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-not-allowed-option.yml +0 -0
  343. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-overridden-ssl-option.yml +0 -0
  344. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-overridden-uri-option.yml +0 -0
  345. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-unallowed-option.yml +0 -0
  346. data/spec/spec_tests/data/seed_list_discovery/replica-set/uri-with-admin-database.yml +13 -0
  347. data/spec/spec_tests/data/seed_list_discovery/replica-set/uri-with-auth.yml +12 -0
  348. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/uri-with-port.yml +0 -0
  349. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/uri-with-two-hosts.yml +0 -0
  350. data/spec/spec_tests/data/sessions_unified/snapshot-sessions-not-supported-client-error.yml +69 -0
  351. data/spec/spec_tests/data/sessions_unified/snapshot-sessions-not-supported-server-error.yml +102 -0
  352. data/spec/spec_tests/data/sessions_unified/snapshot-sessions-unsupported-ops.yml +258 -0
  353. data/spec/spec_tests/data/sessions_unified/snapshot-sessions.yml +482 -0
  354. data/spec/spec_tests/data/transactions/retryable-abort-errorLabels.yml +2 -0
  355. data/spec/spec_tests/data/transactions/retryable-abort.yml +2 -0
  356. data/spec/spec_tests/data/transactions/retryable-commit-errorLabels.yml +2 -0
  357. data/spec/spec_tests/data/transactions/retryable-commit.yml +2 -0
  358. data/spec/spec_tests/data/transactions/retryable-writes.yml +2 -0
  359. data/spec/spec_tests/data/uri_options/connection-options.yml +60 -0
  360. data/spec/spec_tests/load_balancers_spec.rb +15 -0
  361. data/spec/spec_tests/retryable_reads_spec.rb +2 -2
  362. data/spec/spec_tests/retryable_writes_spec.rb +1 -1
  363. data/spec/spec_tests/sdam_integration_spec.rb +1 -1
  364. data/spec/spec_tests/sdam_monitoring_spec.rb +10 -5
  365. data/spec/spec_tests/sdam_spec.rb +1 -1
  366. data/spec/spec_tests/seed_list_discovery_spec.rb +118 -0
  367. data/spec/spec_tests/sessions_unified_spec.rb +13 -0
  368. data/spec/spec_tests/uri_options_spec.rb +4 -4
  369. data/spec/stress/fork_reconnect_stress_spec.rb +1 -5
  370. data/spec/stress/push_monitor_close_spec.rb +44 -0
  371. data/spec/support/certificates/atlas-ocsp-ca.crt +82 -90
  372. data/spec/support/certificates/atlas-ocsp.crt +127 -122
  373. data/spec/support/common_shortcuts.rb +2 -3
  374. data/spec/support/matchers.rb +13 -0
  375. data/spec/support/shared/auth_context.rb +16 -0
  376. data/spec/support/shared/session.rb +2 -2
  377. data/spec/support/spec_config.rb +10 -11
  378. data/spec/support/using_hash.rb +31 -0
  379. data/spec/support/utils.rb +1 -1
  380. data.tar.gz.sig +3 -4
  381. metadata +1111 -1029
  382. metadata.gz.sig +2 -3
  383. data/lib/mongo/collection/view/builder/find_command.rb +0 -173
  384. data/lib/mongo/collection/view/builder/op_query.rb +0 -94
  385. data/lib/mongo/cursor/builder/get_more_command.rb +0 -80
  386. data/lib/mongo/cursor/builder/kill_cursors_command.rb +0 -111
  387. data/lib/mongo/cursor/builder/op_get_more.rb +0 -64
  388. data/lib/mongo/cursor/builder/op_kill_cursors.rb +0 -106
  389. data/lib/mongo/server/context.rb +0 -72
  390. data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +0 -66
  391. data/spec/runners/unified/using_hash.rb +0 -34
  392. data/spec/spec_tests/dns_seedlist_discovery_spec.rb +0 -79
  393. data/spec/support/event_subscriber.rb +0 -221
@@ -194,13 +194,12 @@ module Mongo
194
194
  #
195
195
  # @raise [Mongo::Error] If handshake failed.
196
196
  def handshake!
197
- document = handshake_document(
198
- @app_metadata,
199
- server_api: options[:server_api]
197
+ command = handshake_command(
198
+ handshake_document(
199
+ @app_metadata,
200
+ server_api: options[:server_api]
201
+ )
200
202
  )
201
- # TODO (DR): OP_MSG should be used if api version is declared.
202
- # See https://github.com/mongodb/specifications/blob/master/source/message/OP_MSG.rst#id5
203
- command = Protocol::Query.new(Database::ADMIN, Database::COMMAND, document, :limit => -1)
204
203
  payload = command.serialize.to_s
205
204
  message = dispatch_bytes(payload)
206
205
  result = Operation::Result.new(message)
@@ -215,7 +215,8 @@ module Mongo
215
215
  old_description = server.description
216
216
 
217
217
  new_description = Description.new(server.address, result,
218
- server.round_trip_time_averager.average_round_trip_time)
218
+ average_round_trip_time: server.round_trip_time_averager.average_round_trip_time
219
+ )
219
220
 
220
221
  server.cluster.run_sdam_flow(server.description, new_description, awaited: awaited)
221
222
 
@@ -71,32 +71,41 @@ module Mongo
71
71
  raise Error::InternalDriverError, "Connection description cannot be unknown after successful handshake: #{description.inspect}"
72
72
  end
73
73
 
74
- if speculative_auth_doc && (speculative_auth_result = result['speculativeAuthenticate'])
75
- unless description.features.scram_sha_1_enabled?
76
- raise Error::InvalidServerAuthResponse, "Speculative auth succeeded on a pre-3.0 server"
77
- end
78
- case speculative_auth_user.mechanism
79
- when :mongodb_x509
80
- # Done
81
- # We default auth mechanism to scram256, but if user specified
82
- # scram explicitly we may be able to authenticate speculatively
83
- # with scram.
84
- when :scram, :scram256
85
- authenticate!(
86
- speculative_auth_client_nonce: speculative_auth.conversation.client_nonce,
87
- speculative_auth_mech: speculative_auth_user.mechanism,
88
- speculative_auth_result: speculative_auth_result,
89
- )
90
- else
91
- raise Error::InternalDriverError, "Speculative auth unexpectedly succeeded for mechanism #{speculative_auth_user.mechanism.inspect}"
74
+ begin
75
+ if speculative_auth_doc && (speculative_auth_result = result['speculativeAuthenticate'])
76
+ unless description.features.scram_sha_1_enabled?
77
+ raise Error::InvalidServerAuthResponse, "Speculative auth succeeded on a pre-3.0 server"
78
+ end
79
+ case speculative_auth_user.mechanism
80
+ when :mongodb_x509
81
+ # Done
82
+ # We default auth mechanism to scram256, but if user specified
83
+ # scram explicitly we may be able to authenticate speculatively
84
+ # with scram.
85
+ when :scram, :scram256
86
+ authenticate!(
87
+ speculative_auth_client_nonce: speculative_auth.conversation.client_nonce,
88
+ speculative_auth_mech: speculative_auth_user.mechanism,
89
+ speculative_auth_result: speculative_auth_result,
90
+ )
91
+ else
92
+ raise Error::InternalDriverError, "Speculative auth unexpectedly succeeded for mechanism #{speculative_auth_user.mechanism.inspect}"
93
+ end
94
+ elsif !description.arbiter?
95
+ authenticate!
92
96
  end
93
- elsif !description.arbiter?
94
- authenticate!
97
+ rescue Mongo::Error, Mongo::Error::AuthError => exc
98
+ exc.service_id = service_id
99
+ raise
95
100
  end
96
101
 
97
102
  if description.unknown?
98
103
  raise Error::InternalDriverError, "Connection description cannot be unknown after successful authentication: #{description.inspect}"
99
104
  end
105
+
106
+ if server.load_balancer? && !description.mongos?
107
+ raise Error::BadLoadBalancerTarget, "Load-balanced operation requires being connected a mongos, but the server at #{address.seed} reported itself as #{description.server_type.to_s.gsub('_', ' ')}"
108
+ end
100
109
  end
101
110
 
102
111
  private
@@ -111,16 +120,14 @@ module Mongo
111
120
  raise Error::InternalDriverError, "Cannot handshake because there is no usable socket (for #{address})"
112
121
  end
113
122
 
114
- hello_doc = handshake_document(
115
- app_metadata,
116
- speculative_auth_doc: speculative_auth_doc,
117
- server_api: options[:server_api],
123
+ hello_command = handshake_command(
124
+ handshake_document(
125
+ app_metadata,
126
+ speculative_auth_doc: speculative_auth_doc,
127
+ load_balancer: server.load_balancer?,
128
+ server_api: options[:server_api]
129
+ )
118
130
  )
119
-
120
- # TODO (DR): OP_MSG should be used if api version is declared.
121
- # See https://github.com/mongodb/specifications/blob/master/source/message/OP_MSG.rst#id5
122
- hello_command = Protocol::Query.new(Database::ADMIN, Database::COMMAND, hello_doc, :limit => -1)
123
-
124
131
  doc = nil
125
132
  @server.handle_handshake_failure! do
126
133
  begin
@@ -144,6 +151,10 @@ module Mongo
144
151
  end
145
152
  end
146
153
 
154
+ if @server.force_load_balancer?
155
+ doc['serviceId'] ||= "fake:#{rand(2**32-1)+1}"
156
+ end
157
+
147
158
  post_handshake(doc, @server.round_trip_time_averager.average_round_trip_time)
148
159
 
149
160
  doc
@@ -193,7 +204,7 @@ module Mongo
193
204
  # This is a separate method to keep the nesting level down.
194
205
  #
195
206
  # @return [ Server::Description ] The server description calculated from
196
- # hello response for this particular connection.
207
+ # the handshake response for this particular connection.
197
208
  def post_handshake(response, average_rtt)
198
209
  if response["ok"] == 1
199
210
  # Auth mechanism is entirely dependent on the contents of
@@ -210,7 +221,12 @@ module Mongo
210
221
  @sasl_supported_mechanisms = nil
211
222
  end
212
223
 
213
- @description = Description.new(address, response, average_rtt).tap do |new_description|
224
+ @description = Description.new(
225
+ address, response,
226
+ average_round_trip_time: average_rtt,
227
+ load_balancer: server.load_balancer?,
228
+ force_load_balancer: options[:connect] == :load_balanced,
229
+ ).tap do |new_description|
214
230
  @server.cluster.run_sdam_flow(@server.description, new_description)
215
231
  end
216
232
  end
@@ -110,13 +110,22 @@ module Mongo
110
110
  if new_description.topology_version
111
111
  @topology_version = new_description.topology_version
112
112
  end
113
- rescue Mongo::Error => exc
113
+ rescue IOError, SocketError, SystemCallError, Mongo::Error => exc
114
+ stop_requested = @lock.synchronize { @stop_requested }
115
+ if stop_requested
116
+ # Ignore the exception, see RUBY-2771.
117
+ return
118
+ end
119
+
114
120
  msg = "Error running awaited hello on #{server.address}"
115
121
  Utils.warn_bg_exception(msg, exc,
116
122
  logger: options[:logger],
117
123
  log_prefix: options[:log_prefix],
118
124
  bg_error_backtrace: options[:bg_error_backtrace],
119
125
  )
126
+
127
+ # Avoid tight looping in push monitor - see RUBY-2806.
128
+ sleep(0.5)
120
129
  end
121
130
 
122
131
  def check
data/lib/mongo/server.rb CHANGED
@@ -54,6 +54,9 @@ module Mongo
54
54
  # done by this server. Note: setting this option to false will make
55
55
  # the server non-functional. It is intended for use in tests which
56
56
  # manually invoke SDAM state transitions.
57
+ # @option options [ true | false ] :load_balancer Whether this server
58
+ # is a load balancer.
59
+ # @option options [ String ] :connect The client connection mode.
57
60
  #
58
61
  # @since 2.0.0
59
62
  def initialize(address, cluster, monitoring, event_listeners, options = {})
@@ -69,7 +72,10 @@ module Mongo
69
72
  end
70
73
  @scan_semaphore = DistinguishingSemaphore.new
71
74
  @round_trip_time_averager = RoundTripTimeAverager.new
72
- @description = Description.new(address, {})
75
+ @description = Description.new(address, {},
76
+ load_balancer: !!@options[:load_balancer],
77
+ force_load_balancer: force_load_balancer?,
78
+ )
73
79
  @last_scan = nil
74
80
  @last_scan_monotime = nil
75
81
  unless options[:monitoring_io] == false
@@ -107,6 +113,15 @@ module Mongo
107
113
  # description the monitor refreshes.
108
114
  attr_reader :description
109
115
 
116
+ # Returns whether this server is forced to be a load balancer.
117
+ #
118
+ # @return [ true | false ] Whether this server is forced to be a load balancer.
119
+ #
120
+ # @api private
121
+ def force_load_balancer?
122
+ options[:connect] == :load_balanced
123
+ end
124
+
110
125
  # @return [ Time | nil ] last_scan The time when the last server scan
111
126
  # completed, or nil if the server has not been scanned yet.
112
127
  #
@@ -180,6 +195,7 @@ module Mongo
180
195
  :secondary?,
181
196
  :standalone?,
182
197
  :unknown?,
198
+ :load_balancer?,
183
199
  :last_write_date,
184
200
  :logical_session_timeout
185
201
 
@@ -222,20 +238,6 @@ module Mongo
222
238
  address == other.address
223
239
  end
224
240
 
225
- # Get a new context for this server in which to send messages.
226
- #
227
- # @example Get the server context.
228
- # server.context
229
- #
230
- # @return [ Mongo::Server::Context ] context The server context.
231
- #
232
- # @since 2.0.0
233
- #
234
- # @deprecated Will be removed in version 3.0
235
- def context
236
- Context.new(self)
237
- end
238
-
239
241
  # Determine if a connection to the server is able to be established and
240
242
  # messages can be sent to it.
241
243
  #
@@ -301,13 +303,20 @@ module Mongo
301
303
  #
302
304
  # @api private
303
305
  def start_monitoring
306
+ publish_opening_event
307
+ if options[:monitoring_io] != false
308
+ monitor.run!
309
+ end
310
+ end
311
+
312
+ # Publishes the server opening event.
313
+ #
314
+ # @api private
315
+ def publish_opening_event
304
316
  publish_sdam_event(
305
317
  Monitoring::SERVER_OPENING,
306
318
  Monitoring::Event::ServerOpening.new(address, cluster.topology)
307
319
  )
308
- if options[:monitoring_io] != false
309
- monitor.run!
310
- end
311
320
  end
312
321
 
313
322
  # Get a pretty printed server inspection.
@@ -327,6 +336,8 @@ module Mongo
327
336
  # @api private
328
337
  def status
329
338
  case
339
+ when load_balancer?
340
+ 'LB'
330
341
  when primary?
331
342
  'PRIMARY'
332
343
  when secondary?
@@ -433,8 +444,8 @@ module Mongo
433
444
  # @return [ Object ] The result of the block execution.
434
445
  #
435
446
  # @since 2.3.0
436
- def with_connection(&block)
437
- pool.with_connection(&block)
447
+ def with_connection(service_id: nil, &block)
448
+ pool.with_connection(service_id: service_id, &block)
438
449
  end
439
450
 
440
451
  # Handle handshake failure.
@@ -444,7 +455,11 @@ module Mongo
444
455
  def handle_handshake_failure!
445
456
  yield
446
457
  rescue Mongo::Error::SocketError, Mongo::Error::SocketTimeoutError => e
447
- unknown!(generation: e.generation, stop_push_monitor: true)
458
+ unknown!(
459
+ generation: e.generation,
460
+ service_id: e.service_id,
461
+ stop_push_monitor: true,
462
+ )
448
463
  raise
449
464
  end
450
465
 
@@ -467,7 +482,11 @@ module Mongo
467
482
  raise
468
483
  rescue Mongo::Error::SocketError => e
469
484
  # non-timeout network error
470
- unknown!(generation: e.generation, stop_push_monitor: true)
485
+ unknown!(
486
+ generation: e.generation,
487
+ service_id: e.service_id,
488
+ stop_push_monitor: true,
489
+ )
471
490
  raise
472
491
  rescue Auth::Unauthorized
473
492
  # auth error, keep server description and topology as they are
@@ -513,13 +532,33 @@ module Mongo
513
532
  # respective server is cleared. Set this option to true to keep the
514
533
  # existing connection pool (required when handling not master errors
515
534
  # on 4.2+ servers).
535
+ # @option options [ Object ] :service_id Discard state for the specified
536
+ # service id only.
516
537
  # @option options [ TopologyVersion ] :topology_version Topology version
517
538
  # of the error response that is causing the server to be marked unknown.
518
539
  # @option options [ true | false ] :stop_push_monitor Whether to stop
519
540
  # the PushMonitor associated with the server, if any.
541
+ # @option options [ Object ] :service_id Discard state for the specified
542
+ # service id only.
520
543
  #
521
544
  # @since 2.4.0, SDAM events are sent as of version 2.7.0
522
545
  def unknown!(options = {})
546
+ if load_balancer?
547
+ # When the client is in load-balanced topology, servers (the one and
548
+ # only that can be) starts out as a load balancer and stays as a
549
+ # load balancer indefinitely. As such it is not marked unknown.
550
+ #
551
+ # However, this method also clears connection pool for the server
552
+ # when the latter is marked unknown, and this part needs to happen
553
+ # when the server is a load balancer.
554
+ if service_id = options[:service_id]
555
+ pool.disconnect!(service_id: service_id)
556
+ elsif Lint.enabled?
557
+ raise Error::LintError, 'Load balancer was asked to be marked unknown without a service id'
558
+ end
559
+ return
560
+ end
561
+
523
562
  if options[:generation] && options[:generation] < pool.generation
524
563
  return
525
564
  end
@@ -537,10 +576,16 @@ module Mongo
537
576
  # SDAM flow will update description on the server without in-place
538
577
  # mutations and invoke SDAM transitions as needed.
539
578
  config = {}
579
+ if options[:service_id]
580
+ config['serviceId'] = options[:service_id]
581
+ end
540
582
  if options[:topology_version]
541
583
  config['topologyVersion'] = options[:topology_version]
542
584
  end
543
- new_description = Description.new(address, config)
585
+ new_description = Description.new(address, config,
586
+ load_balancer: load_balancer?,
587
+ force_load_balancer: options[:connect] == :load_balanced,
588
+ )
544
589
  cluster.run_sdam_flow(description, new_description, options)
545
590
  end
546
591
 
@@ -549,11 +594,14 @@ module Mongo
549
594
  @description = description
550
595
  end
551
596
 
597
+ # @param [ Object ] :service_id Close connections with the specified
598
+ # service id only.
599
+ #
552
600
  # @api private
553
- def clear_connection_pool
601
+ def clear_connection_pool(service_id: nil)
554
602
  @pool_lock.synchronize do
555
603
  if @pool
556
- @pool.disconnect!
604
+ @pool.disconnect!(service_id: service_id)
557
605
  end
558
606
  end
559
607
  end
@@ -577,7 +625,6 @@ require 'mongo/server/connection_base'
577
625
  require 'mongo/server/pending_connection'
578
626
  require 'mongo/server/connection'
579
627
  require 'mongo/server/connection_pool'
580
- require 'mongo/server/context'
581
628
  require 'mongo/server/description'
582
629
  require 'mongo/server/monitor'
583
630
  require 'mongo/server/round_trip_time_averager'
@@ -162,6 +162,8 @@ module Mongo
162
162
  # Deprecated and ignored.
163
163
  # @param [ Session | nil ] session Optional session to take into account
164
164
  # for mongos pinning. Added in version 2.10.0.
165
+ # @param [ true | false ] write_aggregation Whether we need a server that
166
+ # supports writing aggregations (e.g. with $merge/$out) on secondaries.
165
167
  #
166
168
  # @return [ Mongo::Server ] A server matching the server preference.
167
169
  #
@@ -172,7 +174,11 @@ module Mongo
172
174
  # lint mode is enabled.
173
175
  #
174
176
  # @since 2.0.0
175
- def select_server(cluster, ping = nil, session = nil)
177
+ def select_server(cluster, ping = nil, session = nil, write_aggregation: false)
178
+ if cluster.topology.is_a?(Cluster::Topology::LoadBalanced)
179
+ return cluster.servers.first
180
+ end
181
+
176
182
  server_selection_timeout = cluster.options[:server_selection_timeout] || SERVER_SELECTION_TIMEOUT
177
183
 
178
184
  # Special handling for zero timeout: if we have to select a server,
@@ -239,7 +245,7 @@ module Mongo
239
245
  =end
240
246
 
241
247
  loop do
242
- server = try_select_server(cluster)
248
+ server = try_select_server(cluster, write_aggregation: write_aggregation)
243
249
 
244
250
  if server
245
251
  unless cluster.topology.compatible?
@@ -247,7 +253,7 @@ module Mongo
247
253
  end
248
254
 
249
255
  if session && session.starting_transaction? && cluster.sharded?
250
- session.pin(server)
256
+ session.pin_to_server(server)
251
257
  end
252
258
 
253
259
  return server
@@ -290,11 +296,31 @@ module Mongo
290
296
  # Tries to find a suitable server, returns the server if one is available
291
297
  # or nil if there isn't a suitable server.
292
298
  #
299
+ # @param [ Mongo::Cluster ] cluster The cluster from which to select
300
+ # an eligible server.
301
+ # @param [ true | false ] write_aggregation Whether we need a server that
302
+ # supports writing aggregations (e.g. with $merge/$out) on secondaries.
303
+ #
293
304
  # @return [ Server | nil ] A suitable server, if one exists.
294
305
  #
295
306
  # @api private
296
- def try_select_server(cluster)
297
- servers = suitable_servers(cluster)
307
+ def try_select_server(cluster, write_aggregation: false)
308
+ servers = if write_aggregation && cluster.replica_set?
309
+ # 1. Check if ALL servers in cluster support secondary writes.
310
+ is_write_supported = cluster.servers.reduce(true) do |res, server|
311
+ res && server.features.merge_out_on_secondary_enabled?
312
+ end
313
+
314
+ if is_write_supported
315
+ # 2. If all servers support secondary writes, we respect read preference.
316
+ suitable_servers(cluster)
317
+ else
318
+ # 3. Otherwise we fallback to primary for replica set.
319
+ [cluster.servers.detect(&:primary?)]
320
+ end
321
+ else
322
+ suitable_servers(cluster)
323
+ end
298
324
 
299
325
  # This list of servers may be ordered in a specific way
300
326
  # by the selector (e.g. for secondary preferred, the first
@@ -133,6 +133,13 @@ module Mongo
133
133
  private
134
134
 
135
135
  def about_to_expire?(session)
136
+ # Load balancers spec explicitly requires to ignore the logical session
137
+ # timeout value.
138
+ # No rationale is provided as of the time of this writing.
139
+ if @cluster.load_balanced?
140
+ return false
141
+ end
142
+
136
143
  logical_session_timeout = @cluster.logical_session_timeout
137
144
 
138
145
  if logical_session_timeout
@@ -142,6 +149,10 @@ module Mongo
142
149
  end
143
150
 
144
151
  def prune!
152
+ # Load balancers spec explicitly requires not to prune sessions.
153
+ # No rationale is provided as of the time of this writing.
154
+ return if @cluster.load_balanced?
155
+
145
156
  while !@queue.empty?
146
157
  if about_to_expire?(@queue[-1])
147
158
  @queue.pop
data/lib/mongo/session.rb CHANGED
@@ -56,10 +56,16 @@ module Mongo
56
56
  # - *:mode* -- the read preference as a string or symbol; valid values are
57
57
  # *:primary*, *:primary_preferred*, *:secondary*, *:secondary_preferred*
58
58
  # and *:nearest*.
59
+ # @option options [ true | false ] :snapshot Set up the session for
60
+ # snapshot reads.
59
61
  #
60
62
  # @since 2.5.0
61
63
  # @api private
62
64
  def initialize(server_session, client, options = {})
65
+ if options[:causal_consistency] && options[:snapshot]
66
+ raise ArgumentError, ':causal_consistency and :snapshot options cannot be both set on a session'
67
+ end
68
+
63
69
  @server_session = server_session
64
70
  options = options.dup
65
71
 
@@ -83,6 +89,12 @@ module Mongo
83
89
  @client.cluster
84
90
  end
85
91
 
92
+ # @return [ true | false ] Whether the session is configured for snapshot
93
+ # reads.
94
+ def snapshot?
95
+ !!options[:snapshot]
96
+ end
97
+
86
98
  # @return [ BSON::Timestamp ] The latest seen operation time for this session.
87
99
  #
88
100
  # @since 2.5.0
@@ -208,6 +220,12 @@ module Mongo
208
220
  # @api private
209
221
  attr_reader :pinned_server
210
222
 
223
+ # @return [ Object | nil ] The service id that this session is pinned to,
224
+ # if any.
225
+ #
226
+ # @api private
227
+ attr_reader :pinned_service_id
228
+
211
229
  # @return [ BSON::Document | nil ] Recovery token for the sharded
212
230
  # transaction being executed on this session, if any.
213
231
  #
@@ -430,6 +448,7 @@ module Mongo
430
448
  transaction_in_progress = false
431
449
  raise
432
450
  end
451
+ @state = NO_TRANSACTION_STATE
433
452
  next
434
453
  else
435
454
  transaction_in_progress = false
@@ -499,6 +518,10 @@ module Mongo
499
518
  =end
500
519
  end
501
520
 
521
+ if snapshot?
522
+ raise Mongo::Error::SnapshotSessionTransactionProhibited
523
+ end
524
+
502
525
  check_if_ended!
503
526
 
504
527
  if within_states?(STARTING_TRANSACTION_STATE, TRANSACTION_IN_PROGRESS_STATE)
@@ -695,7 +718,7 @@ module Mongo
695
718
  # @param [ Server ] server The server to pin this session to.
696
719
  #
697
720
  # @api private
698
- def pin(server)
721
+ def pin_to_server(server)
699
722
  if server.nil?
700
723
  raise ArgumentError, 'Cannot pin to a nil server'
701
724
  end
@@ -707,11 +730,24 @@ module Mongo
707
730
  @pinned_server = server
708
731
  end
709
732
 
733
+ # Pins this session to the specified service.
734
+ #
735
+ # @param [ Object ] service_id The service id to pin this session to.
736
+ #
737
+ # @api private
738
+ def pin_to_service(service_id)
739
+ if service_id.nil?
740
+ raise ArgumentError, 'Cannot pin to a nil service id'
741
+ end
742
+ @pinned_service_id = service_id
743
+ end
744
+
710
745
  # Unpins this session from the pinned server, if the session was pinned.
711
746
  #
712
747
  # @api private
713
748
  def unpin
714
749
  @pinned_server = nil
750
+ @pinned_service_id = nil
715
751
  end
716
752
 
717
753
  # Unpins this session from the pinned server, if the session was pinned
@@ -1004,6 +1040,9 @@ module Mongo
1004
1040
  @server_session.txn_num
1005
1041
  end
1006
1042
 
1043
+ # @api private
1044
+ attr_accessor :snapshot_timestamp
1045
+
1007
1046
  private
1008
1047
 
1009
1048
  # Get the read concern the session will use when starting a transaction.
@@ -21,8 +21,7 @@ module Mongo
21
21
  # This module caches OCSP responses for their indicated validity time.
22
22
  #
23
23
  # The key is the CertificateId used for the OCSP request.
24
- # The value is the SingleResponse on Ruby 2.4+, or the OpenStruct
25
- # emulation of it on Ruby 2.3.
24
+ # The value is the SingleResponse.
26
25
  #
27
26
  # @api private
28
27
  module OcspCache
@@ -40,7 +39,7 @@ module Mongo
40
39
  # expire by the time caller uses them. The caller should not perform
41
40
  # update time checks on the returned response.
42
41
  #
43
- # @return [ OpenSSL::OCSP::SingleResponse | OpenStruct ] The previously
42
+ # @return [ OpenSSL::OCSP::SingleResponse ] The previously
44
43
  # retrieved response.
45
44
  module_function def get(cert_id)
46
45
  resp = responses.detect do |resp|
@@ -237,43 +237,12 @@ module Mongo
237
237
  return false
238
238
  end
239
239
 
240
- if resp.respond_to?(:find_response)
241
- # Ruby 2.4+
242
- resp = resp.find_response(cert_id)
243
- # TODO make a new class instead of patching the stdlib one?
244
- resp.instance_variable_set('@uri', uri)
245
- resp.instance_variable_set('@original_uri', original_uri)
246
- class << resp
247
- attr_reader :uri, :original_uri
248
- end
249
- else
250
- # Ruby 2.3
251
- found = nil
252
- resp.status.each do |_cert_id, cert_status, revocation_reason, revocation_time, this_update, next_update, extensions|
253
- if _cert_id.cmp(cert_id)
254
- found = OpenStruct.new(
255
- cert_status: cert_status,
256
- certid: _cert_id,
257
- next_update: next_update,
258
- this_update: this_update,
259
- revocation_reason: revocation_reason,
260
- revocation_time: revocation_time,
261
- extensions: extensions,
262
- uri: uri,
263
- original_uri: original_uri,
264
- )
265
- class << found
266
- # Unlike the stdlib method, this one doesn't accept
267
- # any arguments.
268
- def check_validity
269
- now = Time.now
270
- this_update <= now && next_update >= now
271
- end
272
- end
273
- break
274
- end
275
- end
276
- resp = found
240
+ resp = resp.find_response(cert_id)
241
+ # TODO make a new class instead of patching the stdlib one?
242
+ resp.instance_variable_set('@uri', uri)
243
+ resp.instance_variable_set('@original_uri', original_uri)
244
+ class << resp
245
+ attr_reader :uri, :original_uri
277
246
  end
278
247
 
279
248
  unless resp
data/lib/mongo/socket.rb CHANGED
@@ -362,11 +362,7 @@ module Mongo
362
362
  end
363
363
 
364
364
  def allocate_string(capacity)
365
- if RUBY_VERSION >= '2.4.0'
366
- String.new('', :capacity => capacity, :encoding => 'BINARY')
367
- else
368
- ('x'*capacity).force_encoding('BINARY')
369
- end
365
+ String.new('', :capacity => capacity, :encoding => 'BINARY')
370
366
  end
371
367
 
372
368
  def read_buffer_size
@@ -268,6 +268,7 @@ module Mongo
268
268
  # Topology options
269
269
  uri_option 'directConnection', :direct_connection, type: :bool
270
270
  uri_option 'connect', :connect, type: :symbol
271
+ uri_option 'loadBalanced', :load_balanced, type: :bool
271
272
 
272
273
  # Auth Options
273
274
  uri_option 'authSource', :auth_source