mongo 1.1.5 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. data/README.md +15 -15
  2. data/Rakefile +38 -17
  3. data/docs/FAQ.md +4 -0
  4. data/docs/HISTORY.md +59 -0
  5. data/docs/RELEASES.md +33 -0
  6. data/docs/REPLICA_SETS.md +13 -16
  7. data/lib/mongo/collection.rb +157 -69
  8. data/lib/mongo/connection.rb +189 -65
  9. data/lib/mongo/cursor.rb +43 -29
  10. data/lib/mongo/db.rb +63 -43
  11. data/lib/mongo/exceptions.rb +4 -1
  12. data/lib/mongo/gridfs/grid.rb +1 -1
  13. data/lib/mongo/gridfs/grid_ext.rb +1 -1
  14. data/lib/mongo/gridfs/grid_file_system.rb +1 -1
  15. data/lib/mongo/gridfs/grid_io.rb +89 -8
  16. data/lib/mongo/gridfs/grid_io_fix.rb +1 -1
  17. data/lib/mongo/repl_set_connection.rb +72 -20
  18. data/lib/mongo/test.rb +20 -0
  19. data/lib/mongo/util/conversions.rb +1 -1
  20. data/lib/mongo/util/core_ext.rb +11 -1
  21. data/lib/mongo/util/pool.rb +67 -15
  22. data/lib/mongo/util/server_version.rb +1 -1
  23. data/lib/mongo/util/support.rb +1 -1
  24. data/lib/mongo/util/uri_parser.rb +127 -13
  25. data/lib/mongo.rb +38 -2
  26. data/test/async/collection_test.rb +224 -0
  27. data/test/async/connection_test.rb +24 -0
  28. data/test/async/cursor_test.rb +162 -0
  29. data/test/async/worker_pool_test.rb +99 -0
  30. data/test/auxillary/fork_test.rb +30 -0
  31. data/test/auxillary/repl_set_auth_test.rb +58 -0
  32. data/test/auxillary/threaded_authentication_test.rb +101 -0
  33. data/test/bson/bson_test.rb +140 -28
  34. data/test/bson/byte_buffer_test.rb +18 -0
  35. data/test/bson/object_id_test.rb +14 -1
  36. data/test/bson/ordered_hash_test.rb +7 -0
  37. data/test/bson/timestamp_test.rb +24 -0
  38. data/test/collection_test.rb +104 -15
  39. data/test/connection_test.rb +78 -2
  40. data/test/conversions_test.rb +10 -11
  41. data/test/cursor_fail_test.rb +1 -1
  42. data/test/cursor_message_test.rb +1 -1
  43. data/test/cursor_test.rb +33 -4
  44. data/test/db_api_test.rb +30 -52
  45. data/test/db_test.rb +3 -3
  46. data/test/grid_file_system_test.rb +0 -1
  47. data/test/grid_io_test.rb +72 -1
  48. data/test/grid_test.rb +16 -16
  49. data/test/load/resque/load.rb +21 -0
  50. data/test/load/resque/processor.rb +26 -0
  51. data/test/load/thin/load.rb +24 -0
  52. data/test/load/unicorn/load.rb +23 -0
  53. data/test/load/unicorn/unicorn.rb +29 -0
  54. data/test/replica_sets/connect_test.rb +11 -1
  55. data/test/replica_sets/connection_string_test.rb +32 -0
  56. data/test/replica_sets/query_secondaries.rb +16 -0
  57. data/test/replica_sets/query_test.rb +10 -0
  58. data/test/replica_sets/replication_ack_test.rb +2 -0
  59. data/test/replica_sets/rs_test_helper.rb +9 -11
  60. data/test/support/hash_with_indifferent_access.rb +0 -13
  61. data/test/support_test.rb +0 -1
  62. data/test/test_helper.rb +27 -8
  63. data/test/tools/auth_repl_set_manager.rb +14 -0
  64. data/test/tools/load.rb +58 -0
  65. data/test/tools/repl_set_manager.rb +34 -9
  66. data/test/tools/sharding_manager.rb +202 -0
  67. data/test/tools/test.rb +3 -12
  68. data/test/unit/collection_test.rb +20 -24
  69. data/test/unit/connection_test.rb +4 -18
  70. data/test/unit/cursor_test.rb +16 -6
  71. data/test/unit/db_test.rb +10 -11
  72. data/test/unit/repl_set_connection_test.rb +0 -23
  73. data/test/unit/safe_test.rb +3 -3
  74. data/test/uri_test.rb +91 -0
  75. metadata +49 -12
  76. data/docs/1.0_UPGRADE.md +0 -21
