mongo 2.19.1 → 2.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (356) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +40 -1
  3. data/Rakefile +83 -174
  4. data/lib/mongo/address.rb +22 -3
  5. data/lib/mongo/auth/aws/credentials_retriever.rb +70 -17
  6. data/lib/mongo/auth/base.rb +1 -1
  7. data/lib/mongo/bulk_write.rb +35 -2
  8. data/lib/mongo/client.rb +38 -6
  9. data/lib/mongo/client_encryption.rb +6 -3
  10. data/lib/mongo/cluster/reapers/cursor_reaper.rb +6 -1
  11. data/lib/mongo/cluster/sdam_flow.rb +20 -7
  12. data/lib/mongo/cluster/topology/base.rb +16 -0
  13. data/lib/mongo/cluster.rb +41 -5
  14. data/lib/mongo/collection/helpers.rb +1 -1
  15. data/lib/mongo/collection/view/aggregation/behavior.rb +131 -0
  16. data/lib/mongo/collection/view/aggregation.rb +33 -99
  17. data/lib/mongo/collection/view/builder/aggregation.rb +1 -7
  18. data/lib/mongo/collection/view/change_stream.rb +80 -27
  19. data/lib/mongo/collection/view/iterable.rb +92 -60
  20. data/lib/mongo/collection/view/map_reduce.rb +25 -8
  21. data/lib/mongo/collection/view/readable.rb +79 -30
  22. data/lib/mongo/collection/view/writable.rb +109 -48
  23. data/lib/mongo/collection/view.rb +44 -3
  24. data/lib/mongo/collection.rb +185 -26
  25. data/lib/mongo/config.rb +2 -2
  26. data/lib/mongo/crypt/auto_encrypter.rb +4 -6
  27. data/lib/mongo/crypt/binding.rb +4 -4
  28. data/lib/mongo/crypt/context.rb +20 -14
  29. data/lib/mongo/crypt/encryption_io.rb +56 -26
  30. data/lib/mongo/crypt/explicit_encrypter.rb +49 -20
  31. data/lib/mongo/crypt/explicit_encryption_context.rb +17 -11
  32. data/lib/mongo/crypt/kms/azure/credentials_retriever.rb +22 -6
  33. data/lib/mongo/crypt/kms/gcp/credentials_retriever.rb +29 -4
  34. data/lib/mongo/csot_timeout_holder.rb +119 -0
  35. data/lib/mongo/cursor/kill_spec.rb +5 -2
  36. data/lib/mongo/cursor/nontailable.rb +27 -0
  37. data/lib/mongo/cursor.rb +86 -24
  38. data/lib/mongo/cursor_host.rb +82 -0
  39. data/lib/mongo/database/view.rb +81 -14
  40. data/lib/mongo/database.rb +88 -18
  41. data/lib/mongo/error/operation_failure.rb +209 -204
  42. data/lib/mongo/error/server_timeout_error.rb +12 -0
  43. data/lib/mongo/error/socket_timeout_error.rb +3 -1
  44. data/lib/mongo/error/timeout_error.rb +23 -0
  45. data/lib/mongo/error/transactions_not_supported.rb +34 -0
  46. data/lib/mongo/error.rb +3 -0
  47. data/lib/mongo/grid/fs_bucket.rb +48 -9
  48. data/lib/mongo/grid/stream/read.rb +15 -1
  49. data/lib/mongo/grid/stream/write.rb +21 -4
  50. data/lib/mongo/index/view.rb +77 -16
  51. data/lib/mongo/monitoring/event/secure.rb +1 -1
  52. data/lib/mongo/operation/context.rb +40 -2
  53. data/lib/mongo/operation/create_search_indexes/op_msg.rb +31 -0
  54. data/lib/mongo/operation/create_search_indexes.rb +15 -0
  55. data/lib/mongo/operation/delete/op_msg.rb +2 -1
  56. data/lib/mongo/operation/drop_search_index/op_msg.rb +33 -0
  57. data/lib/mongo/operation/drop_search_index.rb +15 -0
  58. data/lib/mongo/operation/find/op_msg.rb +45 -0
  59. data/lib/mongo/operation/get_more/op_msg.rb +33 -0
  60. data/lib/mongo/operation/insert/op_msg.rb +3 -2
  61. data/lib/mongo/operation/insert/result.rb +4 -2
  62. data/lib/mongo/operation/list_collections/result.rb +1 -1
  63. data/lib/mongo/operation/map_reduce/result.rb +1 -1
  64. data/lib/mongo/operation/op_msg_base.rb +3 -1
  65. data/lib/mongo/operation/result.rb +26 -5
  66. data/lib/mongo/operation/shared/executable.rb +55 -28
  67. data/lib/mongo/operation/shared/op_msg_executable.rb +4 -1
  68. data/lib/mongo/operation/shared/response_handling.rb +25 -27
  69. data/lib/mongo/operation/shared/sessions_supported.rb +1 -1
  70. data/lib/mongo/operation/shared/specifiable.rb +7 -0
  71. data/lib/mongo/operation/shared/timed.rb +52 -0
  72. data/lib/mongo/operation/shared/write.rb +4 -1
  73. data/lib/mongo/operation/update/op_msg.rb +2 -1
  74. data/lib/mongo/operation/update_search_index/op_msg.rb +34 -0
  75. data/lib/mongo/operation/update_search_index.rb +15 -0
  76. data/lib/mongo/operation.rb +4 -0
  77. data/lib/mongo/protocol/message.rb +1 -4
  78. data/lib/mongo/protocol/msg.rb +2 -2
  79. data/lib/mongo/retryable/base_worker.rb +28 -3
  80. data/lib/mongo/retryable/read_worker.rb +78 -36
  81. data/lib/mongo/retryable/write_worker.rb +59 -25
  82. data/lib/mongo/retryable.rb +8 -2
  83. data/lib/mongo/search_index/view.rb +232 -0
  84. data/lib/mongo/server/app_metadata/environment.rb +64 -9
  85. data/lib/mongo/server/app_metadata.rb +5 -4
  86. data/lib/mongo/server/connection.rb +11 -5
  87. data/lib/mongo/server/connection_base.rb +22 -2
  88. data/lib/mongo/server/connection_pool.rb +32 -14
  89. data/lib/mongo/server/description/features.rb +2 -1
  90. data/lib/mongo/server/description.rb +18 -5
  91. data/lib/mongo/server/monitor.rb +7 -4
  92. data/lib/mongo/server/pending_connection.rb +25 -8
  93. data/lib/mongo/server/{round_trip_time_averager.rb → round_trip_time_calculator.rb} +25 -7
  94. data/lib/mongo/server.rb +11 -6
  95. data/lib/mongo/server_selector/base.rb +54 -12
  96. data/lib/mongo/session/server_session/dirtyable.rb +52 -0
  97. data/lib/mongo/session/server_session.rb +3 -0
  98. data/lib/mongo/session/session_pool.rb +12 -18
  99. data/lib/mongo/session.rb +110 -9
  100. data/lib/mongo/socket/ssl.rb +131 -18
  101. data/lib/mongo/socket/tcp.rb +40 -6
  102. data/lib/mongo/socket.rb +154 -25
  103. data/lib/mongo/uri/options_mapper.rb +1 -0
  104. data/lib/mongo/uri.rb +0 -4
  105. data/lib/mongo/version.rb +1 -5
  106. data/lib/mongo.rb +2 -0
  107. data/mongo.gemspec +9 -18
  108. data/spec/atlas/atlas_connectivity_spec.rb +9 -9
  109. data/spec/atlas/operations_spec.rb +5 -5
  110. data/spec/faas/ruby-sam-app/Gemfile +9 -0
  111. data/spec/faas/ruby-sam-app/mongodb/Gemfile +4 -0
  112. data/spec/faas/ruby-sam-app/mongodb/app.rb +149 -0
  113. data/spec/faas/ruby-sam-app/template.yaml +48 -0
  114. data/spec/integration/client_side_encryption/auto_encryption_mongocryptd_spawn_spec.rb +2 -1
  115. data/spec/integration/client_side_encryption/auto_encryption_spec.rb +494 -487
  116. data/spec/integration/client_side_encryption/corpus_spec.rb +10 -2
  117. data/spec/integration/client_side_encryption/on_demand_aws_credentials_spec.rb +1 -1
  118. data/spec/integration/client_side_encryption/range_explicit_encryption_prose_spec.rb +67 -20
  119. data/spec/integration/client_side_operations_timeout/encryption_prose_spec.rb +131 -0
  120. data/spec/integration/connection_pool_populator_spec.rb +2 -0
  121. data/spec/integration/cursor_pinning_spec.rb +15 -60
  122. data/spec/integration/cursor_reaping_spec.rb +1 -1
  123. data/spec/integration/docs_examples_spec.rb +1 -1
  124. data/spec/integration/find_options_spec.rb +227 -0
  125. data/spec/integration/operation_failure_code_spec.rb +1 -1
  126. data/spec/integration/operation_failure_message_spec.rb +3 -3
  127. data/spec/integration/retryable_errors_spec.rb +2 -2
  128. data/spec/integration/retryable_reads_errors_spec.rb +196 -31
  129. data/spec/integration/retryable_writes_errors_spec.rb +156 -0
  130. data/spec/integration/sdam_error_handling_spec.rb +4 -1
  131. data/spec/integration/search_indexes_prose_spec.rb +172 -0
  132. data/spec/integration/server_spec.rb +4 -3
  133. data/spec/integration/transactions_api_examples_spec.rb +2 -0
  134. data/spec/kerberos/kerberos_spec.rb +4 -0
  135. data/spec/lite_spec_helper.rb +34 -20
  136. data/spec/mongo/auth/user/view_spec.rb +1 -1
  137. data/spec/mongo/caching_cursor_spec.rb +1 -1
  138. data/spec/mongo/client_encryption_spec.rb +1 -0
  139. data/spec/mongo/client_spec.rb +158 -4
  140. data/spec/mongo/cluster_spec.rb +36 -0
  141. data/spec/mongo/collection/view/aggregation_spec.rb +20 -40
  142. data/spec/mongo/collection/view/change_stream_spec.rb +3 -3
  143. data/spec/mongo/collection/view/explainable_spec.rb +2 -0
  144. data/spec/mongo/collection_crud_spec.rb +2 -1
  145. data/spec/mongo/collection_spec.rb +5 -6
  146. data/spec/mongo/crypt/auto_encrypter_spec.rb +14 -12
  147. data/spec/mongo/crypt/data_key_context_spec.rb +3 -1
  148. data/spec/mongo/crypt/explicit_encryption_context_spec.rb +2 -2
  149. data/spec/mongo/crypt/handle_spec.rb +1 -1
  150. data/spec/mongo/cursor_spec.rb +26 -9
  151. data/spec/mongo/error/operation_failure_heavy_spec.rb +2 -2
  152. data/spec/mongo/operation/context_spec.rb +79 -0
  153. data/spec/mongo/operation/create/op_msg_spec.rb +106 -110
  154. data/spec/mongo/operation/delete/op_msg_spec.rb +6 -5
  155. data/spec/mongo/operation/find/op_msg_spec.rb +66 -0
  156. data/spec/mongo/operation/get_more/op_msg_spec.rb +65 -0
  157. data/spec/mongo/operation/insert/op_msg_spec.rb +128 -131
  158. data/spec/mongo/operation/insert_spec.rb +1 -1
  159. data/spec/mongo/operation/shared/csot/examples.rb +113 -0
  160. data/spec/mongo/query_cache_spec.rb +243 -225
  161. data/spec/mongo/retryable/write_worker_spec.rb +39 -0
  162. data/spec/mongo/retryable_spec.rb +1 -0
  163. data/spec/mongo/server/app_metadata/environment_spec.rb +135 -0
  164. data/spec/mongo/server/app_metadata_spec.rb +12 -2
  165. data/spec/mongo/server/connection_spec.rb +26 -0
  166. data/spec/mongo/server/round_trip_time_calculator_spec.rb +120 -0
  167. data/spec/mongo/session/session_pool_spec.rb +1 -16
  168. data/spec/mongo/session_transaction_spec.rb +15 -0
  169. data/spec/mongo/socket/ssl_spec.rb +0 -10
  170. data/spec/mongo/uri_spec.rb +0 -9
  171. data/spec/runners/change_streams/test.rb +2 -2
  172. data/spec/runners/crud/operation.rb +1 -1
  173. data/spec/runners/crud/test.rb +0 -8
  174. data/spec/runners/crud/verifier.rb +3 -1
  175. data/spec/runners/crud.rb +1 -1
  176. data/spec/runners/transactions/operation.rb +4 -6
  177. data/spec/runners/transactions/test.rb +12 -3
  178. data/spec/runners/unified/ambiguous_operations.rb +13 -0
  179. data/spec/runners/unified/assertions.rb +20 -3
  180. data/spec/runners/unified/change_stream_operations.rb +14 -24
  181. data/spec/runners/unified/crud_operations.rb +82 -47
  182. data/spec/runners/unified/ddl_operations.rb +38 -7
  183. data/spec/runners/unified/grid_fs_operations.rb +37 -2
  184. data/spec/runners/unified/search_index_operations.rb +63 -0
  185. data/spec/runners/unified/support_operations.rb +46 -9
  186. data/spec/runners/unified/test.rb +33 -12
  187. data/spec/runners/unified.rb +1 -1
  188. data/spec/solo/clean_exit_spec.rb +2 -0
  189. data/spec/spec_helper.rb +1 -1
  190. data/spec/spec_tests/client_side_operations_timeout_spec.rb +15 -0
  191. data/spec/spec_tests/data/change_streams_unified/change-streams-clusterTime.yml +3 -1
  192. data/spec/spec_tests/data/change_streams_unified/change-streams-disambiguatedPaths.yml +3 -1
  193. data/spec/spec_tests/data/change_streams_unified/change-streams-errors.yml +3 -1
  194. data/spec/spec_tests/data/change_streams_unified/change-streams-pre_and_post_images.yml +1 -1
  195. data/spec/spec_tests/data/change_streams_unified/change-streams-resume-allowlist.yml +1 -1
  196. data/spec/spec_tests/data/change_streams_unified/change-streams-resume-errorLabels.yml +1 -1
  197. data/spec/spec_tests/data/change_streams_unified/change-streams-showExpandedEvents.yml +1 -1
  198. data/spec/spec_tests/data/client_side_encryption/badQueries.yml +2 -1
  199. data/spec/spec_tests/data/client_side_encryption/explain.yml +2 -2
  200. data/spec/spec_tests/data/client_side_encryption/fle2v2-BypassQueryAnalysis.yml +1 -0
  201. data/spec/spec_tests/data/client_side_encryption/fle2v2-Compact.yml +1 -0
  202. data/spec/spec_tests/data/client_side_encryption/fle2v2-CreateCollection.yml +1 -0
  203. data/spec/spec_tests/data/client_side_encryption/fle2v2-DecryptExistingData.yml +1 -0
  204. data/spec/spec_tests/data/client_side_encryption/fle2v2-Delete.yml +1 -0
  205. data/spec/spec_tests/data/client_side_encryption/fle2v2-EncryptedFields-vs-EncryptedFieldsMap.yml +1 -0
  206. data/spec/spec_tests/data/client_side_encryption/fle2v2-EncryptedFields-vs-jsonSchema.yml +1 -0
  207. data/spec/spec_tests/data/client_side_encryption/fle2v2-EncryptedFieldsMap-defaults.yml +1 -0
  208. data/spec/spec_tests/data/client_side_encryption/fle2v2-FindOneAndUpdate.yml +1 -0
  209. data/spec/spec_tests/data/client_side_encryption/fle2v2-InsertFind-Indexed.yml +1 -0
  210. data/spec/spec_tests/data/client_side_encryption/fle2v2-InsertFind-Unindexed.yml +1 -0
  211. data/spec/spec_tests/data/client_side_encryption/fle2v2-MissingKey.yml +1 -0
  212. data/spec/spec_tests/data/client_side_encryption/fle2v2-NoEncryption.yml +1 -0
  213. data/spec/spec_tests/data/client_side_encryption/fle2v2-Update.yml +1 -0
  214. data/spec/spec_tests/data/client_side_encryption/fle2v2-validatorAndPartialFieldExpression.yml +2 -1
  215. data/spec/spec_tests/data/client_side_encryption/timeoutMS.yml +67 -0
  216. data/spec/spec_tests/data/client_side_operations_timeout/bulkWrite.yml +87 -0
  217. data/spec/spec_tests/data/client_side_operations_timeout/change-streams.yml +358 -0
  218. data/spec/spec_tests/data/client_side_operations_timeout/close-cursors.yml +129 -0
  219. data/spec/spec_tests/data/client_side_operations_timeout/command-execution.yml +250 -0
  220. data/spec/spec_tests/data/client_side_operations_timeout/convenient-transactions.yml +113 -0
  221. data/spec/spec_tests/data/client_side_operations_timeout/cursors.yml +70 -0
  222. data/spec/spec_tests/data/client_side_operations_timeout/deprecated-options.yml +3982 -0
  223. data/spec/spec_tests/data/client_side_operations_timeout/error-transformations.yml +96 -0
  224. data/spec/spec_tests/data/client_side_operations_timeout/global-timeoutMS.yml +3236 -0
  225. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-advanced.yml +207 -0
  226. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-delete.yml +152 -0
  227. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-download.yml +182 -0
  228. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-find.yml +100 -0
  229. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-upload.yml +249 -0
  230. data/spec/spec_tests/data/client_side_operations_timeout/legacy-timeouts.yml +204 -0
  231. data/spec/spec_tests/data/client_side_operations_timeout/non-tailable-cursors.yml +307 -0
  232. data/spec/spec_tests/data/client_side_operations_timeout/override-collection-timeoutMS.yml +1877 -0
  233. data/spec/spec_tests/data/client_side_operations_timeout/override-operation-timeoutMS.yml +1918 -0
  234. data/spec/spec_tests/data/client_side_operations_timeout/retryability-legacy-timeouts.yml +1676 -0
  235. data/spec/spec_tests/data/client_side_operations_timeout/retryability-timeoutMS.yml +2824 -0
  236. data/spec/spec_tests/data/client_side_operations_timeout/sessions-inherit-timeoutMS.yml +168 -0
  237. data/spec/spec_tests/data/client_side_operations_timeout/sessions-override-operation-timeoutMS.yml +171 -0
  238. data/spec/spec_tests/data/client_side_operations_timeout/sessions-override-timeoutMS.yml +168 -0
  239. data/spec/spec_tests/data/client_side_operations_timeout/tailable-awaitData.yml +247 -0
  240. data/spec/spec_tests/data/client_side_operations_timeout/tailable-non-awaitData.yml +181 -0
  241. data/spec/spec_tests/data/connection_string/invalid-uris.yml +0 -10
  242. data/spec/spec_tests/data/connection_string/valid-options.yml +13 -0
  243. data/spec/spec_tests/data/crud_unified/aggregate-write-readPreference.yml +6 -0
  244. data/spec/spec_tests/data/crud_unified/db-aggregate-write-readPreference.yml +6 -0
  245. data/spec/spec_tests/data/crud_unified/find-test-all-options.yml +377 -0
  246. data/spec/spec_tests/data/index_management/createSearchIndex.yml +64 -0
  247. data/spec/spec_tests/data/index_management/createSearchIndexes.yml +86 -0
  248. data/spec/spec_tests/data/index_management/dropSearchIndex.yml +43 -0
  249. data/spec/spec_tests/data/index_management/listSearchIndexes.yml +91 -0
  250. data/spec/spec_tests/data/index_management/updateSearchIndex.yml +46 -0
  251. data/spec/spec_tests/data/retryable_writes/unified/bulkWrite-serverErrors.yml +3 -6
  252. data/spec/spec_tests/data/retryable_writes/unified/insertOne-serverErrors.yml +3 -6
  253. data/spec/spec_tests/data/run_command_unified/runCommand.yml +319 -0
  254. data/spec/spec_tests/data/sessions_unified/driver-sessions-dirty-session-errors.yml +351 -0
  255. data/spec/spec_tests/data/unified/valid-pass/poc-crud.yml +1 -1
  256. data/spec/spec_tests/data/unified/valid-pass/poc-retryable-writes.yml +7 -7
  257. data/spec/spec_tests/data/unified/valid-pass/poc-sessions.yml +3 -4
  258. data/spec/spec_tests/data/unified/valid-pass/poc-transactions-convenient-api.yml +1 -1
  259. data/spec/spec_tests/data/unified/valid-pass/poc-transactions-mongos-pin-auto.yml +1 -1
  260. data/spec/spec_tests/data/unified/valid-pass/poc-transactions.yml +3 -3
  261. data/spec/spec_tests/index_management_unified_spec.rb +13 -0
  262. data/spec/spec_tests/run_command_unified_spec.rb +13 -0
  263. data/spec/spec_tests/sdam_unified_spec.rb +2 -0
  264. data/spec/spec_tests/server_selection_rtt_spec.rb +6 -6
  265. data/spec/spec_tests/transactions_unified_spec.rb +2 -1
  266. data/spec/support/certificates/atlas-ocsp-ca.crt +89 -79
  267. data/spec/support/certificates/atlas-ocsp.crt +117 -122
  268. data/spec/support/certificates/retrieve-atlas-cert +1 -1
  269. data/spec/support/cluster_tools.rb +3 -3
  270. data/spec/support/common_shortcuts.rb +2 -2
  271. data/spec/support/constraints.rb +6 -0
  272. data/spec/support/crypt/encrypted_fields/range-encryptedFields-Date.json +1 -1
  273. data/spec/support/crypt/encrypted_fields/range-encryptedFields-DecimalNoPrecision.json +1 -1
  274. data/spec/support/crypt/encrypted_fields/range-encryptedFields-DecimalPrecision.json +1 -1
  275. data/spec/support/crypt/encrypted_fields/range-encryptedFields-DoubleNoPrecision.json +1 -1
  276. data/spec/support/crypt/encrypted_fields/range-encryptedFields-DoublePrecision.json +1 -1
  277. data/spec/support/crypt/encrypted_fields/range-encryptedFields-Int.json +1 -1
  278. data/spec/support/crypt/encrypted_fields/range-encryptedFields-Long.json +1 -1
  279. data/spec/support/ocsp +1 -1
  280. data/spec/support/recording_logger.rb +27 -0
  281. data/spec/support/shared/session.rb +2 -2
  282. data/spec/support/spec_config.rb +5 -0
  283. data/spec/support/spec_setup.rb +2 -2
  284. data/spec/support/utils.rb +3 -1
  285. metadata +1329 -1368
  286. checksums.yaml.gz.sig +0 -0
  287. data/spec/mongo/server/round_trip_time_averager_spec.rb +0 -48
  288. data/spec/shared/LICENSE +0 -20
  289. data/spec/shared/bin/get-mongodb-download-url +0 -17
  290. data/spec/shared/bin/s3-copy +0 -45
  291. data/spec/shared/bin/s3-upload +0 -69
  292. data/spec/shared/lib/mrss/child_process_helper.rb +0 -80
  293. data/spec/shared/lib/mrss/cluster_config.rb +0 -231
  294. data/spec/shared/lib/mrss/constraints.rb +0 -378
  295. data/spec/shared/lib/mrss/docker_runner.rb +0 -295
  296. data/spec/shared/lib/mrss/eg_config_utils.rb +0 -51
  297. data/spec/shared/lib/mrss/event_subscriber.rb +0 -210
  298. data/spec/shared/lib/mrss/lite_constraints.rb +0 -238
  299. data/spec/shared/lib/mrss/server_version_registry.rb +0 -113
  300. data/spec/shared/lib/mrss/session_registry.rb +0 -69
  301. data/spec/shared/lib/mrss/session_registry_legacy.rb +0 -60
  302. data/spec/shared/lib/mrss/spec_organizer.rb +0 -179
  303. data/spec/shared/lib/mrss/utils.rb +0 -37
  304. data/spec/shared/share/Dockerfile.erb +0 -330
  305. data/spec/shared/share/haproxy-1.conf +0 -16
  306. data/spec/shared/share/haproxy-2.conf +0 -17
  307. data/spec/shared/shlib/config.sh +0 -27
  308. data/spec/shared/shlib/distro.sh +0 -74
  309. data/spec/shared/shlib/server.sh +0 -416
  310. data/spec/shared/shlib/set_env.sh +0 -169
  311. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Aggregate.yml +0 -241
  312. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Correctness.yml +0 -422
  313. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Delete.yml +0 -182
  314. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-FindOneAndUpdate.yml +0 -239
  315. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-InsertFind.yml +0 -235
  316. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Update.yml +0 -252
  317. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Aggregate.yml +0 -1687
  318. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Correctness.yml +0 -293
  319. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Delete.yml +0 -905
  320. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-FindOneAndUpdate.yml +0 -1684
  321. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-InsertFind.yml +0 -1680
  322. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Update.yml +0 -1697
  323. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Aggregate.yml +0 -329
  324. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Correctness.yml +0 -424
  325. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Delete.yml +0 -226
  326. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.yml +0 -327
  327. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-InsertFind.yml +0 -319
  328. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Update.yml +0 -336
  329. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Aggregate.yml +0 -913
  330. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Correctness.yml +0 -292
  331. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Delete.yml +0 -518
  332. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-FindOneAndUpdate.yml +0 -911
  333. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-InsertFind.yml +0 -907
  334. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Update.yml +0 -924
  335. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Aggregate.yml +0 -325
  336. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Correctness.yml +0 -424
  337. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Delete.yml +0 -224
  338. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-FindOneAndUpdate.yml +0 -323
  339. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-InsertFind.yml +0 -319
  340. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Update.yml +0 -338
  341. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Aggregate.yml +0 -241
  342. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Correctness.yml +0 -423
  343. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Delete.yml +0 -182
  344. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-FindOneAndUpdate.yml +0 -239
  345. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-InsertFind.yml +0 -235
  346. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Update.yml +0 -254
  347. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Aggregate.yml +0 -241
  348. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Correctness.yml +0 -422
  349. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Delete.yml +0 -182
  350. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-FindOneAndUpdate.yml +0 -239
  351. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-InsertFind.yml +0 -235
  352. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Update.yml +0 -254
  353. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-WrongType.yml +0 -43
  354. data/spec/spec_tests/data/cmap/pool-clear-interrupt-immediately.yml +0 -49
  355. data.tar.gz.sig +0 -0
  356. metadata.gz.sig +0 -2
