mongo 1.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/README.md +9 -6
  2. data/Rakefile +3 -4
  3. data/docs/HISTORY.md +20 -2
  4. data/docs/READ_PREFERENCE.md +39 -0
  5. data/docs/RELEASES.md +1 -1
  6. data/docs/REPLICA_SETS.md +23 -2
  7. data/docs/TAILABLE_CURSORS.md +51 -0
  8. data/docs/TUTORIAL.md +4 -4
  9. data/docs/WRITE_CONCERN.md +5 -2
  10. data/lib/mongo.rb +7 -22
  11. data/lib/mongo/collection.rb +96 -29
  12. data/lib/mongo/connection.rb +107 -62
  13. data/lib/mongo/cursor.rb +136 -57
  14. data/lib/mongo/db.rb +26 -5
  15. data/lib/mongo/exceptions.rb +17 -1
  16. data/lib/mongo/gridfs/grid.rb +1 -1
  17. data/lib/mongo/repl_set_connection.rb +273 -156
  18. data/lib/mongo/util/logging.rb +42 -0
  19. data/lib/mongo/util/node.rb +183 -0
  20. data/lib/mongo/util/pool.rb +76 -13
  21. data/lib/mongo/util/pool_manager.rb +208 -0
  22. data/lib/mongo/util/ssl_socket.rb +38 -0
  23. data/lib/mongo/util/support.rb +9 -1
  24. data/lib/mongo/util/timeout.rb +42 -0
  25. data/lib/mongo/version.rb +3 -0
  26. data/mongo.gemspec +2 -2
  27. data/test/bson/binary_test.rb +1 -1
  28. data/test/bson/bson_string_test.rb +30 -0
  29. data/test/bson/bson_test.rb +6 -3
  30. data/test/bson/byte_buffer_test.rb +1 -1
  31. data/test/bson/hash_with_indifferent_access_test.rb +1 -1
  32. data/test/bson/json_test.rb +1 -1
  33. data/test/bson/object_id_test.rb +2 -18
  34. data/test/bson/ordered_hash_test.rb +38 -3
  35. data/test/bson/test_helper.rb +46 -0
  36. data/test/bson/timestamp_test.rb +32 -10
  37. data/test/collection_test.rb +89 -3
  38. data/test/connection_test.rb +35 -20
  39. data/test/cursor_test.rb +63 -2
  40. data/test/db_test.rb +12 -2
  41. data/test/pool_test.rb +21 -0
  42. data/test/replica_sets/connect_test.rb +26 -13
  43. data/test/replica_sets/connection_string_test.rb +1 -4
  44. data/test/replica_sets/count_test.rb +1 -0
  45. data/test/replica_sets/insert_test.rb +1 -0
  46. data/test/replica_sets/pooled_insert_test.rb +4 -1
  47. data/test/replica_sets/query_secondaries.rb +2 -1
  48. data/test/replica_sets/query_test.rb +2 -1
  49. data/test/replica_sets/read_preference_test.rb +43 -0
  50. data/test/replica_sets/refresh_test.rb +123 -0
  51. data/test/replica_sets/replication_ack_test.rb +9 -4
  52. data/test/replica_sets/rs_test_helper.rb +2 -2
  53. data/test/timeout_test.rb +14 -0
  54. data/test/tools/repl_set_manager.rb +134 -23
  55. data/test/unit/collection_test.rb +6 -8
  56. data/test/unit/connection_test.rb +4 -4
  57. data/test/unit/cursor_test.rb +23 -5
  58. data/test/unit/db_test.rb +2 -0
  59. data/test/unit/grid_test.rb +2 -0
  60. data/test/unit/node_test.rb +73 -0
  61. data/test/unit/pool_manager_test.rb +47 -0
  62. data/test/unit/read_test.rb +101 -0
  63. metadata +214 -138
  64. data/lib/mongo/test.rb +0 -20
  65. data/test/async/collection_test.rb +0 -224
  66. data/test/async/connection_test.rb +0 -24
  67. data/test/async/cursor_test.rb +0 -162
  68. data/test/async/worker_pool_test.rb +0 -99
  69. data/test/load/resque/load.rb +0 -21
  70. data/test/load/resque/processor.rb +0 -26
  71. data/test/load/unicorn/unicorn.rb +0 -29
  72. data/test/tools/load.rb +0 -58
  73. data/test/tools/sharding_manager.rb +0 -202
  74. data/test/tools/test.rb +0 -4
  75. data/test/unit/repl_set_connection_test.rb +0 -59
@@ -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
@@ -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
@@ -1,4 +0,0 @@
1
- require 'sharding_manager'
2
-
3
- m = ShardingManager.new(:config_count => 3)
4
- m.start_cluster
@@ -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