mongo 2.4.0.rc1 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/mongo/auth/cr/conversation.rb +1 -1
  5. data/lib/mongo/auth/ldap/conversation.rb +1 -1
  6. data/lib/mongo/auth/scram/conversation.rb +1 -1
  7. data/lib/mongo/auth/x509/conversation.rb +4 -2
  8. data/lib/mongo/client.rb +7 -4
  9. data/lib/mongo/cluster.rb +55 -5
  10. data/lib/mongo/cluster/app_metadata.rb +7 -1
  11. data/lib/mongo/cluster/topology.rb +7 -6
  12. data/lib/mongo/cluster/topology/replica_set.rb +48 -2
  13. data/lib/mongo/cluster/topology/sharded.rb +47 -1
  14. data/lib/mongo/cluster/topology/single.rb +55 -4
  15. data/lib/mongo/cluster/topology/unknown.rb +65 -9
  16. data/lib/mongo/error/invalid_server_preference.rb +3 -1
  17. data/lib/mongo/event.rb +8 -0
  18. data/lib/mongo/event/description_changed.rb +20 -2
  19. data/lib/mongo/event/member_discovered.rb +65 -0
  20. data/lib/mongo/event/primary_elected.rb +3 -1
  21. data/lib/mongo/event/standalone_discovered.rb +1 -1
  22. data/lib/mongo/monitoring.rb +41 -0
  23. data/lib/mongo/monitoring/event.rb +6 -0
  24. data/lib/mongo/monitoring/event/server_closed.rb +46 -0
  25. data/lib/mongo/monitoring/event/server_description_changed.rb +58 -0
  26. data/lib/mongo/monitoring/event/server_opening.rb +46 -0
  27. data/lib/mongo/monitoring/event/topology_changed.rb +46 -0
  28. data/lib/mongo/monitoring/event/topology_closed.rb +41 -0
  29. data/lib/mongo/monitoring/event/topology_opening.rb +41 -0
  30. data/lib/mongo/monitoring/publishable.rb +12 -0
  31. data/lib/mongo/monitoring/sdam_log_subscriber.rb +54 -0
  32. data/lib/mongo/monitoring/server_closed_log_subscriber.rb +30 -0
  33. data/lib/mongo/monitoring/server_description_changed_log_subscriber.rb +33 -0
  34. data/lib/mongo/monitoring/server_opening_log_subscriber.rb +30 -0
  35. data/lib/mongo/monitoring/topology_changed_log_subscriber.rb +40 -0
  36. data/lib/mongo/monitoring/topology_opening_log_subscriber.rb +30 -0
  37. data/lib/mongo/server.rb +6 -0
  38. data/lib/mongo/server/connection.rb +1 -1
  39. data/lib/mongo/server/description.rb +23 -3
  40. data/lib/mongo/server/description/inspector.rb +4 -2
  41. data/lib/mongo/server/description/inspector/description_changed.rb +2 -2
  42. data/lib/mongo/server/description/inspector/member_discovered.rb +59 -0
  43. data/lib/mongo/server/description/inspector/primary_elected.rb +2 -0
  44. data/lib/mongo/server_selector.rb +10 -5
  45. data/lib/mongo/server_selector/nearest.rb +1 -1
  46. data/lib/mongo/server_selector/primary_preferred.rb +1 -1
  47. data/lib/mongo/server_selector/secondary.rb +1 -1
  48. data/lib/mongo/server_selector/secondary_preferred.rb +1 -1
  49. data/lib/mongo/server_selector/selectable.rb +24 -12
  50. data/lib/mongo/uri.rb +1 -1
  51. data/lib/mongo/version.rb +1 -1
  52. data/mongo.gemspec +1 -1
  53. data/spec/mongo/auth/cr_spec.rb +6 -1
  54. data/spec/mongo/auth/ldap_spec.rb +6 -1
  55. data/spec/mongo/auth/scram_spec.rb +6 -1
  56. data/spec/mongo/auth/x509/conversation_spec.rb +69 -0
  57. data/spec/mongo/auth/x509_spec.rb +9 -4
  58. data/spec/mongo/client_spec.rb +40 -2
  59. data/spec/mongo/cluster/topology/replica_set_spec.rb +218 -9
  60. data/spec/mongo/cluster/topology/sharded_spec.rb +17 -2
  61. data/spec/mongo/cluster/topology/single_spec.rb +19 -4
  62. data/spec/mongo/cluster/topology/unknown_spec.rb +19 -1
  63. data/spec/mongo/cluster/topology_spec.rb +11 -7
  64. data/spec/mongo/cluster_spec.rb +25 -7
  65. data/spec/mongo/max_staleness_spec.rb +40 -22
  66. data/spec/mongo/monitoring_spec.rb +2 -2
  67. data/spec/mongo/sdam_monitoring_spec.rb +60 -0
  68. data/spec/mongo/sdam_spec.rb +77 -0
  69. data/spec/mongo/server/connection_pool_spec.rb +6 -1
  70. data/spec/mongo/server/connection_spec.rb +6 -1
  71. data/spec/mongo/server/description_spec.rb +90 -1
  72. data/spec/mongo/server_selection_spec.rb +7 -6
  73. data/spec/mongo/server_selector/nearest_spec.rb +7 -7
  74. data/spec/mongo/server_selector/primary_preferred_spec.rb +7 -7
  75. data/spec/mongo/server_selector/primary_spec.rb +4 -4
  76. data/spec/mongo/server_selector/secondary_preferred_spec.rb +6 -6
  77. data/spec/mongo/server_selector/secondary_spec.rb +6 -6
  78. data/spec/mongo/server_selector_spec.rb +8 -0
  79. data/spec/mongo/server_spec.rb +6 -1
  80. data/spec/mongo/uri_spec.rb +4 -4
  81. data/spec/spec_helper.rb +2 -0
  82. data/spec/support/max_staleness/ReplicaSetNoPrimary/Incompatible.yml +4 -4
  83. data/spec/support/max_staleness/ReplicaSetNoPrimary/LastUpdateTime.yml +3 -3
  84. data/spec/support/max_staleness/ReplicaSetNoPrimary/Nearest.yml +3 -3
  85. data/spec/support/max_staleness/ReplicaSetNoPrimary/Nearest2.yml +3 -3
  86. data/spec/support/max_staleness/ReplicaSetNoPrimary/NoKnownServers.yml +15 -0
  87. data/spec/support/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred.yml +1 -1
  88. data/spec/support/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred_tags.yml +3 -3
  89. data/spec/support/max_staleness/ReplicaSetNoPrimary/Secondary.yml +3 -3
  90. data/spec/support/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred.yml +1 -1
  91. data/spec/support/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred_tags.yml +3 -3
  92. data/spec/support/max_staleness/ReplicaSetNoPrimary/ZeroMaxStaleness.yml +23 -0
  93. data/spec/support/max_staleness/ReplicaSetWithPrimary/Incompatible.yml +4 -4
  94. data/spec/support/max_staleness/ReplicaSetWithPrimary/LastUpdateTime.yml +5 -5
  95. data/spec/support/max_staleness/ReplicaSetWithPrimary/{ShortHeartbeartShortMaxStaleness2.yml → LongHeartbeat.yml} +4 -4
  96. data/spec/support/max_staleness/ReplicaSetWithPrimary/{ShortHeartbeartShortMaxStaleness.yml → LongHeartbeat2.yml} +6 -10
  97. data/spec/support/max_staleness/ReplicaSetWithPrimary/MaxStalenessTooSmall.yml +3 -2
  98. data/spec/support/max_staleness/ReplicaSetWithPrimary/MaxStalenessWithModePrimary.yml +2 -2
  99. data/spec/support/max_staleness/ReplicaSetWithPrimary/Nearest.yml +3 -3
  100. data/spec/support/max_staleness/ReplicaSetWithPrimary/Nearest2.yml +3 -3
  101. data/spec/support/max_staleness/ReplicaSetWithPrimary/Nearest_tags.yml +3 -3
  102. data/spec/support/max_staleness/ReplicaSetWithPrimary/PrimaryPreferred.yml +2 -2
  103. data/spec/support/max_staleness/ReplicaSetWithPrimary/PrimaryPreferred_incompatible.yml +3 -3
  104. data/spec/support/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred.yml +1 -1
  105. data/spec/support/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags.yml +3 -3
  106. data/spec/support/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags2.yml +3 -3
  107. data/spec/support/max_staleness/ReplicaSetWithPrimary/Secondary_tags.yml +3 -3
  108. data/spec/support/max_staleness/ReplicaSetWithPrimary/Secondary_tags2.yml +3 -3
  109. data/spec/support/max_staleness/ReplicaSetWithPrimary/ZeroMaxStaleness.yml +7 -11
  110. data/spec/support/max_staleness/Sharded/Incompatible.yml +4 -4
  111. data/spec/support/max_staleness/Sharded/SmallMaxStaleness.yml +10 -2
  112. data/spec/support/max_staleness/Single/Incompatible.yml +4 -4
  113. data/spec/support/max_staleness/Single/SmallMaxStaleness.yml +2 -2
  114. data/spec/support/max_staleness/Unknown/SmallMaxStaleness.yml +14 -0
  115. data/spec/support/sdam/rs/primary_mismatched_me.yml +2 -2
  116. data/spec/support/sdam/rs/secondary_mismatched_me.yml +2 -2
  117. data/spec/support/sdam_monitoring.rb +144 -0
  118. data/spec/support/sdam_monitoring/replica_set_with_no_primary.yml +112 -0
  119. data/spec/support/sdam_monitoring/replica_set_with_primary.yml +111 -0
  120. data/spec/support/sdam_monitoring/replica_set_with_removal.yml +106 -0
  121. data/spec/support/sdam_monitoring/required_replica_set.yml +84 -0
  122. data/spec/support/sdam_monitoring/standalone.yml +70 -0
  123. data/spec/support/server_discovery_and_monitoring.rb +34 -1
  124. data/spec/support/server_selection.rb +14 -11
  125. data/spec/support/shared/server_selector.rb +6 -0
  126. metadata +49 -13
  127. metadata.gz.sig +0 -0
  128. data/spec/mongo/server_discovery_and_monitoring_spec.rb +0 -115
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0fceb612725957e97b29a1b35a376821d685dea7
4
- data.tar.gz: 3f1ee5867327a164aa2bff5e00a517387df406e0
3
+ metadata.gz: 18d9f304edd2e651c1dfde03646f780951e4d068
4
+ data.tar.gz: d7bc0adaa7a4dc5eb8f319caafb1a98fd1357233
5
5
  SHA512:
