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
@@ -0,0 +1,40 @@
1
+ # Copyright (C) 2016 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the 'License');
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an 'AS IS' BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+ class Monitoring
17
+
18
+ # Subscribes to Topology Changed events and logs them.
19
+ #
20
+ # @since 2.4.0
21
+ class TopologyChangedLogSubscriber < SDAMLogSubscriber
22
+
23
+ private
24
+
25
+ def log_event(event)
26
+ if event.previous_topology != event.new_topology
27
+ log_debug(
28
+ "Topology type '#{event.previous_topology.display_name.downcase}' changed to " +
29
+ "type '#{event.new_topology.display_name.downcase}'."
30
+ )
31
+ else
32
+ log_debug(
33
+ "There was a change in the members of the '#{event.new_topology.display_name.downcase}' " +
34
+ "topology."
35
+ )
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,30 @@
1
+ # Copyright (C) 2016 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the 'License');
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an 'AS IS' BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+ class Monitoring
17
+
18
+ # Subscribes to Topology Openeing events and logs them.
19
+ #
20
+ # @since 2.4.0
21
+ class TopologyOpeningLogSubscriber < SDAMLogSubscriber
22
+
23
+ private
24
+
25
+ def log_event(event)
26
+ log_debug("Topology type '#{event.topology.display_name.downcase}' initializing.")
27
+ end
28
+ end
29
+ end
30
+ end
@@ -27,6 +27,7 @@ module Mongo
27
27
  # @since 2.0.0
28
28
  class Server
29
29
  extend Forwardable
30
+ include Monitoring::Publishable
30
31
 
31
32
  # @return [ String ] The configured address for the server.
32
33
  attr_reader :address
@@ -45,6 +46,7 @@ module Mongo
45
46
 
46
47
  # Get the description from the monitor and scan on monitor.
47
48
  def_delegators :monitor, :description, :scan!, :heartbeat_frequency, :last_scan
49
+ alias :heartbeat_frequency_seconds :heartbeat_frequency
48
50
 
49
51
  # Delegate convenience methods to the monitor description.
50
52
  def_delegators :description,
@@ -163,6 +165,10 @@ module Mongo
163
165
  @cluster = cluster
164
166
  @monitoring = monitoring
165
167
  @options = options.freeze
168
+ publish_sdam_event(
169
+ Monitoring::SERVER_OPENING,
170
+ Monitoring::Event::ServerOpening.new(address, cluster.topology)
171
+ )
166
172
  @monitor = Monitor.new(address, event_listeners, options.merge(app_metadata: cluster.app_metadata))
167
173
  monitor.scan!
168
174
  monitor.run!
@@ -175,7 +175,7 @@ module Mongo
175
175
  end
176
176
 
177
177
  def authenticate!
178
- if options[:user]
178
+ if options[:user] || options[:auth_mech]
179
179
  user = Auth::User.new(Options::Redacted.new(:auth_mech => default_mechanism).merge(options))
180
180
  @server.handle_auth_failure! do
181
181
  Auth.get(user).login(self)
@@ -239,7 +239,7 @@ module Mongo
239
239
  #
240
240
  # @param [ Address ] address The server address.
241
241
  # @param [ Hash ] config The result of the ismaster command.
242
- # @param [ Float ] average_round_trip_time The moving average time (ms) the ismaster
242
+ # @param [ Float ] average_round_trip_time The moving average time (sec) the ismaster
243
243
  # call took to complete.
244
244
  #
245
245
  # @since 2.0.0
@@ -480,6 +480,24 @@ module Mongo
480
480
  !!config[SECONDARY] && !replica_set_name.nil?
481
481
  end
482
482
 
483
+ # Returns the server type as a symbol.
484
+ #
485
+ # @example Get the server type.
486
+ # description.server_type
487
+ #
488
+ # @return [ Symbol ] The server type.
489
+ #
490
+ # @since 2.4.0
491
+ def server_type
492
+ return :arbiter if arbiter?
493
+ return :ghost if ghost?
494
+ return :sharded if mongos?
495
+ return :primary if primary?
496
+ return :secondary if secondary?
497
+ return :standalone if standalone?
498
+ :unknown
499
+ end
500
+
483
501
  # Is this server a standalone server?
484
502
  #
485
503
  # @example Is the server standalone?
