File: server_selection.rb

package info (click to toggle)
ruby-mongo 2.5.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 4,332 kB
  • sloc: ruby: 45,579; makefile: 5
file content (163 lines) | stat: -rw-r--r-- 5,430 bytes parent folder | download | duplicates (4)
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
module Mongo
  module ServerSelection
    module Read

      # Represents a Server Selection specification test.
      #
      # @since 2.0.0
      class Spec

        # Mapping of topology description strings to topology type classes.
        #
        # @since 2.0.0
        TOPOLOGY_TYPES = {
          'ReplicaSetNoPrimary' => Mongo::Cluster::Topology::ReplicaSet,
          'ReplicaSetWithPrimary' => Mongo::Cluster::Topology::ReplicaSet,
          'Sharded' => Mongo::Cluster::Topology::Sharded,
          'Single' => Mongo::Cluster::Topology::Single,
          'Unknown' => Mongo::Cluster::Topology::Unknown
        }

        # Mapping of read preference modes.
        #
        # @since 2.0.0
        READ_PREFERENCES = {
          'Primary' => :primary,
          'Secondary' => :secondary,
          'PrimaryPreferred' => :primary_preferred,
          'SecondaryPreferred' => :secondary_preferred,
          'Nearest' => :nearest,
        }

        # @return [ String ] description The spec description.
        #
        # @since 2.0.0
        attr_reader :description

        # @return [ Hash ] read_preference The read preference to be used for selection.
        #
        # @since 2.0.0
        attr_reader :read_preference

        # @return [ Integer ] heartbeat_frequency The heartbeat frequency to be set on the client.
        #
        # @since 2.4.0
        attr_reader :heartbeat_frequency

        # @return [ Integer ] max_staleness The max_staleness.
        #
        # @since 2.4.0
        attr_reader :max_staleness

        # @return [ Array<Hash> ] eligible_servers The eligible servers before the latency
        #   window is taken into account.
        #
        # @since 2.0.0
        attr_reader :eligible_servers

        # @return [ Array<Hash> ] suitable_servers The set of servers matching all server
        #  selection logic. May be a subset of eligible_servers and/or candidate_servers.
        #
        # @since 2.0.0
        attr_reader :suitable_servers

        # @return [ Mongo::Cluster::Topology ] type The topology type.
        #
        # @since 2.0.0
        attr_reader :type

        # Instantiate the new spec.
        #
        # @example Create the spec.
        #   Spec.new(file)
        #
        # @param [ String ] file The name of the file.
        #
        # @since 2.0.0
        def initialize(file)
          file = File.new(file)
          @test = YAML.load(ERB.new(file.read).result)
          file.close
          @description = "#{@test['topology_description']['type']}: #{File.basename(file)}"
          @heartbeat_frequency = @test['heartbeatFrequencyMS'] / 1000 if @test['heartbeatFrequencyMS']
          @read_preference = @test['read_preference']
          @read_preference['mode'] = READ_PREFERENCES[@read_preference['mode']]
          @max_staleness = @read_preference['maxStalenessSeconds']
          @candidate_servers = @test['topology_description']['servers']
          @suitable_servers = @test['suitable_servers'] || []
          @in_latency_window = @test['in_latency_window'] || []
          @type = TOPOLOGY_TYPES[@test['topology_description']['type']]
        end

        # Whether this spec describes a replica set.
        #
        # @example Determine if the spec describes a replica set.
        #   spec.replica_set?
        #
        # @return [true, false] If the spec describes a replica set.
        #
        # @since 2.0.0
        def replica_set?
          type == Mongo::Cluster::Topology::ReplicaSet
        end

        # Does this spec expect a server to be found.
        #
        # @example Will a server be found with this spec.
        #   spec.server_available?
        #
        # @return [true, false] If a server will be found with this spec.
        #
        # @since 2.0.0
        def server_available?
          !in_latency_window.empty?
        end

        # Is the max staleness setting invalid.
        #
        # @example Will the max staleness setting be valid with other options.
        #   spec.invalid_max_staleness?
        #
        # @return [ true, false ] If an error will be raised by the max staleness setting.
        #
        # @since 2.4.0
        def invalid_max_staleness?
          @test['error']
        end

        # The subset of suitable servers that falls within the allowable latency
        #   window.
        # We have to correct for our server selection algorithm that adds the primary
        #  to the end of the list for SecondaryPreferred read preference mode.
        #
        # @example Get the list of suitable servers within the latency window.
        #   spec.in_latency_window
        #
        # @return [ Array<Hash> ] The servers within the latency window.
        #
        # @since 2.0.0
        def in_latency_window
          if read_preference['mode'] == :secondary_preferred && primary
            return @in_latency_window.push(primary).uniq
          end
          @in_latency_window
        end

        # The servers a topology would return as candidates for selection.
        #
        # @return [ Array<Hash> ] candidate_servers The candidate servers.
        #
        # @since 2.0.0
        def candidate_servers
          @candidate_servers.select { |s| s['type'] != 'Unknown' }
        end

        private

        def primary
          @candidate_servers.find { |s| s['type'] == 'RSPrimary' }
        end
      end
    end
  end
end