Author: timbo
Date: Mon Apr 16 15:28:24 2007
New Revision: 9419

Modified:
   dbi/trunk/Changes
   dbi/trunk/DBI.pm
   dbi/trunk/DBI.xs
   dbi/trunk/DBIXS.h
   dbi/trunk/lib/DBI/PurePerl.pm
   dbi/trunk/t/01basics.t
   dbi/trunk/t/06attrs.t

Log:
Convert CachedKids into an (almost) normal attribute
to avoid need for FETCH in connect_cached and prepare_cached.


Modified: dbi/trunk/Changes
==============================================================================
--- dbi/trunk/Changes   (original)
+++ dbi/trunk/Changes   Mon Apr 16 15:28:24 2007
@@ -24,17 +24,15 @@
 Pedantic policy should force a fresh connect each time - add new policy item
 Add attr-passthru to prepare()? ie for gofer cache control
 Terminology for client and server ends
-Document user/passwd issues at the various levels of the stack
+Document user/passwd issues at the various levels of the gofer stack
 Policy's from pod
 Policy for dbh attr FETCH (ie example_driver_path)
     or piggyback on skip_connect_check
     could also remember which attr have been returned to us
     so not bother FETCHing them (unless pedantic)
 Refactor http transport like the others re timeout
-Call method on transport timeout so transport can cleanup/reset it it wants
+Call method on transport failure so transport can cleanup/reset it it wants
 
-Implement tie in C.
-Make CachedKids a plain attrib to avoid FETCH in connect_cached/prepare_cached
 prepare(...,{ Err=>\my $isolated_err, ...})
 Add trace modules that just records the last N trace messages into an array
 and prepends them to any error message.
@@ -46,21 +44,23 @@
   Fixed 42prof_data.t on fast systems with poor timers thanks to Malcolm 
Nooning.
   Fixed gofer pipeone & stream transports to avoid risk of hanging.
 
-  Changed DBD::Gofer to work around a DBD::Sybase bind_param bug
-    (which is now fixed in DBD::Sybase 1.07)
+  Changed some handle creation code from perl to C code,
+    to reduce handle creation cost by ~20%.
+  Changed connect_cached and prepare_cached to avoid a method call which
+    reduced cost by ~5% for connect_cached and ~30% for prepare_cached.
   Changed _set_fbav to not croak when given a wrongly sized array,
     it now warns and adjusts the row buffer to match.
   Changed DBD::NullP to be slightly more useful for testing.
   Changed File::Spec prerequisite to not require a minimum version.
   Changed tests to work with other DBMs thanks to ZMAN.
-  Changed some handle creation code from perl to C code,
-    so handle creation cost reduced by ~20%.
-  Many assorted Gofer related bug fixes, enhancements and docs.
+  Changed DBD::Gofer to work around a DBD::Sybase bind_param bug
+    (which is now fixed in DBD::Sybase 1.07)
+  Many other assorted Gofer related bug fixes, enhancements and docs.
 
