mongo 1.5.1 → 1.5.2

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.
data/Rakefile CHANGED
@@ -1,11 +1,16 @@
1
1
  # -*- mode: ruby; -*-
2
- require 'rubygems'
3
- require 'rubygems/specification'
2
+ if RUBY_VERSION < '1.9.0'
3
+ require 'rubygems'
4
+ require 'rubygems/specification'
5
+ end
4
6
  require 'fileutils'
5
- require 'rake'
6
7
  require 'rake/testtask'
7
- require 'rake/gempackagetask'
8
8
  require 'rbconfig'
9
+ require 'rake'
10
+ begin
11
+ require 'ci/reporter/rake/test_unit'
12
+ rescue LoadError
13
+ end
9
14
  include Config
10
15
  ENV['TEST_MODE'] = 'TRUE'
11
16
 
@@ -154,11 +159,11 @@ namespace :bamboo do
154
159
  end
155
160
 
156
161
  namespace :test do
157
- task :ruby => [:ci_reporter, "ci:setup:testunit"] do
162
+ task :ruby do
158
163
  Rake::Task['test:ruby'].invoke
159
164
  end
160
165
 
161
- task :c => [:ci_reporter, "ci:setup:testunit"] do
166
+ task :c do
162
167
  Rake::Task['gem:install_extensions'].invoke
163
168
  Rake::Task['test:c'].invoke
164
169
  end
@@ -1,5 +1,12 @@
1
1
  # MongoDB Ruby Driver History
2
2
 
3
+ ### 1.5.2
4
+ 2011-12-13
5
+
6
+ * Lots of fixes for replica set connection edge cases.
7
+ * Set default op_timeout and connect_timeout to 30 seconds.
8
+ * Support GeoHaystack indexing.
9
+
3
10
  ### 1.5.1
4
11
  2011-11-29
5
12
 
@@ -16,14 +16,13 @@
16
16
  # limitations under the License.
17
17
  # ++
18
18
 
19
- $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
20
-
21
19
  require 'mongo/version'
22
20
 
23
21
  module Mongo
24
- ASCENDING = 1
25
- DESCENDING = -1
26
- GEO2D = '2d'
22
+ ASCENDING = 1
23
+ DESCENDING = -1
24
+ GEO2D = '2d'
25
+ GEOHAYSTACK = 'geoHaystack'
27
26
 
28
27
  DEFAULT_MAX_BSON_SIZE = 4 * 1024 * 1024
29
28
 
@@ -888,7 +888,7 @@ module Mongo
888
888
  field_spec[spec.to_s] = 1
889
889
  elsif spec.is_a?(Array) && spec.all? {|field| field.is_a?(Array) }
890
890
  spec.each do |f|
891
- if [Mongo::ASCENDING, Mongo::DESCENDING, Mongo::GEO2D].include?(f[1])
891
+ if [Mongo::ASCENDING, Mongo::DESCENDING, Mongo::GEO2D, Mongo::GEOHAYSTACK].include?(f[1])
892
892
  field_spec[f[0].to_s] = f[1]
893
893
  else
894
894
  raise MongoArgumentError, "Invalid index field #{f[1].inspect}; " +
@@ -458,12 +458,13 @@ module Mongo
458
458
  @primary_pool
459
459
  end
460
460
 
461
- # The value of the read preference. Because
462
- # this is a single-node connection, the value
463
- # is +:primary+, and the connection will read
464
- # from whichever type of node it's connected to.
461
+ # The value of the read preference.
465
462
  def read_preference
466
- :primary
463
+ if slave_ok?
464
+ :secondary
465
+ else
466
+ :primary
467
+ end
467
468
  end
468
469
 
469
470
  # Close the connection to the database.
@@ -614,7 +615,13 @@ module Mongo
614
615
  socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
615
616
  end
616
617
 
