mongo 1.6.4 → 1.7.0.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.
Files changed (50) hide show
  1. data/README.md +13 -13
  2. data/Rakefile +7 -10
  3. data/docs/{GridFS.md → GRID_FS.md} +0 -0
  4. data/docs/HISTORY.md +16 -0
  5. data/docs/READ_PREFERENCE.md +70 -10
  6. data/docs/TUTORIAL.md +2 -2
  7. data/lib/mongo.rb +2 -0
  8. data/lib/mongo/collection.rb +62 -11
  9. data/lib/mongo/connection.rb +31 -41
  10. data/lib/mongo/cursor.rb +42 -86
  11. data/lib/mongo/db.rb +10 -8
  12. data/lib/mongo/networking.rb +30 -65
  13. data/lib/mongo/repl_set_connection.rb +91 -170
  14. data/lib/mongo/sharded_connection.rb +221 -0
  15. data/lib/mongo/util/node.rb +29 -36
  16. data/lib/mongo/util/pool.rb +10 -3
  17. data/lib/mongo/util/pool_manager.rb +77 -90
  18. data/lib/mongo/util/sharding_pool_manager.rb +143 -0
  19. data/lib/mongo/util/support.rb +22 -2
  20. data/lib/mongo/util/tcp_socket.rb +10 -15
  21. data/lib/mongo/util/uri_parser.rb +17 -10
  22. data/lib/mongo/version.rb +1 -1
  23. data/test/collection_test.rb +133 -1
  24. data/test/connection_test.rb +50 -4
  25. data/test/db_api_test.rb +3 -3
  26. data/test/db_test.rb +6 -1
  27. data/test/replica_sets/basic_test.rb +3 -6
  28. data/test/replica_sets/complex_connect_test.rb +14 -2
  29. data/test/replica_sets/complex_read_preference_test.rb +237 -0
  30. data/test/replica_sets/connect_test.rb +47 -67
  31. data/test/replica_sets/count_test.rb +1 -1
  32. data/test/replica_sets/cursor_test.rb +70 -0
  33. data/test/replica_sets/read_preference_test.rb +171 -118
  34. data/test/replica_sets/refresh_test.rb +3 -3
  35. data/test/replica_sets/refresh_with_threads_test.rb +2 -2
  36. data/test/replica_sets/rs_test_helper.rb +2 -2
  37. data/test/sharded_cluster/basic_test.rb +112 -0
  38. data/test/sharded_cluster/mongo_config_test.rb +126 -0
  39. data/test/sharded_cluster/sc_test_helper.rb +39 -0
  40. data/test/test_helper.rb +3 -3
  41. data/test/threading/threading_with_large_pool_test.rb +1 -1
  42. data/test/tools/mongo_config.rb +307 -0
  43. data/test/tools/repl_set_manager.rb +12 -12
  44. data/test/unit/collection_test.rb +1 -1
  45. data/test/unit/cursor_test.rb +11 -6
  46. data/test/unit/db_test.rb +4 -0
  47. data/test/unit/grid_test.rb +2 -0
  48. data/test/unit/read_test.rb +39 -8
  49. data/test/uri_test.rb +4 -8
  50. metadata +144 -127
@@ -5,7 +5,7 @@ class ReplicaSetCountTest < Test::Unit::TestCase
5
5
 
6
6
  def setup
7
7
  ensure_rs
8
- @conn = ReplSetConnection.new(build_seeds(3), :read => :secondary)
8
+ @conn = ReplSetConnection.new(build_seeds(3), :read => :primary_preferred)
9
9
  assert @conn.primary_pool
10
10
  @primary = Connection.new(@conn.primary_pool.host, @conn.primary_pool.port)
11
11
  @db = @conn.db(MONGO_TEST_DB)