@@ -33,11 +33,11 @@ module Mongo
33
33
  #
34
34
  # @option options [ Integer ] :local_threshold The local threshold boundary for
35
35
  # nearest selection in seconds.
36
- # @option options [ Integer ] max_staleness The maximum replication lag,
36
+ # @option options [ Integer ] :max_staleness The maximum replication lag,
37
37
  # in seconds, that a secondary can suffer and still be eligible for a read.
38
38
  # A value of -1 is treated identically to nil, which is to not
39
39
  # have a maximum staleness.
40
- # @option options [ Hash | nil ] hedge A Hash specifying whether to enable hedged
40
+ # @option options [ Hash | nil ] :hedge A Hash specifying whether to enable hedged
41
41
  # reads on the server. Hedged reads are not enabled by default. When
42
42
  # specifying this option, it must be in the format: { enabled: true },
43
43
  # where the value of the :enabled key is a boolean value.
@@ -164,6 +164,12 @@ module Mongo
164
164
  # for mongos pinning. Added in version 2.10.0.
165
165
  # @param [ true | false ] write_aggregation Whether we need a server that
166
166
  # supports writing aggregations (e.g. with $merge/$out) on secondaries.
167
+ # @param [ Array<Server> ] deprioritized A list of servers that should
168
+ # be selected from only if no other servers are available. This is
169
+ # used to avoid selecting the same server twice in a row when
170
+ # retrying a command.
171
+ # @param [ Float | nil ] :timeout Timeout in seconds for the operation,
172
+ # if any.
167
173
  #
