mongo 2.8.0 → 2.9.0.rc0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -96,7 +96,7 @@ module Mongo
96
96
  buffer = serialize(message)
97
97
  ensure_connected do |socket|
98
98
  operation_id = Monitoring.next_operation_id
99
- command_started(address, operation_id, message.payload)
99
+ command_started(address, operation_id, message.payload, socket.object_id)
100
100
  start = Time.now
101
101
  result = nil
102
102
  begin
@@ -12,73 +12,346 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require 'mongo/server/connection_pool/queue'
16
-
17
15
  module Mongo
18
16
  class Server
19
17
 
20
18
  # Represents a connection pool for server connections.
21
19
  #
22
- # @since 2.0.0
20
+ # @since 2.0.0, largely rewritten in 2.9.0
23
21
  class ConnectionPool
24
22
  include Loggable
23
+ include Monitoring::Publishable
25
24
  extend Forwardable
26
25
 
27
- # Create the new connection pool.
26
+ # The default max size for the connection pool.
28
27
  #
29
- # @example Create the new connection pool.
30
- # Pool.new(wait_queue_timeout: 0.5) do
31
- # Connection.new
32
- # end
28
+ # @since 2.9.0
29
+ DEFAULT_MAX_SIZE = 5.freeze
30
+
31
+ # The default min size for the connection pool.
33
32
  #
34
- # @note A block must be passed to set up the connections on initialization.
33
+ # @since 2.9.0
34
+ DEFAULT_MIN_SIZE = 0.freeze
35
+
36
+ # The default timeout, in seconds, to wait for a connection.
37
+ #
38
+ # @since 2.9.0
39
+ DEFAULT_WAIT_TIMEOUT = 1.freeze
40
+
41
+ # Create the new connection pool.
35
42
  #
43
+ # @param [ Server ] server The server which this connection pool is for.
36
44
  # @param [ Hash ] options The connection pool options.
37
45
  #
38
- # @option options [ Integer ] :max_pool_size The maximum pool size.
39
- # @option options [ Integer ] :min_pool_size The minimum pool size.
40
- # @option options [ Float ] :wait_queue_timeout The time to wait, in
46
+ # @option options [ Integer ] :max_size The maximum pool size.
47
+ # @option options [ Integer ] :max_pool_size Deprecated.
48
+ # The maximum pool size. If max_size is also given, max_size and
49
+ # max_pool_size must be identical.
50
+ # @option options [ Integer ] :min_size The minimum pool size.
51
+ # @option options [ Integer ] :min_pool_size Deprecated.
52
+ # The minimum pool size. If min_size is also given, min_size and
53
+ # min_pool_size must be identical.
54
+ # @option options [ Float ] :wait_timeout The time to wait, in
41
55
  # seconds, for a free connection.
56
+ # @option options [ Float ] :wait_queue_timeout Deprecated.
57
+ # Alias for :wait_timeout. If both wait_timeout and wait_queue_timeout
58
+ # are given, their values must be identical.
59
+ # @option options [ Float ] :max_idle_time The time, in seconds,
60
+ # after which idle connections should be closed by the pool.
42
61
  #