6
- metadata.gz: 70a87aadb4c5f8a31582dfada8c8810a4a71d8c7b59fd4fda010f2d680a8d555a2401e190e37d37106f268d40019e67926a7cb48ae33f5937d90b5227e9b29af
7
- data.tar.gz: c6d42e01149a0140f59494999d98e69a3f7df8480fc5fac6054d518fca9d80fa58278e3529a8b9e7274ef069080d4e5f07cf1aae72e3119c90527465268b01b1
6
+ metadata.gz: 83e651334a083f7acb5e11c9c7cb650a8ce13ab3f7fb10ee4a839e05d7d2edca3adcdb3aeae3b795771b3c8b370772471565a0812cbdf30754c8a50b7e5c217a
7
+ data.tar.gz: 34db7e14619cc5b08235fff572034a19c282c982439f6feb7d3769ed5c402b05c60029309fc877d3505e8df6de31baee0519b4ebd6e36bfdeae926807f9e146b
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -98,7 +98,7 @@ module Mongo
98
98
 
99
99
  # Create the new conversation.
100
100
  #
101
- # @example Create the new coversation.
101
+ # @example Create the new conversation.
102
102
  # Conversation.new(user, "admin")
103
103
  #
104
104
  # @param [ Auth::User ] user The user to converse about.
