mongo 2.23.0 → 2.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. checksums.yaml +4 -4
  2. data/bin/mongo_console +0 -1
  3. data/lib/mongo/active_support.rb +1 -2
  4. data/lib/mongo/address/ipv4.rb +3 -6
  5. data/lib/mongo/address/ipv6.rb +6 -10
  6. data/lib/mongo/address/unix.rb +1 -4
  7. data/lib/mongo/address/validator.rb +16 -28
  8. data/lib/mongo/address.rb +30 -40
  9. data/lib/mongo/auth/aws/conversation.rb +6 -10
  10. data/lib/mongo/auth/aws/credentials.rb +0 -1
  11. data/lib/mongo/auth/aws/credentials_cache.rb +0 -1
  12. data/lib/mongo/auth/aws/credentials_retriever.rb +45 -59
  13. data/lib/mongo/auth/aws/request.rb +20 -35
  14. data/lib/mongo/auth/aws.rb +1 -2
  15. data/lib/mongo/auth/base.rb +20 -29
  16. data/lib/mongo/auth/conversation_base.rb +14 -18
  17. data/lib/mongo/auth/cr/conversation.rb +0 -3
  18. data/lib/mongo/auth/cr.rb +1 -4
  19. data/lib/mongo/auth/credential_cache.rb +0 -2
  20. data/lib/mongo/auth/gssapi/conversation.rb +3 -8
  21. data/lib/mongo/auth/gssapi.rb +1 -4
  22. data/lib/mongo/auth/ldap/conversation.rb +0 -3
  23. data/lib/mongo/auth/ldap.rb +1 -4
  24. data/lib/mongo/auth/roles.rb +16 -19
  25. data/lib/mongo/auth/sasl_conversation_base.rb +7 -11
  26. data/lib/mongo/auth/scram/conversation.rb +2 -5
  27. data/lib/mongo/auth/scram.rb +5 -10
  28. data/lib/mongo/auth/scram256/conversation.rb +2 -5
  29. data/lib/mongo/auth/scram256.rb +1 -3
  30. data/lib/mongo/auth/scram_conversation_base.rb +18 -24
  31. data/lib/mongo/auth/stringprep/profiles/sasl.rb +17 -18
  32. data/lib/mongo/auth/stringprep/tables.rb +2209 -2210
  33. data/lib/mongo/auth/stringprep/unicode_normalize/normalize.rb +36 -38
  34. data/lib/mongo/auth/stringprep/unicode_normalize/tables.rb +1142 -1150
  35. data/lib/mongo/auth/stringprep.rb +9 -12
  36. data/lib/mongo/auth/user/view.rb +3 -5
  37. data/lib/mongo/auth/user.rb +14 -24
  38. data/lib/mongo/auth/x509/conversation.rb +0 -3
  39. data/lib/mongo/auth/x509.rb +7 -9
  40. data/lib/mongo/auth.rb +18 -30
  41. data/lib/mongo/background_thread.rb +9 -17
  42. data/lib/mongo/bson.rb +0 -2
  43. data/lib/mongo/bulk_write/combineable.rb +0 -3
  44. data/lib/mongo/bulk_write/ordered_combiner.rb +1 -3
  45. data/lib/mongo/bulk_write/result.rb +11 -16
  46. data/lib/mongo/bulk_write/result_combiner.rb +9 -12
  47. data/lib/mongo/bulk_write/transformable.rb +16 -19
  48. data/lib/mongo/bulk_write/unordered_combiner.rb +1 -3
  49. data/lib/mongo/bulk_write/validatable.rb +11 -18
  50. data/lib/mongo/bulk_write.rb +76 -91
  51. data/lib/mongo/caching_cursor.rb +2 -7
  52. data/lib/mongo/client.rb +230 -275
  53. data/lib/mongo/client_encryption.rb +4 -5
  54. data/lib/mongo/cluster/periodic_executor.rb +2 -5
  55. data/lib/mongo/cluster/reapers/cursor_reaper.rb +21 -29
  56. data/lib/mongo/cluster/reapers/socket_reaper.rb +1 -6
  57. data/lib/mongo/cluster/sdam_flow.rb +136 -159
  58. data/lib/mongo/cluster/topology/base.rb +15 -18
  59. data/lib/mongo/cluster/topology/load_balanced.rb +24 -14
  60. data/lib/mongo/cluster/topology/no_replica_set_options.rb +3 -6
  61. data/lib/mongo/cluster/topology/replica_set_no_primary.rb +20 -23
  62. data/lib/mongo/cluster/topology/replica_set_with_primary.rb +0 -2
  63. data/lib/mongo/cluster/topology/sharded.rb +19 -9
  64. data/lib/mongo/cluster/topology/single.rb +24 -14
  65. data/lib/mongo/cluster/topology/unknown.rb +20 -10
  66. data/lib/mongo/cluster/topology.rb +29 -25
  67. data/lib/mongo/cluster.rb +148 -183
  68. data/lib/mongo/cluster_time.rb +14 -31
  69. data/lib/mongo/collection/helpers.rb +5 -8
  70. data/lib/mongo/collection/view/aggregation.rb +5 -10
  71. data/lib/mongo/collection/view/builder/aggregation.rb +6 -9
  72. data/lib/mongo/collection/view/builder/map_reduce.rb +18 -17
  73. data/lib/mongo/collection/view/builder.rb +0 -1
  74. data/lib/mongo/collection/view/change_stream/retryable.rb +3 -8
  75. data/lib/mongo/collection/view/change_stream.rb +59 -58
  76. data/lib/mongo/collection/view/explainable.rb +11 -20
  77. data/lib/mongo/collection/view/immutable.rb +1 -3
  78. data/lib/mongo/collection/view/iterable.rb +35 -28
  79. data/lib/mongo/collection/view/map_reduce.rb +20 -25
  80. data/lib/mongo/collection/view/readable.rb +50 -57
  81. data/lib/mongo/collection/view/writable.rb +56 -72
  82. data/lib/mongo/collection/view.rb +9 -8
  83. data/lib/mongo/collection.rb +63 -76
  84. data/lib/mongo/condition_variable.rb +4 -4
  85. data/lib/mongo/config/options.rb +0 -3
  86. data/lib/mongo/config/validators/option.rb +3 -5
  87. data/lib/mongo/config.rb +2 -4
  88. data/lib/mongo/crypt/auto_decryption_context.rb +0 -3
  89. data/lib/mongo/crypt/auto_encrypter.rb +34 -43
  90. data/lib/mongo/crypt/auto_encryption_context.rb +0 -3
  91. data/lib/mongo/crypt/binary.rb +5 -9
  92. data/lib/mongo/crypt/binding.rb +149 -155
  93. data/lib/mongo/crypt/context.rb +10 -17
  94. data/lib/mongo/crypt/data_key_context.rb +2 -7
  95. data/lib/mongo/crypt/encryption_io.rb +29 -39
  96. data/lib/mongo/crypt/explicit_decryption_context.rb +0 -3
  97. data/lib/mongo/crypt/explicit_encrypter.rb +1 -1
  98. data/lib/mongo/crypt/explicit_encryption_context.rb +19 -30
  99. data/lib/mongo/crypt/explicit_encryption_expression_context.rb +0 -2
  100. data/lib/mongo/crypt/handle.rb +42 -48
  101. data/lib/mongo/crypt/hooks.rb +12 -15
  102. data/lib/mongo/crypt/kms/aws/credentials.rb +12 -16
  103. data/lib/mongo/crypt/kms/aws/master_document.rb +6 -9
  104. data/lib/mongo/crypt/kms/aws.rb +0 -2
  105. data/lib/mongo/crypt/kms/azure/credentials_retriever.rb +2 -7
  106. data/lib/mongo/crypt/kms/azure/master_document.rb +15 -19
  107. data/lib/mongo/crypt/kms/azure.rb +0 -1
  108. data/lib/mongo/crypt/kms/credentials.rb +13 -27
  109. data/lib/mongo/crypt/kms/gcp/credentials.rb +12 -14
  110. data/lib/mongo/crypt/kms/gcp/credentials_retriever.rb +7 -9
  111. data/lib/mongo/crypt/kms/gcp/master_document.rb +12 -16
  112. data/lib/mongo/crypt/kms/gcp.rb +0 -2
  113. data/lib/mongo/crypt/kms/kmip/credentials.rb +7 -8
  114. data/lib/mongo/crypt/kms/kmip/master_document.rb +3 -5
  115. data/lib/mongo/crypt/kms/kmip.rb +0 -1
  116. data/lib/mongo/crypt/kms/local/credentials.rb +7 -8
  117. data/lib/mongo/crypt/kms/local/master_document.rb +2 -6
  118. data/lib/mongo/crypt/kms/local.rb +0 -1
  119. data/lib/mongo/crypt/kms/master_key_document.rb +11 -15
  120. data/lib/mongo/crypt/kms.rb +14 -16
  121. data/lib/mongo/crypt/kms_context.rb +0 -2
  122. data/lib/mongo/crypt/rewrap_many_data_key_context.rb +2 -7
  123. data/lib/mongo/crypt/rewrap_many_data_key_result.rb +2 -4
  124. data/lib/mongo/crypt/status.rb +12 -14
  125. data/lib/mongo/crypt.rb +0 -1
  126. data/lib/mongo/csot_timeout_holder.rb +3 -2
  127. data/lib/mongo/cursor/kill_spec.rb +7 -10
  128. data/lib/mongo/cursor.rb +74 -64
  129. data/lib/mongo/cursor_host.rb +8 -10
  130. data/lib/mongo/database/view.rb +16 -37
  131. data/lib/mongo/database.rb +52 -56
  132. data/lib/mongo/dbref.rb +0 -1
  133. data/lib/mongo/distinguishing_semaphore.rb +0 -1
  134. data/lib/mongo/error/auth_error.rb +0 -2
  135. data/lib/mongo/error/bad_load_balancer_target.rb +0 -2
  136. data/lib/mongo/error/bulk_write_error.rb +7 -10
  137. data/lib/mongo/error/change_stream_resumable.rb +0 -2
  138. data/lib/mongo/error/client_closed.rb +0 -2
  139. data/lib/mongo/error/closed_stream.rb +1 -4
  140. data/lib/mongo/error/connection_check_out_timeout.rb +3 -6
  141. data/lib/mongo/error/connection_perished.rb +0 -2
  142. data/lib/mongo/error/connection_unavailable.rb +0 -2
  143. data/lib/mongo/error/credential_check_error.rb +0 -2
  144. data/lib/mongo/error/crypt_error.rb +0 -2
  145. data/lib/mongo/error/extra_file_chunk.rb +1 -4
  146. data/lib/mongo/error/failed_string_prep_validation.rb +5 -6
  147. data/lib/mongo/error/file_not_found.rb +0 -3
  148. data/lib/mongo/error/handshake_error.rb +0 -2
  149. data/lib/mongo/error/insufficient_iteration_count.rb +1 -4
  150. data/lib/mongo/error/internal_driver_error.rb +0 -2
  151. data/lib/mongo/error/invalid_address.rb +0 -2
  152. data/lib/mongo/error/invalid_application_name.rb +0 -3
  153. data/lib/mongo/error/invalid_bulk_operation.rb +1 -4
  154. data/lib/mongo/error/invalid_bulk_operation_type.rb +1 -4
  155. data/lib/mongo/error/invalid_collection_name.rb +1 -4
  156. data/lib/mongo/error/invalid_config_option.rb +0 -3
  157. data/lib/mongo/error/invalid_cursor_operation.rb +0 -2
  158. data/lib/mongo/error/invalid_database_name.rb +1 -4
  159. data/lib/mongo/error/invalid_document.rb +1 -4
  160. data/lib/mongo/error/invalid_file.rb +0 -3
  161. data/lib/mongo/error/invalid_file_revision.rb +0 -3
  162. data/lib/mongo/error/invalid_min_pool_size.rb +0 -3
  163. data/lib/mongo/error/invalid_nonce.rb +0 -3
  164. data/lib/mongo/error/invalid_read_concern.rb +2 -4
  165. data/lib/mongo/error/invalid_read_option.rb +0 -3
  166. data/lib/mongo/error/invalid_replacement_document.rb +2 -5
  167. data/lib/mongo/error/invalid_server_auth_host.rb +0 -2
  168. data/lib/mongo/error/invalid_server_auth_response.rb +0 -2
  169. data/lib/mongo/error/invalid_server_preference.rb +7 -16
  170. data/lib/mongo/error/invalid_session.rb +1 -4
  171. data/lib/mongo/error/invalid_signature.rb +0 -3
  172. data/lib/mongo/error/invalid_transaction_operation.rb +5 -8
  173. data/lib/mongo/error/invalid_txt_record.rb +0 -2
  174. data/lib/mongo/error/invalid_update_document.rb +2 -5
  175. data/lib/mongo/error/invalid_uri.rb +1 -4
  176. data/lib/mongo/error/invalid_write_concern.rb +2 -5
  177. data/lib/mongo/error/kms_error.rb +0 -2
  178. data/lib/mongo/error/labelable.rb +0 -3
  179. data/lib/mongo/error/lint_error.rb +0 -2
  180. data/lib/mongo/error/max_bson_size.rb +8 -11
  181. data/lib/mongo/error/max_message_size.rb +2 -5
  182. data/lib/mongo/error/mismatched_domain.rb +0 -2
  183. data/lib/mongo/error/missing_connection.rb +0 -2
  184. data/lib/mongo/error/missing_file_chunk.rb +0 -3
  185. data/lib/mongo/error/missing_password.rb +0 -2
  186. data/lib/mongo/error/missing_resume_token.rb +1 -4
  187. data/lib/mongo/error/missing_scram_server_signature.rb +2 -4
  188. data/lib/mongo/error/missing_service_id.rb +0 -2
  189. data/lib/mongo/error/mongocryptd_spawn_error.rb +0 -2
  190. data/lib/mongo/error/multi_index_drop.rb +0 -3
  191. data/lib/mongo/error/need_primary_server.rb +0 -2
  192. data/lib/mongo/error/no_server_available.rb +3 -8
  193. data/lib/mongo/error/no_service_connection_available.rb +1 -3
  194. data/lib/mongo/error/no_srv_records.rb +0 -2
  195. data/lib/mongo/error/notable.rb +8 -16
  196. data/lib/mongo/error/operation_failure.rb +22 -35
  197. data/lib/mongo/error/parser.rb +33 -75
  198. data/lib/mongo/error/pool_cleared_error.rb +1 -3
  199. data/lib/mongo/error/pool_closed_error.rb +0 -3
  200. data/lib/mongo/error/pool_error.rb +0 -3
  201. data/lib/mongo/error/pool_paused_error.rb +0 -2
  202. data/lib/mongo/error/raise_original_error.rb +1 -3
  203. data/lib/mongo/error/read_write_retryable.rb +14 -17
  204. data/lib/mongo/error/sdam_error_detection.rb +3 -5
  205. data/lib/mongo/error/server_api_conflict.rb +0 -2
  206. data/lib/mongo/error/server_certificate_revoked.rb +0 -2
  207. data/lib/mongo/error/server_not_usable.rb +0 -2
  208. data/lib/mongo/error/session_ended.rb +1 -3
  209. data/lib/mongo/error/session_not_materialized.rb +1 -3
  210. data/lib/mongo/error/sessions_not_supported.rb +1 -4
  211. data/lib/mongo/error/snapshot_session_invalid_server_version.rb +1 -4
  212. data/lib/mongo/error/snapshot_session_transaction_prohibited.rb +1 -4
  213. data/lib/mongo/error/socket_error.rb +0 -2
  214. data/lib/mongo/error/socket_timeout_error.rb +0 -2
  215. data/lib/mongo/error/transactions_not_supported.rb +3 -6
  216. data/lib/mongo/error/unchangeable_collection_option.rb +1 -4
  217. data/lib/mongo/error/unexpected_chunk_length.rb +0 -3
  218. data/lib/mongo/error/unexpected_response.rb +1 -4
  219. data/lib/mongo/error/unknown_payload_type.rb +0 -3
  220. data/lib/mongo/error/unmet_dependency.rb +0 -2
  221. data/lib/mongo/error/unsupported_array_filters.rb +3 -24
  222. data/lib/mongo/error/unsupported_collation.rb +3 -24
  223. data/lib/mongo/error/unsupported_features.rb +0 -2
  224. data/lib/mongo/error/unsupported_message_type.rb +0 -2
  225. data/lib/mongo/error/unsupported_option.rb +19 -21
  226. data/lib/mongo/error/write_retryable.rb +0 -2
  227. data/lib/mongo/error.rb +10 -24
  228. data/lib/mongo/event/base.rb +0 -2
  229. data/lib/mongo/event/listeners.rb +0 -3
  230. data/lib/mongo/event/publisher.rb +0 -3
  231. data/lib/mongo/event/subscriber.rb +0 -4
  232. data/lib/mongo/event.rb +4 -6
  233. data/lib/mongo/grid/file/chunk.rb +7 -10
  234. data/lib/mongo/grid/file/info.rb +20 -24
  235. data/lib/mongo/grid/file.rb +7 -8
  236. data/lib/mongo/grid/fs_bucket.rb +40 -48
  237. data/lib/mongo/grid/stream/read.rb +25 -35
  238. data/lib/mongo/grid/stream/write.rb +17 -22
  239. data/lib/mongo/grid/stream.rb +2 -4
  240. data/lib/mongo/grid.rb +0 -1
  241. data/lib/mongo/id.rb +0 -1
  242. data/lib/mongo/index/view.rb +49 -48
  243. data/lib/mongo/index.rb +7 -10
  244. data/lib/mongo/lint.rb +31 -37
  245. data/lib/mongo/loggable.rb +5 -8
  246. data/lib/mongo/logger.rb +1 -7
  247. data/lib/mongo/monitoring/cmap_log_subscriber.rb +0 -2
  248. data/lib/mongo/monitoring/command_log_subscriber.rb +25 -33
  249. data/lib/mongo/monitoring/event/cmap/base.rb +0 -2
  250. data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +1 -4
  251. data/lib/mongo/monitoring/event/cmap/connection_check_out_started.rb +0 -3
  252. data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +1 -4
  253. data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +2 -5
  254. data/lib/mongo/monitoring/event/cmap/connection_closed.rb +1 -4
  255. data/lib/mongo/monitoring/event/cmap/connection_created.rb +1 -4
  256. data/lib/mongo/monitoring/event/cmap/connection_ready.rb +1 -4
  257. data/lib/mongo/monitoring/event/cmap/pool_cleared.rb +0 -3
  258. data/lib/mongo/monitoring/event/cmap/pool_closed.rb +1 -4
  259. data/lib/mongo/monitoring/event/cmap/pool_created.rb +1 -4
  260. data/lib/mongo/monitoring/event/cmap/pool_ready.rb +1 -4
  261. data/lib/mongo/monitoring/event/cmap.rb +0 -1
  262. data/lib/mongo/monitoring/event/command_failed.rb +5 -9
  263. data/lib/mongo/monitoring/event/command_started.rb +8 -12
  264. data/lib/mongo/monitoring/event/command_succeeded.rb +7 -15
  265. data/lib/mongo/monitoring/event/secure.rb +15 -20
  266. data/lib/mongo/monitoring/event/server_closed.rb +1 -4
  267. data/lib/mongo/monitoring/event/server_description_changed.rb +4 -8
  268. data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +5 -10
  269. data/lib/mongo/monitoring/event/server_heartbeat_started.rb +1 -4
  270. data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +3 -8
  271. data/lib/mongo/monitoring/event/server_opening.rb +1 -4
  272. data/lib/mongo/monitoring/event/topology_changed.rb +2 -5
  273. data/lib/mongo/monitoring/event/topology_closed.rb +1 -4
  274. data/lib/mongo/monitoring/event/topology_opening.rb +1 -4
  275. data/lib/mongo/monitoring/event.rb +0 -1
  276. data/lib/mongo/monitoring/publishable.rb +20 -30
  277. data/lib/mongo/monitoring/sdam_log_subscriber.rb +0 -2
  278. data/lib/mongo/monitoring/server_closed_log_subscriber.rb +0 -3
  279. data/lib/mongo/monitoring/server_description_changed_log_subscriber.rb +0 -3
  280. data/lib/mongo/monitoring/server_opening_log_subscriber.rb +0 -3
  281. data/lib/mongo/monitoring/topology_changed_log_subscriber.rb +5 -8
  282. data/lib/mongo/monitoring/topology_closed_log_subscriber.rb +0 -3
  283. data/lib/mongo/monitoring/topology_opening_log_subscriber.rb +0 -3
  284. data/lib/mongo/monitoring/unified_sdam_log_subscriber.rb +1 -3
  285. data/lib/mongo/monitoring.rb +38 -39
  286. data/lib/mongo/operation/aggregate/op_msg.rb +0 -2
  287. data/lib/mongo/operation/aggregate/result.rb +3 -6
  288. data/lib/mongo/operation/aggregate.rb +0 -2
  289. data/lib/mongo/operation/collections_info/result.rb +0 -3
  290. data/lib/mongo/operation/collections_info.rb +0 -2
  291. data/lib/mongo/operation/command/op_msg.rb +1 -4
  292. data/lib/mongo/operation/command.rb +0 -2
  293. data/lib/mongo/operation/context.rb +13 -16
  294. data/lib/mongo/operation/count/op_msg.rb +2 -4
  295. data/lib/mongo/operation/count.rb +0 -2
  296. data/lib/mongo/operation/create/op_msg.rb +2 -5
  297. data/lib/mongo/operation/create.rb +0 -2
  298. data/lib/mongo/operation/create_index/op_msg.rb +3 -7
  299. data/lib/mongo/operation/create_index.rb +0 -2
  300. data/lib/mongo/operation/create_user/op_msg.rb +2 -4
  301. data/lib/mongo/operation/create_user.rb +0 -2
  302. data/lib/mongo/operation/delete/bulk_result.rb +2 -3
  303. data/lib/mongo/operation/delete/op_msg.rb +3 -10
  304. data/lib/mongo/operation/delete/result.rb +0 -3
  305. data/lib/mongo/operation/delete.rb +1 -5
  306. data/lib/mongo/operation/distinct/op_msg.rb +2 -5
  307. data/lib/mongo/operation/distinct.rb +0 -2
  308. data/lib/mongo/operation/drop/op_msg.rb +0 -2
  309. data/lib/mongo/operation/drop.rb +0 -2
  310. data/lib/mongo/operation/drop_database/op_msg.rb +0 -2
  311. data/lib/mongo/operation/drop_database.rb +0 -2
  312. data/lib/mongo/operation/drop_index/op_msg.rb +4 -6
  313. data/lib/mongo/operation/drop_index.rb +0 -2
  314. data/lib/mongo/operation/explain/op_msg.rb +0 -2
  315. data/lib/mongo/operation/explain/result.rb +0 -3
  316. data/lib/mongo/operation/explain.rb +0 -2
  317. data/lib/mongo/operation/find/builder/command.rb +4 -12
  318. data/lib/mongo/operation/find/builder/flags.rb +9 -15
  319. data/lib/mongo/operation/find/builder/modifiers.rb +1 -4
  320. data/lib/mongo/operation/find/builder.rb +0 -1
  321. data/lib/mongo/operation/find/op_msg.rb +4 -12
  322. data/lib/mongo/operation/find/result.rb +0 -3
  323. data/lib/mongo/operation/find.rb +0 -2
  324. data/lib/mongo/operation/get_more/command_builder.rb +1 -6
  325. data/lib/mongo/operation/get_more/op_msg.rb +10 -4
  326. data/lib/mongo/operation/get_more/result.rb +0 -3
  327. data/lib/mongo/operation/get_more.rb +0 -2
  328. data/lib/mongo/operation/indexes/op_msg.rb +0 -2
  329. data/lib/mongo/operation/indexes/result.rb +1 -5
  330. data/lib/mongo/operation/indexes.rb +0 -2
  331. data/lib/mongo/operation/insert/bulk_result.rb +2 -6
  332. data/lib/mongo/operation/insert/op_msg.rb +2 -4
  333. data/lib/mongo/operation/insert/result.rb +0 -3
  334. data/lib/mongo/operation/insert.rb +2 -5
  335. data/lib/mongo/operation/kill_cursors/command_builder.rb +0 -3
  336. data/lib/mongo/operation/kill_cursors/op_msg.rb +1 -3
  337. data/lib/mongo/operation/kill_cursors.rb +0 -2
  338. data/lib/mongo/operation/list_collections/op_msg.rb +4 -6
  339. data/lib/mongo/operation/list_collections/result.rb +1 -4
  340. data/lib/mongo/operation/list_collections.rb +0 -2
  341. data/lib/mongo/operation/map_reduce/op_msg.rb +0 -2
  342. data/lib/mongo/operation/map_reduce/result.rb +3 -6
  343. data/lib/mongo/operation/map_reduce.rb +0 -2
  344. data/lib/mongo/operation/op_msg_base.rb +0 -1
  345. data/lib/mongo/operation/parallel_scan/op_msg.rb +4 -5
  346. data/lib/mongo/operation/parallel_scan/result.rb +2 -5
  347. data/lib/mongo/operation/parallel_scan.rb +0 -2
  348. data/lib/mongo/operation/remove_user/op_msg.rb +2 -4
  349. data/lib/mongo/operation/remove_user.rb +0 -2
  350. data/lib/mongo/operation/result.rb +38 -48
  351. data/lib/mongo/operation/shared/bypass_document_validation.rb +3 -7
  352. data/lib/mongo/operation/shared/causal_consistency_supported.rb +0 -3
  353. data/lib/mongo/operation/shared/executable.rb +19 -28
  354. data/lib/mongo/operation/shared/executable_no_validate.rb +0 -3
  355. data/lib/mongo/operation/shared/executable_transaction_label.rb +0 -2
  356. data/lib/mongo/operation/shared/idable.rb +3 -6
  357. data/lib/mongo/operation/shared/limited.rb +0 -3
  358. data/lib/mongo/operation/shared/object_id_generator.rb +0 -3
  359. data/lib/mongo/operation/shared/op_msg_executable.rb +0 -2
  360. data/lib/mongo/operation/shared/polymorphic_lookup.rb +0 -2
  361. data/lib/mongo/operation/shared/polymorphic_result.rb +2 -4
  362. data/lib/mongo/operation/shared/read_preference_supported.rb +10 -15
  363. data/lib/mongo/operation/shared/response_handling.rb +13 -26
  364. data/lib/mongo/operation/shared/result/aggregatable.rb +12 -13
  365. data/lib/mongo/operation/shared/sessions_supported.rb +87 -99
  366. data/lib/mongo/operation/shared/specifiable.rb +32 -58
  367. data/lib/mongo/operation/shared/write.rb +12 -17
  368. data/lib/mongo/operation/shared/write_concern_supported.rb +4 -7
  369. data/lib/mongo/operation/update/bulk_result.rb +13 -17
  370. data/lib/mongo/operation/update/op_msg.rb +2 -5
  371. data/lib/mongo/operation/update/result.rb +5 -5
  372. data/lib/mongo/operation/update.rb +1 -5
  373. data/lib/mongo/operation/update_user/op_msg.rb +2 -4
  374. data/lib/mongo/operation/update_user.rb +0 -2
  375. data/lib/mongo/operation/users_info/op_msg.rb +2 -4
  376. data/lib/mongo/operation/users_info/result.rb +1 -4
  377. data/lib/mongo/operation/users_info.rb +0 -2
  378. data/lib/mongo/operation/write_command/op_msg.rb +2 -10
  379. data/lib/mongo/operation/write_command.rb +0 -2
  380. data/lib/mongo/operation.rb +9 -14
  381. data/lib/mongo/options/mapper.rb +8 -15
  382. data/lib/mongo/options/redacted.rb +7 -9
  383. data/lib/mongo/options.rb +0 -1
  384. data/lib/mongo/protocol/bit_vector.rb +3 -5
  385. data/lib/mongo/protocol/caching_hash.rb +2 -7
  386. data/lib/mongo/protocol/compressed.rb +5 -10
  387. data/lib/mongo/protocol/get_more.rb +2 -8
  388. data/lib/mongo/protocol/kill_cursors.rb +2 -8
  389. data/lib/mongo/protocol/message.rb +103 -105
  390. data/lib/mongo/protocol/msg.rb +48 -63
  391. data/lib/mongo/protocol/query.rb +32 -41
  392. data/lib/mongo/protocol/registry.rb +2 -5
  393. data/lib/mongo/protocol/reply.rb +10 -16
  394. data/lib/mongo/protocol/serializers.rb +41 -59
  395. data/lib/mongo/protocol.rb +0 -1
  396. data/lib/mongo/query_cache.rb +7 -15
  397. data/lib/mongo/retryable/backpressure.rb +31 -0
  398. data/lib/mongo/retryable/base_worker.rb +39 -13
  399. data/lib/mongo/retryable/read_worker.rb +77 -21
  400. data/lib/mongo/retryable/retry_policy.rb +59 -0
  401. data/lib/mongo/retryable/write_worker.rb +155 -56
  402. data/lib/mongo/retryable.rb +70 -9
  403. data/lib/mongo/search_index/view.rb +1 -1
  404. data/lib/mongo/semaphore.rb +0 -1
  405. data/lib/mongo/server/app_metadata/environment.rb +3 -3
  406. data/lib/mongo/server/app_metadata.rb +4 -5
  407. data/lib/mongo/server/connection.rb +61 -61
  408. data/lib/mongo/server/connection_base.rb +43 -53
  409. data/lib/mongo/server/connection_common.rb +41 -64
  410. data/lib/mongo/server/connection_pool/generation_manager.rb +6 -11
  411. data/lib/mongo/server/connection_pool/populator.rb +1 -4
  412. data/lib/mongo/server/connection_pool.rb +195 -167
  413. data/lib/mongo/server/description/features.rb +23 -60
  414. data/lib/mongo/server/description/load_balancer.rb +0 -2
  415. data/lib/mongo/server/description.rb +117 -138
  416. data/lib/mongo/server/monitor/app_metadata.rb +3 -4
  417. data/lib/mongo/server/monitor/connection.rb +28 -35
  418. data/lib/mongo/server/monitor.rb +65 -60
  419. data/lib/mongo/server/pending_connection.rb +70 -71
  420. data/lib/mongo/server/push_monitor/connection.rb +0 -3
  421. data/lib/mongo/server/push_monitor.rb +21 -29
  422. data/lib/mongo/server/round_trip_time_calculator.rb +11 -17
  423. data/lib/mongo/server.rb +60 -93
  424. data/lib/mongo/server_selector/base.rb +133 -157
  425. data/lib/mongo/server_selector/nearest.rb +2 -5
  426. data/lib/mongo/server_selector/primary.rb +1 -5
  427. data/lib/mongo/server_selector/primary_preferred.rb +2 -6
  428. data/lib/mongo/server_selector/secondary.rb +2 -6
  429. data/lib/mongo/server_selector/secondary_preferred.rb +1 -5
  430. data/lib/mongo/server_selector.rb +3 -4
  431. data/lib/mongo/session/server_session.rb +6 -7
  432. data/lib/mongo/session/session_pool.rb +20 -34
  433. data/lib/mongo/session.rb +287 -188
  434. data/lib/mongo/socket/ocsp_cache.rb +8 -13
  435. data/lib/mongo/socket/ocsp_verifier.rb +69 -70
  436. data/lib/mongo/socket/ssl.rb +44 -43
  437. data/lib/mongo/socket/tcp.rb +5 -8
  438. data/lib/mongo/socket/unix.rb +0 -4
  439. data/lib/mongo/socket.rb +80 -102
  440. data/lib/mongo/srv/monitor.rb +6 -11
  441. data/lib/mongo/srv/resolver.rb +15 -24
  442. data/lib/mongo/srv/result.rb +18 -24
  443. data/lib/mongo/srv.rb +0 -1
  444. data/lib/mongo/timeout.rb +4 -11
  445. data/lib/mongo/topology_version.rb +8 -13
  446. data/lib/mongo/tracing/open_telemetry/command_tracer.rb +1 -1
  447. data/lib/mongo/tracing/open_telemetry/operation_tracer.rb +1 -1
  448. data/lib/mongo/tracing/open_telemetry/tracer.rb +1 -1
  449. data/lib/mongo/uri/options_mapper.rb +135 -126
  450. data/lib/mongo/uri/srv_protocol.rb +25 -38
  451. data/lib/mongo/uri.rb +95 -139
  452. data/lib/mongo/utils.rb +5 -12
  453. data/lib/mongo/version.rb +1 -1
  454. data/lib/mongo/write_concern/acknowledged.rb +0 -2
  455. data/lib/mongo/write_concern/base.rb +6 -6
  456. data/lib/mongo/write_concern/unacknowledged.rb +0 -2
  457. data/lib/mongo/write_concern.rb +14 -15
  458. data/lib/mongo.rb +1 -3
  459. data/mongo.gemspec +17 -17
  460. metadata +5 -5
  461. data/lib/mongo/error/server_api_not_supported.rb +0 -27
  462. data/lib/mongo/operation/shared/result/use_legacy_error_parser.rb +0 -32
  463. data/lib/mongo/operation/shared/validatable.rb +0 -87
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- # rubocop:todo all
3
2
 
