mongo 2.4.0.rc1 → 2.4.0

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.
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)