Class: Pod4::ConnectionPool

Inherits:
Connection show all
Defined in:
lib/pod4/connection_pool.rb

Defined Under Namespace

Classes: Pool, PoolItem

Constant Summary collapse

DEFAULT_MAX_CLIENTS =
10

Instance Attribute Summary collapse

Attributes inherited from Connection

#data_layer_options, #interface_class

Instance Method Summary collapse

Constructor Details

#initialize(args) ⇒ ConnectionPool

As Connection, but with some options you can set.

  • max_clients – if this many clients are assigned to threads, wait until one is freed.

pass nil for no maximum. Tries to default to something sensible.

  • max_wait – throw a Pod4::PoolTimeout if you wait more than this time in seconds.

Pass nil to wait forever. Default is nil, because you would need to handle that timeout.

Note that the :interface parameter is optional here. You probably want one pool for all your models and interfaces, so you should leave it out.



80
81
82
83
84
85
86
# File 'lib/pod4/connection_pool.rb', line 80

def initialize(args)
  super(args)

  @max_clients = args[:max_clients] || DEFAULT_MAX_CLIENTS
  @max_wait    = args[:max_wait]
  @pool        = Pool.new
end

Instance Attribute Details

#max_clientsObject (readonly)

of Pool



64
65
66
# File 'lib/pod4/connection_pool.rb', line 64

def max_clients
  @max_clients
end

#max_waitObject (readonly)

of Pool



64
65
66
# File 'lib/pod4/connection_pool.rb', line 64

def max_wait
  @max_wait
end

Instance Method Details

#_poolObject

Dump the internal pool (for test purposes only)



171
172
173
# File 'lib/pod4/connection_pool.rb', line 171

def _pool
  @pool._dump
end

#client(interface) ⇒ Object

Return a client for the interface to use.

Return the client we gave this thread before. Failing that, assign a free one from the pool. Failing that, ask the interface to give us a new client. Failing that, if we’ve set a timeout, wait for a client to be freed; if we have not, release

the oldest client and use that.

Note: ‘interface’ is the instance of the interface class. It passes itself in case we want to call it back to get a new client or to close a client; but clients are assigned to a thread, not an interface. Every interface in a given thread gets the same pool item, the same client object.



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/pod4/connection_pool.rb', line 102

def client(interface)
  time = Time.now
  cl   = nil

  Pod4.logger.debug(__FILE__){ "Pool size: #{@pool.size} Thread: #{Thread.current.object_id}" }

  # NB: We are constrained to use loop in order for our test to work
  loop do
    if (pi = @pool.get_current)
      Pod4.logger.debug(__FILE__){ "get current: #{pi.inspect}" }
      cl = pi.client
      break
    end

    if (pi = @pool.get_free)
      Pod4.logger.debug(__FILE__){ "get free: #{pi.inspect}" }
      cl = pi.client
      break
    end

    if @max_clients && @pool.size >= @max_clients 
      if @max_wait
        raise Pod4::PoolTimeout if @max_wait && (Time.now - time > @max_wait)
        Pod4.logger.warn(__FILE__){ "waiting for a free client..." }
        sleep 1
        next
      else
        Pod4.logger.debug(__FILE__){ "releasing oldest client" }
        oldest = @pool.get_oldest
        interface.close_connection oldest.client
        @pool.release(oldest.thread_id)
        next
      end
    end

    Pod4.logger.debug(__FILE__){ "new connection" }
    cl = interface.new_connection(@data_layer_options)
    @pool << cl
    break
  end # of loop

  Pod4.logger.debug(__FILE__){ "Got client: #{cl.inspect}" }
  cl
end

#close(interface) ⇒ Object

De-assign the client for the current thread from that thread.

Note: ‘interface’ is the instance of the interface class. This is so we can call it and get it to close the client; we don’t know how to do that.



153
154
155
156
157
# File 'lib/pod4/connection_pool.rb', line 153

def close(interface)
  current = @pool.get_current
  interface.close_connection current.client
  @pool.release current.thread_id
end

#drop(interface) ⇒ Object

Remove the client from the pool but don’t try to close it. we provide this for if the Interface finds that a connection is no longer open; TdsInterface uses it.



164
165
166
# File 'lib/pod4/connection_pool.rb', line 164

def drop(interface)
  @pool.release
end