data/lib/mongo/db.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  # --
4
- # Copyright (C) 2008-2010 10gen Inc.
4
+ # Copyright (C) 2008-2011 10gen Inc.
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -56,33 +56,33 @@ module Mongo
56
56
 
57
57
  # Instances of DB are normally obtained by calling Mongo#db.
58
58
  #
59
- # @param [String] db_name the database name.
59
+ # @param [String] name the database name.
60
60
  # @param [Mongo::Connection] connection a connection object pointing to MongoDB. Note
61
61
  # that databases are usually instantiated via the Connection class. See the examples below.
62
62
  #
63
- # @option options [Boolean] :strict (False) If true, collections must exist to be accessed and must
63
+ # @option opts [Boolean] :strict (False) If true, collections must exist to be accessed and must
64
64
  # not exist to be created. See DB#collection and DB#create_collection.
65
65
  #
66
- # @option options [Object, #create_pk(doc)] :pk (Mongo::ObjectId) A primary key factory object,
66
+ # @option opts [Object, #create_pk(doc)] :pk (Mongo::ObjectId) A primary key factory object,
67
67
  # which should take a hash and return a hash which merges the original hash with any primary key
68
68
  # fields the factory wishes to inject. (NOTE: if the object already has a primary key,
69
69
  # the factory should not inject a new key).
70
70
  #
71
- # @option options [Boolean, Hash] :safe (false) Set the default safe-mode options
72
- # propogated to Collection objects instantiated off of this DB. If no
71
+ # @option opts [Boolean, Hash] :safe (false) Set the default safe-mode options
72
+ # propagated to Collection objects instantiated off of this DB. If no
73
73
  # value is provided, the default value set on this instance's Connection object will be used. This
74
74
  # default can be overridden upon instantiation of any collection by explicity setting a :safe value
75
75
  # on initialization
76
- # @option options [Integer] :cache_time (300) Set the time that all ensure_index calls should cache the command.
76
+ # @option opts [Integer] :cache_time (300) Set the time that all ensure_index calls should cache the command.
77
77
  #
78
78
  # @core databases constructor_details
79
- def initialize(db_name, connection, options={})
80
- @name = Mongo::Support.validate_db_name(db_name)
79
+ def initialize(name, connection, opts={})
80
+ @name = Mongo::Support.validate_db_name(name)
81
81
  @connection = connection
82
- @strict = options[:strict]
83
- @pk_factory = options[:pk]
84
- @safe = options.has_key?(:safe) ? options[:safe] : @connection.safe
85
- @cache_time = options[:cache_time] || 300 #5 minutes.
82
+ @strict = opts[:strict]
83
+ @pk_factory = opts[:pk]
84
+ @safe = opts.fetch(:safe, @connection.safe)
85
+ @cache_time = opts[:cache_time] || 300 #5 minutes.
86
86
  end
87
87
 
88
88
  # Authenticate with the given username and password. Note that mongod
@@ -92,7 +92,8 @@ module Mongo
92
92
  # @param [String] password
93
93
  # @param [Boolean] save_auth
94
94
  # Save this authentication to the connection object using Connection#add_auth. This
95
- # will ensure that the authentication will be applied on database reconnect.
95
+ # will ensure that the authentication will be applied on database reconnect. Note
96
+ # that this value must be true when using connection pooling.
96
97
  #
97
98
  # @return [Boolean]
