mongo 2.10.5 → 2.11.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 (191) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CONTRIBUTING.md +1 -1
  5. data/lib/mongo.rb +2 -0
  6. data/lib/mongo/address.rb +4 -0
  7. data/lib/mongo/address/validator.rb +99 -0
  8. data/lib/mongo/auth.rb +7 -2
  9. data/lib/mongo/auth/user.rb +1 -7
  10. data/lib/mongo/background_thread.rb +135 -0
  11. data/lib/mongo/bulk_write/transformable.rb +3 -3
  12. data/lib/mongo/client.rb +74 -16
  13. data/lib/mongo/cluster.rb +193 -41
  14. data/lib/mongo/cluster/periodic_executor.rb +31 -43
  15. data/lib/mongo/cluster/sdam_flow.rb +26 -3
  16. data/lib/mongo/cluster/srv_monitor.rb +127 -0
  17. data/lib/mongo/collection/view/readable.rb +3 -5
  18. data/lib/mongo/collection/view/writable.rb +3 -3
  19. data/lib/mongo/cursor/builder/get_more_command.rb +1 -4
  20. data/lib/mongo/cursor/builder/kill_cursors_command.rb +5 -23
  21. data/lib/mongo/cursor/builder/op_get_more.rb +2 -2
  22. data/lib/mongo/cursor/builder/op_kill_cursors.rb +5 -24
  23. data/lib/mongo/error.rb +1 -0
  24. data/lib/mongo/error/auth_error.rb +1 -1
  25. data/lib/mongo/error/connection_check_out_timeout.rb +7 -8
  26. data/lib/mongo/error/invalid_address.rb +24 -0
  27. data/lib/mongo/error/notable.rb +2 -2
  28. data/lib/mongo/error/operation_failure.rb +3 -3
  29. data/lib/mongo/error/pool_closed_error.rb +11 -4
  30. data/lib/mongo/event.rb +1 -1
  31. data/lib/mongo/grid/file.rb +0 -5
  32. data/lib/mongo/grid/file/chunk.rb +0 -2
  33. data/lib/mongo/grid/fs_bucket.rb +13 -15
  34. data/lib/mongo/grid/stream/write.rb +3 -9
  35. data/lib/mongo/loggable.rb +5 -1
  36. data/lib/mongo/monitoring.rb +1 -0
  37. data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +7 -0
  38. data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +11 -3
  39. data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +11 -3
  40. data/lib/mongo/monitoring/event/cmap/pool_closed.rb +11 -3
  41. data/lib/mongo/monitoring/event/cmap/pool_created.rb +12 -3
  42. data/lib/mongo/monitoring/unified_sdam_log_subscriber.rb +62 -0
  43. data/lib/mongo/operation/shared/executable.rb +5 -10
  44. data/lib/mongo/operation/shared/sessions_supported.rb +1 -5
  45. data/lib/mongo/protocol/get_more.rb +1 -2
  46. data/lib/mongo/protocol/kill_cursors.rb +13 -6
  47. data/lib/mongo/protocol/serializers.rb +4 -20
  48. data/lib/mongo/retryable.rb +9 -34
  49. data/lib/mongo/semaphore.rb +1 -1
  50. data/lib/mongo/server.rb +113 -42
  51. data/lib/mongo/server/connection.rb +12 -5
  52. data/lib/mongo/server/connection_pool.rb +250 -40
  53. data/lib/mongo/server/connection_pool/populator.rb +58 -0
  54. data/lib/mongo/server/description.rb +9 -2
  55. data/lib/mongo/server/monitor.rb +68 -93
  56. data/lib/mongo/server/monitor/connection.rb +2 -0
  57. data/lib/mongo/server_selector/selectable.rb +13 -5
  58. data/lib/mongo/session.rb +0 -13
  59. data/lib/mongo/srv.rb +17 -0
  60. data/lib/mongo/srv/monitor.rb +96 -0
  61. data/lib/mongo/srv/resolver.rb +130 -0
  62. data/lib/mongo/srv/result.rb +126 -0
  63. data/lib/mongo/srv/warning_result.rb +35 -0
  64. data/lib/mongo/uri.rb +45 -55
  65. data/lib/mongo/uri/srv_protocol.rb +89 -42
  66. data/lib/mongo/version.rb +1 -1
  67. data/mongo.gemspec +3 -4
  68. data/spec/README.md +6 -1
  69. data/spec/enterprise_auth/kerberos_spec.rb +7 -6
  70. data/spec/integration/change_stream_examples_spec.rb +0 -4
  71. data/spec/integration/client_construction_spec.rb +14 -2
  72. data/spec/integration/connect_single_rs_name_spec.rb +2 -2
  73. data/spec/integration/connection_pool_populator_spec.rb +296 -0
  74. data/spec/integration/connection_spec.rb +31 -22
  75. data/spec/integration/cursor_reaping_spec.rb +1 -2
  76. data/spec/integration/docs_examples_spec.rb +0 -4
  77. data/spec/integration/heartbeat_events_spec.rb +17 -15
  78. data/spec/integration/reconnect_spec.rb +144 -1
  79. data/spec/integration/retryable_writes_errors_spec.rb +0 -4
  80. data/spec/integration/retryable_writes_spec.rb +36 -36
  81. data/spec/integration/sdam_error_handling_spec.rb +31 -25
  82. data/spec/integration/sdam_events_spec.rb +2 -6
  83. data/spec/integration/server_monitor_spec.rb +28 -0
  84. data/spec/integration/server_selector_spec.rb +7 -5
  85. data/spec/integration/srv_monitoring_spec.rb +360 -0
  86. data/spec/integration/step_down_spec.rb +4 -6
  87. data/spec/lite_spec_helper.rb +22 -0
  88. data/spec/mongo/address/validator_spec.rb +51 -0
  89. data/spec/mongo/auth/cr_spec.rb +1 -29
  90. data/spec/mongo/auth/ldap_spec.rb +1 -29
  91. data/spec/mongo/auth/scram/conversation_spec.rb +0 -2
  92. data/spec/mongo/auth/scram/negotiation_spec.rb +1 -1
  93. data/spec/mongo/auth/scram_spec.rb +1 -29
  94. data/spec/mongo/auth/user/view_spec.rb +1 -36
  95. data/spec/mongo/auth/user_spec.rb +0 -12
  96. data/spec/mongo/auth/x509_spec.rb +1 -29
  97. data/spec/mongo/bulk_write_spec.rb +2 -2
  98. data/spec/mongo/client_construction_spec.rb +56 -15
  99. data/spec/mongo/client_spec.rb +31 -27
  100. data/spec/mongo/cluster/periodic_executor_spec.rb +16 -0
  101. data/spec/mongo/cluster/srv_monitor_spec.rb +214 -0
  102. data/spec/mongo/cluster/topology/replica_set_spec.rb +16 -11
  103. data/spec/mongo/cluster/topology/sharded_spec.rb +12 -9
  104. data/spec/mongo/cluster/topology/single_spec.rb +20 -11
  105. data/spec/mongo/cluster_spec.rb +45 -29
  106. data/spec/mongo/collection/view/map_reduce_spec.rb +14 -9
  107. data/spec/mongo/collection/view/readable_spec.rb +0 -16
  108. data/spec/mongo/collection_spec.rb +0 -44
  109. data/spec/mongo/cursor/builder/get_more_command_spec.rb +2 -4
  110. data/spec/mongo/cursor/builder/op_get_more_spec.rb +2 -4
  111. data/spec/mongo/cursor_spec.rb +27 -7
  112. data/spec/mongo/monitoring/event/cmap/connection_checked_in_spec.rb +10 -3
  113. data/spec/mongo/monitoring/event/cmap/connection_checked_out_spec.rb +10 -3
  114. data/spec/mongo/monitoring/event/cmap/pool_closed_spec.rb +10 -3
  115. data/spec/mongo/monitoring/event/cmap/pool_created_spec.rb +10 -3
  116. data/spec/mongo/operation/delete/op_msg_spec.rb +17 -8
  117. data/spec/mongo/operation/insert/op_msg_spec.rb +50 -35
  118. data/spec/mongo/operation/update/op_msg_spec.rb +14 -7
  119. data/spec/mongo/retryable_spec.rb +52 -31
  120. data/spec/mongo/server/app_metadata_spec.rb +0 -8
  121. data/spec/mongo/server/connection_auth_spec.rb +5 -2
  122. data/spec/mongo/server/connection_pool/populator_spec.rb +101 -0
  123. data/spec/mongo/server/connection_pool_spec.rb +256 -107
  124. data/spec/mongo/server/connection_spec.rb +22 -33
  125. data/spec/mongo/server/description_spec.rb +42 -4
  126. data/spec/mongo/server/monitor/connection_spec.rb +22 -11
  127. data/spec/mongo/server/monitor_spec.rb +66 -107
  128. data/spec/mongo/server_spec.rb +82 -60
  129. data/spec/mongo/session/session_pool_spec.rb +1 -5
  130. data/spec/mongo/session_spec.rb +0 -4
  131. data/spec/mongo/socket/ssl_spec.rb +2 -2
  132. data/spec/mongo/srv/monitor_spec.rb +211 -0
  133. data/spec/mongo/srv/result_spec.rb +54 -0
  134. data/spec/mongo/uri/srv_protocol_spec.rb +30 -15
  135. data/spec/mongo/uri_spec.rb +125 -4
  136. data/spec/spec_helper.rb +6 -0
  137. data/spec/spec_tests/auth_spec.rb +39 -0
  138. data/spec/spec_tests/cmap_spec.rb +55 -8
  139. data/spec/spec_tests/connection_string_spec.rb +6 -31
  140. data/spec/spec_tests/data/auth/connection-string.yml +297 -0
  141. data/spec/spec_tests/data/cmap/pool-checkout-error-closed.yml +4 -1
  142. data/spec/spec_tests/data/cmap/pool-create-with-options.yml +1 -0
  143. data/spec/spec_tests/data/command_monitoring/insertMany.yml +1 -1
  144. data/spec/spec_tests/data/connection_string/invalid-uris.yml +20 -0
  145. data/spec/spec_tests/data/connection_string/valid-auth.yml +16 -0
  146. data/spec/spec_tests/data/connection_string/valid-warnings.yml +26 -30
  147. data/spec/spec_tests/data/transactions/abort.yml +3 -3
  148. data/spec/spec_tests/data/transactions/error-labels.yml +3 -3
  149. data/spec/spec_tests/data/transactions_api/callback-retry.yml +3 -3
  150. data/spec/spec_tests/data/uri_options/auth-options.yml +1 -1
  151. data/spec/spec_tests/max_staleness_spec.rb +7 -2
  152. data/spec/spec_tests/retryable_reads_spec.rb +0 -31
  153. data/spec/spec_tests/sdam_monitoring_spec.rb +12 -12
  154. data/spec/spec_tests/sdam_spec.rb +4 -7
  155. data/spec/spec_tests/server_selection_spec.rb +6 -2
  156. data/spec/spec_tests/transactions_spec.rb +0 -2
  157. data/spec/spec_tests/uri_options_spec.rb +4 -2
  158. data/spec/stress/connection_pool_stress_spec.rb +203 -0
  159. data/spec/stress/connection_pool_timing_spec.rb +181 -0
  160. data/spec/support/auth.rb +113 -0
  161. data/spec/support/background_thread_registry.rb +63 -0
  162. data/spec/support/client_registry.rb +11 -2
  163. data/spec/support/cluster_config.rb +65 -46
  164. data/spec/support/cluster_tools.rb +2 -2
  165. data/spec/support/cmap.rb +13 -14
  166. data/spec/support/cmap/verifier.rb +4 -5
  167. data/spec/support/command_monitoring.rb +0 -5
  168. data/spec/support/common_shortcuts.rb +101 -1
  169. data/spec/support/constraints.rb +25 -0
  170. data/spec/support/dns.rb +13 -0
  171. data/spec/support/event_subscriber.rb +0 -7
  172. data/spec/support/json_ext_formatter.rb +5 -1
  173. data/spec/support/lite_constraints.rb +22 -6
  174. data/spec/support/local_resource_registry.rb +34 -0
  175. data/spec/support/sdam_monitoring.rb +115 -0
  176. data/spec/support/spec_config.rb +20 -6
  177. data/spec/support/spec_setup.rb +2 -2
  178. data/spec/support/transactions.rb +1 -1
  179. data/spec/support/transactions/test.rb +1 -1
  180. data/spec/support/utils.rb +1 -16
  181. metadata +685 -659
  182. metadata.gz.sig +0 -0
  183. data/lib/mongo/event/description_changed.rb +0 -52
  184. data/spec/integration/bson_symbol_spec.rb +0 -34
  185. data/spec/integration/crud_spec.rb +0 -45
  186. data/spec/integration/get_more_spec.rb +0 -32
  187. data/spec/integration/grid_fs_bucket_spec.rb +0 -48
  188. data/spec/integration/retryable_errors_spec.rb +0 -265
  189. data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +0 -98
  190. data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +0 -56
  191. data/spec/runners/sdam/verifier.rb +0 -88
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8527a8f3a30fbe793408b726ac3cd9c751aa2abae43f62122280c196f3885bb5
4
- data.tar.gz: 92efeea394a0070ebeefb63c66cdfe33535ebf09a7bdc4373cf50d15df1bf3ba
3
+ metadata.gz: b7c88c591ffb30fe10134db69727372a4d1c3801a11dce59804ebe53d475d08f
4
+ data.tar.gz: 16ce4f803cd46df9e0bc6948048fc4c0ea5356d437fbf75b149d38cd872ccca1
5
5
  SHA512:
