mongo 1.3.1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +9 -6
- data/Rakefile +3 -4
- data/docs/HISTORY.md +20 -2
- data/docs/READ_PREFERENCE.md +39 -0
- data/docs/RELEASES.md +1 -1
- data/docs/REPLICA_SETS.md +23 -2
- data/docs/TAILABLE_CURSORS.md +51 -0
- data/docs/TUTORIAL.md +4 -4
- data/docs/WRITE_CONCERN.md +5 -2
- data/lib/mongo.rb +7 -22
- data/lib/mongo/collection.rb +96 -29
- data/lib/mongo/connection.rb +107 -62
- data/lib/mongo/cursor.rb +136 -57
- data/lib/mongo/db.rb +26 -5
- data/lib/mongo/exceptions.rb +17 -1
- data/lib/mongo/gridfs/grid.rb +1 -1
- data/lib/mongo/repl_set_connection.rb +273 -156
- data/lib/mongo/util/logging.rb +42 -0
- data/lib/mongo/util/node.rb +183 -0
- data/lib/mongo/util/pool.rb +76 -13
- data/lib/mongo/util/pool_manager.rb +208 -0
- data/lib/mongo/util/ssl_socket.rb +38 -0
- data/lib/mongo/util/support.rb +9 -1
- data/lib/mongo/util/timeout.rb +42 -0
- data/lib/mongo/version.rb +3 -0
- data/mongo.gemspec +2 -2
- data/test/bson/binary_test.rb +1 -1
- data/test/bson/bson_string_test.rb +30 -0
- data/test/bson/bson_test.rb +6 -3
- data/test/bson/byte_buffer_test.rb +1 -1
- data/test/bson/hash_with_indifferent_access_test.rb +1 -1
- data/test/bson/json_test.rb +1 -1
- data/test/bson/object_id_test.rb +2 -18
- data/test/bson/ordered_hash_test.rb +38 -3
- data/test/bson/test_helper.rb +46 -0
- data/test/bson/timestamp_test.rb +32 -10
- data/test/collection_test.rb +89 -3
- data/test/connection_test.rb +35 -20
- data/test/cursor_test.rb +63 -2
- data/test/db_test.rb +12 -2
- data/test/pool_test.rb +21 -0
- data/test/replica_sets/connect_test.rb +26 -13
- data/test/replica_sets/connection_string_test.rb +1 -4
- data/test/replica_sets/count_test.rb +1 -0
- data/test/replica_sets/insert_test.rb +1 -0
- data/test/replica_sets/pooled_insert_test.rb +4 -1
- data/test/replica_sets/query_secondaries.rb +2 -1
- data/test/replica_sets/query_test.rb +2 -1
- data/test/replica_sets/read_preference_test.rb +43 -0
- data/test/replica_sets/refresh_test.rb +123 -0
- data/test/replica_sets/replication_ack_test.rb +9 -4
- data/test/replica_sets/rs_test_helper.rb +2 -2
- data/test/timeout_test.rb +14 -0
- data/test/tools/repl_set_manager.rb +134 -23
- data/test/unit/collection_test.rb +6 -8
- data/test/unit/connection_test.rb +4 -4
- data/test/unit/cursor_test.rb +23 -5
- data/test/unit/db_test.rb +2 -0
- data/test/unit/grid_test.rb +2 -0
- data/test/unit/node_test.rb +73 -0
- data/test/unit/pool_manager_test.rb +47 -0
- data/test/unit/read_test.rb +101 -0
- metadata +214 -138
- data/lib/mongo/test.rb +0 -20
- data/test/async/collection_test.rb +0 -224
- data/test/async/connection_test.rb +0 -24
- data/test/async/cursor_test.rb +0 -162
- data/test/async/worker_pool_test.rb +0 -99
- data/test/load/resque/load.rb +0 -21
- data/test/load/resque/processor.rb +0 -26
- data/test/load/unicorn/unicorn.rb +0 -29
- data/test/tools/load.rb +0 -58
- data/test/tools/sharding_manager.rb +0 -202
- data/test/tools/test.rb +0 -4
- data/test/unit/repl_set_connection_test.rb +0 -59
data/test/load/resque/load.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '..', '..', '..', 'lib', 'mongo')
|
2
|
-
require 'logger'
|
3
|
-
require 'rubygems'
|
4
|
-
require 'resque'
|
5
|
-
require 'sinatra'
|
6
|
-
require File.join(File.dirname(__FILE__), 'processor')
|
7
|
-
|
8
|
-
$con = Mongo::Connection.new
|
9
|
-
$db = $con['foo']
|
10
|
-
|
11
|
-
|
12
|
-
configure do
|
13
|
-
LOGGER = Logger.new("sinatra.log")
|
14
|
-
enable :logging, :dump_errors
|
15
|
-
set :raise_errors, true
|
16
|
-
end
|
17
|
-
|
18
|
-
get '/' do
|
19
|
-
Processor.perform(1)
|
20
|
-
true
|
21
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
require 'logger'
|
2
|
-
|
3
|
-
class Processor
|
4
|
-
@queue = :processor
|
5
|
-
|
6
|
-
def self.connection
|
7
|
-
@log ||= Logger.new(STDOUT)
|
8
|
-
@con ||= Mongo::Connection.new("localhost", 27017)
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.perform(n)
|
12
|
-
begin
|
13
|
-
100.times do |n|
|
14
|
-
self.connection['resque']['docs'].insert({:n => n, :data => "0" * 1000}, :safe => true)
|
15
|
-
end
|
16
|
-
|
17
|
-
5.times do |n|
|
18
|
-
num = rand(100)
|
19
|
-
self.connection['resque']['docs'].find({:n => {"$gt" => num}}).limit(1).to_a
|
20
|
-
end
|
21
|
-
rescue => e
|
22
|
-
@log.warn(e.inspect)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
# set path to app that will be used to configure unicorn,
|
2
|
-
# # note the trailing slash in this example
|
3
|
-
@dir = "/home/kyle/work/10gen/ruby-driver/test/load/"
|
4
|
-
|
5
|
-
worker_processes 10
|
6
|
-
working_directory @dir
|
7
|
-
|
8
|
-
preload_app true
|
9
|
-
|
10
|
-
timeout 30
|
11
|
-
|
12
|
-
# Specify path to socket unicorn listens to,
|
13
|
-
# we will use this in our nginx.conf later
|
14
|
-
listen "#{@dir}tmp/sockets/unicorn.sock", :backlog => 64
|
15
|
-
|
16
|
-
# Set process id path
|
17
|
-
pid "#{@dir}tmp/pids/unicorn.pid"
|
18
|
-
|
19
|
-
# # Set log file paths
|
20
|
-
stderr_path "#{@dir}log/unicorn.stderr.log"
|
21
|
-
stdout_path "#{@dir}log/unicorn.stdout.log"
|
22
|
-
|
23
|
-
# NOTE: You need this when using forking web servers!
|
24
|
-
after_fork do |server, worker|
|
25
|
-
$con.close if $con
|
26
|
-
$con = Mongo::Connection.new
|
27
|
-
$db = $con['foo']
|
28
|
-
STDERR << "FORKED #{server} #{worker}"
|
29
|
-
end
|
data/test/tools/load.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'mongo'
|
3
|
-
require 'sharding_manager'
|
4
|
-
|
5
|
-
class MongoLoader
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
@mongo = Mongo::Connection.new("localhost", 50000)
|
9
|
-
@data = BSON::Binary.new(File.open("tools.gz").read)
|
10
|
-
@count = 0
|
11
|
-
@manager = ShardingManager.new(:config_count => 3)
|
12
|
-
@manager.start_cluster
|
13
|
-
end
|
14
|
-
|
15
|
-
def kill
|
16
|
-
@manager.kill_random
|
17
|
-
end
|
18
|
-
|
19
|
-
def restart
|
20
|
-
@manager.restart_killed_nodes
|
21
|
-
end
|
22
|
-
|
23
|
-
def run
|
24
|
-
Thread.new do
|
25
|
-
("a".."z").each do |p|
|
26
|
-
seed(p)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def seed(prefix)
|
32
|
-
@queue = []
|
33
|
-
1000.times do |n|
|
34
|
-
id = BSON::OrderedHash.new
|
35
|
-
id[:p] = prefix
|
36
|
-
id[:c] = n
|
37
|
-
@queue << {:tid => id, :data => @data}
|
38
|
-
end
|
39
|
-
|
40
|
-
while @queue.length > 0 do
|
41
|
-
begin
|
42
|
-
doc = @queue.pop
|
43
|
-
@mongo['app']['photos'].insert(doc, :safe => {:w => 3})
|
44
|
-
@count += 1
|
45
|
-
p @count
|
46
|
-
rescue StandardError => e
|
47
|
-
p e
|
48
|
-
p @count
|
49
|
-
@queue.push(doc)
|
50
|
-
@count -= 1
|
51
|
-
sleep(10)
|
52
|
-
retry
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
@m = MongoLoader.new
|
@@ -1,202 +0,0 @@
|
|
1
|
-
require 'repl_set_manager'
|
2
|
-
require 'thread'
|
3
|
-
|
4
|
-
class ShardingManager
|
5
|
-
|
6
|
-
attr_accessor :shards
|
7
|
-
|
8
|
-
def initialize(opts={})
|
9
|
-
@durable = opts.fetch(:durable, true)
|
10
|
-
@host = "localhost"
|
11
|
-
|
12
|
-
@mongos_port = opts[:mongos_port] || 50000
|
13
|
-
@config_port = opts[:config_port] || 40000
|
14
|
-
@shard_start_port = opts[:start_shard_port] || 30000
|
15
|
-
@path = File.join(File.expand_path(File.dirname(__FILE__)), "data")
|
16
|
-
system("rm -rf #{@path}")
|
17
|
-
|
18
|
-
@shard_count = 2
|
19
|
-
@mongos_count = 1
|
20
|
-
@config_count = opts.fetch(:config_count, 1)
|
21
|
-
if ![1, 3].include?(@config_count)
|
22
|
-
raise ArgumentError, "Must specify 1 or 3 config servers."
|
23
|
-
end
|
24
|
-
|
25
|
-
@config_servers = {}
|
26
|
-
@mongos_servers = {}
|
27
|
-
@shards = []
|
28
|
-
@ports = []
|
29
|
-
end
|
30
|
-
|
31
|
-
def kill_random
|
32
|
-
shard_to_kill = rand(@shard_count)
|
33
|
-
@shards[shard_to_kill].kill_primary
|
34
|
-
end
|
35
|
-
|
36
|
-
def restart_killed
|
37
|
-
threads = []
|
38
|
-
@shards.each do |k, shard|
|
39
|
-
threads << Thread.new do
|
40
|
-
shard.restart_killed_nodes
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def start_cluster
|
46
|
-
start_sharding_components
|
47
|
-
start_mongos_servers
|
48
|
-
configure_cluster
|
49
|
-
end
|
50
|
-
|
51
|
-
def configure_cluster
|
52
|
-
add_shards
|
53
|
-
enable_sharding
|
54
|
-
shard_collection
|
55
|
-
end
|
56
|
-
|
57
|
-
def enable_sharding
|
58
|
-
mongos['admin'].command({:enablesharding => "app"})
|
59
|
-
end
|
60
|
-
|
61
|
-
def shard_collection
|
62
|
-
cmd = BSON::OrderedHash.new
|
63
|
-
cmd[:shardcollection] = "app.photos"
|
64
|
-
cmd[:key] = {:tid => 1}
|
65
|
-
p mongos['admin'].command(cmd)
|
66
|
-
end
|
67
|
-
|
68
|
-
def add_shards
|
69
|
-
@shards.each do |shard|
|
70
|
-
cmd = {:addshard => shard.shard_string}
|
71
|
-
p cmd
|
72
|
-
p mongos['admin'].command(cmd)
|
73
|
-
end
|
74
|
-
p mongos['admin'].command({:listshards => 1})
|
75
|
-
end
|
76
|
-
|
77
|
-
def mongos
|
78
|
-
attempt do
|
79
|
-
@mongos ||= Mongo::Connection.new(@host, @mongos_servers[0]['port'])
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
private
|
84
|
-
|
85
|
-
def start_sharding_components
|
86
|
-
system("killall mongos")
|
87
|
-
|
88
|
-
threads = []
|
89
|
-
threads << Thread.new do
|
90
|
-
start_shards
|
91
|
-
end
|
92
|
-
|
93
|
-
threads << Thread.new do
|
94
|
-
start_config_servers
|
95
|
-
end
|
96
|
-
threads.each {|t| t.join}
|
97
|
-
puts "\nShards and config servers up!"
|
98
|
-
end
|
99
|
-
|
100
|
-
def start_shards
|
101
|
-
threads = []
|
102
|
-
@shard_count.times do |n|
|
103
|
-
threads << Thread.new do
|
104
|
-
port = @shard_start_port + n * 100
|
105
|
-
shard = ReplSetManager.new(:arbiter_count => 0, :secondary_count => 2,
|
106
|
-
:passive_count => 0, :start_port => port, :durable => @durable,
|
107
|
-
:name => "shard-#{n}")
|
108
|
-
shard.start_set
|
109
|
-
shard.ensure_up
|
110
|
-
@shards << shard
|
111
|
-
end
|
112
|
-
end
|
113
|
-
threads.each {|t| t.join}
|
114
|
-
end
|
115
|
-
|
116
|
-
def start_config_servers
|
117
|
-
@config_count.times do |n|
|
118
|
-
@config_servers[n] ||= {}
|
119
|
-
port = @config_port + n
|
120
|
-
@ports << port
|
121
|
-
@config_servers[n]['port'] = port
|
122
|
-
@config_servers[n]['db_path'] = get_path("config-#{port}")
|
123
|
-
@config_servers[n]['log_path'] = get_path("log-config-#{port}")
|
124
|
-
system("rm -rf #{@config_servers[n]['db_path']}")
|
125
|
-
system("mkdir -p #{@config_servers[n]['db_path']}")
|
126
|
-
|
127
|
-
@config_servers[n]['start'] = start_config_cmd(n)
|
128
|
-
|
129
|
-
start(@config_servers, n)
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def start_mongos_servers
|
134
|
-
@mongos_count.times do |n|
|
135
|
-
@mongos_servers[n] ||= {}
|
136
|
-
port = @mongos_port + n
|
137
|
-
@ports << port
|
138
|
-
@mongos_servers[n]['port'] = port
|
139
|
-
@mongos_servers[n]['db_path'] = get_path("mongos-#{port}")
|
140
|
-
@mongos_servers[n]['pidfile_path'] = File.join(@mongos_servers[n]['db_path'], "mongod.lock")
|
141
|
-
@mongos_servers[n]['log_path'] = get_path("log-mongos-#{port}")
|
142
|
-
system("rm -rf #{@mongos_servers[n]['db_path']}")
|
143
|
-
system("mkdir -p #{@mongos_servers[n]['db_path']}")
|
144
|
-
|
145
|
-
@mongos_servers[n]['start'] = start_mongos_cmd(n)
|
146
|
-
|
147
|
-
start(@mongos_servers, n)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
def start_config_cmd(n)
|
152
|
-
cmd = "mongod --configsvr --logpath '#{@config_servers[n]['log_path']}' " +
|
153
|
-
" --dbpath #{@config_servers[n]['db_path']} --port #{@config_servers[n]['port']} --fork"
|
154
|
-
cmd += " --dur" if @durable
|
155
|
-
cmd
|
156
|
-
end
|
157
|
-
|
158
|
-
def start_mongos_cmd(n)
|
159
|
-
"mongos --configdb #{config_db_string} --logpath '#{@mongos_servers[n]['log_path']}' " +
|
160
|
-
"--pidfilepath #{@mongos_servers[n]['pidfile_path']} --port #{@mongos_servers[n]['port']} --fork"
|
161
|
-
end
|
162
|
-
|
163
|
-
def config_db_string
|
164
|
-
@config_servers.map do |k, v|
|
165
|
-
"#{@host}:#{v['port']}"
|
166
|
-
end.join(',')
|
167
|
-
end
|
168
|
-
|
169
|
-
def start(set, node)
|
170
|
-
system(set[node]['start'])
|
171
|
-
set[node]['up'] = true
|
172
|
-
sleep(0.5)
|
173
|
-
set[node]['pid'] = File.open(File.join(set[node]['db_path'], 'mongod.lock')).read.strip
|
174
|
-
end
|
175
|
-
alias :restart :start
|
176
|
-
|
177
|
-
private
|
178
|
-
|
179
|
-
def cleanup_config
|
180
|
-
end
|
181
|
-
|
182
|
-
def get_path(name)
|
183
|
-
File.join(@path, name)
|
184
|
-
end
|
185
|
-
|
186
|
-
# TODO: put this into a shared module
|
187
|
-
def attempt
|
188
|
-
raise "No block given!" unless block_given?
|
189
|
-
count = 0
|
190
|
-
|
191
|
-
while count < 50 do
|
192
|
-
begin
|
193
|
-
return yield
|
194
|
-
rescue Mongo::OperationFailure, Mongo::ConnectionFailure
|
195
|
-
sleep(1)
|
196
|
-
count += 1
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
raise exception
|
201
|
-
end
|
202
|
-
end
|
data/test/tools/test.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
require './test/test_helper'
|
2
|
-
include Mongo
|
3
|
-
|
4
|
-
class ReplSetConnectionTest < Test::Unit::TestCase
|
5
|
-
context "Initialization: " do
|
6
|
-
context "connecting to a replica set" do
|
7
|
-
setup do
|
8
|
-
TCPSocket.stubs(:new).returns(new_mock_socket('localhost', 27017))
|
9
|
-
@conn = ReplSetConnection.new(['localhost', 27017], :connect => false, :read_secondary => true)
|
10
|
-
|
11
|
-
admin_db = new_mock_db
|
12
|
-
@hosts = ['localhost:27018', 'localhost:27019', 'localhost:27020']
|
13
|
-
|
14
|
-
admin_db.stubs(:command).returns({'ok' => 1, 'ismaster' => 1, 'hosts' => @hosts}).
|
15
|
-
then.returns({'ok' => 1, 'ismaster' => 0, 'hosts' => @hosts, 'secondary' => 1}).
|
16
|
-
then.returns({'ok' => 1, 'ismaster' => 0, 'hosts' => @hosts, 'secondary' => 1}).
|
17
|
-
then.returns({'ok' => 1, 'ismaster' => 0, 'arbiterOnly' => 1})
|
18
|
-
|
19
|
-
@conn.stubs(:[]).with('admin').returns(admin_db)
|
20
|
-
@conn.connect
|
21
|
-
end
|
22
|
-
|
23
|
-
should "store the hosts returned from the ismaster command" do
|
24
|
-
assert_equal 'localhost', @conn.primary_pool.host
|
25
|
-
assert_equal 27017, @conn.primary_pool.port
|
26
|
-
|
27
|
-
assert_equal 'localhost', @conn.secondary_pools[0].host
|
28
|
-
assert_equal 27018, @conn.secondary_pools[0].port
|
29
|
-
|
30
|
-
assert_equal 'localhost', @conn.secondary_pools[1].host
|
31
|
-
assert_equal 27019, @conn.secondary_pools[1].port
|
32
|
-
|
33
|
-
assert_equal 2, @conn.secondary_pools.length
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
context "connecting to a replica set and providing seed nodes" do
|
38
|
-
setup do
|
39
|
-
TCPSocket.stubs(:new).returns(new_mock_socket)
|
40
|
-
@conn = ReplSetConnection.new(['localhost', 27017], ['localhost', 27019], :connect => false)
|
41
|
-
|
42
|
-
admin_db = new_mock_db
|
43
|
-
@hosts = ['localhost:27017', 'localhost:27018', 'localhost:27019']
|
44
|
-
admin_db.stubs(:command).returns({'ok' => 1, 'ismaster' => 1, 'hosts' => @hosts})
|
45
|
-
@conn.stubs(:[]).with('admin').returns(admin_db)
|
46
|
-
@conn.connect
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
context "initializing with a mongodb uri" do
|
51
|
-
|
52
|
-
should "parse a uri specifying multiple nodes" do
|
53
|
-
@conn = Connection.from_uri("mongodb://localhost:27017,mydb.com:27018", :connect => false)
|
54
|
-
assert_equal ['localhost', 27017], @conn.nodes[0]
|
55
|
-
assert_equal ['mydb.com', 27018], @conn.nodes[1]
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|