168
174
  # @return [ Mongo::Server ] A server matching the server preference.
169
175
  #
@@ -174,21 +180,35 @@ module Mongo
174
180
  # lint mode is enabled.
175
181
  #
176
182
  # @since 2.0.0
177
- def select_server(cluster, ping = nil, session = nil, write_aggregation: false)
178
- select_server_impl(cluster, ping, session, write_aggregation).tap do |server|
183
+ def select_server(
184
+ cluster,
185
+ ping = nil,
186
+ session = nil,
187
+ write_aggregation: false,
188
+ deprioritized: [],
189
+ timeout: nil
190
+ )
191
+ select_server_impl(cluster, ping, session, write_aggregation, deprioritized, timeout).tap do |server|
179
192
  if Lint.enabled? && !server.pool.ready?
180
193
  raise Error::LintError, 'Server selector returning a server with a pool which is not ready'
181
194
  end
182
195
  end
183
196
  end
184
197
 
185
- # Parameters and return values are the same as for select_server.
186
- private def select_server_impl(cluster, ping, session, write_aggregation)
198
+ # Parameters and return values are the same as for select_server, only
199
+ # the +timeout+ param is renamed to +csot_timeout+.
200
+ private def select_server_impl(cluster, ping, session, write_aggregation, deprioritized, csot_timeout)
187
201
  if cluster.topology.is_a?(Cluster::Topology::LoadBalanced)
