mongo 1.8.3 → 1.8.4.rc0

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.
@@ -241,7 +241,7 @@ module Mongo
241
241
  def apply_saved_authentication(opts={})
242
242
  return false if @auths.empty?
243
243
  @auths.each do |auth|
244
- self[auth['db_name']].issue_authentication(auth['username'], auth['password'], false,
244
+ self[auth[:db_name]].issue_authentication(auth[:username], auth[:password], false,
245
245
  :socket => opts[:socket])
246
246
  end
247
247
  true
@@ -261,11 +261,15 @@ module Mongo
261
261
  #
262
262
  # @return [Hash] a hash representing the authentication just added.
263
263
  def add_auth(db_name, username, password)
264
- remove_auth(db_name)
265
- auth = {}
266
- auth['db_name'] = db_name
267
- auth['username'] = username
268
- auth['password'] = password
264
+ if @auths.any? {|a| a[:db_name] == db_name}
265
+ raise MongoArgumentError, "Cannot apply multiple authentications to database '#{db_name}'"
266
+ end
267
+
268
+ auth = {
269
+ :db_name => db_name,
270
+ :username => username,
271
+ :password => password
272
+ }
269
273
  @auths << auth
270
274
  auth
271
275
  end
@@ -277,11 +281,7 @@ module Mongo
277
281
  # @return [Boolean]
278
282
  def remove_auth(db_name)
279
283
  return unless @auths
280
- if @auths.reject! { |a| a['db_name'] == db_name }
281
- true
282
- else
283
- false
284
- end
284
+ @auths.reject! { |a| a[:db_name] == db_name } ? true : false
285
285
  end
286
286
 
287
287
  # Remove all authentication information stored in this connection.
@@ -351,10 +351,14 @@ module Mongo
351
351
  def refresh
352
352
  end
353
353
 
354
- def pin_pool(pool)
354
+ def pinned_pool
355
+ @primary_pool
356
+ end
357
+
358
+ def pin_pool(pool, read_prefs)
355
359
  end
356
360
 
357
- def unpin_pool(pool)
361
+ def unpin_pool
358
362
  end
359
363
 
360
364
  # Drop a database.
@@ -521,7 +525,7 @@ module Mongo
521
525
 
522
526
  # Checkout a socket for reading (i.e., a secondary node).
523
527
  # Note: this is overridden in MongoReplicaSetClient.
524
- def checkout_reader(mode=:primary, tag_sets={}, acceptable_latency=15)
528
+ def checkout_reader(read_preference)
525
529
  connect unless connected?
526
530
  @primary_pool.checkout
527
531
  end
@@ -2,6 +2,7 @@ module Mongo
2
2
 
3
3
  # Instantiates and manages connections to a MongoDB replica set.
4
4
  class MongoReplicaSetClient < MongoClient
5
+ include ReadPreference
5
6
  include ThreadLocalVariableManager
6
7
 
7
8
  REPL_SET_OPTS = [
@@ -268,7 +269,7 @@ module Mongo
268
269
  #
269
270
  # @return [Boolean]
270
271
  def read_primary?
271
- @manager.read_pool == @manager.primary_pool
272
+ read_pool == primary_pool
272
273
  end
273
274
  alias :primary? :read_primary?
274
275
 
@@ -282,6 +283,7 @@ module Mongo
282
283
 
283
284
  # Clear the reference to this object.
284
285
  thread_local[:managers].delete(self)
286
+ unpin_pool
285
287
 
286
288
  @connected = false
287
289
  end
@@ -335,9 +337,9 @@ module Mongo
335
337
  end
336
338
  end
337
339
 
338
- def checkout_reader(mode=@read, tag_sets=@tag_sets, acceptable_latency=@acceptable_latency)
340
+ def checkout_reader(read_pref={})
339
341
  checkout do
340
- pool = read_pool(mode, tag_sets, acceptable_latency)
342
+ pool = read_pool(read_pref)
341
343
  get_socket_from_pool(pool)
342
344
  end
343
345
  end
@@ -361,11 +363,20 @@ module Mongo
361
363
  thread_local[:managers][self] = @manager
362
364
  end
363
365
 
364
- def pin_pool(pool)
365
- thread_local[:pinned_pools][@manager.object_id] = pool if @manager
366
+ def pinned_pool
367
+ thread_local[:pinned_pools][@manager.object_id] if @manager
366
368
  end
367
369
 
368
- def unpin_pool(pool)
370
+ def pin_pool(pool, read_preference)
371
+ if @manager
372
+ thread_local[:pinned_pools][@manager.object_id] = {
373
+ :pool => pool,
374
+ :read_preference => read_preference
375
+ }
376
+ end
377
+ end
378
+
379
+ def unpin_pool
369
380
  thread_local[:pinned_pools].delete @manager.object_id if @manager
370
381
  end
371
382
 
@@ -402,10 +413,6 @@ module Mongo
402
413
  local_manager ? local_manager.primary_pool : nil
403
414
  end
404
415
 
405
- def read_pool(mode=@read, tags=@tag_sets, acceptable_latency=@acceptable_latency)
406
- local_manager ? local_manager.read_pool(mode, tags, acceptable_latency) : nil
407
- end
408
-
409
416
  def secondary_pool
410
417
  local_manager ? local_manager.secondary_pool : nil
411
418
  end
@@ -85,25 +85,6 @@ module Mongo
85
85
  !@closed
86
86
  end
87
87
 
88
- def matches_mode(mode)
89
- if mode == :primary && @node.secondary? ||
90
- mode == :secondary && @node.primary?
91
- false
92
- else
93
- true
94
- end
95
- end
96
-
97
- def matches_tag_set(tag_set)
98
- tag_set.all? do |tag, value|
99
- tags.has_key?(tag) && tags[tag] == value
100
- end
101
- end
102
-
103
- def matches_tag_sets(tag_sets)
104
- tag_sets.all? {|set| matches_tag_set(set)}
105
- end
106
-
107
88
  def inspect
108
89
  "#<Mongo::Pool:0x#{self.object_id.to_s(16)} @host=#{@host} @port=#{port} " +
109
90
  "@ping_time=#{@ping_time} #{@checked_out.size}/#{@size} sockets available " +
@@ -1,6 +1,5 @@
1
1
  module Mongo
2
2
  class PoolManager
3
- include Mongo::ReadPreference
4
3
  include ThreadLocalVariableManager
5
4
 
6
5
  attr_reader :client,
@@ -114,26 +113,6 @@ module Mongo
114
113
  read_pool.host_port
115
114
  end
116
115
 
117
- def read_pool(mode=@client.read,
118
- tags=@client.tag_sets,
119
- acceptable_latency=@client.acceptable_latency)
120
-
121
- pinned = thread_local[:pinned_pools][self.object_id]
122
-
123
- if pinned && pinned.matches_mode(mode) && pinned.matches_tag_sets(tags) && pinned.up?
124
- pool = pinned
125
- else
126
- pool = select_pool(mode, tags, acceptable_latency)
127
- end
128
-
129
- unless pool
130
- raise ConnectionFailure, "No replica set member available for query " +
131
- "with read preference matching mode #{mode} and tags matching #{tags}."
132
- end
133
-
134
- pool
135
- end
136
-
137
116
  def max_bson_size
138
117
  @max_bson_size ||= config_min('maxBsonObjectSize', DEFAULT_MAX_BSON_SIZE)
139
118
  end
@@ -33,29 +33,56 @@ module Mongo
33
33
  end
34
34
  end
35
35
 
36
- def select_pool(mode, tags, latency)
37
- return primary_pool if @client.mongos?
36
+ def read_preference
37
+ {
38
+ :mode => @read,
39
+ :tags => @tag_sets,
40
+ :latency => @acceptable_latency
41
+ }
42
+ end
43
+
44
+ def read_pool(read_preference_override={})
45
+ return primary_pool if mongos?
46
+
47
+ read_pref = read_preference.merge(read_preference_override)
48
+
49
+ if pinned_pool && pinned_pool[:read_preference] == read_pref
50
+ pool = pinned_pool[:pool]
51
+ else
52
+ unpin_pool
53
+ pool = select_pool(read_pref)
54
+ end
55
+
56
+ unless pool
57
+ raise ConnectionFailure, "No replica set member available for query " +
58
+ "with read preference matching mode #{read_pref[:mode]} and tags " +
59
+ "matching #{read_pref[:tags]}."
60
+ end
61
+
62
+ pool
63
+ end
38
64
 
39
- if mode == :primary && !tags.empty?
65
+ def select_pool(read_pref)
66
+ if read_pref[:mode] == :primary && !read_pref[:tags].empty?
40
67
  raise MongoArgumentError, "Read preference :primary cannot be combined with tags"
41
68
  end
42
69
 
43
- case mode
70
+ case read_pref[:mode]
44
71
  when :primary
45
72
  primary_pool
46
73
  when :primary_preferred
47
- primary_pool || select_secondary_pool(secondary_pools, tags, latency)
74
+ primary_pool || select_secondary_pool(secondary_pools, read_pref)
48
75
  when :secondary
49
- select_secondary_pool(secondary_pools, tags, latency)
76
+ select_secondary_pool(secondary_pools, read_pref)
50
77
  when :secondary_preferred
51
- select_secondary_pool(secondary_pools, tags, latency) || primary_pool
78
+ select_secondary_pool(secondary_pools, read_pref) || primary_pool
52
79
  when :nearest
53
- select_secondary_pool(pools, tags, latency)
80
+ select_secondary_pool(pools, read_pref)
54
81
  end
55
82
  end
56
83
 
57
- def select_secondary_pool(candidates, tag_sets, latency)
58
- tag_sets = [tag_sets] unless tag_sets.is_a?(Array)
84
+ def select_secondary_pool(candidates, read_pref)
85
+ tag_sets = read_pref[:tags]
59
86
 
60
87
  if !tag_sets.empty?
61
88
  matches = []
@@ -70,10 +97,11 @@ module Mongo
70
97
  matches = candidates
71
98
  end
72
99
 
73
- matches.empty? ? nil : select_near_pool(matches, latency)
100
+ matches.empty? ? nil : select_near_pool(matches, read_pref)
74
101
  end
75
102
 
76
- def select_near_pool(candidates, latency)
103
+ def select_near_pool(candidates, read_pref)
104
+ latency = read_pref[:latency]
77
105
  nearest_pool = candidates.min_by { |candidate| candidate.ping_time }
78
106
  near_pools = candidates.select do |candidate|
79
107
  (candidate.ping_time - nearest_pool.ping_time) <= latency
@@ -220,7 +220,7 @@ module Mongo
220
220
  opts[:pool_size] = @pool_size
221
221
  end
222
222
 
223
- if @readpreference && replicaset?
223
+ if @readpreference
224
224
  opts[:read] = @readpreference
225
225
  end
226
226
 
@@ -285,7 +285,7 @@ module Mongo
285
285
  end
286
286
 
287
287
  if uname && pwd && db
288
- auths << {'db_name' => db, 'username' => uname, 'password' => pwd}
288
+ auths << {:db_name => db, :username => uname, :password => pwd}
289
289
  elsif uname || pwd
290
290
  raise MongoArgumentError, "MongoDB URI must include username, password, "
291
291
  "and db if username and password are specified."
@@ -9,6 +9,7 @@ Gem::Specification.new do |s|
9
9
  s.summary = 'Ruby driver for MongoDB'
10
10
  s.description = 'A Ruby driver for MongoDB. For more information about Mongo, see http://www.mongodb.org.'
11
11
  s.rubyforge_project = 'mongo'
12
+ s.license = 'Apache License Version 2.0'
12
13
 
13
14
  s.signing_key = 'gem-private_key.pem'
14
15
  s.cert_chain = ['gem-public_cert.pem']
File without changes
@@ -70,11 +70,17 @@ class ObjectIdTest < Test::Unit::TestCase
70
70
  end
71
71
 
72
72
  def test_illegal_from_string
73
- assert_raise InvalidObjectId do
73
+ assert_raise InvalidObjectId do
74
74
  ObjectId.from_string("")
75
75
  end
76
76
  end
77
77
 
78
+ def test_from_string_with_object_id
79
+ assert_raise InvalidObjectId do
80
+ ObjectId.from_string(@o)
81
+ end
82
+ end
83
+
78
84
  def test_legal
79
85
  assert !ObjectId.legal?(nil)
80
86
  assert !ObjectId.legal?("fred")
@@ -1075,7 +1075,6 @@ end
1075
1075
  coll.ensure_index([['a', 1]])
1076
1076
  end
1077
1077
 
1078
-
1079
1078
  if @@version > '2.0.0'
1080
1079
  def test_show_disk_loc
1081
1080
  @@test.save({:a => 1})
@@ -1252,12 +1251,36 @@ end
1252
1251
  assert_nil @geo.index_information['baz']
1253
1252
  end
1254
1253
 
1254
+ #should "create a text index" do
1255
+ # @geo.save({'title' => "some text"})
1256
+ # @geo.create_index([['title', Mongo::TEXT]])
1257
+ # assert @geo.index_information['title_text']
1258
+ #end
1259
+
1260
+ should "create a hashed index" do
1261
+ @geo.save({'a' => 1})
1262
+ @geo.create_index([['a', Mongo::HASHED]])
1263
+ assert @geo.index_information['a_hashed']
1264
+ end
1265
+
1255
1266
  should "create a geospatial index" do
1256
1267
  @geo.save({'loc' => [-100, 100]})
1257
1268
  @geo.create_index([['loc', Mongo::GEO2D]])
1258
1269
  assert @geo.index_information['loc_2d']
1259
1270
  end
1260
1271
 
1272
+ should "create a geoHaystack index" do
1273
+ @geo.save({ "_id" => 100, "pos" => { "long" => 126.9, "lat" => 35.2 }, "type" => "restaurant"})
1274
+ @geo.create_index([['pos', Mongo::GEOHAYSTACK], ['type', Mongo::ASCENDING]], :bucket_size => 1)
1275
+ puts @geo.index_information['loc_geoHaystack_type_1']
1276
+ end
1277
+
1278
+ should "create a geo 2dsphere index" do
1279
+ @collection.insert({"coordinates" => [ 5 , 5 ], "type" => "Point"})
1280
+ @geo.create_index([['coordinates', Mongo::GEO2DSPHERE]])
1281
+ assert @geo.index_information['coordinates_2dsphere']
1282
+ end
1283
+
1261
1284
  should "create a unique index" do
1262
1285
  @collection.create_index([['a', Mongo::ASCENDING]], :unique => true)
1263
1286
  assert @collection.index_information['a_1']['unique'] == true
@@ -336,8 +336,8 @@ class TestConnection < Test::Unit::TestCase
336
336
  context "Saved authentications" do
337
337
  setup do
338
338
  @client = standard_connection
339
- @auth = {'db_name' => 'test', 'username' => 'bob', 'password' => 'secret'}
340
- @client.add_auth(@auth['db_name'], @auth['username'], @auth['password'])
339
+ @auth = {:db_name => 'test', :username => 'bob', :password => 'secret'}
340
+ @client.add_auth(@auth[:db_name], @auth[:username], @auth[:password])
341
341
  end
342
342
 
343
343
  teardown do
@@ -348,11 +348,11 @@ class TestConnection < Test::Unit::TestCase
348
348
  assert_equal @auth, @client.auths[0]
349
349
  end
350
350
 
351
- should "replace the auth if given a new auth for the same db" do
352
- auth = {'db_name' => 'test', 'username' => 'mickey', 'password' => 'm0u53'}
353
- @client.add_auth(auth['db_name'], auth['username'], auth['password'])
354
- assert_equal 1, @client.auths.length
355
- assert_equal auth, @client.auths[0]
351
+ should "not allow multiple authentications for the same db" do
352
+ auth = {:db_name => 'test', :username => 'mickey', :password => 'm0u53'}
353
+ assert_raise Mongo::MongoArgumentError do
354
+ @client.add_auth(auth[:db_name], auth[:username], auth[:password])
355
+ end
356
356
  end
357
357
 
358
358
  should "remove auths by database" do
@@ -92,7 +92,7 @@ class DBAPITest < Test::Unit::TestCase
92
92
  # Can't compare _id values because at insert, an _id was added to @r1 by
93
93
  # the database but we don't know what it is without re-reading the record
94
94
  # (which is what we are doing right now).
95
- # assert_equal doc['_id'], @r1['_id']
95
+ # assert_equal doc['_id'], @r1['_id']
96
96
  assert_equal doc['a'], @r1['a']
97
97
  end
98
98
 
@@ -194,7 +194,7 @@ class DBAPITest < Test::Unit::TestCase
194
194
  @@coll.insert('a' => 2, 'b' => 1)
195
195
  @@coll.insert('a' => 3, 'b' => 2)
196
196
  @@coll.insert('a' => 4, 'b' => 1)
197
-
197
+
198
198
  oh = BSON::OrderedHash.new
199
199
  oh['a'] = -1
200
200
 
@@ -312,7 +312,7 @@ class DBAPITest < Test::Unit::TestCase
312
312
 
313
313
  begin
314
314
  coll = @@db.create_collection('foobar', :capped => true, :size => 1024)
315
- options = coll.options()
315
+ options = coll.options
316
316
  assert_equal 'foobar', options['create']
317
317
  assert_equal true, options['capped']
318
318
  assert_equal 1024, options['size']
@@ -488,7 +488,7 @@ HERE
488
488
  fail "expected exception"
489
489
  rescue => ex
490
490
  assert_equal Mongo::MongoDBError, ex.class
491
- assert_equal "Collection does-not-exist doesn't exist. Currently in strict mode.", ex.to_s
491
+ assert_equal "Collection 'does-not-exist' doesn't exist. (strict=true)", ex.to_s
492
492
  ensure
493
493
  @@db.strict = false
494
494
  @@db.drop_collection('does-not-exist')
@@ -500,8 +500,7 @@ HERE
500
500
  @@db.strict = true
501
501
 
502
502
  begin
503
- @@db.create_collection('foobar')
504
- assert true
503
+ assert @@db.create_collection('foobar')
505
504
  rescue => ex
506
505
  fail "did not expect exception \"#{ex}\""
507
506
  end
@@ -26,17 +26,17 @@ class URITest < Test::Unit::TestCase
26
26
 
27
27
  def test_complex_passwords
28
28
  parser = Mongo::URIParser.new('mongodb://bob:secret.word@a.example.com:27018/test')
29
- assert_equal "bob", parser.auths[0]["username"]
30
- assert_equal "secret.word", parser.auths[0]["password"]
29
+ assert_equal "bob", parser.auths[0][:username]
30
+ assert_equal "secret.word", parser.auths[0][:password]
31
31
 
32
32
  parser = Mongo::URIParser.new('mongodb://bob:s-_3#%R.t@a.example.com:27018/test')
33
- assert_equal "bob", parser.auths[0]["username"]
34
- assert_equal "s-_3#%R.t", parser.auths[0]["password"]
33
+ assert_equal "bob", parser.auths[0][:username]
34
+ assert_equal "s-_3#%R.t", parser.auths[0][:password]
35
35
  end
36
36
 
37
37
  def test_complex_usernames
38
38
  parser = Mongo::URIParser.new('mongodb://b:ob:secret.word@a.example.com:27018/test')
39
- assert_equal "b:ob", parser.auths[0]["username"]
39
+ assert_equal "b:ob", parser.auths[0][:username]
40
40
  end
41
41
 
42
42
  def test_passwords_contain_no_commas
@@ -51,12 +51,12 @@ class URITest < Test::Unit::TestCase
51
51
  assert_equal ['a.example.com', 27018], parser.nodes[0]
52
52
  assert_equal ['b.example.com', 27017], parser.nodes[1]
53
53
  assert_equal 2, parser.auths.length
54
- assert_equal "bob", parser.auths[0]["username"]
55
- assert_equal "secret", parser.auths[0]["password"]
56
- assert_equal "test", parser.auths[0]["db_name"]
57
- assert_equal "bob", parser.auths[1]["username"]
58
- assert_equal "secret", parser.auths[1]["password"]
59
- assert_equal "test", parser.auths[1]["db_name"]
54
+ assert_equal "bob", parser.auths[0][:username]
55
+ assert_equal "secret", parser.auths[0][:password]
56
+ assert_equal "test", parser.auths[0][:db_name]
57
+ assert_equal "bob", parser.auths[1][:username]
58
+ assert_equal "secret", parser.auths[1][:password]
59
+ assert_equal "test", parser.auths[1][:db_name]
60
60
  end
61
61
 
62
62
  def test_opts_with_semincolon_separator
@@ -165,14 +165,14 @@ class URITest < Test::Unit::TestCase
165
165
  assert_equal :nearest, parser.connection_options[:read]
166
166
  end
167
167
 
168
- def test_read_preference_connection_options_prefers_preference_over_slaveok
169
- parser = Mongo::URIParser.new("mongodb://localhost:27018?replicaset=test&readPreference=nearest&slaveok=true")
168
+ def test_read_preference_connection_options_with_no_replica_set
169
+ parser = Mongo::URIParser.new("mongodb://localhost:27018?readPreference=nearest")
170
170
  assert_equal :nearest, parser.connection_options[:read]
171
171
  end
172
172
 
173
- def test_read_preference_when_no_replica_set
174
- parser = Mongo::URIParser.new("mongodb://localhost:27018?readPreference=nearest")
175
- assert_nil parser.connection_options[:read]
173
+ def test_read_preference_connection_options_prefers_preference_over_slaveok
174
+ parser = Mongo::URIParser.new("mongodb://localhost:27018?replicaset=test&readPreference=nearest&slaveok=true")
175
+ assert_equal :nearest, parser.connection_options[:read]
176
176
  end
177
177
 
178
178
  def test_connection_when_sharded_with_no_options