Line # Revision Author
1 8 ahitrov@rambler.ru package PidFile::DatabaseCompat;
2
3 use strict;
4 use warnings 'all';
5
6 use DBI;
7 use Digest::MD5 qw(md5);
8 use FindBin;
9 use POSIX qw(strftime);
10
11
12 sub new {
13 my ($class, $keeper, %opts) = @_;
14
15 my ($crc1, $crc2) = map {abs unpack 'j',$_} grep {$_} split /(.{8})/, md5(($opts{pid_name}||$FindBin::RealScript).($opts{per_host} ? $opts{host} : ''));
16
17 my $self = {
18 dbh => $keeper->create_db_t_connect,
19 delay => exists $opts{delay} ? $opts{delay} : 30,
20 host => $opts{host},
21 mutex => $crc1^$crc2,
22 per_host => $opts{per_host},
23 script => "$FindBin::RealBin/$FindBin::RealScript",
24 verbose => $opts{verbose},
25 };
26
27 $self->{dbh}{PrintError} = 0;
28 $self->{dbh}{RaiseError} = 1;
29
30 bless $self, $class;
31 }
32
33 sub block {
34 my ($self, $now) = @_;
35
36 $self->{started} = $now;
37
38 # our candidature
39 $self->{dbh}->do("INSERT INTO pid (pid, mutex, host, script, started, state) VALUES (?,?,?,?,?,1)", {}, $$, $self->{mutex}, $self->{host}, $self->{script}, strftime('%Y-%m-%d %H:%M:%S', localtime $now));
40 $self->{id} = $self->{dbh}->selectrow_array("SELECT currval('documents_id_seq')");
41 $self->{dbh}->commit;
42
43 # election now
44 eval {
45 $self->{cands} = $self->{dbh}->selectall_arrayref("SELECT * FROM pid WHERE mutex=? AND state=1 FOR UPDATE NOWAIT", {Slice=>{}}, $self->{mutex});
46 };
47 if ($@ && $@=~/could not obtain lock on row/) {
48 $@ = "Found alive process, exit\n";
49 die $@ if $self->{verbose};
50 exit;
51 }
52
53 # is real winner?
54 unless (grep {$_->{id}==$self->{id}} @{$self->{cands}}) {
55 $@ = "Seems like other process overtaked, exit\n";
56 die $@ if $self->{verbose};
57 exit;
58 }
59
60 print "Created PID record (PID: $$) at ".localtime($now)."\n" if $self->{verbose};
61 }
62
63 sub release {
64 my ($self, $now) = @_;
65
66 my $sleep = $self->{delay} ? $self->{delay} - ($now - $self->{started}) : 0;
67 $sleep = 0 if $sleep<0;
68
69 if ($sleep) {
70 print "Sleeping for $sleep seconds before exit...\n" if $self->{verbose};
71 sleep $sleep;
72 }
73
74 for (@{$self->{cands}}) {
75 if ($_->{id}==$self->{id}) {
76 $self->{dbh}->do("UPDATE pid SET finished=?, state=2 WHERE id=?", {}, strftime('%Y-%m-%d %H:%M:%S', localtime $now), $self->{id});
77 } else {
78 $self->{dbh}->do("DELETE FROM pid WHERE id=?", {}, $_->{id});
79 }
80 }
81 $self->{dbh}->commit;
82
83 print "Removed PID record (PID: $$) at ".localtime($now)."\n" if $self->{verbose};
84
85 return $sleep;
86 }
87
88 sub DESTROY {
89 my $self = shift;
90
91 eval {
92 $self->{dbh}->disconnect;
93 };
94 }
95
96 1;