@@ -0,0 +1,70 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require './test/replica_sets/rs_test_helper'
3
+
4
+ class ReplicaSetCursorTest < Test::Unit::TestCase
5
+ def setup
6
+ ensure_rs
7
+ end
8
+
9
+ def test_cursors_get_closed
10
+ setup_connection
11
+ assert_cursor_count
12
+ end
13
+
14
+ def test_cursors_get_closed_secondary
15
+ setup_connection(:secondary)
16
+ assert_cursor_count
17
+ end
18
+
19
+ private
20
+
21
+ def setup_connection(read=:primary)
22
+ # Setup ReplicaSet Connection
23
+ @replconn = Mongo::ReplSetConnection.new(
24
+ build_seeds(3),
25
+ :read => read
26
+ )
27
+
28
+ @db = @replconn.db(MONGO_TEST_DB)
29
+ @db.drop_collection("cursor_tests")
30
+ @coll = @db.collection("cursor_tests")
31
+
32
+ @coll.insert({:a => 1}, :safe => true, :w => 3)
33
+ @coll.insert({:b => 2}, :safe => true, :w => 3)
34
+ @coll.insert({:c => 3}, :safe => true, :w => 3)
35
+
36
+ # Pin reader
37
+ @coll.find_one
38
+
39
+ # Setup Direct Connections
40
+ @primary = Mongo::Connection.new(*@replconn.manager.primary)
41
+ @read = Mongo::Connection.new(*@replconn.manager.read)
42
+ end
43
+
44
+ def cursor_count(connection)
45
+ connection['cursor_tests'].command({:cursorInfo => 1})['totalOpen']
46
+ end
47
+
48
+ def query_count(connection)
49
+ connection['admin'].command({:serverStatus => 1})['opcounters']['query']
50
+ end
51
+
52
+ def assert_cursor_count
53
+ before_primary = cursor_count(@primary)
54
+ before_read = cursor_count(@read)
55
+ before_query = query_count(@read)
56
+
57
+ @coll.find.limit(2).to_a
58
+ sleep(1)
59
+
60
+ after_primary = cursor_count(@primary)
61
+ after_read = cursor_count(@read)
62
+ after_query = query_count(@read)
63
+
64
+ assert_equal before_primary, after_primary
65
+ assert_equal before_read, after_read
66
+ assert_equal 1, after_query - before_query
67
+ end
68
+
69
+ end
70
+
@@ -5,80 +5,169 @@ require 'logger'
5
5
  class ReadPreferenceTest < Test::Unit::TestCase
6
6
 
7
7
  def setup
8
- ensure_rs
9
- log = Logger.new("test.log")
10
- seeds = build_seeds(2)
11
- args = {
12
- :read => :secondary,
13
- :pool_size => 50,
14
- :refresh_mode => false,
15
- :refresh_interval => 5,
16
- :logger => log
17
- }
18
- @conn = ReplSetConnection.new(seeds, args)
19
- @db = @conn.db(MONGO_TEST_DB)
20
- @db.drop_collection("test-sets")
21
- end
8
+ ensure_rs(:secondary_count => 1, :arbiter_count => 1)
22
9
 
23
- def teardown
24
- @rs.restart_killed_nodes
10
+ # Insert data
11
+ conn = Connection.new(@rs.host, @rs.primary[1])
12
+ db = conn.db(MONGO_TEST_DB)
13
+ coll = db.collection("test-sets")
14
+ coll.save({:a => 20}, :safe => {:w => 2})
25
15
  end
26
16
 
27
17
  def test_read_primary
18
+ conn = make_connection
19
+ rescue_connection_failure do
20
+ assert conn.read_primary?
21
+ assert conn.primary?
22
+ end
23
+
24
+ conn = make_connection(:primary_preferred)
28
25
  rescue_connection_failure do
29
- assert !@conn.read_primary?
30
- assert !@conn.primary?
26
+ assert conn.read_primary?
27
+ assert conn.primary?
28
+ end
29
+
30
+ conn = make_connection(:secondary)
31
+ rescue_connection_failure do
32
+ assert !conn.read_primary?
33
+ assert !conn.primary?
34
+ end
35
+
36
+ conn = make_connection(:secondary_preferred)
37
+ rescue_connection_failure do
38
+ assert !conn.read_primary?
39
+ assert !conn.primary?
31
40
  end
32
41
  end
33
42
 
34
- def test_con
35
- assert @conn.primary_pool, "No primary pool!"
36
- assert @conn.read_pool, "No read pool!"
37
- assert @conn.primary_pool.port != @conn.read_pool.port,
38
- "Primary port and read port at the same!"
43
+ def test_connection_pools
44
+ conn = make_connection
45
+ assert conn.primary_pool, "No primary pool!"
46
+ assert conn.read_pool, "No read pool!"
47
+ assert conn.primary_pool.port == conn.read_pool.port,
48
+ "Primary port and read port are not the same!"
49
+
50
+ conn = make_connection(:primary_preferred)
51
+ assert conn.primary_pool, "No primary pool!"
52
+ assert conn.read_pool, "No read pool!"
53
+ assert conn.primary_pool.port == conn.read_pool.port,
54
+ "Primary port and read port are not the same!"
55
+
56
+ conn = make_connection(:secondary)
57
+ assert conn.primary_pool, "No primary pool!"
58
+ assert conn.read_pool, "No read pool!"
59
+ assert conn.primary_pool.port != conn.read_pool.port,
60
+ "Primary port and read port are the same!"
61
+
62
+ conn = make_connection(:secondary_preferred)
63
+ assert conn.primary_pool, "No primary pool!"
64
+ assert conn.read_pool, "No read pool!"
65
+ assert conn.primary_pool.port != conn.read_pool.port,
66
+ "Primary port and read port are the same!"
39
67
  end
