diff options
author | Matthew Draper <matthew@trebex.net> | 2016-11-10 14:18:40 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-11-10 14:18:40 -0500 |
commit | cac3be6341f95c9a347d62173a4a130d1e42141b (patch) | |
tree | 0e24a0271cbe5ab2e50615685cb8c51093705a50 | |
parent | c58083584c3a7a2e29f609760547e10e46d56a33 (diff) | |
parent | 3c785bdceed4bdf67708197aa687ced6728d77f3 (diff) | |
download | rails-cac3be6341f95c9a347d62173a4a130d1e42141b.tar.gz rails-cac3be6341f95c9a347d62173a4a130d1e42141b.tar.bz2 rails-cac3be6341f95c9a347d62173a4a130d1e42141b.zip |
Merge pull request #26978 from matthewd/query-cache-pool
Configure query caching (per thread) on the connection pool
4 files changed, 73 insertions, 4 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index 9727d63883..5d8546916e 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -307,6 +307,7 @@ module ActiveRecord end include MonitorMixin + include QueryCache::ConnectionPoolConfiguration attr_accessor :automatic_reconnect, :checkout_timeout, :schema_cache attr_reader :spec, :connections, :size, :reaper diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb index d4229dfdba..7eab7de5d3 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb @@ -4,6 +4,8 @@ module ActiveRecord class << self def included(base) #:nodoc: dirties_query_cache base, :insert, :update, :delete, :rollback_to_savepoint, :rollback_db_transaction + + base.set_callback :checkout, :after, :configure_query_cache! base.set_callback :checkin, :after, :disable_query_cache! end @@ -19,6 +21,27 @@ module ActiveRecord end end + module ConnectionPoolConfiguration + def initialize(*) + super + @query_cache_enabled = Concurrent::Map.new { false } + end + + def enable_query_cache! + @query_cache_enabled[connection_cache_key(Thread.current)] = true + connection.enable_query_cache! if active_connection? + end + + def disable_query_cache! + @query_cache_enabled.delete connection_cache_key(Thread.current) + connection.disable_query_cache! if active_connection? + end + + def query_cache_enabled + @query_cache_enabled[connection_cache_key(Thread.current)] + end + end + attr_reader :query_cache, :query_cache_enabled def initialize(*) @@ -98,6 +121,10 @@ module ActiveRecord def locked?(arel) arel.respond_to?(:locked) && arel.locked end + + def configure_query_cache! + enable_query_cache! if pool.query_cache_enabled + end end end end diff --git a/activerecord/lib/active_record/query_cache.rb b/activerecord/lib/active_record/query_cache.rb index 23dae825c2..ec246e97bc 100644 --- a/activerecord/lib/active_record/query_cache.rb +++ b/activerecord/lib/active_record/query_cache.rb @@ -24,12 +24,19 @@ module ActiveRecord end def self.run - ActiveRecord::Base.connection.enable_query_cache! + caching_pool = ActiveRecord::Base.connection_pool + caching_was_enabled = caching_pool.query_cache_enabled + + caching_pool.enable_query_cache! + + [caching_pool, caching_was_enabled] end - def self.complete(_) - unless ActiveRecord::Base.connected? && ActiveRecord::Base.connection.transaction_open? - ActiveRecord::Base.clear_active_connections! + def self.complete((caching_pool, caching_was_enabled)) + caching_pool.disable_query_cache! unless caching_was_enabled + + ActiveRecord::Base.connection_handler.connection_pool_list.each do |pool| + pool.release_connection if pool.active_connection? && !pool.connection.transaction_open? end end diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index 5b0477aabe..90054ce83d 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -313,6 +313,40 @@ class QueryCacheTest < ActiveRecord::TestCase end end + def test_query_cache_does_not_establish_connection_if_unconnected + ActiveRecord::Base.clear_active_connections! + refute ActiveRecord::Base.connection_handler.active_connections? # sanity check + + middleware { + refute ActiveRecord::Base.connection_handler.active_connections?, "QueryCache forced ActiveRecord::Base to establish a connection in setup" + }.call({}) + + refute ActiveRecord::Base.connection_handler.active_connections?, "QueryCache forced ActiveRecord::Base to establish a connection in cleanup" + end + + def test_query_cache_is_enabled_on_connections_established_after_middleware_runs + ActiveRecord::Base.clear_active_connections! + refute ActiveRecord::Base.connection_handler.active_connections? # sanity check + + middleware { + assert ActiveRecord::Base.connection.query_cache_enabled, "QueryCache did not get lazily enabled" + }.call({}) + end + + def test_query_caching_is_local_to_the_current_thread + ActiveRecord::Base.clear_active_connections! + + middleware { + assert ActiveRecord::Base.connection_pool.query_cache_enabled + assert ActiveRecord::Base.connection.query_cache_enabled + + Thread.new { + refute ActiveRecord::Base.connection_pool.query_cache_enabled + refute ActiveRecord::Base.connection.query_cache_enabled + }.join + }.call({}) + end + private def middleware(&app) executor = Class.new(ActiveSupport::Executor) |