4
3
  # Copyright (C) 2015-2023 MongoDB Inc.
5
4
  #
@@ -19,7 +18,6 @@ require 'mongo/retryable/base_worker'
19
18
 
20
19
  module Mongo
21
20
  module Retryable
22
-
23
21
  # Implements the logic around retrying write operations.
24
22
  #
25
23
  # @api private
@@ -62,7 +60,7 @@ module Mongo
62
60
  # @return [ Result ] The result of the operation.
63
61
  #
64
62
  # @since 2.1.0
65
- def write_with_retry(write_concern, ending_transaction: false, context:, &block)
63
+ def write_with_retry(write_concern, context:, ending_transaction: false, &block)
66
64
  session = context.session
67
65
 
68
66
  ensure_valid_state!(ending_transaction, session)
@@ -104,19 +102,46 @@ module Mongo
104
102
  # write should be sent.
105
103
  # @yieldparam [ nil ] txn_num nil as transaction number.
106
104
  # @yieldparam [ Operation::Context ] context The operation context.
107
- def nro_write_with_retry(write_concern, context:, &block)
105
+ def nro_write_with_retry(_write_concern, context:, &block)
108
106
  session = context.session
109
107
  server = select_server(cluster, ServerSelector.primary, session)
110
108
  options = session&.client&.options || {}