-  Added goferperf.pl utility (doesn't get installed).
-  Added dbilogstrip utility (gets installed)
   Added support for DBI Profile Path to contain refs to scalars
     which will be de-ref'd for each profile sample.
+  Added goferperf.pl utility (doesn't get installed).
+  Added dbilogstrip utility (gets installed)
 
 =head2 Changes in DBI 1.54 (svn rev 9157),  23rd February 2007
 

Modified: dbi/trunk/DBI.pm
==============================================================================
--- dbi/trunk/DBI.pm    (original)
+++ dbi/trunk/DBI.pm    Mon Apr 16 15:28:24 2007
@@ -1410,14 +1410,10 @@
 
 
     sub connect_cached {
-       my $drh = shift;
-       my ($dsn, $user, $auth, $attr)= @_;
+        my $drh = shift;
+       my ($dsn, $user, $auth, $attr) = @_;
 
-       # Needs support at dbh level to clear cache before complaining about
-       # active children. The XS template code does this. Drivers not using
-       # the template must handle clearing the cache themselves.
-       my $cache = $drh->FETCH('CachedKids');
-       $drh->STORE('CachedKids', $cache = {}) unless $cache;
+       my $cache = $drh->{CachedKids} ||= {};
 
        my @attr_keys = $attr ? sort keys %$attr : ();
        my $key = do { local $^W; # silence undef warnings
@@ -1627,8 +1623,7 @@
        # Needs support at dbh level to clear cache before complaining about
        # active children. The XS template code does this. Drivers not using
        # the template must handle clearing the cache themselves.
-       my $cache = $dbh->FETCH('CachedKids');
-       $dbh->STORE('CachedKids', $cache = {}) unless $cache;
+       my $cache = $dbh->{CachedKids} ||= {};
        my @attr_keys = ($attr) ? sort keys %$attr : ();
        my $key = ($attr) ? join("~~", $statement, @attr_keys, @[EMAIL 
PROTECTED]) : $statement;
        my $sth = $cache->{$key};

Modified: dbi/trunk/DBI.xs
==============================================================================
--- dbi/trunk/DBI.xs    (original)
+++ dbi/trunk/DBI.xs    Mon Apr 16 15:28:24 2007
@@ -1147,6 +1147,16 @@
        }
     }
 
+    /* setup CachedKids */
+    if (DBIc_TYPE(imp) < DBIt_ST) {
+        SV **tmp_svp = hv_fetch((HV*)SvRV(h), "CachedKids", 10, 1);
+        imp_dbh_t *imp_dbh = (imp_dbh_t*)imp; /* also drh */
+        if (!SvROK(*tmp_svp) || SvTYPE(SvRV(*tmp_svp)) != SVt_PVHV) {
+           sv_setsv(*tmp_svp, newRV_noinc((SV*)newHV()));
+        }
+        DBIc_CACHED_KIDS_SVP(imp_dbh) = tmp_svp;
+    }
+
     /* Use DBI magic on inner handle to carry handle attributes        */
     sv_magic(SvRV(h), dbih_imp_sv, DBI_MAGIC, Nullch, 0);
     SvREFCNT_dec(dbih_imp_sv); /* since sv_magic() incremented it      */
@@ -1236,8 +1246,9 @@
 
     if (DBIc_TYPE(imp_xxh) <= DBIt_DB) {
        const imp_dbh_t *imp_dbh = (imp_dbh_t*)imp_xxh;
-       if (DBIc_CACHED_KIDS(imp_dbh))
-           PerlIO_printf(DBILOGFP,"%s CachedKids %d\n", pad, 
(int)HvKEYS(DBIc_CACHED_KIDS(imp_dbh)));
+       HV *hv = DBIc_CACHED_KIDS(imp_dbh);
+       if (hv && HvKEYS(hv))
+           PerlIO_printf(DBILOGFP,"%s CachedKids %d\n", pad, (int)HvKEYS(hv));
     }
     if (DBIc_TYPE(imp_xxh) == DBIt_ST) {
        const imp_sth_t *imp_sth = (imp_sth_t*)imp_xxh;
@@ -1307,13 +1318,13 @@
 
     if (!dirty) {
        if (DBIc_TYPE(imp_xxh) <= DBIt_DB) {
+            HV *hv;
            imp_dbh_t *imp_dbh = (imp_dbh_t*)imp_xxh; /* works for DRH also */
-           if (DBIc_CACHED_KIDS(imp_dbh)) {
+           if ((hv=DBIc_CACHED_KIDS(imp_dbh)) && HvKEYS(hv)>0) {
                warn("DBI %s handle 0x%lx cleared whilst still holding %d 
cached kids",
                         dbih_htype_name(DBIc_TYPE(imp_xxh)),
-                       (unsigned long)DBIc_MY_H(imp_xxh), 
(int)HvKEYS(DBIc_CACHED_KIDS(imp_dbh)) );
-               SvREFCNT_dec(DBIc_CACHED_KIDS(imp_dbh)); /* may recurse */
-               DBIc_CACHED_KIDS(imp_dbh) = Nullhv;
+                       (unsigned long)DBIc_MY_H(imp_xxh), (int)HvKEYS(hv) );
+               hv_clear(hv); /* may recurse */
            }
        }
 
@@ -1708,15 +1719,11 @@
     else if (strEQ(key, "TaintOut")) {
        DBIc_set(imp_xxh,DBIcf_TaintOut, on);
     }
-    else if (htype<=DBIt_DB && keylen==10 && strEQ(key, "CachedKids")) {
-       D_imp_dbh(h);   /* XXX also for drh */
-       if (DBIc_CACHED_KIDS(imp_dbh)) {
-           SvREFCNT_dec(DBIc_CACHED_KIDS(imp_dbh));
-           DBIc_CACHED_KIDS(imp_dbh) = Nullhv;
-       }
-       if (SvROK(valuesv)) {
-           DBIc_CACHED_KIDS(imp_dbh) = (HV*)SvREFCNT_inc(SvRV(valuesv));
-       }
+    else if (htype<=DBIt_DB && keylen==10 && strEQ(key, "CachedKids")
+        /* only allow hash refs */
+        && SvROK(valuesv) && SvTYPE(SvRV(valuesv))==SVt_PVHV
+    ) {
+       cacheit = 1;
     }
     else if (keylen==9 && strEQ(key, "Callbacks")) {
        if ( on && (!SvROK(valuesv) || (SvTYPE(SvRV(valuesv)) != SVt_PVHV)) )
@@ -1940,12 +1947,7 @@
     }
 
     if (valuesv == Nullsv && htype <= DBIt_DB) {
-        if (keylen==10  && strEQ(key, "CachedKids")) {
-           D_imp_dbh(h);
-           HV *hv = DBIc_CACHED_KIDS(imp_dbh);
-           valuesv = (hv) ? newRV((SV*)hv) : &sv_undef;
-       }
-        else if (keylen==10 && strEQ(key, "AutoCommit")) {
+        if (keylen==10 && strEQ(key, "AutoCommit")) {
             valuesv = boolSV(DBIc_has(imp_xxh,DBIcf_AutoCommit));
         }
     }
@@ -2251,20 +2253,24 @@
 static void
 clear_cached_kids(SV *h, imp_xxh_t *imp_xxh, const char *meth_name, int 
trace_level)
 {
-    dTHX;
-    dPERINTERP;
-    if (DBIc_TYPE(imp_xxh) <= DBIt_DB && 
DBIc_CACHED_KIDS((imp_drh_t*)imp_xxh)) {
-       if (DBIc_TRACE_LEVEL(imp_xxh) > trace_level)
-           trace_level = DBIc_TRACE_LEVEL(imp_xxh);
-       if (trace_level >= 2) {
-           PerlIO_printf(DBILOGFP,"    >> %s %s clearing %d CachedKids\n",
-               meth_name, neatsvpv(h,0), 
(int)HvKEYS(DBIc_CACHED_KIDS((imp_drh_t*)imp_xxh)));
-           PerlIO_flush(DBILOGFP);
-       }
-       /* This will probably recurse through dispatch to DESTROY the kids */
-       /* For drh we should probably explicitly do dbh disconnects */
-       SvREFCNT_dec(DBIc_CACHED_KIDS((imp_drh_t*)imp_xxh));
-       DBIc_CACHED_KIDS((imp_drh_t*)imp_xxh) = Nullhv;
+    HV *hv;
+
+    if (DBIc_TYPE(imp_xxh) > DBIt_DB)
+        return;
+    hv = DBIc_CACHED_KIDS((imp_drh_t*)imp_xxh);
+    if (hv && HvKEYS(hv)) {
+        dTHX;
+        dPERINTERP;
+        if (DBIc_TRACE_LEVEL(imp_xxh) > trace_level)
+            trace_level = DBIc_TRACE_LEVEL(imp_xxh);
+        if (trace_level >= 2) {
+            PerlIO_printf(DBILOGFP,"    >> %s %s clearing %d CachedKids\n",
+                meth_name, neatsvpv(h,0), (int)HvKEYS(hv));
+            PerlIO_flush(DBILOGFP);
+        }
+        /* This will probably recurse through dispatch to DESTROY the kids */
+        /* For drh we should probably explicitly do dbh disconnects */
+        hv_clear(hv);
     }
 }
 
@@ -2703,7 +2709,7 @@
                goto is_DESTROY_wrong_thread;
            }
 #endif
-           if (imp_xxh && DBIc_TYPE(imp_xxh) <= DBIt_DB && 
DBIc_CACHED_KIDS((imp_drh_t*)imp_xxh))
+           if (imp_xxh && DBIc_TYPE(imp_xxh) <= DBIt_DB)
                clear_cached_kids(mg->mg_obj, imp_xxh, meth_name, trace_level);
            if (trace_level >= 3) {
                 /* XXX might be better to move this down to after call_depth 
has been
@@ -2931,8 +2937,7 @@
                sv_setsv(DBIc_STATE(parent_imp),  DBIc_STATE(imp_xxh));
            }
 
-           if (DBIc_CACHED_KIDS((imp_drh_t*)imp_xxh))
-               clear_cached_kids(h, imp_xxh, meth_name, trace_flags);
+            clear_cached_kids(h, imp_xxh, meth_name, trace_flags);
        }
 
        if (DBIc_IADESTROY(imp_xxh)) { /* want's ineffective destroy    */
@@ -3883,19 +3888,18 @@
     SV *       imp_datasv
     SV *       imp_class
     PPCODE:
-    dTHX;
     dPERINTERP;
     HV *outer;
     SV *outer_ref;
-    GV *class_stash = gv_stashsv(class, GV_ADDWARN);
-    (void)cv;
+    HV *class_stash = gv_stashsv(class, GV_ADDWARN);
 
     if (DBIS_TRACE_LEVEL >= 3) {
         PerlIO_printf(DBILOGFP, "    New %s (for %s, parent=%s, id=%s)\n",
             neatsvpv(class,0), SvPV_nolen(imp_class), neatsvpv(parent,0), 
neatsvpv(imp_datasv,0));
+        (void)cv; /* avoid unused warning */
     }
 
-    hv_store(SvRV(attr_ref), "ImplementorClass", 16, SvREFCNT_inc(imp_class), 
0);
+    hv_store((HV*)SvRV(attr_ref), "ImplementorClass", 16, 
SvREFCNT_inc(imp_class), 0);
 
     /* make attr into inner handle by blessing it into class */
     sv_bless(attr_ref, class_stash);
@@ -3906,16 +3910,7 @@
     sv_bless(outer_ref, class_stash);
     /* tie outer handle to inner handle */
     sv_magic((SV*)outer, attr_ref, PERL_MAGIC_tied, Nullch, 0);
-    /*SvREFCNT_dec(attr_ref);  /* because sv_magic() incremented it */
 
-    /*
-        my (%outer, $i, $h);
-        $i = tie    %outer, $class, $attr;  # ref to inner hash (for driver)
-        $h = bless \%outer, $class;         # ref to outer hash (for 
application)
-        DBI::_setup_handle($h, $imp_class, $parent, $imp_data);
-        return $h unless wantarray;
-        return ($h, $i);
-    */
     dbih_setup_handle(outer_ref, SvPV_nolen(imp_class), parent, 
SvOK(imp_datasv) ? imp_datasv : Nullsv);
 
     /* return outer handle, plus inner handle if not in scalar context */
@@ -4329,7 +4324,7 @@
      * destroyed they may need to interact with the 'zombie' parent dbh.
      * So we do our best to neautralize them (finish & rebless)
      */
-    if (DBIc_TYPE(imp_xxh) <= DBIt_DB && DBIc_CACHED_KIDS((imp_dbh_t*)imp_xxh))
+    if (DBIc_TYPE(imp_xxh) <= DBIt_DB)
        clear_cached_kids(h, imp_xxh, "take_imp_data", 0);
     if ((tmp_svp = hv_fetch((HV*)SvRV(h), "ChildHandles", 12, FALSE)) && 
SvROK(*tmp_svp)) {
        AV *av = (AV*)SvRV(*tmp_svp);

Modified: dbi/trunk/DBIXS.h
==============================================================================
--- dbi/trunk/DBIXS.h   (original)
+++ dbi/trunk/DBIXS.h   Mon Apr 16 15:28:24 2007
@@ -133,13 +133,13 @@
 typedef struct {               /* -- DRIVER --                         */
     dbih_com_std_t     std;
     dbih_com_attr_t    attr;
-    HV          *cached_kids;  /* $drh->connect_cached(...)            */
+    SV          **cached_kids_svp;      /* \($h->{CachedKids}) */
 } dbih_drc_t;
 
 typedef struct {               /* -- DATABASE --                       */
     dbih_com_std_t     std;    /* \__ standard structure               */
     dbih_com_attr_t    attr;   /* /   plus... (nothing else right now) */
-    HV          *cached_kids;  /* $dbh->prepare_cached(...)            */
+    SV          **cached_kids_svp;     /* \($h->{CachedKids}) */
 } dbih_dbc_t;
 
 typedef struct {               /* -- STATEMENT --                      */
@@ -231,8 +231,9 @@
 #define DBIc_FetchHashKeyName(imp) (_imp2com(imp, attr.FetchHashKeyName))
 
 /* handle sub-type specific fields                                             
*/
-/*     dbh     */
-#define DBIc_CACHED_KIDS(imp)          _imp2com(imp, cached_kids)
+/*     dbh & drh       */
+#define DBIc_CACHED_KIDS_SVP(imp) _imp2com(imp, cached_kids_svp)
+#define DBIc_CACHED_KIDS(imp)          ((HV*)SvRV( *DBIc_CACHED_KIDS_SVP(imp) 
))
 /*     sth     */
 #define DBIc_NUM_FIELDS(imp)   _imp2com(imp, num_fields)
 #define DBIc_NUM_PARAMS(imp)   _imp2com(imp, num_params)

Modified: dbi/trunk/lib/DBI/PurePerl.pm
==============================================================================
--- dbi/trunk/lib/DBI/PurePerl.pm       (original)
+++ dbi/trunk/lib/DBI/PurePerl.pm       Mon Apr 16 15:28:24 2007
@@ -484,6 +484,7 @@
        }
        elsif (ref($parent) =~ /::dr$/){
            $h_inner->{Driver} = $parent;
+            $h_inner->{CachedKids} ||= {};
        }
        $h_inner->{_parent} = $parent;
 
@@ -508,6 +509,7 @@
        $h_inner->{FetchHashKeyName}    ||= 'NAME';
        $h_inner->{LongReadLen}         ||= 80;
        $h_inner->{ChildHandles}        ||= [] if $HAS_WEAKEN;
+       $h_inner->{CachedKids}          ||= {};
        $h_inner->{Type}                ||= 'dr';
     }
     $h_inner->{"_call_depth"} = 0;

Modified: dbi/trunk/t/01basics.t
==============================================================================
--- dbi/trunk/t/01basics.t      (original)
+++ dbi/trunk/t/01basics.t      Mon Apr 16 15:28:24 2007
@@ -2,7 +2,7 @@
 
 use strict;
 
-use Test::More tests => 132;
+use Test::More tests => 131;
 use File::Spec;
 
 $|=1;
@@ -176,11 +176,11 @@
 cmp_ok(($switch->{private_test1} = 1), '==', 1, '... this should work and 
return 1');
 cmp_ok($switch->{private_test1},       '==', 1, '... this should equal 1');
 
-ok(!defined $switch->{CachedKids},     '... CachedKids shouldnt be defined');
-ok(($switch->{CachedKids} = { }),      '... assigned empty hash to 
CachedKids');
 is(ref($switch->{CachedKids}), 'HASH', '... CachedKids should be a HASH 
reference');
-
-cmp_ok(scalar(keys(%{$switch->{CachedKids}})), '==', 0, '... CachedKids should 
be an empty HASH reference');
+ok(!keys %{ $switch->{CachedKids} },   '... CachedKids should be empty');
+my $cache = {};
+$switch->{CachedKids} = $cache;
+is($switch->{CachedKids}, $cache,      '... CachedKids should be our ref');
 
 cmp_ok($switch->{Kids},       '==', 0, '... this should be zero');
 cmp_ok($switch->{ActiveKids}, '==', 0, '... this should be zero');

Modified: dbi/trunk/t/06attrs.t
==============================================================================
--- dbi/trunk/t/06attrs.t       (original)
+++ dbi/trunk/t/06attrs.t       Mon Apr 16 15:28:24 2007
@@ -61,7 +61,7 @@
     cmp_ok($dbh->{ActiveKids}, '==', 0, '... checking ActiveKids attribute for 
dbh');;
 }
 
-ok(!defined $dbh->{CachedKids},   '... checking CachedKids attribute for dbh');
+is(ref $dbh->{CachedKids},'HASH', '... checking CachedKids attribute for dbh');
 ok(!defined $dbh->{HandleError},  '... checking HandleError attribute for 
dbh');
 ok(!defined $dbh->{Profile},      '... checking Profile attribute for dbh');
 ok(!defined $dbh->{Statement},    '... checking Statement attribute for dbh');
@@ -128,7 +128,7 @@
     cmp_ok($drh->{ActiveKids}, '==', 1, '... checking ActiveKids attribute for 
drh');
 }
 
-ok(!defined $drh->{CachedKids},  '... checking CachedKids attribute for drh');
+is(ref $drh->{CachedKids},'HASH','... checking CachedKids attribute for drh');
 ok(!defined $drh->{HandleError}, '... checking HandleError attribute for drh');
 ok(!defined $drh->{Profile},     '... checking Profile attribute for drh');
 

Reply via email to