@@ -70,7 +70,7 @@ module Mongo
70
70
 
71
71
  # Create the new conversation.
72
72
  #
73
- # @example Create the new coversation.
73
+ # @example Create the new conversation.
74
74
  # Conversation.new(user, "admin")
75
75
  #
76
76
  # @param [ Auth::User ] user The user to converse about.
@@ -172,7 +172,7 @@ module Mongo
172
172
 
173
173
  # Create the new conversation.
174
174
  #
175
- # @example Create the new coversation.
175
+ # @example Create the new conversation.
176
176
  # Conversation.new(user)
177
177
  #
178
178
  # @param [ Auth::User ] user The user to converse about.
@@ -60,17 +60,19 @@ module Mongo
60
60
  #
61
61
  # @since 2.0.0
62
62
  def start
63
+ login = LOGIN.merge(mechanism: X509::MECHANISM)
64
+ login[:user] = user.name if user.name
63
65
  Protocol::Query.new(
64
66
  Auth::EXTERNAL,
65
67
  Database::COMMAND,
66
- LOGIN.merge(user: user.name, mechanism: X509::MECHANISM),
68
+ login,
67
69
  limit: -1
68
70
  )
69
71
  end
70
72
 
71
73
  # Create the new conversation.
72
74
  #
73
- # @example Create the new coversation.
75
+ # @example Create the new conversation.
74
76
  # Conversation.new(user, "admin")
