mongo 2.20.1 → 2.21.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 (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
@@ -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/cursor_host'
19
+
18
20
  module Mongo
19
21
  class Collection
20
22
  class View
@@ -24,13 +26,7 @@ module Mongo
24
26
  #
25
27
  # @since 2.0.0
26
28
  module Iterable
27
-
28
- # Returns the cursor associated with this view, if any.
29
- #
30
- # @return [ nil | Cursor ] The cursor, if any.
31
- #
32
- # @api private
33
- attr_reader :cursor
29
+ include Mongo::CursorHost
34
30
 
35
31
  # Iterate through documents returned by a query with this +View+.
36
32
  #
@@ -45,48 +41,21 @@ module Mongo
45
41
  #
46
42
  # @yieldparam [ Hash ] Each matching document.
47
43
  def each
48
- # If the caching cursor is closed and was not fully iterated,
49
- # the documents we have in it are not the complete result set and
50
- # we have no way of completing that iteration.
51
- # Therefore, discard that cursor and start iteration again.
52
- # The case of the caching cursor not being closed and not having
53
- # been fully iterated isn't tested - see RUBY-2773.
54
- @cursor = if use_query_cache? && cached_cursor && (
55
- cached_cursor.fully_iterated? || !cached_cursor.closed?
56
- )
57
- cached_cursor
58
- else
59
- session = client.send(:get_session, @options)
60
- select_cursor(session).tap do |cursor|
61
- if use_query_cache?
62
- # No need to store the cursor in the query cache if there is
63
- # already a cached cursor stored at this key.
64
- QueryCache.set(cursor, **cache_options)
65
- end
66
- end
67
- end
44
+ @cursor = prefer_cached_cursor? ? cached_cursor : new_cursor_for_iteration
45
+ return @cursor.to_enum unless block_given?
68
46
 
69
- if use_query_cache?
70
- # If a query with a limit is performed, the query cache will
71
- # re-use results from an earlier query with the same or larger
72
- # limit, and then impose the lower limit during iteration.
73
- limit_for_cached_query = respond_to?(:limit) ? QueryCache.normalized_limit(limit) : nil
74
- end
47
+ limit_for_cached_query = compute_limit_for_cached_query
75
48
 
76
- if block_given?
77
- # Ruby versions 2.5 and older do not support arr[0..nil] syntax, so
78
- # this must be a separate conditional.
79
- cursor_to_iterate = if limit_for_cached_query
80
- @cursor.to_a[0...limit_for_cached_query]
81
- else
82
- @cursor
83
- end
84
-
85
- cursor_to_iterate.each do |doc|
86
- yield doc
87
- end
49
+ # Ruby versions 2.5 and older do not support arr[0..nil] syntax, so
50
+ # this must be a separate conditional.
51
+ cursor_to_iterate = if limit_for_cached_query
52
+ @cursor.to_a[0...limit_for_cached_query]
88
53
  else
89
- @cursor.to_enum
54
+ @cursor
55
+ end
56
+
57
+ cursor_to_iterate.each do |doc|
58
+ yield doc
90
59
  end
91
60
  end
92
61
 
@@ -100,7 +69,7 @@ module Mongo
100
69
  #
101
70
  # @return [ nil ] Always nil.
102
71
  #
103
- # @raise [ Error::OperationFailure ] If the server cursor close fails.
72
+ # @raise [ Error::OperationFailure::Family ] If the server cursor close fails.
104
73
  #
105
74
  # @since 2.1.0
106
75
  def close_query
@@ -113,18 +82,25 @@ module Mongo
113
82
  private
114
83
 
115
84
  def select_cursor(session)
85
+ context = Operation::Context.new(
86
+ client: client,
87
+ session: session,
88
+ operation_timeouts: operation_timeouts,
89
+ view: self
90
+ )
91
+
116
92
  if respond_to?(:write?, true) && write?
117
93
  server = server_selector.select_server(cluster, nil, session, write_aggregation: true)
118
- result = send_initial_query(server, session)
94
+ result = send_initial_query(server, context)
119
95
 
120
96
  if use_query_cache?
121
- CachingCursor.new(view, result, server, session: session)
97
+ CachingCursor.new(view, result, server, session: session, context: context)
122
98
  else
123
- Cursor.new(view, result, server, session: session)
99
+ Cursor.new(view, result, server, session: session, context: context)
124
100
  end
125
101
  else
126
- read_with_retry_cursor(session, server_selector, view) do |server|
127
- send_initial_query(server, session)
102
+ read_with_retry_cursor(session, server_selector, view, context: context) do |server|
103
+ send_initial_query(server, context)
128
104
  end
129
105
  end
130
106
  end
@@ -168,18 +144,13 @@ module Mongo
168
144
  batch_size: batch_size,
169
145
  hint: options[:hint],
170
146
  max_scan: options[:max_scan],
171
- max_time_ms: options[:max_time_ms],
172
147
  max_value: options[:max_value],
173
148
  min_value: options[:min_value],
174
149
  no_cursor_timeout: options[:no_cursor_timeout],
175
150
  return_key: options[:return_key],
176
151
  show_disk_loc: options[:show_disk_loc],
177
152
  comment: options[:comment],
178
- oplog_replay: if (v = options[:oplog_replay]).nil?
179
- collection.options[:oplog_replay]
180
- else
181
- v
182
- end,
153
+ oplog_replay: oplog_replay
183
154
  }
