1

i'm using AnyEvent to trigger event every X minutes. Some process are long and the result to record in the database are sometimes long to record (more than 3 seconds sometimes). I want to be sure that there is only one function that access to my database the same time. So I use lock from the threads::shared module. Here is my code :

main.pl :

my $var :shared;
$var = 0;

my $w1 = AnyEvent->timer(after => 0, interval => 120, cb => sub {
my @targeted_users = TargetUsers::get_targeted_account_from_followers($dbh,$account,'myrhline');
TargetUsers::save_users_to_follow($dbh,'RH',$var,@targeted_users);
});

my $w2 = AnyEvent->timer(after => 0, interval => 120, cb => sub {
my @targeted_users2 = TargetUsers::get_targeted_account_from_followers($dbh,$account2,'actuel_rh');
TargetUsers::save_users_to_follow($dbh,'RH',$var,@targeted_users2);
});

AnyEvent::Loop::run;

TargetUsers :

sub save_users_to_follow{
my ($dbh,$topic,$var,@targeted_users) = @_;

lock($var); #I call lock($var) to lock the access to the database.

my @array1 = ();

$dbh->{AutoCommit} = 0;

my $sth2 = $dbh->prepare(
"UPDATE People_TO_FOLLOW
         SET   Pertinence       = Pertinence + 1
         WHERE Id_user = ?");

my $tuples_update = $sth2->execute_array(
{ ArrayTupleStatus => \my @tuple_status_update },
\@targeted_users,
);

if ($tuples_update) {
print "Successfully updated $tuples_update records\n";
}
else {
for my $tuple_1 (0..$#targeted_users) {
    my $status_1 = $tuple_status_update[$tuple_1];
    $status_1 = [0, "Skipped"] unless defined $status_1;
    next unless ref $status_1;
    printf "Failed to update (%s): %s\n",
        $targeted_users[$tuple_1], $status_1->[1];
}
}
$sth2->finish();

my $sth = $dbh ->prepare(
"INSERT OR IGNORE INTO People_TO_FOLLOW(Id_user,Topic,Already_followed,Pertinence) VALUES (?,'$topic',0,1)");

my $tuples_insert = $sth->execute_array(
{ ArrayTupleStatus => \my @tuple_status_insert },
\@targeted_users,
);

if ($tuples_insert) {
print "Successfully inserted $tuples_insert records\n";
}
else {
for my $tuple_2 (0..$#targeted_users) {
    my $status_2 = $tuple_status_insert[$tuple_2];
    $status_2 = [0, "Skipped"] unless defined $status_2;
    next unless ref $status_2;
    printf "Failed to insert (%s): %s\n",
    $targeted_users[$tuple_2], $status_2->[1];
}
}
$sth->finish();
$dbh->commit;
$dbh->{AutoCommit} = 1;    
}

But I get this error : "lock can only be used on shared values"

Have you some idea please ? Thanks

  • For what it's worth, most databases allow concurrent access without you needing to lock anything. It is true that it's hard to update the database the way you want (say "add 10" to the account), so this might not be good enough to you, but it's also possible that you're solving a problem that you don't need to solve. – Max Lybbert May 13 '14 at 13:26

1 Answers1

4

You have two vars named $var, the one in main.pl, and the one in save_users_to_follow. The former is the shared variable, but you are trying to lock the latter.

Move the var from main to TargetUsers, or pass a reference to the lock var to save_users_to_follow.

ikegami
  • 367,544
  • 15
  • 269
  • 518