75
77
  #
76
78
  # @param [ Auth::User ] user The user to converse about.
@@ -48,6 +48,7 @@ module Mongo
48
48
  :min_pool_size,
49
49
  :monitoring,
50
50
  :password,
51
+ :platform,
51
52
  :read,
52
53
  :read_retry_interval,
53
54
  :replica_set,
@@ -200,10 +201,10 @@ module Mongo
200
201
  # certification authority certifications used to validate certs passed from the
201
202
  # other end of the connection. One of :ssl_ca_cert, :ssl_ca_cert_string or
202
203
  # :ssl_ca_cert_object (in order of priority) is required for :ssl_verify.
203
- # @option options [ Array<OpenSSL::X509::Certificate> ] :ssl_ca_cert_object An array of OpenSSL::X509::Certificate
204
- # reprenting the certification authority certifications used to validate certs passed from the
205
- # other end of the connection. One of :ssl_ca_cert, :ssl_ca_cert_string or
206
- # :ssl_ca_cert_object (in order of priority) is required for :ssl_verify.
204
+ # @option options [ Array<OpenSSL::X509::Certificate> ] :ssl_ca_cert_object An array of
205
+ # OpenSSL::X509::Certificate representing the certification authority certifications used
206
+ # to validate certs passed from the other end of the connection. One of :ssl_ca_cert,
207
+ # :ssl_ca_cert_string or :ssl_ca_cert_object (in order of priority) is required for :ssl_verify.
207
208
  # @option options [ Float ] :socket_timeout The timeout, in seconds, to
208
209
  # execute operations on a socket.
209
210
  # @option options [ String ] :user The user name.
@@ -222,6 +223,8 @@ module Mongo
222
223
  # for documents. Must respond to #generate.
223
224
  # @option options [ String, Symbol ] :app_name Application name that is printed to the
224
225
  # mongod logs upon establishing a connection in server versions >= 3.4.
226
+ # @option options [ String ] :platform Platform information to include in the
227
+ # metadata printed to the mongod logs upon establishing a connection in server versions >= 3.4.
225
228
  #
226
229
  # @since 2.0.0
227
230
  def initialize(addresses_or_uri, options = Options::Redacted.new)
@@ -24,6 +24,7 @@ module Mongo
24
24
  # @since 2.0.0
25
25
  class Cluster
26
26
  extend Forwardable
27
+ include Monitoring::Publishable
27
28
  include Event::Subscriber
28
29
  include Loggable
29
30
 
@@ -37,9 +38,17 @@ module Mongo
37
38
  # @since 2.1.1
38
39
  READ_RETRY_INTERVAL = 5
39
40
 
41
+ # How often an idle primary writes a no-op to the oplog.
42
+ #
43
+ # @since 2.4.0
44
+ IDLE_WRITE_PERIOD_SECONDS = 10
45
+
40
46
  # @return [ Hash ] The options hash.
41
47
  attr_reader :options
42
48
 
49
+ # @return [ Monitoring ] monitoring The monitoring.
50
+ attr_reader :monitoring
51
+
43
52
  # @return [ Object ] The cluster topology.
44
53
  attr_reader :topology
45
54
 
@@ -49,7 +58,8 @@ module Mongo
49
58
  # @since 2.4.0
50
59
  attr_reader :app_metadata
51
60
 
52
- def_delegators :topology, :replica_set?, :replica_set_name, :sharded?, :single?, :unknown?
61
+ def_delegators :topology, :replica_set?, :replica_set_name, :sharded?,
62
+ :single?, :unknown?, :member_discovered
53
63
  def_delegators :@cursor_reaper, :register_cursor, :schedule_kill_cursor, :unregister_cursor
54
64
 
55
65
  # Determine if this cluster of servers is equal to another object. Checks the
