moped 1.5.3 → 2.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of moped might be problematic. Click here for more details.

Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -5
  3. data/README.md +1 -1
  4. data/lib/moped.rb +10 -13
  5. data/lib/moped/address.rb +56 -0
  6. data/lib/moped/authenticatable.rb +89 -0
  7. data/lib/moped/cluster.rb +169 -136
  8. data/lib/moped/collection.rb +53 -19
  9. data/lib/moped/connection.rb +69 -10
  10. data/lib/moped/connection/manager.rb +49 -0
  11. data/lib/moped/connection/pool.rb +198 -0
  12. data/lib/moped/connection/queue.rb +93 -0
  13. data/lib/moped/connection/reaper.rb +52 -0
  14. data/lib/moped/connection/socket.rb +4 -0
  15. data/lib/moped/connection/socket/connectable.rb +169 -0
  16. data/lib/moped/connection/socket/ssl.rb +52 -0
  17. data/lib/moped/connection/socket/tcp.rb +25 -0
  18. data/lib/moped/connection/sockets.rb +4 -0
  19. data/lib/moped/cursor.rb +3 -5
  20. data/lib/moped/database.rb +18 -24
  21. data/lib/moped/errors.rb +35 -6
  22. data/lib/moped/executable.rb +96 -0
  23. data/lib/moped/failover.rb +41 -0
  24. data/lib/moped/failover/disconnect.rb +31 -0
  25. data/lib/moped/failover/ignore.rb +29 -0
  26. data/lib/moped/failover/reconfigure.rb +34 -0
  27. data/lib/moped/failover/retry.rb +37 -0
  28. data/lib/moped/indexes.rb +4 -1
  29. data/lib/moped/instrumentable.rb +39 -0
  30. data/lib/moped/instrumentable/log.rb +43 -0
  31. data/lib/moped/instrumentable/noop.rb +31 -0
  32. data/lib/moped/loggable.rb +110 -0
  33. data/lib/moped/node.rb +316 -297
  34. data/lib/moped/operation.rb +3 -0
  35. data/lib/moped/operation/read.rb +62 -0
  36. data/lib/moped/operation/write.rb +57 -0
  37. data/lib/moped/protocol/command.rb +65 -4
  38. data/lib/moped/protocol/commands/authenticate.rb +1 -2
  39. data/lib/moped/protocol/delete.rb +16 -0
  40. data/lib/moped/protocol/get_more.rb +102 -31
  41. data/lib/moped/protocol/insert.rb +17 -0
  42. data/lib/moped/protocol/message.rb +44 -46
  43. data/lib/moped/protocol/query.rb +175 -92
  44. data/lib/moped/protocol/reply.rb +19 -8
  45. data/lib/moped/protocol/update.rb +18 -0
  46. data/lib/moped/query.rb +43 -17
  47. data/lib/moped/read_preference.rb +49 -0
  48. data/lib/moped/read_preference/nearest.rb +55 -0
  49. data/lib/moped/read_preference/primary.rb +60 -0
  50. data/lib/moped/read_preference/primary_preferred.rb +55 -0
  51. data/lib/moped/read_preference/secondary.rb +50 -0
  52. data/lib/moped/read_preference/secondary_preferred.rb +53 -0
  53. data/lib/moped/read_preference/selectable.rb +79 -0
  54. data/lib/moped/readable.rb +55 -0
  55. data/lib/moped/session.rb +122 -70
  56. data/lib/moped/{mongo_uri.rb → uri.rb} +75 -31
  57. data/lib/moped/version.rb +1 -1
  58. data/lib/moped/write_concern.rb +33 -0
  59. data/lib/moped/write_concern/propagate.rb +38 -0
  60. data/lib/moped/write_concern/unverified.rb +28 -0
  61. metadata +79 -44
  62. data/lib/moped/bson.rb +0 -45
  63. data/lib/moped/bson/binary.rb +0 -137
  64. data/lib/moped/bson/code.rb +0 -112
  65. data/lib/moped/bson/document.rb +0 -41
  66. data/lib/moped/bson/extensions.rb +0 -91
  67. data/lib/moped/bson/extensions/array.rb +0 -37
  68. data/lib/moped/bson/extensions/boolean.rb +0 -16
  69. data/lib/moped/bson/extensions/false_class.rb +0 -19
  70. data/lib/moped/bson/extensions/float.rb +0 -22
  71. data/lib/moped/bson/extensions/hash.rb +0 -39
  72. data/lib/moped/bson/extensions/integer.rb +0 -36
  73. data/lib/moped/bson/extensions/nil_class.rb +0 -19
  74. data/lib/moped/bson/extensions/object.rb +0 -11
  75. data/lib/moped/bson/extensions/regexp.rb +0 -38
  76. data/lib/moped/bson/extensions/string.rb +0 -45
  77. data/lib/moped/bson/extensions/symbol.rb +0 -33
  78. data/lib/moped/bson/extensions/time.rb +0 -23
  79. data/lib/moped/bson/extensions/true_class.rb +0 -19
  80. data/lib/moped/bson/max_key.rb +0 -51
  81. data/lib/moped/bson/min_key.rb +0 -51
  82. data/lib/moped/bson/object_id.rb +0 -301
  83. data/lib/moped/bson/timestamp.rb +0 -38
  84. data/lib/moped/bson/types.rb +0 -67
  85. data/lib/moped/logging.rb +0 -58
  86. data/lib/moped/session/context.rb +0 -115
  87. data/lib/moped/sockets/connectable.rb +0 -167
  88. data/lib/moped/sockets/ssl.rb +0 -50
  89. data/lib/moped/sockets/tcp.rb +0 -23
  90. data/lib/moped/threaded.rb +0 -69
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 76d85fae38ea0ef7558bf6961c620082e3792f8c
4
- data.tar.gz: c166d20629d965e0db7dfba2a91b758eaba55083
3
+ metadata.gz: 13a013a208ac0941e9a6d68d183574f2becafa79
4
+ data.tar.gz: 808d31b55227c47ff8d9503918c218d191b6b193
5
5
  SHA512:
