Skip to content

Commit 816539f

Browse files
committed
Clear server pool when a server is marked unknown
1 parent 04ca01a commit 816539f

File tree

5 files changed

+57
-15
lines changed

5 files changed

+57
-15
lines changed

lib/mongo/cluster.rb

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,18 +502,42 @@ def scan!(sync=true)
502502
true
503503
end
504504

505+
# Runs SDAM flow on the cluster.
506+
#
507+
# This method can be invoked to process a new server description returned
508+
# by the server on a monitoring or non-monitoring connection, and also
509+
# by the driver when it marks a server unknown as a result of a (network)
510+
# error.
511+
#
505512
# @param [ Server::Description ] previous_desc Previous server description.
506513
# @param [ Server::Description ] updated_desc The changed description.
514+
# @param [ Hash ] options Options.
515+
#
516+
# @option options [ true | false ] :keep_connection_pool Usually when the
517+
# new server description is unknown, the connection pool on the
518+
# respective server is cleared. Set this option to true to keep the
519+
# existing connection pool (required when handling not master errors
520+
# on 4.2+ servers).
507521
#
508522
# @api private
509-
def run_sdam_flow(previous_desc, updated_desc)
523+
def run_sdam_flow(previous_desc, updated_desc, options = {})
510524
@sdam_flow_lock.synchronize do
511525
flow = SdamFlow.new(self, previous_desc, updated_desc)
512526
flow.server_description_changed
513527

514528
# SDAM flow may alter the updated description - grab the final
515529
# version for the purposes of broadcasting if a server is available
516530
updated_desc = flow.updated_desc
531+
532+
unless options[:keep_connection_pool]
533+
if flow.became_unknown?
534+
servers_list.each do |server|
535+
if server.address == updated_desc.address
536+
server.clear_connection_pool
537+
end
538+
end
539+
end
540+
end
517541
end
518542

519543
# Some updated descriptions, e.g. a mismatched me one, result in the

lib/mongo/cluster/sdam_flow.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class SdamFlow
2828
def initialize(cluster, previous_desc, updated_desc)
2929
@cluster = cluster
3030
@topology = cluster.topology
31-
@previous_desc = previous_desc
31+
@original_desc = @previous_desc = previous_desc
3232
@updated_desc = updated_desc
3333
end
3434

@@ -48,6 +48,7 @@ def initialize(cluster, previous_desc, updated_desc)
4848

4949
attr_reader :previous_desc
5050
attr_reader :updated_desc
51+
attr_reader :original_desc
5152

5253
def_delegators :topology, :replica_set_name
5354

@@ -490,5 +491,12 @@ def stale_primary?
490491
end
491492
false
492493
end
494+
495+
# Returns whether the server whose description this flow processed
496+
# was not previously unknown, and is now. Used to decide, in particular,
497+
# whether to clear the server's connection pool.
498+
def became_unknown?
499+
updated_desc.unknown? && !original_desc.unknown?
500+
end
493501
end
494502
end

lib/mongo/operation/shared/executable.rb

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,13 @@ def process_result(result, server)
6262

6363
if result.not_master? || result.node_recovering?
6464
if result.node_shutting_down?
65-
disconnect_pool = true
65+
keep_pool = false
6666
else
67-
# Max wire version needs to be checked prior to marking the
68-
# server unknown
69-
disconnect_pool = !server.description.server_version_gte?('4.2')
67+
# Max wire version needs to be examined while the server is known
68+
keep_pool = server.description.server_version_gte?('4.2')
7069
end
7170

72-
server.unknown!
73-
74-
if disconnect_pool
75-
server.pool.disconnect!
76-
end
71+
server.unknown!(keep_connection_pool: keep_pool)
7772

7873
server.scan_semaphore.signal
7974
end

lib/mongo/server.rb

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,6 @@ def handle_auth_failure!
432432
rescue Mongo::Error::SocketError
433433
# non-timeout network error
434434
unknown!
435-
pool.disconnect!
436435
raise
437436
rescue Auth::Unauthorized
438437
# auth error, keep server description and topology as they are
@@ -465,18 +464,35 @@ def retry_writes?
465464
# Marks server unknown and publishes the associated SDAM event
466465
# (server description changed).
467466
#
467+
# @param [ Hash ] options Options.
468+
#
469+
# @option options [ true | false ] :keep_connection_pool Usually when the
470+
# new server description is unknown, the connection pool on the
471+
# respective server is cleared. Set this option to true to keep the
472+
# existing connection pool (required when handling not master errors
473+
# on 4.2+ servers).
474+
#
468475
# @since 2.4.0, SDAM events are sent as of version 2.7.0
469-
def unknown!
476+
def unknown!(options = {})
470477
# SDAM flow will update description on the server without in-place
471478
# mutations and invoke SDAM transitions as needed.
472-
cluster.run_sdam_flow(description, Description.new(address))
479+
cluster.run_sdam_flow(description, Description.new(address), options)
473480
end
474481

475482
# @api private
476483
def update_description(description)
477484
@description = description
478485
end
479486

487+
# @api private
488+
def clear_connection_pool
489+
@pool_lock.synchronize do
490+
if @pool
491+
@pool.disconnect!
492+
end
493+
end
494+
end
495+
480496
# @api private
481497
def next_connection_id
482498
@connection_id_gen.next_id

lib/mongo/server/connection.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,6 @@ def deliver(message)
384384
# Important: timeout errors are not handled here
385385
rescue Error::SocketError
386386
@server.unknown!
387-
@server.pool.disconnect!
388387
raise
389388
end
390389
end

0 commit comments

Comments
 (0)