mongo 1.8.3 → 1.8.4.rc0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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