6
- metadata.gz: 7027124e3caefcc77952ae0f8af98690f877b67ae759a175fdd79b65c4e4b063106a15b3fdda1163ab3e506e4778e22833eae70abed95b7e88286ee4abee6508
7
- data.tar.gz: 0a0eb20add7205c06e78be13f82861dc999a37376bf7f7de3d68f10853152c11853a217b25b43f7bbeb9247dfef6d292014feb416c8481691a3d7b6fcb4d96f1
6
+ metadata.gz: 56f954deab2f283830fc371a134d8f1b9055b6d985910886a27ed905a55b58403044f7acd9ea58e363b5dd296858a7dadc152ca8934e048c9fcec7ad60e5d600
7
+ data.tar.gz: b568935bcda3e6a73e5601819de389bab69f9e1acba1b40395bd0042b1a062ea86606e787778505fb08a3230855e9cf1b8be57d30925bd6611fe03967a8d1114
data/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # Overview
2
2
 
3
+ ## 2.0.0
4
+
5
+ ### New Features
6
+
7
+ * \#196 Adding method on collection to rename itself (Arthur Neves)
8
+
9
+ ### API Changes (Backwards Incompatible)
10
+
11
+ * \#190 Connection retries are now logged. (Jan Paul Posma)
12
+
13
+ * \#133 Moped now supports the new read preferences that the core drivers
14
+ provide. These include:
15
+
16
+ - `:primary`: Will always read from a primary node. (default)
17
+ - `:primary_preferred`: Attempt a primary first, then secondary if none available.
18
+ - `:secondary`: Will always read from a secondary node.
19
+ - `:secondary_preferred`: Attempt a secondary first, then primary if none available.
20
+ - `:nearest`: Attempt to read from the node with the lowest latency.
21
+
22
+ Sample syntax:
23
+
24
+ Moped::Session.new([ "127.0.0.1:27017" ], read: :secondary)
25
+ session.with(read: :nearest)[:users].find
26
+
27
+ The `:consistency` option is no longer valid and will be ignored.
28
+
29
+ * \#92 Moped now defaults all writes to propagate (formerly "safe mode") and now
30
+ has different propagate semantics:
31
+
32
+ - `{ w: -1 }`: Don't verify writes and raise no network errors.
33
+ - `{ w: 0 }`: Don't verify writes and raise network errors.
34
+ - `{ w: 1 }`: Verify writes on the primary node. (default)
35
+ - `{ w: n }`: Verify writes on n number of nodes.
36
+ - `{ w: :majority }`: Verify writes on a majority of nodes.
37
+
38
+ Sample syntax:
39
+
40
+ Moped::Session.new([ "127.0.0.1:27017" ], write: { w: 0 })
41
+ session.with(write: { w: -1 })[:users].insert(document)
42
+
43
+ The `:safe` option is no longer valid and will be ignored.
44
+
3
45
  ## 1.5.1