40
68
 
41
- def test_read_secondary_only
42
- @rs.add_arbiter
43
- @rs.remove_secondary_node
44
-
45
- @conn = ReplSetConnection.new(build_seeds(3), :read => :secondary_only)
69
+ def test_read_routing
70
+ prepare_routing_test
46
71
 
47
- @db = @conn.db(MONGO_TEST_DB)
48
- @coll = @db.collection("test-sets")
49
-
50
- @coll.save({:a => 20}, :safe => {:w => 2})
72
+ # Test that reads are going to the right members
73
+ assert_query_route(@primary, @primary_direct)
74
+ assert_query_route(@primary_preferred, @primary_direct)
75
+ assert_query_route(@secondary, @secondary_direct)
76
+ assert_query_route(@secondary_preferred, @secondary_direct)
77
+ end
51
78
 
52
- # Test that reads are going to secondary on ReplSetConnection
53
- @secondary = Connection.new(@rs.host, @conn.secondary_pool.port, :slave_ok => true)
54
- queries_before = @secondary['admin'].command({:serverStatus => 1})['opcounters']['query']
55
- @coll.find_one
56
- queries_after = @secondary['admin'].command({:serverStatus => 1})['opcounters']['query']
57
- assert_equal 1, queries_after - queries_before
79
+ def test_read_routing_with_primary_down
80
+ prepare_routing_test
81
+
82
+ # Test that reads are going to the right members
83
+ assert_query_route(@primary, @primary_direct)
84
+ assert_query_route(@primary_preferred, @primary_direct)
85
+ assert_query_route(@secondary, @secondary_direct)
86
+ assert_query_route(@secondary_preferred, @secondary_direct)
87
+
88
+ # Kill the primary so only a single secondary exists
89
+ @rs.kill_primary
58
90
 
91
+ # Test that reads are going to the right members
92
+ assert_raise_error ConnectionFailure do
93
+ @primary[MONGO_TEST_DB]['test-sets'].find_one
94
+ end
95
+ assert_query_route(@primary_preferred, @secondary_direct)
96
+ assert_query_route(@secondary, @secondary_direct)
97
+ assert_query_route(@secondary_preferred, @secondary_direct)
98
+
99
+ # Restore set
100
+ @rs.restart_killed_nodes
101
+ sleep(1)
102
+ @repl_cons.each { |con| con.refresh }
103
+ sleep(1)
104
+ @primary_direct = Connection.new(
105
+ @rs.host,
106
+ @primary.read_pool.port
107
+ )
108
+
109
+ # Test that reads are going to the right members
110
+ assert_query_route(@primary, @primary_direct)
111
+ assert_query_route(@primary_preferred, @primary_direct)
112
+ assert_query_route(@secondary, @secondary_direct)
113
+ assert_query_route(@secondary_preferred, @secondary_direct)
114
+ end
115
+
116
+ def test_read_routing_with_secondary_down
117
+ prepare_routing_test
118
+
119
+ # Test that reads are going to the right members
120
+ assert_query_route(@primary, @primary_direct)
121
+ assert_query_route(@primary_preferred, @primary_direct)
122
+ assert_query_route(@secondary, @secondary_direct)
123
+ assert_query_route(@secondary_preferred, @secondary_direct)
124
+
125
+ # Kill the secondary so that only primary exists
59
126
  @rs.kill_secondary
60
- @conn.refresh
61
-
62
- # Test that reads are only allowed from secondaries
63
- assert_raise ConnectionFailure.new("Could not checkout a socket.") do
64
- @coll.find_one
127
+
128
+ # Test that reads are going to the right members
129
+ assert_query_route(@primary, @primary_direct)
130
+ assert_query_route(@primary_preferred, @primary_direct)
131
+ assert_raise_error ConnectionFailure do
132
+ @secondary[MONGO_TEST_DB]['test-sets'].find_one
65
133
  end