43
- # @since 2.0.0
44
- def initialize(options = {}, &block)
45
- @options = options.dup.freeze
46
- @queue = queue = Queue.new(@options, &block)
62
+ # @since 2.0.0, API changed in 2.9.0
63
+ def initialize(server, options = {})
64
+ unless server.is_a?(Server)
65
+ raise ArgumentError, 'First argument must be a Server instance'
66
+ end
67
+ options = options.dup
68
+ if options[:min_size] && options[:min_pool_size] && options[:min_size] != options[:min_pool_size]
69
+ raise ArgumentError, "Min size #{options[:min_size]} is not identical to min pool size #{options[:min_pool_size]}"
70
+ end
71
+ if options[:max_size] && options[:max_pool_size] && options[:max_size] != options[:max_pool_size]
72
+ raise ArgumentError, "Max size #{options[:max_size]} is not identical to max pool size #{options[:max_pool_size]}"
73
+ end
74
+ if options[:wait_timeout] && options[:wait_queue_timeout] && options[:wait_timeout] != options[:wait_queue_timeout]
75
+ raise ArgumentError, "Wait timeout #{options[:wait_timeout]} is not identical to wait queue timeout #{options[:wait_queue_timeout]}"
76
+ end
77
+ options[:min_size] ||= options[:min_pool_size]
78
+ options.delete(:min_pool_size)
79
+ options[:max_size] ||= options[:max_pool_size]
80
+ options.delete(:max_pool_size)
81
+ if options[:min_size] && options[:max_size] &&
82
+ options[:min_size] > options[:max_size]
83
+ then
84
+ raise ArgumentError, "Cannot have min size #{options[:min_size]} exceed max size #{options[:max_size]}"
85
+ end
86
+ if options[:wait_queue_timeout]
87
+ options[:wait_timeout] ||= options[:wait_queue_timeout]
88
+ end
89
+ options.delete(:wait_queue_timeout)
90
+
91
+ @server = server
92
+ @options = options.freeze
93
+
94
+ @generation = 1
95
+ @closed = false
96
+
97
+ # A connection owned by this pool should be either in the
98
+ # available connections array (which is used as a stack)
99
+ # or in the checked out connections set.
100
+ @available_connections = available_connections = []
101
+ @checked_out_connections = Set.new
102
+
103
+ # Mutex used for synchronizing access to @available_connections and
104
+ # @checked_out_connections. The pool object is thread-safe, thus
105
+ # all methods that retrieve or modify instance variables generally
106
+ # must do so under this lock.
107
+ @lock = Mutex.new
108
+
109
+ # Condition variable broadcast when a connection is added to
110
+ # @available_connections, to wake up any threads waiting for an
111
+ # available connection when pool is at max size
112
+ @available_semaphore = Semaphore.new
47
113
 
48
114
  finalizer = proc do
49
- queue.disconnect!
115
+ available_connections.each do |connection|
116
+ connection.disconnect!(reason: :pool_closed)
117
+ end
118
+ available_connections.clear
119
+ # Finalizer does not close checked out connections.
120
+ # Those would have to be garbage collected on their own
121
+ # and that should close them.
50
122
  end
51
123
  ObjectSpace.define_finalizer(self, finalizer)
124
+
125
+ publish_cmap_event(
126
+ Monitoring::Event::Cmap::PoolCreated.new(@server.address, options)
127
+ )
52
128
  end
53
129
 
54
130
  # @return [ Hash ] options The pool options.
55
131
  attr_reader :options
56
132
 
57
- def_delegators :queue, :close_stale_sockets!
133
+ # Get the maximum size of the connection pool.
134
+ #
135
+ # @return [ Integer ] The maximum size of the connection pool.
136
+ #
137
+ # @since 2.9.0
138
+ def max_size
139
+ @max_size ||= options[:max_size] || [DEFAULT_MAX_SIZE, min_size].max
140
+ end
141
+
142
+ # Get the minimum size of the connection pool.
143
+ #
144
+ # @return [ Integer ] The minimum size of the connection pool.
145
+ #
146
+ # @since 2.9.0
147
+ def min_size
148
+ @min_size ||= options[:min_size] || DEFAULT_MIN_SIZE
149
+ end
58
150
 
59
- # Check a connection back into the pool. Will pull the connection from a
60
- # thread local stack that should contain it after it was checked out.
151
+ # The time to wait, in seconds, for a connection to become available.
61
152
  #
62
- # @example Checkin the thread's connection to the pool.
63
- # pool.checkin
153
+ # @return [ Float ] The queue wait timeout.
64
154
  #
65
- # @since 2.0.0
66
- def checkin(connection)
67
- queue.enqueue(connection)
155
+ # @since 2.9.0
156
+ def wait_timeout
157
+ @wait_timeout ||= options[:wait_timeout] || DEFAULT_WAIT_TIMEOUT
68
158
  end
69
159
 
70
- # Check a connection out from the pool. If a connection exists on the same
71
- # thread it will get that connection, otherwise it will dequeue a
72
- # connection from the queue and pin it to this thread.
160
+ # The maximum seconds a socket can remain idle since it has been
161
+ # checked in to the pool, if set.
73
162
  #
