artemave has asked for the wisdom of the Perl Monks concerning the following question:

Greetings,

I've recently encoutered problems using Class::DBI under mod_perl 2 environment (win32). As long as there is more than one response handler which uses CDBI objects, apache throws this error:
[Wed May 02 18:55:09 2007] [error] [client 127.0.0.1] DBD::mysql::db F +ETCH failed: handle 2 is owned by thread 161929c not current thread 1 +ba79ec (handles can't be shared between threads and your driver may n +eed a CLONE method added) at c:/Perl/site/lib/Apache/DBI.pm line 226. +\n
I have then googled for a possible workaround and found this patch to Ima::DBI :
sub _mk_db_closure { my ($class, $dsn, $user, $pass, $attr) = @_; $attr ||= {}; my $dbh; my $process_id = $$; return sub { # set the PID in a private cache key to prevent us # from sharing one with the parent after fork. This # is better than disconnecting the existing $dbh since # the parent may still need the connection open. Note # that forking code also needs to set InactiveDestroy # on all open handles in the child or the connection # will be broken during DESTROY. $attr->{private_cache_key_pid} = $$; # reopen if this is a new process or if the connection # is bad if ($process_id != $$ or not ($dbh && $dbh->FETCH('Active') && + $dbh->ping)) { $dbh = DBI->connect_cached($dsn, $user, $pass, $attr); $process_id = $$; } return $dbh; }; }
Which leads to the same result. Perhaps it is because all threads share the same process id?

Then I've found another solution here, but I failed to undestand how to use it! The problem is that I don't know how to get current request object inside db_Main. Because Apache->request (class method; which used in the solution) is something I can't find under Apache2.
The way I usually get the request object is I'm grabbing it, when it is passed to the response handler and then passing it further if needed or store it as an object member.
But I'd like to keep my model classes and underlying data mapping classes away from any references to request object. Perhaps there is a way just to get the request object for the current context, which would suit perfectly.

Or perhaps I'm missing something obvious again ;)

May be there is another way to deal with cdbi under mod_perl? Or another way for objects mapping?

Thanx,
Artem.

Replies are listed 'Best First'.
Re: Class::DBI and mod_perl 2
by perrin (Chancellor) on May 03, 2007 at 21:07 UTC
    I believe the equivalent for threads is threads->tid. I didn't use it in either of these solutions because I don't use threads.

      Thanks for your work on this, perrin. One question - the only place I can find "private_cache_key_pid" is in this code snippet, where it is only assigned. Is this a custom attribute for DBI that is in a locally modified copy?

      I'm trying to use this in conjunction with Class::DBI, and when I paste this into my DBI class, instead of "fetch before execute" errors in the parent, I'm getting "server has gone away". I'm setting InactiveDestroy on all the children, but the best I can figure is that somewhere Class::DBI is breaking my connection in its own DESTROY handlers. I don't actually use DBI in the children, it's just that the fork behavior breaks the parent's connection.

      As you know, Ima::DBI creates closures and I likely have a ton of references to it in child "memory", so it's not as simple as setting InactiveDestroy and undefining a handle. =\

      mhoward - at - hattmoward.org

        Read the section in the DBI docs about connect_cached. It comes from there.

        By the way, I recently released a new version of Ima::DBI which includes this patch, but doesn't use threads->tid. If you can verify that threads->tid works for you, I could put it in the main Ima::DBI distribution so you wouldn't need to patch it.

Re: Class::DBI and mod_perl 2
by ides (Deacon) on May 04, 2007 at 14:47 UTC

    To get the current request object under mod_perl 2 you need to use Apache2::RequestUtil->request(). Here is a link to the docs on that.

    You'll find that whole page covers everything you'll need to know to translate mod_perl 1.x code to mod_perl 2.x code.

    If you haven't done so already I'd also check into DBIx::Class , personally I gave up on using Class::DBI long ago after running into all sorts of odd problems that I couldn't find easy solutions to.

    Frank Wiles <frank@revsys.com>
    www.revsys.com

      Thank you, Frank.

      This information is really helpful.

      Artem.

      P.S. Defintely, I've looked through RequestUtil methods couple of times, but failed to notice what I need. Thanx again.