Tim Bunce wrote:
On Sun, Apr 10, 2005 at 03:08:04PM -0400, Stas Bekman wrote:

Tim Bunce wrote:

On Sat, Apr 09, 2005 at 01:08:40AM -0400, Stas Bekman wrote:


Tim,

I've a pretty well working prototype now. There is one problem though.

Before take_imp_data can be called all $sth must be destroyed. for example the following code:

 my $dbh = DBI->connect('dbi:mysql:test', '', '', {});
 my $sth0 = $dbh->prepare("show tables");
 $sth0->execute();
 while (my @row = $sth0->fetchrow_array) {
     $dbh->do("DROP TABLE $table") if $row[0] eq $table;
 }
 $dbh->disconnect;

fails:

DBD::mysql::db take_imp_data failed: Can't take_imp_data from handle while it still has kids at /home/stas/work/modules/DBI-Pool/blib/lib/DBI/Pool.pm line 96.

since I try to call take_imp_data in the overridden DBI::Pool::disconnect. This fixes the problem in the caller script:

 undef $sth0;
 $dbh->disconnect;

but it requires an unusual modification to the original script and DBI::Pool should be able to work transparently to the user.

So how can we eliminate this problem?

Tricky. The risk is that child statement handles may contain pointers to their parents data structures which may be used when the statement handle is destroyed.

The restriction could be relaxed to check ActiveKids instead of Kids.
That would reduce the risk - but not eliminate it.

Another good thing to do would be to have take_imp_data not detach and
return the original imp_xxh structure, but make a copy, then zero out
(or poison?) the original one, before returning the copy. That way if
the statement handle DESTROY does try to access the parents imp_xxh
structure we'll find out about it very clearly :)

Feel free to make both those changes and see how it goes...

How about a different approach. Instead of taking imp_data in disconnect, would it be better to do the same in dbd_db_disconnect, when all children should be already dead?


Any use of prepare_cached() is likely to mean the kids are immortal.

Using $dbh->disconnect as a signal that the app has finished using the
handle seems like a neat fit - especially as it's disabled in
DBI::Apache anyway. It can do $dbh->{CachedKids} = undef;

with $dbh->{CachedKids} = undef; in the overriden disconnect() I still get:

DBD::mysql::db take_imp_data failed: Can't take_imp_data from handle while it still has kids at /home/stas/work/modules/DBI-Pool/blib/lib/DBI/Pool.pm line 97.

What's the best way to override this one globally or may be some higher level function?


Umm. Still tricky. The only place to intercept a call when all the
statement handles have been destroyed would be the dbh DESTROY
(specifically the DESTROY call for the _inner_ handle).

You could get at that via a subclass (which I presume DBI::Pool is).
Or via the new callback mechanism.

it's a subclass.

Doh! disconnect was too early, but DESTROY is too late:

DBD::mysql::db take_imp_data failed: Can't take_imp_data from handle that's not Active at /home/stas/work/modules/DBI-Pool/blib/lib/DBI/Pool.pm line 96.

:(

(For all this you're relying on the application not caching the db handles.
Otherwise DESTROY won't be called till global destruction, of course.)

right, but if it's already caching it, it's its problem.

Tim.

p.s. An alternative would be to add a weakref mechanism for parent
handles to track their children. It's been on the ToDo list for ages.
Possibly non-trivial, but has a good pay-back.

How soon can this possibly happen?

--
__________________________________________________________________
Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/     mod_perl Guide ---> http://perl.apache.org
mailto:[EMAIL PROTECTED] http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com

Reply via email to