Class: Mongo::ServerSelector::Base

Inherits:
Object
  • Object
show all
Defined in:
build/ruby-driver-master/lib/mongo/server_selector/base.rb

Overview

Since:

  • 2.0.0

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = nil) ⇒ Base

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Initialize the server selector.

Examples:

Initialize the selector.

Mongo::ServerSelector::Secondary.new(:tag_sets => [{'dc' => 'nyc'}])

Initialize the preference with no options.

Mongo::ServerSelector::Secondary.new

Parameters:

  • options (Hash) (defaults to: nil)

    The server preference options.

Options Hash (options):

  • :local_threshold (Integer)

    The local threshold boundary for nearest selection in seconds.

  • max_staleness (Integer)

    The maximum replication lag, in seconds, that a secondary can suffer and still be eligible for a read. A value of -1 is treated identically to nil, which is to not have a maximum staleness.

  • hedge (Hash | nil)

    A Hash specifying whether to enable hedged reads on the server. Hedged reads are not enabled by default. When specifying this option, it must be in the format: { enabled: true }, where the value of the :enabled key is a boolean value.

Raises:

Since:

  • 2.0.0



49
50
51
52
53
54
55
56
57
58
59
60
# File 'build/ruby-driver-master/lib/mongo/server_selector/base.rb', line 49

def initialize(options = nil)
  options = options ? options.dup : {}
  if options[:max_staleness] == -1
    options.delete(:max_staleness)
  end
  @options = options
  @tag_sets = options[:tag_sets] || []
  @max_staleness = options[:max_staleness]
  @hedge = options[:hedge]

  validate!
end

Instance Attribute Details

#hedgeHash | nil (readonly)

Returns hedge The document specifying whether to enable hedged reads.

Returns:

  • (Hash | nil)

    hedge The document specifying whether to enable hedged reads.

Since:

  • 2.0.0



76
77
78
# File 'build/ruby-driver-master/lib/mongo/server_selector/base.rb', line 76

def hedge
  @hedge
end

#max_stalenessInteger (readonly)

Returns max_staleness The maximum replication lag, in seconds, that a secondary can suffer and still be eligible for a read.

Returns:

  • (Integer)

    max_staleness The maximum replication lag, in seconds, that a secondary can suffer and still be eligible for a read.

Since:

  • 2.4.0



72
73
74
# File 'build/ruby-driver-master/lib/mongo/server_selector/base.rb', line 72

def max_staleness
  @max_staleness
end

#optionsHash (readonly)

Returns options The options.

Returns:

  • (Hash)

    options The options.

Since:

  • 2.0.0



63
64
65
# File 'build/ruby-driver-master/lib/mongo/server_selector/base.rb', line 63

def options
  @options
end

#tag_setsArray (readonly)

Returns tag_sets The tag sets used to select servers.

Returns:

  • (Array)

    tag_sets The tag sets used to select servers.

Since:

  • 2.0.0



66
67
68
# File 'build/ruby-driver-master/lib/mongo/server_selector/base.rb', line 66

def tag_sets
  @tag_sets
end

Instance Method Details

#==(other) ⇒ true, false

Check equality of two server selectors.

Examples:

Check server selector equality.

preference == other

Parameters:

  • other (Object)

    The other preference.

Returns:

  • (true, false)

    Whether the objects are equal.

Since:

  • 2.0.0



136
137
138
139
# File 'build/ruby-driver-master/lib/mongo/server_selector/base.rb', line 136

def ==(other)
  name == other.name && hedge == other.hedge &&
    max_staleness == other.max_staleness && tag_sets == other.tag_sets
end

#candidates(cluster) ⇒ Array<Server>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns servers of acceptable types from the cluster.

Does not perform staleness validation, staleness filtering or latency filtering.

Parameters:

  • cluster (Cluster)

    The cluster.

Returns:

  • (Array<Server>)

    The candidate servers.

Since:

  • 2.0.0



358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
# File 'build/ruby-driver-master/lib/mongo/server_selector/base.rb', line 358

def candidates(cluster)
  servers = cluster.servers
  servers.each do |server|
    validate_max_staleness_support!(server)
  end
  if cluster.single?
    servers
  elsif cluster.sharded?
    servers
  elsif cluster.replica_set?
    select_in_replica_set(servers)
  else
    # Unknown cluster - no servers
    []
  end
end

#inspectString

Inspect the server selector.

Examples:

Inspect the server selector.

selector.inspect

Returns:

  • (String)

    The inspection.

Since:

  • 2.2.0



122
123
124
# File 'build/ruby-driver-master/lib/mongo/server_selector/base.rb', line 122

def inspect
  "#<#{self.class.name}:0x#{object_id} tag_sets=#{tag_sets.inspect} max_staleness=#{max_staleness.inspect} hedge=#{hedge}>"