617
- config = self['admin'].command({:ismaster => 1}, :socket => socket)
618
+ if @connect_timeout
619
+ Mongo::TimeoutHandler.timeout(@connect_timeout, OperationTimeout) do
620
+ config = self['admin'].command({:ismaster => 1}, :socket => socket)
621
+ end
622
+ else
623
+ config = self['admin'].command({:ismaster => 1}, :socket => socket)
624
+ end
618
625
  rescue OperationFailure, SocketError, SystemCallError, IOError => ex
619
626
  close
620
627
  ensure
@@ -86,7 +86,7 @@ module Mongo
86
86
  if(!@timeout)
87
87
  add_option(OP_QUERY_NO_CURSOR_TIMEOUT)
88
88
  end
89
- if(@connection.slave_ok?)
89
+ if(@read_preference != :primary)
90
90
  add_option(OP_QUERY_SLAVE_OK)
91
91
  end
92
92
  if(@tailable)
@@ -136,7 +136,7 @@ module Mongo
136
136
  # If the server has stopped being the master (e.g., it's one of a
137
137
  # pair but it has died or something like that) then we close that
138
138
  # connection. The next request will re-open on master server.
139
- if err == "not master"
139
+ if err.include?("not master")
140
140
  @connection.close
141
141
  raise ConnectionFailure.new(err, doc['code'], doc)
142
142
  end
@@ -463,9 +463,8 @@ module Mongo
463
463
 
464
464
  def send_initial_query
465
465
  message = construct_query_message
466
- payload = instrument_payload if @logger
467
466
  sock = @socket || checkout_socket_from_connection
468
- instrument(:find, payload) do
467
+ instrument(:find, instrument_payload) do
469
468
  begin
470
469
  results, @n_received, @cursor_id = @connection.receive_message(
471
470
  Mongo::Constants::OP_QUERY, message, nil, sock, @command,
@@ -518,13 +517,21 @@ module Mongo
518
517
  end
519
518
 
520
519
  def checkout_socket_from_connection
521
- @checkin_connection = true
522
- if @command || @read_preference == :primary
523
- @connection.checkout_writer
524
- else
525
- @read_pool = @connection.read_pool
526
- @connection.checkout_reader
520
+ socket = nil
521
+ begin
522
+ @checkin_connection = true
523
+ if @command || @read_preference == :primary
524
+ socket = @connection.checkout_writer
525
+ else
526
+ @read_pool = @connection.read_pool
527
+ socket = @connection.checkout_reader
528
+ end
529
+ rescue SystemStackError, NoMemoryError, SystemCallError => ex
530
+ @connection.close
531
+ raise ex
527
532
  end
533
+
534
+ socket
528
535
  end
529
536
 
530
537
  def checkout_socket_for_op_get_more
@@ -540,9 +547,15 @@ module Mongo
540
547
  pool.host == @read_pool.host && pool.port == @read_pool.port
541
548
  end
542
549
  if new_pool
543
- @read_pool = new_pool
544
- sock = new_pool.checkout
545
- @checkin_read_pool = true
550
+ sock = nil
551
+ begin
552
+ @read_pool = new_pool
553
+ sock = new_pool.checkout
554
+ @checkin_read_pool = true
555
+ rescue SystemStackError, NoMemoryError, SystemCallError => ex
556
+ @connection.close
557
+ raise ex
558
+ end
546
559
  return sock
547
560
  else
548
561
  raise Mongo::OperationFailure, "Failure to continue iterating " +
@@ -28,19 +28,25 @@ module Mongo
28
28
  add_message_headers(message, operation)
29
29
  packed_message = message.to_s
30
30
 
31
- if connection == :writer
32
- sock = checkout_writer
33
- else
34
- sock = checkout_reader
35
- end
36
-
31
+ sock = nil
37
32
  begin
38
- send_message_on_socket(packed_message, sock)
39
- ensure
40
33
  if connection == :writer
41
- checkin_writer(sock)
34
+ sock = checkout_writer
42
35
  else
43
- checkin_reader(sock)
36
+ sock = checkout_reader
37
+ end
38
+
39
+ send_message_on_socket(packed_message, sock)
40
+ rescue SystemStackError, NoMemoryError, SystemCallError => ex
41
+ close
42
+ raise ex
43
+ ensure
44
+ if sock
45
+ if connection == :writer
46
+ checkin_writer(sock)
47
+ else
48
+ checkin_reader(sock)
49
+ end
44
50
  end
45
51
  end
46
52
  end
@@ -66,14 +72,18 @@ module Mongo
66
72
  last_error_id = add_message_headers(last_error_message, Mongo::Constants::OP_QUERY)
67
73
 
68
74
  packed_message = message.append!(last_error_message).to_s
69
- sock = checkout_writer
75
+ sock = nil
70
76
  begin
77
+ sock = checkout_writer
71
78
  send_message_on_socket(packed_message, sock)
72
79
  docs, num_received, cursor_id = receive(sock, last_error_id)
73
80
  checkin_writer(sock)
74
81
  rescue ConnectionFailure, OperationFailure, OperationTimeout => ex
75
82
  checkin_writer(sock)
76
83
  raise ex
84
+ rescue SystemStackError, NoMemoryError, SystemCallError => ex
85
+ close
86
+ raise ex
77
87
  end
78
88
 
79
89
  if num_received == 1 && (error = docs[0]['err'] || docs[0]['errmsg'])
@@ -103,24 +113,29 @@ module Mongo
103
113
  read=:primary, exhaust=false)