@@ -501,7 +519,8 @@ module Mongo
501
519
  #
502
520
  # @since 2.0.0
503
521
  def unknown?
504
- config.empty? || config[Operation::Result::OK] != 1
522
+ config.empty? || (config[Operation::Result::OK] &&
523
+ config[Operation::Result::OK] != 1)
505
524
  end
506
525
 
507
526
  # A result from another server's ismaster command before this server has
@@ -592,6 +611,7 @@ module Mongo
592
611
  # @since 2.0.6
593
612
  def ==(other)
594
613
  return false if self.class != other.class
614
+ return false if unknown? || other.unknown?
595
615
  compare_config(other)
596
616
  end
597
617
  alias_method :eql?, :==
@@ -599,7 +619,7 @@ module Mongo
599
619
  private
600
620
 
601
621
  def compare_config(other)
602
- !config.keys.empty? && config.keys.all? do |k|
622
+ config.keys.all? do |k|
603
623
  config[k] == other.config[k] || EXCLUDE_FOR_COMPARISON.include?(k)
604
624
  end
605
625
  end
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ require 'mongo/server/description/inspector/member_discovered'
16
+ # @deprecated. Will be removed in 3.0
15
17
  require 'mongo/server/description/inspector/primary_elected'
16
18
  require 'mongo/server/description/inspector/description_changed'
17
19
  require 'mongo/server/description/inspector/standalone_discovered'
@@ -34,7 +36,7 @@ module Mongo
34
36
  INSPECTORS = [
35
37
  Inspector::StandaloneDiscovered,
36
38
  Inspector::DescriptionChanged,
37
- Inspector::PrimaryElected
39
+ Inspector::MemberDiscovered
38
40
  ].freeze
39
41
 
40
42
  # @return [ Array ] inspectors The description inspectors.
@@ -61,7 +63,7 @@ module Mongo
61
63
  #
62
64
  # @param [ Description ] description The old description.
63
65
  # @param [ Hash ] ismaster The updated ismaster.
64
- # @param [ Float ] average_round_trip_time The moving average round trip time (ms).
66
+ # @param [ Float ] average_round_trip_time The moving average round trip time (sec).
65
67
  #
66
68
  # @return [ Description ] The new description.
67
69
  #
@@ -46,8 +46,8 @@ module Mongo
46
46
  #
47
47
  # @since 2.0.0
48
48
  def run(description, updated)
49
- unless description == updated
50
- publish(Event::DESCRIPTION_CHANGED, updated)
49
+ unless (description.unknown? && updated.unknown?) || (description == updated)
50
+ publish(Event::DESCRIPTION_CHANGED, description, updated)
51
51
  end
52
52
  end
53
53
  end
@@ -0,0 +1,59 @@
1
+ # Copyright (C) 2015 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the 'License');
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an 'AS IS' BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+ class Server
17
+ class Description
18
+ class Inspector
19
+
20
+ # Handles inspecting the result of an ismaster command to check if this
21
+ # a server is a member of a known topology.
22
+ #
23
+ # @since 2.4.0
24
+ class MemberDiscovered
25
+ include Event::Publisher
26
+
27
+ # Instantiate the member discovered inspection.
28
+ #
29
+ # @example Instantiate the inspection.
30
+ # MemberDiscovered.new(listeners)
31
+ #
32
+ # @param [ Event::Listeners ] event_listeners The event listeners.
33
+ #
34
+ # @since 2.4.0
35
+ def initialize(event_listeners)
36
+ @event_listeners = event_listeners
37
+ end
38
+
39
+ # Run the member discovered inspection.
40
+ #
41
+ # @example Run the inspection.
42
+ # MemberDiscovered.run(description, {})
43
+ #
44
+ # @param [ Description ] description The server description.
45
+ # @param [ Description ] updated The updated description.
46
+ #
47
+ # @since 2.4.0
48
+ def run(description, updated)
49
+ if (!description.primary? && updated.primary?) ||
50
+ (!description.mongos? && updated.mongos?) ||
51
+ (description.unknown? && !updated.unknown?)
52
+ publish(Event::MEMBER_DISCOVERED, description, updated)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -21,6 +21,8 @@ module Mongo
21
21
  # server was elected primary.
22
22
  #
23
23
  # @since 2.0.0
