perljunky has asked for the wisdom of the Perl Monks concerning the following question:

I have the following snippet of code. I make a DBI connection and after which sleep does not 'sleep'. Attached is my code
use DBI; while (1) { # never ending loop my ($sec,$min,$hour,$mday,$mon,$year) = localtime(time); $mon++; + $year+=1900; $now = sprintf("%02d/%02d/%04d %02d:%02d:%02d", $mon, $mday, $year, $hour, $min, $sec); print "Time before sleep $now\n"; sleep 30; print "Time after sleep $now\n"; $dbh = ();# Initializing the dbi variables $dbh = DBI->connect("DBI:Oracle:DEMODB", "DEMO" , "DEMO", { PrintError => 0 } ) or die "Unable to connect to DB $DB $!"; $dbh->disconnect or die; }
Attached is the output
Time before sleep 09/14/2007 13:21:08 Time after sleep 09/14/2007 13:21:08 Time before sleep 09/14/2007 13:21:38 Time after sleep 09/14/2007 13:21:38 Time before sleep 09/14/2007 13:21:38 Time after sleep 09/14/2007 13:21:38 Time before sleep 09/14/2007 13:21:38 Time after sleep 09/14/2007 13:21:38 Time before sleep 09/14/2007 13:21:38 Time after sleep 09/14/2007 13:21:38 Time before sleep 09/14/2007 13:21:39 Time after sleep 09/14/2007 13:21:39 Time before sleep 09/14/2007 13:21:39 Time after sleep 09/14/2007 13:21:39 Time before sleep 09/14/2007 13:21:39 Time after sleep 09/14/2007 13:21:39 Time before sleep 09/14/2007 13:21:39 Time after sleep 09/14/2007 13:21:39 Time before sleep 09/14/2007 13:21:39 Time after sleep 09/14/2007 13:21:39
So the first sleep works just fine but subsequent sleeps dont really sleep. Please help. Thanks I added an additional sleep clause after the first sleep and that seems to do the trick. So the first sleep fails the second one works. Blow is the new code -- Thanks ikegami
while (1) { # never ending loop my ($sec,$min,$hour,$mday,$mon,$year) = localtime(time); $mon++; + $year+=1900; $now = sprintf("%02d/%02d/%04d %02d:%02d:%02d", $mon, $mday, $year, $hour, $min, $sec); print "Time before 1st sleep $now\n"; sleep 30; $now = sprintf("%02d/%02d/%04d %02d:%02d:%02d", $mon, $mday, $year, $hour, $min, $sec); print "Time after 1st sleep $now\n"; $now = sprintf("%02d/%02d/%04d %02d:%02d:%02d", $mon, $mday, $year, $hour, $min, $sec); # new sleep added BELOW print "Time before 2nd sleep $now\n"; sleep 30; $now = sprintf("%02d/%02d/%04d %02d:%02d:%02d", $mon, $mday, $year, $hour, $min, $sec); print "Time after 2nd sleep $now\n"; $dbh = ();# Initializing the dbi variables $dbh = DBI->connect("DBI:Oracle:DEMODB", "DEMO" , "DEMO", { PrintError => 0 } ) or die "Unable to connect to DB $DB $!"; $dbh->disconnect or die; }

Replies are listed 'Best First'.
Re: DBI messes up sleep
by ikegami (Patriarch) on Sep 14, 2007 at 21:05 UTC

    Sleep is woken by signals. Perhaps some are being used by the database driver. Just keep going back to sleep until you want to wake up.

    # Optional, but a good idea with short durations. use Time::HiRes qw( sleep time ); sub uninterrupted_sleep { my ($duration) = @_; die if !$duration; my $sleep_till = time() + $duration; while ($duration > 0) { sleep($duration); $duration = $sleep_till - time(); } }
      When I put another sleep 30 at the end of the while loop the second sleep doesnt really sleep but then the first sleep kicks in and works as expected.
        That's consistent with what I said. That it only interrupts once is great! My solution will handle that nicely.

        Definitly sounds like a bug that should be reported to the DBI maintainers.


        ___________
        Eric Hodges
Re: DBI messes up sleep
by runrig (Abbot) on Sep 14, 2007 at 20:48 UTC
    Something that jumps out at me but doesn't explain your problem is that $! is for system errors not DBI errors. Those would be in $DBI::errstr, or you could just set RaiseError in the connect. But like I said, that doesn't explain this behavior unless there's some other loop around this loop that you're not showing.
      Thanks. The code is complete. My big piece of code was using up lot of CPU cycles and I then narrowed down to his chunk of code. This snippet of code when I run after the first sleep becomes an insomniac.
Re: DBI messes up sleep
by pilcrow (Sexton) on Sep 15, 2007 at 04:21 UTC

    What does a kernel trace via truss/ktrace/strace/tusc/par/etc. show? That ought to confirm ikegami's suspicion of signalry right away.

    That suspicion, FWIW, strikes me as probably correct. IIRC, at least some versions of the OCI handled at least SIGINTs themselves, and the Sys::SigAction pod documents one coder's woe in dealing with 5.8's signal behavior vis-a-vis Oracle. Your versions of Perl, DBD::Oracle and the OCI will probably factor in to what's gone awry, as might something subtly wrong with your connection to the Oracle data source.

    -pilcrow
      The perl and the DBI I am using is an older version and he OS it runs on is a Dec Unix box. The sysadmin had been having trouble of late installing modules on the dec boxes. FYI The current version of perl I am using is
      version 5.6.1 built for alpha-dec_osf DBI version:1.2.1
      Thanks for your response. For now I'll workaround with an additional sleep command. And yes this was a snippet of code that I quicky plucked out and forgot to include the localtime call before the second print.
Re: DBI messes up sleep
by bigmacbear (Monk) on Sep 14, 2007 at 22:48 UTC

    I think your issue is that you only actually check the time once, in the very first statement in the loop, when you run localtime(time). All the sprintf commands that follow merely format the same snapshot in time.

    One of the nice features of localtime and gmtime in Perl is that if you run them in scalar context, you get a string with the time already formatted for you. So all you need to do to fix this issue is replace the assignment to $now every time it appears with:

    $now = localtime(time);

    and get rid of the first line that begins with "my" in its entirety. This will give you a much clearer picture of whether or not your sleep commands are being messed up by DBI, because they will be more accurate.

      ...you only actually check the time once, in the very first statement in the loop...

      No, localtime is called for each of many loop iterations, as you'll see if you inspect the sample output or re-examine (or run) the code.

      (I, too, saw the OP's false and misleading "time after sleep" print statement, and initially thought as did you.)

      -pilcrow

        I have to agree with bigmacbear that localtime is only called once per iteration. So the shown behaviour is as expected.