cartodb-4.42/lib/cartodb/connection_pool.rb
2024-04-06 05:25:13 +00:00

98 lines
2.9 KiB
Ruby

require 'fiber'
require 'cartodb/sequel_connection_helper'
module CartoDB
class ConnectionPool
include CartoDB::SequelConnectionHelper
# Until migration to AR is done
MAX_POOL_SIZE = 600
def initialize
@pool = {}
end
# Intended only for testing
def all
@pool
end
def fetch(configuration, &block)
conn = nil
if @pool[connection_id(configuration)]
Rails.logger.debug "[pool] Found a connection for #{connection_id(configuration)} (#{@pool.keys.size})"
@pool[connection_id(configuration)][:last_accessed] = Time.now
conn = @pool[connection_id(configuration)][:connection]
else
conn = create_new_connection(configuration, &block)
end
# This conn may be still broken after 3 tries
return conn
end
def max_pool_size?
if @pool.size >= MAX_POOL_SIZE
#close_connections!
close_oldest_connection!
end
end
def create_new_connection(configuration, &block)
max_pool_size?
connection = yield
@pool[connection_id(configuration)] = { :connection => connection, :last_accessed => Time.now }
Rails.logger.debug "[pool] Creating a new connection for #{connection_id(configuration)} (#{@pool.keys.size})"
connection
end
def close_connections!(db=nil)
newpool = {}
@pool.each do |id, conn|
if ! db || ( id.start_with? "#{db}:" )
Rails.logger.debug "[pool] Dropping connection #{id}"
close_connection(conn[:connection], id)
else
Rails.logger.debug "[pool] Not dropping connection #{id}"
newpool[id] = conn
end
end
@pool = newpool
end
def close_oldest_connection!
older = nil
oldest_access = nil
@pool.each do |connection_id, conn|
if oldest_access.nil? || conn[:last_accessed] < oldest_access
oldest_access = conn[:last_accessed]
older = connection_id
end
end
close_connection(@pool[older][:connection], older)
@pool.delete(older)
end
private
def close_connection(connection, id)
if id.end_with?('sequel')
close_sequel_connection(connection)
else
connection.disconnect!
end
end
def connection_id(configuration)
# TODO: Due to migration from Sequel to ActiveRecord, afterwards can be used with only symbols
host = configuration.fetch(:host, configuration['host'])
database = configuration.fetch(:database, configuration['database'])
username = configuration.fetch(:username, configuration['username'])
orm = configuration.fetch(:orm, 'sequel')
port = configuration.fetch(:port, configuration['port'])
# Be aware of close_connections! and close_connection logic when prepending or appending new
# parameters to the id.
"#{host}:#{database}:#{port}:#{username}:#{orm}"
end
end
end