xbar 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/README.mkdn +1 -1
- data/Rakefile +5 -2
- data/dummy/.gitignore +15 -0
- data/dummy/Gemfile +38 -0
- data/dummy/README.rdoc +261 -0
- data/dummy/Rakefile +7 -0
- data/dummy/app/assets/images/rails.png +0 -0
- data/dummy/app/assets/javascripts/application.js +15 -0
- data/dummy/app/assets/stylesheets/application.css +13 -0
- data/dummy/app/controllers/application_controller.rb +3 -0
- data/dummy/app/helpers/application_helper.rb +2 -0
- data/dummy/app/mailers/.gitkeep +0 -0
- data/dummy/app/models/.gitkeep +0 -0
- data/dummy/app/views/layouts/application.html.erb +14 -0
- data/dummy/config.ru +4 -0
- data/dummy/config/application.rb +59 -0
- data/dummy/config/boot.rb +6 -0
- data/dummy/config/database.yml +25 -0
- data/dummy/config/environment.rb +5 -0
- data/dummy/config/environments/development.rb +37 -0
- data/dummy/config/environments/production.rb +67 -0
- data/dummy/config/environments/test.rb +37 -0
- data/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/dummy/config/initializers/inflections.rb +15 -0
- data/dummy/config/initializers/mime_types.rb +5 -0
- data/dummy/config/initializers/secret_token.rb +7 -0
- data/dummy/config/initializers/session_store.rb +8 -0
- data/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/dummy/config/locales/en.yml +5 -0
- data/dummy/config/routes.rb +58 -0
- data/dummy/db/schema.rb +16 -0
- data/dummy/db/seeds.rb +7 -0
- data/dummy/doc/README_FOR_APP +2 -0
- data/dummy/lib/assets/.gitkeep +0 -0
- data/dummy/lib/generators/initializer/USAGE +8 -0
- data/dummy/lib/generators/initializer/initializer_generator.rb +8 -0
- data/dummy/lib/generators/initializer/templates/initializer.rb +1 -0
- data/dummy/lib/tasks/.gitkeep +0 -0
- data/dummy/log/.gitkeep +0 -0
- data/dummy/public/404.html +26 -0
- data/dummy/public/422.html +26 -0
- data/dummy/public/500.html +25 -0
- data/dummy/public/favicon.ico +0 -0
- data/dummy/public/index.html +241 -0
- data/dummy/public/robots.txt +5 -0
- data/dummy/script/rails +6 -0
- data/dummy/test/fixtures/.gitkeep +0 -0
- data/dummy/test/functional/.gitkeep +0 -0
- data/dummy/test/integration/.gitkeep +0 -0
- data/dummy/test/performance/browsing_test.rb +12 -0
- data/dummy/test/test_helper.rb +13 -0
- data/dummy/test/unit/.gitkeep +0 -0
- data/dummy/vendor/assets/javascripts/.gitkeep +0 -0
- data/dummy/vendor/assets/stylesheets/.gitkeep +0 -0
- data/dummy/vendor/plugins/.gitkeep +0 -0
- data/examples/README +3 -1
- data/examples/basic.rb +34 -0
- data/examples/config/canada.json +17 -0
- data/examples/config/canada2.json +17 -0
- data/examples/config/connection.rb +2 -0
- data/examples/config/simple.json +10 -10
- data/examples/lib/helpers.rb +90 -0
- data/examples/{setup.rb → lib/setup.rb} +14 -6
- data/examples/migrations/1_create_users.rb +1 -1
- data/examples/multithread.rb +47 -0
- data/examples/pause.rb +67 -0
- data/examples/pause_switch.rb +61 -0
- data/examples/switch.rb +42 -0
- data/gemfiles/rails32.gemfile.lock +3 -3
- data/lib/xbar.rb +1 -0
- data/lib/xbar/mapper.rb +61 -14
- data/lib/xbar/model.rb +1 -10
- data/lib/xbar/proxy.rb +104 -33
- data/lib/xbar/shard.rb +17 -1
- data/lib/xbar/version.rb +1 -1
- data/run +15 -7
- data/spec/console.rb +0 -1
- data/spec/spec_helper.rb +5 -2
- data/spec/xbar/association_spec.rb +1 -0
- data/spec/xbar/mapper_spec.rb +2 -4
- data/spec/xbar/model_spec.rb +11 -8
- data/spec/xbar/proxy_spec.rb +1 -1
- metadata +90 -28
- data/examples/example1.rb +0 -34
@@ -10,18 +10,23 @@ require 'xbar'
|
|
10
10
|
module Examples
|
11
11
|
module Setup
|
12
12
|
|
13
|
-
MIGRATIONS_ROOT = File.expand_path(File.join(File.dirname(__FILE__),
|
13
|
+
MIGRATIONS_ROOT = File.expand_path(File.join(File.dirname(__FILE__),
|
14
|
+
'../migrations'))
|
15
|
+
|
16
|
+
def self.clean
|
17
|
+
# This must agree with what's in the 'simple' JSON config file. Make
|
18
|
+
# sure that we're starting with a clean slate.
|
19
|
+
%x{ rm -f /tmp/store.sqlite3 /tmp/bakery.sqlite3 \
|
20
|
+
/tmp/deli.sqlite3 /tmp/produce.sqlite3 }
|
21
|
+
end
|
14
22
|
|
15
23
|
def self.start(xbar_env, app_env, version = nil)
|
16
24
|
|
17
|
-
|
18
|
-
# sure that we're starting with a clean slate.
|
19
|
-
%x{ rm -f /tmp/paris.sqlite3 /tmp/france_1.sqlite3 \
|
20
|
-
/tmp/france_2.sqlite3 /tmp/france_3.sqlite3 }
|
25
|
+
clean
|
21
26
|
|
22
27
|
# This directory should have a subdirectory called 'config' which
|
23
28
|
# actually holds the config files.
|
24
|
-
XBar.directory = File.expand_path(File.dirname(__FILE__))
|
29
|
+
XBar.directory = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
25
30
|
|
26
31
|
# Initialize the mapper with the 'test' environment from the 'simple'
|
27
32
|
# configuration file.
|
@@ -37,6 +42,9 @@ module Examples
|
|
37
42
|
if version
|
38
43
|
ActiveRecord::Migrator.run(:down, MIGRATIONS_ROOT, version)
|
39
44
|
end
|
45
|
+
|
46
|
+
clean
|
47
|
+
|
40
48
|
end
|
41
49
|
|
42
50
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_record'
|
3
|
+
require 'xbar'
|
4
|
+
|
5
|
+
XBar.directory = File.expand_path(File.dirname(__FILE__))
|
6
|
+
XBar::Mapper.reset(xbar_env: 'canada', app_env: 'test')
|
7
|
+
|
8
|
+
threads = []
|
9
|
+
|
10
|
+
class User < ActiveRecord::Base; end
|
11
|
+
|
12
|
+
config = XBar::Mapper.shards[:canada][0].spec.config
|
13
|
+
|
14
|
+
if config[:adapter] == "mysql2"
|
15
|
+
client = Mysql2::Client.new(config)
|
16
|
+
client.query("DELETE FROM users")
|
17
|
+
end
|
18
|
+
|
19
|
+
5.times do |i|
|
20
|
+
threads << Thread.new(i) do
|
21
|
+
XBar.using(:canada) do
|
22
|
+
100.times do |j|
|
23
|
+
name = "Thread_#{i}_#{j}"
|
24
|
+
User.create(:name => name)
|
25
|
+
User.using_any.all # allow read from slave
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
threads.each(&:join)
|
32
|
+
|
33
|
+
XBar::Mapper.disconnect_all!
|
34
|
+
|
35
|
+
if config[:adapter] == "mysql2"
|
36
|
+
results = client.query("SELECT COUNT(*) AS count FROM users")
|
37
|
+
results.each do |row|
|
38
|
+
puts row["count"]
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
puts User.using(:canada).all.size
|
44
|
+
puts User.using(:canada).all.size
|
45
|
+
puts User.using(:canada_east).all.size
|
46
|
+
puts User.using(:canada_central).all.size
|
47
|
+
puts User.using(:canada_west).all.size
|
data/examples/pause.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require_relative "lib/helpers"
|
2
|
+
|
3
|
+
include XBar::Example::Helpers
|
4
|
+
|
5
|
+
# More setup, before we start up threads.
|
6
|
+
XBar.directory = File.expand_path(File.dirname(__FILE__))
|
7
|
+
XBar::Mapper.reset(xbar_env: 'canada', app_env: 'test')
|
8
|
+
class User < ActiveRecord::Base; end
|
9
|
+
# %x{ ssh _mysql@deimos repctl switch_master 1 2 3 }
|
10
|
+
|
11
|
+
empty_users_table(:canada)
|
12
|
+
|
13
|
+
puts %x{ ssh _mysql@deimos repctl status}
|
14
|
+
|
15
|
+
do_work(5, 100, :canada)
|
16
|
+
|
17
|
+
sleep 1
|
18
|
+
puts "Requesting all proxies to pause"
|
19
|
+
request_pause
|
20
|
+
print "Requests complete, waiting for pause..."
|
21
|
+
wait_for_pause
|
22
|
+
puts("done")
|
23
|
+
|
24
|
+
count = query_users_table(:canada)
|
25
|
+
puts "Before pause 1: entered #{count} records in master replica of Canada shard"
|
26
|
+
sleep 1
|
27
|
+
count = query_users_table(:canada)
|
28
|
+
puts "Before pause 2: entered #{count} records in master replica of Canada shard"
|
29
|
+
|
30
|
+
unpause
|
31
|
+
|
32
|
+
join_workers
|
33
|
+
|
34
|
+
cleanup_exited_threads
|
35
|
+
|
36
|
+
count = query_users_table(:canada)
|
37
|
+
puts "After join: #{count} records in master replica of Canada shard"
|
38
|
+
|
39
|
+
puts "Done"
|
40
|
+
exit 0
|
41
|
+
|
42
|
+
puts %x{ ssh _mysql@deimos repctl status}
|
43
|
+
|
44
|
+
puts %x{ ssh _mysql@deimos repctl switch_master 2 1 3 }
|
45
|
+
puts %x{ ssh _mysql@deimos repctl status }
|
46
|
+
|
47
|
+
XBar::Mapper.reset(xbar_env: 'canada2', app_env: 'test')
|
48
|
+
|
49
|
+
do_work(5, 10, :canada)
|
50
|
+
|
51
|
+
join_workers
|
52
|
+
User.using(:canada_central).all.size
|
53
|
+
cleanup_exited_threads
|
54
|
+
|
55
|
+
puts %x{ ssh _mysql@deimos repctl status}
|
56
|
+
|
57
|
+
puts query_users_table(:canada)
|
58
|
+
puts User.using(:canada).all.size
|
59
|
+
puts User.using(:canada_east).all.size
|
60
|
+
puts User.using(:canada_central).all.size
|
61
|
+
puts User.using(:canada_west).all.size
|
62
|
+
|
63
|
+
# Switch master back to server 1 for the benefit of
|
64
|
+
# other tests.
|
65
|
+
puts %x{ ssh _mysql@deimos repctl switch_master 1 2 3 }
|
66
|
+
puts %x{ ssh _mysql@deimos repctl status }
|
67
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require_relative "lib/helpers"
|
2
|
+
|
3
|
+
include XBar::Example::Helpers
|
4
|
+
|
5
|
+
# More setup, before we start up threads.
|
6
|
+
XBar.directory = File.expand_path(File.dirname(__FILE__))
|
7
|
+
|
8
|
+
puts "Using XBar config files from #{XBar.directory}/config"
|
9
|
+
|
10
|
+
XBar::Mapper.reset(xbar_env: 'canada', app_env: 'test')
|
11
|
+
class User < ActiveRecord::Base; end
|
12
|
+
%x{ ssh _mysql@deimos repctl switch_master 1 2 3 }
|
13
|
+
|
14
|
+
empty_users_table(:canada)
|
15
|
+
|
16
|
+
puts %x{ ssh _mysql@deimos repctl status}
|
17
|
+
|
18
|
+
do_work(5, 100, :canada)
|
19
|
+
|
20
|
+
sleep 1
|
21
|
+
puts "Requesting all proxies to pause"
|
22
|
+
request_pause
|
23
|
+
print "Requests complete, waiting for pause..."
|
24
|
+
wait_for_pause
|
25
|
+
puts("done")
|
26
|
+
|
27
|
+
count = query_users_table(:canada)
|
28
|
+
puts "After pause : entered #{count} records in master replica of Canada shard"
|
29
|
+
|
30
|
+
print "Switching master..."
|
31
|
+
puts %x{ ssh _mysql@deimos repctl switch_master 2 1 3 }
|
32
|
+
print "done:"
|
33
|
+
puts %x{ ssh _mysql@deimos repctl status }
|
34
|
+
|
35
|
+
print "Switching to new XBar environment..."
|
36
|
+
XBar::Mapper.reset(xbar_env: 'canada2', app_env: 'test')
|
37
|
+
puts "done."
|
38
|
+
|
39
|
+
print "Resuming paused threads..."
|
40
|
+
unpause
|
41
|
+
puts "done."
|
42
|
+
|
43
|
+
print "Waiting for all workers to complete..."
|
44
|
+
join_workers
|
45
|
+
puts "done"
|
46
|
+
|
47
|
+
cleanup_exited_threads
|
48
|
+
|
49
|
+
count = query_users_table(:canada)
|
50
|
+
puts %x{ ssh _mysql@deimos repctl status}
|
51
|
+
|
52
|
+
puts query_users_table(:canada)
|
53
|
+
puts User.using(:canada).all.size
|
54
|
+
puts User.using(:canada_east).all.size
|
55
|
+
puts User.using(:canada_central).all.size
|
56
|
+
puts User.using(:canada_west).all.size
|
57
|
+
|
58
|
+
# Switch master back to server 1 for the benefit of
|
59
|
+
# other tests.
|
60
|
+
puts %x{ ssh _mysql@deimos repctl switch_master 1 2 3 }
|
61
|
+
puts %x{ ssh _mysql@deimos repctl status }
|
data/examples/switch.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative "lib/helpers"
|
2
|
+
|
3
|
+
include XBar::Example::Helpers
|
4
|
+
|
5
|
+
# More setup, before we start up threads.
|
6
|
+
XBar.directory = File.expand_path(File.dirname(__FILE__))
|
7
|
+
XBar::Mapper.reset(xbar_env: 'canada', app_env: 'test')
|
8
|
+
class User < ActiveRecord::Base; end
|
9
|
+
%x{ ssh _mysql@deimos repctl switch_master 1 2 3 }
|
10
|
+
empty_users_table(:canada)
|
11
|
+
|
12
|
+
puts %x{ ssh _mysql@deimos repctl status}
|
13
|
+
|
14
|
+
do_work(5, 10, :canada)
|
15
|
+
join_workers
|
16
|
+
cleanup_exited_threads
|
17
|
+
|
18
|
+
puts %x{ ssh _mysql@deimos repctl status}
|
19
|
+
|
20
|
+
puts %x{ ssh _mysql@deimos repctl switch_master 2 1 3 }
|
21
|
+
puts %x{ ssh _mysql@deimos repctl status }
|
22
|
+
|
23
|
+
XBar::Mapper.reset(xbar_env: 'canada2', app_env: 'test')
|
24
|
+
|
25
|
+
do_work(5, 10, :canada)
|
26
|
+
|
27
|
+
join_workers
|
28
|
+
User.using(:canada_central).all.size
|
29
|
+
cleanup_exited_threads
|
30
|
+
|
31
|
+
puts %x{ ssh _mysql@deimos repctl status}
|
32
|
+
|
33
|
+
puts query_users_table(:canada)
|
34
|
+
puts User.using(:canada).all.size
|
35
|
+
puts User.using(:canada_east).all.size
|
36
|
+
puts User.using(:canada_central).all.size
|
37
|
+
puts User.using(:canada_west).all.size
|
38
|
+
|
39
|
+
# Switch master back to server 1 for the benefit of
|
40
|
+
# other tests.
|
41
|
+
puts %x{ ssh _mysql@deimos repctl switch_master 1 2 3 }
|
42
|
+
puts %x{ ssh _mysql@deimos repctl status }
|
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
|
-
remote: /
|
2
|
+
remote: /opt/projects/xbar
|
3
3
|
specs:
|
4
|
-
xbar (0.4.
|
4
|
+
xbar (0.4.2)
|
5
5
|
activerecord
|
6
6
|
mysql2
|
7
7
|
|
@@ -53,7 +53,7 @@ GEM
|
|
53
53
|
mime-types (1.17.2)
|
54
54
|
multi_json (1.0.4)
|
55
55
|
mysql2 (0.3.11)
|
56
|
-
pg (0.
|
56
|
+
pg (0.13.1)
|
57
57
|
polyglot (0.3.3)
|
58
58
|
rack (1.4.1)
|
59
59
|
rack-cache (1.1)
|
data/lib/xbar.rb
CHANGED
data/lib/xbar/mapper.rb
CHANGED
@@ -58,7 +58,7 @@ module XBar
|
|
58
58
|
@@cached_config = nil
|
59
59
|
@@shards = HashWithIndifferentAccess.new
|
60
60
|
@@connections = HashWithIndifferentAccess.new
|
61
|
-
@@proxies =
|
61
|
+
@@proxies = {}
|
62
62
|
@@adapters = Set.new
|
63
63
|
@@config = nil
|
64
64
|
@@app_env = nil
|
@@ -76,10 +76,17 @@ module XBar
|
|
76
76
|
|
77
77
|
def config_from_file
|
78
78
|
file_name = config_file_name
|
79
|
-
|
79
|
+
|
80
80
|
if File.exists? file_name
|
81
|
+
if XBar.debug
|
82
|
+
puts "XBar::Mapper, reading configuration from file #{file_name}"
|
83
|
+
end
|
81
84
|
config = JSON.parse(ERB.new(File.read(file_name)).result)
|
82
85
|
else
|
86
|
+
if XBar.debug
|
87
|
+
puts("XBar::Mapper: No config file #{file_name} -- " +
|
88
|
+
"Deriving defaults.")
|
89
|
+
end
|
83
90
|
config = {}
|
84
91
|
end
|
85
92
|
HashWithIndifferentAccess.new(config)
|
@@ -115,6 +122,7 @@ module XBar
|
|
115
122
|
# a hash in the XBar module.
|
116
123
|
#
|
117
124
|
def reset(options = {})
|
125
|
+
force = options.delete(:force)
|
118
126
|
new_xbar_env = options[:xbar_env] || xbar_env
|
119
127
|
if (new_xbar_env != xbar_env) || (options[:clear_cache]) ||
|
120
128
|
(!@@cached_config.nil? && @@cached_config.empty?)
|
@@ -123,7 +131,9 @@ module XBar
|
|
123
131
|
self.xbar_env = new_xbar_env
|
124
132
|
self.app_env = options[:app_env] if options[:app_env]
|
125
133
|
|
126
|
-
|
134
|
+
if XBar.debug
|
135
|
+
puts "XBar::Mapper#reset, xbar_env=#{xbar_env}, app_env=#{app_env}"
|
136
|
+
end
|
127
137
|
initialize_shards(config)
|
128
138
|
initialize_options(config)
|
129
139
|
|
@@ -159,9 +169,14 @@ module XBar
|
|
159
169
|
@@adapters << connection_pool.spec.config
|
160
170
|
end
|
161
171
|
|
162
|
-
@@proxies.each do |proxy|
|
163
|
-
|
172
|
+
@@proxies.values.each do |proxy|
|
173
|
+
if force
|
174
|
+
proxy.do_reset
|
175
|
+
else
|
176
|
+
proxy.request_reset
|
177
|
+
end
|
164
178
|
end
|
179
|
+
|
165
180
|
self
|
166
181
|
end
|
167
182
|
|
@@ -174,12 +189,33 @@ module XBar
|
|
174
189
|
@@options[:verify_connection] ||= false
|
175
190
|
end
|
176
191
|
|
192
|
+
# Register a proxy on behalf of the current thread. This is only
|
193
|
+
# called by Proxy#new. It is up to the calling thread to assign
|
194
|
+
# Thread.current[:connection_proxy] = <new proxy> if it wishes.
|
177
195
|
def register(proxy)
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
196
|
+
reset if shards.empty?
|
197
|
+
if @@proxies[Thread.current.object_id]
|
198
|
+
raise RuntimeError, "Mapper: already registered this proxy"
|
199
|
+
end
|
200
|
+
@@proxies[Thread.current.object_id] = proxy
|
201
|
+
end
|
202
|
+
|
203
|
+
# Unregister the proxy for the current thread, or for the specified
|
204
|
+
# thread. A thread can be specified by passing a Thread instance or
|
205
|
+
# its object_id.
|
206
|
+
def unregister(thread_spec = Thread.current)
|
207
|
+
thread_spec = thread_spec.object_id if thread_spec.instance_of?(Thread)
|
208
|
+
XBar::Mapper.proxies.delete(thread_spec)
|
209
|
+
end
|
210
|
+
|
211
|
+
def disconnect_all!
|
212
|
+
shards.each do |name, pool_list|
|
213
|
+
pool_list.each_with_index do |p, i|
|
214
|
+
if p.connected?
|
215
|
+
p.disconnect!
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
183
219
|
end
|
184
220
|
|
185
221
|
def app_env
|
@@ -207,9 +243,15 @@ module XBar
|
|
207
243
|
|
208
244
|
def initialize_shards(aconfig)
|
209
245
|
|
246
|
+
# The way this works right now, if the same adapter spec is used
|
247
|
+
# in multiple shards, we will get multiple connection pools
|
248
|
+
# initialized with the same spec. It might be better to share
|
249
|
+
# connection pools among the shards.
|
250
|
+
|
210
251
|
@@connections.clear
|
211
252
|
@@adapters.clear
|
212
253
|
@@shards.clear
|
254
|
+
pool_for_spec = {}
|
213
255
|
|
214
256
|
if aconfig
|
215
257
|
begin
|
@@ -227,18 +269,23 @@ module XBar
|
|
227
269
|
end
|
228
270
|
if connection_key.kind_of? String
|
229
271
|
spec = aconfig["connections"][connection_key]
|
230
|
-
|
272
|
+
# unless pool = pool_for_spec[spec]
|
273
|
+
pool = install_connection(connection_key, spec)
|
274
|
+
# pool_for_spec[spec] = pool
|
275
|
+
# end
|
231
276
|
@@shards[shard_key] = [pool]
|
232
277
|
else # an array of connection keys
|
233
278
|
@@shards[shard_key] = []
|
234
279
|
connection_key.each do |conn_key|
|
235
280
|
spec = aconfig["connections"][conn_key]
|
236
|
-
pool =
|
281
|
+
# unless pool = pool_for_spec[spec]
|
282
|
+
pool = install_connection(conn_key, spec)
|
283
|
+
# pool_for_spec[spec] = pool
|
284
|
+
# end
|
237
285
|
@@shards[shard_key] << pool
|
238
286
|
end
|
239
287
|
end
|
240
288
|
end
|
241
|
-
# @@shards[:master] = [@@connections[:master]]
|
242
289
|
end
|
243
290
|
|
244
291
|
# Should return a ConnectionPool.
|
@@ -285,7 +332,7 @@ module XBar
|
|
285
332
|
end
|
286
333
|
|
287
334
|
# Give module XBar::Mapper the above class methods.
|
288
|
-
|
335
|
+
self.extend(ClassMethods)
|
289
336
|
|
290
337
|
Mapper.exports.each do |meth|
|
291
338
|
define_method(meth) {Mapper.send(meth)}
|