mongo 2.8.0 → 2.9.0.rc0

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 (276) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +12 -0
  5. data/lib/mongo.rb +15 -1
  6. data/lib/mongo/address/ipv6.rb +0 -2
  7. data/lib/mongo/auth/scram/conversation.rb +0 -3
  8. data/lib/mongo/bulk_write/result_combiner.rb +12 -2
  9. data/lib/mongo/client.rb +59 -6
  10. data/lib/mongo/cluster.rb +19 -8
  11. data/lib/mongo/cluster/reapers/cursor_reaper.rb +0 -2
  12. data/lib/mongo/cluster/reapers/socket_reaper.rb +12 -9
  13. data/lib/mongo/collection.rb +1 -1
  14. data/lib/mongo/collection/view/aggregation.rb +5 -1
  15. data/lib/mongo/collection/view/builder/map_reduce.rb +1 -1
  16. data/lib/mongo/collection/view/change_stream.rb +30 -10
  17. data/lib/mongo/collection/view/iterable.rb +13 -6
  18. data/lib/mongo/collection/view/map_reduce.rb +12 -10
  19. data/lib/mongo/collection/view/readable.rb +19 -14
  20. data/lib/mongo/cursor.rb +12 -8
  21. data/lib/mongo/database.rb +10 -7
  22. data/lib/mongo/database/view.rb +18 -11
  23. data/lib/mongo/error.rb +2 -2
  24. data/lib/mongo/error/connection_check_out_timeout.rb +49 -0
  25. data/lib/mongo/error/operation_failure.rb +9 -9
  26. data/lib/mongo/error/parser.rb +25 -3
  27. data/lib/mongo/error/pool_closed_error.rb +43 -0
  28. data/lib/mongo/error/sdam_error_detection.rb +18 -0
  29. data/lib/mongo/grid/file/chunk.rb +0 -2
  30. data/lib/mongo/grid/fs_bucket.rb +26 -12
  31. data/lib/mongo/grid/stream/read.rb +36 -21
  32. data/lib/mongo/index/view.rb +11 -7
  33. data/lib/mongo/logger.rb +0 -2
  34. data/lib/mongo/monitoring.rb +31 -0
  35. data/lib/mongo/monitoring/cmap_log_subscriber.rb +53 -0
  36. data/lib/mongo/monitoring/event.rb +1 -0
  37. data/lib/mongo/monitoring/event/cmap.rb +25 -0
  38. data/lib/mongo/monitoring/event/cmap/base.rb +28 -0
  39. data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +78 -0
  40. data/lib/mongo/monitoring/event/cmap/connection_check_out_started.rb +56 -0
  41. data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +63 -0
  42. data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +64 -0
  43. data/lib/mongo/monitoring/event/cmap/connection_closed.rb +103 -0
  44. data/lib/mongo/monitoring/event/cmap/connection_created.rb +64 -0
  45. data/lib/mongo/monitoring/event/cmap/connection_ready.rb +64 -0
  46. data/lib/mongo/monitoring/event/cmap/pool_cleared.rb +57 -0
  47. data/lib/mongo/monitoring/event/cmap/pool_closed.rb +57 -0
  48. data/lib/mongo/monitoring/event/cmap/pool_created.rb +63 -0
  49. data/lib/mongo/monitoring/event/command_started.rb +12 -3
  50. data/lib/mongo/monitoring/publishable.rb +10 -2
  51. data/lib/mongo/operation.rb +0 -1
  52. data/lib/mongo/operation/find/legacy/result.rb +1 -0
  53. data/lib/mongo/operation/list_collections/result.rb +7 -1
  54. data/lib/mongo/operation/result.rb +10 -1
  55. data/lib/mongo/operation/shared/executable.rb +15 -0
  56. data/lib/mongo/operation/shared/result/use_legacy_error_parser.rb +29 -0
  57. data/lib/mongo/operation/shared/specifiable.rb +0 -16
  58. data/lib/mongo/operation/update/legacy/result.rb +1 -0
  59. data/lib/mongo/protocol/compressed.rb +0 -2
  60. data/lib/mongo/protocol/msg.rb +25 -2
  61. data/lib/mongo/retryable.rb +171 -33
  62. data/lib/mongo/server.rb +26 -7
  63. data/lib/mongo/server/app_metadata.rb +0 -2
  64. data/lib/mongo/server/connectable.rb +8 -2
  65. data/lib/mongo/server/connection.rb +83 -13
  66. data/lib/mongo/server/connection_base.rb +1 -1
  67. data/lib/mongo/server/connection_pool.rb +439 -43
  68. data/lib/mongo/server/monitor/connection.rb +4 -1
  69. data/lib/mongo/session.rb +37 -5
  70. data/lib/mongo/session/session_pool.rb +2 -2
  71. data/lib/mongo/socket.rb +0 -2
  72. data/lib/mongo/socket/ssl.rb +0 -2
  73. data/lib/mongo/uri.rb +127 -66
  74. data/lib/mongo/uri/srv_protocol.rb +35 -13
  75. data/lib/mongo/version.rb +1 -1
  76. data/spec/README.md +190 -63
  77. data/spec/integration/change_stream_spec.rb +64 -0
  78. data/spec/integration/command_spec.rb +0 -7
  79. data/spec/integration/error_detection_spec.rb +39 -0
  80. data/spec/integration/read_concern.rb +83 -0
  81. data/spec/integration/retryable_writes_spec.rb +6 -50
  82. data/spec/integration/sdam_error_handling_spec.rb +60 -7
  83. data/spec/integration/ssl_uri_options_spec.rb +24 -0
  84. data/spec/integration/step_down_spec.rb +197 -0
  85. data/spec/lite_spec_helper.rb +4 -0
  86. data/spec/mongo/client_construction_spec.rb +42 -17
  87. data/spec/mongo/client_spec.rb +32 -1
  88. data/spec/mongo/cluster/socket_reaper_spec.rb +2 -2
  89. data/spec/mongo/cluster_spec.rb +36 -2
  90. data/spec/mongo/collection/view/aggregation_spec.rb +2 -0
  91. data/spec/mongo/collection/view/change_stream_spec.rb +28 -28
  92. data/spec/mongo/collection/view/readable_spec.rb +1 -1
  93. data/spec/mongo/collection/view_spec.rb +3 -1
  94. data/spec/mongo/cursor_spec.rb +5 -5
  95. data/spec/mongo/error/parser_spec.rb +61 -1
  96. data/spec/mongo/grid/stream/read_spec.rb +2 -2
  97. data/spec/mongo/monitoring/event/cmap/connection_check_out_failed_spec.rb +23 -0
  98. data/spec/mongo/monitoring/event/cmap/connection_check_out_started_spec.rb +19 -0
  99. data/spec/mongo/monitoring/event/cmap/connection_checked_in_spec.rb +23 -0
  100. data/spec/mongo/monitoring/event/cmap/connection_checked_out_spec.rb +23 -0
  101. data/spec/mongo/monitoring/event/cmap/connection_closed_spec.rb +27 -0
  102. data/spec/mongo/monitoring/event/cmap/connection_created_spec.rb +24 -0
  103. data/spec/mongo/monitoring/event/cmap/connection_ready_spec.rb +24 -0
  104. data/spec/mongo/monitoring/event/cmap/pool_cleared_spec.rb +19 -0
  105. data/spec/mongo/monitoring/event/cmap/pool_closed_spec.rb +19 -0
  106. data/spec/mongo/monitoring/event/cmap/pool_created_spec.rb +26 -0
  107. data/spec/mongo/operation/delete/bulk_spec.rb +1 -6
  108. data/spec/mongo/operation/delete/command_spec.rb +1 -1
  109. data/spec/mongo/operation/delete/op_msg_spec.rb +1 -1
  110. data/spec/mongo/operation/delete_spec.rb +4 -4
  111. data/spec/mongo/operation/insert/bulk_spec.rb +1 -1
  112. data/spec/mongo/operation/insert/command_spec.rb +1 -1
  113. data/spec/mongo/operation/insert/op_msg_spec.rb +1 -1
  114. data/spec/mongo/operation/update/bulk_spec.rb +1 -1
  115. data/spec/mongo/operation/update/command_spec.rb +2 -2
  116. data/spec/mongo/operation/update/op_msg_spec.rb +2 -2
  117. data/spec/mongo/protocol/msg_spec.rb +11 -0
  118. data/spec/mongo/retryable_spec.rb +78 -25
  119. data/spec/mongo/server/connection_pool_spec.rb +661 -126
  120. data/spec/mongo/server/connection_spec.rb +55 -7
  121. data/spec/mongo/server_spec.rb +5 -0
  122. data/spec/mongo/uri/srv_protocol_spec.rb +135 -2
  123. data/spec/mongo/uri_option_parsing_spec.rb +511 -0
  124. data/spec/mongo/uri_spec.rb +42 -6
  125. data/spec/spec_helper.rb +1 -84
  126. data/spec/spec_tests/cmap_spec.rb +50 -0
  127. data/spec/spec_tests/command_monitoring_spec.rb +7 -18
  128. data/spec/spec_tests/crud_spec.rb +3 -49
  129. data/spec/spec_tests/data/cmap/connection-must-have-id.yml +21 -0
  130. data/spec/spec_tests/data/cmap/connection-must-order-ids.yml +21 -0
  131. data/spec/spec_tests/data/cmap/pool-checkin-destroy-closed.yml +24 -0
  132. data/spec/spec_tests/data/cmap/pool-checkin-destroy-stale.yml +24 -0
  133. data/spec/spec_tests/data/cmap/pool-checkin-make-available.yml +21 -0
  134. data/spec/spec_tests/data/cmap/pool-checkin.yml +18 -0
  135. data/spec/spec_tests/data/cmap/pool-checkout-connection.yml +13 -0
  136. data/spec/spec_tests/data/cmap/pool-checkout-error-closed.yml +28 -0
  137. data/spec/spec_tests/data/cmap/pool-checkout-multiple.yml +34 -0
  138. data/spec/spec_tests/data/cmap/pool-checkout-no-idle.yml +31 -0
  139. data/spec/spec_tests/data/cmap/pool-checkout-no-stale.yml +29 -0
  140. data/spec/spec_tests/data/cmap/pool-close-destroy-conns.yml +26 -0
  141. data/spec/spec_tests/data/cmap/pool-close.yml +11 -0
  142. data/spec/spec_tests/data/cmap/pool-create-max-size.yml +56 -0
  143. data/spec/spec_tests/data/cmap/pool-create-min-size.yml +27 -0
  144. data/spec/spec_tests/data/cmap/pool-create-with-options.yml +20 -0
  145. data/spec/spec_tests/data/cmap/pool-create.yml +12 -0
  146. data/spec/spec_tests/data/cmap/wait-queue-fairness.yml +94 -0
  147. data/spec/spec_tests/data/cmap/wait-queue-timeout.yml +41 -0
  148. data/spec/spec_tests/data/retryable_reads/aggregate-serverErrors.yml +157 -0
  149. data/spec/spec_tests/data/retryable_reads/aggregate.yml +87 -0
  150. data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch-serverErrors.yml +149 -0
  151. data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch.yml +61 -0
  152. data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch-serverErrors.yml +149 -0
  153. data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch.yml +65 -0
  154. data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch-serverErrors.yml +153 -0
  155. data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch.yml +61 -0
  156. data/spec/spec_tests/data/retryable_reads/count-serverErrors.yml +150 -0
  157. data/spec/spec_tests/data/retryable_reads/count.yml +64 -0
  158. data/spec/spec_tests/data/retryable_reads/countDocuments-serverErrors.yml +150 -0
  159. data/spec/spec_tests/data/retryable_reads/countDocuments.yml +64 -0
  160. data/spec/spec_tests/data/retryable_reads/distinct-serverErrors.yml +156 -0
  161. data/spec/spec_tests/data/retryable_reads/distinct.yml +71 -0
  162. data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-serverErrors.yml +148 -0
  163. data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount.yml +62 -0
  164. data/spec/spec_tests/data/retryable_reads/find-serverErrors.yml +160 -0
  165. data/spec/spec_tests/data/retryable_reads/find.yml +86 -0
  166. data/spec/spec_tests/data/retryable_reads/findOne-serverErrors.yml +154 -0
  167. data/spec/spec_tests/data/retryable_reads/findOne.yml +68 -0
  168. data/spec/spec_tests/data/retryable_reads/gridfs-download-serverErrors.yml +173 -0
  169. data/spec/spec_tests/data/retryable_reads/gridfs-download.yml +79 -0
  170. data/spec/spec_tests/data/retryable_reads/gridfs-downloadByName-serverErrors.yml +174 -0
  171. data/spec/spec_tests/data/retryable_reads/gridfs-downloadByName.yml +79 -0
  172. data/spec/spec_tests/data/retryable_reads/listCollectionNames-serverErrors.yml +143 -0
  173. data/spec/spec_tests/data/retryable_reads/listCollectionNames.yml +59 -0
  174. data/spec/spec_tests/data/retryable_reads/listCollectionObjects-serverErrors.yml +144 -0
  175. data/spec/spec_tests/data/retryable_reads/listCollectionObjects.yml +59 -0
  176. data/spec/spec_tests/data/retryable_reads/listCollections-serverErrors.yml +143 -0
  177. data/spec/spec_tests/data/retryable_reads/listCollections.yml +59 -0
  178. data/spec/spec_tests/data/retryable_reads/listDatabaseNames-serverErrors.yml +143 -0
  179. data/spec/spec_tests/data/retryable_reads/listDatabaseNames.yml +59 -0
  180. data/spec/spec_tests/data/retryable_reads/listDatabaseObjects-serverErrors.yml +144 -0
  181. data/spec/spec_tests/data/retryable_reads/listDatabaseObjects.yml +59 -0
  182. data/spec/spec_tests/data/retryable_reads/listDatabases-serverErrors.yml +144 -0
  183. data/spec/spec_tests/data/retryable_reads/listDatabases.yml +59 -0
  184. data/spec/spec_tests/data/retryable_reads/listIndexNames-serverErrors.yml +144 -0
  185. data/spec/spec_tests/data/retryable_reads/listIndexNames.yml +60 -0
  186. data/spec/spec_tests/data/retryable_reads/listIndexes-serverErrors.yml +145 -0
  187. data/spec/spec_tests/data/retryable_reads/listIndexes.yml +60 -0
  188. data/spec/spec_tests/data/retryable_reads/mapReduce.yml +60 -0
  189. data/spec/spec_tests/data/retryable_writes/bulkWrite-serverErrors.yml +10 -7
  190. data/spec/spec_tests/data/retryable_writes/bulkWrite.yml +15 -22
  191. data/spec/spec_tests/data/retryable_writes/deleteMany.yml +22 -0
  192. data/spec/spec_tests/data/retryable_writes/deleteOne-serverErrors.yml +8 -7
  193. data/spec/spec_tests/data/retryable_writes/deleteOne.yml +5 -8
  194. data/spec/spec_tests/data/retryable_writes/findOneAndDelete-serverErrors.yml +8 -7
  195. data/spec/spec_tests/data/retryable_writes/findOneAndDelete.yml +5 -8
  196. data/spec/spec_tests/data/retryable_writes/findOneAndReplace-serverErrors.yml +8 -7
  197. data/spec/spec_tests/data/retryable_writes/findOneAndReplace.yml +5 -8
  198. data/spec/spec_tests/data/retryable_writes/findOneAndUpdate-serverErrors.yml +8 -7
  199. data/spec/spec_tests/data/retryable_writes/findOneAndUpdate.yml +5 -8
  200. data/spec/spec_tests/data/retryable_writes/insertMany-serverErrors.yml +8 -7
  201. data/spec/spec_tests/data/retryable_writes/insertMany.yml +5 -8
  202. data/spec/spec_tests/data/retryable_writes/insertOne-serverErrors.yml +10 -45
  203. data/spec/spec_tests/data/retryable_writes/insertOne.yml +5 -8
  204. data/spec/spec_tests/data/retryable_writes/replaceOne-serverErrors.yml +8 -7
  205. data/spec/spec_tests/data/retryable_writes/replaceOne.yml +5 -8
  206. data/spec/spec_tests/data/retryable_writes/updateMany.yml +27 -0
  207. data/spec/spec_tests/data/retryable_writes/updateOne-serverErrors.yml +8 -7
  208. data/spec/spec_tests/data/retryable_writes/updateOne.yml +5 -14
  209. data/spec/spec_tests/data/transactions/abort.yml +7 -2
  210. data/spec/spec_tests/data/transactions/bulk.yml +7 -2
  211. data/spec/spec_tests/data/transactions/causal-consistency.yml +11 -4
  212. data/spec/spec_tests/data/transactions/commit.yml +11 -4
  213. data/spec/spec_tests/data/transactions/count.yml +64 -0
  214. data/spec/spec_tests/data/transactions/delete.yml +7 -2
  215. data/spec/spec_tests/data/transactions/error-labels.yml +8 -2
  216. data/spec/spec_tests/data/transactions/errors.yml +7 -2
  217. data/spec/spec_tests/data/transactions/findOneAndDelete.yml +7 -2
  218. data/spec/spec_tests/data/transactions/findOneAndReplace.yml +7 -2
  219. data/spec/spec_tests/data/transactions/findOneAndUpdate.yml +7 -2
  220. data/spec/spec_tests/data/transactions/insert.yml +9 -2
  221. data/spec/spec_tests/data/transactions/isolation.yml +7 -2
  222. data/spec/spec_tests/data/transactions/read-concern.yml +15 -6
  223. data/spec/spec_tests/data/transactions/read-pref.yml +7 -2
  224. data/spec/spec_tests/data/transactions/reads.yml +8 -48
  225. data/spec/spec_tests/data/transactions/retryable-abort.yml +7 -2
  226. data/spec/spec_tests/data/transactions/retryable-commit.yml +7 -2
  227. data/spec/spec_tests/data/transactions/retryable-writes.yml +7 -2
  228. data/spec/spec_tests/data/transactions/run-command.yml +7 -2
  229. data/spec/spec_tests/data/transactions/transaction-options.yml +7 -2
  230. data/spec/spec_tests/data/transactions/update.yml +7 -2
  231. data/spec/spec_tests/data/transactions/write-concern.yml +7 -2
  232. data/spec/spec_tests/data/transactions_api/callback-aborts.yml +6 -1
  233. data/spec/spec_tests/data/transactions_api/callback-commits.yml +6 -1
  234. data/spec/spec_tests/data/transactions_api/callback-retry.yml +6 -1
  235. data/spec/spec_tests/data/transactions_api/commit-retry.yml +6 -1
  236. data/spec/spec_tests/data/transactions_api/commit-transienttransactionerror-4.2.yml +6 -3
  237. data/spec/spec_tests/data/transactions_api/commit-transienttransactionerror.yml +6 -1
  238. data/spec/spec_tests/data/transactions_api/commit-writeconcernerror.yml +6 -1
  239. data/spec/spec_tests/data/transactions_api/commit.yml +6 -1
  240. data/spec/spec_tests/data/transactions_api/transaction-options.yml +6 -1
  241. data/spec/spec_tests/retryable_reads_spec.rb +11 -0
  242. data/spec/spec_tests/retryable_writes_spec.rb +4 -69
  243. data/spec/spec_tests/transactions_api_spec.rb +42 -37
  244. data/spec/spec_tests/transactions_spec.rb +42 -33
  245. data/spec/support/authorization.rb +12 -0
  246. data/spec/support/change_streams/operation.rb +1 -1
  247. data/spec/support/client_registry.rb +20 -0
  248. data/spec/support/cluster_config.rb +16 -15
  249. data/spec/support/cluster_tools.rb +346 -0
  250. data/spec/support/cmap.rb +367 -0
  251. data/spec/support/cmap/verifier.rb +46 -0
  252. data/spec/support/command_monitoring.rb +4 -6
  253. data/spec/support/common_shortcuts.rb +6 -0
  254. data/spec/support/connection_string.rb +2 -2
  255. data/spec/support/crud.rb +171 -184
  256. data/spec/support/crud/operation.rb +43 -0
  257. data/spec/support/crud/outcome.rb +53 -0
  258. data/spec/support/crud/read.rb +102 -12
  259. data/spec/support/crud/requirement.rb +69 -0
  260. data/spec/support/crud/spec.rb +68 -0
  261. data/spec/support/crud/test.rb +141 -0
  262. data/spec/support/crud/verifier.rb +96 -18
  263. data/spec/support/crud/write.rb +18 -3
  264. data/spec/support/event_subscriber.rb +15 -0
  265. data/spec/support/primary_socket.rb +2 -2
  266. data/spec/support/spec_config.rb +89 -20
  267. data/spec/support/transactions.rb +2 -306
  268. data/spec/support/transactions/operation.rb +7 -7
  269. data/spec/support/transactions/spec.rb +28 -0
  270. data/spec/support/transactions/test.rb +191 -0
  271. data/spec/support/utils.rb +123 -0
  272. metadata +202 -9
  273. metadata.gz.sig +0 -0
  274. data/lib/mongo/server/connection_pool/queue.rb +0 -359
  275. data/spec/mongo/server/connection_pool/queue_spec.rb +0 -353
  276. data/spec/support/transactions/verifier.rb +0 -97