end

#local_thresholdFloat

Deprecated.

This setting is now taken from the cluster options when a server is selected. Will be removed in version 3.0.

Get the local threshold boundary for nearest selection in seconds.

Examples:

Get the local threshold.

selector.local_threshold

Returns:

  • (Float)

    The local threshold.

Since:

  • 2.0.0



105
106
107
# File 'build/ruby-driver-master/lib/mongo/server_selector/base.rb', line 105

def local_threshold
  @local_threshold ||= (options[:local_threshold] || ServerSelector::LOCAL_THRESHOLD)
end

#local_threshold_with_cluster(cluster) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Since:

  • 2.0.0



110
111
112
# File 'build/ruby-driver-master/lib/mongo/server_selector/base.rb', line 110

def local_threshold_with_cluster(cluster)
  options[:local_threshold] || cluster.options[:local_threshold] || LOCAL_THRESHOLD
end

#select_server(cluster, ping = nil, session = nil, write_aggregation: false) ⇒ Mongo::Server

Select a server from the specified cluster, taking into account mongos pinning for the specified session.

If the session is given and has a pinned server, this server is the only server considered for selection. If the server is of type mongos, it is returned immediately; otherwise monitoring checks on this server are initiated to update its status, and if the server becomes a mongos within the server selection timeout, it is returned.

If no session is given or the session does not have a pinned server, normal server selection process is performed among all servers in the specified cluster matching the preference of this server selector object. Monitoring checks are initiated on servers in the cluster until a suitable server is found, up to the server selection timeout.

If a suitable server is not found within the server selection timeout, this method raises Error::NoServerAvailable.

Parameters:

  • cluster (Mongo::Cluster)

    The cluster from which to select an eligible server.

  • ping (true, false) (defaults to: nil)

    Whether to ping the server before selection. Deprecated and ignored.

  • session (Session | nil) (defaults to: nil)

    Optional session to take into account for mongos pinning. Added in version 2.10.0.

  • write_aggregation (true | false) (defaults to: false)

    Whether we need a server that supports writing aggregations (e.g. with $merge/$out) on secondaries.

Returns:

Raises:

  • (Error::NoServerAvailable)

    No server was found matching the specified preference / pinning requirement in the server selection timeout.

  • (Error::LintError)

    An unexpected condition was detected, and lint mode is enabled.

Since:

  • 2.0.0



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'build/ruby-driver-master/lib/mongo/server_selector/base.rb', line 177

def select_server(cluster, ping = nil, session = nil, write_aggregation: false)
  if cluster.topology.is_a?(Cluster::Topology::LoadBalanced)
    return cluster.servers.first
  end

  server_selection_timeout = cluster.options[:server_selection_timeout] || SERVER_SELECTION_TIMEOUT

  # Special handling for zero timeout: if we have to select a server,
  # and the timeout is zero, fail immediately (since server selection
  # will take some non-zero amount of time in any case).
  if server_selection_timeout == 0
    msg = "Failing server selection due to zero timeout. " +
      " Requested #{name} in cluster: #{cluster.summary}"
    raise Error::NoServerAvailable.new(self, cluster, msg)
  end

  deadline = Utils.monotonic_time + server_selection_timeout

  if session && session.pinned_server
    if Mongo::Lint.enabled?
      unless cluster.sharded?
        raise Error::LintError, "Session has a pinned server in a non-sharded topology: #{topology}"
      end
    end

    if !session.in_transaction?
      session.unpin
    end

    if server = session.pinned_server
      # Here we assume that a mongos stays in the topology indefinitely.
      # This will no longer be the case once SRV polling is implemented.

      unless server.mongos?
        while (time_remaining = deadline - Utils.monotonic_time) > 0
          wait_for_server_selection(cluster, time_remaining)
        end

        unless server.mongos?
          msg = "The session being used is pinned to the server which is not a mongos: #{server.summary} " +
            "(after #{server_selection_timeout} seconds)"
          raise Error::NoServerAvailable.new(self, cluster, msg)
        end
      end

      return server
    end
  end

  if cluster.replica_set?
    validate_max_staleness_value_early!
  end

  if cluster.addresses.empty?
    if Lint.enabled?
      unless cluster.servers.empty?
        raise Error::LintError, "Cluster has no addresses but has servers: #{cluster.servers.map(&:inspect).join(', ')}"
      end
    end
    msg = "Cluster has no addresses, and therefore will never have a server"
    raise Error::NoServerAvailable.new(self, cluster, msg)
  end

=begin Add this check in version 3.0.0
  unless cluster.connected?
    msg = 'Cluster is disconnected'
    raise Error::NoServerAvailable.new(self, cluster, msg)
  end
