mongo 1.3.1 → 1.4.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/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
|