184
155
 
185
156
  if spec[:oplog_replay]
@@ -196,14 +167,52 @@ module Mongo
196
167
  end
197
168
  end
198
169
 
199
- def send_initial_query(server, session = nil)
200
- initial_query_op(session).execute(server, context: Operation::Context.new(client: client, session: session))
170
+ def send_initial_query(server, context)
171
+ operation = initial_query_op(context.session)
172
+ if server.load_balancer?
173
+ # Connection will be checked in when cursor is drained.
174
+ connection = server.pool.check_out(context: context)
175
+ operation.execute_with_connection(connection, context: context)
176
+ else
177
+ operation.execute(server, context: context)
178
+ end
201
179
  end
202
180
 
203
181
  def use_query_cache?
204
182
  QueryCache.enabled? && !collection.system_collection?
205
183
  end
206
184
 
185
+ # If the caching cursor is closed and was not fully iterated,
186
+ # the documents we have in it are not the complete result set and
187
+ # we have no way of completing that iteration.
188
+ # Therefore, discard that cursor and start iteration again.
189
+ def prefer_cached_cursor?
190
+ use_query_cache? &&
191
+ cached_cursor &&
192
+ (cached_cursor.fully_iterated? || !cached_cursor.closed?)
193
+ end
194
+
195
+ # Start a new cursor for use when iterating (via #each).
196
+ def new_cursor_for_iteration
197
+ session = client.get_session(@options)
198
+ select_cursor(session).tap do |cursor|
199
+ if use_query_cache?
200
+ # No need to store the cursor in the query cache if there is
201
+ # already a cached cursor stored at this key.
202
+ QueryCache.set(cursor, **cache_options)
203
+ end
204
+ end
205
+ end
206
+
207
+ def compute_limit_for_cached_query
208
+ return nil unless use_query_cache? && respond_to?(:limit)
209
+
210
+ # If a query with a limit is performed, the query cache will
211
+ # re-use results from an earlier query with the same or larger
212
+ # limit, and then impose the lower limit during iteration.
213
+ return QueryCache.normalized_limit(limit)
214
+ end
215
+
207
216
  # Add tailable cusror options to the command specifiction if needed.
208
217
  #
209
218
  # @param [ Hash ] spec The command specification.
@@ -216,6 +225,13 @@ module Mongo
216
225
  spec[:await_data] = true
217
226
  end
218
227
  end
228
+
229
+ # @return [ true | false | nil ] options[:oplog_replay], if
230
+ # set, otherwise the same option from the collection.
231
+ def oplog_replay
232
+ v = options[:oplog_replay]
233
+ v.nil? ? collection.options[:oplog_replay] : v
234
+ end
219
235
  end
220
236
  end
221
237
  end
@@ -51,7 +51,7 @@ module Mongo
51
51
  attr_reader :reduce_function
52
52
 
53
53
  # Delegate necessary operations to the view.
54
- def_delegators :view, :collection, :read, :cluster
54
+ def_delegators :view, :collection, :read, :cluster, :timeout_ms
55
55
 
