activerecord-turntable 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +25 -0
- data/.rspec +3 -0
- data/Gemfile +25 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +290 -0
- data/Rakefile +101 -0
- data/activerecord-turntable.gemspec +47 -0
- data/lib/active_record/turntable.rb +58 -0
- data/lib/active_record/turntable/active_record_ext.rb +26 -0
- data/lib/active_record/turntable/active_record_ext/.gitkeep +0 -0
- data/lib/active_record/turntable/active_record_ext/abstract_adapter.rb +50 -0
- data/lib/active_record/turntable/active_record_ext/clever_load.rb +90 -0
- data/lib/active_record/turntable/active_record_ext/fixtures.rb +131 -0
- data/lib/active_record/turntable/active_record_ext/log_subscriber.rb +64 -0
- data/lib/active_record/turntable/active_record_ext/persistence.rb +95 -0
- data/lib/active_record/turntable/active_record_ext/schema_dumper.rb +107 -0
- data/lib/active_record/turntable/active_record_ext/sequencer.rb +28 -0
- data/lib/active_record/turntable/active_record_ext/transactions.rb +33 -0
- data/lib/active_record/turntable/algorithm.rb +7 -0
- data/lib/active_record/turntable/algorithm/.gitkeep +0 -0
- data/lib/active_record/turntable/algorithm/base.rb +11 -0
- data/lib/active_record/turntable/algorithm/range_algorithm.rb +37 -0
- data/lib/active_record/turntable/algorithm/range_bsearch_algorithm.rb +41 -0
- data/lib/active_record/turntable/base.rb +130 -0
- data/lib/active_record/turntable/cluster.rb +70 -0
- data/lib/active_record/turntable/compatible.rb +19 -0
- data/lib/active_record/turntable/config.rb +24 -0
- data/lib/active_record/turntable/connection_proxy.rb +218 -0
- data/lib/active_record/turntable/connection_proxy/mixable.rb +39 -0
- data/lib/active_record/turntable/error.rb +8 -0
- data/lib/active_record/turntable/helpers.rb +5 -0
- data/lib/active_record/turntable/helpers/test_helper.rb +25 -0
- data/lib/active_record/turntable/master_shard.rb +28 -0
- data/lib/active_record/turntable/migration.rb +132 -0
- data/lib/active_record/turntable/mixer.rb +203 -0
- data/lib/active_record/turntable/mixer/fader.rb +34 -0
- data/lib/active_record/turntable/mixer/fader/calculate_shards_sum_result.rb +15 -0
- data/lib/active_record/turntable/mixer/fader/insert_shards_merge_result.rb +24 -0
- data/lib/active_record/turntable/mixer/fader/select_shards_merge_result.rb +22 -0
- data/lib/active_record/turntable/mixer/fader/specified_shard.rb +12 -0
- data/lib/active_record/turntable/mixer/fader/update_shards_merge_result.rb +17 -0
- data/lib/active_record/turntable/pool_proxy.rb +56 -0
- data/lib/active_record/turntable/rack.rb +5 -0
- data/lib/active_record/turntable/rack/connection_management.rb +18 -0
- data/lib/active_record/turntable/railtie.rb +14 -0
- data/lib/active_record/turntable/railties/databases.rake +205 -0
- data/lib/active_record/turntable/seq_shard.rb +14 -0
- data/lib/active_record/turntable/sequencer.rb +46 -0
- data/lib/active_record/turntable/sequencer/api.rb +36 -0
- data/lib/active_record/turntable/sequencer/mysql.rb +32 -0
- data/lib/active_record/turntable/shard.rb +48 -0
- data/lib/active_record/turntable/sql_tree_patch.rb +199 -0
- data/lib/active_record/turntable/version.rb +5 -0
- data/lib/activerecord-turntable.rb +2 -0
- data/lib/generators/active_record/turntable/install_generator.rb +14 -0
- data/lib/generators/templates/turntable.yml +40 -0
- data/sample_app/.gitignore +16 -0
- data/sample_app/Gemfile +41 -0
- data/sample_app/README.rdoc +261 -0
- data/sample_app/Rakefile +7 -0
- data/sample_app/app/assets/images/rails.png +0 -0
- data/sample_app/app/assets/javascripts/application.js +15 -0
- data/sample_app/app/assets/stylesheets/application.css +13 -0
- data/sample_app/app/controllers/application_controller.rb +3 -0
- data/sample_app/app/helpers/application_helper.rb +2 -0
- data/sample_app/app/mailers/.gitkeep +0 -0
- data/sample_app/app/models/.gitkeep +0 -0
- data/sample_app/app/models/user.rb +4 -0
- data/sample_app/app/views/layouts/application.html.erb +14 -0
- data/sample_app/config.ru +4 -0
- data/sample_app/config/application.rb +65 -0
- data/sample_app/config/boot.rb +6 -0
- data/sample_app/config/database.yml +70 -0
- data/sample_app/config/environment.rb +5 -0
- data/sample_app/config/environments/development.rb +37 -0
- data/sample_app/config/environments/production.rb +67 -0
- data/sample_app/config/environments/test.rb +37 -0
- data/sample_app/config/initializers/backtrace_silencers.rb +7 -0
- data/sample_app/config/initializers/inflections.rb +15 -0
- data/sample_app/config/initializers/mime_types.rb +5 -0
- data/sample_app/config/initializers/secret_token.rb +7 -0
- data/sample_app/config/initializers/session_store.rb +8 -0
- data/sample_app/config/initializers/wrap_parameters.rb +14 -0
- data/sample_app/config/locales/en.yml +5 -0
- data/sample_app/config/routes.rb +58 -0
- data/sample_app/config/turntable.yml +64 -0
- data/sample_app/db/migrate/20120316073058_create_users.rb +11 -0
- data/sample_app/db/seeds.rb +7 -0
- data/sample_app/lib/assets/.gitkeep +0 -0
- data/sample_app/lib/tasks/.gitkeep +0 -0
- data/sample_app/log/.gitkeep +0 -0
- data/sample_app/public/404.html +26 -0
- data/sample_app/public/422.html +26 -0
- data/sample_app/public/500.html +25 -0
- data/sample_app/public/favicon.ico +0 -0
- data/sample_app/public/index.html +241 -0
- data/sample_app/public/robots.txt +5 -0
- data/sample_app/script/rails +6 -0
- data/sample_app/vendor/assets/javascripts/.gitkeep +0 -0
- data/sample_app/vendor/assets/stylesheets/.gitkeep +0 -0
- data/sample_app/vendor/plugins/.gitkeep +0 -0
- data/script/performance/algorithm +32 -0
- data/spec/active_record/turntable/active_record_ext/clever_load_spec.rb +81 -0
- data/spec/active_record/turntable/active_record_ext/persistence_spec.rb +151 -0
- data/spec/active_record/turntable/algorithm/range_algorithm_spec.rb +35 -0
- data/spec/active_record/turntable/algorithm_spec.rb +69 -0
- data/spec/active_record/turntable/base_spec.rb +13 -0
- data/spec/active_record/turntable/cluster_spec.rb +18 -0
- data/spec/active_record/turntable/config_spec.rb +17 -0
- data/spec/active_record/turntable/connection_proxy_spec.rb +186 -0
- data/spec/active_record/turntable/finder_spec.rb +27 -0
- data/spec/active_record/turntable/mixer/fader_spec.rb +4 -0
- data/spec/active_record/turntable/mixer_spec.rb +114 -0
- data/spec/active_record/turntable/shard_spec.rb +21 -0
- data/spec/active_record/turntable_spec.rb +30 -0
- data/spec/config/database.yml +45 -0
- data/spec/config/turntable.yml +17 -0
- data/spec/fabricators/.gitkeep +0 -0
- data/spec/fabricators/turntable_fabricator.rb +14 -0
- data/spec/migrations/.gitkeep +0 -0
- data/spec/migrations/001_create_users.rb +16 -0
- data/spec/migrations/002_create_user_statuses.rb +16 -0
- data/spec/migrations/003_create_cards.rb +14 -0
- data/spec/migrations/004_create_cards_users.rb +15 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/test_models.rb +27 -0
- data/spec/turntable_helper.rb +29 -0
- metadata +367 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
require "active_record/turntable/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "activerecord-turntable"
|
6
|
+
s.version = ActiveRecord::Turntable::VERSION
|
7
|
+
s.authors = ["gussan"]
|
8
|
+
s.homepage = "https://github.com/drecom/activerecord-turntable"
|
9
|
+
s.summary = %q{ActiveRecord Sharding plugin}
|
10
|
+
s.description = %q{AcviveRecord Sharding plugin}
|
11
|
+
|
12
|
+
s.rubyforge_project = "activerecord-turntable"
|
13
|
+
s.extra_rdoc_files = [
|
14
|
+
"LICENSE.txt",
|
15
|
+
"README.rdoc"
|
16
|
+
]
|
17
|
+
|
18
|
+
s.files = `git ls-files | grep -v "^spec"`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
s.licenses = ["MIT"]
|
23
|
+
s.rubygems_version = "1.8.16"
|
24
|
+
|
25
|
+
# runtime dependencies
|
26
|
+
s.add_runtime_dependency(%q<activerecord>, [">= 3.0.0"])
|
27
|
+
s.add_runtime_dependency(%q<activesupport>, [">=3.0.0"])
|
28
|
+
s.add_runtime_dependency(%q<sql_tree>, ["= 0.2.0"])
|
29
|
+
s.add_runtime_dependency(%q<bsearch>, ["~> 1.5"])
|
30
|
+
s.add_runtime_dependency(%q<httpclient>, [">= 0"])
|
31
|
+
|
32
|
+
# development dependencies
|
33
|
+
s.add_development_dependency(%q<rake>, ["~> 0.9.2"])
|
34
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
35
|
+
s.add_development_dependency(%q<rr>, [">= 0"])
|
36
|
+
s.add_development_dependency(%q<mysql2>, [">= 0"])
|
37
|
+
s.add_development_dependency(%q<fabrication>, [">= 0"])
|
38
|
+
s.add_development_dependency(%q<faker>, [">= 0"])
|
39
|
+
s.add_development_dependency(%q<activerecord-import>, [">= 0"])
|
40
|
+
s.add_development_dependency(%q<pry>, [">= 0"])
|
41
|
+
s.add_development_dependency(%q<guard-rspec>, [">= 0"])
|
42
|
+
|
43
|
+
if RUBY_PLATFORM =~ /darwin/
|
44
|
+
s.add_development_dependency(%q<growl>, [">= 0"])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#
|
2
|
+
#= ActiveRecord::Turntable
|
3
|
+
#
|
4
|
+
# ActiveRecord Sharding Plugin
|
5
|
+
#
|
6
|
+
require 'active_record/turntable/version'
|
7
|
+
require 'active_record'
|
8
|
+
require 'active_record/fixtures'
|
9
|
+
require 'active_support/concern'
|
10
|
+
require 'active_record/turntable/error'
|
11
|
+
require 'logger'
|
12
|
+
require 'singleton'
|
13
|
+
|
14
|
+
module ActiveRecord::Turntable
|
15
|
+
extend ActiveSupport::Concern
|
16
|
+
|
17
|
+
autoload :ActiveRecordExt, 'active_record/turntable/active_record_ext'
|
18
|
+
autoload :Algorithm, 'active_record/turntable/algorithm'
|
19
|
+
autoload :Base, 'active_record/turntable/base'
|
20
|
+
autoload :Cluster, 'active_record/turntable/cluster'
|
21
|
+
autoload :Config, 'active_record/turntable/config'
|
22
|
+
autoload :Compatible, "active_record/turntable/compatible"
|
23
|
+
autoload :ConnectionProxy, 'active_record/turntable/connection_proxy'
|
24
|
+
autoload :Helpers, 'active_record/turntable/helpers'
|
25
|
+
autoload :MasterShard, 'active_record/turntable/master_shard'
|
26
|
+
autoload :Migration, 'active_record/turntable/migration'
|
27
|
+
autoload :Mixer, 'active_record/turntable/mixer'
|
28
|
+
autoload :PoolProxy, 'active_record/turntable/pool_proxy'
|
29
|
+
autoload :Rack, 'active_record/turntable/rack'
|
30
|
+
autoload :SeqShard, 'active_record/turntable/seq_shard'
|
31
|
+
autoload :Sequencer, 'active_record/turntable/sequencer'
|
32
|
+
autoload :Shard, 'active_record/turntable/shard'
|
33
|
+
|
34
|
+
included do
|
35
|
+
include ActiveRecordExt
|
36
|
+
include Base
|
37
|
+
end
|
38
|
+
|
39
|
+
module ClassMethods
|
40
|
+
DEFAULT_PATH = File.dirname(File.dirname(__FILE__))
|
41
|
+
|
42
|
+
def turntable_config_file
|
43
|
+
@@turntable_config_file ||=
|
44
|
+
File.join(defined?(::Rails) ?
|
45
|
+
::Rails.root.to_s : DEFAULT_PATH, 'config/turntable.yml')
|
46
|
+
end
|
47
|
+
|
48
|
+
def turntable_config_file=(filename)
|
49
|
+
@@turntable_config_file = filename
|
50
|
+
end
|
51
|
+
|
52
|
+
def turntable_config
|
53
|
+
ActiveRecord::Turntable::Config.instance
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
require "active_record/turntable/railtie" if defined?(Rails)
|
58
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module ActiveRecord::Turntable
|
2
|
+
module ActiveRecordExt
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
autoload :AbstractAdapter, 'active_record/turntable/active_record_ext/abstract_adapter'
|
6
|
+
autoload :CleverLoad, 'active_record/turntable/active_record_ext/clever_load'
|
7
|
+
autoload :LogSubscriber, 'active_record/turntable/active_record_ext/log_subscriber'
|
8
|
+
autoload :Persistence, 'active_record/turntable/active_record_ext/persistence'
|
9
|
+
autoload :SchemaDumper, 'active_record/turntable/active_record_ext/schema_dumper'
|
10
|
+
autoload :Sequencer, 'active_record/turntable/active_record_ext/sequencer'
|
11
|
+
autoload :Transactions, 'active_record/turntable/active_record_ext/transactions'
|
12
|
+
|
13
|
+
included do
|
14
|
+
include Transactions
|
15
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, Sequencer)
|
16
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, AbstractAdapter)
|
17
|
+
ActiveRecord::LogSubscriber.send(:include, LogSubscriber)
|
18
|
+
ActiveRecord::Persistence.send(:include, Persistence)
|
19
|
+
ActiveRecord::Relation.send(:include, CleverLoad)
|
20
|
+
ActiveRecord::VERSION::STRING < '3.1' ?
|
21
|
+
ActiveRecord::Migration.extend(ActiveRecord::Turntable::Migration) :
|
22
|
+
ActiveRecord::Migration.send(:include, ActiveRecord::Turntable::Migration)
|
23
|
+
require 'active_record/turntable/active_record_ext/fixtures'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
File without changes
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module ActiveRecord::Turntable
|
2
|
+
module ActiveRecordExt
|
3
|
+
module AbstractAdapter
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
protected
|
8
|
+
|
9
|
+
if ActiveRecord::VERSION::STRING < '3.1'
|
10
|
+
def log(sql, name)
|
11
|
+
name ||= "SQL"
|
12
|
+
@instrumenter.instrument("sql.active_record",
|
13
|
+
:sql => sql, :name => name, :connection_id => object_id,
|
14
|
+
:turntable_shard_name => turntable_shard_name) do
|
15
|
+
yield
|
16
|
+
end
|
17
|
+
rescue Exception => e
|
18
|
+
message = "#{e.class.name}: #{e.message}: #{sql} : #{turntable_shard_name}"
|
19
|
+
@logger.debug message if @logger
|
20
|
+
raise translate_exception(e, message)
|
21
|
+
end
|
22
|
+
else
|
23
|
+
def log(sql, name = "SQL", binds = [])
|
24
|
+
@instrumenter.instrument(
|
25
|
+
"sql.active_record",
|
26
|
+
:sql => sql,
|
27
|
+
:name => name,
|
28
|
+
:connection_id => object_id,
|
29
|
+
:binds => binds,
|
30
|
+
:turntable_shard_name => turntable_shard_name) { yield }
|
31
|
+
rescue Exception => e
|
32
|
+
message = "#{e.class.name}: #{e.message}: #{sql} : #{turntable_shard_name}"
|
33
|
+
@logger.debug message if @logger
|
34
|
+
exception = translate_exception(e, message)
|
35
|
+
exception.set_backtrace e.backtrace
|
36
|
+
raise exception
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def turntable_shard_name=(name)
|
42
|
+
@turntable_shard_name = name.to_s
|
43
|
+
end
|
44
|
+
|
45
|
+
def turntable_shard_name
|
46
|
+
@turntable_shard_name
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module ActiveRecord::Turntable::ActiveRecordExt
|
2
|
+
module CleverLoad
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
ActiveRecord::VERSION::STRING < '3.1' ?
|
7
|
+
include(AR30):
|
8
|
+
include(AR31)
|
9
|
+
|
10
|
+
class << ActiveRecord::Base
|
11
|
+
delegate :clever_load!, :to => :scoped
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module AR30
|
16
|
+
def clever_load!(association_name)
|
17
|
+
# load records
|
18
|
+
records = self.to_a
|
19
|
+
klass = records.first.class
|
20
|
+
reflection = klass.reflections[association_name]
|
21
|
+
|
22
|
+
if reflection
|
23
|
+
foreign_class = reflection.klass
|
24
|
+
foreign_objects = case reflection.macro
|
25
|
+
when :has_one
|
26
|
+
foreign_class.where(reflection.primary_key_name => records.map(&reflection.association_primary_key.to_sym).uniq)
|
27
|
+
when :belongs_to
|
28
|
+
foreign_class.where(reflection.association_primary_key => records.map(&reflection.primary_key_name.to_sym).uniq)
|
29
|
+
else
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
|
33
|
+
self.each do |obj|
|
34
|
+
matched_object = case reflection.macro
|
35
|
+
when :has_one
|
36
|
+
foreign_objects.find {|fo|
|
37
|
+
obj.send(reflection.association_primary_key) == fo.send(reflection.primary_key_name)
|
38
|
+
}
|
39
|
+
when :belongs_to
|
40
|
+
foreign_objects.find {|fo|
|
41
|
+
obj.send(reflection.primary_key_name) == fo.send(reflection.association_primary_key)
|
42
|
+
}
|
43
|
+
end
|
44
|
+
association_proxy = obj.send("set_#{reflection.name}_target", matched_object)
|
45
|
+
# TODO: set reverse_instance
|
46
|
+
# association_proxy.send(:set_inverse_instance, matched_object, obj)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
records
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module AR31
|
54
|
+
def clever_load!(association_name)
|
55
|
+
# load records
|
56
|
+
records = self.to_a
|
57
|
+
klass = records.first.class
|
58
|
+
reflection = klass.reflections[association_name]
|
59
|
+
|
60
|
+
if reflection
|
61
|
+
foreign_class = reflection.klass
|
62
|
+
foreign_objects = case reflection.macro
|
63
|
+
when :has_one
|
64
|
+
foreign_class.where(reflection.foreign_key => records.map(&reflection.association_primary_key.to_sym).uniq)
|
65
|
+
when :belongs_to
|
66
|
+
foreign_class.where(reflection.association_primary_key => records.map(&reflection.foreign_key.to_sym).uniq)
|
67
|
+
else
|
68
|
+
[]
|
69
|
+
end
|
70
|
+
|
71
|
+
self.each do |obj|
|
72
|
+
matched_object = case reflection.macro
|
73
|
+
when :has_one
|
74
|
+
foreign_objects.find {|fo|
|
75
|
+
obj.send(reflection.association_primary_key) == fo.send(reflection.foreign_key)
|
76
|
+
}
|
77
|
+
when :belongs_to
|
78
|
+
foreign_objects.find {|fo|
|
79
|
+
obj.send(reflection.foreign_key) == fo.send(reflection.association_primary_key)
|
80
|
+
}
|
81
|
+
end
|
82
|
+
obj.association(association_name).target = matched_object
|
83
|
+
obj.association(association_name).send(:set_inverse_instance, matched_object)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
records
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
#
|
2
|
+
# force TestFixtures to begin transaction with all shards.
|
3
|
+
#
|
4
|
+
require 'active_record/fixtures'
|
5
|
+
module ActiveRecord
|
6
|
+
class Fixtures
|
7
|
+
def self.create_fixtures(fixtures_directory, table_names, class_names = {})
|
8
|
+
table_names = [table_names].flatten.map { |n| n.to_s }
|
9
|
+
table_names.each { |n|
|
10
|
+
class_names[n.tr('/', '_').to_sym] = n.classify if n.include?('/')
|
11
|
+
}
|
12
|
+
|
13
|
+
# FIXME: Apparently JK uses this.
|
14
|
+
connection = block_given? ? yield : ActiveRecord::Base.connection
|
15
|
+
|
16
|
+
files_to_read = table_names.reject { |table_name|
|
17
|
+
fixture_is_cached?(connection, table_name)
|
18
|
+
}
|
19
|
+
|
20
|
+
unless files_to_read.empty?
|
21
|
+
connection.disable_referential_integrity do
|
22
|
+
fixtures_map = {}
|
23
|
+
|
24
|
+
fixture_files = files_to_read.map do |path|
|
25
|
+
table_name = path.tr '/', '_'
|
26
|
+
|
27
|
+
fixtures_map[path] = ActiveRecord::Fixtures.new(
|
28
|
+
connection,
|
29
|
+
table_name,
|
30
|
+
class_names[table_name.to_sym] || table_name.classify,
|
31
|
+
::File.join(fixtures_directory, path))
|
32
|
+
end
|
33
|
+
|
34
|
+
all_loaded_fixtures.update(fixtures_map)
|
35
|
+
|
36
|
+
ActiveRecord::Turntable::Base.force_transaction_all_shards!(:requires_new => true) do
|
37
|
+
fixture_files.each do |ff|
|
38
|
+
conn = ff.model_class.respond_to?(:connection) ? ff.model_class.connection : connection
|
39
|
+
table_rows = ff.table_rows
|
40
|
+
|
41
|
+
table_rows.keys.each do |table|
|
42
|
+
conn.delete "DELETE FROM #{conn.quote_table_name(table)}", 'Fixture Delete'
|
43
|
+
end
|
44
|
+
|
45
|
+
table_rows.each do |table_name,rows|
|
46
|
+
rows.each do |row|
|
47
|
+
conn.insert_fixture(row, table_name)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Cap primary key sequences to max(pk).
|
53
|
+
if connection.respond_to?(:reset_pk_sequence!)
|
54
|
+
table_names.each do |table_name|
|
55
|
+
connection.reset_pk_sequence!(table_name.tr('/', '_'))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
cache_fixtures(connection, fixtures_map)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
cached_fixtures(connection, table_names)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
module TestFixtures
|
69
|
+
def setup_fixtures
|
70
|
+
return unless !ActiveRecord::Base.configurations.blank?
|
71
|
+
|
72
|
+
if pre_loaded_fixtures && !use_transactional_fixtures
|
73
|
+
raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
|
74
|
+
end
|
75
|
+
|
76
|
+
@fixture_cache = {}
|
77
|
+
@fixture_connections = []
|
78
|
+
@@already_loaded_fixtures ||= {}
|
79
|
+
|
80
|
+
# Load fixtures once and begin transaction.
|
81
|
+
if run_in_transaction?
|
82
|
+
if @@already_loaded_fixtures[self.class]
|
83
|
+
@loaded_fixtures = @@already_loaded_fixtures[self.class]
|
84
|
+
else
|
85
|
+
@loaded_fixtures = load_fixtures
|
86
|
+
@@already_loaded_fixtures[self.class] = @loaded_fixtures
|
87
|
+
end
|
88
|
+
ActiveRecord::Base.force_connect_all_shards!
|
89
|
+
@fixture_connections = enlist_fixture_connections
|
90
|
+
@fixture_connections.each do |connection|
|
91
|
+
connection.increment_open_transactions
|
92
|
+
connection.transaction_joinable = false
|
93
|
+
connection.begin_db_transaction
|
94
|
+
end
|
95
|
+
# Load fixtures for every test.
|
96
|
+
else
|
97
|
+
ActiveRecord::Fixtures.reset_cache
|
98
|
+
@@already_loaded_fixtures[self.class] = nil
|
99
|
+
@loaded_fixtures = load_fixtures
|
100
|
+
end
|
101
|
+
|
102
|
+
# Instantiate fixtures for every test if requested.
|
103
|
+
instantiate_fixtures if use_instantiated_fixtures
|
104
|
+
end
|
105
|
+
|
106
|
+
def enlist_fixture_connections
|
107
|
+
ActiveRecord::Base.connection_handler.connection_pools.values.map(&:connection) +
|
108
|
+
ActiveRecord::Base.turntable_connections.values.map(&:connection)
|
109
|
+
end
|
110
|
+
|
111
|
+
def teardown_fixtures
|
112
|
+
return unless defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
|
113
|
+
|
114
|
+
unless run_in_transaction?
|
115
|
+
ActiveRecord::Fixtures.reset_cache
|
116
|
+
end
|
117
|
+
|
118
|
+
# Rollback changes if a transaction is active.
|
119
|
+
if run_in_transaction?
|
120
|
+
@fixture_connections.each do |connection|
|
121
|
+
if connection.open_transactions != 0
|
122
|
+
connection.rollback_db_transaction
|
123
|
+
connection.decrement_open_transactions
|
124
|
+
end
|
125
|
+
end
|
126
|
+
@fixture_connections.clear
|
127
|
+
end
|
128
|
+
ActiveRecord::Base.clear_active_connections!
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module ActiveRecord::Turntable
|
2
|
+
module ActiveRecordExt
|
3
|
+
module LogSubscriber
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
if ActiveRecord::VERSION::STRING < '3.1'
|
8
|
+
def sql(event)
|
9
|
+
self.class.runtime += event.duration
|
10
|
+
return unless logger.debug?
|
11
|
+
|
12
|
+
name = '%s (%.1fms)' % [event.payload[:name], event.duration]
|
13
|
+
shard = '[Shard: %s]' % (event.payload[:turntable_shard_name] ? event.payload[:turntable_shard_name] : nil)
|
14
|
+
sql = event.payload[:sql].squeeze(' ')
|
15
|
+
|
16
|
+
if odd?
|
17
|
+
name = color(name, ActiveRecord::LogSubscriber::CYAN, true)
|
18
|
+
shard = color(shard, ActiveRecord::LogSubscriber::CYAN, true)
|
19
|
+
sql = color(sql, nil, true)
|
20
|
+
else
|
21
|
+
name = color(name, ActiveRecord::LogSubscriber::MAGENTA, true)
|
22
|
+
shard = color(shard, ActiveRecord::LogSubscriber::MAGENTA, true)
|
23
|
+
end
|
24
|
+
|
25
|
+
debug " #{name} #{shard} #{sql}"
|
26
|
+
end
|
27
|
+
|
28
|
+
else
|
29
|
+
def sql(event)
|
30
|
+
self.class.runtime += event.duration
|
31
|
+
return unless logger.debug?
|
32
|
+
|
33
|
+
payload = event.payload
|
34
|
+
|
35
|
+
return if 'SCHEMA' == payload[:name]
|
36
|
+
|
37
|
+
name = '%s (%.1fms)' % [payload[:name], event.duration]
|
38
|
+
shard = '[Shard: %s]' % (event.payload[:turntable_shard_name] ? event.payload[:turntable_shard_name] : nil)
|
39
|
+
sql = payload[:sql].squeeze(' ')
|
40
|
+
binds = nil
|
41
|
+
|
42
|
+
unless (payload[:binds] || []).empty?
|
43
|
+
binds = " " + payload[:binds].map { |col,v|
|
44
|
+
[col.name, v]
|
45
|
+
}.inspect
|
46
|
+
end
|
47
|
+
|
48
|
+
if odd?
|
49
|
+
name = color(name, ActiveRecord::LogSubscriber::CYAN, true)
|
50
|
+
shard = color(shard, ActiveRecord::LogSubscriber::CYAN, true)
|
51
|
+
sql = color(sql, nil, true)
|
52
|
+
else
|
53
|
+
name = color(name, ActiveRecord::LogSubscriber::MAGENTA, true)
|
54
|
+
shard = color(shard, ActiveRecord::LogSubscriber::MAGENTA, true)
|
55
|
+
end
|
56
|
+
|
57
|
+
debug " #{name} #{shard} #{sql}#{binds}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|