@@ -84,7 +94,6 @@ module Mongo
84
94
  address = Address.new(host)
85
95
  if !addresses.include?(address)
86
96
  if addition_allowed?(address)
87
- log_debug("Adding #{address.to_s} to the cluster.")
88
97
  @update_lock.synchronize { @addresses.push(address) }
89
98
  server = Server.new(address, self, @monitoring, event_listeners, options)
90
99
  @update_lock.synchronize { @servers.push(server) }
@@ -93,6 +102,34 @@ module Mongo
93
102
  end
94
103
  end
95
104
 
105
+ # Determine if the cluster would select a readable server for the
106
+ # provided read preference.
107
+ #
108
+ # @example Is a readable server present?
109
+ # topology.has_readable_server?(server_selector)
110
+ #
111
+ # @param [ ServerSelector ] server_selector The server
112
+ # selector.
113
+ #
114
+ # @return [ true, false ] If a readable server is present.
115
+ #
116
+ # @since 2.4.0
117
+ def has_readable_server?(server_selector = nil)
118
+ topology.has_readable_server?(self, server_selector)
119
+ end
120
+
121
+ # Determine if the cluster would select a writable server.
122
+ #
123
+ # @example Is a writable server present?
124
+ # topology.has_writable_server?
125
+ #
126
+ # @return [ true, false ] If a writable server is present.
127
+ #
128
+ # @since 2.4.0
129
+ def has_writable_server?
130
+ topology.has_writable_server?(self)
131
+ end
132
+
96
133
  # Instantiate the new cluster.
97
134
  #
98
135
  # @api private
@@ -114,16 +151,26 @@ module Mongo
114
151
  @event_listeners = Event::Listeners.new
115
152
  @options = options.freeze
116
153
  @app_metadata ||= AppMetadata.new(self)
117
- @topology = Topology.initial(seeds, options)
118
154
  @update_lock = Mutex.new
119
155
  @pool_lock = Mutex.new
156
+ @topology = Topology.initial(seeds, monitoring, options)
157
+
158
+ publish_sdam_event(
159
+ Monitoring::TOPOLOGY_OPENING,
160
+ Monitoring::Event::TopologyOpening.new(@topology)
161
+ )
120
162
 
121
163
  subscribe_to(Event::STANDALONE_DISCOVERED, Event::StandaloneDiscovered.new(self))
122
164
  subscribe_to(Event::DESCRIPTION_CHANGED, Event::DescriptionChanged.new(self))
123
- subscribe_to(Event::PRIMARY_ELECTED, Event::PrimaryElected.new(self))
165
+ subscribe_to(Event::MEMBER_DISCOVERED, Event::MemberDiscovered.new(self))
124
166
 
125
167
  seeds.each{ |seed| add(seed) }
126
168
 
169
+ publish_sdam_event(
170
+ Monitoring::TOPOLOGY_CHANGED,
171
+ Monitoring::Event::TopologyChanged.new(@topology, @topology)
172
+ ) if @servers.size > 1
173
+
127
174
  @cursor_reaper = CursorReaper.new
128
175
  @cursor_reaper.run!
129
176
 
@@ -259,11 +306,14 @@ module Mongo
259
306
  #
260
307
  # @since 2.0.0
261
308
  def remove(host)
262
- log_debug("#{host} being removed from the cluster.")
263
309
  address = Address.new(host)
264
310
  removed_servers = @servers.select { |s| s.address == address }
265
311
  @update_lock.synchronize { @servers = @servers - removed_servers }
266
312
  removed_servers.each{ |server| server.disconnect! } if removed_servers
313
+ publish_sdam_event(
314
+ Monitoring::SERVER_CLOSED,
315
+ Monitoring::Event::ServerClosed.new(address, topology)
316
+ )
267
317
  @update_lock.synchronize { @addresses.reject! { |addr| addr == address } }
268
318
  end
269
319
 
@@ -53,6 +53,7 @@ module Mongo
53
53
  # @since 2.4.0
54
54
  def initialize(cluster)
55
55
  @app_name = cluster.options[:app_name]
56
+ @platform = cluster.options[:platform]
56
57
  end
57
58
 
58
59
  # Get the bytes of the ismaster message including this metadata.
@@ -133,7 +134,12 @@ module Mongo
133
134
  end