104
114
  request_id = add_message_headers(message, operation)
105
115
  packed_message = message.to_s
106
- if socket
107
- sock = socket
108
- should_checkin = false
109
- else
110
- if command || read == :primary
111
- sock = checkout_writer
112
- elsif read == :secondary
113
- sock = checkout_reader
114
- else
115
- sock = checkout_tagged(read)
116
- end
117
- should_checkin = true
118
- end
119
116
 
120
117
  result = ''
118
+ sock = nil
121
119
  begin
120
+ if socket
121
+ sock = socket
122
+ should_checkin = false
123
+ else
124
+ if command || read == :primary
125
+ sock = checkout_writer
126
+ elsif read == :secondary
127
+ sock = checkout_reader
128
+ else
129
+ sock = checkout_tagged(read)
130
+ end
131
+ should_checkin = true
132
+ end
133
+
122
134
  send_message_on_socket(packed_message, sock)
123
135
  result = receive(sock, request_id, exhaust)
136
+ rescue SystemStackError, NoMemoryError, SystemCallError => ex
137
+ close
138
+ raise ex
124
139
  ensure
125
140
  if should_checkin
126
141
  if command || read == :primary
@@ -51,9 +51,8 @@ module Mongo
51
51
  # @option options [Float] :pool_timeout (5.0) When all of the connections a pool are checked out,
52
52
  # this is the number of seconds to wait for a new connection to be released before throwing an exception.
53
53
  # Note: this setting is relevant only for multi-threaded applications.
54
- # @option opts [Float] :op_timeout (nil) The number of seconds to wait for a read operation to time out.
55
- # Disabled by default.
56
- # @option opts [Float] :connect_timeout (nil) The number of seconds to wait before timing out a
54
+ # @option opts [Float] :op_timeout (30) The number of seconds to wait for a read operation to time out.
55
+ # @option opts [Float] :connect_timeout (30) The number of seconds to wait before timing out a
57
56
  # connection attempt.
58
57
  # @option opts [Boolean] :ssl (false) If true, create the connection to the server using SSL.
59
58
  # @option opts [Boolean] :refresh_mode (false) Set this to :sync to periodically update the
@@ -91,8 +90,10 @@ module Mongo
91
90
  raise MongoArgumentError, "A ReplSetConnection requires at least one seed node."