98
99
  #
@@ -100,8 +101,19 @@ module Mongo
100
101
  #
101
102
  # @core authenticate authenticate-instance_method
102
103
  def authenticate(username, password, save_auth=true)
103
- doc = command({:getnonce => 1}, :check_response => false)
104
- raise "error retrieving nonce: #{doc}" unless ok?(doc)
104
+ if @connection.pool_size > 1
105
+ if !save_auth
106
+ raise MongoArgumentError, "If using connection pooling, :save_auth must be set to true."
107
+ end
108
+ @connection.authenticate_pools
109
+ end
110
+
111
+ issue_authentication(username, password, save_auth)
112
+ end
113
+
114
+ def issue_authentication(username, password, save_auth=true, opts={})
115
+ doc = command({:getnonce => 1}, :check_response => false, :socket => opts[:socket])
116
+ raise MongoDBError, "Error retrieving nonce: #{doc}" unless ok?(doc)
105
117
  nonce = doc['nonce']
106
118
 
107
119
  auth = BSON::OrderedHash.new
@@ -109,7 +121,7 @@ module Mongo
109
121
  auth['user'] = username
110
122
  auth['nonce'] = nonce
111
123
  auth['key'] = Mongo::Support.auth_key(username, password, nonce)
112
- if ok?(self.command(auth, :check_response => false))
124
+ if ok?(self.command(auth, :check_response => false, :socket => opts[:socket]))
113
125
  if save_auth
114
126
  @connection.add_auth(@name, username, password)
115
127
  end
@@ -121,7 +133,7 @@ module Mongo
121
133
 
122
134
  # Adds a stored Javascript function to the database which can executed
123
135
  # server-side in map_reduce, db.eval and $where clauses.
124
- #
136
+ #
125
137
  # @param [String] function_name
126
138
  # @param [String] code
127
139
  #
@@ -179,14 +191,22 @@ module Mongo
179
191
  end
180
192
 
181
193
  # Deauthorizes use for this database for this connection. Also removes
182
- # any saved authorization in the connection class associated with this
194
+ # any saved authentication in the connection class associated with this
183
195
  # database.
184
196
  #
185
197
  # @raise [MongoDBError] if logging out fails.
186
198
  #
187
199
  # @return [Boolean]
188
- def logout
189
- doc = command(:logout => 1)
200
+ def logout(opts={})
201
+ if @connection.pool_size > 1
202
+ @connection.logout_pools(@name)
203
+ end
204
+
205
+ issue_logout(opts)
206
+ end
207
+
208
+ def issue_logout(opts={})
209
+ doc = command({:logout => 1}, :socket => opts[:socket])
190
210
  if ok?(doc)
191
211
  @connection.remove_auth(@name)
192
212
  true
@@ -208,8 +228,8 @@ module Mongo
208
228
  #
209
229
  # @return [Array<Mongo::Collection>]
210
230
  def collections
211
- collection_names.map do |collection_name|
212
- Collection.new(self, collection_name)
231
+ collection_names.map do |name|
232
+ Collection.new(name, self)
213
233
  end
214
234
  end
215
235
 
@@ -223,7 +243,7 @@ module Mongo
223
243
  def collections_info(coll_name=nil)
224
244
  selector = {}
225
245
  selector[:name] = full_collection_name(coll_name) if coll_name
226
- Cursor.new(Collection.new(self, SYSTEM_NAMESPACE_COLLECTION), :selector => selector)
246
+ Cursor.new(Collection.new(SYSTEM_NAMESPACE_COLLECTION, self), :selector => selector)
227
247
  end
228
248
 
229
249
  # Create a collection.
@@ -233,52 +253,52 @@ module Mongo
233
253
  #
234
254
  # @param [String] name the name of the new collection.
235
255
  #
236
- # @option options [Boolean] :capped (False) created a capped collection.
256
+ # @option opts [Boolean] :capped (False) created a capped collection.
237
257
  #
