DEV: Remove cache PG connection type map freedom patch (#26153)

Why this change?

Previously, we identified that ActiveRecord's PostgreSQL adapter
executes 3 db queries each time a new connection is created. The 3 db
queries was identified when we looked at the `pg_stats_statement` table
on one of our multisite production cluster. At that time, the hypothesis
is that because we were agressively reaping and creating connections,
the db queries executed each time a connection is created is wasting
resources on our database servers. However, we didn't see any the needle
move much on our servers after deploying the patch so we have decided to
drop this patch as it makes it harder for us to upgrade ActiveRecord in
the future.
This commit is contained in:
Alan Guo Xiang Tan 2024-03-13 13:28:06 +08:00 committed by GitHub
parent e7f539df10
commit 1f71db426e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 0 additions and 74 deletions

View File

@ -1,50 +0,0 @@
# frozen_string_literal: true
# This patch has been added to address the problems identified in https://github.com/rails/rails/issues/35311. For every,
# new connection created using the PostgreSQL adapter, 3 queries are executed to fetch the type map adding about 1ms overhead
# to every connection creation. In multisite clusters where connections are reaped more aggressively, the 3 queries executed
# accounts for a significant portion of CPU usage on the PostgreSQL cluster. This patch works around the problem by
# caching the type map in a class level attribute to reuse across connections.
#
# The latest attempt to fix the problem in Rails is in https://github.com/rails/rails/pull/46409 but it has gone stale.
module FreedomPatches
module PostgreSQLAdapter
# Definition as of writing: https://github.com/rails/rails/blob/5bf5344521a6f305ca17e0004273322a0a26f50a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L316
def reload_type_map
self.class.type_map = nil
super
end
# Definition as of writing: https://github.com/rails/rails/blob/5bf5344521a6f305ca17e0004273322a0a26f50a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L614
def initialize_type_map(m = type_map)
if !self.class.type_map.nil?
@type_map = self.class.type_map
else
super.tap { self.class.type_map = @type_map }
end
end
end
module PostgreSQLAdapterClassMethods
extend ActiveSupport::Concern
included do
@type_map_mutex = Mutex.new
@type_map = nil
def self.type_map
@type_map_mutex.synchronize { @type_map }
end
def self.type_map=(type_map)
@type_map_mutex.synchronize { @type_map = type_map }
end
end
end
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(FreedomPatches::PostgreSQLAdapter)
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.include(
FreedomPatches::PostgreSQLAdapterClassMethods,
)
end

View File

@ -1,24 +0,0 @@
# frozen_string_literal: true
RSpec.describe "Caching PostgreSQL connection type map" do
it "caches the type map and avoid querying the database for type map information on every new connection" do
expect(ActiveRecord::Base.connection.class.type_map).to be_present
pg_type_queries = []
subscriber =
ActiveSupport::Notifications.subscribe("sql.active_record") do |*, payload|
if payload[:name] == "SCHEMA"
sql = payload[:sql]
pg_type_queries.push(sql) if sql.include?("pg_type")
end
end
expect do
ActiveRecord::Base.clear_active_connections!
ActiveRecord::Base.establish_connection
end.to change { pg_type_queries.length }.by(1) # There is some default pg_type query but if stuff was not cached, we would see 4 queries here
ensure
ActiveSupport::Notifications.unsubscribe(subscriber)
end
end