111
109
 
112
110
  if options[:retry_writes]
111
+ error_count = 0
112
+ error_to_raise = nil
113
113
  begin
114
114
  server.with_connection(connection_global_id: context.connection_global_id) do |connection|
115
115
  yield connection, nil, context
116
116
  end
117
+ rescue Error::TimeoutError
118
+ raise
117
119
  rescue *retryable_exceptions, Error::PoolError, Error::OperationFailure::Family => e
118
- e.add_note('retries disabled')
119
- raise e
120
+ if retryable_overload_error?(e)
121
+ error_count += 1
122
+ error_to_raise ||= e
123
+ unless e.respond_to?(:label?) && e.label?('NoWritesPerformed')
124
+ error_to_raise = e
125
+ end
126
+ delay = retry_policy.backoff_delay(error_count)
127
+ raise error_to_raise unless retry_policy.should_retry_overload?(error_count, delay, context: context)
128
+
129
+ log_retry(e, message: 'Write retry (overload backoff)')
130
+ sleep(delay)
131
+ begin
132
+ server = select_server(
133
+ cluster, ServerSelector.primary, session, server,
134
+ error: e, timeout: context.remaining_timeout_sec
135
+ )
136
+ rescue Error, Error::AuthError => select_err
137
+ error_to_raise.add_note("later retry failed: #{select_err.class}: #{select_err}")
138
+ raise error_to_raise
139
+ end
140
+ retry
141
+ else
142
+ e.add_note('retries disabled')
143
+ raise e
144
+ end
120
145
  end