238
- # @option options [Integer] :size (Nil) If +capped+ is +true+, specifies the maximum number of
258
+ # @option opts [Integer] :size (Nil) If +capped+ is +true+, specifies the maximum number of
239
259
  # bytes for the capped collection. If +false+, specifies the number of bytes allocated
240
260
  # for the initial extent of the collection.
241
261
  #
242
- # @option options [Integer] :max (Nil) If +capped+ is +true+, indicates the maximum number of records
262
+ # @option opts [Integer] :max (Nil) If +capped+ is +true+, indicates the maximum number of records
243
263
  # in a capped collection.
244
264
  #
245
265
  # @raise [MongoDBError] raised under two conditions: either we're in +strict+ mode and the collection
246
266
  # already exists or collection creation fails on the server.
247
267
  #
248
268
  # @return [Mongo::Collection]
249
- def create_collection(name, options={})
269
+ def create_collection(name, opts={})
250
270
  # Does the collection already exist?
251
271
  if collection_names.include?(name)
252
272
  if strict?
253
273
  raise MongoDBError, "Collection #{name} already exists. Currently in strict mode."
254
274
  else
255
- return Collection.new(self, name)
275
+ return Collection.new(name, self, opts)
256
276
  end
257
277
  end
258
278
 
259
279
  # Create a new collection.
260
280
  oh = BSON::OrderedHash.new
261
281
  oh[:create] = name
262
- doc = command(oh.merge(options || {}))
263
- return Collection.new(self, name, :pk => @pk_factory) if ok?(doc)
282
+ doc = command(oh.merge(opts || {}))
283
+ return Collection.new(name, self, :pk => @pk_factory) if ok?(doc)
264
284
  raise MongoDBError, "Error creating collection: #{doc.inspect}"
265
285
  end
266
286
 
267
287
  # Get a collection by name.
268
288
  #
269
289
  # @param [String] name the collection name.
270
- # @param [Hash] options any valid options that can me passed to Collection#new.
290
+ # @param [Hash] opts any valid options that can be passed to Collection#new.
271
291
  #
272
292
  # @raise [MongoDBError] if collection does not already exist and we're in +strict+ mode.
273
293
  #
274
294
  # @return [Mongo::Collection]
275
- def collection(name, options={})
295
+ def collection(name, opts={})
276
296
  if strict? && !collection_names.include?(name)
277
297
  raise Mongo::MongoDBError, "Collection #{name} doesn't exist. Currently in strict mode."
278
298
  else
279
- options[:safe] = options.has_key?(:safe) ? options[:safe] : @safe
280
- options.merge!(:pk => @pk_factory) unless options[:pk]
281
- Collection.new(self, name, options)
299
+ opts[:safe] = opts.fetch(:safe, @safe)
300
+ opts.merge!(:pk => @pk_factory) unless opts[:pk]
301
+ Collection.new(name, self, opts)
282
302
  end
283
303
  end
284
304
  alias_method :[], :collection
@@ -403,7 +423,7 @@ module Mongo
403
423
  def drop_index(collection_name, index_name)
404
424
  oh = BSON::OrderedHash.new
405
425
  oh[:deleteIndexes] = collection_name
406
- oh[:index] = index_name
426
+ oh[:index] = index_name.to_s
407
427
  doc = command(oh, :check_response => false)
408
428
  ok?(doc) || raise(MongoDBError, "Error with drop_index command: #{doc.inspect}")
409
429
  end
@@ -418,7 +438,7 @@ module Mongo
418
438
  def index_information(collection_name)
419
439
  sel = {:ns => full_collection_name(collection_name)}
420
440
  info = {}
421
- Cursor.new(Collection.new(self, SYSTEM_INDEX_COLLECTION), :selector => sel).each do |index|
441
+ Cursor.new(Collection.new(SYSTEM_INDEX_COLLECTION, self), :selector => sel).each do |index|
422
442
  info[index['name']] = index
423
443
  end
424
444
  info
@@ -455,14 +475,14 @@ module Mongo
455
475
  #