188
202
  return cluster.servers.first
189
203
  end
190
204
 
191
- server_selection_timeout = cluster.options[:server_selection_timeout] || SERVER_SELECTION_TIMEOUT
205
+ timeout = cluster.options[:server_selection_timeout] || SERVER_SELECTION_TIMEOUT
206
+
207
+ server_selection_timeout = if csot_timeout && csot_timeout > 0
208
+ [timeout, csot_timeout].min
209
+ else
210
+ timeout
211
+ end
192
212
 
193
213
  # Special handling for zero timeout: if we have to select a server,
194
214
  # and the timeout is zero, fail immediately (since server selection
@@ -266,7 +286,7 @@ module Mongo
266
286
  end
267
287
  end
268
288
 
269
- server = try_select_server(cluster, write_aggregation: write_aggregation)
289
+ server = try_select_server(cluster, write_aggregation: write_aggregation, deprioritized: deprioritized)
270
290
 
271
291
  if server
272
292
  unless cluster.topology.compatible?
@@ -321,11 +341,15 @@ module Mongo
321
341
  # an eligible server.
322
342
  # @param [ true | false ] write_aggregation Whether we need a server that
323
343
  # supports writing aggregations (e.g. with $merge/$out) on secondaries.
344
+ # @param [ Array<Server> ] deprioritized A list of servers that should
345
+ # be selected from only if no other servers are available. This is
346
+ # used to avoid selecting the same server twice in a row when
347
+ # retrying a command.
324
348
  #