121
146
  else
122
147
  legacy_write_with_retry(server, context: context, &block)
@@ -134,11 +159,7 @@ module Mongo
134
159
  def retry_write_allowed?(session, write_concern)
135
160
  return false unless session&.retry_writes?
136
161
 
137
- if write_concern.nil?
138
- true
139
- else
140
- WriteConcern.get(write_concern).acknowledged?
141
- end
162
+ write_concern.nil? || WriteConcern.get(write_concern).acknowledged?
142
163
  end
143
164
 
144
165
  private
@@ -150,9 +171,9 @@ module Mongo
150
171
  # @param [ nil | Mongo::Session ] session The session that the operation
151
172
  # is being run on (if any).
152
173
  def ensure_valid_state!(ending_transaction, session)
153
- if ending_transaction && !session
154
- raise ArgumentError, 'Cannot end a transaction without a session'
155
- end
174
+ return unless ending_transaction && !session
175
+
176
+ raise ArgumentError, 'Cannot end a transaction without a session'
156
177
  end
157
178
 
158
179
  # Implements legacy write retrying functionality by yielding to the passed
@@ -199,16 +220,13 @@ module Mongo
199
220
  e.add_note('legacy retry')
200
221
  e.add_note("attempt #{attempt}")
201
222
  server = nil