456
476
  # @option opts [Boolean] :check_response (true) If +true+, raises an exception if the
457
477
  # command fails.
458
- # @option opts [Socket] :sock a socket to use for sending the command. This is mainly for internal use.
478
+ # @option opts [Socket] :socket a socket to use for sending the command. This is mainly for internal use.
459
479
  #
460
480
  # @return [Hash]
461
481
  #
462
482
  # @core commands command_instance-method
463
483
  def command(selector, opts={})
464
484
  check_response = opts.fetch(:check_response, true)
465
- sock = opts[:sock]
485
+ socket = opts[:socket]
466
486
  raise MongoArgumentError, "command must be given a selector" unless selector.is_a?(Hash) && !selector.empty?
467
487
  if selector.keys.length > 1 && RUBY_VERSION < '1.9' && selector.class != BSON::OrderedHash
468
488
  raise MongoArgumentError, "DB#command requires an OrderedHash when hash contains multiple keys"
@@ -470,7 +490,7 @@ module Mongo
470
490
 
471
491
  begin
472
492
  result = Cursor.new(system_command_collection,
473
- :limit => -1, :selector => selector, :socket => sock).next_document
493
+ :limit => -1, :selector => selector, :socket => socket).next_document
474
494
  rescue OperationFailure => ex
475
495
  raise OperationFailure, "Database command '#{selector.keys.first}' failed: #{ex.message}"
476
496
  end
@@ -558,7 +578,7 @@ module Mongo
558
578
  #
559
579
  # @return [Array] a list of documents containing profiling information.
560
580
  def profiling_info
561
- Cursor.new(Collection.new(self, DB::SYSTEM_PROFILE_COLLECTION), :selector => {}).to_a
581
+ Cursor.new(Collection.new(SYSTEM_PROFILE_COLLECTION, self), :selector => {}).to_a
562
582
  end
563
583
 
564
584
  # Validate a named collection.
@@ -581,7 +601,7 @@ module Mongo
581
601
  private
582
602
 
583
603
  def system_command_collection
584
- Collection.new(self, SYSTEM_COMMAND_COLLECTION)
604
+ Collection.new(SYSTEM_COMMAND_COLLECTION, self)
585
605
  end
586
606
  end
587
607
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  #
4
4
  # --
5
- # Copyright (C) 2008-2010 10gen Inc.
5
+ # Copyright (C) 2008-2011 10gen Inc.
6
6
  #
7
7
  # Licensed under the Apache License, Version 2.0 (the "License");
8
8
  # you may not use this file except in compliance with the License.
@@ -57,6 +57,9 @@ module Mongo
57
57
  # Raised when a database operation fails.
58
58
  class OperationFailure < MongoDBError; end
59
59
 
60
+ # Raised when a socket read operation times out.
61
+ class OperationTimeout < ::Timeout::Error; end
62
+
60
63
  # Raised when a client attempts to perform an invalid operation.
61
64
  class InvalidOperation < MongoDBError; end
62
65
 
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  # --
4
- # Copyright (C) 2008-2010 10gen Inc.
4
+ # Copyright (C) 2008-2011 10gen Inc.
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  # --
4
- # Copyright (C) 2008-2010 10gen Inc.
4
+ # Copyright (C) 2008-2011 10gen Inc.
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  # --
4
- # Copyright (C) 2008-2010 10gen Inc.
4
+ # Copyright (C) 2008-2011 10gen Inc.
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  # --
4
- # Copyright (C) 2008-2010 10gen Inc.
4
+ # Copyright (C) 2008-2011 10gen Inc.
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -17,10 +17,6 @@
17
17
  # ++
18
18
 
19
19
  require 'digest/md5'
20
- begin
21
- require 'mime/types'
22
- rescue LoadError
23
- end
24
20
 
25
21
  module Mongo
26
22
 
@@ -172,6 +168,91 @@ module Mongo
172
168
  def tell
173
169
  @file_position
174
170
  end
