mongo 1.8.2 → 1.8.3.rc0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data.tar.gz.sig +0 -0
  2. data/LICENSE +1 -1
  3. data/README.md +2 -7
  4. data/VERSION +1 -1
  5. data/lib/mongo.rb +2 -18
  6. data/lib/mongo/collection.rb +20 -24
  7. data/lib/mongo/cursor.rb +30 -35
  8. data/lib/mongo/db.rb +1 -19
  9. data/lib/mongo/exceptions.rb +0 -19
  10. data/lib/mongo/gridfs/grid.rb +18 -29
  11. data/lib/mongo/gridfs/grid_ext.rb +0 -18
  12. data/lib/mongo/gridfs/grid_file_system.rb +17 -26
  13. data/lib/mongo/gridfs/grid_io.rb +0 -18
  14. data/lib/mongo/legacy.rb +0 -18
  15. data/lib/mongo/mongo_client.rb +11 -33
  16. data/lib/mongo/mongo_replica_set_client.rb +29 -56
  17. data/lib/mongo/mongo_sharded_client.rb +38 -50
  18. data/lib/mongo/networking.rb +5 -4
  19. data/lib/mongo/util/conversions.rb +0 -17
  20. data/lib/mongo/util/core_ext.rb +0 -18
  21. data/lib/mongo/util/node.rb +16 -3
  22. data/lib/mongo/util/pool.rb +46 -36
  23. data/lib/mongo/util/pool_manager.rb +102 -71
  24. data/lib/mongo/util/read_preference.rb +4 -2
  25. data/lib/mongo/util/server_version.rb +0 -17
  26. data/lib/mongo/util/sharding_pool_manager.rb +4 -23
  27. data/lib/mongo/util/socket_util.rb +20 -0
  28. data/lib/mongo/util/ssl_socket.rb +10 -19
  29. data/lib/mongo/util/support.rb +0 -18
  30. data/lib/mongo/util/tcp_socket.rb +1 -9
  31. data/lib/mongo/util/thread_local_variable_manager.rb +0 -18
  32. data/lib/mongo/util/uri_parser.rb +87 -82
  33. data/lib/mongo/util/write_concern.rb +0 -18
  34. data/mongo.gemspec +4 -1
  35. data/test/auxillary/pool_reuse_test.rb +65 -0
  36. data/test/functional/collection_test.rb +92 -3
  37. data/test/functional/connection_test.rb +30 -6
  38. data/test/functional/db_api_test.rb +11 -0
  39. data/test/functional/timeout_test.rb +23 -0
  40. data/test/functional/uri_test.rb +69 -0
  41. data/test/replica_set/client_test.rb +0 -22
  42. data/test/replica_set/cursor_test.rb +11 -5
  43. data/test/replica_set/refresh_test.rb +0 -0
  44. data/test/replica_set/z_cluster_shutdown.rb +13 -0
  45. data/test/sharded_cluster/basic_test.rb +46 -32
  46. data/test/test_helper.rb +26 -1
  47. data/test/threading/basic_test.rb +10 -9
  48. data/test/tools/mongo_config.rb +6 -2
  49. data/test/unit/collection_test.rb +1 -1
  50. data/test/unit/grid_test.rb +20 -13
  51. data/test/unit/mongo_sharded_client_test.rb +32 -0
  52. data/test/unit/pool_manager_test.rb +28 -14
  53. metadata +45 -12
  54. metadata.gz.sig +0 -0
@@ -1,21 +1,3 @@
1
- # encoding: UTF-8
2
-
3
- # --
4
- # Copyright (C) 2008-2012 10gen Inc.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- # ++
18
-
19
1
  module Mongo
20
2
  module GridExt
21
3
  module InstanceMethods
@@ -1,21 +1,3 @@
1
- # encoding: UTF-8
2
-
3
- # --
4
- # Copyright (C) 2008-2012 10gen Inc.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- # ++
18
-
19
1
  module Mongo
20
2
 