325
349
  # @return [ Server | nil ] A suitable server, if one exists.
326
350
  #
327
351
  # @api private
328
- def try_select_server(cluster, write_aggregation: false)
352
+ def try_select_server(cluster, write_aggregation: false, deprioritized: [])
329
353
  servers = if write_aggregation && cluster.replica_set?
330
354
  # 1. Check if ALL servers in cluster support secondary writes.
331
355
  is_write_supported = cluster.servers.reduce(true) do |res, server|
@@ -347,7 +371,7 @@ module Mongo
347
371
  # by the selector (e.g. for secondary preferred, the first
348
372
  # server may be a secondary and the second server may be primary)
349
373
  # and we should take the first server here respecting the order
350
- server = servers.first
374
+ server = suitable_server(servers, deprioritized)
351
375
 
352
376
  if server
353
377
  if Lint.enabled?
@@ -418,6 +442,24 @@ module Mongo
418
442
 
419
443
  private
420
444
 
445
+ # Returns a server from the list of servers that is suitable for
446
+ # executing the operation.
447
+ #
448
+ # @param [ Array<Server> ] servers The candidate servers.
449
+ # @param [ Array<Server> ] deprioritized A list of servers that should
450
+ # be selected from only if no other servers are available.
451
+ #
452
+ # @return [ Server | nil ] The suitable server or nil if no suitable
453
+ # server is available.
454
+ def suitable_server(servers, deprioritized)
455
+ preferred = servers - deprioritized
456
+ if preferred.empty?
457
+ servers.first
458
+ else
459
+ preferred.first
460
+ end
461
+ end
462
+
421
463
  # Convert this server preference definition into a format appropriate
