mongo 1.7.1 → 1.8.0
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.
- data/{LICENSE.txt → LICENSE} +0 -0
- data/README.md +124 -111
- data/Rakefile +9 -325
- data/VERSION +1 -0
- data/bin/mongo_console +4 -4
- data/examples/admin.rb +43 -0
- data/examples/capped.rb +22 -0
- data/examples/cursor.rb +48 -0
- data/examples/gridfs.rb +44 -0
- data/examples/index_test.rb +126 -0
- data/examples/info.rb +31 -0
- data/examples/queries.rb +74 -0
- data/examples/replica_set.rb +26 -0
- data/examples/simple.rb +25 -0
- data/examples/strict.rb +35 -0
- data/examples/types.rb +36 -0
- data/{test/load → examples/web}/thin/load.rb +3 -1
- data/{test/load → examples/web}/unicorn/load.rb +5 -3
- data/lib/mongo.rb +8 -10
- data/lib/mongo/collection.rb +134 -114
- data/lib/mongo/cursor.rb +21 -14
- data/lib/mongo/db.rb +30 -28
- data/lib/mongo/exceptions.rb +1 -1
- data/lib/mongo/gridfs/grid.rb +8 -7
- data/lib/mongo/gridfs/grid_ext.rb +1 -1
- data/lib/mongo/gridfs/grid_file_system.rb +6 -5
- data/lib/mongo/gridfs/grid_io.rb +22 -19
- data/lib/mongo/legacy.rb +82 -0
- data/lib/mongo/{connection.rb → mongo_client.rb} +82 -61
- data/lib/mongo/{repl_set_connection.rb → mongo_replica_set_client.rb} +54 -39
- data/lib/mongo/{sharded_connection.rb → mongo_sharded_client.rb} +9 -9
- data/lib/mongo/networking.rb +25 -20
- data/lib/mongo/util/conversions.rb +1 -1
- data/lib/mongo/util/core_ext.rb +1 -1
- data/lib/mongo/util/logging.rb +20 -4
- data/lib/mongo/util/node.rb +16 -16
- data/lib/mongo/util/pool.rb +56 -27
- data/lib/mongo/util/pool_manager.rb +28 -27
- data/lib/mongo/util/server_version.rb +1 -1
- data/lib/mongo/util/sharding_pool_manager.rb +8 -8
- data/lib/mongo/util/ssl_socket.rb +1 -5
- data/lib/mongo/util/support.rb +24 -8
- data/lib/mongo/util/tcp_socket.rb +0 -4
- data/lib/mongo/util/uri_parser.rb +54 -38
- data/lib/mongo/util/write_concern.rb +67 -0
- data/mongo.gemspec +21 -32
- data/test/auxillary/{1.4_features.rb → 1.4_feature_test.rb} +4 -5
- data/test/auxillary/authentication_test.rb +18 -20
- data/test/auxillary/autoreconnect_test.rb +3 -5
- data/test/auxillary/fork_test.rb +5 -7
- data/test/auxillary/repl_set_auth_test.rb +13 -15
- data/test/auxillary/slave_connection_test.rb +8 -7
- data/test/auxillary/threaded_authentication_test.rb +15 -17
- data/test/bson/binary_test.rb +1 -1
- data/test/bson/bson_test.rb +60 -36
- data/test/bson/byte_buffer_test.rb +1 -1
- data/test/bson/hash_with_indifferent_access_test.rb +2 -2
- data/test/bson/json_test.rb +1 -2
- data/test/bson/object_id_test.rb +1 -2
- data/test/bson/ordered_hash_test.rb +1 -1
- data/test/bson/timestamp_test.rb +1 -1
- data/test/{collection_test.rb → functional/collection_test.rb} +57 -57
- data/test/{connection_test.rb → functional/connection_test.rb} +75 -89
- data/test/{conversions_test.rb → functional/conversions_test.rb} +1 -1
- data/test/{cursor_fail_test.rb → functional/cursor_fail_test.rb} +3 -29
- data/test/{cursor_message_test.rb → functional/cursor_message_test.rb} +1 -1
- data/test/{cursor_test.rb → functional/cursor_test.rb} +5 -1
- data/test/{db_api_test.rb → functional/db_api_test.rb} +8 -9
- data/test/{db_connection_test.rb → functional/db_connection_test.rb} +3 -5
- data/test/{db_test.rb → functional/db_test.rb} +13 -13
- data/test/{grid_file_system_test.rb → functional/grid_file_system_test.rb} +2 -2
- data/test/{grid_io_test.rb → functional/grid_io_test.rb} +6 -6
- data/test/{grid_test.rb → functional/grid_test.rb} +4 -10
- data/test/{pool_test.rb → functional/pool_test.rb} +1 -1
- data/test/functional/safe_test.rb +84 -0
- data/test/{support_test.rb → functional/support_test.rb} +1 -1
- data/test/{threading_test.rb → functional/threading_test.rb} +9 -9
- data/test/{timeout_test.rb → functional/timeout_test.rb} +1 -1
- data/test/{uri_test.rb → functional/uri_test.rb} +1 -1
- data/test/functional/write_concern_test.rb +104 -0
- data/test/replica_set/basic_test.rb +139 -0
- data/test/replica_set/client_test.rb +255 -0
- data/test/replica_set/complex_connect_test.rb +62 -0
- data/test/replica_set/connection_test.rb +255 -0
- data/test/{replica_sets → replica_set}/count_test.rb +17 -14
- data/test/replica_set/cursor_test.rb +75 -0
- data/test/{replica_sets → replica_set}/insert_test.rb +19 -16
- data/test/replica_set/query_test.rb +64 -0
- data/test/replica_set/refresh_test.rb +153 -0
- data/test/{replica_sets → replica_set}/replication_ack_test.rb +21 -17
- data/test/sharded_cluster/basic_test.rb +31 -50
- data/test/support/hash_with_indifferent_access.rb +1 -1
- data/test/test_helper.rb +56 -9
- data/test/threading/threading_with_large_pool_test.rb +8 -8
- data/test/tools/mongo_config.rb +270 -58
- data/test/tools/mongo_config_test.rb +146 -0
- data/test/unit/client_test.rb +230 -0
- data/test/unit/collection_test.rb +45 -32
- data/test/unit/connection_test.rb +82 -74
- data/test/unit/cursor_test.rb +14 -6
- data/test/unit/db_test.rb +8 -8
- data/test/unit/grid_test.rb +11 -11
- data/test/unit/node_test.rb +24 -24
- data/test/unit/pool_manager_test.rb +13 -13
- data/test/unit/pool_test.rb +1 -1
- data/test/unit/read_test.rb +21 -26
- data/test/unit/safe_test.rb +52 -33
- data/test/unit/util_test.rb +55 -0
- data/test/unit/write_concern_test.rb +161 -0
- metadata +158 -171
- data/docs/CREDITS.md +0 -123
- data/docs/FAQ.md +0 -116
- data/docs/GRID_FS.md +0 -158
- data/docs/HISTORY.md +0 -392
- data/docs/READ_PREFERENCE.md +0 -99
- data/docs/RELEASES.md +0 -54
- data/docs/REPLICA_SETS.md +0 -113
- data/docs/TAILABLE_CURSORS.md +0 -51
- data/docs/TUTORIAL.md +0 -356
- data/docs/WRITE_CONCERN.md +0 -31
- data/lib/mongo/gridfs/grid_io_fix.rb +0 -38
- data/lib/mongo/version.rb +0 -3
- data/test/bson/test_helper.rb +0 -30
- data/test/replica_sets/basic_test.rb +0 -119
- data/test/replica_sets/complex_connect_test.rb +0 -57
- data/test/replica_sets/complex_read_preference_test.rb +0 -237
- data/test/replica_sets/connect_test.rb +0 -156
- data/test/replica_sets/cursor_test.rb +0 -70
- data/test/replica_sets/pooled_insert_test.rb +0 -57
- data/test/replica_sets/query_test.rb +0 -50
- data/test/replica_sets/read_preference_test.rb +0 -234
- data/test/replica_sets/refresh_test.rb +0 -156
- data/test/replica_sets/refresh_with_threads_test.rb +0 -60
- data/test/replica_sets/rs_test_helper.rb +0 -39
- data/test/safe_test.rb +0 -68
- data/test/sharded_cluster/mongo_config_test.rb +0 -126
- data/test/sharded_cluster/sc_test_helper.rb +0 -39
- data/test/tools/repl_set_manager.rb +0 -418
data/test/test_helper.rb
CHANGED
@@ -1,8 +1,52 @@
|
|
1
|
-
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
1
|
require 'rubygems'
|
3
|
-
require 'mongo'
|
4
|
-
gem 'test-unit'
|
5
2
|
require 'test/unit'
|
3
|
+
require 'tools/mongo_config'
|
4
|
+
|
5
|
+
class Test::Unit::TestCase
|
6
|
+
|
7
|
+
TEST_DATA = File.join(File.dirname(__FILE__), 'data')
|
8
|
+
|
9
|
+
def ensure_cluster(kind=nil)
|
10
|
+
if defined?(@@current_class) and @@current_class == self.class
|
11
|
+
@@cluster.start
|
12
|
+
else
|
13
|
+
@@current_class = self.class
|
14
|
+
|
15
|
+
if kind == :rs
|
16
|
+
opts = Mongo::Config::DEFAULT_REPLICA_SET
|
17
|
+
opts.merge!(:arbiters => 2)
|
18
|
+
else
|
19
|
+
opts = Mongo::Config::DEFAULT_SHARDED_SIMPLE
|
20
|
+
opts.merge!(:routers => 4)
|
21
|
+
end
|
22
|
+
|
23
|
+
dbpath = ENV['DBPATH'] || 'data'
|
24
|
+
opts.merge!(:dbpath => dbpath)
|
25
|
+
|
26
|
+
#debug 1, opts
|
27
|
+
config = Mongo::Config.cluster(opts)
|
28
|
+
#debug 1, config
|
29
|
+
@@cluster = Mongo::Config::ClusterManager.new(config)
|
30
|
+
@@cluster.start
|
31
|
+
end
|
32
|
+
instance_variable_set("@#{kind}", @@cluster)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Generic code for rescuing connection failures and retrying operations.
|
36
|
+
# This could be combined with some timeout functionality.
|
37
|
+
def rescue_connection_failure(max_retries=30)
|
38
|
+
retries = 0
|
39
|
+
begin
|
40
|
+
yield
|
41
|
+
rescue Mongo::ConnectionFailure => ex
|
42
|
+
#puts "Rescue attempt #{retries}: from #{ex}"
|
43
|
+
retries += 1
|
44
|
+
raise ex if retries > max_retries
|
45
|
+
sleep(2)
|
46
|
+
retry
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
6
50
|
|
7
51
|
def silently
|
8
52
|
warn_level = $VERBOSE
|
@@ -16,7 +60,6 @@ def silently
|
|
16
60
|
end
|
17
61
|
|
18
62
|
begin
|
19
|
-
require 'rubygems' if RUBY_VERSION < "1.9.0" && !ENV['C_EXT']
|
20
63
|
silently { require 'shoulda' }
|
21
64
|
silently { require 'mocha' }
|
22
65
|
rescue LoadError
|
@@ -38,7 +81,7 @@ unless defined? MONGO_TEST_DB
|
|
38
81
|
end
|
39
82
|
|
40
83
|
unless defined? TEST_PORT
|
41
|
-
TEST_PORT = ENV['MONGO_RUBY_DRIVER_PORT'] ? ENV['MONGO_RUBY_DRIVER_PORT'].to_i : Mongo::
|
84
|
+
TEST_PORT = ENV['MONGO_RUBY_DRIVER_PORT'] ? ENV['MONGO_RUBY_DRIVER_PORT'].to_i : Mongo::MongoClient::DEFAULT_PORT
|
42
85
|
end
|
43
86
|
|
44
87
|
unless defined? TEST_HOST
|
@@ -49,12 +92,16 @@ class Test::Unit::TestCase
|
|
49
92
|
include Mongo
|
50
93
|
include BSON
|
51
94
|
|
52
|
-
def self.standard_connection(options={})
|
53
|
-
|
95
|
+
def self.standard_connection(options={}, legacy=false)
|
96
|
+
if legacy
|
97
|
+
Connection.new(TEST_HOST, TEST_PORT, options)
|
98
|
+
else
|
99
|
+
MongoClient.new(TEST_HOST, TEST_PORT, options)
|
100
|
+
end
|
54
101
|
end
|
55
102
|
|
56
|
-
def standard_connection(options={})
|
57
|
-
self.class.standard_connection(options)
|
103
|
+
def standard_connection(options={}, legacy=false)
|
104
|
+
self.class.standard_connection(options, legacy)
|
58
105
|
end
|
59
106
|
|
60
107
|
def self.host_port
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'test_helper'
|
2
2
|
|
3
3
|
# Essentialy the same as test_threading.rb but with an expanded pool for
|
4
4
|
# testing multiple connections.
|
@@ -6,7 +6,8 @@ class TestThreadingLargePool < Test::Unit::TestCase
|
|
6
6
|
|
7
7
|
include Mongo
|
8
8
|
|
9
|
-
@@
|
9
|
+
@@client = standard_connection(:pool_size => 50, :pool_timeout => 60)
|
10
|
+
@@db = @@client.db(MONGO_TEST_DB)
|
10
11
|
@@coll = @@db.collection('thread-test-collection')
|
11
12
|
|
12
13
|
def set_up_safe_data
|
@@ -29,10 +30,10 @@ class TestThreadingLargePool < Test::Unit::TestCase
|
|
29
30
|
threads[i] = Thread.new do
|
30
31
|
if i % 2 == 0
|
31
32
|
assert_raise Mongo::OperationFailure do
|
32
|
-
@unique.update({"test" => "insert"}, {"$set" => {"test" => "update"}}
|
33
|
+
@unique.update({"test" => "insert"}, {"$set" => {"test" => "update"}})
|
33
34
|
end
|
34
35
|
else
|
35
|
-
@duplicate.update({"test" => "insert"}, {"$set" => {"test" => "update"}}
|
36
|
+
@duplicate.update({"test" => "insert"}, {"$set" => {"test" => "update"}})
|
36
37
|
end
|
37
38
|
end
|
38
39
|
end
|
@@ -49,10 +50,10 @@ class TestThreadingLargePool < Test::Unit::TestCase
|
|
49
50
|
threads[i] = Thread.new do
|
50
51
|
if i % 2 == 0
|
51
52
|
assert_raise Mongo::OperationFailure do
|
52
|
-
@unique.insert({"test" => "insert"}
|
53
|
+
@unique.insert({"test" => "insert"})
|
53
54
|
end
|
54
55
|
else
|
55
|
-
@duplicate.insert({"test" => "insert"}
|
56
|
+
@duplicate.insert({"test" => "insert"})
|
56
57
|
end
|
57
58
|
end
|
58
59
|
end
|
@@ -67,7 +68,7 @@ class TestThreadingLargePool < Test::Unit::TestCase
|
|
67
68
|
@@coll = @@db.collection('thread-test-collection')
|
68
69
|
|
69
70
|
1000.times do |i|
|
70
|
-
@@coll.insert("x" => i
|
71
|
+
@@coll.insert({ "x" => i })
|
71
72
|
end
|
72
73
|
|
73
74
|
threads = []
|
@@ -86,5 +87,4 @@ class TestThreadingLargePool < Test::Unit::TestCase
|
|
86
87
|
threads[i].join
|
87
88
|
end
|
88
89
|
end
|
89
|
-
|
90
90
|
end
|
data/test/tools/mongo_config.rb
CHANGED
@@ -1,15 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
2
|
require 'socket'
|
4
3
|
require 'fileutils'
|
4
|
+
require 'mongo'
|
5
|
+
require 'sfl'
|
5
6
|
|
6
7
|
$debug_level = 2
|
7
8
|
STDOUT.sync = true
|
8
9
|
|
9
|
-
unless defined? Mongo
|
10
|
-
require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'mongo')
|
11
|
-
end
|
12
|
-
|
13
10
|
def debug(level, arg)
|
14
11
|
if level <= $debug_level
|
15
12
|
file_line = caller[0][/(.*:\d+):/, 1]
|
@@ -18,19 +15,28 @@ def debug(level, arg)
|
|
18
15
|
end
|
19
16
|
end
|
20
17
|
|
18
|
+
#
|
19
|
+
# Design Notes
|
20
|
+
# Configuration and Cluster Management are modularized with the concept that the Cluster Manager
|
21
|
+
# can be supplied with any configuration to run.
|
22
|
+
# A configuration can be edited, modified, copied into a test file, and supplied to a cluster manager
|
23
|
+
# as a parameter.
|
24
|
+
#
|
21
25
|
module Mongo
|
22
26
|
class Config
|
23
|
-
DEFAULT_BASE_OPTS = { :host => 'localhost', :
|
24
|
-
DEFAULT_REPLICA_SET = DEFAULT_BASE_OPTS.merge( :replicas => 3 )
|
27
|
+
DEFAULT_BASE_OPTS = { :host => 'localhost', :dbpath => 'data', :logpath => 'data/log'}
|
28
|
+
DEFAULT_REPLICA_SET = DEFAULT_BASE_OPTS.merge( :replicas => 3, :arbiters => 0 )
|
25
29
|
DEFAULT_SHARDED_SIMPLE = DEFAULT_BASE_OPTS.merge( :shards => 2, :configs => 1, :routers => 2 )
|
26
|
-
DEFAULT_SHARDED_REPLICA = DEFAULT_SHARDED_SIMPLE.merge( :replicas => 3 )
|
30
|
+
DEFAULT_SHARDED_REPLICA = DEFAULT_SHARDED_SIMPLE.merge( :replicas => 3, :arbiters => 0)
|
27
31
|
|
28
|
-
|
32
|
+
IGNORE_KEYS = [:host, :command, :_id]
|
29
33
|
SHARDING_OPT_KEYS = [:shards, :configs, :routers]
|
30
|
-
REPLICA_OPT_KEYS = [:replicas]
|
34
|
+
REPLICA_OPT_KEYS = [:replicas, :arbiters]
|
31
35
|
MONGODS_OPT_KEYS = [:mongods]
|
32
36
|
CLUSTER_OPT_KEYS = SHARDING_OPT_KEYS + REPLICA_OPT_KEYS + MONGODS_OPT_KEYS
|
33
37
|
|
38
|
+
FLAGS = [:noprealloc, :smallfiles, :logappend, :configsvr, :shardsvr, :quiet]
|
39
|
+
|
34
40
|
DEFAULT_VERIFIES = 60
|
35
41
|
BASE_PORT = 3000
|
36
42
|
@@port = BASE_PORT
|
@@ -41,31 +47,99 @@ module Mongo
|
|
41
47
|
|
42
48
|
def self.cluster(opts = DEFAULT_SHARDED_SIMPLE)
|
43
49
|
raise "missing required option" if [:host, :dbpath].any?{|k| !opts[k]}
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
self.cluster(opts.reject{|k,v| SHARDING_OPT_KEYS.include?(k)}.merge(:dbpath => dbpath))
|
50
|
+
|
51
|
+
config = opts.reject {|k,v| CLUSTER_OPT_KEYS.include?(k)}
|
52
|
+
kinds = CLUSTER_OPT_KEYS.select{|key| opts.has_key?(key)} # order is significant
|
53
|
+
|
54
|
+
replica_count = 0
|
55
|
+
|
56
|
+
kinds.each do |kind|
|
57
|
+
config[kind] = opts.fetch(kind,1).times.collect do |i| #default to 1 of whatever
|
58
|
+
if kind == :shards && opts[:replicas]
|
59
|
+
self.cluster(opts.reject{|k,v| SHARDING_OPT_KEYS.include?(k)}.merge(:dbpath => path))
|
55
60
|
else
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
when :
|
60
|
-
|
61
|
-
|
61
|
+
node = case kind
|
62
|
+
when :replicas
|
63
|
+
make_replica(opts, replica_count)
|
64
|
+
when :arbiters
|
65
|
+
make_replica(opts, replica_count)
|
66
|
+
when :configs
|
67
|
+
make_config(opts)
|
68
|
+
when :routers
|
69
|
+
make_router(config, opts)
|
70
|
+
else
|
71
|
+
make_mongod(kind, opts)
|
62
72
|
end
|
73
|
+
|
74
|
+
replica_count += 1 if [:replicas, :arbiters].member?(kind)
|
75
|
+
node
|
63
76
|
end
|
64
77
|
end
|
65
78
|
end
|
66
79
|
config
|
67
80
|
end
|
68
81
|
|
82
|
+
def self.make_mongo(kind, opts)
|
83
|
+
dbpath = opts[:dbpath]
|
84
|
+
port = self.get_available_port
|
85
|
+
path = "#{dbpath}/#{kind}-#{port}"
|
86
|
+
logpath = "#{path}/#{kind}.log"
|
87
|
+
|
88
|
+
{
|
89
|
+
:host => opts[:host],
|
90
|
+
:port => port,
|
91
|
+
:logpath => logpath,
|
92
|
+
:logappend => true
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.make_mongod(kind, opts)
|
97
|
+
params = make_mongo('mongods', opts)
|
98
|
+
|
99
|
+
mongod = ENV['MONGOD'] || 'mongod'
|
100
|
+
path = File.dirname(params[:logpath])
|
101
|
+
|
102
|
+
noprealloc = opts[:noprealloc] || true
|
103
|
+
smallfiles = opts[:smallfiles] || true
|
104
|
+
quiet = opts[:quiet] || true
|
105
|
+
|
106
|
+
params.merge(
|
107
|
+
:command => mongod,
|
108
|
+
:dbpath => path,
|
109
|
+
:smallfiles => smallfiles,
|
110
|
+
:noprealloc => noprealloc,
|
111
|
+
:quiet => quiet
|
112
|
+
)
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.make_replica(opts, count)
|
116
|
+
params = make_mongod('replicas', opts)
|
117
|
+
|
118
|
+
replSet = opts[:replSet] || 'ruby-driver-test'
|
119
|
+
oplog_size = opts[:oplog_size] || 10
|
120
|
+
|
121
|
+
params.merge(
|
122
|
+
:_id => count,
|
123
|
+
:replSet => replSet,
|
124
|
+
:oplogSize => oplog_size
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.make_config(opts)
|
129
|
+
params = make_mongod('configs', opts)
|
130
|
+
params.merge(:configsvr => nil)
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.make_router(config, opts)
|
134
|
+
params = make_mongo('routers', opts)
|
135
|
+
mongos = ENV['MONGOS'] || 'mongos'
|
136
|
+
|
137
|
+
params.merge(
|
138
|
+
:command => mongos,
|
139
|
+
:configdb => self.configdb(config)
|
140
|
+
)
|
141
|
+
end
|
142
|
+
|
69
143
|
def self.port_available?(port)
|
70
144
|
ret = false
|
71
145
|
socket = Socket.new(Socket::Constants::AF_INET, Socket::Constants::SOCK_STREAM, 0)
|
@@ -96,15 +170,23 @@ module Mongo
|
|
96
170
|
@cmd = cmd
|
97
171
|
end
|
98
172
|
|
173
|
+
def clear_zombie
|
174
|
+
if @pid
|
175
|
+
begin
|
176
|
+
pid = Process.waitpid(@pid, Process::WNOHANG)
|
177
|
+
rescue Errno::ECHILD
|
178
|
+
# JVM might have already reaped the exit status
|
179
|
+
end
|
180
|
+
@pid = nil if pid && pid > 0
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
99
184
|
def start(verifies = 0)
|
185
|
+
clear_zombie
|
100
186
|
return @pid if running?
|
101
187
|
begin
|
102
|
-
@pid =
|
103
|
-
|
104
|
-
STDOUT.reopen '/dev/null', 'a'
|
105
|
-
STDERR.reopen STDOUT
|
106
|
-
exec cmd # spawn(@cmd, [:in, :out, :err] => :close) #
|
107
|
-
end
|
188
|
+
@pid = Process.spawn(*@cmd) # redirection not supported in jruby
|
189
|
+
sleep 1
|
108
190
|
verify(verifies) if verifies > 0
|
109
191
|
@pid
|
110
192
|
end
|
@@ -115,16 +197,20 @@ module Mongo
|
|
115
197
|
wait
|
116
198
|
end
|
117
199
|
|
118
|
-
def kill
|
200
|
+
def kill(signal_no = 2)
|
119
201
|
begin
|
120
|
-
@pid && Process.kill(
|
202
|
+
@pid && Process.kill(signal_no, @pid) && true
|
121
203
|
rescue Errno::ESRCH
|
122
204
|
false
|
123
205
|
end
|
124
206
|
end
|
125
207
|
|
126
208
|
def wait
|
127
|
-
|
209
|
+
begin
|
210
|
+
Process.waitpid(@pid) if @pid
|
211
|
+
rescue Errno::ECHILD
|
212
|
+
# JVM might have already reaped the exit status
|
213
|
+
end
|
128
214
|
@pid = nil
|
129
215
|
end
|
130
216
|
|
@@ -153,17 +239,34 @@ module Mongo
|
|
153
239
|
@host = host
|
154
240
|
@port = port
|
155
241
|
end
|
242
|
+
|
243
|
+
def host_port
|
244
|
+
[@host, @port].join(':')
|
245
|
+
end
|
246
|
+
|
247
|
+
def host_port_a # for old format
|
248
|
+
[@host, @port]
|
249
|
+
end
|
156
250
|
end
|
157
251
|
|
158
252
|
class DbServer < Server
|
159
253
|
attr_accessor :config
|
254
|
+
|
160
255
|
def initialize(config)
|
161
256
|
@config = config
|
162
257
|
dbpath = @config[:dbpath]
|
163
258
|
[dbpath, File.dirname(@config[:logpath])].compact.each{|dir| FileUtils.mkdir_p(dir) unless File.directory?(dir) }
|
164
259
|
command = @config[:command] || 'mongod'
|
165
|
-
|
166
|
-
|
260
|
+
params = @config.reject{|k,v| IGNORE_KEYS.include?(k)}
|
261
|
+
arguments = params.sort{|a, b| a[0].to_s <=> b[0].to_s}.collect do |arg, value| # sort block is needed for 1.8.7 which lacks Symbol#<=>
|
262
|
+
argument = '--' + arg.to_s
|
263
|
+
if FLAGS.member?(arg)
|
264
|
+
[argument]
|
265
|
+
else
|
266
|
+
[argument, value.to_s]
|
267
|
+
end
|
268
|
+
end
|
269
|
+
cmd = [command, arguments].flatten.compact
|
167
270
|
super(cmd, @config[:host], @config[:port])
|
168
271
|
end
|
169
272
|
|
@@ -172,19 +275,20 @@ module Mongo
|
|
172
275
|
verify(verifies)
|
173
276
|
end
|
174
277
|
|
175
|
-
def verify(verifies =
|
278
|
+
def verify(verifies = 600)
|
176
279
|
verifies.times do |i|
|
177
|
-
#puts "DbServer.verify - port
|
280
|
+
#puts "DbServer.verify via connection probe - port:#{@port.inspect} iteration:#{i} @pid:#{@pid.inspect} kill:#{Process.kill(0, @pid).inspect} running?:#{running?.inspect} cmd:#{cmd.inspect}"
|
178
281
|
begin
|
179
282
|
raise Mongo::ConnectionFailure unless running?
|
180
|
-
Mongo::
|
283
|
+
Mongo::MongoClient.new(@host, @port).close
|
181
284
|
#puts "DbServer.verified via connection - port: #{@port} iteration: #{i}"
|
182
285
|
return @pid
|
183
286
|
rescue Mongo::ConnectionFailure
|
184
287
|
sleep 1
|
185
288
|
end
|
186
289
|
end
|
187
|
-
|
290
|
+
system "ps -fp #{@pid}; cat #{@config[:logpath]}"
|
291
|
+
raise Mongo::ConnectionFailure, "DbServer.start verify via connection probe failed - port:#{@port.inspect} @pid:#{@pid.inspect} kill:#{Process.kill(0, @pid).inspect} running?:#{running?.inspect} cmd:#{cmd.inspect}"
|
188
292
|
end
|
189
293
|
|
190
294
|
end
|
@@ -210,15 +314,16 @@ module Mongo
|
|
210
314
|
cmd_servers = cmd_servers.class == Array ? cmd_servers : [cmd_servers]
|
211
315
|
cmd_servers.each do |cmd_server|
|
212
316
|
debug 3, cmd_server.inspect
|
213
|
-
|
317
|
+
cmd_server = cmd_server.config if cmd_server.is_a?(DbServer)
|
318
|
+
client = Mongo::MongoClient.new(cmd_server[:host], cmd_server[:port])
|
214
319
|
cmd.each do |c|
|
215
320
|
debug 3, "ClusterManager.command c:#{c.inspect}"
|
216
|
-
response =
|
321
|
+
response = client[db_name].command( c, opts )
|
217
322
|
debug 3, "ClusterManager.command response:#{response.inspect}"
|
218
323
|
raise Mongo::OperationFailure, "c:#{c.inspect} opts:#{opts.inspect} failed" unless response["ok"] == 1.0 || opts.fetch(:check_response, true) == false
|
219
324
|
ret << response
|
220
325
|
end
|
221
|
-
|
326
|
+
client.close
|
222
327
|
end
|
223
328
|
debug 3, "command ret:#{ret.inspect}"
|
224
329
|
ret.size == 1 ? ret.first : ret
|
@@ -228,26 +333,130 @@ module Mongo
|
|
228
333
|
command( @config[:replicas].first, 'admin', { :replSetGetStatus => 1 }, {:check_response => false } )
|
229
334
|
end
|
230
335
|
|
231
|
-
def
|
232
|
-
|
233
|
-
|
234
|
-
|
336
|
+
def repl_set_get_config
|
337
|
+
host, port = primary_name.split(":")
|
338
|
+
client = Mongo::MongoClient.new(host, port)
|
339
|
+
client['local']['system.replset'].find_one
|
340
|
+
end
|
341
|
+
|
342
|
+
def repl_set_config
|
343
|
+
members = []
|
344
|
+
@config[:replicas].each{|s| members << { :_id => s[:_id], :host => "#{s[:host]}:#{s[:port]}" } }
|
345
|
+
@config[:arbiters].each{|s| members << { :_id => s[:_id], :host => "#{s[:host]}:#{s[:port]}", :arbiterOnly => true } }
|
346
|
+
{
|
347
|
+
:_id => @config[:replicas].first[:replSet],
|
348
|
+
:members => members
|
235
349
|
}
|
236
|
-
|
350
|
+
end
|
351
|
+
|
352
|
+
def repl_set_initiate( cfg = nil )
|
353
|
+
command( @config[:replicas].first, 'admin', { :replSetInitiate => cfg || repl_set_config } )
|
237
354
|
end
|
238
355
|
|
239
356
|
def repl_set_startup
|
240
357
|
response = nil
|
241
358
|
60.times do |i|
|
242
|
-
|
359
|
+
response = repl_set_get_status
|
360
|
+
members = response['members']
|
361
|
+
if response['ok'] == 1.0 && members.collect{|m| m['state']}.all?{|state| [1,2,7].index(state)}
|
362
|
+
return response if members.any?{|m| m['state'] == 1}
|
363
|
+
end
|
243
364
|
sleep 1
|
244
365
|
end
|
245
|
-
raise Mongo::OperationFailure, "replSet startup failed - status: #{
|
246
|
-
|
366
|
+
raise Mongo::OperationFailure, "replSet startup failed - status: #{response.inspect}"
|
367
|
+
end
|
368
|
+
|
369
|
+
def repl_set_seeds
|
370
|
+
@config[:replicas].collect{|node| "#{node[:host]}:#{node[:port]}"}
|
371
|
+
end
|
372
|
+
|
373
|
+
def repl_set_seeds_old
|
374
|
+
@config[:replicas].collect{|node| [node[:host], node[:port]]}
|
375
|
+
end
|
376
|
+
|
377
|
+
def repl_set_name
|
378
|
+
@config[:replicas].first[:replSet]
|
379
|
+
end
|
380
|
+
|
381
|
+
def member_names_by_state(state)
|
382
|
+
states = Array(state)
|
383
|
+
status = repl_set_get_status
|
384
|
+
status['members'].find_all{|member| states.index(member['state']) }.collect{|member| member['name']}
|
385
|
+
end
|
386
|
+
|
387
|
+
def primary_name
|
388
|
+
member_names_by_state(1).first
|
389
|
+
end
|
390
|
+
|
391
|
+
def secondary_names
|
392
|
+
member_names_by_state(2)
|
393
|
+
end
|
394
|
+
|
395
|
+
def replica_names
|
396
|
+
member_names_by_state([1,2])
|
397
|
+
end
|
398
|
+
|
399
|
+
def arbiter_names
|
400
|
+
member_names_by_state(7)
|
401
|
+
end
|
402
|
+
|
403
|
+
def members_by_name(names)
|
404
|
+
names.collect do |name|
|
405
|
+
servers.find{|server| server.host_port == name}
|
406
|
+
end.compact
|
407
|
+
end
|
408
|
+
|
409
|
+
def primary
|
410
|
+
members_by_name([primary_name]).first
|
411
|
+
end
|
412
|
+
|
413
|
+
def secondaries
|
414
|
+
members_by_name(secondary_names)
|
415
|
+
end
|
416
|
+
|
417
|
+
def replicas
|
418
|
+
members_by_name(replica_names)
|
419
|
+
end
|
420
|
+
|
421
|
+
def arbiters
|
422
|
+
members_by_name(arbiter_names)
|
423
|
+
end
|
424
|
+
|
425
|
+
def config_names_by_kind(kind)
|
426
|
+
@config[kind].collect{|conf| "#{conf[:host]}:#{conf[:port]}"}
|
427
|
+
end
|
428
|
+
|
429
|
+
def shards
|
430
|
+
members_by_name(config_names_by_kind(:shards))
|
431
|
+
end
|
432
|
+
|
433
|
+
def repl_set_reconfig(new_config)
|
434
|
+
new_config['version'] = repl_set_get_config['version'] + 1
|
435
|
+
command( primary, 'admin', { :replSetReconfig => new_config } )
|
436
|
+
repl_set_startup
|
437
|
+
end
|
438
|
+
|
439
|
+
def repl_set_remove_node(state = [1,2])
|
440
|
+
names = member_names_by_state(state)
|
441
|
+
name = names[rand(names.length)]
|
442
|
+
|
443
|
+
@config[:replicas].delete_if{|node| "#{node[:host]}:#{node[:port]}" == name}
|
444
|
+
repl_set_reconfig(repl_set_config)
|
445
|
+
end
|
446
|
+
|
447
|
+
def repl_set_add_node
|
448
|
+
end
|
449
|
+
|
450
|
+
def configs
|
451
|
+
members_by_name(config_names_by_kind(:configs))
|
452
|
+
end
|
453
|
+
|
454
|
+
def routers
|
455
|
+
members_by_name(config_names_by_kind(:routers))
|
247
456
|
end
|
248
457
|
|
249
458
|
def mongos_seeds
|
250
|
-
|
459
|
+
config_names_by_kind(:routers)
|
251
460
|
end
|
252
461
|
|
253
462
|
def ismaster
|
@@ -272,14 +481,16 @@ module Mongo
|
|
272
481
|
|
273
482
|
def mongos_discover # can also do @config[:routers] find but only want mongos for connections
|
274
483
|
(@config[:configs]).collect do |cmd_server|
|
275
|
-
|
276
|
-
result =
|
277
|
-
|
484
|
+
client = Mongo::MongoClient.new(cmd_server[:host], cmd_server[:port])
|
485
|
+
result = client['config']['mongos'].find.to_a
|
486
|
+
client.close
|
278
487
|
result
|
279
488
|
end
|
280
489
|
end
|
281
490
|
|
282
491
|
def start
|
492
|
+
# Must start configs before mongos -- hash order not guaranteed on 1.8.X
|
493
|
+
servers(:configs).each{|server| server.start}
|
283
494
|
servers.each{|server| server.start}
|
284
495
|
# TODO - sharded replica sets - pending
|
285
496
|
if @config[:replicas]
|
@@ -291,6 +502,7 @@ module Mongo
|
|
291
502
|
end
|
292
503
|
self
|
293
504
|
end
|
505
|
+
alias :restart :start
|
294
506
|
|
295
507
|
def stop
|
296
508
|
servers.each{|server| server.stop}
|
@@ -298,7 +510,7 @@ module Mongo
|
|
298
510
|
end
|
299
511
|
|
300
512
|
def clobber
|
301
|
-
system "rm -fr #{@config[:dbpath]}"
|
513
|
+
system "rm -fr #{@config[:dbpath]}/*"
|
302
514
|
self
|
303
515
|
end
|
304
516
|
end
|