202
- if attempt > client.max_write_retries
203
- raise e
204
- end
205
- if e.label?('RetryableWriteError')
206
- log_retry(e, message: 'Legacy write retry')
207
- cluster.scan!(false)
208
- retry
209
- else
210
- raise e
211
- end
223
+ raise e if attempt > client.max_write_retries
224
+
225
+ raise e unless e.label?('RetryableWriteError')
226
+
227
+ log_retry(e, message: 'Legacy write retry')
228
+ cluster.scan!(false)
229
+ retry
212
230
  end
213
231
  end
214
232
 
@@ -232,6 +250,7 @@ module Mongo
232
250
  def modern_write_with_retry(session, server, context, &block)
233
251
  txn_num = nil
234
252
  connection_succeeded = false
253
+ was_starting = false
235
254
 
236
255
  server.with_connection(
237
256
  connection_global_id: context.connection_global_id,
@@ -241,6 +260,7 @@ module Mongo
241
260
 
242
261
  session.materialize_if_needed
243
262
  txn_num = session.in_transaction? ? session.txn_num : session.next_txn_num
263
+ was_starting = session.starting_transaction?
244
264
 
245
265
  # The context needs to be duplicated here because we will be using
246
266
  # it later for the retry as well.
@@ -249,15 +269,28 @@ module Mongo
249
269
  rescue *retryable_exceptions, Error::PoolError, Auth::Unauthorized, Error::OperationFailure::Family => e
250
270
  e.add_notes('modern retry', 'attempt 1')
251
271
 
252
- if e.is_a?(Error::OperationFailure::Family)
253
- ensure_retryable!(e)
254
- else
255
- ensure_labeled_retryable!(e, connection_succeeded, session)
272
+ is_overload = retryable_overload_error?(e)
273
+ unless is_overload
274
+ if e.is_a?(Error::OperationFailure::Family)
275
+ ensure_retryable!(e)
276
+ else
277
+ ensure_labeled_retryable!(e, connection_succeeded, session)
278
+ end
256
279
  end
257
280
 
258
- # Context#with creates a new context, which is not necessary here
259
- # but the API is less prone to misuse this way.
260
- retry_write(e, txn_num, context: context.with(is_retry: true), failed_server: server, &block)
281
+ retry_context = context.with(is_retry: true)
282
+
283
+ if is_overload
284
+ overload_write_retry(e, session, txn_num,
285
+ context: retry_context.with(overload_only_retry: true),
286
+ failed_server: server, error_count: 1,
287
+ was_starting_transaction: was_starting,
288
+ &block)
289
+ else
290
+ # Context#with creates a new context, which is not necessary here
291
+ # but the API is less prone to misuse this way.
292
+ retry_write(e, txn_num, context: retry_context, failed_server: server, &block)
293
+ end
261
294
  end
262
295
 
263
296
  # Called after a failed write, this will retry the write no more than
@@ -272,6 +305,7 @@ module Mongo
272
305
  #
273
306
  # @return [ Result ] The result of the operation.
274
307
  def retry_write(original_error, txn_num, context:, failed_server: nil, &block)
308
+ failed_error ||= original_error
275
309
  context&.check_timeout!
276
310
 
277
311
  session = context.session
@@ -286,6 +320,7 @@ module Mongo
286
320
  ServerSelector.primary,
287
321
  session,
288
322
  failed_server,
323
+ error: failed_error,
289
324
  timeout: context.remaining_timeout_sec
290
325
  )
