moped 1.2.1 → 1.2.2

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.

data/CHANGELOG.md CHANGED
@@ -4,10 +4,20 @@
4
4
 
5
5
  ### New Features
6
6
 
7
- ## 1.2.2 (branch: 1.2.0-stable)
7
+ ## 1.2.2
8
8
 
9
9
  ### Resolved Issues
10
10
 
11
+ * \#73 Raise a `Moped::Errors::CursorNotFound` on long running queries where
12
+ the cursor was killed by the server. (Marius Podwyszynski)
13
+
14
+ * \#72 Reauthenticate properly when an `rs.stepDown()` occurs in the middle of
15
+ cursor execution.
16
+
17
+ * \#71 When DNS cannot resolve on node initialization, the node will be flagged
18
+ as down instead of raising a `SocketError`. On subsequent refreshes Moped will
19
+ attempt to resolve the DNS again to determine if the node can be brought up.
20
+
11
21
  ## 1.2.1
12
22
 
13
23
  ### Resolved Issues
data/lib/moped/errors.rb CHANGED
@@ -97,6 +97,13 @@ module Moped
97
97
  # Exception raised on invalid queries.
98
98
  class QueryFailure < MongoError; end
99
99
 
100
+ # Exception raised if the cursor could not be found.
101
+ class CursorNotFound < MongoError
102
+ def initialize(operation, cursor_id)
103
+ super(operation, {"errmsg" => "cursor #{cursor_id} not found"})
104
+ end
105
+ end
106
+
100
107
  # @api private
101
108
  #
102
109
  # Internal exception raised by Node#ensure_primary and captured by
data/lib/moped/node.rb CHANGED
@@ -125,7 +125,7 @@ module Moped
125
125
  # Someone else wrapped this in an #ensure_primary block, so let the
126
126
  # reconfiguration exception bubble up.
127
127
  raise
128
- rescue Errors::OperationFailure, Errors::AuthenticationFailure, Errors::QueryFailure
128
+ rescue Errors::OperationFailure, Errors::AuthenticationFailure, Errors::QueryFailure, Errors::CursorNotFound
129
129
  # These exceptions are "expected" in the normal course of events, and
130
130
  # don't necessitate disconnecting.
131
131
  raise
@@ -179,12 +179,15 @@ module Moped
179
179
  # @param [ Collection ] collection The collection to get more from.
180
180
  # @param [ Integer ] cursor_id The id of the cursor on the server.
181
181
  # @param [ Integer ] limit The number of documents to limit.
182
+ # @raise [ CursorNotFound ] if the cursor has been killed
182
183
  #
183
184
  # @return [ Message ] The result of the operation.
184
185
  #
185
186
  # @since 1.0.0
186
187
  def get_more(database, collection, cursor_id, limit)
187
- process(Protocol::GetMore.new(database, collection, cursor_id, limit))
188
+ reply = process(Protocol::GetMore.new(database, collection, cursor_id, limit))
189
+ raise Moped::Errors::CursorNotFound.new("GET MORE", cursor_id) if reply.cursor_not_found?
190
+ reply
188
191
  end
189
192
 
190
193
  # Get the hash identifier for the node.
@@ -209,17 +212,12 @@ module Moped
209
212
  # @since 1.0.0
210
213
  def initialize(address)
211
214
  @address = address
212
-
213
- host, port = address.split(":")
214
- @ip_address = ::Socket.getaddrinfo(host, nil, ::Socket::AF_INET, ::Socket::SOCK_STREAM).first[3]
215
- @port = port.to_i
216
- @resolved_address = "#{@ip_address}:#{@port}"
217
-
218
215
  @timeout = 5
219
216
  @down_at = nil
220
217
  @refreshed_at = nil
221
218
  @primary = nil
222
219
  @secondary = nil
220
+ resolve_address
223
221
  end
224
222
 
225
223
  # Insert documents into the database.
@@ -340,9 +338,20 @@ module Moped
340
338
  def query(database, collection, selector, options = {})
341
339
  operation = Protocol::Query.new(database, collection, selector, options)
342
340
 
343
- process operation do |reply|
344
- if reply.flags.include?(:query_failure)
345
- raise Errors::QueryFailure.new(operation, reply.documents.first)
341
+ process(operation) do |reply|
342
+ if reply.query_failed?
343
+ if reply.unauthorized? && auth.has_key?[database]
344
+ # If we got here, most likely this is the case of Moped
345
+ # authenticating successfully against the node originally, but the
346
+ # node has been reset or gone down and come back up. The most
347
+ # common case here is a rs.stepDown() which will reinitialize the
348
+ # connection. In this case we need to requthenticate and try again,
349
+ # otherwise we'll just raise the error to the user.
350
+ login(database, *auth[database])
351
+ query(database, collection, selector, options)
352
+ else
353
+ raise Errors::QueryFailure.new(operation, reply.documents.first)
354
+ end
346
355
  end
347
356
  reply
348
357
  end
@@ -363,25 +372,27 @@ module Moped
363
372
  #
364
373
  # @since 1.0.0
365
374
  def refresh