6
- metadata.gz: 50ebc39f36eab6b9de4cc20c0864f0d2bbdf8331c40690564c8bbe1260ca2df263ba9d1e0746b928b687de378f3194d53b1319648fbc061bf8b9861c406325e3
7
- data.tar.gz: 0706a73de3f10992c3e8ad1fec0aec150221c122d98dae4fe95c05a6371c1c34987fa54041cefbebfe82e502161ac13515b09e059fdb6296a603c6acdc32d3de
6
+ metadata.gz: eb30b7789af0a8816ce50e4b5c3be68e0b0a6f3a0b2da8d4c13a6f6bc8ad826b6a6b505e99df369ed49b24543baa28ff08db655ce3701c1fd2f13b55d4bb9374
7
+ data.tar.gz: 7490c21d89f2b2c88aaa69d8203973869c409c637c0a212cb2d3cd2783ca258cd6a2df6729375e39894303b39541fd0296faee7c691d1b3e4c3553f6c6169385
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/CONTRIBUTING.md CHANGED
@@ -23,7 +23,7 @@ Environment
23
23
  We recommend using [rbenv](https://github.com/sstephenson/rbenv) to set up
24
24
  the Ruby development and testing environments, though other tools like
25
25
  [RVM](https://rvm.io/) will also work. The driver currently supports
26
- MRI 1.9.3-2.6 and JRuby 9.1-9.2.
26
+ MRI 2.3-2.6 and JRuby 9.2.
27
27
 
28
28
  A MongoDB cluster is required to run the tests. Setup procedures and
29
29
  recommendations for various clusters, as well as how to configure the
data/lib/mongo.rb CHANGED
@@ -44,6 +44,7 @@ require 'mongo/event'
44
44
  require 'mongo/address'
45
45
  require 'mongo/auth'
46
46
  require 'mongo/protocol'
47
+ require 'mongo/background_thread'
47
48
  require 'mongo/cluster'
48
49
  require 'mongo/cursor'
49
50
  require 'mongo/collection'
@@ -56,6 +57,7 @@ require 'mongo/server'
56
57
  require 'mongo/server_selector'
57
58
  require 'mongo/session'
58
59
  require 'mongo/socket'
60
+ require 'mongo/srv'
59
61
  require 'mongo/uri'
60
62
  require 'mongo/version'
61
63
  require 'mongo/write_concern'
data/lib/mongo/address.rb CHANGED
@@ -15,6 +15,7 @@
15
15
  require 'mongo/address/ipv4'
16
16
  require 'mongo/address/ipv6'
17
17
  require 'mongo/address/unix'
18
+ require 'mongo/address/validator'
18
19
 
19
20
  module Mongo
20
21
 
@@ -67,6 +68,9 @@ module Mongo
67
68
  #
68
69
  # @since 2.0.0
69
70
  def initialize(seed, options = {})
71
+ if seed.nil?
72
+ raise ArgumentError, "address must be not nil"
73
+ end
70
74
  @seed = seed
71
75
  @host, @port = parse_host_port
72
76
  @options = options
@@ -0,0 +1,99 @@
1
+ # Copyright (C) 2017-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
+
17
+ class Address
18
+
19
+ # @api private
20
+ module Validator
21
+
22
+ # Takes an address string in ipv4/ipv6/hostname/socket path format and
23
+ # validates its format.
24
+ def validate_address_str!(address_str)
25
+ case address_str
26
+ when /\A\[[\d:]+\](?::(\d+))?\z/
27
+ # ipv6 with optional port
28
+ if port_str = $1
29
+ validate_port_str!(port_str)
30
+ end
31
+ when /\A\//, /\.sock\z/
32
+ # Unix socket path.
33
+ # Spec requires us to validate that the path has no unescaped
34
+ # slashes, but if this were to be the case, parsing would have
35
+ # already failed elsewhere because the URI would've been split in
36
+ # a weird place.
37
+ # The spec also allows relative socket paths and requires that
38
+ # socket paths end in ".sock". We accept all paths but special case
39
+ # the .sock extension to avoid relative paths falling into the
40
+ # host:port case below.
41
+ when /[\/\[\]]/
42
+ # Not a host:port nor an ipv4 address with optional port.
43
+ # Possibly botched ipv6 address with e.g. port delimiter present and
44
+ # port missing, or extra junk before or after.
45
+ raise Error::InvalidAddress,
46
+ "Invalid hostname: #{address_str}"
47
+ when /:.*:/m
48
+ raise Error::InvalidAddress,
49
+ "Multiple port delimiters are not allowed: #{address_str}"
50
+ else
51
+ # host:port or ipv4 address with optional port number
52
+ host, port = address_str.split(':')
53
+ if host.empty?
54
+ raise Error::InvalidAddress, "Host is empty: #{address_str}"
55
+ end
56
+
57
+ validate_hostname!(host)
58
+
59
+ if port && port.empty?
60
+ raise Error::InvalidAddress, "Port is empty: #{address_str}"
61
+ end
62
+
63
+ validate_port_str!(port)
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ # Validates format of the hostname, in particular for further use as
70
+ # the origin in same origin verification.
71
+ #
72
+ # The hostname must have been normalized to remove the trailing dot if
73
+ # it was obtained from a DNS record. This method prohibits trailing dots.
74
+ def validate_hostname!(host)
75
+ # Since we are performing same origin verification during SRV
76
+ # processing, prohibit leading dots in hostnames, trailing dots
77
+ # and runs of multiple dots. DNS resolution of SRV records yields
78
+ # hostnames with trailing dots, those trailing dots are removed
79
+ # during normalization process prior to validation.
80
+ if host.start_with?('.')
81
+ raise Error::InvalidAddress, "Hostname cannot start with a dot: #{host}"
82
+ end
83
+ if host.end_with?('.')
84
+ raise Error::InvalidAddress, "Hostname cannot end with a dot: #{host}"
85
+ end
86
+ if host.include?('..')
87
+ raise Error::InvalidAddress, "Runs of multiple dots are not allowed in hostname: #{host}"
88
+ end
89
+ end
90
+
91
+ def validate_port_str!(port)
92
+ unless port.nil? || (port.length > 0 && port.to_i > 0 && port.to_i <= 65535)
93
+ raise Error::InvalidAddress,
94
+ "Invalid port: #{port}. Port must be an integer greater than 0 and less than 65536"
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
data/lib/mongo/auth.rb CHANGED
@@ -70,10 +70,15 @@ module Mongo
70
70
  SOURCES[mechanism].new(user)
71
71
  end
72
72
 
73
+ # Raised when trying to authorize with an invalid configuration
74
+ #
75
+ # @since 2.11.0
76
+ class InvalidConfiguration < Mongo::Error::AuthError; end
77
+
73
78
  # Raised when trying to get an invalid authorization mechanism.
74
79
  #
75
80
  # @since 2.0.0
76
- class InvalidMechanism < RuntimeError
81
+ class InvalidMechanism < InvalidConfiguration
77
82
 
78
83
  # Instantiate the new error.
79
84
  #
@@ -94,7 +99,7 @@ module Mongo
94
99
  # Raised when a user is not authorized on a database.
95
100
  #
96
101
  # @since 2.0.0
97
- class Unauthorized < RuntimeError
102
+ class Unauthorized < Mongo::Error::AuthError
98
103
 
99
104
  # Instantiate the new error.
100
105
  #
@@ -151,8 +151,6 @@ module Mongo
151
151
  # authorized for.
152
152
  # @option options [ String ] :user The user name.
153
153
  # @option options [ String ] :password The user's password.
154
- # @option options [ String ] :pwd Legacy option for the user's password.
155
- # If :password and :pwd are both specified, :password takes precedence.
156
154
  # @option options [ Symbol ] :auth_mech The authorization mechanism.
157
155
  # @option options [ Array<String>, Array<Hash> ] roles The user roles.
158
156
  # @option options [ String ] :client_key The user's client key cached from a previous
@@ -198,11 +196,7 @@ module Mongo
198
196
  #
199
197
  # @since 2.0.0
200
198
  def spec
201
- {roles: roles}.tap do |spec|
202
- if password
203
- spec[:pwd] = password
204
- end
205
- end
199
+ { pwd: password, roles: roles }
206
200
  end
207
201
 
208
202
  private
@@ -0,0 +1,135 @@
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
+
17
+ # The run!, running? and stop! methods used to be part of the public API
18
+ # in some of the classes which now include this module. Therefore these
19
+ # methods must be considered part of the driver's public API for backwards
20
+ # compatibility reasons. However using these methods outside of the driver
21
+ # is deprecated.
22
+ #
23
+ # @api private
24
+ module BackgroundThread
25
+ include Loggable
26
+
27
+ # Start the background thread.
28
+ #
29
+ # If the thread is already running, this method does nothing.
30
+ #
31
+ # @api public for backwards compatibility only
32
+ def run!
33
+ if running?
34
+ @thread
35
+ else
36
+ start!
37
+ end
38
+ end
39
+
40
+ # @api public for backwards compatibility only
41
+ def running?
42
+ if @thread
43
+ @thread.alive?
44
+ else
45
+ false
46
+ end
47
+ end
48
+
49
+ # Stop the background thread and wait for to terminate for a reasonable
50
+ # amount of time.
51
+ #
52
+ # @return [ true | false ] Whether the thread was terminated.
53
+ #
54
+ # @api public for backwards compatibility only
55
+ def stop!
56
+ # If the thread was not started, there is nothing to stop.
57
+ #
58
+ # Classes including this module may want to perform additional
59
+ # cleanup, which they can do by overriding this method.
60
+ return true unless @thread
61
+
62
+ # Background threads generally perform operations in a loop.
63
+ # This flag is meant to be checked on each iteration of the
64
+ # working loops and the thread should stop working when this flag
65
+ # is set.
66
+ @stop_requested = true
67
+
68
+ # Besides setting the flag, a particular class may have additional
69
+ # ways of signaling the background thread to either stop working or
70
+ # wake up to check the stop flag, for example, setting a semaphore.
71
+ # This can be accomplished by providing the pre_stop method.
72
+ pre_stop
73
+
74
+ # Now we have requested the graceful termination, and we could wait
75
+ # for the thread to exit on its own accord. A future version of the
76
+ # driver may allow a certain amount of time for the thread to quit.
77
+ # For now, we additionally use the Ruby machinery to request the thread
78
+ # be terminated, and do so immediately.
79
+ #
80
+ # Note that this may cause the background thread to terminate in
81
+ # the middle of an operation.
82
+ @thread.kill
83
+
84
+ # Wait for the thread to die. This is important in order to reliably
85
+ # clean up resources like connections knowing that no background
86
+ # thread will reconnect because it is still working.
87
+ #
88
+ # However, we do not want to wait indefinitely because in theory
89
+ # a background thread could be performing, say, network I/O and if
90
+ # the network is no longer available that could take a long time.
91
+ start_time = Time.now
92
+ ([0.1, 0.15] + [0.2] * 5 + [0.3] * 20).each do |interval|
93
+ begin
94
+ Timeout.timeout(interval) do
95
+ @thread.join
96
+ end
97
+ break
98
+ rescue Timeout::Error
99
+ end
100
+ end
101
+
102
+ # Some driver objects can be reconnected, for backwards compatibiilty
103
+ # reasons. Clear the thread instance variable to support this cleanly.
104
+ if @thread.alive?
105
+ log_warn("Failed to stop background thread in #{self} in #{(Time.now - start_time).to_i} seconds")
106
+ false
107
+ else
108
+ @thread = nil
109
+ true
110
+ end
111
+ end
112
+
113
+ private
114
+
115
+ # @return [ Thread ] The created Thread instance.
116
+ def start!
117
+ @thread = Thread.new do
118
+ catch(:done) do
119
+ until @stop_requested
120
+ do_work
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ # Override this method to do the work in the background thread.
127
+ def do_work
128
+ end
129
+
130
+ # Override this method to perform additional signaling for the background
131
+ # thread to stop.
132
+ def pre_stop
133
+ end
134
+ end
135
+ end
@@ -92,7 +92,7 @@ module Mongo
92
92
  Operation::U => doc[:replacement],
93
93
  }.tap do |d|
94
94
  if doc[:upsert]
95
- d['upsert'] = true
95
+ d[:upsert] = true
96
96
  end
97
97
  d[Operation::COLLATION] = doc[:collation] if doc[:collation]
98
98
  end
@@ -108,7 +108,7 @@ module Mongo
108
108
  Operation::MULTI => true,
109
109
  }.tap do |d|