=end

  loop do
    server = try_select_server(cluster, write_aggregation: write_aggregation)

    if server
      unless cluster.topology.compatible?
        raise Error::UnsupportedFeatures, cluster.topology.compatibility_error.to_s
      end

      if session && session.starting_transaction? && cluster.sharded?
        session.pin_to_server(server)
      end

      return server
    end

    cluster.scan!(false)

    time_remaining = deadline - Utils.monotonic_time
    if time_remaining > 0
      wait_for_server_selection(cluster, time_remaining)

      # If we wait for server selection, perform another round of
      # attempting to locate a suitable server. Otherwise server selection
      # can raise NoServerAvailable message when the diagnostics
      # reports an available server of the requested type.
    else
      break
    end
  end

  msg = "No #{name} server"
  if is_a?(ServerSelector::Secondary) && !tag_sets.empty?
    msg += " with tag sets: #{tag_sets}"
  end
  msg += " is available in cluster: #{cluster.summary} " +
          "with timeout=#{server_selection_timeout}, " +
          "LT=#{local_threshold_with_cluster(cluster)}"
  msg += server_selection_diagnostic_message(cluster)
  raise Error::NoServerAvailable.new(self, cluster, msg)
rescue Error::NoServerAvailable => e
  if session && session.in_transaction? && !session.committing_transaction?
    e.add_label('TransientTransactionError')
  end
  if session && session.committing_transaction?
    e.add_label('UnknownTransactionCommitResult')
  end
  raise e
end

#server_selection_timeoutFloat

Deprecated.

This setting is now taken from the cluster options when a server is selected. Will be removed in version 3.0.

Get the timeout for server selection.

Examples:

Get the server selection timeout, in seconds.

selector.server_selection_timeout

Returns:

  • (Float)

    The timeout.

Since:

  • 2.0.0



89
90
91
92
# File 'build/ruby-driver-master/lib/mongo/server_selector/base.rb', line 89

def server_selection_timeout
  @server_selection_timeout ||=
    (options[:server_selection_timeout] || ServerSelector::SERVER_SELECTION_TIMEOUT)
end

#suitable_servers(cluster) ⇒ Array<Server>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns servers satisfying the server selector from the cluster.

Parameters:

  • cluster (Cluster)

    The cluster.

Returns:

  • (Array<Server>)

    The suitable servers.

Since:

  • 2.0.0



382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
# File 'build/ruby-driver-master/lib/mongo/server_selector/base.rb', line 382

def suitable_servers(cluster)
  if cluster.single?
    candidates(cluster)
  elsif cluster.sharded?
    local_threshold = local_threshold_with_cluster(cluster)
    servers = candidates(cluster)
    near_servers(servers, local_threshold)
  elsif cluster.replica_set?
    validate_max_staleness_value!(cluster)
    candidates(cluster)
  else
    # Unknown cluster - no servers
    []
  end
end

#try_select_server(cluster, write_aggregation: false) ⇒ Server | nil

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Tries to find a suitable server, returns the server if one is available or nil if there isn't a suitable server.

Parameters:

  • cluster (Mongo::Cluster)

    The cluster from which to select an eligible server.

  • write_aggregation (true | false) (defaults to: false)

    Whether we need a server that supports writing aggregations (e.g. with $merge/$out) on secondaries.

Returns:

  • (Server | nil)

    A suitable server, if one exists.

Since:

  • 2.0.0



307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
# File 'build/ruby-driver-master/lib/mongo/server_selector/base.rb', line 307

def try_select_server(cluster, write_aggregation: false)
  servers = if write_aggregation && cluster.replica_set?
    # 1. Check if ALL servers in cluster support secondary writes.
    is_write_supported = cluster.servers.reduce(true) do |res, server|
      res && server.features.merge_out_on_secondary_enabled?
    end

    if is_write_supported
      # 2. If all servers support secondary writes, we respect read preference.
      suitable_servers(cluster)
    else
      # 3. Otherwise we fallback to primary for replica set.
      [cluster.servers.detect(&:primary?)]
    end
  else
    suitable_servers(cluster)
  end

  # This list of servers may be ordered in a specific way
  # by the selector (e.g. for secondary preferred, the first
  # server may be a secondary and the second server may be primary)
  # and we should take the first server here respecting the order
  server = servers.first

  if server
    if Lint.enabled?
      # It is possible for a server to have a nil average RTT here
      # because the ARTT comes from description which may be updated
      # by a background thread while server selection is running.
      # Currently lint mode is not a public feature, if/when this
      # changes (https://jira.mongodb.org/browse/RUBY-1576) the
      # requirement for ARTT to be not nil would need to be removed.
      if server.average_round_trip_time.nil?
        raise Error::LintError, "Server #{server.address} has nil average rtt"
      end
    end
  end

  server
end