Skip to content

Commit 10c0b59

Browse files
authored
Merge pull request rails#43372 from eileencodes/add-option-to-lazy-load-schema-cache
Add ability to lazily load the schema cache on connection
2 parents 9320c85 + d38578a commit 10c0b59

File tree

7 files changed

+94
-1
lines changed

7 files changed

+94
-1
lines changed

activerecord/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
* Add option to lazily load the schema cache on the connection.
2+
3+
Previously, the only way to load the schema cache in Active Record was through the Railtie on boot. This option provides the ability to load the schema cache on the connection after it's been established. Loading the cache lazily on the connection can be beneficial for Rails applications that use multiple databases because it will load the cache at the time the connection is established. Currently Railties doesn't have access to the connections before boot.
4+
5+
To use the cache, set `config.active_record.lazily_load_schema_cache = true` in your application configuration. In addition a `schema_cache_path` should be set in your database configuration if you don't want to use the default "db/schema_cache.yml" path.
6+
7+
*Eileen M. Uchitelle*
8+
19
* Allow automatic `inverse_of` detection for associations with scopes.
210

311
Automatic `inverse_of` detection now works for associations with scopes. For

activerecord/lib/active_record.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,12 @@ module Tasks
170170
autoload :TestDatabases, "active_record/test_databases"
171171
autoload :TestFixtures, "active_record/fixtures"
172172

173+
# Lazily load the schema cache. This option will load the schema cache
174+
# when a connection is established rather than on boot. If set,
175+
# +config.active_record.use_schema_cache_dump+ will be set to false.
176+
singleton_class.attr_accessor :lazily_load_schema_cache
177+
self.lazily_load_schema_cache = false
178+
173179
# A list of tables or regex's to match tables to ignore when
174180
# dumping the schema cache. For example if this is set to +[/^_/]+
175181
# the schema cache will not dump tables named with an underscore.

activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ def get_schema_cache(connection)
1919
def set_schema_cache(cache)
2020
self.schema_cache = cache
2121
end
22+
23+
def lazily_set_schema_cache
24+
return unless ActiveRecord.lazily_load_schema_cache
25+
26+
cache = SchemaCache.load_from(db_config.lazy_schema_cache_path)
27+
set_schema_cache(cache)
28+
end
2229
end
2330

2431
class NullPool # :nodoc:
@@ -147,6 +154,8 @@ def initialize(pool_config)
147154

148155
@async_executor = build_async_executor
149156

157+
lazily_set_schema_cache
158+
150159
@reaper = Reaper.new(self, db_config.reaping_frequency)
151160
@reaper.run
152161
end

activerecord/lib/active_record/database_configurations/hash_config.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,18 @@ def schema_cache_path
109109
configuration_hash[:schema_cache_path]
110110
end
111111

112+
def default_schema_cache_path
113+
"db/schema_cache.yml"
114+
end
115+
116+
def lazy_schema_cache_path
117+
schema_cache_path || default_schema_cache_path
118+
end
119+
120+
def primary? # :nodoc:
121+
Base.configurations.primary?(name)
122+
end
123+
112124
# Determines whether to dump the schema for a database.
113125
def schema_dump
114126
configuration_hash.fetch(:schema_dump, true)

activerecord/lib/active_record/railtie.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ class Railtie < Rails::Railtie # :nodoc:
130130
initializer "active_record.check_schema_cache_dump" do
131131
check_schema_cache_dump_version = config.active_record.check_schema_cache_dump_version
132132

133-
if config.active_record.use_schema_cache_dump
133+
if config.active_record.use_schema_cache_dump && !config.active_record.lazily_load_schema_cache
134134
config.after_initialize do |app|
135135
ActiveSupport.on_load(:active_record) do
136136
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first

activerecord/test/cases/connection_adapters/schema_cache_test.rb

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,54 @@ def test_clear_data_source_cache
319319
assert_not @cache.columns_hash?("posts")
320320
end
321321