110
110
  if doc[:upsert]
111
- d['upsert'] = true
111
+ d[:upsert] = true
112
112
  end
113
113
  d[Operation::COLLATION] = doc[:collation] if doc[:collation]
114
114
  d[Operation::ARRAY_FILTERS] = doc[:array_filters] if doc[:array_filters]
@@ -124,7 +124,7 @@ module Mongo
124
124
  Operation::U => doc[:update],
125
125
  }.tap do |d|
126
126
  if doc[:upsert]
127
- d['upsert'] = true
127
+ d[:upsert] = true
128
128
  end
129
129
  d[Operation::COLLATION] = doc[:collation] if doc[:collation]
130
130
  d[Operation::ARRAY_FILTERS] = doc[:array_filters] if doc[:array_filters]
data/lib/mongo/client.rb CHANGED
@@ -62,6 +62,7 @@ module Mongo
62
62
  :id_generator,
63
63
  :local_threshold,
64
64
  :logger,
65
+ :log_prefix,
65
66
  :max_idle_time,
66
67
  :max_pool_size,
67
68
  :max_read_retries,
@@ -75,6 +76,7 @@ module Mongo
75
76
  :read_concern,
76
77
  :read_retry_interval,
77
78
  :replica_set,
79
+ :resolv_options,
78
80
  :retry_reads,
