mongo 2.20.1 → 2.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (246) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -0
  3. data/Rakefile +2 -2
  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.rb +14 -4
  13. data/lib/mongo/collection/helpers.rb +1 -1
  14. data/lib/mongo/collection/view/aggregation/behavior.rb +131 -0
  15. data/lib/mongo/collection/view/aggregation.rb +33 -99
  16. data/lib/mongo/collection/view/builder/aggregation.rb +1 -7
  17. data/lib/mongo/collection/view/change_stream.rb +80 -27
  18. data/lib/mongo/collection/view/iterable.rb +76 -60
  19. data/lib/mongo/collection/view/map_reduce.rb +25 -8
  20. data/lib/mongo/collection/view/readable.rb +79 -30
  21. data/lib/mongo/collection/view/writable.rb +109 -48
  22. data/lib/mongo/collection/view.rb +43 -3
  23. data/lib/mongo/collection.rb +158 -23
  24. data/lib/mongo/crypt/auto_encrypter.rb +4 -6
  25. data/lib/mongo/crypt/binding.rb +4 -4
  26. data/lib/mongo/crypt/context.rb +20 -14
  27. data/lib/mongo/crypt/encryption_io.rb +56 -26
  28. data/lib/mongo/crypt/explicit_encrypter.rb +49 -20
  29. data/lib/mongo/crypt/explicit_encryption_context.rb +17 -11
  30. data/lib/mongo/crypt/kms/azure/credentials_retriever.rb +22 -6
  31. data/lib/mongo/crypt/kms/gcp/credentials_retriever.rb +29 -4
  32. data/lib/mongo/csot_timeout_holder.rb +119 -0
  33. data/lib/mongo/cursor/kill_spec.rb +5 -2
  34. data/lib/mongo/cursor/nontailable.rb +27 -0
  35. data/lib/mongo/cursor.rb +86 -24
  36. data/lib/mongo/cursor_host.rb +82 -0
  37. data/lib/mongo/database/view.rb +81 -14
  38. data/lib/mongo/database.rb +88 -18
  39. data/lib/mongo/error/operation_failure.rb +209 -204
  40. data/lib/mongo/error/server_timeout_error.rb +12 -0
  41. data/lib/mongo/error/socket_timeout_error.rb +3 -1
  42. data/lib/mongo/error/timeout_error.rb +23 -0
  43. data/lib/mongo/error.rb +2 -0
  44. data/lib/mongo/grid/fs_bucket.rb +45 -12
  45. data/lib/mongo/grid/stream/read.rb +15 -1
  46. data/lib/mongo/grid/stream/write.rb +21 -4
  47. data/lib/mongo/index/view.rb +77 -16
  48. data/lib/mongo/operation/context.rb +40 -2
  49. data/lib/mongo/operation/create_search_indexes/op_msg.rb +2 -2
  50. data/lib/mongo/operation/delete/op_msg.rb +2 -1
  51. data/lib/mongo/operation/drop_search_index/op_msg.rb +2 -2
  52. data/lib/mongo/operation/find/op_msg.rb +45 -0
  53. data/lib/mongo/operation/get_more/op_msg.rb +33 -0
  54. data/lib/mongo/operation/insert/op_msg.rb +3 -2
  55. data/lib/mongo/operation/insert/result.rb +4 -2
  56. data/lib/mongo/operation/list_collections/result.rb +1 -1
  57. data/lib/mongo/operation/map_reduce/result.rb +1 -1
  58. data/lib/mongo/operation/op_msg_base.rb +3 -1
  59. data/lib/mongo/operation/result.rb +26 -5
  60. data/lib/mongo/operation/shared/executable.rb +12 -1
  61. data/lib/mongo/operation/shared/op_msg_executable.rb +4 -1
  62. data/lib/mongo/operation/shared/response_handling.rb +3 -3
  63. data/lib/mongo/operation/shared/sessions_supported.rb +1 -1
  64. data/lib/mongo/operation/shared/timed.rb +52 -0
  65. data/lib/mongo/operation/shared/write.rb +4 -1
  66. data/lib/mongo/operation/update/op_msg.rb +2 -1
  67. data/lib/mongo/operation/update_search_index/op_msg.rb +2 -2
  68. data/lib/mongo/operation.rb +1 -0
  69. data/lib/mongo/protocol/message.rb +1 -4
  70. data/lib/mongo/protocol/msg.rb +2 -2
  71. data/lib/mongo/retryable/read_worker.rb +69 -29
  72. data/lib/mongo/retryable/write_worker.rb +49 -18
  73. data/lib/mongo/retryable.rb +8 -2
  74. data/lib/mongo/server/connection.rb +11 -5
  75. data/lib/mongo/server/connection_base.rb +22 -2
  76. data/lib/mongo/server/connection_pool.rb +32 -14
  77. data/lib/mongo/server/description/features.rb +1 -1
  78. data/lib/mongo/server/description.rb +18 -5
  79. data/lib/mongo/server/monitor.rb +7 -4
  80. data/lib/mongo/server/pending_connection.rb +7 -3
  81. data/lib/mongo/server/{round_trip_time_averager.rb → round_trip_time_calculator.rb} +25 -7
  82. data/lib/mongo/server.rb +11 -6
  83. data/lib/mongo/server_selector/base.rb +25 -9
  84. data/lib/mongo/session.rb +78 -9
  85. data/lib/mongo/socket/ssl.rb +109 -17
  86. data/lib/mongo/socket/tcp.rb +40 -6
  87. data/lib/mongo/socket.rb +154 -25
  88. data/lib/mongo/uri/options_mapper.rb +1 -0
  89. data/lib/mongo/version.rb +1 -1
  90. data/lib/mongo.rb +1 -0
  91. data/spec/atlas/atlas_connectivity_spec.rb +4 -0
  92. data/spec/atlas/operations_spec.rb +4 -0
  93. data/spec/integration/client_side_encryption/auto_encryption_mongocryptd_spawn_spec.rb +2 -1
  94. data/spec/integration/client_side_encryption/auto_encryption_spec.rb +494 -487
  95. data/spec/integration/client_side_encryption/on_demand_aws_credentials_spec.rb +1 -1
  96. data/spec/integration/client_side_encryption/range_explicit_encryption_prose_spec.rb +66 -22
  97. data/spec/integration/client_side_operations_timeout/encryption_prose_spec.rb +131 -0
  98. data/spec/integration/connection_pool_populator_spec.rb +2 -0
  99. data/spec/integration/cursor_pinning_spec.rb +15 -60
  100. data/spec/integration/cursor_reaping_spec.rb +1 -1
  101. data/spec/integration/docs_examples_spec.rb +1 -1
  102. data/spec/integration/operation_failure_code_spec.rb +1 -1
  103. data/spec/integration/operation_failure_message_spec.rb +3 -3
  104. data/spec/integration/retryable_errors_spec.rb +2 -2
  105. data/spec/integration/sdam_error_handling_spec.rb +2 -1
  106. data/spec/integration/search_indexes_prose_spec.rb +4 -0
  107. data/spec/integration/server_spec.rb +4 -3
  108. data/spec/integration/transactions_api_examples_spec.rb +2 -0
  109. data/spec/kerberos/kerberos_spec.rb +4 -0
  110. data/spec/lite_spec_helper.rb +3 -1
  111. data/spec/mongo/auth/user/view_spec.rb +1 -1
  112. data/spec/mongo/caching_cursor_spec.rb +1 -1
  113. data/spec/mongo/client_encryption_spec.rb +1 -0
  114. data/spec/mongo/client_spec.rb +158 -4
  115. data/spec/mongo/collection/view/aggregation_spec.rb +14 -39
  116. data/spec/mongo/collection/view/change_stream_spec.rb +3 -3
  117. data/spec/mongo/collection_spec.rb +5 -6
  118. data/spec/mongo/crypt/auto_encrypter_spec.rb +14 -12
  119. data/spec/mongo/crypt/data_key_context_spec.rb +3 -1
  120. data/spec/mongo/crypt/explicit_encryption_context_spec.rb +2 -2
  121. data/spec/mongo/crypt/handle_spec.rb +1 -1
  122. data/spec/mongo/cursor_spec.rb +26 -9
  123. data/spec/mongo/error/operation_failure_heavy_spec.rb +2 -2
  124. data/spec/mongo/operation/context_spec.rb +79 -0
  125. data/spec/mongo/operation/create/op_msg_spec.rb +106 -110
  126. data/spec/mongo/operation/delete/op_msg_spec.rb +6 -5
  127. data/spec/mongo/operation/find/op_msg_spec.rb +66 -0
  128. data/spec/mongo/operation/get_more/op_msg_spec.rb +65 -0
  129. data/spec/mongo/operation/insert/op_msg_spec.rb +128 -131
  130. data/spec/mongo/operation/shared/csot/examples.rb +113 -0
  131. data/spec/mongo/query_cache_spec.rb +243 -225
  132. data/spec/mongo/retryable_spec.rb +1 -0
  133. data/spec/mongo/server/round_trip_time_calculator_spec.rb +120 -0
  134. data/spec/mongo/socket/ssl_spec.rb +0 -10
  135. data/spec/runners/change_streams/test.rb +2 -2
  136. data/spec/runners/crud/operation.rb +1 -1
  137. data/spec/runners/crud/verifier.rb +3 -1
  138. data/spec/runners/transactions/operation.rb +4 -6
  139. data/spec/runners/unified/ambiguous_operations.rb +13 -0
  140. data/spec/runners/unified/assertions.rb +4 -0
  141. data/spec/runners/unified/change_stream_operations.rb +14 -24
  142. data/spec/runners/unified/crud_operations.rb +82 -59
  143. data/spec/runners/unified/ddl_operations.rb +38 -7
  144. data/spec/runners/unified/grid_fs_operations.rb +37 -2
  145. data/spec/runners/unified/support_operations.rb +43 -4
  146. data/spec/runners/unified/test.rb +22 -10
  147. data/spec/runners/unified.rb +1 -1
  148. data/spec/solo/clean_exit_spec.rb +2 -0
  149. data/spec/spec_tests/client_side_operations_timeout_spec.rb +15 -0
  150. data/spec/spec_tests/data/change_streams_unified/change-streams-clusterTime.yml +3 -1
  151. data/spec/spec_tests/data/change_streams_unified/change-streams-disambiguatedPaths.yml +3 -1
  152. data/spec/spec_tests/data/change_streams_unified/change-streams-errors.yml +3 -1
  153. data/spec/spec_tests/data/change_streams_unified/change-streams-pre_and_post_images.yml +1 -1
  154. data/spec/spec_tests/data/change_streams_unified/change-streams-resume-allowlist.yml +1 -1
  155. data/spec/spec_tests/data/change_streams_unified/change-streams-resume-errorLabels.yml +1 -1
  156. data/spec/spec_tests/data/change_streams_unified/change-streams-showExpandedEvents.yml +1 -1
  157. data/spec/spec_tests/data/client_side_encryption/badQueries.yml +2 -1
  158. data/spec/spec_tests/data/client_side_encryption/timeoutMS.yml +67 -0
  159. data/spec/spec_tests/data/client_side_operations_timeout/bulkWrite.yml +87 -0
  160. data/spec/spec_tests/data/client_side_operations_timeout/change-streams.yml +358 -0
  161. data/spec/spec_tests/data/client_side_operations_timeout/close-cursors.yml +129 -0
  162. data/spec/spec_tests/data/client_side_operations_timeout/command-execution.yml +250 -0
  163. data/spec/spec_tests/data/client_side_operations_timeout/convenient-transactions.yml +113 -0
  164. data/spec/spec_tests/data/client_side_operations_timeout/cursors.yml +70 -0
  165. data/spec/spec_tests/data/client_side_operations_timeout/deprecated-options.yml +3982 -0
  166. data/spec/spec_tests/data/client_side_operations_timeout/error-transformations.yml +96 -0
  167. data/spec/spec_tests/data/client_side_operations_timeout/global-timeoutMS.yml +3236 -0
  168. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-advanced.yml +207 -0
  169. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-delete.yml +152 -0
  170. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-download.yml +182 -0
  171. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-find.yml +100 -0
  172. data/spec/spec_tests/data/client_side_operations_timeout/gridfs-upload.yml +249 -0
  173. data/spec/spec_tests/data/client_side_operations_timeout/legacy-timeouts.yml +204 -0
  174. data/spec/spec_tests/data/client_side_operations_timeout/non-tailable-cursors.yml +307 -0
  175. data/spec/spec_tests/data/client_side_operations_timeout/override-collection-timeoutMS.yml +1877 -0
  176. data/spec/spec_tests/data/client_side_operations_timeout/override-operation-timeoutMS.yml +1918 -0
  177. data/spec/spec_tests/data/client_side_operations_timeout/retryability-legacy-timeouts.yml +1676 -0
  178. data/spec/spec_tests/data/client_side_operations_timeout/retryability-timeoutMS.yml +2824 -0
  179. data/spec/spec_tests/data/client_side_operations_timeout/sessions-inherit-timeoutMS.yml +168 -0
  180. data/spec/spec_tests/data/client_side_operations_timeout/sessions-override-operation-timeoutMS.yml +171 -0
  181. data/spec/spec_tests/data/client_side_operations_timeout/sessions-override-timeoutMS.yml +168 -0
  182. data/spec/spec_tests/data/client_side_operations_timeout/tailable-awaitData.yml +247 -0
  183. data/spec/spec_tests/data/client_side_operations_timeout/tailable-non-awaitData.yml +181 -0
  184. data/spec/spec_tests/data/crud_unified/aggregate-write-readPreference.yml +4 -0
  185. data/spec/spec_tests/data/crud_unified/db-aggregate-write-readPreference.yml +4 -0
  186. data/spec/spec_tests/data/crud_unified/find-test-all-options.yml +29 -0
  187. data/spec/spec_tests/server_selection_rtt_spec.rb +6 -6
  188. data/spec/support/certificates/atlas-ocsp-ca.crt +81 -83
  189. data/spec/support/certificates/atlas-ocsp.crt +107 -107
  190. data/spec/support/cluster_tools.rb +3 -3
  191. data/spec/support/common_shortcuts.rb +2 -2
  192. data/spec/support/crypt/encrypted_fields/range-encryptedFields-Date.json +1 -1
  193. data/spec/support/crypt/encrypted_fields/range-encryptedFields-DecimalNoPrecision.json +1 -1
  194. data/spec/support/crypt/encrypted_fields/range-encryptedFields-DecimalPrecision.json +1 -1
  195. data/spec/support/crypt/encrypted_fields/range-encryptedFields-DoubleNoPrecision.json +1 -1
  196. data/spec/support/crypt/encrypted_fields/range-encryptedFields-DoublePrecision.json +1 -1
  197. data/spec/support/crypt/encrypted_fields/range-encryptedFields-Int.json +1 -1
  198. data/spec/support/crypt/encrypted_fields/range-encryptedFields-Long.json +1 -1
  199. data/spec/support/shared/session.rb +2 -2
  200. data/spec/support/spec_setup.rb +2 -2
  201. data/spec/support/utils.rb +3 -1
  202. metadata +78 -91
  203. data/spec/mongo/server/round_trip_time_averager_spec.rb +0 -48
  204. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Aggregate.yml +0 -242
  205. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Correctness.yml +0 -423
  206. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Delete.yml +0 -183
  207. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-FindOneAndUpdate.yml +0 -240
  208. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-InsertFind.yml +0 -236
  209. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Update.yml +0 -253
  210. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Aggregate.yml +0 -1688
  211. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Correctness.yml +0 -294
  212. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Delete.yml +0 -906
  213. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-FindOneAndUpdate.yml +0 -1685
  214. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-InsertFind.yml +0 -1681
  215. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Update.yml +0 -1698
  216. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Aggregate.yml +0 -330
  217. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Correctness.yml +0 -425
  218. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Delete.yml +0 -227
  219. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.yml +0 -328
  220. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-InsertFind.yml +0 -320
  221. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Update.yml +0 -337
  222. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Aggregate.yml +0 -914
  223. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Correctness.yml +0 -293
  224. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Delete.yml +0 -519
  225. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-FindOneAndUpdate.yml +0 -912
  226. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-InsertFind.yml +0 -908
  227. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Update.yml +0 -925
  228. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Aggregate.yml +0 -326
  229. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Correctness.yml +0 -425
  230. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Delete.yml +0 -225
  231. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-FindOneAndUpdate.yml +0 -324
  232. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-InsertFind.yml +0 -320
  233. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Update.yml +0 -339
  234. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Aggregate.yml +0 -242
  235. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Correctness.yml +0 -424
  236. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Delete.yml +0 -183
  237. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-FindOneAndUpdate.yml +0 -240
  238. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-InsertFind.yml +0 -236
  239. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Update.yml +0 -255
  240. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Aggregate.yml +0 -242
  241. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Correctness.yml +0 -423
  242. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Delete.yml +0 -183
  243. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-FindOneAndUpdate.yml +0 -240
  244. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-InsertFind.yml +0 -236
  245. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Update.yml +0 -255
  246. data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-WrongType.yml +0 -44
