Author: timbo
Date: Wed Apr 18 04:49:07 2007
New Revision: 9434

Modified:
   dbi/trunk/Changes
   dbi/trunk/DBI.pm
   dbi/trunk/dbilogstrip.PL
   dbi/trunk/lib/DBD/Gofer/Transport/pipeone.pm
   dbi/trunk/lib/DBI/Gofer/Transport/Base.pm

Log:
Document dbilogstrip.
Refactor DBI/Gofer/Transport/Base slightly and add in a 'packet header' with 
basic transport version number.
Make DBI profile object that's enabled via DBI_PROFILE be accessible externally 
(our not my).


Modified: dbi/trunk/Changes
==============================================================================
--- dbi/trunk/Changes   (original)
+++ dbi/trunk/Changes   Wed Apr 18 04:49:07 2007
@@ -34,15 +34,23 @@
 Call method on transport failure so transport can cleanup/reset it it wants
 
 prepare(...,{ Err=>\my $isolated_err, ...})
+Move _new_sth to DBI::db::_new_sth (leave alias) and implement in C
+Or call _new_child and move to DBI::common?
 Add trace modules that just records the last N trace messages into an array
 and prepends them to any error message.
 
 =head2 Changes in DBI 1.55 (svn rev XXX),  XXX
 
+XXX DBIc_CACHED_KIDS needs to be an lvalue for Drivers using Driver.xst
+Perl.xs: In function 'XS_DBD__Perl__db_disconnect':
+Perl.xs:277: warning: target of assignment not really an lvalue; this will be 
a hard error in the future
+Perl.xs: In function 'XS_DBD__Perl__db_DESTROY':
+Perl.xs:337: warning: target of assignment not really an lvalue; this will be 
a hard error in the future
+
+
   Fixed set_err so HandleSetErr hook is executed reliably, if set.
   Fixed accuracy of profiling when perl configured to use long doubles.
   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 some handle creation code from perl to C code,
     to reduce handle creation cost by ~20%.
@@ -53,14 +61,19 @@
   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 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 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)