79
81
  :retry_writes,
80
82
  :scan,
@@ -215,13 +217,16 @@ module Mongo
215
217
  # @option options [ Float ] :connect_timeout The timeout, in seconds, to
216
218
  # attempt a connection.
217
219
  # @option options [ String ] :database The database to connect to.
218
- # @option options [ Float ] :heartbeat_frequency The number of seconds for
219
- # the server monitor to refresh it's description via ismaster.
220
+ # @option options [ Float ] :heartbeat_frequency The interval, in seconds,
221
+ # for the server monitor to refresh its description via ismaster.
220
222
  # @option options [ Object ] :id_generator A custom object to generate ids
221
223
  # for documents. Must respond to #generate.
222
224
  # @option options [ Integer ] :local_threshold The local threshold boundary
223
225
  # in seconds for selecting a near server for an operation.
224
- # @option options [ Logger ] :logger A custom logger if desired.
226
+ # @option options [ Logger ] :logger A custom logger to use.
227
+ # @option options [ String ] :log_prefix A custom log prefix to use when
228
+ # logging. This option is experimental and subject to change in a future
229
+ # version of the driver.
225
230
  # @option options [ Integer ] :max_idle_time The maximum seconds a socket can remain idle
226
231
  # since it has been checked in to the pool.
227
232
  # @option options [ Integer ] :max_pool_size The maximum size of the