@@ -18,242 +18,247 @@ require 'mongo/error/read_write_retryable'
18
18
 
19
19
  module Mongo
20
20
  class Error
21
-
22
21
  # Raised when an operation fails for some reason.
23
- #
24
- # @since 2.0.0
25
22
  class OperationFailure < Error
26
- extend Forwardable
27
- include SdamErrorDetection
28
- include ReadWriteRetryable
23
+ # Implements the behavior for an OperationFailure error. Other errors
24
+ # (e.g. ServerTimeoutError) may also implement this, so that they may
25
+ # be recognized and treated as OperationFailure errors.
26
+ module OperationFailure::Family
27
+ extend Forwardable
28
+ include SdamErrorDetection
29
+ include ReadWriteRetryable
29
30
 
30
- def_delegators :@result, :operation_time
31
+ def_delegators :@result, :operation_time
31
32
 
32
- # @!method connection_description
33
- #
34
- # @return [ Server::Description ] Server description of the server that
35
- # the operation that this exception refers to was performed on.
36
- #
37
- # @api private
38
- def_delegator :@result, :connection_description
33
+ # @!method connection_description
34
+ #
35
+ # @return [ Server::Description ] Server description of the server that
36
+ # the operation that this exception refers to was performed on.
37
+ #
38
+ # @api private
39
+ def_delegator :@result, :connection_description
39
40
 