422
464
  # for sending to a MongoDB server (i.e., as a command field).
423
465
  #
@@ -612,9 +654,9 @@ module Mongo
612
654
  # state resulting from SDAM will immediately wake up this method and
613
655
  # cause it to return.
614
656
  #
615
- # If the cluster des not have a server selection semaphore, waits
657
+ # If the cluster does not have a server selection semaphore, waits
616
658
  # the smaller of 0.25 seconds and the specified remaining time.
617
- # This functionality is provided for backwards compatibilty only for
659
+ # This functionality is provided for backwards compatibility only for
618
660
  # applications directly invoking the server selection process.
619
661
  # If lint mode is enabled and the cluster does not have a server
620
662
  # selection semaphore, Error::LintError will be raised.
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2024 MongoDB Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ module Mongo
18
+ class Session
19
+ class ServerSession
20
+ # Functionality for manipulating and querying a session's
21
+ # "dirty" state, per the last paragraph at
22
+ # https://github.com/mongodb/specifications/blob/master/source/sessions/driver-sessions.rst#server-session-pool
23
+ #
24
+ # If a driver has a server session pool and a network error is
25
+ # encountered when executing any command with a ClientSession, the
26
+ # driver MUST mark the associated ServerSession as dirty. Dirty server
27
+ # sessions are discarded when returned to the server session pool. It is
28
+ # valid for a dirty session to be used for subsequent commands (e.g. an
29
+ # implicit retry attempt, a later command in a bulk write, or a later
30
+ # operation on an explicit session), however, it MUST remain dirty for
31
+ # the remainder of its lifetime regardless if later commands succeed.
32
+ #
33
+ # @api private
34
+ module Dirtyable
35
+ # Query whether the server session has been marked dirty or not.
36
+ #
37
+ # @return [ true | false ] the server session's dirty state
38
+ def dirty?
39
+ @dirty
40
+ end
41
+
42
+ # Mark the server session as dirty (the default) or clean.
43
+ #
44
+ # @param [ true | false ] mark whether the mark the server session
45
+ # dirty or not.
46
+ def dirty!(mark = true)
47
+ @dirty = mark
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -15,6 +15,8 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
+ require 'mongo/session/server_session/dirtyable'
19
+
18
20
  module Mongo
19
21
 
20
22
  class Session
@@ -25,6 +27,7 @@ module Mongo
25
27
  #
26
28
  # @since 2.5.0
27
29
  class ServerSession
30
+ include Dirtyable
28
31
 
29
32
  # Regex for removing dashes from the UUID string.
30
33
  #
@@ -25,21 +25,6 @@ module Mongo
25
25
  #
26
26
  # @since 2.5.0
27
27
  class SessionPool
28
-
29
- # Create a SessionPool.
30
- #
31
- # @example
32
- # SessionPool.create(cluster)
33
- #
34
- # @param [ Mongo::Cluster ] cluster The cluster that will be associated with this
35
- # session pool.
36
- #
37
- # @since 2.5.0
38
- def self.create(cluster)
39
- pool = new(cluster)
40
- cluster.instance_variable_set(:@session_pool, pool)
41
- end
42
-
43
28
  # Initialize a SessionPool.
44
29
  #
45
30
  # @example
@@ -105,9 +90,7 @@ module Mongo
105
90
 