21
3
  # A file store built on the GridFS specification featuring
@@ -39,12 +21,12 @@ module Mongo
39
21
 
40
22
  @default_query_opts = {:sort => [['filename', 1], ['uploadDate', -1]], :limit => 1}
41
23
 
42
- # Create indexes only if we're connected to a primary node.
24
+ # This will create indexes only if we're connected to a primary node.
43
25
  connection = @db.connection
44
- if (connection.class == MongoClient && connection.read_primary?) ||
45
- (connection.class == MongoReplicaSetClient && connection.primary)
46
- @files.create_index([['filename', 1], ['uploadDate', -1]])
47
- @chunks.create_index([['files_id', Mongo::ASCENDING], ['n', Mongo::ASCENDING]], :unique => true)
26
+ begin
27
+ @files.ensure_index([['filename', 1], ['uploadDate', -1]])
28
+ @chunks.ensure_index([['files_id', Mongo::ASCENDING], ['n', Mongo::ASCENDING]], :unique => true)
29
+ rescue Mongo::ConnectionFailure
48
30
  end
49
31
  end
50
32
 
@@ -104,9 +86,18 @@ module Mongo
104
86
  opts = opts.dup
105
87
  opts.merge!(default_grid_io_opts(filename))
106
88
  if mode == 'w'
107
- versions = opts.delete(:versions)
108
- if opts.delete(:delete_old) || (versions && versions < 1)
109
- versions = 1
89
+ begin
90
+ # Ensure there are the appropriate indexes, as state may have changed since instantiation of self.
91
+ # Recall that index definitions are cached with ensure_index so this statement won't unneccesarily repeat index creation.
92
+ @files.ensure_index([['filename', 1], ['uploadDate', -1]])
93
+ @chunks.ensure_index([['files_id', Mongo::ASCENDING], ['n', Mongo::ASCENDING]], :unique => true)
94
+ versions = opts.delete(:versions)
95
+ if opts.delete(:delete_old) || (versions && versions < 1)
96
+ versions = 1
97
+ end
98
+ rescue Mongo::ConnectionFailure => e
99
+ raise e, "Failed to create necessary indexes and write data."
100
+ return
110
101
  end
111
102
  end
112
103
  file = GridIO.new(@files, @chunks, filename, mode, opts)
@@ -1,21 +1,3 @@
1
- # encoding: UTF-8
2
-
3
- # --
4
- # Copyright (C) 2008-2012 10gen Inc.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- # ++
18
-
19
1
  require 'digest/md5'
20
2
 
21
3
  module Mongo
@@ -1,21 +1,3 @@
1
- # encoding: UTF-8
2
-
3
- # --
4
- # Copyright (C) 2008-2012 10gen Inc.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- # ++
18
-
19
1
  module Mongo
20
2
  module LegacyWriteConcern
21
3
  @legacy_write_concern = true
@@ -1,21 +1,3 @@
1
- # encoding: UTF-8
2
-
3
- # --
4
- # Copyright (C) 2008-2012 10gen Inc.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- # ++
18
-
19
1
  require 'set'
20
2
  require 'socket'
21
3
  require 'thread'
@@ -128,9 +110,6 @@ module Mongo
128
110
  opts = args.last.is_a?(Hash) ? args.pop : {}
129
111
  @host, @port = parse_init(args[0], args[1], opts)
130
112
 
131
- # Default maximum BSON object size
132
- @max_bson_size = Mongo::DEFAULT_MAX_BSON_SIZE
133
-
134
113
  # Lock for request ids.
135
114
  @id_lock = Mutex.new
136
115
 
@@ -181,7 +160,7 @@ module Mongo
181
160
 
182
161
  # Initialize a connection to MongoDB using the MongoDB URI spec.
183
162
  #
184
- # Since MongoClient.new cannot be used with any <code>ENV["MONGODB_URI"]</code> that has multiple hosts (implying a replicaset),
163
+ # Since MongoClient.new cannot be used with any <code>ENV["MONGODB_URI"]</code> that has multiple hosts (implying a replicaset),
185
164
  # you may use this when the type of your connection varies by environment and should be determined solely from <code>ENV["MONGODB_URI"]</code>.