291
326
 
@@ -296,7 +331,7 @@ module Mongo
296
331
 
297
332
  # When we want to raise the original error, we must not run the
298
333
  # rescue blocks below that add diagnostics because the diagnostics
299
- # added would either be rendundant (e.g. modern retry note) or wrong
334
+ # added would either be redundant (e.g. modern retry note) or wrong
300
335
  # (e.g. "attempt 2", we are raising the exception produced in the
301
336
  # first attempt and haven't attempted the second time). Use the
302
337
  # special marker class to bypass the ordinarily applicable rescues.
@@ -309,12 +344,24 @@ module Mongo
309
344
  yield(connection, txn_num, context)
310
345
  end
311
346
  rescue *retryable_exceptions, Error::PoolError => e
347
+ if retryable_overload_error?(e)
348
+ e.add_notes('modern retry', "attempt #{attempt}")
349
+ return overload_write_retry(e, context.session, txn_num,
350
+ context: context, failed_server: server, error_count: attempt, was_starting_transaction: false, &block)
351
+ end
312
352
  maybe_fail_on_retryable(e, original_error, context, attempt)
313
353
  failed_server = server
354
+ failed_error = e
314
355
  retry
315
356
  rescue Error::OperationFailure::Family => e
357
+ if retryable_overload_error?(e)
358
+ e.add_notes('modern retry', "attempt #{attempt}")
359
+ return overload_write_retry(e, context.session, txn_num,
360
+ context: context, failed_server: server, error_count: attempt, was_starting_transaction: false, &block)
361
+ end
316
362
  maybe_fail_on_operation_failure(e, original_error, context, attempt)