171
+ alias :pos :tell
172
+
173
+ # Rewind the file. This is equivalent to seeking to the zeroth position.
174
+ #
175
+ # @return [Integer] the position of the file after rewinding (always zero).
176
+ def rewind
177
+ raise GridError, "file not opened for read" unless @mode[0] == ?r
178
+ seek(0)
179
+ end
180
+
181
+ # Return a boolean indicating whether the position pointer is
182
+ # at the end of the file.
183
+ #
184
+ # @return [Boolean]
185
+ def eof
186
+ raise GridError, "file not opened for read #{@mode}" unless @mode[0] == ?r
187
+ @file_position >= @file_length
188
+ end
189
+ alias :eof? :eof
190
+
191
+ # Return the next line from a GridFS file. This probably
192
+ # makes sense only if you're storing plain text. This method
193
+ # has a somewhat tricky API, which it inherits from Ruby's
194
+ # StringIO#gets.
195
+ #
196
+ # @param [String, Integer] separator or length. If a separator,
197
+ # read up to the separator. If a length, read the +length+ number
198
+ # of bytes. If nil, read the entire file.
199
+ # @param [Integer] length If a separator is provided, then
200
+ # read until either finding the separator or
201
+ # passing over the +length+ number of bytes.
202
+ #
203
+ # @return [String]
204
+ def gets(separator="\n", length=nil)
205
+ if separator.nil?
206
+ read_all
207
+ elsif separator.is_a?(Integer)
208
+ read_length(separator)
209
+ elsif separator.length > 1
210
+ result = ''
211
+ len = 0
212
+ match_idx = 0
213
+ match_num = separator.length - 1
214
+ to_match = separator[match_idx].chr
215
+ if length
216
+ matcher = lambda {|idx, num| idx < num && len < length }
217
+ else
218
+ matcher = lambda {|idx, num| idx < num}
219
+ end
220
+ while matcher.call(match_idx, match_num) && char = getc
221
+ result << char
222
+ len += 1
223
+ if char == to_match
224
+ while match_idx < match_num do
225
+ match_idx += 1
226
+ to_match = separator[match_idx].chr
227
+ char = getc
228
+ result << char
229
+ if char != to_match
230
+ match_idx = 0
231
+ to_match = separator[match_idx].chr
232
+ break
233
+ end
234
+ end
235
+ end
236
+ end
237
+ result
238
+ else
239
+ result = ''
240
+ len = 0
241
+ while char = getc
242
+ result << char
243
+ len += 1
244
+ break if char == separator || (length ? len >= length : false)
245
+ end
246
+ result
247
+ end
248
+ end
249
+
250
+ # Return the next byte from the GridFS file.
251
+ #
252
+ # @return [String]
253
+ def getc
254
+ read_length(1)
255
+ end
175
256
 
176
257
  # Creates or updates the document from the files collection that
177
258
  # stores the chunks' metadata. The file becomes available only after
@@ -260,7 +341,7 @@ module Mongo
260
341
  if length.nil?
261
342
  to_read = remaining
262
343
  else
263
- to_read = length > remaining ? remaining : length
344
+ to_read = length > remaining ? remaining : length
264
345
  end
265
346
  return nil unless remaining > 0
266
347
 
@@ -335,8 +416,8 @@ module Mongo
335
416
  @files_id = opts.delete(:_id) || BSON::ObjectId.new
336
417
  @content_type = opts.delete(:content_type) || (defined? MIME) && get_content_type || DEFAULT_CONTENT_TYPE
337
418
  @chunk_size = opts.delete(:chunk_size) || DEFAULT_CHUNK_SIZE
338
- @metadata = opts.delete(:metadata) if opts[:metadata]
339
- @aliases = opts.delete(:aliases) if opts[:aliases]
419
+ @metadata = opts.delete(:metadata)
420
+ @aliases = opts.delete(:aliases)
340
421
  @file_length = 0
341
422
  opts.each {|k, v| self[k] = v}