366
- info = command("admin", ismaster: 1)
367
-
368
- @refreshed_at = Time.now
369
- primary = true if info["ismaster"]
370
- secondary = true if info["secondary"]
371
-
372
- peers = []
373
- peers.push(info["primary"]) if info["primary"]
374
- peers.concat(info["hosts"]) if info["hosts"]
375
- peers.concat(info["passives"]) if info["passives"]
376
- peers.concat(info["arbiters"]) if info["arbiters"]
377
-
378
- @peers = peers.map { |peer| Node.new(peer) }
379
- @primary, @secondary = primary, secondary
380
- @arbiter = info["arbiterOnly"]
381
- @passive = info["passive"]
382
-
383
- if !primary && Threaded.executing?(:ensure_primary)
384
- raise Errors::ReplicaSetReconfigured, "#{inspect} is no longer the primary node."
375
+ if resolve_address
376
+ info = command("admin", ismaster: 1)
377
+
378
+ @refreshed_at = Time.now
379
+ primary = true if info["ismaster"]
380
+ secondary = true if info["secondary"]
381
+
382
+ peers = []
383
+ peers.push(info["primary"]) if info["primary"]
384
+ peers.concat(info["hosts"]) if info["hosts"]
385
+ peers.concat(info["passives"]) if info["passives"]
386
+ peers.concat(info["arbiters"]) if info["arbiters"]
387
+
388
+ @peers = peers.map { |peer| Node.new(peer) }
389
+ @primary, @secondary = primary, secondary
390
+ @arbiter = info["arbiterOnly"]
391
+ @passive = info["passive"]
392
+
393
+ if !primary && Threaded.executing?(:ensure_primary)
394
+ raise Errors::ReplicaSetReconfigured, "#{inspect} is no longer the primary node."
395
+ end
385
396
  end
386
397
  end
387
398
 
@@ -548,5 +559,28 @@ module Moped
548
559
  logger.debug indent + last.log_inspect + runtime
549
560
  end
550
561
  end
562
+
563
+ def resolve_address
564
+ unless ip_address
565
+ begin
566
+ parse_address and true
567
+ rescue SocketError
568
+ if logger = Moped.logger
569
+ logger.warn " MOPED: Could not resolve IP address for #{address}"
570
+ end
571
+ @down_at = Time.new
572
+ false
573
+ end
574
+ else
575
+ true
576
+ end
577
+ end
578
+
579
+ def parse_address
580
+ host, port = address.split(":")
581
+ @port = port.to_i
582
+ @ip_address = ::Socket.getaddrinfo(host, nil, ::Socket::AF_INET, ::Socket::SOCK_STREAM).first[3]
583
+ @resolved_address = "#{@ip_address}:#{@port}"
584
+ end
551
585
  end
552
586
  end
@@ -13,6 +13,8 @@ module Moped
13
13
  class Reply
14
14
  include Message
15
15
 
16
+ UNAUTHORIZED = 10057
17
+
16
18
  # @attribute
17
19
  # @return [Number] the length of the message
18
20
  int32 :length
@@ -53,6 +55,18 @@ module Moped
53
55
 
54
56
  finalize
55
57
 
58
+ def cursor_not_found?
59
+ flags.include?(:cursor_not_found)
60
+ end
61
+
62
+ def query_failed?
63
+ flags.include?(:query_failure)
64
+ end
65
+
66
+ def unauthorized?
67
+ documents.first["code"] == UNAUTHORIZED
68
+ end
69
+
56
70
  class << self
57
71
 
58
72
  # Consumes a buffer, returning the deserialized Reply message.
data/lib/moped/query.rb CHANGED
@@ -202,9 +202,12 @@ module Moped
202
202
  command[:fields] = operation.fields if operation.fields
203
203
  command[:update] = change unless options[:remove]
204
204
 
205
- session.with(consistency: :strong) do |sess|
205
+ result = session.with(consistency: :strong) do |sess|
206
206
  sess.command(command)["value"]
207
207
  end
208
+
209
+ # Keeping moped compatibility with mongodb >= 2.2.0-rc0
210
+ options[:upsert] && !result ? [] : result
208
211
  end
209
212
 
210
213
  # Remove a single document matching the query's selector.
data/lib/moped/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Moped
3
- VERSION = "1.2.1"
3
+ VERSION = "1.2.2"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moped
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.2.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-27 00:00:00.000000000 Z
12
+ date: 2012-09-16 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: A MongoDB driver for Ruby.
15
15
  email:
@@ -85,7 +85,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
85
85
  version: '0'
86
86
  segments:
87
87
  - 0
88
- hash: -3114748466186243780
88
+ hash: 3008607768252365192
89
89
  required_rubygems_version: !ruby/object:Gem::Requirement
90
90
  none: false
91
91
  requirements:
@@ -94,7 +94,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
94
  version: '0'
95
95
  segments:
96
96
  - 0
97
- hash: -3114748466186243780
97
+ hash: 3008607768252365192
98
98
  requirements: []
99
99
  rubyforge_project:
100
100
  rubygems_version: 1.8.24