92
91
  end
93
92
 
94
- # The list of seed nodes
93
+ # The original, immutable list of seed node.
94
+ # TODO: add a method for replacing this list of node.
95
95
  @seeds = args
96
+ @seeds.freeze
96
97
 
97
98
  # TODO: get rid of this
98
99
  @nodes = @seeds.dup
@@ -152,10 +153,12 @@ module Mongo
152
153
  def connect
153
154
  log(:info, "Connecting...")
154
155
  return if @connected
155
- manager = PoolManager.new(self, @seeds)
156
- manager.connect
157
156
 
158
- update_config(manager)
157
+ discovered_seeds = @manager ? @manager.seeds : []
158
+ @manager = PoolManager.new(self, discovered_seeds)
159
+
160
+ @manager.connect
161
+ @refresh_version += 1
159
162
 
160
163
  if @require_primary && self.primary.nil? #TODO: in v2.0, we'll let this be optional and do a lazy connect.
161
164
  close
@@ -200,19 +203,21 @@ module Mongo
200
203
  # to get the refresh lock.
201
204
  def hard_refresh!
202
205
  log(:info, "Initiating hard refresh...")
203
- background_manager = PoolManager.new(self, @seeds)
206
+ discovered_seeds = @manager ? @manager.seeds : []
207
+ background_manager = PoolManager.new(self, discovered_seeds | @seeds)
204
208
  background_manager.connect
205
209
 
206
210
  # TODO: make sure that connect has succeeded
207
211
  old_manager = @manager
208
- update_config(background_manager)
212
+ @manager = background_manager
209
213
  old_manager.close(:soft => true)
214
+ @refresh_version += 1
210
215
 
211
216
  return true
212
217
  end
213
218
 
214
219
  def connected?
215
- self.primary_pool || self.read_pool
220
+ @connected && (self.primary_pool || self.read_pool)
216
221
  end
217
222
 
218
223
  # @deprecated
@@ -255,9 +260,13 @@ module Mongo
255
260
  end
256
261
 
257
262
  # Close the connection to the database.
258
- def close
263
+ def close(opts={})
264
+ if opts[:soft]
265
+ @manager.close(:soft => true) if @manager
266
+ else
267
+ @manager.close if @manager
268
+ end
259
269
  @connected = false
260
- @manager.close(:soft => true) if @manager
261
270
  end
262
271
 
263
272
  # If a ConnectionFailure is raised, this method will be called
@@ -298,12 +307,22 @@ module Mongo
298
307
  # Note that @read_pool might point to the primary pool
299
308
  # if no read pool has been defined.
300
309
  def checkout_reader
301
- connect unless connected?
302
- socket = get_socket_from_pool(self.read_pool)
303
-
304
- if !socket
310
+ if connected?
311
+ sync_refresh
312
+ else
305
313
  connect
306
- socket = get_socket_from_pool(self.primary_pool)
314
+ end
315
+
316
+ begin
317
+ socket = get_socket_from_pool(self.read_pool)
318
+
319
+ if !socket
320
+ connect
321
+ socket = get_socket_from_pool(self.primary_pool)
322
+ end
323
+ rescue => ex
324
+ checkin(socket) if socket
325
+ raise ex
307
326
  end
308
327
 
309
328
  if socket
@@ -315,12 +334,21 @@ module Mongo
315
334
 
316
335
  # Checkout a socket for writing (i.e., a primary node).
317
336
  def checkout_writer
318
- connect unless connected?
319
- socket = get_socket_from_pool(self.primary_pool)
320
-
321
- if !socket
337
+ if connected?
338
+ sync_refresh
339
+ else
322
340
  connect
341
+ end
342
+ begin
323
343
  socket = get_socket_from_pool(self.primary_pool)
344
+
345
+ if !socket
346
+ connect
347
+ socket = get_socket_from_pool(self.primary_pool)
348
+ end
349
+ rescue => ex
350
+ checkin(socket)
351
+ raise ex
324
352
  end