@@ -37,15 +37,22 @@ module Mongo
37
37
  def each
38
38
  @cursor = nil
39
39
  session = client.send(:get_session, @options)
40
- read_with_retry(session) do
40
+ @cursor = if respond_to?(:out?, true) && out?
41
41
  server = server_selector.select_server(cluster)
42
42
  result = send_initial_query(server, session)
43
- @cursor = Cursor.new(view, result, server, session: session)
43
+ Cursor.new(view, result, server, session: session)
44
+ else
45
+ read_with_retry_cursor(session, server_selector, view) do |server|
46
+ send_initial_query(server, session)
47
+ end
48
+ end
49
+ if block_given?
50
+ @cursor.each do |doc|
51
+ yield doc
52
+ end
53
+ else
54
+ @cursor.to_enum
44
55
  end
45
- @cursor.each do |doc|
46
- yield doc
47
- end if block_given?
48
- @cursor.to_enum
49
56
  end
50
57
 
51
58
  # Stop the iteration by sending a KillCursors command to the server.
@@ -67,15 +67,17 @@ module Mongo
67
67
  def each
68
68
  @cursor = nil
69
69
  session = client.send(:get_session, @options)
70
- legacy_write_with_retry do |server|
71
- result = send_initial_query(server, session)
72
- result = send_fetch_query(server, session) unless inline?
73
- @cursor = Cursor.new(view, result, server, session: session)
70
+ server = cluster.next_primary
71
+ result = send_initial_query(server, session)
72
+ result = send_fetch_query(server, session) unless inline?
73
+ @cursor = Cursor.new(view, result, server, session: session)
74
+ if block_given?
75
+ @cursor.each do |doc|
76
+ yield doc
77
+ end
78
+ else
79
+ @cursor.to_enum
74
80
  end