56
56
  # Delegate necessary operations to the collection.
57
57
  def_delegators :collection, :database, :client
@@ -70,10 +70,18 @@ module Mongo
70
70
  # @yieldparam [ Hash ] Each matching document.
71
71
  def each
72
72
  @cursor = nil
73
- session = client.send(:get_session, @options)
73
+ session = client.get_session(@options)
74
74
  server = cluster.next_primary(nil, session)
75
- result = send_initial_query(server, session, context: Operation::Context.new(client: client, session: session))
76
- result = send_fetch_query(server, session) unless inline?
75
+ context = Operation::Context.new(client: client, session: session, operation_timeouts: view.operation_timeouts)
76
+ if server.load_balancer?
77
+ # Connection will be checked in when cursor is drained.
78
+ connection = server.pool.check_out(context: context)
79
+ result = send_initial_query_with_connection(connection, context.session, context: context)
80
+ result = send_fetch_query_with_connection(connection, session) unless inline?
81
+ else
82
+ result = send_initial_query(server, context)
83
+ result = send_fetch_query(server, session) unless inline?
84
+ end
77
85
  @cursor = Cursor.new(view, result, server, session: session)
78
86
  if block_given?
79
87
  @cursor.each do |doc|
@@ -279,9 +287,9 @@ module Mongo
279
287
  out.respond_to?(:keys) && out.keys.first.to_s.downcase == INLINE
280
288
  end
281
289
 
282
- def send_initial_query(server, session, context:)
290
+ def send_initial_query(server, context)
283
291
  server.with_connection do |connection|
284
- send_initial_query_with_connection(connection, session, context: context)
292
+ send_initial_query_with_connection(connection, context.session, context: context)
285
293
  end
286
294
  end
287
295
 
@@ -305,7 +313,7 @@ module Mongo
305
313
  Builder::MapReduce.new(map_function, reduce_function, view, options.merge(session: session)).command_specification
306
314
  end
307
315
 
308
- def fetch_query_op(server, session)
316
+ def fetch_query_op(session)
309
317
  spec = {
310
318
  coll_name: out_collection_name,
311
319
  db_name: out_database_name,
@@ -319,7 +327,16 @@ module Mongo
319
327
  end
320
328
 
321
329
  def send_fetch_query(server, session)
322
- fetch_query_op(server, session).execute(server, context: Operation::Context.new(client: client, session: session))
330
+ fetch_query_op(session).execute(server, context: Operation::Context.new(client: client, session: session))
331
+ end
332
+
333
+ def send_fetch_query_with_connection(connection, session)
334
+ fetch_query_op(
335
+ session
336
+ ).execute_with_connection(
337
+ connection,
338
+ context: Operation::Context.new(client: client, session: session)
339
+ )
323
340
  end
324
341
  end
325
342
  end
@@ -47,12 +47,13 @@ module Mongo
47
47
  # @option options [ Hash ] :let Mapping of variables to use in the pipeline.
48
48
  # See the server documentation for details.
49
49
  # @option options [ Integer ] :max_time_ms The maximum amount of time in
50
- # milliseconds to allow the aggregation to run.
51
- # @option options [ true, false ] :use_cursor Indicates whether the command
52
- # will request that the server provide results using a cursor. Note that
53
- # as of server version 3.6, aggregations always provide results using a
54
- # cursor and this option is therefore not valid.
50
+ # milliseconds to allow the aggregation to run. This option is deprecated, use
51
+ # :timeout_ms instead.
55
52
  # @option options [ Session ] :session The session to use.
53
+ # @option options [ Integer ] :timeout_ms The operation timeout in milliseconds.
54
+ # Must be a non-negative integer. An explicit value of 0 means infinite.
55
+ # The default value is unset which means the value is inherited from
56
+ # the collection or the database or the client.
56
57
  #
57
58
  # @return [ Aggregation ] The aggregation object.
58
59
  #
@@ -157,6 +158,10 @@ module Mongo
157
158
  # @option opts [ Mongo::Session ] :session The session to use for the operation.
158
159
  # @option opts [ Object ] :comment A user-provided
159
160
  # comment to attach to this command.
161
+ # @option options [ Integer ] :timeout_ms The operation timeout in milliseconds.
162
+ # Must be a non-negative integer. An explicit value of 0 means infinite.
163
+ # The default value is unset which means the value is inherited from
164
+ # the collection or the database or the client.
160
165
  #
161
166
  # @return [ Integer ] The document count.
162
167
  #
@@ -182,7 +187,12 @@ module Mongo
182
187
  read_pref = opts[:read] || read_preference
183
188
  selector = ServerSelector.get(read_pref || server_selector)
184
189
  with_session(opts) do |session|
185
- read_with_retry(session, selector) do |server|
190
+ context = Operation::Context.new(
191
+ client: client,
192
+ session: session,
193
+ operation_timeouts: operation_timeouts(opts)
194
+ )
195
+ read_with_retry(session, selector, context) do |server|
186
196
  Operation::Count.new(
187
197
  selector: cmd,
188
198
  db_name: database.name,
@@ -193,7 +203,10 @@ module Mongo
193
203
  # string key. Note that this isn't documented as valid usage.
194
204
  collation: opts[:collation] || opts['collation'] || collation,
195
205
  comment: opts[:comment],
196
- ).execute(server, context: Operation::Context.new(client: client, session: session))
206
+ ).execute(
207
+ server,
208
+ context: context
209
+ )
197
210
  end.n.to_i