134
135
 
135
136
  def platform
136
- [RUBY_VERSION, RUBY_PLATFORM, RbConfig::CONFIG['build']].join(', ')
137
+ [
138
+ @platform,
139
+ RUBY_VERSION,
140
+ RUBY_PLATFORM,
141
+ RbConfig::CONFIG['build']
142
+ ].compact.join(', ')
137
143
  end
138
144
  end
139
145
  end
@@ -26,14 +26,14 @@ module Mongo
26
26
  module Topology
27
27
  extend self
28
28
 
29
- # The 2 various topologies for server selection.
29
+ # The various topologies for server selection.
30
30
  #
31
31
  # @since 2.0.0
32
32
  OPTIONS = {
33
33
  replica_set: ReplicaSet,
34
34
  sharded: Sharded,
35
35
  direct: Single
36
- }
36
+ }.freeze
37
37
 
38
38
  # Get the initial cluster topology for the provided options.
39
39
  #
@@ -41,18 +41,19 @@ module Mongo
41
41
  # Topology.initial(topology: :replica_set)
42
42
  #
43
43
  # @param [ Array<String> ] seeds The addresses of the configured servers.
44
+ # @param [ Monitoring ] monitoring The monitoring.
44
45
  # @param [ Hash ] options The cluster options.
45
46
  #
46
47
  # @return [ ReplicaSet, Sharded, Single ] The topology.
47
48
  #
48
49
  # @since 2.0.0
49
- def initial(seeds, options)
50
+ def initial(seeds, monitoring, options)
50
51
  if options.has_key?(:connect)
51
- OPTIONS.fetch(options[:connect]).new(options, seeds)
52
+ OPTIONS.fetch(options[:connect]).new(options, monitoring, seeds)
52
53
  elsif options.has_key?(:replica_set)
53
- ReplicaSet.new(options, seeds)
54
+ ReplicaSet.new(options, monitoring, options)
54
55
  else
55
- Unknown.new(options, seeds)
56
+ Unknown.new(options, monitoring, seeds)
56
57
  end
57
58
  end
58
59
  end
@@ -21,6 +21,7 @@ module Mongo
21
21
  # @since 2.0.0
22
22
  class ReplicaSet
23
23
  include Loggable
24
+ include Monitoring::Publishable
24
25
 
25
26
  # Constant for the replica set name configuration option.
26
27
  #
@@ -30,6 +31,9 @@ module Mongo
30
31
  # @return [ Hash ] options The options.
31
32
  attr_reader :options
32
33
 
34
+ # @return [ Monitoring ] monitoring The monitoring.
35
+ attr_reader :monitoring
36
+
33
37
  # The display name for the topology.
34
38
  #
35
39
  # @since 2.0.0
@@ -61,7 +65,6 @@ module Mongo
61
65
  def elect_primary(description, servers)
62
66
  if description.replica_set_name == replica_set_name
63
67
  unless detect_stale_primary!(description)
64
- log_debug("Server #{description.address.to_s} elected as primary in #{replica_set_name}.")
65
68
  servers.each do |server|
66
69
  if server.primary? && server.address != description.address
67
70
  server.description.unknown!
@@ -79,16 +82,51 @@ module Mongo
79
82
  self
80
83
  end
81
84
 
85
+ # Determine if the topology would select a readable server for the
86
+ # provided candidates and read preference.
87
+ #
88
+ # @example Is a readable server present?
89
+ # topology.has_readable_server?(cluster, server_selector)
90
+ #
91
+ # @param [ Cluster ] cluster The cluster.
92
+ # @param [ ServerSelector ] server_selector The server
93
+ # selector.
94
+ #
95
+ # @return [ true, false ] If a readable server is present.
96
+ #
97
+ # @since 2.4.0
98
+ def has_readable_server?(cluster, server_selector = nil)
99
+ (server_selector || ServerSelector.get(mode: :primary)).candidates(cluster).any?
100
+ end
101
+
102
+ # Determine if the topology would select a writable server for the
103
+ # provided candidates.
104
+ #
105
+ # @example Is a writable server present?
106
+ # topology.has_writable_server?(servers)
107
+ #
108
+ # @param [ Cluster ] cluster The cluster.
109
+ #
110
+ # @return [ true, false ] If a writable server is present.
111
+ #
112
+ # @since 2.4.0
113
+ def has_writable_server?(cluster)
114
+ cluster.servers.any?{ |server| server.primary? }
115
+ end
116
+
82
117
  # Initialize the topology with the options.