75
- @cursor.each do |doc|
76
- yield doc
77
- end if block_given?
78
- @cursor.to_enum
79
81
  end
80
82
 
81
83
  # Set or get the finalize function for the operation.
@@ -106,8 +108,8 @@ module Mongo
106
108
  # @since 2.0.0
107
109
  def initialize(view, map, reduce, options = {})
108
110
  @view = view
109
- @map_function = map.freeze
110
- @reduce_function = reduce.freeze
111
+ @map_function = map.dup.freeze
112
+ @reduce_function = reduce.dup.freeze
111
113
  @options = BSON::Document.new(options).freeze
112
114
  end
113
115
 
@@ -138,23 +138,22 @@ module Mongo
138
138
  cmd[:skip] = opts[:skip] if opts[:skip]
139
139
  cmd[:hint] = opts[:hint] if opts[:hint]
140
140
  cmd[:limit] = opts[:limit] if opts[:limit]
141
+ cmd[:readConcern] = read_concern if read_concern
141
142
  cmd[:maxTimeMS] = opts[:max_time_ms] if opts[:max_time_ms]
142
- cmd[:readConcern] = collection.read_concern if collection.read_concern
143
143
  Mongo::Lint.validate_underscore_read_preference(opts[:read])
144
144
  read_pref = opts[:read] || read_preference