198
211
  end
199
212
  end
@@ -210,12 +223,17 @@ module Mongo
210
223
  # MongoDB to use a specific index for the query. Requires server version 3.6+.
211
224
  # @option opts :limit [ Integer ] Max number of docs to count.
212
225
  # @option opts :max_time_ms [ Integer ] The maximum amount of time to allow the
213
- # command to run.
226
+ # command to run. This option is deprecated, use
227
+ # :timeout_ms instead.
214
228
  # @option opts [ Hash ] :read The read preference options.
215
229
  # @option opts [ Hash ] :collation The collation to use.
216
230
  # @option opts [ Mongo::Session ] :session The session to use for the operation.
217
231
  # @option ops [ Object ] :comment A user-provided
218
232
  # comment to attach to this command.
233
+ # @option options [ Integer ] :timeout_ms The operation timeout in milliseconds.
234
+ # Must be a non-negative integer. An explicit value of 0 means infinite.
235
+ # The default value is unset which means the value is inherited from
236
+ # the collection or the database or the client.
219
237
  #
220
238
  # @return [ Integer ] The document count.
221
239
  #
@@ -227,7 +245,7 @@ module Mongo
227
245
  pipeline << { :'$limit' => opts[:limit] } if opts[:limit]
228
246
  pipeline << { :'$group' => { _id: 1, n: { :'$sum' => 1 } } }
229
247
 
230
- opts = opts.slice(:hint, :max_time_ms, :read, :collation, :session, :comment)
248
+ opts = opts.slice(:hint, :max_time_ms, :read, :collation, :session, :comment, :timeout_ms)
231
249
  opts[:collation] ||= collation
232
250
 
233
251
  first = aggregate(pipeline, opts).first
@@ -247,6 +265,10 @@ module Mongo
247
265
  # @option opts [ Hash ] :read The read preference options.
248
266
  # @option opts [ Object ] :comment A user-provided
249
267
  # comment to attach to this command.
268
+ # @option options [ Integer ] :timeout_ms The operation timeout in milliseconds.
269
+ # Must be a non-negative integer. An explicit value of 0 means infinite.
270
+ # The default value is unset which means the value is inherited from
271
+ # the collection or the database or the client.
250
272
  #
251
273
  # @return [ Integer ] The document count.
252
274
  #
@@ -267,8 +289,12 @@ module Mongo
267
289
  read_pref = opts[:read] || read_preference
268
290
  selector = ServerSelector.get(read_pref || server_selector)
269
291
  with_session(opts) do |session|
270
- read_with_retry(session, selector) do |server|
271
- context = Operation::Context.new(client: client, session: session)
292
+ context = Operation::Context.new(
293
+ client: client,
294
+ session: session,
295
+ operation_timeouts: operation_timeouts(opts)
296
+ )
297
+ read_with_retry(session, selector, context) do |server|
272
298
  cmd = { count: collection.name }