40
- # @return [ Integer ] The error code parsed from the document.
41
- #
42
- # @since 2.6.0
43
- attr_reader :code
41
+ # @return [ Integer ] The error code parsed from the document.
42
+ #
43
+ # @since 2.6.0
44
+ attr_reader :code
44
45
 
45
- # @return [ String ] The error code name parsed from the document.
46
- #
47
- # @since 2.6.0
48
- attr_reader :code_name
46
+ # @return [ String ] The error code name parsed from the document.
47
+ #
48
+ # @since 2.6.0
49
+ attr_reader :code_name
49
50
 
50
- # @return [ String ] The server-returned error message
51
- # parsed from the response.
52
- #
53
- # @api experimental
54
- attr_reader :server_message
51
+ # @return [ String ] The server-returned error message
52
+ # parsed from the response.
53
+ #
54
+ # @api experimental
55
+ attr_reader :server_message
55
56
 
56
- # Error codes and code names that should result in a failing getMore
57
- # command on a change stream NOT being resumed.
58
- #
59
- # @api private
60
- CHANGE_STREAM_RESUME_ERRORS = [
61
- {code_name: 'HostUnreachable', code: 6},
62
- {code_name: 'HostNotFound', code: 7},
63
- {code_name: 'NetworkTimeout', code: 89},
64
- {code_name: 'ShutdownInProgress', code: 91},
65
- {code_name: 'PrimarySteppedDown', code: 189},
66
- {code_name: 'ExceededTimeLimit', code: 262},
67
- {code_name: 'SocketException', code: 9001},
68
- {code_name: 'NotMaster', code: 10107},
69
- {code_name: 'InterruptedAtShutdown', code: 11600},
70
- {code_name: 'InterruptedDueToReplStateChange', code: 11602},
71
- {code_name: 'NotPrimaryNoSecondaryOk', code: 13435},
72
- {code_name: 'NotMasterOrSecondary', code: 13436},
57
+ # Error codes and code names that should result in a failing getMore
58
+ # command on a change stream NOT being resumed.
59
+ #
60
+ # @api private
61
+ CHANGE_STREAM_RESUME_ERRORS = [
62
+ {code_name: 'HostUnreachable', code: 6},
63
+ {code_name: 'HostNotFound', code: 7},
64
+ {code_name: 'NetworkTimeout', code: 89},
65
+ {code_name: 'ShutdownInProgress', code: 91},
66
+ {code_name: 'PrimarySteppedDown', code: 189},
67
+ {code_name: 'ExceededTimeLimit', code: 262},
68
+ {code_name: 'SocketException', code: 9001},
69
+ {code_name: 'NotMaster', code: 10107},
70
+ {code_name: 'InterruptedAtShutdown', code: 11600},
71
+ {code_name: 'InterruptedDueToReplStateChange', code: 11602},
72
+ {code_name: 'NotPrimaryNoSecondaryOk', code: 13435},
73
+ {code_name: 'NotMasterOrSecondary', code: 13436},
73
74
 
74
- {code_name: 'StaleShardVersion', code: 63},
75
- {code_name: 'FailedToSatisfyReadPreference', code: 133},
76
- {code_name: 'StaleEpoch', code: 150},
77
- {code_name: 'RetryChangeStream', code: 234},
78
- {code_name: 'StaleConfig', code: 13388},
79
- ].freeze
75
+ {code_name: 'StaleShardVersion', code: 63},
76
+ {code_name: 'FailedToSatisfyReadPreference', code: 133},
77
+ {code_name: 'StaleEpoch', code: 150},
78
+ {code_name: 'RetryChangeStream', code: 234},
79
+ {code_name: 'StaleConfig', code: 13388},
80
+ ].freeze
80
81
 