325
353
 
326
354
  if socket
@@ -332,8 +360,8 @@ module Mongo
332
360
 
333
361
  # Checkin a socket used for reading.
334
362
  def checkin_reader(socket)
335
- if !self.read_pool.checkin(socket) &&
336
- !self.primary_pool.checkin(socket)
363
+ if !((self.read_pool && self.read_pool.checkin(socket)) ||
364
+ (self.primary_pool && self.primary_pool.checkin(socket)))
337
365
  close_socket(socket)
338
366
  end
339
367
  sync_refresh
@@ -341,7 +369,7 @@ module Mongo
341
369
 
342
370
  # Checkin a socket used for writing.
343
371
  def checkin_writer(socket)
344
- if !self.primary_pool.checkin(socket)
372
+ if !self.primary_pool || !self.primary_pool.checkin(socket)
345
373
  close_socket(socket)
346
374
  end
347
375
  sync_refresh
@@ -349,7 +377,7 @@ module Mongo
349
377
 
350
378
  def close_socket(socket)
351
379
  begin
352
- socket.close
380
+ socket.close if socket
353
381
  rescue IOError
354
382
  log(:info, "Tried to close socket #{socket} but already closed.")
355
383
  end
@@ -372,36 +400,40 @@ module Mongo
372
400
  end
373
401
 
374
402
  def primary
375
- @manager.primary
403
+ @manager ? @manager.primary : nil
376
404
  end
377
405
 
378
406
  # Note: might want to freeze these after connecting.
379
407
  def secondaries
380
- @manager.secondaries
408
+ @manager ? @manager.secondaries : []
381
409
  end
382
410
 
383
411
  def hosts
384
- @manager.hosts
412
+ @manager ? @manager.hosts : []
385
413
  end
386
414
 
387
415
  def primary_pool
388
- @manager.primary_pool
416
+ @manager ? @manager.primary_pool : nil
389
417
  end
390
418
 
391
419
  def read_pool
392
- @manager.read_pool
420
+ @manager ? @manager.read_pool : nil
393
421
  end
394
422
 
395
423
  def secondary_pools
396
- @manager.secondary_pools
424
+ @manager ? @manager.secondary_pools : []
397
425
  end
398
426
 
399
427
  def tag_map
400
- @manager.tag_map
428
+ @manager ? @manager.tag_map : {}
401
429
  end
402
430
 
403
431
  def max_bson_size
404
- @manager.max_bson_size
432
+ if @manager && @manager.max_bson_size
433
+ @manager.max_bson_size
434
+ else
435
+ Mongo::DEFAULT_MAX_BSON_SIZE
436
+ end
405
437
  end
406
438
 
407
439
  private
@@ -437,10 +469,10 @@ module Mongo
437
469
  @pool_timeout = opts[:pool_timeout] || opts[:timeout] || 5.0
438
470
 
439
471
  # Timeout on socket read operation.
440
- @op_timeout = opts[:op_timeout] || nil
472
+ @op_timeout = opts[:op_timeout] || 30
441
473
 
442
474
  # Timeout on socket connect.
443
- @connect_timeout = opts[:connect_timeout] || nil
475
+ @connect_timeout = opts[:connect_timeout] || 30
444
476
 
445
477
  # Mutex for synchronizing pool access
446
478
  # TODO: remove this.
@@ -468,14 +500,6 @@ module Mongo
468
500
  connect if should_connect
469
501
  end
470
502
 
471
- # Given a pool manager, update this connection's
472
- # view of the replica set.
473
- def update_config(new_manager)
474
- @manager = new_manager
475
- @seeds = @manager.seeds.dup
476
- @refresh_version += 1
477
- end
478
-
479
503
  # Checkout a socket connected to a node with one of
480
504
  # the provided tags. If no such node exists, raise
481
505
  # an exception.