74
- # @example Check a connection out from the pool.
75
- # pool.checkout
163
+ # @return [ Float | nil ] The max socket idle time in seconds.
164
+ #
165
+ # @since 2.9.0
166
+ def max_idle_time
167
+ @max_idle_time ||= options[:max_idle_time]
168
+ end
169
+
170
+ # @return [ Integer ] generation Generation of connections currently
171
+ # being used by the queue.
172
+ #
173
+ # @since 2.9.0
174
+ # @api private
175
+ attr_reader :generation
176
+
177
+ # Size of the connection pool.
178
+ #
179
+ # Includes available and checked out connections.
180
+ #
181
+ # @return [ Integer ] Size of the connection pool.
182
+ #
183
+ # @since 2.9.0
184
+ def size
185
+ raise_if_closed!
186
+
187
+ @lock.synchronize do
188
+ unsynchronized_size
189
+ end
190
+ end
191
+
192
+ # Returns the size of the connection pool without acquiring the lock.
193
+ # This method should only be used by other pool methods when they are
194
+ # already holding the lock as Ruby does not allow a thread holding a
195
+ # lock to acquire this lock again.
196
+ def unsynchronized_size
197
+ @available_connections.length + @checked_out_connections.size
198
+ end
199
+ private :unsynchronized_size
200
+
201
+ # Number of available connections in the pool.
202
+ #
203
+ # @return [ Integer ] Number of available connections.
204
+ #
205
+ # @since 2.9.0
206
+ def available_count
207
+ raise_if_closed!
208
+
209
+ @lock.synchronize do
210
+ @available_connections.length
211
+ end
212
+ end
213
+
214
+ # Whether the pool has been closed.
215
+ #
216
+ # @return [ true | false ] Whether the pool is closed.
217
+ #
218
+ # @since 2.9.0
219
+ def closed?
220
+ !!@closed
221
+ end
222
+
223
+ # @since 2.9.0
224
+ def_delegators :@server, :monitoring
225
+
226
+ # Checks a connection out of the pool.
227
+ #
228
+ # If there are active connections in the pool, the most recently used
229
+ # connection is returned. Otherwise if the connection pool size is less
230
+ # than the max size, creates a new connection and returns it. Otherwise
231
+ # waits up to the wait timeout and raises Timeout::Error if there are
232
+ # still no active connections and the pool is at max size.
233
+ #
234
+ # The returned connection counts toward the pool's max size. When the
235
+ # caller is finished using the connection, the connection should be
236
+ # checked back in via the check_in method.
76
237
  #
77
238
  # @return [ Mongo::Server::Connection ] The checked out connection.
239
+ # @raise [ Timeout::Error ] If the connection pool is at maximum size
240
+ # and remains so for longer than the wait timeout.
78
241
  #