145
145
  selector = ServerSelector.get(read_pref || server_selector)
146
146
  with_session(opts) do |session|
147
- read_with_retry(session) do
148
- server = selector.select_server(cluster)
147
+ read_with_retry(session, selector) do |server|
149
148
  apply_collation!(cmd, server, opts)
150
- Operation::Count.new({
149
+ Operation::Count.new(
151
150
  :selector => cmd,
152
151
  :db_name => database.name,
153
152
  :options => {:limit => -1},
154
153
  :read => read_pref,
155
154
  :session => session
156
- }).execute(server)
157
- end.n.to_i
155
+ ).execute(server)
156
+ end.n.to_i
158
157
  end
159
158
  end
160
159
 
@@ -181,7 +180,7 @@ module Mongo
181
180
  pipeline = [:'$match' => filter]
182
181
  pipeline << { :'$skip' => opts[:skip] } if opts[:skip]
183
182
  pipeline << { :'$limit' => opts[:limit] } if opts[:limit]
184
- pipeline << { :'$group' => { _id: nil, n: { :'$sum' => 1 } } }
183
+ pipeline << { :'$group' => { _id: 1, n: { :'$sum' => 1 } } }
185
184
 
186
185
  opts.select! { |k, _| [:hint, :max_time_ms, :read, :collation, :session].include?(k) }
