p.s. BTW, here’s that DB pool code i was talking about before:
···
–=-=-=
Content-Type: application/octet-stream
Content-Disposition: attachment; filename=dbasePool.rb
require ‘config’
require ‘dbi’
require ‘thread’
=begin
=end
class DbasePool
@@classMutex = Mutex.new
@@connectionFreed = ConditionVariable.new
@@instance = nil
@monitorThread
@pool
@poolSize
@monitorThread
attr_reader :host, :dbaseName
attr_reader :userName, :password, :monitorInterval
def initialize(host = nil, dbaseName = nil, userName = nil, password =
nil,
poolSize = 5, monitorInterval = 3600)
if @@instance then raise “Attempted to re-init DbasePool” end
@@classMutex.synchronize {
@host = host
@dbaseName = dbaseName
@userName = userName
@password = password
@poolSize = poolSize
@monitorInterval = monitorInterval #in seconds, 0 to disable
monitoring.
@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
#Now override several DBI’s methods.
#The default methods suck big time.
#Also, the MySQL DBD driver does not
#reflect true capability of MySQL.
#So, the following changes allows for nested transaction,
#and also provide transaction for any database that support it
#regardless of what the DBD driver may say.
attr_accessor :transaction_depth
def begin_transaction
if @transaction_depth == 0
self.do(“BEGIN”)
puts “DBASE_POOL: Transaction started”
end
@transaction_depth += 1
end
def commit_transaction
if @transaction_depth == 1
self.do(“COMMIT”)
puts “DBASE_POOL: Transaction stopped”
end
@transaction_depth -= 1
end
def rollback_transaction
if @transaction_depth == 1
self.do(“ROLLBACK”)
puts “DBASE_POOL: Transaction rolled back”
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 {
#puts “HAI, monitoring is awake”
@pool.each do |conn|
if (conn.status == “IDLE”) && (not conn.ping)
conn = connect
end
end
}
end
end
@@instance = self
}
end
def connect
DBI.connect(“DBI:Mysql:#{@dbaseName}:#{@host}”, @userName,
@password)
end
#What’s the destructor name in Ruby?
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
puts “No more free connection in DBASE_POOL. Waiting…”
puts @@instance.inspect
puts caller.join(“\n”)
@@connectionFreed.wait(@@classMutex)
puts “DBASE_POOL: a connection is freed. Resuming.”
cont.call
end
end
idleConn.status = “BUSY”
}
if block_given?
yield idleConn
idleConn.freeConnection
else
idleConn
end
end
def freeConnection(usedConn)
conn = nil #predeclare
@@classMutex.synchronize {
conn = @pool.find do |conn|
conn == usedConn
end
}
if conn
conn.status = “IDLE”
@@connectionFreed.signal
else
raise “Cannot found the referred connection!”
end
end
end
Initialise DBASE_POOL
DBASE_POOL = DbasePool.new(Config::DBASE_HOST,
Config::DBASE_DBNAME,
Config::DBASE_USER,
Config::DBASE_PASSWORD)
if $0 == FILE
#test, and also benchmark.
#on AMD-K62 400MHz, can do 217 SELECT NOW() statements per second.
1.upto(1000) do |i|
puts i if i % 100 == 0
dbh =
1.upto(5) do |i|
dbh[i] = DBASE_POOL.getConnection
end
1.upto(5) do |i|
dbh[i].execute(“SELECT NOW()”)
end
1.upto(5) do |i|
DBASE_POOL.freeConnection dbh[i]
end
1.upto(5) do
DBASE_POOL.getConnection do |dbh|
dbh.execute(“SELECT NOW()”)
end
end
end
end
–=-=-=–
<^>
On Tue, 2002-08-27 at 23:43, Edward Wilson wrote:
What does the Ruby community think?
I have wrestled for 6 months with a idea of writing somthing like this
in C++ and embedding Ruby into a C++ shell of rich objects.
Ultimately I would extend the server using both C/C++ and Ruby.
I have recently come to the conclusion that writing such a beast in
pure Ruby is the only way. Writing an app server covers so much
ground. The implementation could remain a prototype for three years
if it were written in C++. Ruby would be the only way to get off the
ground in less than a year. Porting would be much easier if the
server were written in pure Ruby.
Application servers are mini-operating systems in their own right.
iPlanet was a disaster; JBoss, BEA, JRun, and Tomcat are fantastic
implementations. Even Zope/Python has made a run.
//ed
–
~transami