On Fri, Jun 28, 2002 at 05:30:41PM +0200, Gerald Richter - ecos gmbh wrote:
> Hi,
> 
> thanks Tim for your detailed hints. Here is what I found so far. Every
> testing has taken place under windows NT & Perl 5.8.0 RC2 & mod_perl 1.99_4
> & DBI 1.28 & DBD::Oracle 1.12.
> 
> I looked at the places that you showed me, but finaly (after some tries), I
> find out that all this thread stuff in DBI itself is unnecessary, unless you
> share any handle between threads. Because DBI uses Perl's memory management
> and every thread has it's own memory pool in 5.8.0 (that's different with
> the old thread model), concurrent threads runs without problems.

Beware. You need to consider if the DBI was loaded before or after
the thread was started. If the DBI was loaded before any threads
were started then the pre-loaded DBI module will have been 'cloned'.

Since the DBI doesn't define it's own CLONE method it'll get the default
behaviour of just having all it's data copied.

Part of that data is a pointer to the 'dbistate' structure. The
clones will have cloned copies of the *pointer* and so will share
the same dbistate. Not good. Probably not immediately fatal but
things like $DBI::max_neatlen, trace file, trace level, and (worst
of all) the DBI's concept of the 'last handle used' will be shared
in the worst way.

Given the different issues involved in either loading DBI before
or after threads are created it's important for everyone to clarify
that in any discussions.


> The problem for DBI starts when you want to share handles, for example the
> database connection, between your threads. Perl 5.8.0 share meachnismem is
> not able to share such complex objects, like a DBI handle. It only shares
> simple scalars, arrays and hashs. So for now I have to use one dbh per
> thread anyway. When the sharing problem is solved, then the LOCK/COND_WAIT
> code in DBI must be updated to 5.8.0, but this is really easy and I am
> already half way through.

Great. Thanks.

Note that the LOCK/COND_WAIT code in DBI is there to partly to
protect drivers from having multiple threads enter them - but also
to protect the underlying driver library code (.so/.dll etc), which
may not be thread safe even if the DBD driver code is.

So the LOCK/COND_WAIT (SvLOCK) code is very relevant even before
"the sharing problem is solved" (which it probably won't be).


> Also of this facts I had still gotten segfaults. So I moved on and found
> that the problem are the global SVs in DBD::Oracle. These globals need to be
> shared between threads, otherwise only the thread which created them, could
> access them.

I presume you're talking here about threads started after DBD::Oracle was
loaded. In this case, since handles can't be shared, the global SVs shouldn't
either.

Isn't the problem really that the DBD::Oracle code caches a pointer
to the SV struct and that pointer isn't updated when the intrepreter
is cloned?

The right fix is probably to add a CLONE sub that 'does the right thing'
by re-running certain parts of the initialization code.


> +BEGIN
> +{
> +    if($] >= 5.008) {
> +         require threads;
> +         require threads::shared;
> +    }
> +}

Should only "require threads::shared;" here _not_ "require threads;".
But even that won't be needed if you go for a CLONE sub that does a fixup
rather than using SvSHARE.

> Otherwise I will see if it is possible to get DBI handles shared, but I
> fear, it's much work and more then I have time. But I will give it a try...

I wouldn't bother putting much time in that direction.
(Certainly not till everything else is working and tested etc.)
I think it's fairly doomed.

It people want multiple threads doing DBI work in parallel then they'll
need to load the DBI (or at least connect to databases) in each thread.

Many thanks again for tackling this! You're saving me a lot of time.

Tim.

Reply via email to