File Coverage

inc/Test/SharedFork/Store.pm
Criterion Covered Total %
statement 60 72 83.3
branch 14 30 46.6
condition 1 2 50.0
subroutine 15 17 88.2
pod 0 6 0.0
total 90 127 70.8


line stmt bran cond sub pod time code
1             #line 1
2 55     55   313 package Test::SharedFork::Store;
  55         203  
  55         1974  
3 55     55   320 use strict;
  55         121  
  55         1469  
4 55     55   392 use warnings;
  55         131  
  55         1376  
5 55     55   643 use Storable ();
  55         113  
  55         36686  
6 55     55   79765 use Fcntl ':seek', ':DEFAULT', ':flock';
  55         745026  
  55         1442  
7 55     55   521 use File::Temp ();
  55         129  
  55         47846  
8             use IO::Handle;
9              
10 55     55 0 175 sub new {
11 55         229 my $class = shift;
12 55         289 my %args = @_;
13             my $filename = File::Temp::tmpnam();
14 55   50     33223  
15             my $init = Storable::dclone($args{init} || +{});
16 55         4658  
17             my $self = bless {
18             callback_on_open => $args{cb},
19             filename => $filename,
20             lock => 0,
21             pid => $$,
22             ppid => $$,
23 55         236 }, $class;
24             $self->open();
25              
26 55 50       337 # initialize
27             Storable::nstore_fd($init, $self->{fh}) or die "Cannot write initialize data to $filename";
28 55         8026  
29             return $self;
30             }
31              
32 55     55 0 324 sub open {
33 55 50       469 my $self = shift;
34 55         422 if (my $cb = $self->{callback_on_open}) {
35             $cb->($self);
36 55 50       2978311 }
37 55         847 sysopen my $fh, $self->{filename}, O_RDWR|O_CREAT or die $!;
38 55         3145 $fh->autoflush(1);
39             $self->{fh} = $fh;
40             }
41              
42 0     0 0 0 sub close {
43 0         0 my $self = shift;
44 0         0 close $self->{fh};
45             undef $self->{fh};
46             }
47              
48 4412     4412 0 8979 sub get {
49 4412         8700 my ($self, $key) = @_;
50 4412 50       37730 $self->_reopen_if_needed;
51 4412         15827 seek $self->{fh}, 0, SEEK_SET or die $!;
52             Storable::fd_retrieve($self->{fh})->{$key};
53             }
54              
55 1212     1212 0 5224 sub set {
56             my ($self, $key, $val) = @_;
57 1212         2503  
58             $self->_reopen_if_needed;
59 1212 50       9677  
60 1212         3977 seek $self->{fh}, 0, SEEK_SET or die $!;
61 1212         138169 my $dat = Storable::fd_retrieve($self->{fh});
62             $dat->{$key} = $val;
63 1212         8795414  
64 1212 50       10298 truncate $self->{fh}, 0;
65 1212 50       6680 seek $self->{fh}, 0, SEEK_SET or die $!;
66             Storable::nstore_fd($dat => $self->{fh}) or die "Cannot store data to $self->{filename}";
67             }
68              
69 5624     5624 0 8825 sub get_lock {
70 5624         21453 my ($self, ) = @_;
71             Test::SharedFork::Store::Locker->new($self);
72             }
73              
74 11248     11248   18274 sub _reopen_if_needed {
75 11248 50       41347 my $self = shift;
76 0         0 if ($self->{pid} != $$) { # forked, and I'm just a child.
77 0 0       0 $self->{pid} = $$;
78 0 0       0 if ($self->{lock} > 0) { # unlock! I'm not owner!
79 0         0 flock $self->{fh}, LOCK_UN or die $!;
80             $self->{lock} = 0;
81 0         0 }
82 0         0 $self->close();
83             $self->open();
84             }
85             }
86              
87 0     0   0 sub DESTROY {
88 0 0       0 my $self = shift;
89 0         0 if ($self->{ppid} eq $$) { # cleanup method only run on original process.
90             unlink $self->{filename};
91             }
92             }
93              
94             package # hide from pause
95             Test::SharedFork::Store::Locker;
96 55     55   387  
  55         132  
  55         19144  
97             use Fcntl ':flock';
98              
99 5624     5624   8346 sub new {
100             my ($class, $store) = @_;
101 5624         11060  
102             $store->_reopen_if_needed;
103 5624 100       18398  
104 1988 50       17519 if ($store->{lock}++ == 0) {
105             flock $store->{fh}, LOCK_EX or die $!;
106             }
107 5624         32035  
108             bless { store => $store }, $class;
109             }
110              
111 5624     5624   774503 sub DESTROY {
112             my ($self) = @_;
113 5624         12679  
114 5624 100       42208 $self->{store}->{lock}--;
115 1988 50       62759 if ($self->{store}->{lock} == 0) {
116             flock $self->{store}->{fh}, LOCK_UN or die $!;
117             }
118             }
119              
120             1;