Class: Sequel::Mysql2::Synchrony::ConnectionPool

Inherits:
ConnectionPool
  • Object
show all
Defined in:
lib/my-sequel-synchrony/connection_pool.rb

Overview

A Fiber-aware Sequel::ConnectionPool that works with EM::Synchrony! This version is not shard-aware.

Constant Summary collapse

DEFAULT_MAX_SIZE =
4

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}, &block) ⇒ ConnectionPool

The following additional options are respected:

  • :connection_handling - Set how to handle available connections. By default, uses a a stack for performance. Can be set to :queue to use a queue, which reduces the chances of connections becoming stale. Can also be set to :disconnect, which will disconnect after every query or transaction.

  • :max_connections - The maximum number of connections the connection pool will open (default 4)

Raises:

  • (Sequel::Error)


23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/my-sequel-synchrony/connection_pool.rb', line 23

def initialize(opts = {}, &block)
  super
  @max_size = Integer(opts[:max_connections] || DEFAULT_MAX_SIZE)
  raise(Sequel::Error, ':max_connections must be positive') if @max_size < 1
  @connection_handling = opts[:connection_handling]
  @available_connections = []
  @waiting_fibers = []
  @in_use_connections = {}
  @pending_disconnects = Set.new
  # TODO(ilyam): remove the debug prints once this is rock-solid and has good tests etc.
  @debug = opts[:debug]
end

Instance Attribute Details

#max_sizeObject (readonly)

The maximum number of connections this pool will create (per shard/server if sharding).



11
12
13
# File 'lib/my-sequel-synchrony/connection_pool.rb', line 11

def max_size
  @max_size
end

Instance Method Details

#disconnect(opts = {}, &block) ⇒ Object

Removes all connections currently available, optionally yielding each connection to the given block. This method has the effect of disconnecting from the database, assuming that no connections are currently being used. Schedules all in-use connections to be disconnected next time they are released into the available pool.

After a disconnect, when connections are requested using #hold, the connection pool will create new connections to the database.



49
50
51
52
53
54
55
56
57
# File 'lib/my-sequel-synchrony/connection_pool.rb', line 49

def disconnect(opts={}, &block)
  if_debug? { dputs "disconnect(opts = #{opts.inspect})! Current fiber = #{Fiber.current.inspect}" }
  connections_to_disconnect, @available_connections = @available_connections, []
  @pending_disconnects += @in_use_connections.values.to_set
  block ||= @disconnection_proc
  connections_to_disconnect.each do |conn|
    disconnect_conn(conn, opts, &block)
  end
end

#hold(server = nil) ⇒ Object

Chooses the first available connection, or if none are available, creates a new connection. Passes the connection to the supplied block:

pool.hold {|conn| conn.execute('DROP TABLE posts')}

Pool#hold is re-entrant, meaning it can be called recursively in the same fiber safely.

If no connection is immediately available and the pool is already using the maximum number of connections, Pool#hold will block the current fiber until a connection is available.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/my-sequel-synchrony/connection_pool.rb', line 71

def hold(server = nil)
  if_debug? { dputs "hold(server = #{server.inspect})! Current fiber = #{Fiber.current.inspect}" }
  fiber, conn = Fiber.current, nil
  if conn = @in_use_connections[fiber]
    return yield(conn)
  end

  begin
    conn = acquire(fiber)
    yield conn
  rescue Sequel::DatabaseDisconnectError => error
    disconnect_conn(conn) if conn
    conn = nil
    @in_use_connections.delete(fiber)
    resume_next_waiting_fiber
    raise error
  ensure
    release(fiber) if conn
  end
end

#sizeObject

The total number of open connections, either available or in-use.



37
38
39
# File 'lib/my-sequel-synchrony/connection_pool.rb', line 37

def size
  @in_use_connections.size + @available_connections.size
end