186
165
  #
187
166
  # @param uri [String]
@@ -471,7 +450,8 @@ module Mongo
471
450
  @mongos = true
472
451
  end
473
452
 
474
- @max_bson_size = config['maxBsonObjectSize'] || Mongo::DEFAULT_MAX_BSON_SIZE
453
+ @max_bson_size = config['maxBsonObjectSize']
454
+ @max_message_size = config['maxMessageSizeBytes']
475
455
  set_primary(host_port)
476
456
  end
477
457
 
@@ -479,10 +459,7 @@ module Mongo
479
459
  raise ConnectionFailure, "Failed to connect to a master node at #{host_port.join(":")}"
480
460
  end
481
461
  end
482
-
483
- # Ensures that the alias carries over to the overridden connect method when using
484
- # the replica set or sharded clients.
485
- def reconnect; connect end
462
+ alias :reconnect :connect
486
463
 
487
464
  # It's possible that we defined connected as all nodes being connected???
488
465
  # NOTE: Do check if this needs to be more stringent.
@@ -514,10 +491,7 @@ module Mongo
514
491
  def read_primary?
515
492
  @read_primary
516
493
  end
517
-
518
- # Ensures that the alias carries over to the overridden connect method when using
519
- # the replica set or sharded clients.
520
- def primary?; read_primary? end
494
+ alias :primary? :read_primary?
521
495
 
522
496
  # The socket pool that this connection reads from.
523
497
  #
@@ -538,7 +512,11 @@ module Mongo
538
512
  #
539
513
  # @return [Integer]
540
514
  def max_bson_size
541
- @max_bson_size
515
+ @max_bson_size || DEFAULT_MAX_BSON_SIZE
516
+ end
517
+
518
+ def max_message_size
519
+ @max_message_size || DEFAULT_MAX_MESSAGE_SIZE
542
520
  end
543
521
 
544
522
  # Checkout a socket for reading (i.e., a secondary node).
@@ -559,7 +537,7 @@ module Mongo
559
537
  # Note: this is overridden in MongoReplicaSetClient.
560
538
  def checkin(socket)
561
539
  if @primary_pool && socket && socket.pool
562
- socket.pool.checkin(socket)
540
+ socket.checkin
563
541
  end
564
542
  end
565
543
 
@@ -1,21 +1,3 @@
1
- # encoding: UTF-8
2
-
3
- # --
4
- # Copyright (C) 2008-2012 10gen Inc.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- # ++
18
-
19
1
  module Mongo
20
2
 
21
3
  # Instantiates and manages connections to a MongoDB replica set.
@@ -151,7 +133,6 @@ module Mongo
151
133
 
152
134
  # No connection manager by default.
153
135
  @manager = nil
154
- @old_managers = []
155
136
 
156
137
  # Lock for request ids.
157
138
  @id_lock = Mutex.new
@@ -183,15 +164,26 @@ module Mongo
183
164
  # Initiate a connection to the replica set.
184
165
  def connect
185
166
  log(:info, "Connecting...")
186
- @connect_mutex.synchronize do
187
- return if @connected
188
167
 
189
- seeds = @manager.nil? ? @seeds : @manager.seeds
190
- @manager = PoolManager.new(self, seeds)
168
+ # Prevent recursive connection attempts from the same thread.
169
+ # This is done rather than using a Monitor to prevent potentially recursing
170
+ # infinitely while attempting to connect and continually failing. Instead, fail fast.
171
+ raise ConnectionFailure, "Failed to get node data." if thread_local[:locks][:connecting] == true
191
172
 