106
91
  @mutex.synchronize do
107
92
  prune!
108
- unless about_to_expire?(session)
109
- @queue.unshift(session)
110
- end
93
+ @queue.unshift(session) if return_to_queue?(session)
111
94
  end
112
95
  end
113
96
 
@@ -136,6 +119,17 @@ module Mongo
136
119
 
137
120
  private
138
121
 
122
+ # Query whether the given session is okay to return to the
123
+ # pool's queue.
124
+ #
125
+ # @param [ Session::ServerSession ] session the session to query
126
+ #
127
+ # @return [ true | false ] whether to return the session to the
128
+ # queue.
129
+ def return_to_queue?(session)
130
+ !session.dirty? && !about_to_expire?(session)
131
+ end
132
+
139
133
  def about_to_expire?(session)
140
134
  if session.nil?
141
135
  raise ArgumentError, 'session cannot be nil'
data/lib/mongo/session.rb CHANGED
@@ -57,6 +57,12 @@ module Mongo
57
57
  #
58
58
  # @option options [ true|false ] :causal_consistency Whether to enable
59
59
  # causal consistency for this session.
60
+ # @option options [ Integer ] :default_timeout_ms The timeoutMS value for
61
+ # the following operations executed on the session:
62
+ # - commitTransaction
63
+ # - abortTransaction
64
+ # - withTransaction
65
+ # - endSession
60
66
  # @option options [ Hash ] :default_transaction_options Options to pass
61
67
  # to start_transaction by default, can contain any of the options that
62
68
  # start_transaction accepts.
@@ -96,6 +102,7 @@ module Mongo
96
102
  @options = options.dup.freeze
97
103
  @cluster_time = nil
98
104
  @state = NO_TRANSACTION_STATE
105
+ @with_transaction_deadline = nil
99
106
  end
100
107
 
101
108
  # @return [ Hash ] The options for this session.
@@ -123,6 +130,23 @@ module Mongo
123
130
  # @since 2.5.0
124
131
  attr_reader :operation_time
125
132
 
133
+ # Sets the dirty state to the given value for the underlying server
134
+ # session. If there is no server session, this does nothing.
135
+ #
136
+ # @param [ true | false ] mark whether to mark the server session as
137
+ # dirty, or not.
138
+ def dirty!(mark = true)
139
+ @server_session&.dirty!(mark)
140
+ end
141
+
142
+ # @return [ true | false | nil ] whether the underlying server session is
143
+ # dirty. If no server session exists for this session, returns nil.
144
+ #
145
+ # @api private
146
+ def dirty?
147
+ @server_session&.dirty?
148
+ end
149
+
126
150
  # @return [ Hash ] The options for the transaction currently being executed
127
151
  # on this session.
128
152
  #
@@ -421,9 +445,21 @@ module Mongo
421
445
  # progress or if the write concern is unacknowledged.
422
446
  #
423
447
  # @since 2.7.0
424
- def with_transaction(options=nil)
425
- # Non-configurable 120 second timeout for the entire operation
426
- deadline = Utils.monotonic_time + 120
448
+ def with_transaction(options = nil)
449
+ if timeout_ms = (options || {})[:timeout_ms]
450
+ timeout_sec = timeout_ms / 1_000.0
451
+ deadline = Utils.monotonic_time + timeout_sec
452
+ @with_transaction_deadline = deadline
453
+ elsif default_timeout_ms = @options[:default_timeout_ms]
454
+ timeout_sec = default_timeout_ms / 1_000.0
455
+ deadline = Utils.monotonic_time + timeout_sec
456
+ @with_transaction_deadline = deadline
457
+ elsif @client.timeout_sec
458
+ deadline = Utils.monotonic_time + @client.timeout_sec
459
+ @with_transaction_deadline = deadline
460
+ else
461
+ deadline = Utils.monotonic_time + 120
462
+ end
427
463
  transaction_in_progress = false
428
464
  loop do
429
465
  commit_options = {}
@@ -437,6 +473,7 @@ module Mongo
437
473
  rescue Exception => e
438
474
  if within_states?(STARTING_TRANSACTION_STATE, TRANSACTION_IN_PROGRESS_STATE)
439
475
  log_warn("Aborting transaction due to #{e.class}: #{e}")
476
+ @with_transaction_deadline = nil
440
477
  abort_transaction
441
478
  transaction_in_progress = false
442
479
  end
@@ -464,7 +501,7 @@ module Mongo
464
501
  rescue Mongo::Error => e
465
502
  if e.label?('UnknownTransactionCommitResult')
466
503
  if Utils.monotonic_time >= deadline ||
467
- e.is_a?(Error::OperationFailure) && e.max_time_ms_expired?
504
+ e.is_a?(Error::OperationFailure::Family) && e.max_time_ms_expired?
468
505
  then
469
506
  transaction_in_progress = false
470
507
  raise
@@ -505,9 +542,10 @@ module Mongo
505
542
  log_warn('with_transaction callback broke out of with_transaction loop, aborting transaction')
506
543
  begin
507
544
  abort_transaction
508
- rescue Error::OperationFailure, Error::InvalidTransactionOperation
545
+ rescue Error::OperationFailure::Family, Error::InvalidTransactionOperation
509
546
  end
510
547
  end
548
+ @with_transaction_deadline = nil
511
549
  end
512
550
 
513
551
  # Places subsequent operations in this session into a new transaction.
@@ -522,6 +560,7 @@ module Mongo
522
560
  #
523
561
  # @option options [ Integer ] :max_commit_time_ms The maximum amount of
524
562
  # time to allow a single commitTransaction command to run, in milliseconds.
563
+ # This options is deprecated, use :timeout_ms instead.
525
564
  # @option options [ Hash ] :read_concern The read concern options hash,
526
565
  # with the following optional keys:
527
566
  # - *:level* -- the read preference level as a symbol; valid values
@@ -532,12 +571,18 @@ module Mongo
532
571
  # items:
533
572
  # - *:mode* -- read preference specified as a symbol; the only valid value is
534
573
  # *:primary*.