66
-
67
- @rs = ReplSetManager.new
68
- @rs.start_set
134
+ assert_query_route(@secondary_preferred, @primary_direct)
135
+
136
+ # Restore set
137
+ @rs.restart_killed_nodes
138
+ sleep(1)
139
+ @repl_cons.each { |con| con.refresh }
140
+ sleep(1)
141
+ @secondary_direct = Connection.new(
142
+ @rs.host,
143
+ @secondary.read_pool.port,
144
+ :slave_ok => true
145
+ )
146
+
147
+ # Test that reads are going to the right members
148
+ assert_query_route(@primary, @primary_direct)
149
+ assert_query_route(@primary_preferred, @primary_direct)
150
+ assert_query_route(@secondary, @secondary_direct)
151
+ assert_query_route(@secondary_preferred, @secondary_direct)
69
152
  end
70
153
 
71
- def test_query_secondaries
72
- @secondary = Connection.new(@rs.host, @conn.read_pool.port, :slave_ok => true)
73
- @coll = @db.collection("test-sets", :safe => {:w => 3, :wtimeout => 20000})
154
+ def test_write_conecern
155
+ @conn = make_connection(:secondary_preferred)
156
+ @db = @conn[MONGO_TEST_DB]
157
+ @coll = @db.collection("test-sets", :safe => {
158
+ :w => 2, :wtimeout => 20000
159
+ })
74
160
  @coll.save({:a => 20})
75
161
  @coll.save({:a => 30})
76
162
  @coll.save({:a => 40})
163
+
164
+ # pin the read pool
165
+ @coll.find_one
166
+ @secondary = Connection.new(@rs.host, @conn.read_pool.port, :slave_ok => true)
167
+
77
168
  results = []
78
- queries_before = @secondary['admin'].command({:serverStatus => 1})['opcounters']['query']
79
169
  @coll.find.each {|r| results << r["a"]}
80
- queries_after = @secondary['admin'].command({:serverStatus => 1})['opcounters']['query']
81
- assert_equal 1, queries_after - queries_before
170
+
82
171
  assert results.include?(20)
83
172
  assert results.include?(30)
84
173
  assert results.include?(40)
@@ -87,57 +176,17 @@ class ReadPreferenceTest < Test::Unit::TestCase
87
176
 
88
177
  results = []
89
178
  rescue_connection_failure do
90
- #puts "@coll.find().each"
91
179
  @coll.find.each {|r| results << r}
92
180
  [20, 30, 40].each do |a|
93
181
  assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"
94
182
  end
95
183
  end
96
- end
97
-
98
- def test_kill_primary
99
- @coll = @db.collection("test-sets", :safe => {:w => 3, :wtimeout => 10000})
100
- @coll.save({:a => 20})
101
- @coll.save({:a => 30})
102
- assert_equal 2, @coll.find.to_a.length
103
-
104
- # Should still be able to read immediately after killing master node
105
- @rs.kill_primary
106
- assert_equal 2, @coll.find.to_a.length
107
- rescue_connection_failure do
108
- @coll.save({:a => 50}, :safe => {:w => 2, :wtimeout => 10000})
109
- end
110
184
  @rs.restart_killed_nodes
111
- sleep(1)
112
- @coll.save({:a => 50}, :safe => {:w => 2, :wtimeout => 10000})
113
- assert_equal 4, @coll.find.to_a.length
114
- end
115
-
116
- def test_kill_secondary
117
- @coll = @db.collection("test-sets", {:safe => {:w => 3, :wtimeout => 20000}})
118
- @coll.save({:a => 20})
119
- @coll.save({:a => 30})
120
- assert_equal 2, @coll.find.to_a.length
121
-
122
- read_node = @rs.get_node_from_port(@conn.read_pool.port)
123
- @rs.kill(read_node)
124
-
125
- # Should fail immediately on next read
126
- old_read_pool_port = @conn.read_pool.port
127
- assert_raise ConnectionFailure do
128
- @coll.find.to_a.length
129
- end
130
-
131
- # Should eventually reconnect and be able to read
132
- rescue_connection_failure do
133
- length = @coll.find.to_a.length
134
- assert_equal 2, length
135
- end
136
- new_read_pool_port = @conn.read_pool.port
137
- assert old_read_pool_port != new_read_pool_port
138
185
  end
139
186
 
140
187
  def test_write_lots_of_data
188
+ @conn = make_connection(:secondary_preferred)
189
+ @db = @conn[MONGO_TEST_DB]
141
190
  @coll = @db.collection("test-sets", {:safe => {:w => 2}})
142
191
 
143
192
  6000.times do |n|
@@ -149,33 +198,37 @@ class ReadPreferenceTest < Test::Unit::TestCase
149
198
  cursor.close