187
186
  first = aggregate(pipeline, opts).first
@@ -206,13 +205,12 @@ module Mongo
206
205
  def estimated_document_count(opts = {})
207
206
  cmd = { count: collection.name }
208
207
  cmd[:maxTimeMS] = opts[:max_time_ms] if opts[:max_time_ms]
209
- cmd[:readConcern] = collection.read_concern if collection.read_concern
208
+ cmd[:readConcern] = read_concern if read_concern
210
209
  Mongo::Lint.validate_underscore_read_preference(opts[:read])
211
210
  read_pref = opts[:read] || read_preference
212
211
  selector = ServerSelector.get(read_pref || server_selector)
213
212
  with_session(opts) do |session|
214
- read_with_retry(session) do
215
- server = selector.select_server(cluster)
213
+ read_with_retry(session, selector) do |server|
216
214
  Operation::Count.new(
217
215
  selector: cmd,
218
216
  db_name: database.name,
@@ -244,13 +242,12 @@ module Mongo
244
242
  :key => field_name.to_s,
245
243
  :query => filter }
246
244
  cmd[:maxTimeMS] = opts[:max_time_ms] if opts[:max_time_ms]
247
- cmd[:readConcern] = collection.read_concern if collection.read_concern
245
+ cmd[:readConcern] = read_concern if read_concern
248
246
  Mongo::Lint.validate_underscore_read_preference(opts[:read])