192
- thread_local[:managers][self] = @manager
193
-
194
- @manager.connect
173
+ @connect_mutex.synchronize do
174
+ return if @connected
175
+ begin
176
+ thread_local[:locks][:connecting] = true
177
+ if @manager
178
+ @manager.refresh! @seeds
179
+ else
180
+ @manager = PoolManager.new(self, @seeds)
181
+ thread_local[:managers][self] = @manager
182
+ @manager.connect
183
+ end
184
+ ensure
185
+ thread_local[:locks][:connecting] = false
186
+ end
195
187
  @refresh_version += 1
196
188
 
197
189
  if @manager.pools.empty?
@@ -235,15 +227,7 @@ module Mongo
235
227
  # to get the refresh lock.
236
228
  def hard_refresh!
237
229
  log(:info, "Initiating hard refresh...")
238
- discovered_seeds = @manager.seeds
239
- new_manager = PoolManager.new(self, discovered_seeds | @seeds)
240
- new_manager.connect
241
-
242
- thread_local[:managers][self] = new_manager
243
-
244
- # TODO: make sure that connect has succeeded
245
- @old_managers << @manager
246
- @manager = new_manager
230
+ @manager.refresh! @seeds
247
231
 
248
232
  @refresh_version += 1
249
233
  return true
@@ -286,6 +270,7 @@ module Mongo
286
270
  def read_primary?
287
271
  @manager.read_pool == @manager.primary_pool
288
272
  end
273
+ alias :primary? :read_primary?
289
274
 
290
275
  # Close the connection to the database.
291
276
  def close(opts={})
@@ -343,12 +328,11 @@ module Mongo
343
328
  end
344
329
 
345
330
  if socket
346
- socket
331
+ return socket
347
332
  else
348
333
  @connected = false
349
334
  raise ConnectionFailure.new("Could not checkout a socket.")
350
335
  end
351
- socket
352
336
  end
353
337
 
354
338
  def checkout_reader(mode=@read, tag_sets=@tag_sets, acceptable_latency=@acceptable_latency)
@@ -368,7 +352,7 @@ module Mongo
368
352
  # Checkin a socket used for reading.
369
353
  def checkin(socket)
370
354
  if socket && socket.pool
371
- socket.pool.checkin(socket)
355
+ socket.checkin
372
356
  end
373
357
  sync_refresh
374
358
  end
@@ -435,11 +419,13 @@ module Mongo
435
419
  end
436
420
 
437
421
  def max_bson_size
438
- if local_manager && local_manager.max_bson_size
439
- local_manager.max_bson_size
440
- else
441
- Mongo::DEFAULT_MAX_BSON_SIZE
442
- end
422
+ return local_manager.max_bson_size if local_manager
423
+ DEFAULT_MAX_BSON_SIZE
424
+ end
425
+
426
+ def max_message_size
427
+ return local_manager.max_message_size if local_manager
428
+ DEFAULT_MAX_MESSAGE_SIZE
443
429
  end
444
430
 
445
431
  private
@@ -480,18 +466,6 @@ module Mongo
480
466
  super opts
481
467
  end
482
468
 
483
- def prune_managers
484
- @old_managers.each do |manager|
485
- if manager != @manager
486
- if manager.closed?
487
- @old_managers.delete(manager)
488
- else
489
- manager.close(:soft => true)
490
- end
491
- end
492
- end
493
- end
494
-
495
469
  def sync_refresh
496
470
  if @refresh_mode == :sync &&
497
471
  ((Time.now - @last_refresh) > @refresh_interval)
@@ -501,7 +475,6 @@ module Mongo
501
475
  if @refresh_mutex.try_lock
502
476
  begin
503
477
  refresh
504
- prune_managers
505
478
  ensure
506
479
  @refresh_mutex.unlock
507
480
  end
@@ -1,21 +1,3 @@
1
- # encoding: UTF-8
2
-
3
- # --
4
- # Copyright (C) 2008-2012 10gen Inc.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- # ++
18
-
19
1
  module Mongo
20
2
 
21
3
  # Instantiates and manages connections to a MongoDB sharded cluster for high availability.
@@ -34,11 +16,8 @@ module Mongo
34
16
 
