Hi,
is there an easy way to timeout an SQL statement so that it will fail instead of waiting (e.g. deliver an empty result set or an error message or whatever else) so I can let a job's ressource reservation fail and give another one a chance? I'm looking for some DBI option I've overlooked so far; sending SIGALRMs to myself to commit suicide is rather not what I have in mind (although I might have to resort to that if I had to).
The code snipped is pseudo-ized and shortened to the extreme, but I hope you'll catch the drift.
my $sql = "SELECT one, two, three FROM sometable WHERE this = ? AND that = ?";
my $sth = $self->make_handle( $sql );
eval {
foreach my $this ( sort keys %needed_ressources ) {
# vvv This is where the idle time is spent vvv
$sth->execute( $this, $that ) or die( "DB connection gone?!" );
# ^^^ This is where the idle time is spent ^^^
my ( $one, $two, $three ) = $sth->fetchrow_array();
unless( $one ) { # undefined record set == not found
$self->{DB_HANDLE}->rollback();
die( "$this not defined for $that!" );
}
}
# If we haven't died so far, we can move on
foreach... #similar loop here doing the actual update statement
$self->{DB_HANDLE}->commit();
};
return( 1 ) unless $@;
return( undef );
Here are the gory details for the interested:
In an application that does massively parallel numbercrunching there is a ressource locking mechanism implemented that uses an oracle table. Each job needs to lock a number of ressources for reading and/or a number of ressources to write to, and can only start if all the locks have been acquired successfully. Instead of patiently waiting for ressources to be freed, jobs should just fail and be re-run later by their master (this keeps the number of open transactions low while boosting performance by having more jobs around that actually crunch).
Of course, before actually updating the table, each row is being reserved using a "SELECT ... FOR UPDATE" statement so Oracle uses row level locking and concurrent transactions can happen on the table. In order to further reduce possible race conditions and deadlocks all jobs first select their ressource rows and then row lock them using the same ordering before performing the update.
As of the current implementation this works fine in most of the cases. But, because the "Select for update" blocks until Oracle actually grants the row lock, it may still happen that a job is idle waiting for its ressources, and I'm after those to better utilize the available CPU power. It's OK to wait a second or two, but not ten or more just for the locking. For unlocking later, waiting is required of course, so setting the whole DB connection to only accept immediate results will not work.
I'm always grateful for RTFM answers as long as they point to the location in the M that I should TF have R ;-))
Thanks a lot in advance,
Olfan