249
247
  read_pref = opts[:read] || read_preference
250
248
  selector = ServerSelector.get(read_pref || server_selector)
251
249
  with_session(opts) do |session|
252
- read_with_retry(session) do
253
- server = selector.select_server(cluster)
250
+ read_with_retry(session, selector) do |server|
254
251
  apply_collation!(cmd, server, opts)
255
252
  Operation::Distinct.new({
256
253
  :selector => cmd,
@@ -542,6 +539,14 @@ module Mongo
542
539
  configure(:collation, doc)
543
540
  end
544
541
 
542
+ def read_concern
543
+ if options[:session] && options[:session].in_transaction?
544
+ options[:session].send(:txn_read_concern) || collection.client.read_concern
545
+ else
546
+ collection.read_concern
547
+ end
548
+ end
549
+
545
550
  def read_preference
546
551
  rp = if options[:session] && options[:session].in_transaction?
547
552
  options[:session].txn_read_preference || collection.client.read_preference
@@ -571,7 +576,7 @@ module Mongo
571
576
  :coll_name => collection.name,
572
577
  :db_name => database.name,
573
578
  :cursor_count => cursor_count,
574
- :read_concern => collection.read_concern,
579
+ :read_concern => read_concern,
575
580
  :session => session,
576
581
  }.merge!(options))
577
582
  cmd.execute(server).cursor_ids.map do |cursor_id|
@@ -53,7 +53,10 @@ module Mongo
53
53
  # @param [ Hash ] options The cursor options.
54
54
  #
55
55
  # @option options [ true, false ] :disable_retry Whether to disable
56
- # retrying on error when sending getMores.
56
+ # retrying on error when sending getMore operations (deprecated, getMore
57
+ # operations are no longer retried)
58
+ # @option options [ true, false ] :retry_reads Retry reads (following
59
+ # the modern mechanism), default is true
57
60
  #
58
61
  # @since 2.0.0
59
62
  def initialize(view, result, server, options = {})
@@ -75,6 +78,8 @@ module Mongo
75
78
  end
76
79
  end
77
80
 
81
+ # @api private
82
+ attr_reader :server
78
83
 
79
84
  # Finalize the cursor for garbage collection. Schedules this cursor to be included
80
85
  # in a killCursors operation executed by the Cluster's CursorReaper.
