Skip to content

Commit 1d0b396

Browse files
committed
Clear all threads query cache when a connection is pinned
Ref: Shopify/maintenance_tasks#983 (comment) Ref: rails#51151 Now that query caches are owned by the pool, and assigned on connections during checkout, when running multithreaded code inside transactional tests (typically system tests), the two threads uses the same connection but not the same cache. So it's important that we do clear the caches for all threads when a connection is pinned.
1 parent 3ecc269 commit 1d0b396

File tree

2 files changed

+42
-1
lines changed

2 files changed

+42
-1
lines changed

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,14 @@ def query_cache_enabled
129129
end
130130

131131
def clear_query_cache
132-
query_cache.clear
132+
if @pinned_connection
133+
# With transactional fixtures, and especially systems test
134+
# another thread may use the same connection, but with a different
135+
# query cache. So we must clear them all.
136+
@thread_query_caches.each_value(&:clear)
137+
else
138+
query_cache.clear
139+
end
133140
end
134141

135142
private

activerecord/test/cases/query_cache_test.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,40 @@ def test_clear_query_cache_is_called_on_all_connections
672672
end
673673
end
674674

675+
test "query cache is cleared for all thread when a connection is shared" do
676+
ActiveRecord::Base.connection_pool.pin_connection!(ActiveSupport::IsolatedExecutionState.context)
677+
678+
begin
679+
assert_cache :off
680+
ActiveRecord::Base.connection.enable_query_cache!
681+
assert_cache :clean
682+
683+
Post.first
684+
assert_cache :dirty
685+
686+
thread_a = Thread.new do
687+
middleware { |env|
688+
assert_cache :dirty # The cache is shared with the main thread
689+
690+
Post.first
691+
assert_cache :dirty
692+
693+
Post.delete_all
694+
695+
assert_cache :clean
696+
697+
[200, {}, nil]
698+
}.call({})
699+
end
700+
701+
thread_a.join
702+
703+
assert_cache :clean
704+
ensure
705+
ActiveRecord::Base.connection_pool.unpin_connection!
706+
end
707+
end
708+
675709
private
676710
def with_temporary_connection_pool(&block)
677711
pool_config = ActiveRecord::Base.connection.pool.pool_config

0 commit comments

Comments
 (0)