@@ -361,6 +366,8 @@ module Mongo
361
366
  # Can be :w => Integer|String, :fsync => Boolean, :j => Boolean.
362
367
  # @option options [ Integer ] :zlib_compression_level The Zlib compression level to use, if using compression.
363
368
  # See Ruby's Zlib module for valid levels.
369
+ # @option options [ Hash ] :resolv_options For internal driver use only.
370
+ # Options to pass through to Resolv::DNS constructor for SRV lookups.
364
371
  #
365
372
  # @since 2.0.0
366
373
  def initialize(addresses_or_uri, options = nil)
@@ -370,8 +377,14 @@ module Mongo
370
377
  options = {}
371
378
  end
372
379
 
380
+ srv_uri = nil
373
381
  if addresses_or_uri.is_a?(::String)
374
382
  uri = URI.get(addresses_or_uri, options)
383
+ if uri.is_a?(URI::SRVProtocol)
384
+ # If the URI is an SRV URI, note this so that we can start
385
+ # SRV polling if the topology is a sharded cluster.
386
+ srv_uri = uri
387
+ end
375
388
  addresses = uri.servers
376
389
  uri_options = uri.client_options.dup
377
390
  # Special handing for :write and :write_concern: allow client Ruby
@@ -382,8 +395,10 @@ module Mongo
382
395
  uri_options.delete(:write_concern)
