I'm getting this on four different web sites on three different 
machines and it's causing major problems.  Even if you don't have any 
suggestions on the problem, if you have any comments on the 
architecture I'd appreciate them.

The symptom.

Apparently randomly a page will come up with no data from the 
database.  DBIx::Recordset believes there is data--if there's a 
->Next() loop it will even loop the correct number of times--but the 
actual data from the hash is empty.  The probably typically goes away 
after a few reloads--but that may just mean I've gotten a different 
Apache process.

The configuration.

Various Linux boxes.
Perl 5.6.0 through 5.6.1
Embperl 1.3.3 and 1.3.4
DBIx::Recordset, most recent version.
MySQL.
I use the $ref variation on the return values rather than * as it's 
easier to pass around.

The architecture.

I believe I've seen this under straight HTML::Embperl, but all my 
sites are currently running HTML::EmbperlObject.
1. Apache::DBI loaded in startup.pl (not that not loading it changes anything).

2. All site templates have a line like this:
        [- Execute({ isa => 'SiteInit.html' }); -]

3. SiteInit.html defines (in a [! !]) a routine which checks to see 
if $sitename::Commons exists, if not, it creates the object.  If so, 
it returns it.  This lets me have a generic call to $_[0]->Commons() 
to get my base object structure without having to worry about which 
site I'm in.  So I get reusable code, but separate objects for each 
site, even in a virtual hosting situation.  Out of paranoia I've put 
in some other checks as well:

     sub Commons {
         my ($db, $dbh);
         my ($database, $user, $pass) = ('xxx', 'xxx', 'xxx');

         if (!$PureM::Commons) {
             #print LOG "CACHE_ERROR: Creating PureM::Commons ($$)\n";
             $PureM::Commons = new SWC::Commons(database => $database,
                                               username => $user,
                                               password => $pass,
                                               basepath => $ENV{DOCUMENT_ROOT});
         } elsif ($db = $PureM::Commons->{_db}) {
             if (!($dbh = $db->DBHdl())) {
                 print LOG "CACHE_ERROR: PureM::Commons DBD not 
defined: $db ($$)\n";
                 $PureM::Commons = new SWC::Commons(database => $database,
                                                   username => $user,
                                                   password => $pass,
                                                   basepath => 
$ENV{DOCUMENT_ROOT});
             } elsif (!$dbh->{Active}) {
                 print LOG "CACHE_ERROR: PureM::Commons DBD not 
active: $dbh ($$)\n";
                 $PureM::Commons = new SWC::Commons(database => $database,
                                                   username => $user,
                                                   password => $pass,
                                                   basepath => 
$ENV{DOCUMENT_ROOT});
             } else {
                 #print LOG "CACHE_ERROR: Already have PureM::Commons ($$)\n";
             }
         }

         return $PureM::Commons;
     }

I don't think I'm getting cache errors, unfortunately on the live 
sites I have logging turned off, I'll have to change this to dump to 
the apache log file to see if there is anything there.


4. Every database call in the library calls a setupDB method, passing 
it the table and table attributes for the database operation it's 
going to do.  setupDB looks like this:
     if (!$this->{_db}) {

         $DBIx::Recordset::FetchsizeWarn = 0;
         $this->{_db} = new DBIx::Database({
                 '!DataSource' => $connect,
                 '!DBIAttr' => {PrintError => 0, RaiseError => 1, 
AutoCommit => 1},
                 '!Username' => $this->{username},
                 '!Password' => $this->{password},
                 '!KeepOpen' => 1,
                 '!SaveAs' => 'Commons',
             }) || die $DBI::errstr;

*** Sudden thought ***. I'm not using the SaveAs, and it's the same 
across sites, so using it would get me in trouble.  Is it doing any 
harm?

        ...
         $this->{_setup} = {
                 '!DataSource' => $this->{_db},
                 '!LongNames' => 2,
                 '!Serial' => 'id',
                 '!Filter' =>
                     {
                         'dtm' => $dateparse,
                         'dtc' => $dateparse,
                         'dtv' => $dateparse,
                         'verifydate' => $dateparse,
                         'validdate' => $dateparse,
                         'approveddate' => $dateparse,
                         'pubdate' => $dateparse,
                     },
         };
     }
     my %setup = %{$this->{_setup}};
     my ($key, $val);
     while (($key, $val) = each(%args)) {
         $setup{$key} = $val;
     }

     $set = DBIx::Recordset->Setup(\%setup);
     return $set;

So a typical call looks like this:

         $set = $this->setupDB(
             '!Table'    => 'keywordmap,keyword',
             '!TabJoin'  => 'keyword JOIN keywordmap',
             '!TabRelation'      => 'id = keyword_id',
         );
        $$set->Search($args);
        return $set;

This model keeps the higher level caller from setting database stuff 
we don't want them to set (e.g. through cgi arguments).  We can set 
the ! arguments in the setupDB call, then they are restricted to the 
$ arguments.


Does this all seem like a reasonable way to preserve database 
connections in a virtual host environment?

Does *anyone* have any idea why occasionally the data doesn't show up?

-- 

Kee Hinckley - Somewhere.Com, LLC
http://consulting.somewhere.com/

I'm not sure which upsets me more: that people are so unwilling to accept
responsibility for their own actions, or that they are so eager to regulate
everyone else's.

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to