150
199
  end
151
200
 
152
- # TODO: enable this once we enable reads from tags.
153
- # def test_query_tagged
154
- # col = @db['mongo-test']
201
+ private
155
202
 
156
- # col.insert({:a => 1}, :safe => {:w => 3})
157
- # col.find_one({}, :read => {:db => "main"})
158
- # col.find_one({}, :read => {:dc => "ny"})
159
- # col.find_one({}, :read => {:dc => "sf"})
203
+ def prepare_routing_test
204
+ # Setup replica set connections
205
+ @primary = make_connection(:primary)
206
+ @primary_preferred = make_connection(:primary_preferred)
207
+ @secondary = make_connection(:secondary)
208
+ @secondary_preferred = make_connection(:secondary_preferred)
209
+ @repl_cons = [@primary, @primary_preferred, @secondary, @secondary_preferred]
160
210
 
161
- # assert_raise Mongo::NodeWithTagsNotFound do
162
- # col.find_one({}, :read => {:foo => "bar"})
163
- # end
164
-
165
- # threads = []
166
- # 100.times do
167
- # threads << Thread.new do
168
- # col.find_one({}, :read => {:dc => "sf"})
169
- # end
170
- # end
171
-
172
- # threads.each {|t| t.join }
211
+ # Setup direct connections
212
+ @primary_direct = Connection.new(@rs.host, @primary.read_pool.port)
213
+ @secondary_direct = Connection.new(@rs.host, @secondary.read_pool.port, :slave_ok => true)
214
+ end
173
215
 
174
- # col.remove
175
- # end
216
+ def make_connection(mode = :primary, opts = {})
217
+ opts.merge!({:read => mode})
218
+ ReplSetConnection.new(build_seeds(3), opts)
219
+ end
176
220
 
177
- #def teardown
178
- # @rs.restart_killed_nodes
179
- #end
221
+ def query_count(connection)
222
+ connection['admin'].command({:serverStatus => 1})['opcounters']['query']
223
+ end
180
224
 
225
+ def assert_query_route(test_connection, expected_target)
226
+ #puts "#{test_connection.read_pool.port} #{expected_target.read_pool.port}"
227
+ queries_before = query_count(expected_target)
228
+ assert_nothing_raised do
229
+ test_connection['MONGO_TEST_DB']['test-sets'].find_one
230
+ end
231
+ queries_after = query_count(expected_target)
232
+ assert_equal 1, queries_after - queries_before
233
+ end
181
234
  end
@@ -69,12 +69,12 @@ class ReplicaSetRefreshTest < Test::Unit::TestCase
69
69
 
70
70
  rescue_connection_failure do
71
71
  @conn = ReplSetConnection.new(build_seeds(3),
72
- :refresh_interval => 2, :refresh_mode => :sync)
72
+ :refresh_interval => 2, :refresh_mode => :sync, :read => :secondary_preferred)
73
73
  end
74
74
 
75
75
  assert_equal [], @conn.secondaries
76
76
  assert @conn.connected?
77
- assert_equal @conn.read_pool, @conn.primary_pool
77
+ assert_equal @conn.manager.read, @conn.manager.primary
78
78
  old_refresh_version = @conn.refresh_version
79
79
 
80
80
  @rs.restart_killed_nodes
@@ -86,7 +86,7 @@ class ReplicaSetRefreshTest < Test::Unit::TestCase
86
86
  "Refresh version hasn't changed."
87
87
  assert @conn.secondaries.length > 0,
88
88
  "No secondaries have been added."
89
- assert @conn.read_pool != @conn.primary_pool,
89
+ assert @conn.manager.read != @conn.manager.primary,
90
90
  "Read pool and primary pool are identical."
91
91
  end
92
92
 
@@ -15,13 +15,13 @@ class ReplicaSetRefreshWithThreadsTest < Test::Unit::TestCase
15
15
 
16
16
  def test_read_write_load_with_added_nodes
17
17
  # MongoDB < 2.0 will disconnect clients on rs.reconfig()
18
- return true if @rs.version.first < 2
18
+ return true if @rs.version < "2"
19
19
 
20
20
  seeds = build_seeds(3)
21
21
  args = {
22
22
  :refresh_interval => 5,
23
23
  :refresh_mode => :sync,
24
- :read => :secondary
24
+ :read => :secondary_preferred
25
25
  }
26
26
  @conn = ReplSetConnection.new(seeds, args)
27
27
  @duplicate = @conn[MONGO_TEST_DB]['duplicate']