317
363
  failed_server = server
364
+ failed_error = e
318
365
  retry
319
366
  rescue Mongo::Error::TimeoutError
320
367
  raise
@@ -324,41 +371,93 @@ module Mongo
324
371
  raise original_error
325
372
  end
326
373
 
327
- # Retry writes on MMAPv1 should raise an actionable error; append actionable
328
- # information to the error message and preserve the backtrace.
329
- def raise_unsupported_error(e)
330
- new_error = Error::OperationFailure.new("#{e.class}: #{e} "\
331
- "This MongoDB deployment does not support retryable writes. Please add "\
332
- "retryWrites=false to your connection string or use the retry_writes: false Ruby client option")
333
- new_error.set_backtrace(e.backtrace)
334
- raise new_error
374
+ # Retry loop for overload write errors with exponential backoff.
375
+ #
376
+ # Per the client-backpressure spec, backoff is applied if and only
377
+ # if the error triggering the retry is an overload error. Non-overload
378
+ # retryable errors that occur within this loop are retried immediately
379
+ # (without backoff) but still count toward MAX_RETRIES.
380
+ def overload_write_retry(last_error, session, txn_num, context:, failed_server:, error_count:,
381
+ was_starting_transaction: false)
382
+ # Track the error to return per the NoWritesPerformed spec rules:
383
+ # - first error is always saved
384
+ # - only update when a new error does NOT have NoWritesPerformed
385
+ error_to_raise = last_error
386
+ last_was_overload = true
387
+
388
+ loop do
389
+ delay = last_was_overload ? retry_policy.backoff_delay(error_count) : 0
390
+ raise error_to_raise unless retry_policy.should_retry_overload?(error_count, delay, context: context)
391
+
392
+ log_retry(last_error, message: 'Write retry (overload backoff)')
393
+ sleep(delay) if last_was_overload
394
+
395
+ begin
396
+ server = select_server(
397
+ cluster, ServerSelector.primary, session, failed_server,
398
+ error: last_error,
399
+ timeout: context.remaining_timeout_sec
400
+ )
401
+ rescue Error, Error::AuthError => e
402
+ error_to_raise.add_note("later retry failed: #{e.class}: #{e}")
403
+ raise error_to_raise
404
+ end
405
+
406
+ unless server.retry_writes?
407
+ error_to_raise.add_note('did not retry because server does not support retryable writes')
408
+ raise error_to_raise
409
+ end
410
+
411
+ begin
412
+ session.revert_to_starting_transaction! if was_starting_transaction
413
+ context.check_timeout!
414
+ result = server.with_connection(connection_global_id: context.connection_global_id) do |connection|
415
+ yield connection, txn_num, context
416
+ end
417
+ return result
418
+ rescue Error::TimeoutError
419
+ raise
420
+ rescue *retryable_exceptions, Error::PoolError, Error::OperationFailure::Family => e
421
+ error_count += 1
422
+ e.add_notes('modern retry', "attempt #{error_count}")
423
+ is_overload = retryable_overload_error?(e)
424
+ if e.is_a?(Error::OperationFailure::Family)
425
+ raise e unless is_overload || (e.label?('RetryableWriteError') && !e.label?('NoWritesPerformed'))
426
+ else
427
+ raise e unless is_overload || e.write_retryable?
428
+ end
429
+ unless e.respond_to?(:label?) && e.label?('NoWritesPerformed')
430
+ error_to_raise = e
431
+ end
432
+ last_was_overload = is_overload
433
+ context = context.with(overload_only_retry: false) unless is_overload
434
+ failed_server = server
435
+ last_error = e
436
+ rescue Error, Error::AuthError => e
437
+ error_to_raise.add_note("later retry failed: #{e.class}: #{e}")
438
+ raise error_to_raise
439
+ end
440
+ end
335
441
  end
336
442
 
337
443
  # Make sure the exception object is labeled 'RetryableWriteError'. If it
338
444
  # isn't, and should not be, re-raise the exception.
339
445
  def ensure_labeled_retryable!(e, connection_succeeded, session)
340
- if !e.label?('RetryableWriteError')
341
- # If there was an error before the connection was successfully
342
- # checked out and connected, there was no connection present to use
343
- # for adding labels. Therefore, we should check if it is retryable,
344
- # and if it is, add the label and retry it.
345
- if !connection_succeeded && !session.in_transaction? && e.write_retryable?
346
- e.add_label('RetryableWriteError')
347
- else
348
- raise e
349
- end
350
- end
446
+ return if e.label?('RetryableWriteError')
447
+ # If there was an error before the connection was successfully
448
+ # checked out and connected, there was no connection present to use
449
+ # for adding labels. Therefore, we should check if it is retryable,
450
+ # and if it is, add the label and retry it.
451
+ raise e unless !connection_succeeded && !session.in_transaction? && e.write_retryable?
452
+
453
+ e.add_label('RetryableWriteError')
351
454
  end
352
455
 
353
456
  # Make sure the exception object supports retryable writes. If it does,
354
457
  # make sure it has been appropriately labeled. If either condition fails,
355
458
  # raise an exception.
356
459
  def ensure_retryable!(e)
357
- if e.unsupported_retryable_write?
358
- raise_unsupported_error(e)
359
- elsif !e.label?('RetryableWriteError')
360
- raise e
361
- end
460
+ raise e unless e.label?('RetryableWriteError')
362
461
  end
363
462
 
364
463
  # Raise either e, or original_error, depending on whether e is
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- # rubocop:todo all
3
2
 
4
3
  # Copyright (C) 2015-2020 MongoDB Inc.
5
4
  #
@@ -15,11 +14,12 @@
15
14
  # See the License for the specific language governing permissions and
16
15
  # limitations under the License.
17
16
 
17
+ require 'mongo/retryable/backpressure'
18
+ require 'mongo/retryable/retry_policy'
18
19
  require 'mongo/retryable/read_worker'
19
20
  require 'mongo/retryable/write_worker'
20
21
 
21
22
  module Mongo
22
-
23
23
  # Defines basic behavior around retrying operations.
24
24
  #
25
25
  # @since 2.1.0
@@ -28,14 +28,14 @@ module Mongo
28
28
 
29
29
  # Delegate the public read_with_retry methods to the read_worker
30
30
  def_delegators :read_worker,
31
- :read_with_retry_cursor,
32
- :read_with_retry,
33
- :read_with_one_retry
31
+ :read_with_retry_cursor,
32
+ :read_with_retry,
33
+ :read_with_one_retry
34
34
 
35
35
  # Delegate the public write_with_retry methods to the write_worker
36
36
  def_delegators :write_worker,
37
- :write_with_retry,
38
- :nro_write_with_retry
37
+ :write_with_retry,
38
+ :nro_write_with_retry
39
39
 
40
40
  # This is a separate method to make it possible for the test suite to
41
41
  # assert that server selection is performed during retry attempts.
@@ -46,16 +46,37 @@ module Mongo
46
46
  # @api private