81
- # Change stream can be resumed when these error messages are encountered.
82
- #
83
- # @since 2.6.0
84
- # @api private
85
- CHANGE_STREAM_RESUME_MESSAGES = ReadWriteRetryable::WRITE_RETRY_MESSAGES
82
+ # Change stream can be resumed when these error messages are encountered.
83
+ #
84
+ # @since 2.6.0
85
+ # @api private
86
+ CHANGE_STREAM_RESUME_MESSAGES = ReadWriteRetryable::WRITE_RETRY_MESSAGES
86
87
 
87
- # Can the change stream on which this error occurred be resumed,
88
- # provided the operation that triggered this error was a getMore?
89
- #
90
- # @example Is the error resumable for the change stream?
91
- # error.change_stream_resumable?
92
- #
93
- # @return [ true, false ] Whether the error is resumable.
94
- #
95
- # @since 2.6.0
96
- def change_stream_resumable?
97
- if @result && @result.is_a?(Mongo::Operation::GetMore::Result)
98
- # CursorNotFound exceptions are always resumable because the server
99
- # is not aware of the cursor id, and thus cannot determine if
100
- # the cursor is a change stream and cannot add the
101
- # ResumableChangeStreamError label.
102
- return true if code == 43
88
+ # Can the change stream on which this error occurred be resumed,
89
+ # provided the operation that triggered this error was a getMore?
90
+ #
91
+ # @example Is the error resumable for the change stream?
92
+ # error.change_stream_resumable?
93
+ #
94
+ # @return [ true, false ] Whether the error is resumable.
95
+ #
96
+ # @since 2.6.0
97
+ def change_stream_resumable?
98
+ if @result && @result.is_a?(Mongo::Operation::GetMore::Result)
99
+ # CursorNotFound exceptions are always resumable because the server
100
+ # is not aware of the cursor id, and thus cannot determine if
101
+ # the cursor is a change stream and cannot add the
102
+ # ResumableChangeStreamError label.
103
+ return true if code == 43
103
104
 