4
46
 
5
47
  ### Resolved Issues
@@ -23,15 +65,10 @@
23
65
 
24
66
  Moped::Session.new([ "127.0.0.1:27017" ], auto_discover: false)
25
67
 
26
- * \#189 Moped now logs connection attempts during retries. (Jan Paul Posma)
27
-
28
68
  ## 1.4.6
29
69
 
30
70
  ### Resolved Issues
31
71
 
32
- * \#192 Return the proper result after reauthentication attempts.
33
- (Jonathan Hyman)
34
-
35
72
  * \#191 Checking for "not authorized" in error messages. (Jonathan Hyman)
36
73
 
37
74
  ## 1.4.5
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- Mop[ed [![Build Status](https://secure.travis-ci.org/mongoid/moped.png?branch=master&.png)](http://travis-ci.org/mongoid/moped) [![Code Climate](https://codeclimate.com/github/mongoid/moped.png)](https://codeclimate.com/github/mongoid/moped)
1
+ Moped [![Build Status](https://secure.travis-ci.org/mongoid/moped.png?branch=master&.png)](http://travis-ci.org/mongoid/moped) [![Code Climate](https://codeclimate.com/github/mongoid/moped.png)](https://codeclimate.com/github/mongoid/moped) [![Coverage Status](https://coveralls.io/repos/mongoid/moped/badge.png?branch=master)](https://coveralls.io/r/mongoid/moped?branch=master)
2
2
  ========
3
3
 
4
4
  Moped is a MongoDB driver for Ruby, which exposes a simple, elegant, and fast
data/lib/moped.rb CHANGED
@@ -1,21 +1,18 @@
1
+ # encoding: utf-8
1
2
  require "logger"
2
3
  require "stringio"
3
4
  require "monitor"
4
-
5
- require "moped/bson"
6
- require "moped/cluster"
7
- require "moped/collection"
8
- require "moped/connection"
9
- require "moped/cursor"
10
- require "moped/database"
5
+ require "timeout"
6
+ require "bson"
7
+ require "optionable"
11
8
  require "moped/errors"
12
9
  require "moped/indexes"
13
- require "moped/logging"
14
- require "moped/mongo_uri"
15
- require "moped/node"
10
+ require "moped/loggable"
11
+ require "moped/uri"
16
12
  require "moped/protocol"
17
- require "moped/query"
18
13
  require "moped/session"
19
- require "moped/session/context"
20
- require "moped/threaded"
21
14
  require "moped/version"
15
+
16
+ module Moped
17
+ extend Loggable
18
+ end
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+ module Moped
3
+
4
+ # Encapsulates behaviour around addresses and resolving dns.
5
+ #
6
+ # @since 2.0.0
7
+ class Address
8
+
9
+ # @!attribute host
10
+ # @return [ String ] The host name.
11
+ # @!attribute ip
12
+ # @return [ String ] The ip address.
13
+ # @!attribute original
14
+ # @return [ String ] The original host name.
15
+ # @!attribute port
16
+ # @return [ Integer ] The port.
17
+ # @!attribute resolved
18
+ # @return [ String ] The full resolved address.
19
+ attr_reader :host, :ip, :original, :port, :resolved
20
+
21
+ # Instantiate the new address.
22
+ #
23
+ # @example Instantiate the address.
24
+ # Moped::Address.new("localhost:27017")
25
+ #
26
+ # @param [ String ] address The host:port pair as a string.
27
+ #
28
+ # @since 2.0.0
29
+ def initialize(address)
30
+ @original = address
31
+ @host, port = address.split(":")
32
+ @port = (port || 27017).to_i
33
+ end
34
+
35
+ # Resolve the address for the provided node. If the address cannot be
36
+ # resolved the node will be flagged as down.
37
+ #
38
+ # @example Resolve the address.
39
+ # address.resolve(node)
40
+ #
41
+ # @param [ Node ] node The node to resolve for.
42
+ #
43
+ # @return [ String ] The resolved address.
44
+ #
45
+ # @since 2.0.0
46
+ def resolve(node)
47
+ begin
48
+ @ip ||= Socket.getaddrinfo(host, nil, Socket::AF_INET, Socket::SOCK_STREAM).first[3]
49
+ @resolved ||= "#{ip}:#{port}"
50
+ rescue SocketError => e
51
+ node.instrument(Node::WARN, prefix: " MOPED:", message: "Could not resolve IP for: #{original}")
52
+ node.down! and false
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,89 @@
1
+ # encoding: utf-8
2
+ module Moped
3
+
4
+ # Provides behaviour to nodes around authentication.
5
+ #
6
+ # @since 2.0.0
7
+ module Authenticatable
8
+
9
+ # Apply authentication credentials.
10
+ #
11
+ # @example Apply the authentication credentials.
12
+ # node.apply_credentials({ "moped_test" => [ "user", "pass" ]})
13
+ #
14
+ # @param [ Hash ] credentials The authentication credentials in the form:
15
+ # { database_name: [ user, password ]}
16
+ #
17
+ # @return [ Object ] The authenticated object.
18
+ #
19
+ # @since 2.0.0
20
+ def apply_credentials(logins)
21
+ unless credentials == logins
22
+ logouts = credentials.keys - logins.keys
23
+ logouts.each do |database|
24
+ logout(database)
25
+ end
26
+ logins.each do |database, (username, password)|
27
+ unless credentials[database] == [ username, password ]
28
+ login(database, username, password)
29
+ end
30
+ end
31
+ end
32
+ self
33
+ end
34
+
35
+ # Get the applied credentials.
36
+ #
37
+ # @example Get the applied credentials.
38
+ # node.credentials
39
+ #
40
+ # @return [ Hash ] The credentials.
41
+ #
42
+ # @since 2.0.0
43
+ def credentials
44
+ @credentials ||= {}
45
+ end
46
+
47
+ # Login the user to the provided database with the supplied password.
48
+ #
49
+ # @example Login the user to the database.
50
+ # node.login("moped_test", "user", "pass")
51
+ #
52
+ # @param [ String ] database The database name.
53
+ # @param [ String ] username The username.
54
+ # @param [ String ] password The password.
55
+ #
56
+ # @raise [ Errors::AuthenticationFailure ] If the login failed.
57
+ #
58
+ # @return [ Array ] The username and password.
59
+ #
60
+ # @since 2.0.0
61
+ def login(database, username, password)
62
+ getnonce = Protocol::Command.new(database, getnonce: 1)
63
+ result = Operation::Read.new(getnonce).execute(self)
64
+ authenticate = Protocol::Commands::Authenticate.new(database, username, password, result["nonce"])
65
+ connection do |conn|
66
+ conn.write([ authenticate ])
67
+ document = conn.read.documents.first
68
+ raise Errors::AuthenticationFailure.new(authenticate, document) unless document["ok"] == 1
69
+ credentials[database] = [username, password]
70
+ end
71
+ end
72
+
73
+ # Logout the user from the provided database.
74
+ #
75
+ # @example Logout from the provided database.
76
+ # node.logout("moped_test")
77
+ #
78
+ # @param [ String ] database The database name.
79
+ #
80
+ # @return [ Array ] The username and password.
81
+ #
82
+ # @since 2.0.0
83
+ def logout(database)
84
+ command = Protocol::Command.new(database, logout: 1)
85
+ Operation::Read.new(command).execute(self)
86
+ credentials.delete(database)
87
+ end
88
+ end
89
+ end
data/lib/moped/cluster.rb CHANGED
@@ -1,23 +1,47 @@
1
+ # encoding: utf-8
2
+ require "moped/node"
3
+
1
4
  module Moped
2
5
 
3
6
  # The cluster represents a cluster of MongoDB server nodes, either a single
4
7
  # node, a replica set, or a mongos server.
8
+ #
9
+ # @since 1.0.0
5
10
  class Cluster
6
11
 
7
- # @attribute [r] options The cluster options.
8
- # @attribute [r] seeds The seeds the cluster was initialized with.
9
- attr_reader :options, :seeds
12
+ # The default interval that a node would be flagged as "down".
13
+ #
14
+ # @since 2.0.0
15
+ DOWN_INTERVAL = 30
16
+
17
+ # The default interval that a node should be refreshed in.
18
+ #
19
+ # @since 2.0.0
20
+ REFRESH_INTERVAL = 300
21
+
22
+ # The default time to wait to retry an operation.
23
+ #
24
+ # @since 2.0.0
25
+ RETRY_INTERVAL = 0.25
26
+
27
+ # @!attribute options
28
+ # @return [ Hash ] The refresh options.
29
+ # @!attribute peers
30
+ # @return [ Array<Node> ] The node peers.
31
+ # @!attribute seeds
32
+ # @return [ Array<Node> ] The seed nodes.
33
+ attr_reader :options, :peers, :seeds
10
34
 
11
35
  # Get the credentials for the cluster.
12
36
  #
13
- # @example Get the authentication details.
14
- # cluster.auth
37
+ # @example Get the applied credentials.
38
+ # node.credentials
15
39
  #
16
- # @return [ Hash ] the cached authentication credentials for this cluster.
40
+ # @return [ Hash ] The credentials.
17
41
  #
18
- # @since 1.0.0
19
- def auth
20
- @auth ||= {}
42
+ # @since 2.0.0
43
+ def credentials
44
+ @credentials ||= {}
21
45
  end
22
46
 
23
47
  # Disconnects all nodes in the cluster. This should only be used in cases
@@ -28,7 +52,7 @@ module Moped
28
52
  #
29
53
  # @since 1.2.0
30
54
  def disconnect
31
- nodes(include_arbiters: true).each { |node| node.disconnect } and true
55
+ nodes.each { |node| node.disconnect } and true
32
56
  end
33
57
 
34
58
  # Get the interval at which a node should be flagged as down before
@@ -41,45 +65,7 @@ module Moped
41
65
  #
42
66
  # @since 1.2.7
43
67
  def down_interval
44
- options[:down_interval]
45
- end
46
-
47
- # Get the number of times an operation should be retried before raising an
48
- # error.
49
- #
50
- # @example Get the maximum retries.
51
- # cluster.max_retries
52
- #
53
- # @return [ Integer ] The max retries.
54
- #
55
- # @since 1.2.7
56
- def max_retries
57
- options[:max_retries]
58
- end
59
-
60
- # Get the interval in which the node list should be refreshed.
61
- #
62
- # @example Get the refresh interval, in seconds.
63
- # cluster.refresh_interval
64
- #
65
- # @return [ Integer ] The refresh interval.
66
- #
67
- # @since 1.2.7
68
- def refresh_interval
69
- options[:refresh_interval]
70
- end
71
-
72
- # Get the operation retry interval - the time to wait before retrying a
73
- # single operation.
74
- #
75
- # @example Get the retry interval, in seconds.
76
- # cluster.retry_interval
77
- #
78
- # @return [ Integer ] The retry interval.
79
- #
80
- # @since 1.2.7
81
- def retry_interval
82
- options[:retry_interval]
68
+ @down_interval ||= options[:down_interval] || DOWN_INTERVAL
83
69
  end
84
70
 
85
71
  # Initialize the new cluster.
@@ -98,16 +84,34 @@ module Moped
98
84
  #
99
85
  # @since 1.0.0
100
86
  def initialize(hosts, options)
101
- @seeds = hosts
102
- @nodes = hosts.map { |host| Node.new(host, options) }
87
+ @seeds = hosts.map{ |host| Node.new(host, options) }
103
88
  @peers = []
89
+ @options = options
90
+ end
91
+
92
+ # Provide a pretty string for cluster inspection.
93
+ #
94
+ # @example Inspect the cluster.
95
+ # cluster.inspect
96
+ #
97
+ # @return [ String ] A nicely formatted string.
98
+ #
99
+ # @since 1.0.0
100
+ def inspect
101
+ "#<#{self.class.name}:#{object_id} @seeds=#{seeds.inspect}>"
102
+ end
104
103
 
105
- @options = {
106
- down_interval: 30,
107
- max_retries: 20,
108
- refresh_interval: 300,
109
- retry_interval: 0.25
110
- }.merge(options)
104
+ # Get the number of times an operation should be retried before raising an
105
+ # error.
106
+ #
107
+ # @example Get the maximum retries.
108
+ # cluster.max_retries
109
+ #
110
+ # @return [ Integer ] The max retries.
111
+ #
112
+ # @since 1.2.7
113
+ def max_retries
114
+ @max_retries ||= options[:max_retries] || seeds.size
111
115
  end
112
116
 
113
117
  # Returns the list of available nodes, refreshing 1) any nodes which were
@@ -120,25 +124,19 @@ module Moped
120
124
  # @return [ Array<Node> ] the list of available nodes.
121
125
  #
122
126
  # @since 1.0.0
123
- def nodes(opts = {})
124
- current_time = Time.new
125
- down_boundary = current_time - down_interval
126
- refresh_boundary = current_time - refresh_interval
127
-
127
+ def nodes
128
128
  # Find the nodes that were down but are ready to be refreshed, or those
129
129
  # with stale connection information.
130
- needs_refresh, available = @nodes.partition do |node|
131
- node.down? ? (node.down_at < down_boundary) : node.needs_refresh?(refresh_boundary)
130
+ needs_refresh, available = seeds.partition do |node|
131
+ refreshable?(node)
132
132
  end
133
133
 
134
134
  # Refresh those nodes.
135
- available.concat refresh(needs_refresh)
135
+ available.concat(refresh(needs_refresh))
136
136
 
137
137
  # Now return all the nodes that are available and participating in the
138
138
  # replica set.
139
- available.reject do |node|
140
- node.down? || !member?(node) || (!opts[:include_arbiters] && node.arbiter?)
141
- end
139
+ available.reject{ |node| node.down? }
142
140
  end
143
141
 
144
142
  # Refreshes information for each of the nodes provided. The node list
@@ -155,24 +153,19 @@ module Moped
155
153
  # @return [ Array<Node> ] the available nodes
156
154
  #
157
155
  # @since 1.0.0
158
- def refresh(nodes_to_refresh = @nodes)
156
+ def refresh(nodes_to_refresh = seeds)
159
157
  refreshed_nodes = []
160
158
  seen = {}
161
-
162
159
  # Set up a recursive lambda function for refreshing a node and it's peers.
163
160
  refresh_node = ->(node) do
164
161
  unless seen[node]
165
162
  seen[node] = true
166
-
167
163
  # Add the node to the global list of known nodes.
168
- @nodes << node unless @nodes.include?(node)
169
-
164
+ seeds.push(node) unless seeds.include?(node)
170
165
  begin
171
166
  node.refresh
172
-
173
167
  # This node is good, so add it to the list of nodes to return.
174
- refreshed_nodes << node unless refreshed_nodes.include?(node)
175
-
168
+ refreshed_nodes.push(node) unless refreshed_nodes.include?(node)
176
169
  # Now refresh any newly discovered peer nodes - this will also
177
170
  # remove nodes that are not included in the peer list.
178
171
  refresh_peers(node, &refresh_node)
@@ -183,7 +176,32 @@ module Moped
183
176
  end
184
177
 
185
178
  nodes_to_refresh.each(&refresh_node)
186
- refreshed_nodes.to_a
179
+ refreshed_nodes
180
+ end
181
+
182
+ # Get the interval in which the node list should be refreshed.
183
+ #
184
+ # @example Get the refresh interval, in seconds.
185
+ # cluster.refresh_interval
186
+ #
187
+ # @return [ Integer ] The refresh interval.
188
+ #
189
+ # @since 1.2.7
190
+ def refresh_interval
191
+ @refresh_interval ||= options[:refresh_interval] || REFRESH_INTERVAL
192
+ end
193
+
194
+ # Get the operation retry interval - the time to wait before retrying a
195
+ # single operation.
196
+ #
197
+ # @example Get the retry interval, in seconds.
198
+ # cluster.retry_interval
199
+ #
200
+ # @return [ Integer ] The retry interval.
201
+ #
202
+ # @since 1.2.7
203
+ def retry_interval
204
+ @retry_interval ||= options[:retry_interval] || RETRY_INTERVAL
187
205
  end
188
206
 
189
207
  # Yields the replica set's primary node to the provided block. This method
@@ -202,30 +220,16 @@ module Moped
202
220
  # @return [ Object ] The result of the yield.
203
221
  #
204
222
  # @since 1.0.0
205
- def with_primary(retries = max_retries, &block)
223
+ def with_primary(&block)
206
224
  if node = nodes.find(&:primary?)
207
225
  begin
208
226
  node.ensure_primary do
209
- return yield node.apply_auth(auth)
227
+ return yield(node.apply_credentials(credentials))
210
228
  end
211
229
  rescue Errors::ConnectionFailure, Errors::ReplicaSetReconfigured
212
- # Fall through to the code below if our connection was dropped or the
213
- # node is no longer the primary.
214
230
  end
215
231
  end
216
-
217
- if retries > 0
218
- # We couldn't find a primary node, so refresh the list and try again.
219
- warning(" MOPED: Retrying connection to primary for replica set #{inspect}")
220
- sleep(retry_interval)
221
- refresh
222
- with_primary(retries - 1, &block)
223
- else
224
- raise(
225
- Errors::ConnectionFailure,
226
- "Could not connect to a primary node for replica set #{inspect}"
227
- )
228
- end
232
+ raise Errors::ConnectionFailure, "Could not connect to a primary node for replica set #{inspect}"
229
233
  end
230
234
 
231
235
  # Yields a secondary node if available, otherwise the primary node. This
@@ -243,63 +247,92 @@ module Moped
243
247
  # @return [ Object ] The result of the yield.
244
248
  #
245
249
  # @since 1.0.0
246
- def with_secondary(retries = max_retries, &block)
247
- available_nodes = nodes.shuffle!.partition(&:secondary?).flatten
248
-
250
+ def with_secondary(&block)
251
+ available_nodes = nodes.select(&:secondary?).shuffle!
249
252
  while node = available_nodes.shift
250
253
  begin
251
- return yield node.apply_auth(auth)
252
- rescue Errors::ConnectionFailure
253
- warning(" MOPED: Connection failed to secondary node #{node.inspect}, trying next node.")
254
- # That node's no good, so let's try the next one.
255
- next
256
- rescue Errors::ReplicaSetReconfigured
257
- # That node's no good, so let's try the next one.
254
+ return yield(node.apply_credentials(credentials))
255
+ rescue Errors::ConnectionFailure => e
258
256
  next
259
257
  end
260
258
  end
261
-
262
- if retries > 0
263
- # We couldn't find a secondary or primary node, so refresh the list and
264
- # try again.
265
- warning(" MOPED: Could not connect to any node in replica set #{inspect}, refreshing list.")
266
- sleep(retry_interval)
267
- refresh
268
- with_secondary(retries - 1, &block)
269
- else
270
- raise(
271
- Errors::ConnectionFailure,
272
- "Could not connect to any secondary or primary nodes for replica set #{inspect}"
273
- )
274
- end
275
- end
276
-
277
- def inspect
278
- "<#{self.class.name} nodes=#{@nodes.inspect}>"
259
+ raise Errors::ConnectionFailure, "Could not connect to a secondary node for replica set #{inspect}"
279
260
  end
280
261
 
281
262
  private
282
263
 
283
- def initialize_copy(_)
284
- @nodes = @nodes.map(&:dup)
264
+ # Get the boundary where a node that is down would need to be refreshed.
265
+ #
266
+ # @api private
267
+ #
268
+ # @example Get the down boundary.
269
+ # cluster.down_boundary
270
+ #
271
+ # @return [ Time ] The down boundary.
272
+ #
273
+ # @since 2.0.0
274
+ def down_boundary
275
+ Time.new - down_interval
285
276
  end
286
277
 
287
- def member?(node)
288
- @peers.empty? || @peers.include?(node)
278
+ # Get the standard refresh boundary to discover new nodes.
279
+ #
280
+ # @api private
281
+ #
282
+ # @example Get the refresh boundary.
283
+ # cluster.refresh_boundary
284
+ #
285
+ # @return [ Time ] The refresh boundary.
286
+ #
287
+ # @since 2.0.0
288
+ def refresh_boundary
289
+ Time.new - refresh_interval
289
290
  end
290
291
 
291
- def refresh_peers(node, &block)
292
- peers = node.peers
293
- return if !peers || peers.empty?
294
- peers.each do |node|
295
- block.call(node) unless @nodes.include?(node)
296
- @peers.push(node) unless peers.include?(node)
297
- end
292
+ # Is the provided node refreshable? This is in the case where the refresh
293
+ # boundary has passed, or the node has been down longer than the down
294
+ # boundary.
295
+ #
296
+ # @api private
297
+ #
298
+ # @example Is the node refreshable?
299
+ # cluster.refreshable?(node)
300
+ #
301
+ # @param [ Node ] node The Node to check.
302
+ #
303
+ # @since 2.0.0
304
+ def refreshable?(node)
305
+ node.down? ? node.down_at < down_boundary : node.needs_refresh?(refresh_boundary)
306
+ end
307
+
308
+ # Creating a cloned cluster requires cloning all the seed nodes.
309
+ #
310
+ # @api prviate
311
+ #
312
+ # @example Clone the cluster.
313
+ # cluster.clone
314
+ #
315
+ # @return [ Cluster ] The cloned cluster.
316
+ #
317
+ # @since 1.0.0
318
+ def initialize_copy(_)
319
+ @seeds = seeds.map(&:dup)
298
320
  end
299
321
 
300
- def warning(message)
301
- if logger = Moped.logger
302
- logger.warn(message)
322
+ # Refresh the peers based on the node's peers.
323
+ #
324
+ # @api private
325
+ #
326
+ # @example Refresh the peers.
327
+ # cluster.refresh_peers(node)
328
+ #
329
+ # @param [ Node ] node The node to refresh the peers for.
330
+ #
331
+ # @since 1.0.0
332
+ def refresh_peers(node, &block)
333
+ node.peers.each do |node|
334
+ block.call(node) unless seeds.include?(node)
335
+ peers.push(node) unless peers.include?(node)
303
336
  end
304
337
  end
305
338
  end