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,10 +5,10 @@ require './test/tools/repl_set_manager'
5
5
  class Test::Unit::TestCase
6
6
  # Ensure replica set is available as an instance variable and that
7
7
  # a new set is spun up for each TestCase class
8
- def ensure_rs
8
+ def ensure_rs(opts={})
9
9
  unless defined?(@@current_class) and @@current_class == self.class
10
10
  @@current_class = self.class
11
- @@rs = ReplSetManager.new
11
+ @@rs = ReplSetManager.new(opts)
12
12
  @@rs.start_set
13
13
  end
14
14
  @rs = @@rs
@@ -0,0 +1,112 @@
1
+ $:.unshift(File.expand_path('../..', File.dirname(__FILE__)))
2
+ require 'test/sharded_cluster/sc_test_helper'
3
+ require 'test/tools/mongo_config'
4
+
5
+ class BasicTest < Test::Unit::TestCase
6
+
7
+ def self.suite
8
+ s = super
9
+ def s.setup
10
+
11
+ end
12
+ def s.teardown
13
+ @@sc.stop
14
+ @@sc.clobber
15
+ end
16
+ def s.run(*args)
17
+ setup
18
+ super
19
+ teardown
20
+ end
21
+ s
22
+ end
23
+
24
+ def setup
25
+ ensure_sc
26
+ end
27
+
28
+ def teardown
29
+
30
+ end
31
+
32
+ # TODO member.primary? ==> true
33
+ def test_connect
34
+ seeds = @sc.mongos_seeds
35
+ @con = Mongo::ShardedConnection.new(seeds)
36
+ assert @con.connected?
37
+ assert_equal(seeds.size, @con.seeds.size)
38
+ probe(seeds.size)
39
+ @con.close
40
+ end
41
+
42
+ def test_hard_refresh
43
+ seeds = @sc.mongos_seeds
44
+ @con = Mongo::ShardedConnection.new(seeds)
45
+ assert @con.connected?
46
+ @con.hard_refresh!
47
+ assert @con.connected?
48
+ @con.close
49
+ end
50
+
51
+ def test_reconnect
52
+ seeds = @sc.mongos_seeds
53
+ @con = Mongo::ShardedConnection.new(seeds)
54
+ assert @con.connected?
55
+ router = @sc.servers(:routers).first
56
+ router.stop
57
+ probe(seeds.size)
58
+ assert @con.connected?
59
+ @con.close
60
+ end
61
+
62
+ def test_all_down
63
+ seeds = @sc.mongos_seeds
64
+ @con = Mongo::ShardedConnection.new(seeds)
65
+ assert @con.connected?
66
+ @sc.servers(:routers).each{|router| router.stop}
67
+ assert_raises Mongo::ConnectionFailure do
68
+ probe(seeds.size)
69
+ end
70
+ assert_false @con.connected?
71
+ @con.close
72
+ end
73
+
74
+ def test_cycle
75
+ seeds = @sc.mongos_seeds
76
+ @con = Mongo::ShardedConnection.new(seeds)
77
+ assert @con.connected?
78
+ routers = @sc.servers(:routers)
79
+ while routers.size > 0 do
80
+ rescue_connection_failure do
81
+ probe(seeds.size)
82
+ end
83
+ probe(seeds.size)
84
+ #p @con.manager.primary
85
+ router = routers.detect{|r| r.port == @con.manager.primary.last}
86
+ routers.delete(router)
87
+ router.stop
88
+ end
89
+ assert_raises Mongo::ConnectionFailure do
90
+ probe(seeds.size)
91
+ end
92
+ assert_false @con.connected?
93
+ routers = @sc.servers(:routers).reverse
94
+ routers.each do |r|
95
+ r.start
96
+ @con.hard_refresh!
97
+ #p @con.manager.primary
98
+ rescue_connection_failure do
99
+ probe(seeds.size)
100
+ end
101
+ probe(seeds.size)
102
+ end
103
+ @con.close
104
+ end
105
+
106
+ private
107
+
108
+ def probe(size)
109
+ assert_equal(size, @con['config']['mongos'].find.to_a.size)
110
+ end
111
+
112
+ end
@@ -0,0 +1,126 @@
1
+ $:.unshift(File.expand_path('../../lib', File.dirname(__FILE__))).unshift(File.expand_path('../..', File.dirname(__FILE__)))
2
+ require 'test-unit'
3
+ require 'test/tools/mongo_config'
4
+
5
+ class MongoConfig < Test::Unit::TestCase
6
+
7
+ def self.suite
8
+ s = super
9
+ def s.setup
10
+
11
+ end
12
+ def s.teardown
13
+
14
+ end
15
+ def s.run(*args)
16
+ setup
17
+ super
18
+ teardown
19
+ end
20
+ s
21
+ end
22
+
23
+ test "config defaults" do
24
+ [ Mongo::Config::DEFAULT_BASE_OPTS,
25
+ Mongo::Config::DEFAULT_REPLICA_SET,
26
+ Mongo::Config::DEFAULT_SHARDED_SIMPLE,
27
+ Mongo::Config::DEFAULT_SHARDED_REPLICA
28
+ ].each do |params|
29
+ config = Mongo::Config.cluster(params)
30
+ assert(config.size > 0)
31
+ end
32
+ end
33
+
34
+ test "get available port" do
35
+ assert_not_nil(Mongo::Config.get_available_port)
36
+ end
37
+
38
+ test "SysProc start" do
39
+ cmd = "true"
40
+ sys_proc = Mongo::Config::SysProc.new(cmd)
41
+ assert_equal(cmd, sys_proc.cmd)
42
+ assert_nil(sys_proc.pid)
43
+ assert_not_nil(sys_proc.start(0))
44
+ assert_not_nil(sys_proc.pid)
45
+ end
46
+
47
+ test "SysProc wait" do
48
+ sys_proc = Mongo::Config::SysProc.new("true")
49
+ assert_not_nil(sys_proc.start(0))
50
+ assert(sys_proc.running?)
51
+ sys_proc.wait
52
+ assert(!sys_proc.running?)
53
+ end
54
+
55
+ test "SysProc kill" do
56
+ sys_proc = Mongo::Config::SysProc.new("true")
57
+ assert_not_nil(sys_proc.start(0))
58
+ sys_proc.kill
59
+ sys_proc.wait
60
+ assert(!sys_proc.running?)
61
+ end
62
+
63
+ test "SysProc stop" do
64
+ sys_proc = Mongo::Config::SysProc.new("true")
65
+ assert_not_nil(sys_proc.start(0))
66
+ sys_proc.stop
67
+ assert(!sys_proc.running?)
68
+ end
69
+
70
+ test "Server" do
71
+ server = Mongo::Config::Server.new('a cmd', 'host', 1234)
72
+ assert_equal('a cmd', server.cmd)
73
+ assert_equal('host', server.host)
74
+ assert_equal(1234, server.port)
75
+ end
76
+
77
+ test "DbServer" do
78
+ config = Mongo::Config::DEFAULT_BASE_OPTS
79
+ server = Mongo::Config::DbServer.new(config)
80
+ assert_equal(config, server.config)
81
+ assert_equal("mongod --logpath data/log --dbpath data", server.cmd)
82
+ assert_equal(config[:host], server.host)
83
+ assert_equal(config[:port], server.port)
84
+ end
85
+
86
+ def cluster_test(opts)
87
+ #debug 1, opts.inspect
88
+ config = Mongo::Config.cluster(opts)
89
+ #debug 1, config.inspect
90
+ manager = Mongo::Config::ClusterManager.new(config)
91
+ assert_equal(config, manager.config)
92
+ manager.start
93
+ manager.servers.each{|s| p s}
94
+ manager.stop
95
+ manager.servers.each{|s| assert_equal(false, s.running?)}
96
+ manager.clobber
97
+ end
98
+
99
+ test "cluster manager base" do
100
+ #cluster_test(Mongo::Config::DEFAULT_BASE_OPTS)
101
+ end
102
+
103
+ test "cluster manager replica set" do
104
+ #cluster_test(Mongo::Config::DEFAULT_REPLICA_SET)
105
+ end
106
+
107
+ test "cluster manager sharded simple" do
108
+ #manager = Mongo::Config::ClusterManager.new(Mongo::Config.cluster(Mongo::Config::DEFAULT_SHARDED_SIMPLE)).start
109
+ opts = Mongo::Config::DEFAULT_SHARDED_SIMPLE
110
+ #debug 1, opts.inspect
111
+ config = Mongo::Config.cluster(opts)
112
+ #debug 1, config.inspect
113
+ manager = Mongo::Config::ClusterManager.new(config)
114
+ assert_equal(config, manager.config)
115
+ manager.start
116
+ #debug 1, manager.ismaster
117
+ #debug 1, manager.mongos_discover
118
+ manager.stop.clobber
119
+ end
120
+
121
+ test "cluster manager sharded replica" do
122
+ #cluster_test(Mongo::Config::DEFAULT_SHARDED_REPLICA)
123
+ end
124
+
125
+ end
126
+
@@ -0,0 +1,39 @@
1
+ $:.unshift(File.expand_path('../../lib', File.dirname(__FILE__)))
2
+ require File.expand_path("../../test_helper", __FILE__)
3
+ require 'test/tools/mongo_config'
4
+
5
+ class Test::Unit::TestCase
6
+ # Ensure sharded cluster is available as an instance variable and that
7
+ # a new set is spun up for each TestCase class
8
+ def ensure_sc
9
+ if defined?(@@current_class) and @@current_class == self.class
10
+ @@sc.start
11
+ else
12
+ @@current_class = self.class
13
+ dbpath = 'sc'
14
+ opts = Mongo::Config::DEFAULT_SHARDED_SIMPLE.merge(:dbpath => dbpath).merge(:routers => 4)
15
+ #debug 1, opts
16
+ config = Mongo::Config.cluster(opts)
17
+ #debug 1, config
18
+ @@sc = Mongo::Config::ClusterManager.new(config)
19
+ @@sc.start
20
+ end
21
+ @sc = @@sc
22
+ end
23
+
24
+ # Generic code for rescuing connection failures and retrying operations.
25
+ # This could be combined with some timeout functionality.
26
+ def rescue_connection_failure(max_retries=30)
27
+ retries = 0
28
+ begin
29
+ yield
30
+ rescue Mongo::ConnectionFailure => ex
31
+ #puts "Rescue attempt #{retries}: from #{ex}"
32
+ retries += 1
33
+ raise ex if retries > max_retries
34
+ sleep(2)
35
+ retry
36
+ end
37
+ end
38
+
39
+ end
@@ -1,5 +1,5 @@
1
1
  $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