104
- # Connection description is not populated for unacknowledged writes.
105
- if connection_description.max_wire_version >= 9
106
- label?('ResumableChangeStreamError')
105
+ # Connection description is not populated for unacknowledged writes.
106
+ if connection_description.max_wire_version >= 9
107
+ label?('ResumableChangeStreamError')
108
+ else
109
+ change_stream_resumable_code?
110
+ end
107
111
  else
108
- change_stream_resumable_code?
112
+ false
109
113
  end
110
- else
111
- false
112
114
  end
113
- end
114
115
 
115
- def change_stream_resumable_code?
116
- CHANGE_STREAM_RESUME_ERRORS.any? { |e| e[:code] == code }
117
- end
118
- private :change_stream_resumable_code?
116
+ def change_stream_resumable_code?
117
+ CHANGE_STREAM_RESUME_ERRORS.any? { |e| e[:code] == code }
118
+ end
119
+ private :change_stream_resumable_code?
119
120
 
120
- # @return [ true | false ] Whether the failure includes a write
121
- # concern error. A failure may have a top level error and a write
122
- # concern error or either one of the two.
123
- #
124
- # @since 2.10.0
125
- def write_concern_error?
126
- !!@write_concern_error_document
127
- end
121
+ # @return [ true | false ] Whether the failure includes a write
122
+ # concern error. A failure may have a top level error and a write
123
+ # concern error or either one of the two.
124
+ #
125
+ # @since 2.10.0
126
+ def write_concern_error?
127
+ !!@write_concern_error_document
128
+ end
128
129
 
129
- # Returns the write concern error document as it was reported by the
130
- # server, if any.
131
- #
132
- # @return [ Hash | nil ] Write concern error as reported to the server.
133
- attr_reader :write_concern_error_document
130
+ # Returns the write concern error document as it was reported by the
131
+ # server, if any.
132
+ #
133
+ # @return [ Hash | nil ] Write concern error as reported to the server.
134
+ attr_reader :write_concern_error_document
134
135
 
135
- # @return [ Integer | nil ] The error code for the write concern error,
136
- # if a write concern error is present and has a code.
137
- #
138
- # @since 2.10.0
139
- attr_reader :write_concern_error_code
136
+ # @return [ Integer | nil ] The error code for the write concern error,
137
+ # if a write concern error is present and has a code.
138
+ #
139
+ # @since 2.10.0
140
+ attr_reader :write_concern_error_code
140
141
 
141
- # @return [ String | nil ] The code name for the write concern error,
142
- # if a write concern error is present and has a code name.
143
- #
144
- # @since 2.10.0
145
- attr_reader :write_concern_error_code_name
142
+ # @return [ String | nil ] The code name for the write concern error,
143
+ # if a write concern error is present and has a code name.
144
+ #
145
+ # @since 2.10.0
146
+ attr_reader :write_concern_error_code_name
146
147
 