273
299
  cmd[:maxTimeMS] = opts[:max_time_ms] if opts[:max_time_ms]
274
300
  if read_concern
@@ -284,7 +310,7 @@ module Mongo
284
310
  result.n.to_i
285
311
  end
286
312
  end
287
- rescue Error::OperationFailure => exc
313
+ rescue Error::OperationFailure::Family => exc
288
314
  if exc.code == 26
289
315
  # NamespaceNotFound
290
316
  # This should only happen with the aggregation pipeline path
@@ -331,7 +357,12 @@ module Mongo
331
357
  read_pref = opts[:read] || read_preference
332
358
  selector = ServerSelector.get(read_pref || server_selector)
333
359
  with_session(opts) do |session|
334
- read_with_retry(session, selector) do |server|
360
+ context = Operation::Context.new(
361
+ client: client,
362
+ session: session,
363
+ operation_timeouts: operation_timeouts(opts)
364
+ )
365
+ read_with_retry(session, selector, context) do |server|
335
366
  Operation::Distinct.new(
336
367
  selector: cmd,
337
368
  db_name: database.name,
@@ -342,7 +373,10 @@ module Mongo
342
373
  # For some reason collation was historically accepted as a
343
374
  # string key. Note that this isn't documented as valid usage.
344
375
  collation: opts[:collation] || opts['collation'] || collation,
345
- ).execute(server, context: Operation::Context.new(client: client, session: session))
376
+ ).execute(
377
+ server,
378
+ context: context
379
+ )
346
380
  end.first['values']
347
381
  end
348
382
  end
@@ -627,6 +661,15 @@ module Mongo
627
661
  configure(:cursor_type, type)
628
662
  end
629
663
 
664
+ # The per-operation timeout in milliseconds. Must a positive integer.
665
+ #
666
+ # @param [ Integer ] timeout_ms Timeout value.
667
+ #
668
+ # @return [ Integer, View ] Either the timeout_ms value or a new +View+.
669
+ def timeout_ms(timeout_ms = nil)
670
+ configure(:timeout_ms, timeout_ms)
671
+ end
672
+
630
673
  # @api private
631
674
  def read_concern
632
675
  if options[:session] && options[:session].in_transaction?
@@ -656,24 +699,10 @@ module Mongo
656
699
  end
657
700
  end
658
701
 
659
- private
660
-
661
- def collation(doc = nil)
662
- configure(:collation, doc)
663
- end
664
-
665
- def server_selector
666
- @server_selector ||= if options[:session] && options[:session].in_transaction?
667
- ServerSelector.get(read_preference || client.server_selector)
668
- else
669
- ServerSelector.get(read_preference || collection.server_selector)
670
- end
671
- end
672
-
673
702
  def parallel_scan(cursor_count, options = {})
674
703
  if options[:session]
675
704
  # The session would be overwritten by the one in +options+ later.
676
- session = client.send(:get_session, @options)
705
+ session = client.get_session(@options)
677
706
  else
678
707
  session = nil
679
708
  end
@@ -707,11 +736,31 @@ module Mongo
707
736
  session: session,
708
737
  connection_global_id: result.connection_global_id,
709
738
  )
710
- result = op.execute(server, context: context)
739
+ result = if server.load_balancer?
740
+ # Connection will be checked in when cursor is drained.
741
+ connection = server.pool.check_out(context: context)
742
+ op.execute_with_connection(connection, context: context)
743
+ else
744
+ op.execute(server, context: context)
745
+ end
711
746
  Cursor.new(self, result, server, session: session)
712
747
  end
713
748
  end
714
749
 
750
+ private
751
+
752
+ def collation(doc = nil)
753
+ configure(:collation, doc)
754
+ end
755
+
756
+ def server_selector
757
+ @server_selector ||= if options[:session] && options[:session].in_transaction?
758
+ ServerSelector.get(read_preference || client.server_selector)
759
+ else
760
+ ServerSelector.get(read_preference || collection.server_selector)
761
+ end
762
+ end
763
+
715
764
  def validate_doc!(doc)
716
765
  raise Error::InvalidDocument.new unless doc.respond_to?(:keys)
717
766
  end