- require 'rubygems' if RUBY_VERSION
2
+ require 'rubygems'
3
3
  require 'mongo'
4
4
  gem 'test-unit'
5
5
  require 'test/unit'
@@ -93,7 +93,7 @@ class Test::Unit::TestCase
93
93
  Object.new
94
94
  end
95
95
 
96
- def assert_raise_error(klass, message)
96
+ def assert_raise_error(klass, message=nil)
97
97
  begin
98
98
  yield
99
99
  rescue => e
@@ -101,7 +101,7 @@ class Test::Unit::TestCase
101
101
  flunk "Expected exception class #{klass} but got #{e.class}.\n #{e.backtrace}"
102
102
  end
103
103
 
104
- if !e.message.include?(message)
104
+ if message && !e.message.include?(message)
105
105
  p e.backtrace
106
106
  flunk "#{e.message} does not include #{message}.\n#{e.backtrace}"
107
107
  end
@@ -67,7 +67,7 @@ class TestThreadingLargePool < Test::Unit::TestCase
67
67
  @@coll = @@db.collection('thread-test-collection')
68
68
 
69
69
  1000.times do |i|
70
- @@coll.insert("x" => i)
70
+ @@coll.insert("x" => i, :safe => true)
71
71
  end
72
72
 
73
73
  threads = []