24
+ #
25
+ # @deprecated. Will be removed in 3.0
24
26
  class PrimaryElected
25
27
  include Event::Publisher
26
28
 
@@ -38,6 +38,11 @@ module Mongo
38
38
  # @since 2.0.0
39
39
  SERVER_SELECTION_TIMEOUT = 30.freeze
40
40
 
41
+ # The smallest allowed max staleness value, in seconds.
42
+ #
43
+ # @since 2.4.0
44
+ SMALLEST_MAX_STALENESS_SECONDS = 90
45
+
41
46
  # Primary read preference.
42
47
  #
43
48
  # @since 2.1.0
@@ -48,11 +53,11 @@ module Mongo
48
53
  #
49
54
  # @since 2.0.0
50
55
  PREFERENCES = {
51
- nearest: Nearest,
52
- primary: Primary,
53
- primary_preferred: PrimaryPreferred,
54
- secondary: Secondary,
55
- secondary_preferred: SecondaryPreferred
56
+ nearest: Nearest,
57
+ primary: Primary,
58
+ primary_preferred: PrimaryPreferred,
59
+ secondary: Secondary,
60
+ secondary_preferred: SecondaryPreferred
56
61
  }.freeze
57
62
 
58
63
  # Create a server selector object.
@@ -67,7 +67,7 @@ module Mongo
67
67
  def to_mongos
68
68
  preference = { :mode => 'nearest' }
69
69
  preference.merge!({ :tags => tag_sets }) unless tag_sets.empty?
70
- preference.merge!({ maxStalenessMS: max_staleness * 1000 }) if max_staleness
70
+ preference.merge!({ maxStalenessSeconds: max_staleness }) if max_staleness
71
71
  preference
72
72
  end
73
73
 
@@ -68,7 +68,7 @@ module Mongo
68
68
  def to_mongos
69
69
  preference = { :mode => 'primaryPreferred' }
70
70
  preference.merge!({ :tags => tag_sets }) unless tag_sets.empty?
71
- preference.merge!({ maxStalenessMS: max_staleness * 1000 }) if max_staleness
71
+ preference.merge!({ maxStalenessSeconds: max_staleness }) if max_staleness
72
72
  preference
73
73
  end
74
74
 
@@ -68,7 +68,7 @@ module Mongo
68
68
  def to_mongos
69
69
  preference = { :mode => 'secondary' }
70
70
  preference.merge!({ :tags => tag_sets }) unless tag_sets.empty?
71
- preference.merge!({ maxStalenessMS: max_staleness * 1000 }) if max_staleness
71
+ preference.merge!({ maxStalenessSeconds: max_staleness }) if max_staleness
72
72
  preference
73
73
  end
74
74
 
@@ -71,7 +71,7 @@ module Mongo
71
71
  return nil if tag_sets.empty? && max_staleness.nil?
72
72
  preference = { mode: 'secondaryPreferred' }
73
73
  preference.merge!({ tags: tag_sets }) unless tag_sets.empty?
74
- preference.merge!({ maxStalenessMS: max_staleness * 1000 }) if max_staleness
74
+ preference.merge!({ maxStalenessSeconds: max_staleness }) if max_staleness
75
75
  preference
76
76
  end
77
77
 
@@ -26,7 +26,7 @@ module Mongo
26
26
  # @return [ Array ] tag_sets The tag sets used to select servers.
27
27
  attr_reader :tag_sets
28
28
 
29
- # @return [ Float ] max_staleness The maximum replication lag, in seconds, that a
29
+ # @return [ Integer ] max_staleness The maximum replication lag, in seconds, that a
30
30
  # secondary can suffer and still be eligible for a read.
31
31
  #
32
32
  # @since 2.4.0
@@ -68,7 +68,7 @@ module Mongo
68
68
  def initialize(options = {})
69
69
  @options = (options || {}).freeze
70
70
  @tag_sets = (options[:tag_sets] || []).freeze
71
- @max_staleness = options[:max_staleness] if options[:max_staleness] && options[:max_staleness] > 0
71
+ @max_staleness = options[:max_staleness] unless options[:max_staleness] == -1
72
72
  validate!
73
73
  end
74
74
 