79
- # @since 2.0.0
80
- def checkout
81
- queue.dequeue
242
+ # @since 2.9.0
243
+ def check_out
244
+ raise_if_closed!
245
+
246
+ publish_cmap_event(
247
+ Monitoring::Event::Cmap::ConnectionCheckOutStarted.new(@server.address)
248
+ )
249
+
250
+ deadline = Time.now + wait_timeout
251
+ connection = nil
252
+ # It seems that synchronize sets up its own loop, thus a simple break
253
+ # is insufficient to break the outer loop
254
+ catch(:done) do
255
+ loop do
256
+ # Lock must be taken on each iteration, rather for the method
257
+ # overall, otherwise other threads will not be able to check in
258
+ # a connection while this thread is waiting for one.
259
+ @lock.synchronize do
260
+ until @available_connections.empty?
261
+ connection = @available_connections.pop
262
+
263
+ if connection.generation != generation
264
+ # Stale connections should be disconnected in the clear
265
+ # method, but if any don't, check again here
266
+ connection.disconnect!(reason: :stale)
267
+ next
268
+ end
269
+
270
+ if max_idle_time && connection.last_checkin &&
271
+ Time.now - connection.last_checkin > max_idle_time
272
+ then
273
+ connection.disconnect!(reason: :idle)
274
+ next
275
+ end
276
+
277
+ throw(:done)
278
+ end
279
+
280
+ # Ruby does not allow a thread to lock a mutex which it already
281
+ # holds.
282
+ if unsynchronized_size < max_size
283
+ # This does not currently connect the socket and handshake,
284
+ # but if it did, it would be performing i/o under our lock,
285
+ # which is bad. Fix in the future.
286
+ connection = create_connection
287
+ throw(:done)
288
+ end
289
+ end
290
+
291
+ wait = deadline - Time.now
292
+ if wait <= 0
293
+ publish_cmap_event(
294
+ Monitoring::Event::Cmap::ConnectionCheckOutFailed.new(
295
+ @server.address,
296
+ Monitoring::Event::Cmap::ConnectionCheckOutFailed::TIMEOUT,
297
+ ),
298
+ )
299
+ raise Error::ConnectionCheckOutTimeout.new(@server.address, wait_timeout)
300
+ end
301
+ @available_semaphore.wait(wait)
302
+ end
303
+ end
304
+
305
+ @checked_out_connections << connection
306
+ publish_cmap_event(
307
+ Monitoring::Event::Cmap::ConnectionCheckedOut.new(@server.address, connection.id),
308
+ )
309
+ connection
310
+ end
311
+
312
+ # Check a connection back into the pool.
313
+ #
314
+ # The connection must have been previously created by this pool.
315
+ #
316
+ # @param [ Mongo::Server::Connection ] connection The connection.
317
+ #
318
+ # @since 2.9.0
319
+ def check_in(connection)
320
+ @lock.synchronize do
321
+ unless @checked_out_connections.include?(connection)
322
+ raise ArgumentError, "Trying to check in a connection which is not currently checked out by this pool: #{connection}"
323
+ end
324
+
325
+ @checked_out_connections.delete(connection)
326
+
327
+ # Note: if an event handler raises, resource will not be signaled.
328
+ # This means threads waiting for a connection to free up when
329
+ # the pool is at max size may time out.
330
+ # Threads that begin waiting after this method completes (with
331
+ # the exception) should be fine.
332
+ publish_cmap_event(
333
+ Monitoring::Event::Cmap::ConnectionCheckedIn.new(@server.address, connection.id)
334
+ )
335
+
336
+ if closed?
337
+ connection.disconnect!(reason: :pool_closed)
338
+ return
339
+ end
340
+
341
+ if connection.closed?
342
+ # Connection was closed - for example, because it experienced
343
+ # a network error. Nothing else needs to be done here.
344
+ elsif connection.generation != @generation
345
+ connection.disconnect!(reason: :stale)
346
+ else
347
+ connection.record_checkin!
348
+ @available_connections << connection
349
+
350
+ # Wake up only one thread waiting for an available connection,
351
+ # since only one connection was checked in.
352
+ @available_semaphore.signal
353
+ end
354
+ end
82
355
  end
83
356
 
84
357
  # Closes all idle connections in the pool and schedules currently checked
@@ -86,14 +359,75 @@ module Mongo
86
359
  # The pool remains operational and can create new connections when
87
360
  # requested.
88
361
  #
89
- # @example Disconnect the connection pool.
90
- # pool.disconnect!
362
+ # @option options [ true | false ] :lazy If true, do not close any of
363
+ # the idle connections and instead let them be closed during a
364
+ # subsequent check out operation.
91
365
  #
92
366
  # @return [ true ] true.
93
367
  #
94
368
  # @since 2.1.0
95
- def disconnect!
96
- queue.disconnect!
369
+ def clear(options = nil)
370
+ raise_if_closed!
371
+
372
+ @lock.synchronize do
373
+ @generation += 1
374
+
375
+ publish_cmap_event(
376
+ Monitoring::Event::Cmap::PoolCleared.new(@server.address)
377
+ )
378
+
379
+ unless options && options[:lazy]
380
+ until @available_connections.empty?
381
+ connection = @available_connections.pop
382
+ connection.disconnect!(reason: :stale)
383
+ end
384
+ end
385
+ end
386
+
387
+ true
388
+ end
389
+
390
+ # @since 2.1.0
391
+ # @deprecated
392
+ alias :disconnect! :clear
393
+
394
+ # Marks the pool closed, closes all idle connections in the pool and
395
+ # schedules currently checked out connections to be closed when they are
396
+ # checked back into the pool. If force option is true, checked out
397
+ # connections are also closed. Attempts to use the pool after it is closed
398
+ # will raise Error::PoolClosedError.
399
+ #
400
+ # @option options [ true | false ] :force Also close all checked out
401
+ # connections.
402
+ #
403
+ # @return [ true ] true.
404
+ #
405
+ # @since 2.9.0
406
+ def close(options = nil)
407
+ return if closed?
408
+
409
+ @lock.synchronize do
410
+ until @available_connections.empty?
411
+ connection = @available_connections.pop
412
+ connection.disconnect!(reason: :pool_closed)
413
+ end
414
+
415
+ if options && options[:force]
416
+ until @checked_out_connections.empty?
417
+ connection = @checked_out_connections.take(1).first
418
+ connection.disconnect!(reason: :pool_closed)
419
+ @checked_out_connections.delete(connection)
420
+ end
421
+ end
422
+ end
423
+
424
+ @closed = true
425
+
426
+ publish_cmap_event(
427
+ Monitoring::Event::Cmap::PoolClosed.new(@server.address)
428
+ )
429
+
430
+ true
97
431
  end