383
396
  end
384
397
  options = uri_options.merge(options)
398
+ @srv_records = uri.srv_records
385
399
  else
386
400
  addresses = addresses_or_uri
401
+ @srv_records = nil
387
402
  end
388
403
 
389
404
  unless options[:retry_reads] == false
@@ -407,6 +422,7 @@ module Mongo
407
422
  =end
408
423
  @options.freeze
409
424
  validate_options!
425
+ validate_authentication_options!
410
426
 
411
427
  @database = Database.new(self, @options[:database], @options)
412
428
 
@@ -418,8 +434,7 @@ module Mongo
418
434
  sdam_proc.call(self)
419
435
  end
420
436
 
421
- @server_selection_semaphore = Semaphore.new
422
- @cluster = Cluster.new(addresses, @monitoring, cluster_options)
437
+ @cluster = Cluster.new(addresses, @monitoring, cluster_options.merge(srv_uri: srv_uri))
423
438
 
424
439
  # Unset monitoring, it will be taken out of cluster from now on
425
440
  remove_instance_variable('@monitoring')
@@ -435,7 +450,6 @@ module Mongo
435
450
  options.reject do |key, value|
436
451
  CRUD_OPTIONS.include?(key.to_sym)
437
452
  end.merge(
438
- server_selection_semaphore: @server_selection_semaphore,
439
453
  # but need to put the database back in for auth...
440
454
  database: options[:database],
441
455
 
@@ -444,7 +458,14 @@ module Mongo
444
458
  # applications should read these values from client, not from cluster
445
459
  max_read_retries: options[:max_read_retries],
446
460
  read_retry_interval: options[:read_retry_interval],
447
- )
461
+ ).tap do |options|
462
+ # If the client has a cluster already, forward srv_uri to the new
463
+ # cluster to maintain SRV monitoring. If the client is brand new,
464
+ # its constructor sets srv_uri manually.
465
+ if cluster
466
+ options.update(srv_uri: cluster.options[:srv_uri])
467
+ end
468
+ end
448
469
  end
