Ну, я написал программу на Perl для имитации того, что происходит, так как я не думал, что то, что вы говорите, возможно. Действительно, после запуска симуляции у меня не было никаких проблем, даже когда я отключил блокировку (поскольку SELECT … FOR UPDATE
и UPDATE
должны выполнить необходимую блокировку).
Я запустил это на PG 8.3 и PG 9.0, и он хорошо работал в обоих местах.
Я призываю вас попробовать программу и / или попробовать версию на Python, чтобы получить хороший жесткий тест-кейс, которым вы можете поделиться с классом. Если это работает, вы можете исследовать, в чем различия, и если это не работает, у вас есть что-то, с чем могут играть другие люди.
#!/usr/bin/perl
use DBI;
$numchild = 0;
$SIG{CHLD} = sub { if (wait) {$numchild--;} };
sub worker($)
{
my ($i) = @_;
my ($job);
my $dbh = DBI->connect("dbi:Pg:host=localhost",undef,undef,{'RaiseError'=>0, 'AutoCommit'=>0});
my ($x) = 0;
while(++$x)
{
# $dbh->do("lock table slots in access exclusive mode;") || die "Cannot lock at $i\n";
my @id = $dbh->selectrow_array("select id from slots where job_name is NULL LIMIT 1 FOR UPDATE;");
if ($#id < 0)
{
$dbh->rollback;
sleep(.5);
next;
}
$job = "$$-$i-($x)";
$dbh->do("update slots set job_name='$job' where id=$id[0];") || die "Cannot update at $i\n";
$dbh->commit || die "Cannot commit\n";
last;
}
if (!$job)
{
print STDERR "Could not find slots in 5 attempts for $i $$\n" if ($ENV{'verbose'});
return;
}
else
{
print STDERR "Got $job\n" if ($ENV{'verbose'} > 1);
}
sleep(rand(5));
# $dbh->do("lock table slots in access exclusive mode;") || die "Cannot lock at $i\n";
$dbh->do("update slots set usage=usage+1, job_name = NULL where job_name='$job';") || die "Cannot unlock $job";
print STDERR "Unlocked $job\n" if ($ENV{'verbose'} > 2);
$dbh->commit || die "Cannot commit";
}
my $dbh = DBI->connect("dbi:Pg:host=localhost",undef,undef,{'RaiseError'=>0, 'AutoCommit'=>0});
$dbh->do("drop table slots;");
$dbh->commit;
$dbh->do("create table slots (id serial primary key, job_name text, usage int);") || die "Cannot create\n";
$dbh->do("insert into slots values (DEFAULT,NULL,0), (DEFAULT,NULL,0), (DEFAULT,NULL,0), (DEFAULT,NULL,0), (DEFAULT,NULL,0), (DEFAULT,NULL,0), (DEFAULT,NULL,0), (DEFAULT,NULL,0), (DEFAULT,NULL,0), (DEFAULT,NULL,0);") || die "Cannot insert";
$dbh->commit;
for(my $i=0;$i<200;$i++)
{
if (!fork)
{
worker($i);
exit(0);
}
if (++$numchild > 50)
{
sleep(1);
}
}
while (wait > 0)
{
$numchild--;
print "Waiting numchild $numchild\n";
sleep(1);
}
my $dbh = DBI->connect("dbi:Pg:host=localhost",undef,undef,{'RaiseError'=>0, 'AutoCommit'=>0});
my $slots = $dbh->selectall_arrayref("select * from slots;") || die "Cannot do final select";
my $sum=0;
foreach my $slot (@$slots)
{
printf("%02d %3d %s\n",$slot->[0], $slot->[2], $slot->[1]);
$sum += $slot->[2];
}
print "Successfully made $sum entries\n";