mongo 1.6.4 → 1.7.0.rc0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +13 -13
- data/Rakefile +7 -10
- data/docs/{GridFS.md → GRID_FS.md} +0 -0
- data/docs/HISTORY.md +16 -0
- data/docs/READ_PREFERENCE.md +70 -10
- data/docs/TUTORIAL.md +2 -2
- data/lib/mongo.rb +2 -0
- data/lib/mongo/collection.rb +62 -11
- data/lib/mongo/connection.rb +31 -41
- data/lib/mongo/cursor.rb +42 -86
- data/lib/mongo/db.rb +10 -8
- data/lib/mongo/networking.rb +30 -65
- data/lib/mongo/repl_set_connection.rb +91 -170
- data/lib/mongo/sharded_connection.rb +221 -0
- data/lib/mongo/util/node.rb +29 -36
- data/lib/mongo/util/pool.rb +10 -3
- data/lib/mongo/util/pool_manager.rb +77 -90
- data/lib/mongo/util/sharding_pool_manager.rb +143 -0
- data/lib/mongo/util/support.rb +22 -2
- data/lib/mongo/util/tcp_socket.rb +10 -15
- data/lib/mongo/util/uri_parser.rb +17 -10
- data/lib/mongo/version.rb +1 -1
- data/test/collection_test.rb +133 -1
- data/test/connection_test.rb +50 -4
- data/test/db_api_test.rb +3 -3
- data/test/db_test.rb +6 -1
- data/test/replica_sets/basic_test.rb +3 -6
- data/test/replica_sets/complex_connect_test.rb +14 -2
- data/test/replica_sets/complex_read_preference_test.rb +237 -0
- data/test/replica_sets/connect_test.rb +47 -67
- data/test/replica_sets/count_test.rb +1 -1
- data/test/replica_sets/cursor_test.rb +70 -0
- data/test/replica_sets/read_preference_test.rb +171 -118
- data/test/replica_sets/refresh_test.rb +3 -3
- data/test/replica_sets/refresh_with_threads_test.rb +2 -2
- data/test/replica_sets/rs_test_helper.rb +2 -2
- data/test/sharded_cluster/basic_test.rb +112 -0
- data/test/sharded_cluster/mongo_config_test.rb +126 -0
- data/test/sharded_cluster/sc_test_helper.rb +39 -0
- data/test/test_helper.rb +3 -3
- data/test/threading/threading_with_large_pool_test.rb +1 -1
- data/test/tools/mongo_config.rb +307 -0
- data/test/tools/repl_set_manager.rb +12 -12
- data/test/unit/collection_test.rb +1 -1
- data/test/unit/cursor_test.rb +11 -6
- data/test/unit/db_test.rb +4 -0
- data/test/unit/grid_test.rb +2 -0
- data/test/unit/read_test.rb +39 -8
- data/test/uri_test.rb +4 -8
- 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 => :
|
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
|
-
|
24
|
-
@rs.
|
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
|
30
|
-
assert
|
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
|
35
|
-
|
36
|
-
assert
|
37
|
-
assert
|
38
|
-
|
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
|
42
|
-
|
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
|
-
|
48
|
-
@
|
49
|
-
|
50
|
-
@
|
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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
-
|
68
|
-
|
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
|
72
|
-
@
|
73
|
-
@
|
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
|
-
|
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
|
-
|
153
|
-
# def test_query_tagged
|
154
|
-
# col = @db['mongo-test']
|
201
|
+
private
|
155
202
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
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
|
-
|
162
|
-
|
163
|
-
|
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
|
-
|
175
|
-
|
216
|
+
def make_connection(mode = :primary, opts = {})
|
217
|
+
opts.merge!({:read => mode})
|
218
|
+
ReplSetConnection.new(build_seeds(3), opts)
|
219
|
+
end
|
176
220
|
|
177
|
-
|
178
|
-
|
179
|
-
|
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.
|
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.
|
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
|
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 => :
|
24
|
+
:read => :secondary_preferred
|
25
25
|
}
|
26
26
|
@conn = ReplSetConnection.new(seeds, args)
|
27
27
|
@duplicate = @conn[MONGO_TEST_DB]['duplicate']
|