@@ -0,0 +1,307 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'socket'
4
+ require 'fileutils'
5
+
6
+ $debug_level = 2
7
+ STDOUT.sync = true
8
+
9
+ unless defined? Mongo
10
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'mongo')
11
+ end
12
+
13
+ def debug(level, arg)
14
+ if level <= $debug_level
15
+ file_line = caller[0][/(.*:\d+):/, 1]
16
+ calling_method = caller[0][/`([^']*)'/, 1]
17
+ puts "#{file_line}:#{calling_method}:#{arg.class == String ? arg : arg.inspect}"
18
+ end
19
+ end
20
+
21
+ module Mongo
22
+ class Config
23
+ DEFAULT_BASE_OPTS = { :host => 'localhost', :logpath => 'data/log', :dbpath => 'data' }
24
+ DEFAULT_REPLICA_SET = DEFAULT_BASE_OPTS.merge( :replicas => 3 )
25
+ DEFAULT_SHARDED_SIMPLE = DEFAULT_BASE_OPTS.merge( :shards => 2, :configs => 1, :routers => 2 )
26
+ DEFAULT_SHARDED_REPLICA = DEFAULT_SHARDED_SIMPLE.merge( :replicas => 3 )
27
+
28
+ SERVER_PRELUDE_KEYS = [:host, :command]
29
+ SHARDING_OPT_KEYS = [:shards, :configs, :routers]
30
+ REPLICA_OPT_KEYS = [:replicas]
31
+ MONGODS_OPT_KEYS = [:mongods]
32
+ CLUSTER_OPT_KEYS = SHARDING_OPT_KEYS + REPLICA_OPT_KEYS + MONGODS_OPT_KEYS
33
+
34
+ DEFAULT_VERIFIES = 60
35
+ BASE_PORT = 3000
36
+ @@port = BASE_PORT
37
+
38
+ def self.configdb(config)
39
+ config[:configs].collect{|c|"#{c[:host]}:#{c[:port]}"}.join(' ')
40
+ end
41
+
42
+ def self.cluster(opts = DEFAULT_SHARDED_SIMPLE)
43
+ raise "missing required option" if [:host, :dbpath].any?{|k| !opts[k]}
44
+ config = opts.reject{|k,v| CLUSTER_OPT_KEYS.include?(k)}
45
+ keys = SHARDING_OPT_KEYS.any?{|k| opts[k]} ? SHARDING_OPT_KEYS : nil
46
+ keys ||= REPLICA_OPT_KEYS.any?{|k| opts[k]} ? REPLICA_OPT_KEYS : nil
47
+ keys ||= MONGODS_OPT_KEYS
48
+ keys.each do |key|
49
+ config[key] = opts.fetch(key,1).times.collect do |i| #default to 1 of whatever
50
+ server_base = key.to_s.chop
51
+ dbpath = "#{opts[:dbpath]}/#{server_base}#{i}"
52
+ logpath = "#{dbpath}/#{server_base}.log"
53
+ if key == :shards && opts[:replicas]
54
+ self.cluster(opts.reject{|k,v| SHARDING_OPT_KEYS.include?(k)}.merge(:dbpath => dbpath))
55
+ else
56
+ server_params = { :host => opts[:host], :port => self.get_available_port, :logpath => logpath }
57
+ case key
58
+ when :replicas; server_params.merge!( :command => 'mongod', :dbpath => dbpath, :replSet => File.basename(opts[:dbpath]) )
59
+ when :configs; server_params.merge!( :command => 'mongod', :dbpath => dbpath, :configsvr => nil )
60
+ when :routers; server_params.merge!( :command => 'mongos', :configdb => self.configdb(config) ) # mongos, NO dbpath
61
+ else server_params.merge!( :command => 'mongod', :dbpath => dbpath ) # :mongods, :shards
62
+ end
63
+ end
64
+ end
65
+ end
66
+ config
67
+ end
68
+
69
+ def self.port_available?(port)
70
+ ret = false
71
+ socket = Socket.new(Socket::Constants::AF_INET, Socket::Constants::SOCK_STREAM, 0)
72
+ sockaddr = Socket.sockaddr_in(port, '0.0.0.0')
73
+ begin
74
+ socket.bind(sockaddr)
75
+ ret = true
76
+ rescue Exception
77
+ end
78
+ socket.close
79
+ ret
80
+ end
81
+
82
+ def self.get_available_port
83
+ while true
84
+ port = @@port
85
+ @@port += 1
86
+ break if port_available?(port)
87
+ end
88
+ port
89
+ end
90
+
91
+ class SysProc
92
+ attr_reader :pid, :cmd
93
+
94
+ def initialize(cmd = nil)
95
+ @pid = nil
96
+ @cmd = cmd
97
+ end
98
+
99
+ def start(verifies = 0)
100
+ return @pid if running?
101
+ begin
102
+ @pid = fork do
103
+ STDIN.reopen '/dev/null'
104
+ STDOUT.reopen '/dev/null', 'a'
105
+ STDERR.reopen STDOUT
106
+ exec cmd # spawn(@cmd, [:in, :out, :err] => :close) #
107
+ end
108
+ verify(verifies) if verifies > 0
109
+ @pid
110
+ end
111
+ end
112
+
113
+ def stop
114
+ kill
115
+ wait
116
+ end
117
+
118
+ def kill
119
+ begin
120
+ @pid && Process.kill(3, @pid) && true
121
+ rescue Errno::ESRCH
122
+ false
123
+ end
124
+ end
125
+
126
+ def wait
127
+ Process.wait(@pid) if @pid
128
+ @pid = nil
129
+ end
130
+
131
+ def running?
132
+ begin
133
+ @pid && Process.kill(0, @pid) && true
134
+ rescue Errno::ESRCH
135
+ false
136
+ end
137
+ end
138
+
139
+ def verify(verifies = DEFAULT_VERIFIES)
140
+ verifies.times do |i|
141
+ return @pid if running?
142
+ sleep 1
143
+ end
144
+ nil
145
+ end
146
+ end
147
+
148
+ class Server < SysProc
149
+ attr_reader :host, :port
150
+
151
+ def initialize(cmd = nil, host = nil, port = nil)
152
+ super(cmd)
153
+ @host = host
154
+ @port = port
155
+ end
156
+ end
157
+
158
+ class DbServer < Server
159
+ attr_accessor :config
160
+ def initialize(config)
161
+ @config = config
162
+ dbpath = @config[:dbpath]
163
+ [dbpath, File.dirname(@config[:logpath])].compact.each{|dir| FileUtils.mkdir_p(dir) unless File.directory?(dir) }
164
+ command = @config[:command] || 'mongod'
165
+ arguments = @config.reject{|k,v| SERVER_PRELUDE_KEYS.include?(k)}
166
+ cmd = [command, arguments.collect{|k,v| ['--' + k.to_s, v ]}].flatten.join(' ')
167
+ super(cmd, @config[:host], @config[:port])
168
+ end
169
+
170
+ def start(verifies = DEFAULT_VERIFIES)
171
+ super(verifies)
172
+ verify(verifies)
173
+ end
174
+
175
+ def verify(verifies = 10)
176
+ verifies.times do |i|
177
+ #puts "DbServer.verify - port: #{@port} iteration: #{i}"
178
+ begin
179
+ raise Mongo::ConnectionFailure unless running?
180
+ Mongo::Connection.new(@host, @port).close
181
+ #puts "DbServer.verified via connection - port: #{@port} iteration: #{i}"
182
+ return @pid
183
+ rescue Mongo::ConnectionFailure
184
+ sleep 1
185
+ end
186
+ end
187
+ raise Mongo::ConnectionFailure, "DbServer.start verification via connection failed - port: #{@port}"
188
+ end
189
+
190
+ end
191
+
192
+ class ClusterManager
193
+ attr_reader :config
194
+ def initialize(config)
195
+ @config = config
196
+ @servers = {}
197
+ Mongo::Config::CLUSTER_OPT_KEYS.each do |key|
198
+ @servers[key] = @config[key].collect{|conf| DbServer.new(conf)} if @config[key]
199
+ end
200
+ end
201
+
202
+ def servers(key = nil)
203
+ @servers.collect{|k,v| (!key || key == k) ? v : nil}.flatten.compact
204
+ end
205
+
206
+ def command( cmd_servers, db_name, cmd, opts = {} )
207
+ ret = []
208
+ cmd = cmd.class == Array ? cmd : [ cmd ]
209
+ debug 3, "ClusterManager.command cmd:#{cmd.inspect}"
210
+ cmd_servers = cmd_servers.class == Array ? cmd_servers : [cmd_servers]
211
+ cmd_servers.each do |cmd_server|
212
+ debug 3, cmd_server.inspect
213
+ conn = Mongo::Connection.new(cmd_server[:host], cmd_server[:port])
214
+ cmd.each do |c|
215
+ debug 3, "ClusterManager.command c:#{c.inspect}"
216
+ response = conn[db_name].command( c, opts )
217
+ debug 3, "ClusterManager.command response:#{response.inspect}"
218
+ raise Mongo::OperationFailure, "c:#{c.inspect} opts:#{opts.inspect} failed" unless response["ok"] == 1.0 || opts.fetch(:check_response, true) == false
219
+ ret << response
220
+ end
221
+ conn.close
222
+ end
223
+ debug 3, "command ret:#{ret.inspect}"
224
+ ret.size == 1 ? ret.first : ret
225
+ end
226
+
227
+ def repl_set_get_status
228
+ command( @config[:replicas].first, 'admin', { :replSetGetStatus => 1 }, {:check_response => false } )
229
+ end
230
+
231
+ def repl_set_initiate( cfg = nil )
232
+ cfg ||= {
233
+ :_id => @config[:replicas].first[:replSet],
234
+ :members => @config[:replicas].each_with_index.collect{|s, i| { :_id => i, :host => "#{s[:host]}:#{s[:port]}" } },
235
+ }
236
+ command( @config[:replicas].first, 'admin', { :replSetInitiate => cfg } )
237
+ end
238
+
239
+ def repl_set_startup
240
+ response = nil
241
+ 60.times do |i|
242
+ break if (response = repl_set_get_status)['ok'] == 1.0
243
+ sleep 1
244
+ end
245
+ raise Mongo::OperationFailure, "replSet startup failed - status: #{repsonse.inspect}" unless response && response['ok'] == 1.0
246
+ response
247
+ end
248
+
249
+ def mongos_seeds
250
+ @config[:routers].collect{|router| "#{router[:host]}:#{router[:port]}"}
251
+ end
252
+
253
+ def ismaster
254
+ command( @config[:routers], 'admin', { :ismaster => 1 } )
255
+ end
256
+
257
+ def addshards(shards = @config[:shards])
258
+ command( @config[:routers].first, 'admin', Array(shards).collect{|s| { :addshard => "#{s[:host]}:#{s[:port]}" } } )
259
+ end
260
+
261
+ def listshards
262
+ command( @config[:routers].first, 'admin', { :listshards => 1 } )
263
+ end
264
+
265
+ def enablesharding( dbname )
266
+ command( @config[:routers].first, 'admin', { :enablesharding => dbname } )
267
+ end
268
+
269
+ def shardcollection( namespace, key, unique = false )
270
+ command( @config[:routers].first, 'admin', { :shardcollection => namespace, :key => key, :unique => unique } )
271
+ end
272
+
273
+ def mongos_discover # can also do @config[:routers] find but only want mongos for connections
274
+ (@config[:configs]).collect do |cmd_server|
275
+ conn = Mongo::Connection.new(cmd_server[:host], cmd_server[:port])
276
+ result = conn['config']['mongos'].find.to_a
277
+ conn.close
278
+ result
279
+ end
280
+ end
281
+
282
+ def start
283
+ servers.each{|server| server.start}
284
+ # TODO - sharded replica sets - pending
285
+ if @config[:replicas]
286
+ repl_set_initiate if repl_set_get_status['startupStatus'] == 3
287
+ repl_set_startup
288
+ end
289
+ if @config[:routers]
290
+ addshards if listshards['shards'].size == 0
291
+ end
292
+ self
293
+ end
294
+
295
+ def stop
296
+ servers.each{|server| server.stop}
297
+ self
298
+ end
299
+
300
+ def clobber
301
+ system "rm -fr #{@config[:dbpath]}"
302
+ self
303
+ end
304
+ end
305
+
306
+ end
307
+ end