Cache dbi for web app

Switching to mod_ruby would help a lot, both removing the interpreter
start-up time and giving you a persistent database connection.

For the connection, something as simple as

db ||= DBI.connect(…)

at the start of the script will work fine until you want to get
sophisticated and do things like reconnect after database shutdowns
and the like.

How would this work for multiple, simultaneous web sessions? Is the same
database connection being used by all web sessions? If so, then the rest of
the script would have to protect against any potential problems with that.

Chris

“Morris, Chris” chris.morris@snelling.com writes:

How would this work for multiple, simultaneous web sessions? Is the same
database connection being used by all web sessions? If so, then the rest of
the script would have to protect against any potential problems with that.

mod_ruby is executed by Apache, with each mod_ruby executing in its
own process. With a particular mod_ruby, execution is single threaded
and rus to the completion of the request.

Dave

a little more on persisting a database connection with mod_ruby –

“Morris, Chris” chris.morris@snelling.com writes:
mod_ruby is executed by Apache, with each mod_ruby executing in its
own process. With a particular mod_ruby, execution is single threaded
and rus to the completion of the request.

found this today:

Subject: [ruby-talk:18926] Re: mod_ruby - persistent variables?
From: someone@home.com (Chris)
Date: Wed, 1 Aug 2001 09:56:32 +0900
References: * 18408 18418 *On Tue, 24 Jul 2001 18:44:25 +0900, Michael
Neumann
uu9r@rz.uni-karlsruhe.de wrote in comp.lang.ruby:

You can’t share variables because Apache creates multiple
processes.
So it is not a good idea to use global variables on mod_ruby.

Thanks for the clarification. I heard it once before anywhere but
wasn’t really sure about it.

Is this fact only true for mod_ruby or behaves mod_perl etc…
in the same way?

All of this may be a moot point very soon. Although Apache 1.X uses
fork() to create child processes, Apache 2.X will create multiple
threads to handle requests. This means that variables created during
the initialization phase will be shared with the children. If you use
PerlRequire or RubyRequire in your httpd.conf to bring external modules
into your Apache process then you will need to make your code
thread-safe by declaring variables as volatile and using a mutex.

so, from what i can tell, it may not be a good idea to store a database
connection in a global variable, as i have been doing. i haven’t yet had
the chance to try the ||= trick yet actually, but even so it would
appear that with apache 2.0 that’s not going to work anyway. thus the
use of a Mutex, which is new to me. i’m looking foward to trying one
out.

but does anyone know what it means to declare a variable as volatile?

~transami

···

On Fri, 2002-07-12 at 21:00, Dave Thomas wrote:


~transami

(") dobee dobee do…
\v/
^ ^

Here is my experience using mod_ruby and making a persistent connexion.

Testing where the time is consumed when using mod_ruby,postgresql I
detected the folowing bottlenecks on an AMD 500MHZ.

Postgresql connection on each request 60ms.
CGI instantiation 60 ms.
processing the page template 60 ms.

The postgresql connection was fixed adding:

RubyAddPath '/home/mingo/apache/dadlib’
RubyRequire ‘/home/mingo/apache/dadlib/localsettings’

to the httpd.conf in the mod_ruby section:

require 'postgres’
module Apache
class RubyRun
@@pg_conn_handler = nil

    def RubyRun.pg_conn
        if !@@pg_conn_handler
            @@pg_conn_handler = PGconn.connect(nil, #pghost
                nil, #pgport
                nil, #pgoptions
                nil, #pgtty
                MAIN_DB      #database
                )
        end
        @@pg_conn_handler
    end
end

end

the above in the localsettings.rb file to add a class variable to
Apache::RubyRun to hold the postgresql connection handler and
referencing that field when a PGconn handler is needed.

In CGI.rb comment the following in the Cookie class declaration:

class Cookie #< SimpleDelegator

  #super(@value)   #60 ms was consumed here

If you use CGI::session like me change the following line in
cgi/session.rb:

  unless id
    id, = request[session_key]
    unless id
      #id, = request.cookies[session_key]  #original line
      id = request.cookies[session_key].value[0] #modified line
    end

And test your pages to see how fast they are now.

I use the following to see how long my pages take, at the top of the
template:

$start_t = Time.now

And at the bottom of the template:

cgi.out() { processed_template + "}

The time consume in the Cookies initialization is mainly in de
Delegation class, probably is a good idea to implement it in a
different way because the penaulty in the time consumed to proccess a
template is so huge.

With the modifications above my application seems to run fine but
consuming less than half the time consumed before.

Well folks that is it, I hope it can help someone.

Sorry but I’ve got an error using cgi/session when there is no cookie
already seted in the browser to correct it do the following in
cgi/session initialize:

···
    id, = request[session_key]
    unless id
      #id, = request.cookies[session_key] # original line

#comment the above line and add the lines bellow to next comment
begin
id = request.cookies[session_key].value[0] #DAD
rescue NameError
id = nil
end
#end new code
end

As well looking at delegate.rb I could see that doing a small change
we can improve the performance of it (but still is too much for me, it
decreases the time spent on it 25%).
In Delegate::initialize

#add the line bellow to store the methods definitions and

skip call eval one time for each one

eval_methods = ''
for method in obj.methods
  next if preserved.include? method

here store the methods definition all together to evaluate

all once at the end

  eval_methods << <<-EOS
    def self.#{method}(*args, &block)
      begin
        __getobj__.__send__(:#{method}, *args, &block)
      rescue Exception
        $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #`
        $@.delete_if{|s| /^\\(eval\\):/ =~ s}
        raise
      end
    end
  EOS
end

and here outside the loop evaluate all methods at once

with around 25% less cpu time

eval(eval_methods)

The above could make a general performance improvement in ruby
programs that relay heavilly on delegation.

Again I hope that this will help someone.

domingo@dad-it.com (Domingo Alvarez Duarte) writes:

The postgresql connection was fixed adding:

RubyAddPath '/home/mingo/apache/dadlib’
RubyRequire ‘/home/mingo/apache/dadlib/localsettings’

to the httpd.conf in the mod_ruby section:

I’m new to all this mod_ruby stuff, so bear with me.

In my mod_ruby scripts, I use the line

$store ||= Store.new(…)

where Store is my persistence class which sets up a PostgreSQL
connection. Do I need to rip this out and add one of these fancier
solutions that have been posted recently? It seems to me that this one
line is functionally equivalent, setting up one connection per Apache
process. What am I missing here?

Cheers

Dave