342
423
  check_existing_file if @safe
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  # --
4
- # Copyright (C) 2008-2010 10gen Inc.
4
+ # Copyright (C) 2008-2011 10gen Inc.
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  # --
4
- # Copyright (C) 2008-2010 10gen Inc.
4
+ # Copyright (C) 2008-2011 10gen Inc.
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -29,9 +29,11 @@ module Mongo
29
29
  # Connection#arbiters. This is useful if your application needs to connect manually to nodes other
30
30
  # than the primary.
31
31
  #
32
- # @param [Array] args A list of host-port pairs ending with a hash containing any options. See
33
- # the examples below for exactly how to use the constructor.
32
+ # @param [Array] args A list of host-port pairs to be used as seed nodes followed by a
33
+ # hash containing any options. See the examples below for exactly how to use the constructor.
34
34
  #
35
+ # @option options [String] :rs_name (nil) The name of the replica set to connect to. You
36
+ # can use this option to verify that you're connecting to the right replica set.
35
37
  # @option options [Boolean, Hash] :safe (false) Set the default safe-mode options
36
38
  # propogated to DB objects instantiated off of this Connection. This
37
39
  # default can be overridden upon instantiation of any DB by explicity setting a :safe value
@@ -45,11 +47,15 @@ module Mongo
45
47
  # this is the number of seconds to wait for a new connection to be released before throwing an exception.
46
48
  # Note: this setting is relevant only for multi-threaded applications.
47
49
  #
48
- # @example Connect to a replica set and provide two seed nodes:
50
+ # @example Connect to a replica set and provide two seed nodes. Note that the number of seed nodes does
51
+ # not have to be equal to the number of replica set members. The purpose of seed nodes is to permit
52
+ # the driver to find at least one replica set member even if a member is down.
49
53
  # ReplSetConnection.new(['localhost', 30000], ['localhost', 30001])
50
54
  #
51
- # @example Connect to a replica set providing two seed nodes and allowing reads from a
52
- # secondary node:
55
+ # @example Connect to a replica set providing two seed nodes and ensuring a connection to the replica set named 'prod':
56
+ # ReplSetConnection.new(['localhost', 30000], ['localhost', 30001], :rs_name => 'prod')
57
+ #
58
+ # @example Connect to a replica set providing two seed nodes and allowing reads from a secondary node:
53
59
  # ReplSetConnection.new(['localhost', 30000], ['localhost', 30001], :read_secondary => true)
54
60
  #
55
61
  # @see http://api.mongodb.org/ruby/current/file.REPLICA_SETS.html Replica sets in Ruby
@@ -95,7 +101,7 @@ module Mongo
95
101
  #
96
102
  # @raise [ConnectionFailure] if unable to connect to any host or port.
97
103
  def connect
98
- reset_connection
104
+ close
99
105
  @nodes_to_try = @nodes.clone
100
106
 
101
107
  while connecting?
@@ -111,19 +117,47 @@ module Mongo
111
117
 
112
118
  pick_secondary_for_read if @read_secondary
113
119
 
114
- if !connected?
120
+ if connected?
121
+ BSON::BSON_CODER.update_max_bson_size(self)
122
+ else
115
123
  if @secondary_pools.empty?
124
+ close # close any existing pools and sockets
116
125
  raise ConnectionFailure, "Failed to connect any given host:port"
117
126
  else
127
+ close # close any existing pools and sockets
118
128
  raise ConnectionFailure, "Failed to connect to primary node."
119
129
  end
120
130
  end
121
131
  end
132
+ alias :reconnect :connect
122
133
 
123
134
  def connecting?
124
135
  @nodes_to_try.length > 0
125
136
  end
126
137
 
138
+ # The replica set primary's host name.
139
+ #
140
+ # @return [String]
141
+ def host
142
+ super
143
+ end
144
+
145
+ # The replica set primary's port.
146
+ #
147
+ # @return [Integer]
148
+ def port
149
+ super
150
+ end
151
+
152
+ # Determine whether we're reading from a primary node. If false,
153
+ # this connection connects to a secondary node and @read_secondaries is true.
154
+ #
155
+ # @return [Boolean]
156
+ def read_primary?
157
+ !@read_pool
158
+ end
159
+ alias :primary? :read_primary?
160
+
127
161
  # Close the connection to the database.
