Skip to content

Commit 65ed5d9

Browse files
authored
Merge pull request #836 from estolfo/RUBY-1174-update-max-staleness
RUBY-1174 RUBY-1178 Update Max Staleness implementation
2 parents fb3cc66 + adb6fad commit 65ed5d9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+262
-172
lines changed

lib/mongo/cluster.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ class Cluster
3737
# @since 2.1.1
3838
READ_RETRY_INTERVAL = 5
3939

40+
# How often an idle primary writes a no-op to the oplog.
41+
#
42+
# @since 2.4.0
43+
IDLE_WRITE_PERIOD_SECONDS = 10
44+
4045
# @return [ Hash ] The options hash.
4146
attr_reader :options
4247

lib/mongo/error/invalid_server_preference.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ class InvalidServerPreference < Error
3333
# Error message for when the max staleness is not at least twice the heartbeat frequency.
3434
#
3535
# @since 2.4.0
36-
INVALID_MAX_STALENESS = "max_staleness must be at least twice the client's heartbeat frequency.".freeze
36+
INVALID_MAX_STALENESS = "`max_staleness` value is too small. It must be at least " +
37+
"`ServerSelector::SMALLEST_MAX_STALENESS_SECONDS` and (the cluster's heartbeat_frequency " +
38+
"setting + `Cluster::IDLE_WRITE_PERIOD_SECONDS`).".freeze
3739

3840
# Error message when max staleness cannot be used because one or more servers has version < 3.4.
3941
#

lib/mongo/server.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class Server
4545

4646
# Get the description from the monitor and scan on monitor.
4747
def_delegators :monitor, :description, :scan!, :heartbeat_frequency, :last_scan
48+
alias :heartbeat_frequency_seconds :heartbeat_frequency
4849

4950
# Delegate convenience methods to the monitor description.
5051
def_delegators :description,

lib/mongo/server_selector.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ module ServerSelector
3838
# @since 2.0.0
3939
SERVER_SELECTION_TIMEOUT = 30.freeze
4040

41+
# The smallest allowed max staleness value, in seconds.
42+
#
43+
# @since 2.4.0
44+
SMALLEST_MAX_STALENESS_SECONDS = 90
45+
4146
# Primary read preference.
4247
#
4348
# @since 2.1.0

lib/mongo/server_selector/nearest.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def tags_allowed?
6767
def to_mongos
6868
preference = { :mode => 'nearest' }
6969
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
7171
preference
7272
end
7373

lib/mongo/server_selector/primary_preferred.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def tags_allowed?
6868
def to_mongos
6969
preference = { :mode => 'primaryPreferred' }
7070
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
7272
preference
7373
end
7474

lib/mongo/server_selector/secondary.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def tags_allowed?
6868
def to_mongos
6969
preference = { :mode => 'secondary' }
7070
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
7272
preference
7373
end
7474

lib/mongo/server_selector/secondary_preferred.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def to_mongos
7171
return nil if tag_sets.empty? && max_staleness.nil?
7272
preference = { mode: 'secondaryPreferred' }
7373
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
7575
preference
7676
end
7777

lib/mongo/server_selector/selectable.rb

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ module Selectable
2626
# @return [ Array ] tag_sets The tag sets used to select servers.
2727
attr_reader :tag_sets
2828

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
3030
# secondary can suffer and still be eligible for a read.
3131
#
3232
# @since 2.4.0
@@ -68,7 +68,7 @@ def ==(other)
6868
def initialize(options = {})
6969
@options = (options || {}).freeze
7070
@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
7272
validate!
7373
end
7474

@@ -154,7 +154,7 @@ def candidates(cluster)
154154
elsif cluster.sharded?
155155
near_servers(cluster.servers).each { |server| validate_max_staleness_support!(server) }
156156
else
157-
validate_max_staleness_value!(cluster)
157+
validate_max_staleness_value!(cluster) unless cluster.unknown?
158158
select(cluster.servers)
159159
end
160160
end
@@ -230,14 +230,14 @@ def filter_stale_servers(candidates, primary = nil)
230230
validate_max_staleness_support!(server)
231231
staleness = (server.last_scan - server.last_write_date) -
232232
(primary.last_scan - primary.last_write_date) +
233-
(server.heartbeat_frequency * 1000)
233+
(server.heartbeat_frequency_seconds * 1000)
234234
staleness <= max_staleness_ms
235235
end
236236
else
237237
max_write_date = candidates.collect(&:last_write_date).max
238238
candidates.select do |server|
239239
validate_max_staleness_support!(server)
240-
staleness = max_write_date - server.last_write_date + (server.heartbeat_frequency * 1000)
240+
staleness = max_write_date - server.last_write_date + (server.heartbeat_frequency_seconds * 1000)
241241
staleness <= max_staleness_ms
242242
end
243243
end
@@ -258,10 +258,12 @@ def validate_max_staleness_support!(server)
258258
end
259259

260260
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)
261+
if @max_staleness
262+
heartbeat_frequency_seconds = cluster.options[:heartbeat_frequency] || Server::Monitor::HEARTBEAT_FREQUENCY
263+
unless @max_staleness >= [ SMALLEST_MAX_STALENESS_SECONDS,
264+
(heartbeat_frequency_seconds + Cluster::IDLE_WRITE_PERIOD_SECONDS) ].max
265+
raise Error::InvalidServerPreference.new(Error::InvalidServerPreference::INVALID_MAX_STALENESS)
266+
end
265267
end
266268
end
267269
end

lib/mongo/uri.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ def self.uri_option(uri_key, name, extra = {})
374374
# Read Options
375375
uri_option 'readpreference', :mode, :group => :read, :type => :read_mode
376376
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
378378

379379
# Pool options
380380
uri_option 'minpoolsize', :min_pool_size

0 commit comments

Comments
 (0)