147
- # @return [ String | nil ] The details of the error.
148
- # For WriteConcernErrors this is `document['writeConcernError']['errInfo']`.
149
- # For WriteErrors this is `document['writeErrors'][0]['errInfo']`.
150
- # For all other errors this is nil.
151
- attr_reader :details
148
+ # @return [ String | nil ] The details of the error.
149
+ # For WriteConcernErrors this is `document['writeConcernError']['errInfo']`.
150
+ # For WriteErrors this is `document['writeErrors'][0]['errInfo']`.
151
+ # For all other errors this is nil.
152
+ attr_reader :details
152
153
 
153
- # @return [ BSON::Document | nil ] The server-returned error document.
154
- #
155
- # @api experimental
156
- attr_reader :document
154
+ # @return [ BSON::Document | nil ] The server-returned error document.
155
+ #
156
+ # @api experimental
157
+ attr_reader :document
157
158
 
158
- # Create the operation failure.
159
- #
160
- # @example Create the error object
161
- # OperationFailure.new(message, result)
162
- #
163
- # @example Create the error object with a code and a code name
164
- # OperationFailure.new(message, result, :code => code, :code_name => code_name)
165
- #
166
- # @param [ String ] message The error message.
167
- # @param [ Operation::Result ] result The result object.
168
- # @param [ Hash ] options Additional parameters.
169
- #
170
- # @option options [ Integer ] :code Error code.
171
- # @option options [ String ] :code_name Error code name.
172
- # @option options [ BSON::Document ] :document The server-returned
173
- # error document.
174
- # @option options [ String ] server_message The server-returned
175
- # error message parsed from the response.
176
- # @option options [ Hash ] :write_concern_error_document The
177
- # server-supplied write concern error document, if any.
178
- # @option options [ Integer ] :write_concern_error_code Error code for
179
- # write concern error, if any.
180
- # @option options [ String ] :write_concern_error_code_name Error code
181
- # name for write concern error, if any.
182
- # @option options [ Array<String> ] :write_concern_error_labels Error
183
- # labels for the write concern error, if any.
184
- # @option options [ Array<String> ] :labels The set of labels associated
185
- # with the error.
186
- # @option options [ true | false ] :wtimeout Whether the error is a wtimeout.
187
- def initialize(message = nil, result = nil, options = {})
188
- @details = retrieve_details(options[:document])
189
- super(append_details(message, @details))
159
+ # @return [ Operation::Result ] the result object for the operation.
160
+ #
161
+ # @api private
162
+ attr_reader :result
190
163
 
191
- @result = result
192
- @code = options[:code]
193
- @code_name = options[:code_name]
194
- @write_concern_error_document = options[:write_concern_error_document]
195
- @write_concern_error_code = options[:write_concern_error_code]
196
- @write_concern_error_code_name = options[:write_concern_error_code_name]
197
- @write_concern_error_labels = options[:write_concern_error_labels] || []
198
- @labels = options[:labels] || []
199
- @wtimeout = !!options[:wtimeout]
200
- @document = options[:document]
201
- @server_message = options[:server_message]
202
- end
164
+ # Create the operation failure.
165
+ #
166
+ # @param [ String ] message The error message.
167
+ # @param [ Operation::Result ] result The result object.
168
+ # @param [ Hash ] options Additional parameters.
169
+ #
170
+ # @option options [ Integer ] :code Error code.
171
+ # @option options [ String ] :code_name Error code name.
172
+ # @option options [ BSON::Document ] :document The server-returned
173
+ # error document.
174
+ # @option options [ String ] server_message The server-returned
175
+ # error message parsed from the response.
176
+ # @option options [ Hash ] :write_concern_error_document The
177
+ # server-supplied write concern error document, if any.
178
+ # @option options [ Integer ] :write_concern_error_code Error code for
179
+ # write concern error, if any.
180
+ # @option options [ String ] :write_concern_error_code_name Error code
181
+ # name for write concern error, if any.
182
+ # @option options [ Array<String> ] :write_concern_error_labels Error
183
+ # labels for the write concern error, if any.
184
+ # @option options [ Array<String> ] :labels The set of labels associated
185
+ # with the error.
186
+ # @option options [ true | false ] :wtimeout Whether the error is a wtimeout.
187
+ def initialize(message = nil, result = nil, options = {})
188
+ @details = retrieve_details(options[:document])
189
+ super(append_details(message, @details))
203
190
 
204
- # Whether the error is a write concern timeout.
205
- #
206
- # @return [ true | false ] Whether the error is a write concern timeout.
207
- #
208
- # @since 2.7.1
209
- def wtimeout?
210
- @wtimeout
211
- end
191
+ @result = result
192
+ @code = options[:code]
193
+ @code_name = options[:code_name]
194
+ @write_concern_error_document = options[:write_concern_error_document]
195
+ @write_concern_error_code = options[:write_concern_error_code]
196
+ @write_concern_error_code_name = options[:write_concern_error_code_name]
197
+ @write_concern_error_labels = options[:write_concern_error_labels] || []
198
+ @labels = options[:labels] || []
199
+ @wtimeout = !!options[:wtimeout]
200
+ @document = options[:document]
201
+ @server_message = options[:server_message]
202
+ end
212
203
 