574
+ # @option options [ Integer ] :timeout_ms The operation timeout in milliseconds.
575
+ # Must be a non-negative integer. An explicit value of 0 means infinite.
576
+ # The default value is unset which means the value is inherited from
577
+ # the client.
535
578
  #
536
579
  # @raise [ Error::InvalidTransactionOperation ] If a transaction is already in
537
580
  # progress or if the write concern is unacknowledged.
538
581
  #
539
582
  # @since 2.6.0
540
583
  def start_transaction(options = nil)
584
+ check_transactions_supported!
585
+
541
586
  if options
542
587
  Lint.validate_read_concern_option(options[:read_concern])
543
588
 
@@ -592,6 +637,10 @@ module Mongo
592
637
  #
593
638
  # @option options :write_concern [ nil | WriteConcern::Base ] The write
594
639
  # concern to use for this operation.
640
+ # @option options [ Integer ] :timeout_ms The operation timeout in milliseconds.
641
+ # Must be a non-negative integer. An explicit value of 0 means infinite.
642
+ # The default value is unset which means the value is inherited from
643
+ # the client.
595
644
  #
596
645
  # @raise [ Error::InvalidTransactionOperation ] If there is no active transaction.
597
646
  #
@@ -628,7 +677,11 @@ module Mongo
628
677
  write_concern = WriteConcern.get(write_concern)
629
678
  end
630
679
 
631
- context = Operation::Context.new(client: @client, session: self)
680
+ context = Operation::Context.new(
681
+ client: @client,
682
+ session: self,
683
+ operation_timeouts: operation_timeouts(options)
684
+ )
632
685
  write_with_retry(write_concern, ending_transaction: true,
633
686
  context: context,
634
687
  ) do |connection, txn_num, context|
@@ -666,10 +719,15 @@ module Mongo
666
719
  # @example Abort the transaction.
667
720
  # session.abort_transaction
668
721
  #
722
+ # @option options [ Integer ] :timeout_ms The operation timeout in milliseconds.
723
+ # Must be a non-negative integer. An explicit value of 0 means infinite.
724
+ # The default value is unset which means the value is inherited from
725
+ # the client.
726
+ #
669
727
  # @raise [ Error::InvalidTransactionOperation ] If there is no active transaction.
670
728
  #
671
729
  # @since 2.6.0
672
- def abort_transaction
730
+ def abort_transaction(options = nil)
673
731
  QueryCache.clear
674
732
 
675
733
  check_if_ended!
@@ -686,10 +744,16 @@ module Mongo
686
744
  Mongo::Error::InvalidTransactionOperation.cannot_call_twice_msg(:abortTransaction))
687
745
  end
688
746
 
747
+ options ||= {}
748
+
689
749
  begin
690
750
  unless starting_transaction?
691
751
  @aborting_transaction = true
692
- context = Operation::Context.new(client: @client, session: self)
752
+ context = Operation::Context.new(
753
+ client: @client,
754
+ session: self,
755
+ operation_timeouts: operation_timeouts(options)
756
+ )
693
757
  write_with_retry(txn_options[:write_concern],
694
758
  ending_transaction: true, context: context,
695
759
  ) do |connection, txn_num, context|
@@ -879,7 +943,7 @@ module Mongo
879
943
  #
880
944
  # @since 2.6.0
881
945
  # @api private
882
- def add_txn_opts!(command, read)
946
+ def add_txn_opts!(command, read, context)
883
947
  command.tap do |c|
884
948
  # The read concern should be added to any command that starts a transaction.
885
949
  if starting_transaction?
@@ -933,6 +997,14 @@ module Mongo
933
997
  if c[:writeConcern] && c[:writeConcern][:w] && c[:writeConcern][:w].is_a?(Symbol)
934
998
  c[:writeConcern][:w] = c[:writeConcern][:w].to_s
935
999
  end
1000
+
1001
+ # Ignore wtimeout if csot
1002
+ if context&.csot?
1003
+ c[:writeConcern]&.delete(:wtimeout)
1004
+ end
1005
+
1006
+ # We must not send an empty (server default) write concern.
1007
+ c.delete(:writeConcern) if c[:writeConcern]&.empty?
936
1008
  end
937
1009
  end
938
1010
 
@@ -1119,6 +1191,8 @@ module Mongo
1119
1191
  # @api private
1120
1192
  attr_accessor :snapshot_timestamp
1121
1193
 
1194
+ attr_reader :with_transaction_deadline
1195
+
1122
1196
  private
1123
1197
 
1124
1198
  # Get the read concern the session will use when starting a transaction.
@@ -1185,5 +1259,32 @@ module Mongo
1185
1259
  raise Mongo::Error::InvalidSession.new(MISMATCHED_CLUSTER_ERROR_MSG)
1186
1260
  end
1187
1261
  end
1262
+
1263
+ def check_transactions_supported!
1264
+ raise Mongo::Error::TransactionsNotSupported, "standalone topology" if cluster.single?
1265
+
1266
+ cluster.next_primary.with_connection do |conn|
1267
+ if cluster.replica_set? && !conn.features.transactions_enabled?
1268
+ raise Mongo::Error::TransactionsNotSupported, "server version is < 4.0"
1269
+ end
1270
+ if cluster.sharded? && !conn.features.sharded_transactions_enabled?
1271
+ raise Mongo::Error::TransactionsNotSupported, "sharded transactions require server version >= 4.2"
1272
+ end
1273
+ end
1274
+ end
1275
+
1276
+ def operation_timeouts(opts)
1277
+ {
1278
+ inherited_timeout_ms: @client.timeout_ms
1279
+ }.tap do |result|
1280
+ if @with_transaction_deadline.nil?
1281
+ if timeout_ms = opts[:timeout_ms]
1282
+ result[:operation_timeout_ms] = timeout_ms
1283
+ elsif default_timeout_ms = options[:default_timeout_ms]
1284
+ result[:operation_timeout_ms] = default_timeout_ms
1285
+ end
1286
+ end
1287
+ end
1288
+ end
1188
1289
  end
1189
1290
  end