mongo 2.11.0 → 2.11.5
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.
- 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|
|