213
- # Whether the error is MaxTimeMSExpired.
214
- #
215
- # @return [ true | false ] Whether the error is MaxTimeMSExpired.
216
- #
217
- # @since 2.10.0
218
- def max_time_ms_expired?
219
- code == 50 # MaxTimeMSExpired
220
- end
204
+ # Whether the error is a write concern timeout.
205
+ #
206
+ # @return [ true | false ] Whether the error is a write concern timeout.
207
+ #
208
+ # @since 2.7.1
209
+ def wtimeout?
210
+ @wtimeout
211
+ end
221
212
 
222
- # Whether the error is caused by an attempted retryable write
223
- # on a storage engine that does not support retryable writes.
224
- #
225
- # @return [ true | false ] Whether the error is caused by an attempted
226
- # retryable write on a storage engine that does not support retryable writes.
227
- #
228
- # @since 2.10.0
229
- def unsupported_retryable_write?
230
- # code 20 is IllegalOperation.
231
- # Note that the document is expected to be a BSON::Document, thus
232
- # either having string keys or providing indifferent access.
233
- code == 20 && server_message&.start_with?("Transaction numbers") || false
234
- end
213
+ # Whether the error is MaxTimeMSExpired.
214
+ #
215
+ # @return [ true | false ] Whether the error is MaxTimeMSExpired.
216
+ #
217
+ # @since 2.10.0
218
+ def max_time_ms_expired?
219
+ code == 50 # MaxTimeMSExpired
220
+ end
221
+
222
+ # Whether the error is caused by an attempted retryable write
223
+ # on a storage engine that does not support retryable writes.
224
+ #
225
+ # @return [ true | false ] Whether the error is caused by an attempted
226
+ # retryable write on a storage engine that does not support retryable writes.
227
+ #
228
+ # @since 2.10.0
229
+ def unsupported_retryable_write?
230
+ # code 20 is IllegalOperation.
231
+ # Note that the document is expected to be a BSON::Document, thus
232
+ # either having string keys or providing indifferent access.
233
+ code == 20 && server_message&.start_with?("Transaction numbers") || false
234
+ end
235
235
 
236
- private
236
+ private
237
237
 
238
- # Retrieve the details from a document
239
- #
240
- # @return [ Hash | nil ] the details extracted from the document
241
- def retrieve_details(document)
242
- return nil unless document
243
- if wce = document['writeConcernError']
244
- return wce['errInfo']
245
- elsif we = document['writeErrors']&.first
246
- return we['errInfo']
238
+ # Retrieve the details from a document
239
+ #
240
+ # @return [ Hash | nil ] the details extracted from the document
241
+ def retrieve_details(document)
242
+ return nil unless document
243
+ if wce = document['writeConcernError']
244
+ return wce['errInfo']
245
+ elsif we = document['writeErrors']&.first
246
+ return we['errInfo']
247
+ end
247
248
  end
248
- end
249
249
 
250
- # Append the details to the message
251
- #
252
- # @return [ String ] the message with the details appended to it
253
- def append_details(message, details)
254
- return message unless details && message
255
- message + " -- #{details.to_json}"
250
+ # Append the details to the message
251
+ #
252
+ # @return [ String ] the message with the details appended to it
253
+ def append_details(message, details)
254
+ return message unless details && message
255
+ message + " -- #{details.to_json}"
256
+ end
256
257
  end
258
+
259
+ # OperationFailure is the canonical implementor of the
260
+ # OperationFailure::Family concern.
261
+ include OperationFailure::Family
257
262
  end
258
263
  end
259
264
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mongo/error/timeout_error'
4
+
5
+ module Mongo
6
+ class Error
7
+ # Raised when the server returns error code 50.
8
+ class ServerTimeoutError < TimeoutError
9
+ include OperationFailure::Family
10
+ end
11
+ end
12
+ end
@@ -15,13 +15,15 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
+ require 'mongo/error/timeout_error'
19
+
18
20
  module Mongo
19
21
  class Error
20
22
 
21
23
  # Raised when a socket connection times out.
22
24
  #
23
25
  # @since 2.0.0
24
- class SocketTimeoutError < Error
26
+ class SocketTimeoutError < TimeoutError
25
27
  include WriteRetryable
26
28
  include ChangeStreamResumable
27
29
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2015-present 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 Error
19
+ # Raised when a Client Side Operation Timeout times out.
20
+ class TimeoutError < Error
21
+ end
22
+ end
23
+ end
data/lib/mongo/error.rb CHANGED
@@ -217,7 +217,9 @@ require 'mongo/error/missing_service_id'
217
217
  require 'mongo/error/server_api_conflict'
218
218
  require 'mongo/error/server_api_not_supported'
219
219
  require 'mongo/error/server_not_usable'
220
+ require 'mongo/error/server_timeout_error'
220
221
  require 'mongo/error/transactions_not_supported'
222
+ require 'mongo/error/timeout_error'
221
223
  require 'mongo/error/unknown_payload_type'
222
224
  require 'mongo/error/unmet_dependency'
223
225
  require 'mongo/error/unsupported_option'
@@ -201,8 +201,8 @@ module Mongo
201
201
  # @return [ Result ] The result of the remove.
202
202
  #
203
203
  # @since 2.0.0
204
- def delete_one(file)
205
- delete(file.id)
204
+ def delete_one(file, opts = {})
205
+ delete(file.id, opts)
206
206
  end
207
207
 
208
208
  # Remove a single file, identified by its id from the GridFS.
@@ -217,9 +217,14 @@ module Mongo
217
217
  # @raise [ Error::FileNotFound ] If the file is not found.
218
218
  #
219
219
  # @since 2.1.0