322+
unless in_memory_db?
323+
def test_when_lazily_load_schema_cache_is_set_cache_is_lazily_populated_when_est_connection
324+
tempfile = Tempfile.new(["schema_cache-", ".yml"])
325+
original_config = ActiveRecord::Base.connection_db_config
326+
new_config = original_config.configuration_hash.merge(schema_cache_path: tempfile.path)
327+
328+
ActiveRecord::Base.establish_connection(new_config)
329+
330+
# cache is empty
331+
assert_empty ActiveRecord::Base.connection.schema_cache.instance_variable_get(:@primary_keys)
332+
assert_empty ActiveRecord::Base.connection.schema_cache.instance_variable_get(:@data_sources)
333+
assert_empty ActiveRecord::Base.connection.schema_cache.instance_variable_get(:@indexes)
334+
335+
# calling dump_to will load data sources, but not the rest of the cache
336+
# so we need to set the cache manually. This essentially mimics the behavior
337+
# of the Railtie.
338+
cache = SchemaCache.new(ActiveRecord::Base.connection)
339+
cache.dump_to(tempfile.path)
340+
ActiveRecord::Base.connection.schema_cache = cache
341+
342+
assert File.exist?(tempfile)
343+
assert_not_empty ActiveRecord::Base.connection.schema_cache.instance_variable_get(:@primary_keys)
344+
assert_not_empty ActiveRecord::Base.connection.schema_cache.instance_variable_get(:@data_sources)
345+
assert_not_empty ActiveRecord::Base.connection.schema_cache.instance_variable_get(:@indexes)
346+
347+
# assert cache is empty on new connection
348+
ActiveRecord::Base.establish_connection(new_config)
349+
350+
assert File.exist?(tempfile)
351+
assert_empty ActiveRecord::Base.connection.schema_cache.instance_variable_get(:@primary_keys)
352+
assert_empty ActiveRecord::Base.connection.schema_cache.instance_variable_get(:@data_sources)
353+
assert_empty ActiveRecord::Base.connection.schema_cache.instance_variable_get(:@indexes)
354+
355+
# cache is lazily loaded when lazily loading is on
356+
old_config = ActiveRecord.lazily_load_schema_cache
357+
ActiveRecord.lazily_load_schema_cache = true
358+
ActiveRecord::Base.establish_connection(new_config)
359+
360+
assert File.exist?(tempfile)
361+
assert_not_empty ActiveRecord::Base.connection.schema_cache.instance_variable_get(:@primary_keys)
362+
assert_not_empty ActiveRecord::Base.connection.schema_cache.instance_variable_get(:@data_sources)
363+
assert_not_empty ActiveRecord::Base.connection.schema_cache.instance_variable_get(:@indexes)
364+
ensure
365+
ActiveRecord.lazily_load_schema_cache = old_config
366+
ActiveRecord::Base.establish_connection(:arunit)
367+
end
368+
end
369+
322370
private
323371
def schema_dump_path
324372
"#{ASSETS_ROOT}/schema_dump_5_1.yml"

activerecord/test/cases/database_configurations/hash_config_test.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,16 @@ def test_database_tasks_overrides_with_value
135135
config = HashConfig.new("default_env", "primary", database_tasks: "str")
136136
assert_equal true, config.database_tasks?
137137
end
138+
139+
def test_schema_cache_path_default_for_primary
140+
config = HashConfig.new("default_env", "primary", {})
141+
assert_equal "db/schema_cache.yml", config.default_schema_cache_path
142+
end
143+
144+
def test_schema_cache_path_configuration_hash
145+
config = HashConfig.new("default_env", "primary", { schema_cache_path: "db/config_schema_cache.yml" })
146+
assert_equal "db/config_schema_cache.yml", config.schema_cache_path
147+
end
138148
end
139149
end
140150
end

0 commit comments

Comments
 (0)