@@ -146,19 +146,29 @@ module Mongo
146
146
  @local_threshold ||= (options[:local_threshold] || ServerSelector::LOCAL_THRESHOLD)
147
147
  end
148
148
 
149
- private
150
-
149
+ # Get the potential candidates to select from the cluster.
150
+ #
151
+ # @example Get the server candidates.
152
+ # selectable.candidates(cluster)
153
+ #
154
+ # @param [ Cluster ] cluster The cluster.
155
+ #
156
+ # @return [ Array<Server> ] The candidate servers.
157
+ #
158
+ # @since 2.4.0
151
159
  def candidates(cluster)
152
160
  if cluster.single?
153
161
  cluster.servers.each { |server| validate_max_staleness_support!(server) }
154
162
  elsif cluster.sharded?
155
163
  near_servers(cluster.servers).each { |server| validate_max_staleness_support!(server) }
156
164
  else
157
- validate_max_staleness_value!(cluster)
165
+ validate_max_staleness_value!(cluster) unless cluster.unknown?
158
166
  select(cluster.servers)
159
167
  end
160
168
  end
161
169
 
170
+ private
171
+
162
172
  # Select the primary from a list of provided candidates.
163
173
  #
164
174
  # @param [ Array ] candidates List of candidate servers to select the
@@ -200,7 +210,7 @@ module Mongo
200
210
  def near_servers(candidates = [])
201
211
  return candidates if candidates.empty?
202
212
  nearest_server = candidates.min_by(&:average_round_trip_time)
203
- threshold = nearest_server.average_round_trip_time + (local_threshold * 1000)
213
+ threshold = nearest_server.average_round_trip_time + local_threshold
204
214
  candidates.select { |server| server.average_round_trip_time <= threshold }.shuffle!
205
215
  end
206
216
 
@@ -230,14 +240,14 @@ module Mongo
230
240
  validate_max_staleness_support!(server)
231
241
  staleness = (server.last_scan - server.last_write_date) -
232
242
  (primary.last_scan - primary.last_write_date) +
233
- (server.heartbeat_frequency * 1000)
243
+ (server.heartbeat_frequency_seconds * 1000)
234
244
  staleness <= max_staleness_ms
235
245
  end
236
246
  else
237
247
  max_write_date = candidates.collect(&:last_write_date).max
238
248
  candidates.select do |server|
239
249
  validate_max_staleness_support!(server)
240
- staleness = max_write_date - server.last_write_date + (server.heartbeat_frequency * 1000)
250
+ staleness = max_write_date - server.last_write_date + (server.heartbeat_frequency_seconds * 1000)
241
251
  staleness <= max_staleness_ms
242
252
  end
243
253
  end
@@ -258,10 +268,12 @@ module Mongo
258
268
  end
259
269
 
260
270
  def validate_max_staleness_value!(cluster)
261
- return unless @max_staleness
262
- heartbeat_frequency = cluster.options[:heartbeat_frequency] || Server::Monitor::HEARTBEAT_FREQUENCY
263
- if @max_staleness < heartbeat_frequency * 2
264
- raise Error::InvalidServerPreference.new(Error::InvalidServerPreference::INVALID_MAX_STALENESS)
271
+ if @max_staleness
272
+ heartbeat_frequency_seconds = cluster.options[:heartbeat_frequency] || Server::Monitor::HEARTBEAT_FREQUENCY
273
+ unless @max_staleness >= [ SMALLEST_MAX_STALENESS_SECONDS,
274
+ (heartbeat_frequency_seconds + Cluster::IDLE_WRITE_PERIOD_SECONDS) ].max
275
+ raise Error::InvalidServerPreference.new(Error::InvalidServerPreference::INVALID_MAX_STALENESS)
276
+ end
265
277
  end
266
278
  end
267
279
  end
@@ -374,7 +374,7 @@ module Mongo
374
374
  # Read Options
375
375
  uri_option 'readpreference', :mode, :group => :read, :type => :read_mode
376
376
  uri_option 'readpreferencetags', :tag_sets, :group => :read, :type => :read_tags
377
- uri_option 'maxstalenessms', :max_staleness, :group => :read, :type => :ms_convert
377
+ uri_option 'maxstalenessseconds', :max_staleness, :group => :read
378
378
 
379
379
  # Pool options
380
380
  uri_option 'minpoolsize', :min_pool_size