Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

scrottie (4167)

scrottie
  scott@slowass.net
http://slowass.net/

My email address is scott@slowass.net. Spam me harder! *moan*

Journal of scrottie (4167)

Sunday May 20, 2007
01:28 AM

Postgres -- oops, my fault

[ #33312 ]
Earlier, I was bitching about Postgres and it's "server closed the connection unexpectedly" message.

Here's a refresher. A fellow programmer wrote a few lines of code to exercize an OO-ification I had done, where logic got moved into an object. He made it use one of two subclasses and switch back and forth. Approximately 8,000 lines after the switch, the database would ... vanish. diff'ing traces turned up nothing, and the query that died was often the same but sometimes not. Stumped. The object that gets created forks and runs some code CPU bound code in the fork but doesn't touch the database. I decided to make it close all of the $dbh's it inherited from the parent process when it forked. Boom -- server starts barfing on queries immediately after the object switch happens and the $dbh is closed in the child. Aha!

Solution: destroy the DESTROY routine so the "tell the server to go away" logic never runs. This code in the child process made the server stop going away:

    do {
        # destroy all $dbh's in the forked process, but do so in a way that doesn't
        # affect the parent's connection to the database
        use PadWalker;
        my $i;
        while(1) {
            $i++;
            my $sf = eval { PadWalker::peek_my($i) } or last;
            if(exists $sf->{'$dbh'}) {
                no strict 'refs';
                my $package = ref ${ $sf->{'$dbh'} };  # DBI::db::DESTROY
                *{$package.'::DESTROY'} = sub { };
                ${ $sf->{'$dbh'} } = undef;
            }
        }
    };

Yes, that's ugly, nasty, and evil. Seems like there would be a better way to do this. I guess one kludgey but less evil work-around would be to have the server disconnect, fork, and then reconnect to the database. So, that's the bug that had me stumped for several coding sessions and nearly a week.

-scott

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • Check out the DBI docs for this handle attribute. I think it's what you need to fix this problem.
  • I've ensured that whenever I fetch a dbh object, I fetch it from a hash keyed by pid. Or, use the pid in a closure and generate a new one if I am not currently the same pid. e.g.

      {
        my ($pid, $dbh);
        sub get_dbh {
          if ($$ != $pid) {
            $dbh = DBI->connect(...);
          }
          return $dbh;
        }
      }

    (that's off the top of my head, so probably won't work verbatim)