449
470
 
450
471
  # Get the maximum number of times the client can retry a read operation
@@ -616,6 +637,7 @@ module Mongo
616
637
  options.update(opts)
617
638
  @options = options.freeze
618
639
  validate_options!
640
+ validate_authentication_options!
619
641
  end
620
642
  end
621
643
 
@@ -647,17 +669,11 @@ module Mongo
647
669
 
648
670
  # Close all connections.
649
671
  #
650
- # @example Disconnect the client.
651
- # client.close
652
- #
653
- # @param [ Boolean ] wait Whether to wait for background threads to
654
- # finish running.
655
- #
656
672
  # @return [ true ] Always true.
657
673
  #
658
674
  # @since 2.1.0
659
- def close(wait=false)
660
- @cluster.disconnect!(wait)
675
+ def close
676
+ @cluster.disconnect!
661
677
  true
662
678
  end
663
679
 
@@ -857,7 +873,7 @@ module Mongo
857
873
  end
858
874
 
859
875
  # Validates all options after they are set on the client.
860
- # This method is intended to catch combinations of options which do are
876
+ # This method is intended to catch combinations of options which are
861
877
  # not allowed.
862
878
  def validate_options!
863
879
  if options[:write] && options[:write_concern] && options[:write] != options[:write_concern]