128
162
  def close
129
163
  super
@@ -131,13 +165,6 @@ module Mongo
131
165
  @secondary_pools.each do |pool|
132
166
  pool.close
133
167
  end
134
- end
135
-
136
- # If a ConnectionFailure is raised, this method will be called
137
- # to close the connection and reset connection values.
138
- # TODO: what's the point of this method?
139
- def reset_connection
140
- super
141
168
  @secondaries = []
142
169
  @secondary_pools = []
143
170
  @arbiters = []
@@ -145,6 +172,15 @@ module Mongo
145
172
  @nodes_to_try = []
146
173
  end
147
174
 
175
+ # If a ConnectionFailure is raised, this method will be called
176
+ # to close the connection and reset connection values.
177
+ # @deprecated
178
+ def reset_connection
179
+ close
180
+ warn "ReplSetConnection#reset_connection is now deprecated. " +
181
+ "Use ReplSetConnection#close instead."
182
+ end
183
+
148
184
  # Is it okay to connect to a slave?
149
185
  #
150
186
  # @return [Boolean]
@@ -152,6 +188,20 @@ module Mongo
152
188
  @read_secondary || @slave_ok
153
189
  end
154
190
 
191
+ def authenticate_pools
192
+ super
193
+ @secondary_pools.each do |pool|
194
+ pool.authenticate_existing
195
+ end
196
+ end
197
+
198
+ def logout_pools(db)
199
+ super
200
+ @secondary_pools.each do |pool|
201
+ pool.logout_existing(db)
202
+ end
203
+ end
204
+
155
205
  private
156
206
 
157
207
  def check_is_master(node)
@@ -160,13 +210,17 @@ module Mongo
160
210
  socket = TCPSocket.new(host, port)
161
211
  socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
162
212
 
163
- config = self['admin'].command({:ismaster => 1}, :sock => socket)
213
+ config = self['admin'].command({:ismaster => 1}, :socket => socket)
164
214
 
165
215
  check_set_name(config, socket)
166
216
  rescue OperationFailure, SocketError, SystemCallError, IOError => ex
167
- close unless connected?
217
+ # It's necessary to rescue here. The #connect method will keep trying
218
+ # until it has no more nodes to try and raise a ConnectionFailure if
219
+ # it can't connect to a primary.
168
220
  ensure
221
+ socket.close if socket
169
222
  @nodes_tried << node
223
+
170
224
  if config
171
225
  nodes = []
172
226
  nodes += config['hosts'] if config['hosts']
@@ -178,8 +232,6 @@ module Mongo
178
232
  @logger.warn("MONGODB #{config['msg']}")
179
233
  end
180
234
  end
181
-
182
- socket.close if socket
183
235
  end
184
236
 
185
237
  config
@@ -203,7 +255,7 @@ module Mongo
203
255
  def check_set_name(config, socket)
204
256
  if @replica_set
205
257
  config = self['admin'].command({:replSetGetStatus => 1},
206
- :sock => socket, :check_response => false)
258
+ :socket => socket, :check_response => false)
207
259
 
208
260
  if !Mongo::Support.ok?(config)
209
261
  raise ReplicaSetConnectionError, config['errmsg']
data/lib/mongo/test.rb ADDED
@@ -0,0 +1,20 @@
1
+
2
+ class Foo
3
+
4
+ def zed
5
+ puts "Foo"
6
+ end
7
+
8
+ end
9
+
10
+ class Bar < Foo
11
+
12
+ def zed(n=nil)
13
+ if n.nil?
14
+ puts "Bar"
15
+ else
16
+ super()
17
+ end
18
+ end
19
+
20
+ end
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  # --
4
- # Copyright (C) 2008-2010 10gen Inc.
4
+ # Copyright (C) 2008-2011 10gen Inc.
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.