File Coverage

blib/lib/ResourcePool.pm
Criterion Covered Total %
statement 117 137 85.4
branch 25 28 89.2
condition 8 12 66.6
subroutine 16 21 76.1
pod 4 15 26.6
total 170 213 79.8


line stmt bran cond sub pod time code
1             #*********************************************************************
2             #*** ResourcePool
3             #*** Copyright (c) 2002,2003 by Markus Winand
4             #*** $Id: ResourcePool.pm,v 1.54 2013-04-16 10:14:43 mws Exp $
5             #*********************************************************************
6              
7             ######
8             # TODO
9             #
10             # -> statistics function
11             # -> DEBUG option to find "lost" resources (store backtrace of get() call
12             # and dump on DESTROY)
13             # -> NOTIFYing features
14              
15             package ResourcePool;
16              
17 7     7   51070 use strict;
  7         18  
  7         314  
18 7     7   42 use vars qw($VERSION @ISA);
  7         18  
  7         383  
19 7     7   3945 use ResourcePool::Singleton;
  7         17  
  7         186  
20 7     7   4039 use ResourcePool::Command::Execute;
  7         25  
  7         232  
21              
22             BEGIN {
23             # make script using Time::HiRes, but not fail if it isn't there
24 7     7   575 eval "use Time::HiRes qw(sleep)";
  7     7   16077  
  7         18284  
  7         40  
25             }
26              
27              
28             push @ISA, ("ResourcePool::Command::Execute", "ResourcePool::Singleton");
29             $VERSION = "1.0107";
30            
31             sub new($$@) {
32 24     24 1 1146 my $proto = shift;
33 24   33     120 my $class = ref($proto) || $proto;
34 24         90 my $factory = shift->singleton();
35 24         129 my $self = $class->SUPER::new($factory); # Singleton
36              
37 24 100       119 if (!exists($self->{Factory})) {
38 18         45 $self->{Factory} = $factory;
39 18         43 $self->{FreePool} = [];
40 18         49 $self->{UsedPool} = {};
41 18         38 $self->{FreePoolSize} = 0;
42 18         34 $self->{UsedPoolSize} = 0;
43 18         110 my %options = (
44             Max => 5,
45             Min => 1,
46             MaxTry => 2,
47             MaxExecTry => 2,
48             PreCreate => 0,
49             SleepOnFail => [0]
50             );
51 18 100       94 if (scalar(@_) == 1) {
    100          
52 3         8 %options = ((%options), %{$_[0]});
  3         20  
53             } elsif (scalar(@_) > 1) {
54 11         80 %options = ((%options), @_);
55             }
56              
57 18 100       78 if ($options{MaxTry} <= 1) {
58 3         9 $options{MaxTry} = 2;
59             }
60             # prepare SleepOnFail parameter, extend if neccessary
61 18 50       56 if (ref($options{SleepOnFail})) {
62 18         90 push (@{$options{SleepOnFail}},
  18         51  
63             ($options{SleepOnFail}->[-1]) x
64 18         25 ($options{MaxTry} - 1 - scalar(@{$options{SleepOnFail}})));
65             } else {
66             # convinience if you want set SleepOnFail to a scalar
67 0         0 $options{SleepOnFail}
68             = [($options{SleepOnFail}) x ($options{MaxTry} - 1)];
69            
70             }
71             # truncate list if it is too long
72 18         36 $#{$options{SleepOnFail}} = $options{MaxTry} - 2;
  18         63  
73            
74 18         43 $self->{Max} = $options{Max};
75 18         36 $self->{Min} = $options{Min};
76 18         80 $self->{MaxTry} = $options{MaxTry} - 1;
77 18         39 $self->{MaxExecTry} = $options{MaxExecTry} - 1;
78 18         36 $self->{PreCreate} = $options{PreCreate};
79 18         26 $self->{SleepOnFail} = [reverse @{$options{SleepOnFail}}];
  18         61  
80              
81 18         39 bless($self, $class);
82 18         100 for (my $i = $self->{PreCreate}; $i > 0; $i--) {
83 14         25 $self->inc_pool();
84             }
85             }
86            
87 24         73 return $self;
88             }
89              
90             sub get($) {
91 239     239 1 1570 my ($self) = @_;
92 239         432 my $rec = undef;
93 239         424 my $maxtry = $self->{MaxTry};
94 239         324 my $rv = undef;
95              
96 239   100     467 do {
      66        
97 257 100       758 if (! $self->{FreePoolSize}) {
98 69         171 $self->inc_pool();
99             }
100 257 100       811 if ($self->{FreePoolSize}) {
101 232         327 $rec = shift @{$self->{FreePool}};
  232         418  
102 232         536 $self->{FreePoolSize}--;
103              
104 232 100       643 if (! $rec->precheck()) {
105 4         20 swarn("ResourcePool(%s): precheck failed\n",
106             $self->{Factory}->info());
107 4         23 $rec->fail_close();
108 4         5 undef $rec;
109             }
110 232 100       540 if ($rec) {
111 228         644 $rv = $rec->get_plain_resource();
112 228         737 $self->{UsedPool}->{$rv} = $rec;
113 228         870 $self->{UsedPoolSize}++;
114             }
115             }
116             } while (! $rec && ($maxtry-- > 0) && ($self->sleepit($maxtry)));
117 239         716 return $rv;
118             }
119              
120             sub free($$) {
121 195     195 1 497 my ($self, $plain_rec) = @_;
122              
123 195         457 my $rec = $self->{UsedPool}->{$plain_rec};
124 195 50       437 if ($rec) {
125 195         386 undef $self->{UsedPool}->{$plain_rec};
126 195         255 $self->{UsedPoolSize}--;
127 195 100       651 if ($rec->postcheck()) {
128 194         226 push @{$self->{FreePool}}, $rec;
  194         503  
129 194         415 $self->{FreePoolSize}++;
130             } else {
131 1         4 $rec->fail_close();
132             }
133 195         522 return 1;
134             } else {
135 0         0 return 0;
136             }
137             }
138              
139             sub fail($$) {
140 21     21 1 27 my ($self, $plain_rec) = @_;
141              
142 21         76 swarn("ResourcePool(%s): got failed resource from client\n",
143             $self->{Factory}->info());
144 21         98 my $rec = $self->{UsedPool}->{$plain_rec};
145 21 50       42 if (defined $rec) {
146 21         45 undef $self->{UsedPool}->{$plain_rec};
147 21         38 $self->{UsedPoolSize}--;
148 21         53 $rec->fail_close();
149 21         50 return 1;
150             } else {
151 0         0 return 0;
152             }
153             }
154              
155             sub downsize($) {
156 31     31 0 50 my ($self) = @_;
157 31         42 my $rec;
158              
159 31         149 swarn("ResourcePool(%s): Downsizing\n", $self->{Factory}->info());
160 31         118 while ($rec = shift(@{$self->{FreePool}})) {
  33         173  
161 2         12 $rec->close();
162             }
163 31         62 $self->{FreePoolSize} = 0;
164 31         83 swarn("ResourcePool: Downsized... still %s open (%s)\n",
165             $self->{UsedPoolSize}, $self->{FreePoolSize});
166            
167             }
168              
169             sub postfork($) {
170 0     0 0 0 my ($self) = @_;
171 0         0 my $rec;
172 0         0 $self->{FreePool} = [];
173 0         0 $self->{UsedPool} = {};
174 0         0 $self->{FreePoolSize} = 0;
175 0         0 $self->{UsedPoolSize} = 0;
176             }
177              
178             sub info($) {
179 10     10 0 17 my ($self) = @_;
180 10         36 return $self->{Factory}->info();
181             }
182              
183             sub setMin($$) {
184 0     0 0 0 my ($self, $min) = @_;
185 0         0 $self->{Min} = $min;
186 0         0 return 1;
187             }
188              
189             sub setMax($$) {
190 0     0 0 0 my ($self, $max) = @_;
191 0         0 $self->{Max} = $max;
192 0         0 return 1;
193             }
194              
195             sub print_status($) {
196 0     0 0 0 my ($self) = @_;
197 0         0 printf("\t\t\t\t\tDB> FreePool: <%d>", $self->{FreePoolSize});
198 0         0 printf(" UsedPool: <%d>\n", $self->{UsedPoolSize});
199             }
200              
201             sub get_stat_used($) {
202 110     110 0 132 my ($self) = @_;
203 110         366 return $self->{UsedPoolSize};
204             }
205              
206             sub get_stat_free($) {
207 0     0 0 0 my ($self) = @_;
208 0         0 return $self->{FreePoolSize};
209             }
210              
211             #*********************************************************************
212             #*** Private Part
213             #*********************************************************************
214              
215             sub inc_pool($) {
216 83     83 0 109 my ($self) = @_;
217 83         98 my $rec;
218             my $PoolSize;
219              
220 83         140 $PoolSize=$self->{FreePoolSize} + $self->{UsedPoolSize};
221              
222 83 100 66     631 if ( (! defined $self->{Max}) || ($PoolSize < $self->{Max})) {
223 52         203 $rec = $self->{Factory}->create_resource();
224            
225 52 100       169 if (defined $rec) {
226 49         187 push @{$self->{FreePool}}, $rec;
  49         107  
227 49         134 $self->{FreePoolSize}++;
228             }
229             }
230             }
231              
232             sub sleepit($$) {
233 18     18 0 29 my ($self, $try) = @_;
234 18         95 swarn("ResourcePool> sleeping %s seconds...\n", $self->{SleepOnFail}->[$try]);
235 18         5003177 sleep($self->{SleepOnFail}->[$try]);
236 18         83 $self->downsize();
237 18         168 return 1;
238             }
239              
240              
241             #*********************************************************************
242             #*** Functional Part
243             #*********************************************************************
244              
245             sub swarn($@) {
246 105     105 0 145 my $fmt = shift;
247 105         658 warn sprintf($fmt, @_);
248             }
249              
250             1;