83
118
  #
84
119
  # @example Initialize the topology.
85
120
  # ReplicaSet.new(options)
86
121
  #
87
122
  # @param [ Hash ] options The options.
123
+ # @param [ Monitoring ] monitoring The monitoring.
124
+ # @param [ Array<String> ] seeds The seeds.
88
125
  #
89
126
  # @since 2.0.0
90
- def initialize(options, seeds = [])
127
+ def initialize(options, monitoring, seeds = [])
91
128
  @options = options
129
+ @monitoring = monitoring
92
130
  @max_election_id = nil
93
131
  @max_set_version = nil
94
132
  end
@@ -222,6 +260,14 @@ module Mongo
222
260
  # @since 2.0.6
223
261
  def standalone_discovered; self; end
224
262
 
263
+ # Notify the topology that a member was discovered.
264
+ #
265
+ # @example Notify the topology that a member was discovered.
266
+ # topology.member_discovered
267
+ #
268
+ # @since 2.4.0
269
+ def member_discovered; end;
270
+
225
271
  private
226
272
 
227
273
  def update_max_election_id(description)
@@ -20,12 +20,19 @@ module Mongo
20
20
  #
21
21
  # @since 2.0.0
22
22
  class Sharded
23
+ include Monitoring::Publishable
23
24
 
24
25
  # The display name for the topology.
25
26
  #
26
27
  # @since 2.0.0
27
28
  NAME = 'Sharded'.freeze
28
29
 
30
+ # @return [ Hash ] options The options.
31
+ attr_reader :options
32
+
33
+ # @return [ Monitoring ] monitoring The monitoring.
34
+ attr_reader :monitoring
35
+
29
36
  # Get the display name.
30
37
  #
31
38
  # @example Get the display name.
@@ -51,16 +58,47 @@ module Mongo
51
58
  # @return [ Sharded ] The topology.
52
59
  def elect_primary(description, servers); self; end
53
60
 
61
+ # Determine if the topology would select a readable server for the
62
+ # provided candidates and read preference.
63
+ #
64
+ # @example Is a readable server present?
65
+ # topology.has_readable_server?(cluster, server_selector)
66
+ #
67
+ # @param [ Cluster ] cluster The cluster.
68
+ # @param [ ServerSelector ] server_selector The server
69
+ # selector.
70
+ #
71
+ # @return [ true ] A Sharded cluster always has a readable server.
72
+ #
73
+ # @since 2.4.0
74
+ def has_readable_server?(cluster, server_selector = nil); true; end
75
+
76
+ # Determine if the topology would select a writable server for the
77
+ # provided candidates.
78
+ #
79
+ # @example Is a writable server present?
80
+ # topology.has_writable_server?(servers)
81
+ #
82
+ # @param [ Cluster ] cluster The cluster.
83
+ #
84
+ # @return [ true ] A Sharded cluster always has a writable server.
85
+ #
86
+ # @since 2.4.0
87
+ def has_writable_server?(cluster); true; end
88
+
54
89
  # Initialize the topology with the options.
55
90
  #
56
91
  # @example Initialize the topology.
57
92
  # Sharded.new(options)
58
93
  #
59
94
  # @param [ Hash ] options The options.
95
+ # @param [ Monitoring ] monitoring The monitoring.
96
+ # @param [ Array<String> ] seeds The seeds.
60
97
  #
61
98
  # @since 2.0.0
62
- def initialize(options, seeds = [])
99
+ def initialize(options, monitoring, seeds = [])
63
100
  @options = options
101
+ @monitoring = monitoring
64
102
  end
65
103
 
66
104
  # A sharded topology is not a replica set.
@@ -181,6 +219,14 @@ module Mongo
181
219
  # @since 2.0.6
182
220
  def standalone_discovered; self; end
183
221
 
222
+ # Notify the topology that a member was discovered.
223
+ #
224
+ # @example Notify the cluster that a member was discovered.
225
+ # topology.member_discovered
226
+ #
227
+ # @since 2.4.0
228
+ def member_discovered; end;
229
+
184
230
  private
185
231
 
186
232
  def remove_self?(description, server)