InactiveDestroy with Class::DBI
InactiveDestroy with Class::DBI
am 05.11.2005 21:20:57 von aturner
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
So I'm trying to track down a problem with my program which forks
needing both parent and children to have access to the database via
Class::DBI. The basic issue I'm having is that after the first child
exits, the parent's DBI connection seems to get mangled, because it
can no longer find the prepared statements created by Class::DBI.
I've written a custom db_Main() and connection() which keeps track of
the $dbh in a closure in my Class which is inheriting from
Class::DBI. In the child, I run:
$dbh->{InactiveDestroy} = 1;
$dbh = undef;
MyClass::DBI->connect();
Inspecting the $dbh hashref in the parent/children, I see what I
expect: parent keeps the same handle before and after fork(),
children at first inherit the handle, but then get their own after
calling connect().
But it seems that this issue is happening at the DBI layer and I'm lost.
- ------------------------------------------------------------ ----------
From my main Class::DBI class:
package Mu::DBI;
use base 'Class::DBI';
use IPC::Open3;
use IPC::Open2;
use IO::Select;
use Tie::IxHash;
use DBI;
use Carp qw/croak cluck confess carp/;
my $dbh; # our dbh handle
# figure out where and how to connect
sub dsn {
return "dbi:Pg:dbname=" . Mu::Config->DATABASE .
";host=" . Mu::Config->DBHOST .
";port=" . Mu::Config->DBPORT .
Mu::Config->DBOPTIONS;
}
# replacement for Class::DBI->db_Main()
sub db_Main() {
return $dbh;
}
__PACKAGE__->_remember_handle('Main');
# We have to undef our current handle, before the child can
# reconnect
sub undef_dbh() {
$dbh = undef;
}
# Use Mu::DBI->connect() instead of connection() so we use our
# own $dbh rather then the one provided with Class::DBI
sub connect() {
# Class::DBI expects to inherit from DBIx::ContextualFetch
my $dbenv = Mu::Config->DBENV;
$dbenv->{RootClass} = "DBIx::ContextualFetch";
$dbh = DBI->connect(Mu::DBI->dsn, Mu::Config->DBUSER,
Mu::Config->DBPASS, $dbenv) or
croak("Can't connect to DB: $DBI::errstr");
$dbh->do('SET search_path = "mucore","muapp","muserver";');
return 1;
}
- ------------------------------------------------------------ ----------
From my forking code:
Mu::DBI->connect();
my $dbh = Mu::DBI->db_Main();
[ do some DB stuff here... ]
while (some test) {
[ Do some DB work here... ]
if ($pid = fork()) {
# parent
# do some basic stuff here...
$SIG{CHLD} = \&REAPER;
} else {
croak("Failed to fork: $!") unless defined $pid;
# now we're in the child, so reconnect to the DB
# so that the parent doesn't loose it's handle
if (! ($dbh->{InactiveDestroy} = 1)) {
croak("Why can't i turn off destroy? " . DBI::errstr);
}
Mu::DBI->undef_dbh();
Mu::DBI->connect();
[ do some DB stuff here... ]
}
}
- --
Aaron Turner, Sr. Security Engineer
Ph: 408.329.6320 Fax: 408.329.6317
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (Darwin)
iD8DBQFDbRQvklVhPAXg8nARAsCpAJ9dKPS6Co72s1E3u6cDSF1JCPSBcwCg iFtn
gpl5vHmImx2JQApsHpVKugY=
=tOqd
-----END PGP SIGNATURE-----
Re: InactiveDestroy with Class::DBI
am 06.11.2005 06:56:03 von jonathan.leffler
------=_Part_47987_6439725.1131256563574
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline
On 11/5/05, Aaron Turner wrote:
> So I'm trying to track down a problem with my program which forks
> needing both parent and children to have access to the database via
> Class::DBI. The basic issue I'm having is that after the first child
> exits, the parent's DBI connection seems to get mangled, because it
> can no longer find the prepared statements created by Class::DBI.
> [...]
>
So, the DBI manual says words to the effect of "don't try reusing handles i=
n
child processes - it usually won't work", and your code seems to be
demonstrating exactly that.
Each process that needs to connect to a database needs to connect
separately.
--
Jonathan Leffler #include
Guardian of DBD::Informix - v2005.02 - http://dbi.perl.org
"I don't suffer from insanity - I enjoy every minute of it."
------=_Part_47987_6439725.1131256563574--
Re: InactiveDestroy with Class::DBI
am 06.11.2005 09:31:07 von aturner
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hi Jonathan,
Can you explain why you think that? When I run my code, I see the
$dbh hash change inside of the child process and the parent hash stay
the same. Aren't I avoiding using the same handle by doing a $dbh =
undef in the child and then calling connect again?
Thanks,
Aaron
- --
Aaron Turner, Sr. Security Engineer
Ph: 408.329.6320 Fax: 408.329.6317
On Nov 5, 2005, at 9:56 PM, Jonathan Leffler wrote:
> On 11/5/05, Aaron Turner wrote:
>
>> So I'm trying to track down a problem with my program which forks
>> needing both parent and children to have access to the database via
>> Class::DBI. The basic issue I'm having is that after the first child
>> exits, the parent's DBI connection seems to get mangled, because it
>> can no longer find the prepared statements created by Class::DBI.
>> [...]
>>
>
> So, the DBI manual says words to the effect of "don't try reusing
> handles in
> child processes - it usually won't work", and your code seems to be
> demonstrating exactly that.
>
> Each process that needs to connect to a database needs to connect
> separately.
>
> --
> Jonathan Leffler #include
> Guardian of DBD::Informix - v2005.02 - http://dbi.perl.org
> "I don't suffer from insanity - I enjoy every minute of it."
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (Darwin)
iD8DBQFDbb9MklVhPAXg8nARAsEUAJ4wSgy7SazBf1u27yUaEw45vqSorACf UFPW
ZQv8zFbOs7drORma17NBTDU=
=ty53
-----END PGP SIGNATURE-----
Re: InactiveDestroy with Class::DBI
am 08.11.2005 05:57:05 von jonathan.leffler
------=_Part_11968_3625415.1131425825743
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline
On 11/6/05, Aaron Turner wrote:
> Can you explain why you think that?
It's is the normal source of trouble when someone mentions fork and failure=
..
I didn't scrutinize your code - if I missed something obvious, I apologize
for casting aspersions.
When I run my code, I see the
> $dbh hash change inside of the child process and the parent hash stay
> the same. Aren't I avoiding using the same handle by doing a $dbh =3D
> undef in the child and then calling connect again?
The undef probably does the damage - the connect again would be correct.
If the 'undef' causes the child process to disconnect, then it closes the
connection and the server is none the wiser that it was only one of two
processes that closed the connection.
On Nov 5, 2005, at 9:56 PM, Jonathan Leffler wrote:
> > On 11/5/05, Aaron Turner wrote:
> >> So I'm trying to track down a problem with my program which forks
> >> needing both parent and children to have access to the database via
> >> Class::DBI. The basic issue I'm having is that after the first child
> >> exits, the parent's DBI connection seems to get mangled, because it
> >> can no longer find the prepared statements created by Class::DBI.
> >> [...]
> >>
> >
> > So, the DBI manual says words to the effect of "don't try reusing
> > handles in
> > child processes - it usually won't work", and your code seems to be
> > demonstrating exactly that.
> >
> > Each process that needs to connect to a database needs to connect
> > separately.
>
>
--
Jonathan Leffler #include
Guardian of DBD::Informix - v2005.02 - http://dbi.perl.org
"I don't suffer from insanity - I enjoy every minute of it."
------=_Part_11968_3625415.1131425825743--
Re: InactiveDestroy with Class::DBI
am 08.11.2005 06:41:20 von gonzales
Given that, ALL children threads from a fork inherit the attributes of the
parent, when you issue the undef from within the child, with a named
handle, from the parent, it's likely that this disconnects that handle and
ALL sibling threads also have the same, disconnected view.
When I was programming IPC channels, forks in UNIX for
synchronous/asynchronous communication, that's exactly how they behaved.
The $dbh from each of your child threads and parent see $dbh the same way.
Again, because $dbh is a parent thread variable, it is inherited to each
spawned thread.
On Mon, 7 Nov 2005, Jonathan Leffler wrote:
> On 11/6/05, Aaron Turner wrote:
>
>> Can you explain why you think that?
>
>
>
> It's is the normal source of trouble when someone mentions fork and failure.
>
> I didn't scrutinize your code - if I missed something obvious, I apologize
> for casting aspersions.
>
> When I run my code, I see the
>> $dbh hash change inside of the child process and the parent hash stay
>> the same. Aren't I avoiding using the same handle by doing a $dbh =
>> undef in the child and then calling connect again?
>
>
> The undef probably does the damage - the connect again would be correct.
>
> If the 'undef' causes the child process to disconnect, then it closes the
> connection and the server is none the wiser that it was only one of two
> processes that closed the connection.
>
>
> On Nov 5, 2005, at 9:56 PM, Jonathan Leffler wrote:
>>> On 11/5/05, Aaron Turner wrote:
>>>> So I'm trying to track down a problem with my program which forks
>>>> needing both parent and children to have access to the database via
>>>> Class::DBI. The basic issue I'm having is that after the first child
>>>> exits, the parent's DBI connection seems to get mangled, because it
>>>> can no longer find the prepared statements created by Class::DBI.
>>>> [...]
>>>>
>>>
>>> So, the DBI manual says words to the effect of "don't try reusing
>>> handles in
>>> child processes - it usually won't work", and your code seems to be
>>> demonstrating exactly that.
>>>
>>> Each process that needs to connect to a database needs to connect
>>> separately.
>>
>>
>
>
> --
> Jonathan Leffler #include
> Guardian of DBD::Informix - v2005.02 - http://dbi.perl.org
> "I don't suffer from insanity - I enjoy every minute of it."
>
--
/********** Louis Gonzales ***********\
/****** http://www.linuxlouis.net ****\
/**** louis.gonzales@linuxlouis.net **\
/****** HP Certified Professional ****\
Re: InactiveDestroy with Class::DBI
am 08.11.2005 06:51:57 von aturner
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On Nov 7, 2005, at 8:57 PM, Jonathan Leffler wrote:
> On 11/6/05, Aaron Turner wrote:
>
> When I run my code, I see the
>> $dbh hash change inside of the child process and the parent hash stay
>> the same. Aren't I avoiding using the same handle by doing a $dbh =
>> undef in the child and then calling connect again?
>
>
> The undef probably does the damage - the connect again would be
> correct.
>
> If the 'undef' causes the child process to disconnect, then it
> closes the
> connection and the server is none the wiser that it was only one of
> two
> processes that closed the connection.
Uh, that makes no sense (at least to me). Setting the parent's $dbh
handle to undef or replacing it with another should both cause the
client to process to disconnect under normal circumstances since it
will go out of scope and Perl will call DESTROY on the object at that
time. However, by setting $dbh->{InactiveDestroy} = 1 on the parent
inside the child, should avoid implicitly calling DESTROY (and
thereby avoid the disconnect) when the $dbh goes out of scope for any
reason.
In other words this:
$dbh->{InactiveDestroy} = 1;
$dbh = undef;
$dbh = DBI->connect(...);
should be equivalent to:
$dbh->{InactiveDestroy} = 1;
$dbh= DBI->connect(...);
Or am I missing something?
Thanks,
Aaron
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (Darwin)
iD8DBQFDcDz9klVhPAXg8nARAhvtAJ9xH4vikFXyRwfXdL4txZ50u3/eWwCf SLUb
k8cV3rPKvN+7dZuE5RSCCM4=
=BVkL
-----END PGP SIGNATURE-----
Re: InactiveDestroy with Class::DBI
am 08.11.2005 06:59:09 von aturner
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Right, but that's what InactiveDestroy is for. Otherwise when the
child exits it will call DESTROY on the handle and close the parent's
connection to the DB. Turning on InactiveDestroy in the child turns
off the implicit call to disconnect from DESTROY for the inherited DB
handle from the parent and thus should maintain the parent's connection.
Only calling disconnect() from the child on the handle should
disconnect the parent once InactiveDestroy is turned on.
At least that's what the DBI pod seems to say...
- -Aaron
On Nov 7, 2005, at 9:41 PM, louis gonzales wrote:
> Given that, ALL children threads from a fork inherit the attributes
> of the parent, when you issue the undef from within the child, with
> a named handle, from the parent, it's likely that this disconnects
> that handle and ALL sibling threads also have the same,
> disconnected view.
>
> When I was programming IPC channels, forks in UNIX for synchronous/
> asynchronous communication, that's exactly how they behaved.
>
> The $dbh from each of your child threads and parent see $dbh the
> same way.
> Again, because $dbh is a parent thread variable, it is inherited to
> each spawned thread.
>
>
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (Darwin)
iD8DBQFDcD6tklVhPAXg8nARAlP5AKCVRX3yS6ctCrX1ZMo/BXUCIFx03ACg mbSt
bqTE006QIkOoWCUge+qam0c=
=RpJC
-----END PGP SIGNATURE-----
Re: InactiveDestroy with Class::DBI
am 08.11.2005 07:20:13 von jonathan.leffler
------=_Part_12977_17162303.1131430813920
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline
On 11/7/05, Aaron Turner wrote:
> On Nov 7, 2005, at 8:57 PM, Jonathan Leffler wrote:
> > On 11/6/05, Aaron Turner wrote:
> >
> > When I run my code, I see the
> >> $dbh hash change inside of the child process and the parent hash stay
> >> the same. Aren't I avoiding using the same handle by doing a $dbh =3D
> >> undef in the child and then calling connect again?
> >
> >
> > The undef probably does the damage - the connect again would be
> > correct.
> >
> > If the 'undef' causes the child process to disconnect, then it
> > closes the
> > connection and the server is none the wiser that it was only one of
> > two
> > processes that closed the connection.
>
> Uh, that makes no sense (at least to me). Setting the parent's $dbh
> handle to undef or replacing it with another should both cause the
> client to process to disconnect under normal circumstances since it
> will go out of scope and Perl will call DESTROY on the object at that
> time. However, by setting $dbh->{InactiveDestroy} =3D 1 on the parent
> inside the child, should avoid implicitly calling DESTROY (and
> thereby avoid the disconnect) when the $dbh goes out of scope for any
> reason.
I'm hypothesizing. I could be wrong. I don't even recall which driver you
are using.
If you were using DBD::Informix, I'd be right - it hasn't been updated to
recognize InactiveDestroy and the child disconnect would terminate the
parent's connection - unless DBI itself manages things correctly. (Actually=
,
in the current version, if the child tried to access the DBMS via a handle
created in the parent, it would get a rude message - to the effect that
you're not allowed to try that. But that's independent of the
InactiveDestroy attribute, which is not recognized.)
In other words this:
>
> $dbh->{InactiveDestroy} =3D 1;
> $dbh =3D undef;
> $dbh =3D DBI->connect(...);
>
> should be equivalent to:
>
> $dbh->{InactiveDestroy} =3D 1;
> $dbh=3D DBI->connect(...);
>
Probably - if the driver supports the concept.
Or am I missing something?
Probably not.
I don't have anything more useful to offer on this subject at the moment.
It is unlikely I'll respond again.
--
Jonathan Leffler #include
Guardian of DBD::Informix - v2005.02 - http://dbi.perl.org
"I don't suffer from insanity - I enjoy every minute of it."
------=_Part_12977_17162303.1131430813920--
Re: InactiveDestroy with Class::DBI
am 08.11.2005 15:32:56 von Greg
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Aaron Turner asked:
> So I'm trying to track down a problem with my program which forks
> needing both parent and children to have access to the database via
> Class::DBI. The basic issue I'm having is that after the first child
> exits, the parent's DBI connection seems to get mangled, because it
> can no longer find the prepared statements created by Class::DBI.
Tim Bunce wrote:
> Enabling DBI trace in the client may shed some light on it. The DBD::Pg
> driver may not be honouring InactiveDestroy.
For the record, DBD::Pg does support InactiveDestroy, and we even include
it as part of our test suite. Viewing it might even help the original poster.
The tests in question are at the bottom of this file:
http://search.cpan.org/src/DBDPG/DBD-Pg-1.43/t/02attribs.t
Note that "$dbh=undef" is not needed
- --
Greg Sabino Mullane greg@turnstep.com
PGP Key: 0x14964AC8 200511080930
http://biglumber.com/x/web?pk=2529DF6AB8F79407E94445B4BC9B90 6714964AC8
-----BEGIN PGP SIGNATURE-----
iD8DBQFDcLchvJuQZxSWSsgRAoAzAKD5eklD7WyaFmLFVxAuHj3N/wKOegCf dC6a
QOag2Tzckg9a4cqG1oVKqRg=
=+mOg
-----END PGP SIGNATURE-----