aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
authorAaron Patterson <aaron.patterson@gmail.com>2012-03-07 16:44:50 -0800
committerAaron Patterson <aaron.patterson@gmail.com>2012-03-07 16:44:50 -0800
commit447ecb08ca1bab594198282237c4e9a027f7a3f4 (patch)
treef294ae7de0f0246eca655ac6291b2392566f28d3 /activerecord/lib
parentb700153507b7d539a57a6e3bcf03c84776795051 (diff)
parent46c12172fe651980438e0b0663e2005cf3132079 (diff)
downloadrails-447ecb08ca1bab594198282237c4e9a027f7a3f4.tar.gz
rails-447ecb08ca1bab594198282237c4e9a027f7a3f4.tar.bz2
rails-447ecb08ca1bab594198282237c4e9a027f7a3f4.zip
Merge pull request #5162 from kennyj/schema_cache_dump
[Proposal] Schema cache dump
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/schema_cache.rb64
-rw-r--r--activerecord/lib/active_record/railtie.rb17
-rw-r--r--activerecord/lib/active_record/railties/databases.rake19
4 files changed, 88 insertions, 17 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 594649189d..767c99de4c 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -86,6 +86,11 @@ module ActiveRecord
end
end
+ def schema_cache=(cache)
+ cache.connection = self
+ @schema_cache = cache
+ end
+
def expire
@in_use = false
end
diff --git a/activerecord/lib/active_record/connection_adapters/schema_cache.rb b/activerecord/lib/active_record/connection_adapters/schema_cache.rb
index 962718da56..aad1f9a7ef 100644
--- a/activerecord/lib/active_record/connection_adapters/schema_cache.rb
+++ b/activerecord/lib/active_record/connection_adapters/schema_cache.rb
@@ -1,26 +1,17 @@
module ActiveRecord
module ConnectionAdapters
class SchemaCache
- attr_reader :columns, :columns_hash, :primary_keys, :tables
- attr_reader :connection
+ attr_reader :columns, :columns_hash, :primary_keys, :tables, :version
+ attr_accessor :connection
def initialize(conn)
@connection = conn
- @tables = {}
- @columns = Hash.new do |h, table_name|
- h[table_name] = conn.columns(table_name)
- end
-
- @columns_hash = Hash.new do |h, table_name|
- h[table_name] = Hash[columns[table_name].map { |col|
- [col.name, col]
- }]
- end
-
- @primary_keys = Hash.new do |h, table_name|
- h[table_name] = table_exists?(table_name) ? conn.primary_key(table_name) : nil
- end
+ @columns = {}
+ @columns_hash = {}
+ @primary_keys = {}
+ @tables = {}
+ prepare_default_proc
end
# A cached lookup for table existence.
@@ -30,12 +21,22 @@ module ActiveRecord
@tables[name] = connection.table_exists?(name)
end
+ # Add internal cache for table with +table_name+.
+ def add(table_name)
+ if table_exists?(table_name)
+ @primary_keys[table_name]
+ @columns[table_name]
+ @columns_hash[table_name]
+ end
+ end
+
# Clears out internal caches
def clear!
@columns.clear
@columns_hash.clear
@primary_keys.clear
@tables.clear
+ @version = nil
end
# Clear out internal caches for table with +table_name+.
@@ -45,6 +46,37 @@ module ActiveRecord
@primary_keys.delete table_name
@tables.delete table_name
end
+
+ def marshal_dump
+ # if we get current version during initialization, it happens stack over flow.
+ @version = ActiveRecord::Migrator.current_version
+ [@version] + [:@columns, :@columns_hash, :@primary_keys, :@tables].map do |val|
+ self.instance_variable_get(val).inject({}) { |h, v| h[v[0]] = v[1]; h }
+ end
+ end
+
+ def marshal_load(array)
+ @version, @columns, @columns_hash, @primary_keys, @tables = array
+ prepare_default_proc
+ end
+
+ private
+
+ def prepare_default_proc
+ @columns.default_proc = Proc.new do |h, table_name|
+ h[table_name] = connection.columns(table_name)
+ end
+
+ @columns_hash.default_proc = Proc.new do |h, table_name|
+ h[table_name] = Hash[columns[table_name].map { |col|
+ [col.name, col]
+ }]
+ end
+
+ @primary_keys.default_proc = Proc.new do |h, table_name|
+ h[table_name] = table_exists?(table_name) ? connection.primary_key(table_name) : nil
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index 058dd58efb..516c450f85 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -107,7 +107,7 @@ module ActiveRecord
config.watchable_files.concat ["#{app.root}/db/schema.rb", "#{app.root}/db/structure.sql"]
end
- config.after_initialize do
+ config.after_initialize do |app|
ActiveSupport.on_load(:active_record) do
ActiveRecord::Base.instantiate_observers
@@ -115,6 +115,21 @@ module ActiveRecord
ActiveRecord::Base.instantiate_observers
end
end
+
+ ActiveSupport.on_load(:active_record) do
+ if app.config.use_schema_cache_dump
+ filename = File.join(app.config.paths["db"].first, "schema_cache.dump")
+ if File.file?(filename)
+ cache = Marshal.load(open(filename, 'rb') { |f| f.read })
+ if cache.version == ActiveRecord::Migrator.current_version
+ ActiveRecord::Base.connection.schema_cache = cache
+ else
+ warn "schema_cache.dump is expired. Current version is #{ActiveRecord::Migrator.current_version}, but cache version is #{cache.version}."
+ end
+ end
+ end
+ end
+
end
end
end
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index cf0092e0e3..f26989ae57 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -372,6 +372,25 @@ db_namespace = namespace :db do
task :load_if_ruby => 'db:create' do
db_namespace["schema:load"].invoke if ActiveRecord::Base.schema_format == :ruby
end
+
+ namespace :cache do
+ desc 'Create a db/schema_cache.dump file.'
+ task :dump => :environment do
+ con = ActiveRecord::Base.connection
+ filename = File.join(Rails.application.config.paths["db"].first, "schema_cache.dump")
+
+ con.schema_cache.clear!
+ con.tables.each { |table| con.schema_cache.add(table) }
+ open(filename, 'wb') { |f| f.write(Marshal.dump(con.schema_cache)) }
+ end
+
+ desc 'Clear a db/schema_cache.dump file.'
+ task :clear => :environment do
+ filename = File.join(Rails.application.config.paths["db"].first, "schema_cache.dump")
+ FileUtils.rm(filename) if File.exists?(filename)
+ end
+ end
+
end
namespace :structure do