mongo 2.10.5 → 2.11.0.rc0

Sign up to get free protection for your applications and to get access to all the features.
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)