in reply to Re^4: Perl Alarm Not Working
in thread Perl Alarm Not Working

There's two different issues at play:

When it takes longer than the timeout, does it say "alarm" and ", Time Ran" or just "Time Ran"? If it's the former, you have crazy long database calls and should look at fixing that. If it's the latter, DBD::mysql is probably using alarm itself so you're pre-empted from using it yourself.

Replies are listed 'Best First'.
Re^6: Perl Alarm Not Working
by aceofspace (Acolyte) on Dec 20, 2010 at 06:11 UTC
    Most of time, it will not timeout. In these instances, it will not get into the if($@) loop.
    It will have the following results for various keywords, $keywords:

    Time Ran: 0, Total Count: 3560
    Time Ran: 0, Total Count: 7860
    Time Ran: 0, Total Count: 17863

    For some keywords, it will timeout and it will get into the if($@) loop with results like the followings:

    Alarm, Time Ran: 18, Total Count: 0
    Alarm, Time Ran: 12, Total Count: 0

    They all overshoot the set timeout limit of 5 sec. considerably.

    It appears that MySql is doing funny things to SIGALRM.

    Questions:

    1) Is this problem fixable?

    2) The whole purpose of this exercise is to find a way to get out of the MySql operation if it takes longer than 5 sec. to do MySql. Timeout at around 5 sec. not at anything above 5 sec. If above problem is not fixable, meaning we cannot use eval {} to limit MySql time, what can then?

      It appears that MySql is doing funny things to SIGALRM.

      No, it doesn't. It's the first bullet. The alarm signal is received. C calls are not interruptible, so calling the handler is delayed until the C code returns. alarm is working as expected.

      1) Is this problem fixable?

      You can interrupt C code by using unsafe signals, but it can leave the process in a weird state.

      2) The whole purpose of this exercise is to find a way to get out of the MySql operation if it takes longer than 5 sec. to do MySql.

      Perhaps you should start a thread with that question.

               C calls are not interruptible

        Hmm...?? How do we explain the followings:

        I made a demostration delibrately make MySql execute to a Maximum time of 5 sec, then set a timeout alarm of 3 sec in eval{} to prevent MySql execution more than 3 sec.

        To my surprise, timeout alarm in eval{} stops MySql execution exactly at 3 sec. COSISTENTLY

        The followings is the demonstration script:
        #!/usr/bin/perl $max_time = 5; $timeout = 3; use DBI; print "Content-type: text/html\n\n"; sub do_counter { $time1 = time; $time2 = time; $counter = 0; $time_ran = $time2 - $time1; $dbh=DBI->connect("dbi:mysql:$database:localhost","username"," +password"); $query="SELECT name FROM test"; $sth=$dbh->prepare($query); $sth->execute(); while ( @row = $sth->fetchrow_array ) { while($time_ran <= $max_time) { $conter++; $time2 = time; $time_ran = $time2 - $time1; } } $sth->finish; $dbh->disconnect ||die("Couldn't disconnect to database!\n"); } eval { local $SIG{ALRM} = sub { die "alarm\n" }; alarm $timeout; &do_counter; alarm 0; }; if($@) { print "$@, Time Ran: $time_ran, Counter: $conter\n"; exit; } print "Time Ran: $time_ran, Counter: $conter\n"; exit;

        As you can see, I delibrately make a counter loop inside MySql's while ( @row = $sth->fetchrow_array ) loop. The counter loop can run to a $max_time of 5 sec. before it stops.

        In the eva{} I set a timeout alarm of 3 sec. to stop MySql execution from going over 3 sec.

        When I ran the above script, I got the following results consistently:

        alarm, Time Ran: 3, Counter: 3341554
        alarm, Time Ran: 3, Counter: 3416456

        These results show that alarm in eval{} has stopped MySql execution in 3 sec.

        Can we not say then that alarm has interrupted MySql C Calls (e.g. calls to the db driver), contrary to what you said?

        You can do the same demostration with the above script by doing the followings:

        1) Create a table TEST with a single column: name CHAR(30) NOT NULL
        2) Enter 3 names, like John, Paul, Mary in the table.
        3) Run the above script.