@@ -237,13 +242,12 @@ module Mongo
237
242
  end
238
243
 
239
244
  def get_more
240
- if @options[:disable_retry]
241
- process(get_more_operation.execute(@server))
242
- else
243
- read_with_retry(@session) do
244
- process(get_more_operation.execute(@server))
245
- end
246
- end
245
+ # Modern retryable reads specification prohibits retrying getMores.
246
+ # Legacy retryable read logic used to retry getMores, but since
247
+ # doing so may result in silent data loss, the driver no longer retries
248
+ # getMore operations in any circumstance.
249
+ # https://github.com/mongodb/specifications/blob/master/source/retryable-reads/retryable-reads.rst#qa
250
+ process(get_more_operation.execute(@server))
247
251
  end
248
252
 
249
253
  def get_more_operation
@@ -22,6 +22,7 @@ module Mongo
22
22
  # @since 2.0.0
23
23
  class Database
24
24
  extend Forwardable
25
+ include Retryable
25
26
 
26
27
  # The admin database name.
27
28
  #
@@ -67,6 +68,7 @@ module Mongo
67
68
  :cluster,
68
69
  :read_preference,
69
70
  :server_selector,
71
+ :read_concern,
70
72
  :write_concern
71
73
 
72
74
  # @return [ Mongo::Server ] Get the primary server from the cluster.
@@ -162,15 +164,16 @@ module Mongo
162
164
  txn_read_pref ||= opts[:read] || ServerSelector::PRIMARY
163
165
  Lint.validate_underscore_read_preference(txn_read_pref)
164
166
  preference = ServerSelector.get(txn_read_pref)
165
- server = preference.select_server(cluster)
166
167
 
167
168
  client.send(:with_session, opts) do |session|
168
- Operation::Command.new({
169
- :selector => operation.dup,
170
- :db_name => name,
171
- :read => preference,
172
- :session => session
173
- }).execute(server)
169
+ read_with_retry(session, preference) do |server|
170
+ Operation::Command.new({
171
+ :selector => operation.dup,
172
+ :db_name => name,
173
+ :read => preference,
174
+ :session => session
175
+ }).execute(server)
176
+ end
174
177
  end
175
178
  end
176
179
 
@@ -21,6 +21,7 @@ module Mongo
21
21
  class View
22
22
  extend Forwardable
23
23
  include Enumerable
24
+ include Retryable
24
25
 
25
26
  def_delegators :@database, :cluster, :read_preference, :client
26
27
  def_delegators :cluster, :next_primary
@@ -50,11 +51,12 @@ module Mongo
50
51
  # @since 2.0.0
51
52
  def collection_names(options = {})
52
53
  @batch_size = options[:batch_size]
53
- server = next_primary(false)
54
- @limit = -1 if server.features.list_collections_enabled?
55
54
  session = client.send(:get_session, options)
56
- collections_info(server, session, name_only: true).collect do |info|
57
- if server.features.list_collections_enabled?
55
+ cursor = read_with_retry_cursor(session, ServerSelector.get(mode: :primary), self) do |server|
56
+ send_initial_query(server, session, name_only: true)
57
+ end
58
+ cursor.map do |info|
59
+ if cursor.server.features.list_collections_enabled?
58
60
  info[Database::NAME]
59
61
  else