220
- def delete(id)
221
- result = files_collection.find({ :_id => id }, @options).delete_one
222
- chunks_collection.find({ :files_id => id }, @options).delete_many
220
+ def delete(id, opts = {})
221
+ timeout_holder = CsotTimeoutHolder.new(operation_timeouts: operation_timeouts(opts))
222
+ result = files_collection
223
+ .find({ :_id => id }, @options.merge(timeout_ms: timeout_holder.remaining_timeout_ms))
224
+ .delete_one(timeout_ms: timeout_holder.remaining_timeout_ms)
225
+ chunks_collection
226
+ .find({ :files_id => id }, @options.merge(timeout_ms: timeout_holder.remaining_timeout_ms))
227
+ .delete_many(timeout_ms: timeout_holder.remaining_timeout_ms)
223
228
  raise Error::FileNotFound.new(id, :id) if result.n == 0
224
229
  result
225
230
  end
@@ -485,9 +490,10 @@ module Mongo
485
490
  end
486
491
 
487
492
  # Drop the collections that implement this bucket.
488
- def drop
489
- files_collection.drop
490
- chunks_collection.drop
493
+ def drop(opts = {})
494
+ context = Operation::Context.new(operation_timeouts: operation_timeouts(opts))
495
+ files_collection.drop(timeout_ms: context.remaining_timeout_ms)
496
+ chunks_collection.drop(timeout_ms: context.remaining_timeout_ms)
491
497
  end
492
498
 
493
499
  private
@@ -512,12 +518,24 @@ module Mongo
512
518
  "#{prefix}.#{Grid::File::Info::COLLECTION}"
513
519
  end
514
520
 
515
- def ensure_indexes!
516
- if files_collection.find({}, limit: 1, projection: { _id: 1 }).first.nil?
521
+ def ensure_indexes!(timeout_holder = nil)
522
+ fc_idx = files_collection.find(
523
+ {},
524
+ limit: 1,
525
+ projection: { _id: 1 },
526
+ timeout_ms: timeout_holder&.remaining_timeout_ms
527
+ ).first
528
+ if fc_idx.nil?
517
529
  create_index_if_missing!(files_collection, FSBucket::FILES_INDEX)
518
530
  end
519
531
 
520
- if chunks_collection.find({}, limit: 1, projection: { _id: 1 }).first.nil?
532
+ cc_idx = chunks_collection.find(
533
+ {},
534
+ limit: 1,
535
+ projection: { _id: 1 },
536
+ timeout_ms: timeout_holder&.remaining_timeout_ms
537
+ ).first
538
+ if cc_idx.nil?
521
539
  create_index_if_missing!(chunks_collection, FSBucket::CHUNKS_INDEX, :unique => true)
522
540
  end
523
541
  end
@@ -528,7 +546,7 @@ module Mongo
528
546
  if indexes_view.get(index_spec).nil?
529
547
  indexes_view.create_one(index_spec, options)
530
548
  end
531
- rescue Mongo::Error::OperationFailure => e
549
+ rescue Mongo::Error::OperationFailure::Family => e
532
550
  # proceed with index creation if a NamespaceNotFound error is thrown
533
551
  if e.code == 26
534
552
  indexes_view.create_one(index_spec, options)
@@ -537,6 +555,21 @@ module Mongo
537
555
  end
538
556
  end
539
557
  end
558
+
559
+ # @return [ Hash ] timeout_ms value set on the operation level (if any),
560
+ # and/or timeout_ms that is set on collection/database/client level (if any).
561
+ #
562
+ # @api private
563
+ def operation_timeouts(opts = {})
564
+ # TODO: We should re-evaluate if we need two timeouts separately.
565
+ {}.tap do |result|
566
+ if opts[:timeout_ms].nil?
567
+ result[:inherited_timeout_ms] = database.timeout_ms
568
+ else
569
+ result[:operation_timeout_ms] = opts[:timeout_ms]
570
+ end
571
+ end
572
+ end
540
573
  end
541
574
  end
542
575
  end
@@ -59,6 +59,12 @@ module Mongo
59
59
  @file_id = @options.delete(:file_id)
60
60
  @options.freeze
61
61
  @open = true
62
+ @timeout_holder = CsotTimeoutHolder.new(
63
+ operation_timeouts: {
64
+ operation_timeout_ms: options[:timeout_ms],
65
+ inherited_timeout_ms: fs.database.timeout_ms
66
+ }
67
+ )
62
68
  end
63
69
 
64
70
  # Iterate through chunk data streamed from the FSBucket.
@@ -178,7 +184,11 @@ module Mongo
178
184
  # @since 2.1.0
179
185
  def file_info
180
186
  @file_info ||= begin
181
- doc = options[:file_info_doc] || fs.files_collection.find(_id: file_id).first
187
+ doc = options[:file_info_doc] ||
188
+ fs.files_collection.find(
189
+ { _id: file_id },
190
+ { timeout_ms: @timeout_holder.remaining_timeout_ms! }
191
+ ).first
182
192
  if doc
183
193
  File::Info.new(Options::Mapper.transform(doc, File::Info::MAPPINGS.invert))
184
194
  else
@@ -209,6 +219,10 @@ module Mongo
209
219
  else
210
220
  options
211
221
  end
222
+ if @timeout_holder.csot?
223
+ opts[:timeout_ms] = @timeout_holder.remaining_timeout_ms!
224
+ opts[:timeout_mode] = :cursor_lifetime
225
+ end
212
226
 
213
227
  fs.chunks_collection.find({ :files_id => file_id }, opts).sort(:n => 1)
214
228
  end