35
17
  if nodes.empty? and ENV.has_key?('MONGODB_URI')
36
18
  parser = URIParser.new ENV['MONGODB_URI']
37
- if parser.direct?
38
- raise MongoArgumentError, "Mongo::MongoShardedClient.new called with no arguments, but ENV['MONGODB_URI'] implies a direct connection."
39
- end
40
19
  opts = parser.connection_options.merge! opts
41
- nodes = [parser.nodes]
20
+ nodes = parser.node_strings
42
21
  end
43
22
 
44
23
  unless nodes.length > 0
@@ -59,7 +38,6 @@ module Mongo
59
38
 
60
39
  # No connection manager by default.
61
40
  @manager = nil
62
- @old_managers = []
63
41
 
64
42
  # Lock for request ids.
65
43
  @id_lock = Mutex.new
@@ -80,7 +58,7 @@ module Mongo
80
58
  end
81
59
 
82
60
  def valid_opts
83
- GENERIC_OPTS + SHARDED_CLUSTER_OPTS
61
+ GENERIC_OPTS + SHARDED_CLUSTER_OPTS + READ_PREFERENCE_OPTS + WRITE_CONCERN_OPTS
84
62
  end
85
63
 
86
64
  def inspect
@@ -92,14 +70,26 @@ module Mongo
92
70
  def connect(force = !@connected)
93
71
  return unless force
94
72
  log(:info, "Connecting...")
95
- @connect_mutex.synchronize do
96
- discovered_seeds = @manager ? @manager.seeds : []
97
- @old_managers << @manager if @manager
98
- @manager = ShardingPoolManager.new(self, discovered_seeds | @seeds)
99
73
 
100
- thread_local[:managers][self] = @manager
74
+ # Prevent recursive connection attempts from the same thread.
75
+ # This is done rather than using a Monitor to prevent potentially recursing
76
+ # infinitely while attempting to connect and continually failing. Instead, fail fast.
77
+ raise ConnectionFailure, "Failed to get node data." if thread_local[:locks][:connecting]
78
+
79
+ @connect_mutex.synchronize do
80
+ begin
81
+ thread_local[:locks][:connecting] = true
82
+ if @manager
83
+ @manager.refresh! @seeds
84
+ else
85
+ @manager = ShardingPoolManager.new(self, @seeds)
86
+ thread_local[:managers][self] = @manager
87
+ @manager.connect
88
+ end
89
+ ensure
90
+ thread_local[:locks][:connecting] = false
91
+ end
101
92
 
102
- @manager.connect
103
93
  @refresh_version += 1
104
94
  @last_refresh = Time.now
105
95
  @connected = true
@@ -134,27 +124,25 @@ module Mongo
134
124
  end
135
125
 
136
126
  def checkout(&block)
137
- 2.times do
138
- if connected?
139
- sync_refresh
140
- else
141
- connect
142
- end
143
-
144
- begin
145
- socket = block.call
146
- rescue => ex
147
- checkin(socket) if socket
148
- raise ex
149
- end
150
-
151
- if socket
152
- return socket
153
- else
154
- @connected = false
155
- #raise ConnectionFailure.new("Could not checkout a socket.")
156
- end
127
+ tries = 0
128
+ begin
129
+ super(&block)
130
+ rescue ConnectionFailure
131
+ tries +=1
132
+ tries < 2 ? retry : raise
157
133
  end
158
134
  end
135
+
136
+ # Initialize a connection to MongoDB using the MongoDB URI spec.
137
+ #
138
+ # @param uri [ String ] string of the format:
139
+ # mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/database]
140
+ #
141
+ # @param opts [ Hash ] Any of the options available for MongoShardedClient.new
142
+ #
143
+ # @return [ Mongo::MongoShardedClient ] The sharded client.
144
+ def self.from_uri(uri = ENV['MONGODB_URI'], options = {})
145
+ URIParser.new(uri).connection(options, false, true)
146
+ end
159
147
  end
160
148
  end