60
62
  (info[Database::NAME] &&
@@ -73,7 +75,7 @@ module Mongo
73
75
  # @since 2.0.5
74
76
  def list_collections
75
77
  session = client.send(:get_session)
76
- collections_info(next_primary(false), session)
78
+ collections_info(session, ServerSelector.get(mode: :primary))
77
79
  end
78
80
 
79
81
  # Create the new database view.
@@ -93,12 +95,17 @@ module Mongo
93
95
 
94
96
  private
95
97
 
96
- def collections_info(server, session, options = {}, &block)
97
- cursor = Cursor.new(self, send_initial_query(server, session, options), server, session: session)
98
- cursor.each do |doc|
99
- yield doc
100
- end if block_given?
101
- cursor.to_enum
98
+ def collections_info(session, server_selector, options = {}, &block)
99
+ cursor = read_with_retry_cursor(session, server_selector, self) do |server|
100
+ send_initial_query(server, session, options)
101
+ end
102
+ if block_given?
103
+ cursor.each do |doc|
104
+ yield doc
105
+ end
106
+ else
107
+ cursor.to_enum
108
+ end
102
109
  end
103
110
 
104
111
  def collections_info_spec(session, options = {})
@@ -12,8 +12,6 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require 'forwardable'
16
-
17
15
  module Mongo
18
16
  # Base error class for all Mongo related errors.
19
17
  #
@@ -140,6 +138,7 @@ require 'mongo/error/write_retryable'
140
138
  require 'mongo/error/change_stream_resumable'
141
139
  require 'mongo/error/bulk_write_error'
142
140
  require 'mongo/error/closed_stream'
141
+ require 'mongo/error/connection_check_out_timeout'
143
142
  require 'mongo/error/extra_file_chunk'
144
143
  require 'mongo/error/file_not_found'
145
144
  require 'mongo/error/operation_failure'
@@ -173,6 +172,7 @@ require 'mongo/error/need_primary_server'
173
172
  require 'mongo/error/no_server_available'
174
173
  require 'mongo/error/no_srv_records'
175
174
  require 'mongo/error/session_ended'
175
+ require 'mongo/error/pool_closed_error'
176
176
  require 'mongo/error/socket_error'
177
177
  require 'mongo/error/socket_timeout_error'
178
178
  require 'mongo/error/failed_stringprep_validation'
@@ -0,0 +1,49 @@
1
+ # Copyright (C) 2019 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+ class Error
17
+
18
+ # Exception raised when trying to check out a connection from a connection
19
+ # pool, the pool is at its max size and no connections become available
20
+ # within the configured wait timeout.
21
+ #
22
+ # @note For backwards compatibility reasons this class derives from
23
+ # Timeout::Error rather than Mongo::Error.
24
+ #
25
+ # @since 2.9.0
26
+ class ConnectionCheckOutTimeout < ::Timeout::Error
27
+
28
+ # @return [ Mongo::Address ] address The address of the server the
29
+ # pool's connections connect to.
30
+ #
31
+ # @since 2.9.0
32
+ attr_reader :address
33
+
34
+ # Instantiate the new exception.
35
+ #
36
+ # @param [ Address ] address
37
+ # @param [ Float ] wait_timeout
38
+ #
39
+ # @since 2.9.0
40
+ # @api private
41
+ def initialize(address, wait_timeout)
42
+ @address = address
43
+
44
+ super("Timed out when attempting to check out a connection from pool with address " +
45
+ "#{address} after #{wait_timeout} sec")
46
+ end
47
+ end
48
+ end
49
+ end
@@ -78,24 +78,24 @@ module Mongo
78
78
  # @since 2.6.0
79
79
  attr_reader :code_name
80
80
 
81
- # Can the read operation that caused the error be retried?
81
+ # Whether the error is a retryable error according to the legacy read retry
82
+ # logic.
82
83
  #
83
- # @example Is the error retryable?
84
- # error.retryable?
85
- #
86
- # @return [ true, false ] Whether the error is retryable.
84
+ # @return [ true, false ]
87
85
  #
88
86
  # @since 2.1.1
87
+ # @deprecated
89
88
  def retryable?
90
89
  RETRY_MESSAGES.any?{ |m| message.include?(m) }
91
90
  end
92
91
 
93
- # Can the write operation that caused the error be retried?
92
+ # Whether the error is a retryable error according to the modern retryable
93
+ # reads and retryable writes specifications.
94
94
  #
95
- # @example Is the error retryable for writes?
96
- # error.write_retryable?
95
+ # This method is also used by the legacy retryable write logic to determine
96
+ # whether an error is a retryable one.
97
97
  #
98
- # @return [ true, false ] Whether the error is retryable.
98
+ # @return [ true, false ]
99
99
  #
100
100
  # @since 2.4.2
101
101
  def write_retryable?
@@ -72,15 +72,33 @@ module Mongo
72
72
 
73
73
  # Create the new parser with the returned document.
74
74
  #
75
+ # In legacy mode, the code and codeName fields of the document are not
76
+ # examined because the status (ok: 1) is not part of the document and
77
+ # there is no way to distinguish successful from failed responses using
78
+ # the document itself, and a successful response may legitimately have
79
+ # {code: 123, codeName: 'foo'} as the contents of a user-inserted
80
+ # document. The legacy server versions do not fill out code nor codeName
81
+ # thus not reading them does not lose information.
82
+ #
75
83
  # @example Create the new parser.
76
84
  # Parser.new({ 'errmsg' => 'failed' })
77
85
  #
78
86
  # @param [ BSON::Document ] document The returned document.
87
+ # @param [ Array<Protocol::Message> ] replies The message replies.
88
+ # @param [ Hash ] options The options.
89
+ #
90
+ # @option options [ true | false ] :legacy Whether document and replies
91
+ # are from a legacy (pre-3.2) response
79
92
  #
80
93
  # @since 2.0.0
81
- def initialize(document, replies = nil)
94
+ def initialize(document, replies = nil, options = nil)
82
95
  @document = document || {}
83
96
  @replies = replies
97
+ @options = if options
98
+ options.dup
99
+ else
100
+ {}
101
+ end.freeze
84
102
  parse!
85
103
  end
86
104
 
@@ -130,8 +148,12 @@ module Mongo
130
148
  end
131
149
 
132
150
  def parse_code
133
- @code = document['code']
134
- @code_name = document['codeName']
151
+ if document['ok'] == 1 || @options[:legacy]
152
+ @code = @code_name = nil
153
+ else
154
+ @code = document['code']
155
+ @code_name = document['codeName']
156
+ end
135
157
 
136
158
  # Since there is only room for one code, do not replace
137
159
  # codes of the top level response with write concern error codes.