Permalink
Browse files

Database adapters use a statement pool.

Database adapters use a statement pool for limiting the number of open
prepared statments on the database.  The limit defaults to 1000, but can
be adjusted in your database config by changing 'statement_limit'.
  • Loading branch information...
1 parent b37112f commit 7c04e167854d0c473a9c3f70eb4434b0438402b2 @tenderlove tenderlove committed Sep 6, 2011
@@ -217,7 +217,8 @@ def initialize(connection, logger, connection_options, config)
@connection_options, @config = connection_options, config
@quoted_column_names, @quoted_table_names = {}, {}
@statements = {}
- @statements = StatementPool.new(@connection)
+ @statements = StatementPool.new(@connection,
+ config.fetch(:statement_limit) { 1000 })
@client_encoding = nil
connect
end
@@ -1,6 +1,7 @@
require 'active_record/connection_adapters/abstract_adapter'
require 'active_support/core_ext/kernel/requires'
require 'active_support/core_ext/object/blank'
+require 'active_record/connection_adapters/statement_pool'
# Make sure we're using pg high enough for PGResult#values
gem 'pg', '~> 0.11'
@@ -247,6 +248,43 @@ def supports_statement_cache?
true
end
+ class StatementPool < ConnectionAdapters::StatementPool
+ def initialize(connection, max)
+ super
+ @counter = 0
+ @cache = {}
+ end
+
+ def each(&block); @cache.each(&block); end
+ def key?(key); @cache.key?(key); end
+ def [](key); @cache[key]; end
+ def length; @cache.length; end
+
+ def next_key
+ "a#{@counter + 1}"
+ end
+
+ def []=(sql, key)
+ while @max <= @cache.size
+ dealloc(@cache.shift.last)
+ end
+ @counter += 1
+ @cache[sql] = key
+ end
+
+ def clear
+ @cache.each_value do |stmt_key|
+ dealloc stmt_key
+ end
+ @cache.clear
+ end
+
+ private
+ def dealloc(key)
+ @connection.query "DEALLOCATE #{key}"
+ end
+ end
+
# Initializes and connects a PostgreSQL adapter.
def initialize(connection, logger, connection_parameters, config)
super(connection, logger)
@@ -255,9 +293,10 @@ def initialize(connection, logger, connection_parameters, config)
# @local_tz is initialized as nil to avoid warnings when connect tries to use it
@local_tz = nil
@table_alias_length = nil
- @statements = {}
connect
+ @statements = StatementPool.new @connection,
+ config.fetch(:statement_limit) { 1000 }
if postgresql_version < 80200
raise "Your version of PostgreSQL (#{postgresql_version}) is too old, please upgrade!"
@@ -272,9 +311,6 @@ def self.visitor_for(pool) # :nodoc:
# Clears the prepared statements cache.
def clear_cache!
- @statements.each_value do |value|
- @connection.query "DEALLOCATE #{value}"
- end
@statements.clear
end
@@ -965,7 +1001,7 @@ def exec_no_cache(sql, binds)
def exec_cache(sql, binds)
unless @statements.key? sql
- nextkey = "a#{@statements.length + 1}"
+ nextkey = @statements.next_key
@connection.prepare nextkey, sql
@statements[sql] = nextkey
end
@@ -51,7 +51,7 @@ def <=>(version_string)
end
class StatementPool < ConnectionAdapters::StatementPool
- def initialize(connection, max = 1000)
+ def initialize(connection, max)
super
@cache = {}
end
@@ -83,7 +83,8 @@ def dealloc(stmt)
def initialize(connection, logger, config)
super(connection, logger)
- @statements = StatementPool.new(@connection)
+ @statements = StatementPool.new(@connection,
+ config.fetch(:statement_limit) { 1000 })
@config = config
end

0 comments on commit 7c04e16

Please sign in to comment.