Class: TriCoreDB::Pool

Inherits:
Object
  • Object
show all
Defined in:
lib/tricoredb/pool.rb

Overview

A thread-safe pool of connections.

A connection is lent to exactly one block at a time. Connections are created lazily up to size.

A session transaction is bound to its connection, so a connection is never returned mid-transaction: a block that raises with one open has it rolled back, and a block that returns with one open has it rolled back and raises.

Examples:

pool = TriCoreDB::Pool.new(size: 8, host: "db", port: 8427, user: "app", secret: ENV["TRICORE_SECRET"])
pool.with { |db| db.query("SELECT 1") }
pool.close

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(size: 8, checkout_timeout: 10, **connect_options) ⇒ Pool

Returns a new instance of Pool.

Parameters:

  • size (Integer) (defaults to: 8) —

    maximum connections

  • checkout_timeout (Numeric) (defaults to: 10) —

    seconds #with waits for a free connection

  • connect_options (Hash) —

    passed to Client.connect, tls: included

Raises:

  • (ArgumentError)


24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/tricoredb/pool.rb', line 24

def initialize(size: 8, checkout_timeout: 10, **connect_options)
  raise ArgumentError, "pool size must be >= 1" if size < 1

  @size = size
  @checkout_timeout = checkout_timeout
  @connect_options = connect_options
  @idle = []
  @created = 0
  @waiting = 0
  @closed = false
  @lock = Mutex.new
  @available = ConditionVariable.new
end

Instance Attribute Details

#size ⇒ Integer (readonly)

Returns:

  • (Integer)


19
20
21
# File 'lib/tricoredb/pool.rb', line 19

def size
  @size
end

Instance Method Details

#close ⇒ Object

Close idle connections and refuse further checkouts. Connections in use are closed when they are returned.



80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/tricoredb/pool.rb', line 80

def close
  idle = @lock.synchronize do
    @closed = true
    @available.broadcast
    list = @idle.dup
    @idle.clear
    @created -= list.size
    list
  end
  idle.each(&:close)
  nil
end

#stats ⇒ Hash{Symbol => Integer}

Returns:

  • (Hash{Symbol => Integer})


72
73
74
75
76
# File 'lib/tricoredb/pool.rb', line 72

def stats
  @lock.synchronize do
    { size: @size, created: @created, idle: @idle.size, in_use: @created - @idle.size, waiting: @waiting }
  end
end

#with(timeout: @checkout_timeout) {|db| ... } ⇒ Object

Borrow a connection for the duration of the block.

Yield Parameters:

Returns:

  • (Object) —

    the block's value

Raises:

  • (PoolTimeout) —

    when none frees up within the timeout



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/tricoredb/pool.rb', line 43

def with(timeout: @checkout_timeout)
  raise ArgumentError, "Pool#with needs a block" unless block_given?

  client = checkout(timeout)
  broken = false
  begin
    begin
      result = yield client
    rescue Exception => e # rubocop:disable Lint/RescueException
      if client.closed? || stream_broken?(e)
        broken = true
      elsif client.in_transaction?
        broken = !abandon_transaction(client)
      end
      raise
    end
    if client.in_transaction?
      broken = !abandon_transaction(client)
      raise Error, "the block returned with a session transaction still open on the pooled connection; it " \
                   "has been rolled back rather than returned to the pool. Commit or roll back inside the " \
                   "block, or use db.transaction { }"
    end
    result
  ensure
    checkin(client, broken)
  end
end