47
47
  #
48
48
  # @return [ Mongo::Server ] A server matching the server preference.
49
- def select_server(cluster, server_selector, session, failed_server = nil, timeout: nil)
49
+ def select_server(cluster, server_selector, session, failed_server = nil, error: nil, timeout: nil)
50
+ deprioritized = if failed_server && deprioritize_server?(cluster, error)
51
+ [ failed_server ]
52
+ else
53
+ []
54
+ end
50
55
  server_selector.select_server(
51
56
  cluster,
52
57
  nil,
53
58
  session,
54
- deprioritized: [failed_server].compact,
59
+ deprioritized: deprioritized,
55
60
  timeout: timeout
56
61
  )
57
62
  end
58
63
 
64
+ private
65
+
66
+ # Whether the failed server should be deprioritized during server
67
+ # selection for a retry attempt. For sharded and load-balanced
68
+ # topologies, servers are always deprioritized on any retryable error.
69
+ # For replica sets, servers are deprioritized on overload errors only
70
+ # when enableOverloadRetargeting is enabled.
71
+ def deprioritize_server?(cluster, error)
72
+ return true if cluster.sharded? || cluster.load_balanced?
73
+ return false unless client.options[:enable_overload_retargeting]
74
+
75
+ error.respond_to?(:label?) && error.label?('SystemOverloadedError')
76
+ end
77
+
78
+ public
79
+
59
80
  # Returns the read worker for handling retryable reads.
60
81
  #
61
82
  # @api private
@@ -75,5 +96,45 @@ module Mongo
75
96
  def write_worker
76
97
  @write_worker ||= WriteWorker.new(self)
77
98
  end
99
+
100
+ # Wraps an operation with overload retry logic. On overload errors
101
+ # (SystemOverloadedError + RetryableError), retries the block with
102
+ # exponential backoff up to MAX_RETRIES times.
103
+ #
104
+ # The block should include server selection so it is re-done on retry.
105
+ # For cursor operations (getMore), the same server is reused since the
106
+ # cursor is pinned.
107
+ #
108
+ # @param [ Operation::Context | nil ] context The operation context
109
+ # for CSOT deadline checking.
110
+ # @param [ true | false ] retry_enabled Whether overload retries are
111
+ # permitted. When false, overload errors are raised immediately
112
+ # without retrying (used when retryReads/retryWrites is disabled).
113
+ #
114
+ # @return [ Object ] The result of the block.
115
+ #
116
+ # @api private
117
+ def with_overload_retry(context: nil, retry_enabled: true)
118
+ return yield unless retry_enabled
119
+
120
+ error_count = 0
121
+ loop do
122
+ result = yield
123
+
124
+ return result
125
+ rescue Error::TimeoutError
126
+ raise
127
+ rescue Error::OperationFailure::Family => e
128
+ raise e unless e.label?('SystemOverloadedError') && e.label?('RetryableError')
129
+
130
+ error_count += 1
131
+ policy = client.retry_policy
132
+ delay = policy.backoff_delay(error_count)
133
+ raise e unless policy.should_retry_overload?(error_count, delay, context: context)
134
+
135
+ Logger.logger.warn("Overload retry due to: #{e.class.name}: #{e.message}")
136
+ sleep(delay)
137
+ end
138
+ end
78
139
  end
79
140
  end
@@ -103,7 +103,7 @@ module Mongo
103
103
 
104
104
  # Iterate over the search indexes.
105
105
  #
106
- # @param [ Proc ] block if given, each search index will be yieleded to
106
+ # @param [ Proc ] block if given, each search index will be yielded to
107
107
  # the block.
108
108
  #
109
109
  # @return [ self | Enumerator ] if a block is given, self is returned.
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- # rubocop:todo all
3
2
 
4
3
  # Copyright (C) 2018-2020 MongoDB Inc.
5
4
  #
@@ -100,7 +100,7 @@ module Mongo
100
100
  # @return [ String | nil ] the error message explaining why a valid
101
101
  # FaaS environment was not detected, or nil if no error occurred.
102
102
  #
103
- # @note These error messagess are not to be propogated to the
103
+ # @note These error messages are not to be propagated to the
104
104
  # user; they are intended only for troubleshooting and debugging.)
105
105
  attr_reader :error
106
106
 
@@ -194,7 +194,7 @@ module Mongo
194
194
 
195
195
  private
196
196
 
197
- # Searches the DESCRIMINATORS list to see which (if any) apply to
197
+ # Searches the DISCRIMINATORS list to see which (if any) apply to
198
198
  # the current environment.
199
199
  #
200
200
  # @return [ String | nil ] the name of the detected FaaS provider.
@@ -248,7 +248,7 @@ module Mongo
248
248
  end
249
249
 
250
250
  # Determines whether the named environment variable exists, and (if
251
- # a pattern has been declared for that descriminator) whether the
251
+ # a pattern has been declared for that discriminator) whether the
252
252
  # pattern matches the value of the variable.
253
253
  #
254
254
  # @param [ String ] var the name of the environment variable
@@ -46,8 +46,7 @@ module Mongo
46
46
  #
47
47
  # @param [ Hash ] options Metadata options.
48
48
  # @option options [ String, Symbol ] :app_name Application name that is
49
- # printed to the mongod logs upon establishing a connection in server
50
- # versions >= 3.4.
49
+ # printed to the mongod logs upon establishing a connection
51
50
  # @option options [ Symbol ] :auth_mech The authentication mechanism to
52
51
  # use. One of :mongodb_cr, :mongodb_x509, :plain, :scram, :scram256
53
52
  # @option options [ String ] :auth_source The source to authenticate from.
@@ -57,7 +56,6 @@ module Mongo
57
56
  # driver only supports 'zstd', 'snappy' and 'zlib'.
58
57
  # @option options [ String ] :platform Platform information to include in
59
58
  # the metadata printed to the mongod logs upon establishing a connection
60
- # in server versions >= 3.4.
61
59
  # @option options [ Symbol ] :purpose The purpose of this connection.
62
60
  # @option options [ Hash ] :server_api The requested server API version.
63
61
  # This hash can have the following items:
@@ -97,7 +95,7 @@ module Mongo
97
95
 
98
96
  # @return [ Hash | nil ] The requested server API version.
99
97
  #
100
- # Thes hash can have the following items:
98
+ # This hash can have the following items:
101
99
  # - *:version* -- string
102
100
  # - *:strict* -- boolean
103
101
  # - *:deprecation_errors* -- boolean
@@ -132,6 +130,7 @@ module Mongo
132
130
  doc[:driver] = driver_doc
133
131
  doc[:os] = os_doc
134
132
  doc[:platform] = platform_string
133
+ doc[:backpressure] = true
135
134
  env_doc.tap { |env| doc[:env] = env if env }
136
135
  end
137
136
  end
@@ -139,7 +138,7 @@ module Mongo
139
138
  private
140
139
 
141
140
  # Check whether it is possible to build a valid app metadata document
142
- # with params provided on intialization.
141
+ # with params provided on initialization.
143
142
  #
144
143
  # @raise [ Error::InvalidApplicationName ] When the metadata are invalid.
145
144
  def validate!