98
432
 
99
433
  # Get a pretty printed string inspection for the pool.
@@ -105,10 +439,16 @@ module Mongo
105
439
  #
106
440
  # @since 2.0.0
107
441
  def inspect
108
- "#<Mongo::Server::ConnectionPool:0x#{object_id} queue=#{queue.inspect}>"
442
+ if closed?
443
+ "#<Mongo::Server::ConnectionPool:0x#{object_id} min_size=#{min_size} max_size=#{max_size} " +
444
+ "wait_timeout=#{wait_timeout} closed>"
445
+ else
446
+ "#<Mongo::Server::ConnectionPool:0x#{object_id} min_size=#{min_size} max_size=#{max_size} " +
447
+ "wait_timeout=#{wait_timeout} current_size=#{size} available=#{available_count}>"
448
+ end
109
449
  end
110
450
 
111
- # Yield the block to a connection, while handling checkin/checkout logic.
451
+ # Yield the block to a connection, while handling check in/check out logic.
112
452
  #
113
453
  # @example Execute with a connection.
114
454
  # pool.with_connection do |connection|
@@ -119,15 +459,71 @@ module Mongo
119
459
  #
120
460
  # @since 2.0.0
121
461
  def with_connection
122
- connection = checkout
462
+ raise_if_closed!
463
+
464
+ connection = check_out
123
465
  yield(connection)
124
466
  ensure
125
- checkin(connection) if connection
467
+ if connection
468
+ check_in(connection)
469
+ end
470
+ end
471
+
472
+ # Close sockets that have been open for longer than the max idle time,
473
+ # if the option is set.
474
+ #
475
+ # @since 2.5.0
476
+ def close_idle_sockets
477
+ return if closed?
478
+ return unless max_idle_time
479
+
480
+ @lock.synchronize do
481
+ i = 0
482
+ while i < @available_connections.length
483
+ connection = @available_connections[i]
484
+ if last_checkin = connection.last_checkin
485
+ if (Time.now - last_checkin) > max_idle_time
486
+ connection.disconnect!(reason: :idle)
487
+ @available_connections.delete_at(i)
488
+ next
489
+ end
490
+ end
491
+ i += 1
492
+ end
493
+ end
494
+ end
495
+
496
+ # Creates up to the min size connections.
497
+ #
498
+ # Used by the spec test runner.
499
+ #
500
+ # @api private
501
+ def populate
502
+ while size < min_size
503
+ @available_connections << create_connection
504
+ end
126
505
  end
127
506
 
128
- protected
507
+ private
508
+
509
+ def create_connection
510
+ connection = Connection.new(@server, options.merge(generation: generation))
511
+ # CMAP spec requires connections to be returned from the pool
512
+ # fully established.
513
+ #connection.connect!
514
+ connection
515
+ end
129
516
 
130
- attr_reader :queue
517
+ # Asserts that the pool has not been closed.
518
+ #
519
+ # @raise [ Error::PoolClosedError ] If the pool has been closed.
520
+ #
521
+ # @since 2.9.0
522
+ def raise_if_closed!
523
+ if closed?
524
+ raise Error::PoolClosedError.new(@server.address)
525
+ end
526
+ end
131
527
  end
132
528
  end
133
529
  end