mongo 2.11.0 → 2.11.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/Rakefile +24 -0
- data/lib/mongo/address.rb +53 -37
- data/lib/mongo/auth.rb +30 -10
- data/lib/mongo/auth/cr.rb +1 -0
- data/lib/mongo/auth/cr/conversation.rb +13 -13
- data/lib/mongo/auth/ldap.rb +2 -1
- data/lib/mongo/auth/ldap/conversation.rb +9 -12
- data/lib/mongo/auth/scram.rb +1 -0
- data/lib/mongo/auth/scram/conversation.rb +36 -27
- data/lib/mongo/auth/user.rb +7 -1
- data/lib/mongo/auth/x509.rb +2 -1
- data/lib/mongo/auth/x509/conversation.rb +9 -9
- data/lib/mongo/bulk_write/transformable.rb +3 -3
- data/lib/mongo/client.rb +17 -6
- data/lib/mongo/cluster.rb +67 -49
- data/lib/mongo/cluster/sdam_flow.rb +87 -3
- data/lib/mongo/collection/view/readable.rb +3 -1
- data/lib/mongo/collection/view/writable.rb +3 -3
- data/lib/mongo/cursor/builder/kill_cursors_command.rb +8 -1
- data/lib/mongo/cursor/builder/op_kill_cursors.rb +8 -1
- data/lib/mongo/database.rb +1 -1
- data/lib/mongo/grid/file.rb +5 -0
- data/lib/mongo/grid/file/chunk.rb +2 -0
- data/lib/mongo/grid/fs_bucket.rb +15 -13
- data/lib/mongo/grid/stream/write.rb +9 -3
- data/lib/mongo/protocol/serializers.rb +12 -2
- data/lib/mongo/retryable.rb +33 -8
- data/lib/mongo/server.rb +13 -6
- data/lib/mongo/server/connection.rb +15 -8
- data/lib/mongo/server/connection_base.rb +7 -4
- data/lib/mongo/server/description.rb +34 -21
- data/lib/mongo/server/monitor.rb +1 -1
- data/lib/mongo/server/monitor/connection.rb +2 -3
- data/lib/mongo/session.rb +10 -10
- data/lib/mongo/socket.rb +10 -1
- data/lib/mongo/uri.rb +1 -1
- data/lib/mongo/version.rb +1 -1
- data/mongo.gemspec +1 -1
- data/spec/README.md +13 -0
- data/spec/integration/auth_spec.rb +27 -8
- data/spec/integration/bson_symbol_spec.rb +34 -0
- data/spec/integration/client_construction_spec.rb +14 -0
- data/spec/integration/client_options_spec.rb +5 -5
- data/spec/integration/connection_spec.rb +57 -9
- data/spec/integration/crud_spec.rb +45 -0
- data/spec/integration/cursor_reaping_spec.rb +2 -1
- data/spec/integration/grid_fs_bucket_spec.rb +48 -0
- data/spec/integration/retryable_errors_spec.rb +204 -39
- data/spec/integration/retryable_writes_spec.rb +36 -36
- data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +98 -0
- data/spec/lite_spec_helper.rb +1 -0
- data/spec/mongo/address_spec.rb +19 -13
- data/spec/mongo/auth/ldap/conversation_spec.rb +1 -1
- data/spec/mongo/auth/scram/conversation_spec.rb +25 -14
- data/spec/mongo/auth/user/view_spec.rb +36 -1
- data/spec/mongo/auth/user_spec.rb +12 -0
- data/spec/mongo/auth/x509/conversation_spec.rb +1 -1
- data/spec/mongo/bulk_write_spec.rb +2 -2
- data/spec/mongo/client_construction_spec.rb +1 -21
- data/spec/mongo/cluster_spec.rb +57 -0
- data/spec/mongo/collection/view/map_reduce_spec.rb +1 -1
- data/spec/mongo/collection_spec.rb +26 -2
- data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +56 -0
- data/spec/mongo/server/connection_spec.rb +76 -8
- data/spec/mongo/server/monitor/connection_spec.rb +14 -7
- data/spec/mongo/socket/ssl_spec.rb +132 -98
- data/spec/mongo/socket/tcp_spec.rb +1 -9
- data/spec/mongo/uri_spec.rb +1 -1
- data/spec/runners/sdam/verifier.rb +91 -0
- data/spec/spec_tests/data/sdam/rs/primary_address_change.yml +29 -0
- data/spec/spec_tests/data/sdam/rs/primary_mismatched_me.yml +27 -23
- data/spec/spec_tests/data/sdam/rs/primary_to_no_primary_mismatched_me.yml +56 -79
- data/spec/spec_tests/data/sdam/sharded/primary_address_change.yml +21 -0
- data/spec/spec_tests/data/sdam/sharded/primary_mismatched_me.yml +22 -0
- data/spec/spec_tests/data/sdam/single/primary_address_change.yml +24 -0
- data/spec/spec_tests/data/sdam/single/primary_mismatched_me.yml +25 -0
- data/spec/spec_tests/data/sdam_monitoring/replica_set_with_me_mismatch.yml +159 -0
- data/spec/spec_tests/data/sdam_monitoring/{replica_set_other_seed.yml → replica_set_with_primary_change.yml} +97 -101
- data/spec/spec_tests/data/sdam_monitoring/replica_set_with_primary_removal.yml +22 -18
- data/spec/spec_tests/data/sdam_monitoring/standalone_to_rs_with_me_mismatch.yml +90 -0
- data/spec/spec_tests/sdam_monitoring_spec.rb +9 -4
- data/spec/support/cluster_config.rb +36 -0
- data/spec/support/cluster_tools.rb +5 -3
- data/spec/support/command_monitoring.rb +1 -1
- data/spec/support/constraints.rb +18 -18
- data/spec/support/lite_constraints.rb +8 -0
- data/spec/support/sdam_monitoring.rb +0 -115
- data/spec/support/server_discovery_and_monitoring.rb +2 -0
- data/spec/support/spec_config.rb +1 -1
- data/spec/support/utils.rb +11 -1
- metadata +687 -659
- metadata.gz.sig +3 -2
data/lib/mongo/auth/user.rb
CHANGED
@@ -151,6 +151,8 @@ 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.
|
154
156
|
# @option options [ Symbol ] :auth_mech The authorization mechanism.
|
155
157
|
# @option options [ Array<String>, Array<Hash> ] roles The user roles.
|
156
158
|
# @option options [ String ] :client_key The user's client key cached from a previous
|
@@ -196,7 +198,11 @@ module Mongo
|
|
196
198
|
#
|
197
199
|
# @since 2.0.0
|
198
200
|
def spec
|
199
|
-
{
|
201
|
+
{roles: roles}.tap do |spec|
|
202
|
+
if password
|
203
|
+
spec[:pwd] = password
|
204
|
+
end
|
205
|
+
end
|
200
206
|
end
|
201
207
|
|
202
208
|
private
|
data/lib/mongo/auth/x509.rb
CHANGED
@@ -20,6 +20,7 @@ module Mongo
|
|
20
20
|
# Defines behavior for X.509 authentication.
|
21
21
|
#
|
22
22
|
# @since 2.0.0
|
23
|
+
# @api private
|
23
24
|
class X509
|
24
25
|
|
25
26
|
# The authentication mechinism string.
|
@@ -67,7 +68,7 @@ module Mongo
|
|
67
68
|
conversation = Conversation.new(user)
|
68
69
|
reply = connection.dispatch([ conversation.start(connection) ])
|
69
70
|
connection.update_cluster_time(Operation::Result.new(reply))
|
70
|
-
conversation.finalize(reply)
|
71
|
+
conversation.finalize(reply, connection)
|
71
72
|
end
|
72
73
|
end
|
73
74
|
end
|
@@ -42,26 +42,26 @@ module Mongo
|
|
42
42
|
#
|
43
43
|
# @param [ Protocol::Message ] reply The reply of the previous
|
44
44
|
# message.
|
45
|
+
# @param [ Server::Connection ] connection The connection being
|
46
|
+
# authenticated.
|
45
47
|
#
|
46
48
|
# @return [ Protocol::Query ] The next message to send.
|
47
49
|
#
|
48
50
|
# @since 2.0.0
|
49
|
-
def finalize(reply)
|
50
|
-
validate!(reply)
|
51
|
+
def finalize(reply, connection)
|
52
|
+
validate!(reply, connection.server)
|
51
53
|
end
|
52
54
|
|
53
55
|
# Start the X.509 conversation. This returns the first message that
|
54
56
|
# needs to be sent to the server.
|
55
57
|
#
|
56
|
-
# @
|
57
|
-
#
|
58
|
-
#
|
59
|
-
# @param [ Mongo::Server::Connection ] connection The connection being authenticated.
|
58
|
+
# @param [ Server::Connection ] connection The connection being
|
59
|
+
# authenticated.
|
60
60
|
#
|
61
61
|
# @return [ Protocol::Query ] The first X.509 conversation message.
|
62
62
|
#
|
63
63
|
# @since 2.0.0
|
64
|
-
def start(connection
|
64
|
+
def start(connection)
|
65
65
|
login = LOGIN.merge(mechanism: X509::MECHANISM)
|
66
66
|
login[:user] = user.name if user.name
|
67
67
|
if connection && connection.features.op_msg_enabled?
|
@@ -103,9 +103,9 @@ module Mongo
|
|
103
103
|
|
104
104
|
private
|
105
105
|
|
106
|
-
def validate!(reply)
|
106
|
+
def validate!(reply, server)
|
107
107
|
if reply.documents[0][Operation::Result::OK] != 1
|
108
|
-
raise Unauthorized.new(user, used_mechanism: MECHANISM)
|
108
|
+
raise Unauthorized.new(user, used_mechanism: MECHANISM, server: server)
|
109
109
|
end
|
110
110
|
@reply = reply
|
111
111
|
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[
|
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[
|
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[
|
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
@@ -756,8 +756,8 @@ module Mongo
|
|
756
756
|
#
|
757
757
|
# @since 2.5.0
|
758
758
|
def start_session(options = {})
|
759
|
-
|
760
|
-
|
759
|
+
get_session(options.merge(implicit: false)) or
|
760
|
+
raise Error::InvalidSession.new(Session::SESSIONS_NOT_SUPPORTED)
|
761
761
|
end
|
762
762
|
|
763
763
|
# As of version 3.6 of the MongoDB server, a ``$changeStream`` pipeline stage is supported
|
@@ -827,14 +827,25 @@ module Mongo
|
|
827
827
|
# The session is implicit unless options[:implicit] is given.
|
828
828
|
# If deployment does not support session, returns nil.
|
829
829
|
#
|
830
|
-
# @
|
831
|
-
#
|
830
|
+
# @return [ Session | nil ] Session object or nil if sessions are not
|
831
|
+
# supported by the deployment.
|
832
832
|
def get_session(options = {})
|
833
|
-
|
833
|
+
if options[:session]
|
834
|
+
return options[:session].validate!(self)
|
835
|
+
end
|
836
|
+
|
837
|
+
if cluster.sessions_supported?
|
838
|
+
Session.new(cluster.session_pool.checkout, self, { implicit: true }.merge(options))
|
839
|
+
end
|
834
840
|
end
|
835
841
|
|
836
842
|
def with_session(options = {}, &block)
|
837
|
-
|
843
|
+
session = get_session(options)
|
844
|
+
yield(session)
|
845
|
+
ensure
|
846
|
+
if session && session.implicit?
|
847
|
+
session.end_session
|
848
|
+
end
|
838
849
|
end
|
839
850
|
|
840
851
|
def initialize_copy(original)
|
data/lib/mongo/cluster.rb
CHANGED
@@ -109,6 +109,8 @@ module Mongo
|
|
109
109
|
options[:cleanup] = false
|
110
110
|
end
|
111
111
|
|
112
|
+
seeds = seeds.uniq
|
113
|
+
|
112
114
|
@servers = []
|
113
115
|
@monitoring = monitoring
|
114
116
|
@event_listeners = Event::Listeners.new
|
@@ -162,12 +164,9 @@ module Mongo
|
|
162
164
|
return
|
163
165
|
end
|
164
166
|
|
165
|
-
#
|
166
|
-
|
167
|
-
|
168
|
-
servers.each do |server|
|
169
|
-
server.start_monitoring
|
170
|
-
end
|
167
|
+
# Update instance variables prior to starting monitoring threads.
|
168
|
+
@connecting = false
|
169
|
+
@connected = true
|
171
170
|
|
172
171
|
if options[:cleanup] != false
|
173
172
|
@cursor_reaper = CursorReaper.new
|
@@ -182,8 +181,12 @@ module Mongo
|
|
182
181
|
@periodic_executor.run!
|
183
182
|
end
|
184
183
|
|
185
|
-
|
186
|
-
|
184
|
+
# Need to record start time prior to starting monitoring
|
185
|
+
start_time = Time.now
|
186
|
+
|
187
|
+
servers.each do |server|
|
188
|
+
server.start_monitoring
|
189
|
+
end
|
187
190
|
|
188
191
|
if options[:scan] != false
|
189
192
|
server_selection_timeout = options[:server_selection_timeout] || ServerSelector::SERVER_SELECTION_TIMEOUT
|
@@ -743,30 +746,49 @@ module Mongo
|
|
743
746
|
# server.remove('127.0.0.1:27017')
|
744
747
|
#
|
745
748
|
# @param [ String ] host The host/port or socket address.
|
749
|
+
# @param [ true | false ] disconnect Whether to disconnect the servers
|
750
|
+
# being removed. For internal driver use only.
|
751
|
+
#
|
752
|
+
# @return [ Array<Server> | true | false ] If disconnect is any value other
|
753
|
+
# than false, including nil, returns whether any servers were removed.
|
754
|
+
# If disconnect is false, returns an array of servers that were removed
|
755
|
+
# (and should be disconnected by the caller).
|
746
756
|
#
|
747
|
-
# @return
|
757
|
+
# @note The return value of this method is not part of the driver's
|
758
|
+
# public API.
|
748
759
|
#
|
749
|
-
# @since 2.0.0
|
750
|
-
def remove(host)
|
760
|
+
# @since 2.0.0
|
761
|
+
def remove(host, disconnect: true)
|
751
762
|
address = Address.new(host)
|
752
763
|
removed_servers = @servers.select { |s| s.address == address }
|
753
764
|
@update_lock.synchronize { @servers = @servers - removed_servers }
|
754
|
-
|
755
|
-
|
756
|
-
server
|
757
|
-
publish_sdam_event(
|
758
|
-
Monitoring::SERVER_CLOSED,
|
759
|
-
Monitoring::Event::ServerClosed.new(address, topology)
|
760
|
-
)
|
765
|
+
if disconnect != false
|
766
|
+
removed_servers.each do |server|
|
767
|
+
disconnect_server_if_connected(server)
|
761
768
|
end
|
762
769
|
end
|
763
|
-
|
770
|
+
if disconnect != false
|
771
|
+
removed_servers.any?
|
772
|
+
else
|
773
|
+
removed_servers
|
774
|
+
end
|
764
775
|
end
|
765
776
|
|
766
777
|
# @api private
|
767
778
|
def update_topology(new_topology)
|
768
779
|
old_topology = topology
|
769
780
|
@topology = new_topology
|
781
|
+
|
782
|
+
# If new topology has data bearing servers, we know for sure whether
|
783
|
+
# sessions are supported - update our cached value.
|
784
|
+
# If new topology has no data bearing servers, leave the old value
|
785
|
+
# as it is and sessions_supported? method will perform server selection
|
786
|
+
# to try to determine session support accurately, falling back to the
|
787
|
+
# last known value.
|
788
|
+
if topology.data_bearing_servers?
|
789
|
+
@sessions_supported = !!topology.logical_session_timeout
|
790
|
+
end
|
791
|
+
|
770
792
|
publish_sdam_event(
|
771
793
|
Monitoring::TOPOLOGY_CHANGED,
|
772
794
|
Monitoring::Event::TopologyChanged.new(old_topology, topology)
|
@@ -778,53 +800,49 @@ module Mongo
|
|
778
800
|
@update_lock.synchronize { @servers.dup }
|
779
801
|
end
|
780
802
|
|
781
|
-
private
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
# servers at the time of the call.
|
790
|
-
def get_session(client, options = {})
|
791
|
-
return options[:session].validate!(self) if options[:session]
|
792
|
-
if sessions_supported?
|
793
|
-
Session.new(@session_pool.checkout, client, { implicit: true }.merge(options))
|
803
|
+
# @api private
|
804
|
+
def disconnect_server_if_connected(server)
|
805
|
+
if server.connected?
|
806
|
+
server.disconnect!
|
807
|
+
publish_sdam_event(
|
808
|
+
Monitoring::SERVER_CLOSED,
|
809
|
+
Monitoring::Event::ServerClosed.new(server.address, topology)
|
810
|
+
)
|
794
811
|
end
|
795
812
|
end
|
796
813
|
|
797
|
-
|
798
|
-
|
799
|
-
yield(session)
|
800
|
-
ensure
|
801
|
-
session.end_session if (session && session.implicit?)
|
802
|
-
end
|
803
|
-
|
804
|
-
# Returns whether the deployment (as this term is defined in the sessions
|
805
|
-
# spec) supports sessions.
|
814
|
+
# Returns whether the deployment that the driver is connected to supports
|
815
|
+
# sessions.
|
806
816
|
#
|
807
|
-
#
|
808
|
-
#
|
809
|
-
#
|
817
|
+
# Session support may change over time, for example due to servers in the
|
818
|
+
# deployment being upgraded or downgraded. This method returns the
|
819
|
+
# current information if the client is connected to at least one data
|
820
|
+
# bearing server. If the client is currently not connected to any data
|
821
|
+
# bearing servers, this method returns the last known value for whether
|
822
|
+
# the deployment supports sessions.
|
810
823
|
#
|
811
|
-
# @
|
812
|
-
#
|
813
|
-
# can change depending on how many servers have been contacted, if
|
814
|
-
# the servers are configured differently.
|
824
|
+
# @return [ true | false ] Whether deployment supports sessions.
|
825
|
+
# @api private
|
815
826
|
def sessions_supported?
|
816
827
|
if topology.data_bearing_servers?
|
817
828
|
return !!topology.logical_session_timeout
|
818
829
|
end
|
819
830
|
|
831
|
+
# No data bearing servers known - perform server selection to try to
|
832
|
+
# get a response from at least one of them, to return an accurate
|
833
|
+
# assessment of whether sessions are currently supported.
|
820
834
|
begin
|
821
835
|
ServerSelector.get(mode: :primary_preferred).select_server(self)
|
822
836
|
!!topology.logical_session_timeout
|
823
837
|
rescue Error::NoServerAvailable
|
824
|
-
|
838
|
+
# We haven't been able to contact any servers - use last known
|
839
|
+
# value for esssion support.
|
840
|
+
@sessions_supported || false
|
825
841
|
end
|
826
842
|
end
|
827
843
|
|
844
|
+
private
|
845
|
+
|
828
846
|
# @api private
|
829
847
|
def start_stop_srv_monitor
|
830
848
|
# SRV URI is either always given or not for a given cluster, if one
|
@@ -30,6 +30,7 @@ class Mongo::Cluster
|
|
30
30
|
@topology = cluster.topology
|
31
31
|
@original_desc = @previous_desc = previous_desc
|
32
32
|
@updated_desc = updated_desc
|
33
|
+
@servers_to_disconnect = []
|
33
34
|
end
|
34
35
|
|
35
36
|
attr_reader :cluster
|
@@ -73,6 +74,60 @@ class Mongo::Cluster
|
|
73
74
|
end
|
74
75
|
|
75
76
|
def server_description_changed
|
77
|
+
if updated_desc.me_mismatch? && updated_desc.primary? &&
|
78
|
+
(topology.unknown? || topology.replica_set?)
|
79
|
+
then
|
80
|
+
# When the driver receives a description claiming to be a primary,
|
81
|
+
# we are obligated by spec tests to add and remove hosts in that
|
82
|
+
# description even if it also has a me mismatch. The me mismatch
|
83
|
+
# scenario though presents a number of problems:
|
84
|
+
#
|
85
|
+
# 1. Effectively, the server's address changes, meaning we cannot
|
86
|
+
# update the description of the server whose description change we
|
87
|
+
# are processing (instead servers are added and removed), but we
|
88
|
+
# behave to an extent as if we are updating the description, which
|
89
|
+
# causes a bunch of awkwardness.
|
90
|
+
# 2. The server for which we are processing the response will be
|
91
|
+
# removed from topology, which may cause the current thread to terminate
|
92
|
+
# prior to running the entire sdam flow. To deal with this we separate
|
93
|
+
# the removal event publication from actually removing the server
|
94
|
+
# from topology, which again complicates the flow.
|
95
|
+
|
96
|
+
# Primary-with-me-mismatch response could be the first one we receive
|
97
|
+
# when the topology is still unknown. Change to RS without primary
|
98
|
+
# in this case.
|
99
|
+
if topology.unknown?
|
100
|
+
@topology = Topology::ReplicaSetNoPrimary.new(
|
101
|
+
topology.options.merge(replica_set_name: updated_desc.replica_set_name),
|
102
|
+
topology.monitoring, self)
|
103
|
+
end
|
104
|
+
|
105
|
+
servers = add_servers_from_desc(updated_desc)
|
106
|
+
# Spec tests require us to remove servers based on data in descrptions
|
107
|
+
# with me mismatches. The driver will be more resilient if it only
|
108
|
+
# removed servers from descriptions with matching mes.
|
109
|
+
remove_servers_not_in_desc(updated_desc)
|
110
|
+
|
111
|
+
servers.each do |server|
|
112
|
+
server.start_monitoring
|
113
|
+
end
|
114
|
+
|
115
|
+
# The rest of sdam flow assumes the server being removed is not the one
|
116
|
+
# whose description we are processing, and publishes description update
|
117
|
+
# event. Since we are removing the server whose response we are
|
118
|
+
# processing, do not publish description change event but mark it
|
119
|
+
# published (by assigning to @previous_desc).
|
120
|
+
do_remove(updated_desc.address.to_s)
|
121
|
+
@previous_desc = updated_desc
|
122
|
+
|
123
|
+
# We may have removed the current primary, check if there is a primary.
|
124
|
+
check_if_has_primary
|
125
|
+
# Publish topology change event.
|
126
|
+
commit_changes
|
127
|
+
disconnect_servers
|
128
|
+
return
|
129
|
+
end
|
130
|
+
|
76
131
|
unless update_server_descriptions
|
77
132
|
# All of the transitions require that server whose updated_desc we are
|
78
133
|
# processing is still in the cluster (i.e., was not removed as a result
|
@@ -142,6 +197,7 @@ class Mongo::Cluster
|
|
142
197
|
end
|
143
198
|
|
144
199
|
commit_changes
|
200
|
+
disconnect_servers
|
145
201
|
end
|
146
202
|
|
147
203
|
# Transitions from unknown to single topology type, when a standalone
|
@@ -337,9 +393,14 @@ class Mongo::Cluster
|
|
337
393
|
end.flatten
|
338
394
|
servers_list.each do |server|
|
339
395
|
unless updated_desc_address_strs.include?(address_str = server.address.to_s)
|
396
|
+
updated_host = updated_desc.address.to_s
|
397
|
+
if updated_desc.me && updated_desc.me != updated_host
|
398
|
+
updated_host += " (self-identified as #{updated_desc.me})"
|
399
|
+
end
|
340
400
|
log_warn(
|
341
401
|
"Removing server #{address_str} because it is not in hosts reported by primary " +
|
342
|
-
"#{
|
402
|
+
"#{updated_host}. Reported hosts are: " +
|
403
|
+
updated_desc.hosts.join(', ')
|
343
404
|
)
|
344
405
|
do_remove(address_str)
|
345
406
|
end
|
@@ -356,7 +417,21 @@ class Mongo::Cluster
|
|
356
417
|
# Removes specified server from topology and warns if the topology ends
|
357
418
|
# up with an empty server list as a result
|
358
419
|
def do_remove(address_str)
|
359
|
-
cluster.remove(address_str)
|
420
|
+
servers = cluster.remove(address_str, disconnect: false)
|
421
|
+
servers.each do |server|
|
422
|
+
# We need to publish server closed event here, but we cannot close
|
423
|
+
# the server because it could be the server owning the monitor in
|
424
|
+
# whose thread this flow is presently executing, in which case closing
|
425
|
+
# the server can terminate the thread and leave SDAM processing
|
426
|
+
# incomplete. Thus we have to remove the server from the cluster,
|
427
|
+
# publish the event, but do not call disconnect on the server until
|
428
|
+
# the very end when all processing has completed.
|
429
|
+
publish_sdam_event(
|
430
|
+
Mongo::Monitoring::SERVER_CLOSED,
|
431
|
+
Mongo::Monitoring::Event::ServerClosed.new(server.address, cluster.topology)
|
432
|
+
)
|
433
|
+
end
|
434
|
+
@servers_to_disconnect += servers
|
360
435
|
if servers_list.empty?
|
361
436
|
log_warn(
|
362
437
|
"Topology now has no servers - this is likely a misconfiguration of the cluster and/or the application"
|
@@ -451,6 +526,15 @@ class Mongo::Cluster
|
|
451
526
|
cluster.update_topology(topology)
|
452
527
|
end
|
453
528
|
|
529
|
+
def disconnect_servers
|
530
|
+
while server = @servers_to_disconnect.shift
|
531
|
+
if server.connected?
|
532
|
+
# Do not publish server closed event, as this was already done
|
533
|
+
server.disconnect!
|
534
|
+
end
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
454
538
|
# If the server being processed is identified as data bearing, creates the
|
455
539
|
# server's connection pool so it can start populating
|
456
540
|
def start_pool_if_data_bearing
|
@@ -468,7 +552,7 @@ class Mongo::Cluster
|
|
468
552
|
# invoking this method.
|
469
553
|
def check_if_has_primary
|
470
554
|
unless topology.replica_set?
|
471
|
-
raise ArgumentError,
|
555
|
+
raise ArgumentError, "check_if_has_primary should only be called when topology is replica set, but it is #{topology.class.name.sub(/.*::/, '')}"
|
472
556
|
end
|
473
557
|
|
474
558
|
primary = servers_list.detect do |server|
|