]> git.p6c8.net - selfforum.git/blob - selfforum-cgi/shared/Lock/API.pm
improved the behavior of get_all_threads and create_forum_xml_string
[selfforum.git] / selfforum-cgi / shared / Lock / API.pm
1 package Lock::API;
2
3 ################################################################################
4 # #
5 # File: shared/Lock/API.pm #
6 # #
7 # Authors: André Malo <nd@o3media.de> #
8 # #
9 # Description: system independent part of Locking and Filehandle class #
10 # NOT FOR PUBLIC USE #
11 # #
12 ################################################################################
13
14 use strict;
15 use Carp;
16
17 use base qw(
18 Lock::Handle
19 Lock::_simple
20 );
21
22 ################################################################################
23 #
24 # Version check
25 #
26 # last modified:
27 # $Date$ (GMT)
28 # by $Author$
29 #
30 sub VERSION {(q$Revision$ =~ /([\d.]+)\s*$/)[0] or '0.0'}
31
32 ### sub lock ###################################################################
33 #
34 # set a lock on the file
35 #
36 # Params: $locktype - what kind of locking?
37 # $timeout - (optional) Timeout
38 #
39 # Return: success (boolean)
40 #
41 sub lock {
42 my $self = shift;
43 my $locktype = shift;
44
45 return if $self -> masterlocked;
46
47 ###########################################
48 # shared lock
49 #
50 if ($locktype == $self -> LH_SHARED) {
51 return 1 if $self -> locked_shared;
52 return if $self -> locked_exclusive;
53
54 my $timeout = shift || $self -> timeout ('shared');
55
56 # try to increase the reference counter
57 #
58 if ($self -> add_ref($timeout)) {
59 $self -> set_static (locked_shared => 1);
60 return 1;
61 }
62 }
63
64
65 ###########################################
66 # exclusive lock
67 #
68 elsif ($locktype == $self -> LH_EXCL) {
69 return 1 if $self -> locked_exclusive;
70
71 my $timeout = shift || $self -> timeout ('exclusive');
72
73 #####################
74 # transform exclusive shared lock into exclusive lock
75 #
76 if ($self -> locked_exsh) {
77 my $reflock = new Lock::Handle ($self -> reflock);
78
79 for (0..$timeout) {
80 if ($self -> set_excl_announce and $self -> _simple_lock ($reflock)) {
81 if ($self -> get_ref == 1) {
82 $self -> set_ref(0);
83 $self -> remove_exsh_announce;
84 $self -> set_static (locked_exsh => 0);
85 $self -> set_static (locked_exclusive => 1);
86 return 1;
87 }
88
89 last unless ($self -> _simple_unlock ($reflock->filename));
90 }
91
92 sleep 1;
93 }
94 $self -> remove_excl_announce;
95 }
96
97 #####################
98 # set exclusive lock
99 #
100 else {
101 my $reflock = new Lock::Handle ($self -> reflock);
102
103 for (0..$timeout) {
104 if ($self -> set_excl_announce and $self -> _simple_lock ($reflock)) {
105 if ($self -> get_ref == 0) {
106 $self -> set_static (locked_exclusive => 1);
107 return 1;
108 }
109
110 last unless ($self -> _simple_unlock ($reflock->filename));
111 }
112
113 sleep 1;
114 }
115 $self -> remove_excl_announce;
116 }
117 }
118
119
120 ###########################################
121 # exclusive shared lock
122 #
123 elsif ($locktype == $self -> LH_EXSH) {
124 return 1 if $self -> locked_exsh;
125 return if ($self -> locked_shared or $self -> locked_exclusive);
126
127 my $timeout = shift || $self -> timeout ('shared');
128
129 # try to increase the reference counter
130 #
131 if ($self -> es_add_ref($timeout)) {
132 $self -> set_static (locked_exsh => 1);
133 return 1;
134 }
135 }
136
137
138 ###########################################
139 # master lock
140 #
141 elsif ($locktype == $self -> LH_MASTER) {
142 $self -> lock ($self->LH_EXCL, $self -> timeout('master')) and
143 $self -> _simple_lock (new Lock::Handle ($self->masterlock)) and
144 return 1;
145
146 # oops..?
147 # VERY violent way to set master lock
148 #
149 $self -> release;
150
151 $self -> lock ($self->LH_EXCL, $self -> timeout('master')) and
152 $self -> _simple_lock (new Lock::Handle ($self->masterlock)) and
153 return 1;
154 }
155
156 ###########################################
157 # unknown locking type
158 #
159 else {
160 croak "unknown locking type '$locktype'";
161 }
162
163 # timeout
164 #
165 $self -> unlock_violent;
166 return;
167 }
168
169 ### sub unlock #################################################################
170 #
171 # remove shared or exclusive lock
172 #
173 # Params: $timeout - (optional) Timeout
174 #
175 # Return: success (boolean)
176 #
177 sub unlock {
178 my $self = shift;
179 my $timeout = shift || $self -> timeout ('shared');
180
181 return if $self -> masterlocked;
182
183 ###########################################
184 # shared lock
185 #
186 if ($self -> locked_shared) {
187 # try to decrease the reference counter
188 #
189 if ($self -> sub_ref($timeout)) {
190 $self -> set_static (locked_shared => 0);
191 return 1;
192 }
193 }
194
195
196 ###########################################
197 # exclusive lock
198 #
199 elsif ($self -> locked_exclusive) {
200 my $reflock = new Lock::Handle ($self -> reflock);
201
202 for (0..$timeout) {
203 if ($self -> _simple_unlock ($reflock->filename)) {
204 $self -> remove_excl_announce;
205 $self -> set_static (locked_exclusive => 0);
206 return 1;
207 }
208
209 sleep 1;
210 }
211 }
212
213
214 ###########################################
215 # exclusive shared lock
216 #
217 elsif ($self -> locked_exsh) {
218 # try to decrease the reference counter
219 #
220 if ($self -> es_sub_ref($timeout)) {
221 $self -> remove_exsh_announce;
222 $self -> set_static (locked_exsh => 0);
223 return 1;
224 }
225 }
226
227
228 ###########################################
229 # not locked
230 #
231 else {
232 return 1;
233 }
234
235 # unlocking failed
236 #
237 $self -> unlock_violent;
238 return;
239 }
240
241 ### sub unlock_violent #########################################################
242 #
243 # remove any lock violently (excludes master lock)
244 #
245 # Params: ~none~
246 #
247 # Return: -none- (the success is undefined)
248 #
249 sub unlock_violent {
250 my $self = shift;
251
252 unless ($self -> masterlocked) {
253
254 # find out last modification time
255 # and do nothing unless 'violent-timout' is over
256 #
257 my $time = $self -> _reftime;
258
259 if ($time) {
260 return if ((time - $time) < $self -> timeout('violent'));
261 }
262
263 $self -> set_ref (0); # reference counter = 0
264 $self -> _simple_unlock ($self -> reflock); # release reference counter file
265 $self -> _simple_unlock ($self -> exshlock); # remove excl shared lock
266 $self -> _simple_unlock ($self -> lockfile); # release file
267 }
268
269 return;
270 }
271
272 ### sub release ################################################################
273 #
274 # release a file
275 #
276 # Params: ~none~
277 #
278 # Return: ~none~
279 #
280 sub release {
281 my $self = shift;
282
283 $self -> set_ref (0); # reference counter = 0
284 $self -> _simple_unlock ($self -> reflock); # release reference counter
285 $self -> _simple_unlock ($self -> lockfile); # remove any write lock announce
286 $self -> _simple_unlock ($self -> exshlock); # remove any excl shared lock
287 $self -> _simple_unlock ($self -> masterlock); # remove master lock
288
289 return;
290 }
291
292 # keep 'require' happy
293 1;
294
295 #
296 #
297 ### end of Lock::API ###########################################################

patrick-canterino.de