Class: RDBI::Pool

Inherits:
Object
  • Object
show all
Extended by:
Enumerable
Includes:
Enumerable
Defined in:
lib/rdbi/pool.rb

Overview

RDBI::Pool - Connection Pooling.

Pools are named resources that consist of N concurrent connections which all have the same properties. Many group actions can be performed on them, such as disconnecting the entire lot.

RDBI::Pool itself has a global accessor, by way of RDBI::Pool::[], that can access these pools by name. Alternatively, you may access them through the RDBI.pool interface.

Pools are thread-safe and are capable of being resized without disconnecting the culled database handles.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, connect_args, max = 5) ⇒ Pool

Creates a new pool.

  • name: the name of this pool, which will be used to find it in the global accessor.

  • connect_args: an array of arguments that would be passed to RDBI.connect, including the driver name.

  • max: the maximum number of connections to deal with.

Usage:

Pool.new(:fart, [:SQLite3, :database => “/tmp/foo.db”]) Pool.new(:quux, { :database => :SQLite3, :database => “:memory:” })



87
88
89
90
91
92
93
94
95
# File 'lib/rdbi/pool.rb', line 87

def initialize(name, connect_args, max=5)
  @handles      = []
  @connect_args = connect_args
  munge_connect_args!
  @max          = max
  @last_index   = 0
  @mutex        = Mutex.new
  self.class[name] = self
end

Instance Attribute Details

#handlesObject (readonly)

a list of the pool handles for this object. Do not manipulate this directly.



68
69
70
# File 'lib/rdbi/pool.rb', line 68

def handles
  @handles
end

#last_indexObject (readonly)

the last index corresponding to the latest allocation request.



70
71
72
# File 'lib/rdbi/pool.rb', line 70

def last_index
  @last_index
end

#maxObject (readonly)

the maximum number of items this pool can hold. should only be altered by resize.



72
73
74
# File 'lib/rdbi/pool.rb', line 72

def max
  @max
end

#mutexObject (readonly)

the Mutex for this pool.



74
75
76
# File 'lib/rdbi/pool.rb', line 74

def mutex
  @mutex
end

Class Method Details

.[](name) ⇒ Object

Retrieves a pool object for the name, or nothing if it does not exist.



43
44
45
46
47
48
# File 'lib/rdbi/pool.rb', line 43

def [](name)
  mutex.synchronize do
    @pools ||= { }
    @pools[name.to_sym]
  end
end

.[]=(name, value) ⇒ Object

Sets the pool for the name. This is not recommended for end-user code.



53
54
55
56
57
58
# File 'lib/rdbi/pool.rb', line 53

def []=(name, value)
  mutex.synchronize do
    @pools ||= { }
    @pools[name.to_sym] = value
  end
end

.eachObject

Iterate each pool and get the name of the pool (as a symbol) and the value as a Pool object.



24
25
26
27
28
# File 'lib/rdbi/pool.rb', line 24

def each
  @pools.each do |key, value|
    yield(key, value)
  end
end

.keysObject

obtain the names of each pool.



31
32
33
# File 'lib/rdbi/pool.rb', line 31

def keys
  @pools.keys
end

.mutexObject



60
61
62
# File 'lib/rdbi/pool.rb', line 60

def mutex
  @mutex
end

.valuesObject

obtain the pool objects of each pool.



36
37
38
# File 'lib/rdbi/pool.rb', line 36

def values
  @pools.values
end

Instance Method Details

#add_connectionObject

Add a connection, connecting automatically with the connect arguments supplied to the constructor.



157
158
159
# File 'lib/rdbi/pool.rb', line 157

def add_connection
  add(RDBI.connect(*@connect_args))
end

#disconnectObject

Disconnect all database handles.



148
149
150
151
152
# File 'lib/rdbi/pool.rb', line 148

def disconnect
  mutex.synchronize do
    @handles.each(&:disconnect)
  end
end

#eachObject

Obtain each database handle in the pool.



98
99
100
# File 'lib/rdbi/pool.rb', line 98

def each
  @handles.each { |dbh| yield dbh }
end

#get_dbhObject

Obtain a database handle from the pool. Ordering is round robin.

A new connection may be created if it fills in the pool where a previously empty object existed. Additionally, if the current database handle is disconnected, it will be reconnected.



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/rdbi/pool.rb', line 209

def get_dbh
  mutex.synchronize do
    if @last_index >= @max
      @last_index = 0
    end

    # XXX this is longhand for "make sure it's connected before we hand it
    #     off"
    if @handles[@last_index] and !@handles[@last_index].connected?
      @handles[@last_index].reconnect
    elsif !@handles[@last_index]
      @handles[@last_index] = RDBI.connect(*@connect_args)
    end

    dbh = @handles[@last_index]
    @last_index += 1
    dbh
  end
end

#pingObject

Ping all database connections and average out the amount.

Any disconnected handles will be reconnected before this operation starts.



107
108
109
110
111
112
# File 'lib/rdbi/pool.rb', line 107

def ping
  reconnect_if_disconnected
  mutex.synchronize do 
    @handles.inject(1) { |sum,dbh| sum + (dbh.ping || 1) } / @handles.size
  end
end

#reconnectObject

Unconditionally reconnect all database handles.



130
131
132
133
134
# File 'lib/rdbi/pool.rb', line 130

def reconnect
  mutex.synchronize do 
    @handles.each { |dbh| dbh.reconnect } 
  end
end

#reconnect_if_disconnectedObject

Only reconnect the database handles that have not been already connected.



138
139
140
141
142
143
144
# File 'lib/rdbi/pool.rb', line 138

def reconnect_if_disconnected
  mutex.synchronize do 
    @handles.each do |dbh|
      dbh.reconnect unless dbh.connected?
    end
  end
end

#remove(dbh) ⇒ Object

Remove a specific connection. If this connection does not exist in the pool already, nothing will occur.

This database object is not disconnected – it is your responsibility to do so.



167
168
169
170
171
# File 'lib/rdbi/pool.rb', line 167

def remove(dbh)
  mutex.synchronize do
    @handles.reject! { |x| x.object_id == dbh.object_id }
  end
end

#resize(max = 5) ⇒ Object

Resize the pool. If the new pool size is smaller, connections will be forcibly removed, preferring disconnected handles over connected ones.

No database connections are disconnected.

Returns the handles that were removed, if any.



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/rdbi/pool.rb', line 181

def resize(max=5)
  mutex.synchronize do
    in_pool = @handles.select(&:connected?)

    unless (in_pool.size >= max)
      disconnected = @handles.select { |x| !x.connected? }
      if disconnected.size > 0
        in_pool += disconnected[0..(max - in_pool.size - 1)]
      end
    else
      in_pool = in_pool[0..(max-1)]
    end

    rejected = @handles - in_pool

    @max = max
    @handles = in_pool
    rejected
  end
end

#upObject

Asserts that all the pooled handles are connected. Returns true or false depending on the result of that assertion.



118
119
120
121
122
123
124
125
126
# File 'lib/rdbi/pool.rb', line 118

def up
  alive = false

  mutex.synchronize do
    alive = @handles.select { |x| x.ping.nil? }.empty?
  end

  return alive
end