+  Added dbilogstrip utility to edit DBI logs for diff'ing (gets installed)
+
+  Gofer related changes:
+    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)
+    Added goferperf.pl utility (doesn't get installed).
+    Many other assorted Gofer related bug fixes, enhancements and docs.
+    Both client and server sides will need upgrading in sync,
+      that shouldn't be needed in future.
 
 =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    Wed Apr 18 04:49:07 2007
@@ -1183,7 +1183,7 @@
 # These three special constructors are called by the drivers
 # The way they are called is likely to change.
 
-my $profile;
+our $shared_profile;
 
 sub _new_drh { # called by DBD::<drivername>::driver()
     my ($class, $initial_attr, $imp_data) = @_;
@@ -1208,12 +1208,12 @@
        # The profile object created here when the first driver is loaded
        # is shared by all drivers so we end up with just one set of profile
        # data and thus the 'total time in DBI' is really the true total.
-       if (!$profile) {        # first time
+       if (!$shared_profile) { # first time
            $h->{Profile} = $ENV{DBI_PROFILE};
-           $profile = $h->{Profile};
+           $shared_profile = $h->{Profile};
        }
        else {
-           $h->{Profile} = $profile;
+           $h->{Profile} = $shared_profile;
        }
     }
     return $h unless wantarray;

Modified: dbi/trunk/dbilogstrip.PL
==============================================================================
--- dbi/trunk/dbilogstrip.PL    (original)
+++ dbi/trunk/dbilogstrip.PL    Wed Apr 18 04:49:07 2007
@@ -4,13 +4,48 @@
 my $script = <<'SCRIPT';
 ~startperl~
 
+=head1 NAME
+
+dbilogstrip - filter to normalize DBI trace logs for diff'ing
+
+=head1 SYNOPSIS
+
+Read DBI trace file C<dbitrace.log> and write out a stripped version to 
C<dbitrace_stripped.log>
+
+  dbilogstrip dbitrace.log > dbitrace_stripped.log
+
+Run C<yourscript.pl> twice, each with different sets of arguments, with
+DBI_TRACE enabled. Filter the output and trace through C<dbilogstrip> into a
+separate file for each run. Then compare using diff. (This example assumes
+you're using a standard shell.)
+
+  DBI_TRACE=2 perl yourscript.pl ...args1... 2>&1 | dbilogstrip > dbitrace1.log
+  DBI_TRACE=2 perl yourscript.pl ...args2... 2>&1 | dbilogstrip > dbitrace2.log
+  diff -u dbitrace1.log dbitrace2.log
+
+=head1 DESCRIPTION
+
+Replaces any hex addresses, e.g, C<0x128f72ce> with C<0xN>.
+
+Replaces any references to process id or thread id, like C<pid#6254> with 
C<pidN>.
+
+So a DBI trace line like this:
+
+  -> STORE for DBD::DBM::st (DBI::st=HASH(0x19162a0)~0x191f9c8 'f_params' 
ARRAY(0x1922018)) thr#1800400
+
+will look like this:
+
+  -> STORE for DBD::DBM::st (DBI::st=HASH(0xN)~0xN 'f_params' ARRAY(0xN)) thrN
+
+=cut
+
 use strict;
 
 while (<>) {
-    # normalize hex addresses: 0xDEADHEAD => 0x
-    s/ \b 0x [0-9a-f]+ /0x/gx;
-    # normalize process id number
-    s/ \b pid \W? \d+ /pidN/gx;
+    # normalize hex addresses: 0xDEADHEAD => 0xN
+    s/ \b 0x [0-9a-f]+ /0xN/gx;
+    # normalize process and thread id number
+    s/ \b (pid|tid|thr) \W? \d+ /${1}N/gx;
 
 } continue {
     print or die "-p destination: $!\n";

Modified: dbi/trunk/lib/DBD/Gofer/Transport/pipeone.pm
==============================================================================
--- dbi/trunk/lib/DBD/Gofer/Transport/pipeone.pm        (original)
+++ dbi/trunk/lib/DBD/Gofer/Transport/pipeone.pm        Wed Apr 18 04:49:07 2007
@@ -136,7 +136,7 @@
             unless ($rv) {              # error (undef) or end of file (0)
                 my $action;
                 unless (defined $rv) {  # was an error
-                    $self->trace_msg("error on handle $fh: $!") if $trace >= 4;
+                    $self->trace_msg("error on handle $fh: $!\n") if $trace >= 
4;
                     $action = $actions->{error} || $actions->{eof};
                     ++$errors;
                     # XXX an error may be a permenent condition of the handle
@@ -144,10 +144,10 @@
                 }
                 else {
                     $action = $actions->{eof};
-                    $self->trace_msg("eof on handle $fh") if $trace >= 4;
+                    $self->trace_msg("eof on handle $fh\n") if $trace >= 4;
                 }
                 if ($action->($fh)) {
-                    $self->trace_msg("removing $fh from handle set") if $trace 
>= 4;
+                    $self->trace_msg("removing $fh from handle set\n") if 
$trace >= 4;
                     $ios->remove($fh);
                 }
                 next;

Modified: dbi/trunk/lib/DBI/Gofer/Transport/Base.pm
==============================================================================
--- dbi/trunk/lib/DBI/Gofer/Transport/Base.pm   (original)
+++ dbi/trunk/lib/DBI/Gofer/Transport/Base.pm   Wed Apr 18 04:49:07 2007
@@ -10,8 +10,6 @@
 use strict;
 use warnings;
 
-use Storable qw(nfreeze thaw);
-
 use base qw(DBI::Util::_accessor);
 
 our $VERSION = sprintf("0.%06d", q$Revision$ =~ /(\d+)/o);
@@ -20,6 +18,7 @@
 __PACKAGE__->mk_accessors(qw(
     trace
     go_policy
+    serializer_obj
 ));
 
 
@@ -30,40 +29,72 @@
 sub new {
     my ($class, $args) = @_;
     $args->{trace} ||= $class->_init_trace;
+    $args->{serializer_obj} ||= DBI::Gofer::Serializer->new();
     my $self = bless {}, $class;
     $self->$_( $args->{$_} ) for keys %$args;
     $self->trace_msg("$class->new({ @{[ %$args ]} })\n") if $self->trace;
     return $self;
 }
 
+{   package DBI::Gofer::Serializer;
+    # a very minimal subset of Data::Serializer
+    use Storable qw(nfreeze thaw);
+    sub new {
+        return bless {} => shift;
+    }
+    sub serializer {
+        my $self = shift;
+        local $Storable::forgive_me = 1; # for CODE refs etc
+        return nfreeze(shift);
+    }
+    sub deserializer {
+        my $self = shift;
+        return thaw(shift);
+    }
+}
+
 
+my $packet_header_text  = "GoFER1:";
+my $packet_header_regex = qr/^GoFER(\d):/;
 
-sub freeze_request  { return shift->_freeze_data("request",  @_) }
-sub freeze_response { return shift->_freeze_data("response", @_) }
-sub thaw_request    { return shift->_thaw_data("request",  @_)   }
-sub thaw_response   { return shift->_thaw_data("response", @_)   }
 
 sub _freeze_data {
-    my ($self, $what, $data, $skip_trace) = @_;
-    $self->_dump("freezing $self->{trace} ".ref($data), $data)
-        if !$skip_trace and $self->trace;
-    local $Storable::forgive_me = 1; # for CODE refs etc
-    my $frozen = eval { nfreeze($data) };
+    my ($self, $data, $skip_trace) = @_;
+    my $frozen = eval {
+        $self->_dump("freezing $self->{trace} ".ref($data), $data)
+            if !$skip_trace and $self->trace;
+
+        my $header = $packet_header_text;
+        my $data = $self->{serializer_obj}->serializer($data);
+        $header.$data;
+    };
     if ($@) {
         chomp $@;
         die "Error freezing ".ref($data)." object: $@";
     }
     return $frozen;
-}   
+}
+# public aliases used by subclasses
+*freeze_request  = \&_freeze_data;
+*freeze_response = \&_freeze_data;
+
 
 sub _thaw_data {
-    my ($self, $what, $frozen_data, $skip_trace) = @_;
-    my $data = eval { thaw($frozen_data) };
+    my ($self, $frozen_data, $skip_trace) = @_;
+    my $data;
+    eval {
+        # check for and extract our gofer header and the info it contains
+        $frozen_data =~ s/$packet_header_regex//o
+            or die "does not have gofer header\n";
+        my ($t_version) = $1;
+        $data = $self->{serializer_obj}->deserializer($frozen_data)
+            and $data->{_transport}{version} = $t_version;
+    };
     if ($@) {
         chomp(my $err = $@);
         # remove extra noise from Storable
         $err =~ s{ at \S+?/Storable.pm \(autosplit into 
\S+?/Storable/thaw.al\) line \d+(, \S+ line \d+)?}{};
-        my $msg = sprintf "Error thawing $what: %s (data=%s)", $err, 
DBI::neat($frozen_data,50);
+        my $msg = sprintf "Error thawing: %s (data=%s)", $err, 
DBI::neat($frozen_data,50);
         Carp::cluck("$msg, pid $$ stack trace follows:"); # XXX if 
$self->trace;
         die $msg;
     }
@@ -71,9 +102,13 @@
         if !$skip_trace and $self->trace;
     return $data;
 }
+# public aliases used by subclasses
+*thaw_request  = \&_thaw_data;
+*thaw_response = \&_thaw_data;
 
 
-
+# this should probably live in the request and response classes
+# and the tace level passed in
 sub _dump {
     my ($self, $label, $data) = @_;
     if ($self->trace >= 2) {
@@ -86,7 +121,6 @@
         local $Data::Dumper::Deparse   = 0;
         local $Data::Dumper::Purity    = 0;
         $self->trace_msg("$label: ".Data::Dumper::Dumper($data));
-        return;
     }
     else {
         my $summary = eval { $data->summary_as_text } || $@ || "no summary 
available\n";

Reply via email to