A
download DbPool.rb
Language: Ruby
LOC: 154
Project Info
IOWA
Server: RubyForge
Type: cvs
...Forge\i\iowa\iowa\iowa\src\
   Application.rb
   ApplicationStats.rb
   Association.rb
   BindingsParser.rb
   Client.rb
   Component.rb
   ComponentProxy.rb
   config.rb
   Context.rb
   DbPool.rb
   DynamicElements.rb
   Element.rb
   Form.rb
   HTTPServer.rb
   ISAAC.rb
   KeyValueCoding.rb
   LRUCache.rb
   PageStore.rb
   read_multipart.rb
   Request.rb
   SciTE.properties
   Session.rb
   SessionStats.rb
   SessionStore.rb
   Tag.rb
   TemplateParser.rb
   WEBrickServlet.rb

require 'dbi'
require 'thread'

module Iowa

	class ReInitException < Exception; end
	class MissingConnectionException < Exception; end
  
	class DbPool
		@monitorThread
		@pool
		@poolSize
 
		attr_reader :host, :dbName
		attr_reader :userName, :password, :monitorInterval

		def initialize(vendor=nil, host='localhost', dbName=nil, userName=nil, password=nil, poolSize=5, monitorInterval=300, &block)
			@classMutex = Mutex.new
			@connectionFreed = ConditionVariable.new
			@instance = nil
			@mungeBlock = block ? block : Proc.new {|dbh| dbh}
			
			raise ReInitException if @instance

			@classMutex.synchronize {
				@vendor = vendor
				@host = host
				@dbName = dbName
				@userName = userName
				@password = password
				@poolSize = poolSize
				@monitorInterval = monitorInterval
				@pool = []
				0.upto(@poolSize-1) do |i|
					conn = @pool[i] = connect
					class << conn
						attr_accessor :status
						attr_accessor :parent

						def freeConnection
							parent.freeConnection(self)
						end

						attr_accessor :transaction_depth

						def begin_transaction
							if @transaction_depth == 0
							self.do("BEGIN")
						end
						@transaction_depth += 1
						end

						def commit_transaction
							if @transaction_depth == 1
								self.do("COMMIT")
							end
							@transaction_depth -= 1
						end

						def rollback_transaction
							if @transaction_depth == 1
								self.do("ROLLBACK")
							end
							@transaction_depth -= 1
						end

						def transaction
							raise InterfaceError, "Database connection was already closed!" if @handle.nil?
							raise InterfaceError, "No block given" unless block_given?
							begin_transaction
							begin
								yield self
								commit_transaction
							rescue Exception
								rollback_transaction
								raise
							end
						end
					end
					conn.status = :IDLE
					conn.parent = self
					conn.transaction_depth = 0
				end
				@monitorThread = Thread.new do
					while(true)
						sleep(monitorInterval)
						@classMutex.synchronize {
							@pool.each do |conn|
								if (conn.status == :IDLE) && (not conn.ping)
									conn = connect
								end
							end
						}
					end
				end
				@instance = self
			}
		end


		def connect
			dbh = nil
			if @host.to_s != ''
				if @userName.to_s != ''
					dbh = DBI.connect("DBI:#{@vendor}:#{@dbName}:#{@host}", @userName, @password)
				else
					dbh = DBI.connect("DBI:#{@vendor}:#{@dbName}:#{@host}")
				end
			else
				if @userName.to_s != ''
					dbh = DBI.connect("DBI:#{@vendor}:#{@dbName}",@userName,@password)
				else
					dbh = DBI.connect("DBI:#{@vendor}:#{@dbName}")
				end
			end
			@mungeBlock.call(dbh)
		end
 
		def instance?
			return @instance ? true : false
		end

		def finish
			@classMutex.synchronize {
				@monitorThread.stop
				@pool.each do |conn|
					conn.disconnect
				end
			}
		end


		#Get the next idle connection. If there is no idle connection, will block
		#until there is one.
		#Optionally accepts a block. If a block is given, will execute the block
		#and free up the connection afterwards.

		def getConnection
			idleConn = nil #predeclare
			@classMutex.synchronize {
				callcc do |cont|
					idleConn = @pool.find do |conn|
						conn.status == :IDLE
					end
					if not idleConn
						@connectionFreed.wait(@classMutex)
						cont.call
					end
				end
				idleConn.status = :BUSY
			}
			if block_given?
				begin
					yield idleConn
				ensure
					idleConn.freeConnection
				end
			else
				return idleConn
			end
		end
 

		def freeConnection(usedConn)
			conn = nil
			@classMutex.synchronize {
				conn = @pool.find do |conn|
					conn == usedConn
				end
			}
			if conn
				conn.status = :IDLE
				@connectionFreed.signal
			else
				raise MissingConnectionException
			end

			conn.status
		end
	end                
end

About Koders | Resources | Downloads | Support | Black Duck | Terms of Service | DMCA | Privacy Policy | Contact Us