1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 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
|
# frozen_string_literal: true
# rubocop:todo all
# Copyright (C) 2018-2020 MongoDB Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module Mongo
class Cluster
module Topology
# Defines behavior common to all topologies.
#
# @since 2.7.0
class Base
extend Forwardable
include Loggable
include Monitoring::Publishable
# Initialize the topology with the options.
#
# @param [ Hash ] options The options.
# @param [ Monitoring ] monitoring The monitoring.
# @param [ Cluster ] cluster The cluster.
#
# @option options [ Symbol ] :replica_set Name of the replica set to
# connect to. Can be left blank (either nil or the empty string are
# accepted) to discover the name from the cluster. If the addresses
# belong to different replica sets there is no guarantee which
# replica set is selected - in particular, the driver may choose
# the replica set name of a secondary if it returns its response
# prior to a primary belonging to a different replica set.
# This option can only be specified when instantiating a replica
# set topology.
# @option options [ BSON::ObjectId ] :max_election_id Max election id
# per the SDAM specification.
# This option can only be specified when instantiating a replica
# set topology.
# @option options [ Integer ] :max_set_version Max set version
# per the SDAM specification.
# This option can only be specified when instantiating a replica
# set topology.
#
# @since 2.7.0
# @api private
def initialize(options, monitoring, cluster)
options = validate_options(options, cluster)
@options = options
@monitoring = monitoring
@cluster = cluster
# The list of server descriptions is simply fixed at the time of
# topology creation. If server description change later, a
# new topology instance should be created.
@server_descriptions = {}
(servers = cluster.servers_list).each do |server|
@server_descriptions[server.address.to_s] = server.description
end
if is_a?(LoadBalanced)
@compatible = true
else
begin
server_descriptions.each do |address_str, desc|
unless desc.unknown?
desc.features.check_driver_support!
end
end
rescue Error::UnsupportedFeatures => e
@compatible = false
@compatibility_error = e
else
@compatible = true
end
end
@have_data_bearing_servers = false
@logical_session_timeout = server_descriptions.inject(nil) do |min, (address_str, desc)|
# LST is only read from data-bearing servers
if desc.data_bearing?
@have_data_bearing_servers = true
break unless timeout = desc.logical_session_timeout
[timeout, (min || timeout)].min
else
min
end
end
if Mongo::Lint.enabled?
freeze
end
end
# @return [ Hash ] options The options.
attr_reader :options
# @return [ Cluster ] The cluster.
# @api private
attr_reader :cluster
private :cluster
# @return [ Array<String> ] addresses Server addresses.
def addresses
cluster.addresses.map(&:seed)
end
# @return [ monitoring ] monitoring the monitoring.
attr_reader :monitoring
# Get the replica set name configured for this topology.
#
# @example Get the replica set name.
# topology.replica_set_name
#
# @return [ String ] The name of the configured replica set.
#
# @since 2.0.0
def replica_set_name
options[:replica_set_name]
end
# @return [ Hash ] server_descriptions The map of address strings to
# server descriptions, one for each server in the cluster.
#
# @since 2.7.0
attr_reader :server_descriptions
# @return [ true|false ] compatible Whether topology is compatible
# with the driver.
#
# @since 2.7.0
def compatible?
@compatible
end
# @return [ Exception ] compatibility_error If topology is incompatible
# with the driver, an exception with information regarding the incompatibility.
# If topology is compatible with the driver, nil.
#
# @since 2.7.0
attr_reader :compatibility_error
# The logical session timeout value in minutes.
#
# @note The value is in minutes, unlike most other times in the
# driver which are returned in seconds.
#
# @return [ Integer, nil ] The logical session timeout.
#
# @since 2.7.0
attr_reader :logical_session_timeout
# @return [ true | false ] have_data_bearing_servers Whether the
# topology has any data bearing servers, for the purposes of
# logical session timeout calculation.
#
# @api private
def data_bearing_servers?
@have_data_bearing_servers
end
# The largest electionId ever reported by a primary.
# May be nil.
#
# @return [ BSON::ObjectId ] The election id.
#
# @since 2.7.0
def max_election_id
options[:max_election_id]
end
# The largest setVersion ever reported by a primary.
# May be nil.
#
# @return [ Integer ] The set version.
#
# @since 2.7.0
def max_set_version
options[:max_set_version]
end
# @api private
def new_max_election_id(description)
if description.election_id &&
(max_election_id.nil? ||
description.election_id > max_election_id)
description.election_id
else
max_election_id
end
end
# @api private
def new_max_set_version(description)
if description.set_version &&
(max_set_version.nil? ||
description.set_version > max_set_version)
description.set_version
else
max_set_version
end
end
# Compares each server address against the list of patterns.
#
# @param [ Array<String> ] patterns the URL suffixes to compare
# each server against.
#
# @return [ true | false ] whether any of the addresses match any of
# the patterns or not.
#
# @api private
def server_hosts_match_any?(patterns)
server_descriptions.any? do |addr_spec, _desc|
addr, _port = addr_spec.split(/:/)
patterns.any? { |pattern| addr.end_with?(pattern) }
end
end
private
# Validates and/or transforms options as necessary for the topology.
#
# @return [ Hash ] New options
def validate_options(options, cluster)
options
end
end
end
end
end
|