@@ -865,6 +881,48 @@ module Mongo
865
881
  end
866
882
  end
867
883
 
884
+ # Validates all authentication-related options after they are set on the client
885
+ # This method is intended to catch combinations of options which are not allowed
886
+ def validate_authentication_options!
887
+ auth_mech = options[:auth_mech]
888
+ user = options[:user]
889
+ password = options[:password]
890
+ auth_source = options[:auth_source]
891
+ mech_properties = options[:auth_mech_properties]
892
+
893
+ if auth_mech.nil?
894
+ if user && user.empty?
895
+ raise Mongo::Auth::InvalidConfiguration.new('empty username is not supported for default auth mechanism')
896
+ end
897
+
898
+ return
899
+ end
900
+
901
+ if !Mongo::Auth::SOURCES.key?(auth_mech)
902
+ raise Mongo::Auth::InvalidMechanism.new(auth_mech)
903
+ end
904
+
905
+ if user.nil? && auth_mech != :mongodb_x509
906
+ raise Mongo::Auth::InvalidConfiguration.new("user is required for mechanism #{auth_mech}")
907
+ end
908
+
909
+ if password.nil? && ![:gssapi, :mongodb_x509].include?(auth_mech)
910
+ raise Mongo::Auth::InvalidConfiguration.new("password is required for mechanism #{auth_mech}")
911
+ end
912
+
913
+ if password && auth_mech == :mongodb_x509
914
+ raise Mongo::Auth::InvalidConfiguration.new('password is not supported for mongodb_x509')
915
+ end
916
+
917
+ if ![:external, nil].include?(auth_source) && [:gssapi, :mongodb_x509].include?(auth_mech)
918
+ raise Mongo::Auth::InvalidConfiguration.new("#{auth_source} is an invalid auth source for #{auth_mech}; valid options are $external and nil")
919
+ end
920
+
921
+ if mech_properties && auth_mech != :gssapi
922
+ raise Mongo::Auth::InvalidConfiguration.new("mechanism_properties are not supported for #{auth_mech}")
923
+ end
924
+ end
925
+
868
926
  def valid_compressors(compressors)
869
927
  compressors.select do |compressor|
870
928
  if !VALID_COMPRESSORS.include?(compressor)