]>
git.p6c8.net - selfforum.git/blob - selfforum-cgi/shared/Posting/Cache.pm
1 package Posting
::Cache
;
3 ################################################################################
5 # File: shared/Posting/Cache.pm #
7 # Authors: André Malo <nd@o3media.de>, 2001-04-21 #
9 # Description: Views/Voting Cache class #
11 ################################################################################
18 my $O_BINARY = eval "O_BINARY";
19 $O_BINARY = 0 if ($@
);
21 ### sub new ####################################################################
25 # Params: $filename - full qualified cache file name
27 # Return: Posting::Cache object
30 my $self = bless {} => shift;
33 $self -> set_file
(+shift);
35 $self -> repair_cache
or do {
36 $self -> set_error
('cache '.$self->cachefile.' is broken and not repairable.')
42 ### sub clear_error ############################################################
44 # clear verbal error data
53 $self -> {verb_error
} = undef;
58 sub error
{$_[0]->{verb_error
}}
63 $self -> {verb_error
} = +shift;
67 ### sub set_file ###############################################################
71 # Params: $filename - full qualified cache file name
74 my ($self, $filename) = @_;
76 $self -> {cachefile
} = $filename;
81 sub cachefile
{$_[0] -> {cachefile
}}
82 sub indexfile
{$_[0] -> cachefile
. '.index'}
83 sub temp_cachefile
{$_[0] -> cachefile
. '.temp'}
84 sub temp_indexfile
{$_[0] -> indexfile
. '.temp'}
86 ### sub find_pos ($$) ##########################################################
88 # find position in cache file
89 # (binary search in index file)
91 # Params: $handle - index file handle
92 # $posting - posting number
94 # Return: position or false (undef)
97 my ($I, $posting) = @_;
98 my $reclen = 2 * length pack 'L',0;
99 my $end = (-s
$I) / $reclen;
101 $end == int $end or return;
103 my ($start, $buf, $current) = 0;
105 while ($start <= $end) {
106 seek $I, ($current = ($start + $end) >> 1)*$reclen, 0 or return;
107 $reclen == read ($I, $buf, $reclen) or return;
109 my ($num, $found) = unpack 'L2',$buf;
111 if ($num == $posting) {
114 elsif ($num < $posting) {
125 ### sub add_view ###############################################################
127 # increment the views-counter
131 # Return: Status code (Bool)
134 my ($self, $h, $param) = @_;
135 my ($C, $I) = ($h->{C
}, $h->{I
});
136 my $reclen = 4 * length pack 'L', 0;
138 defined ($pos = find_pos
$I, $param->{posting
}) or return;
141 seek $C, $pos, 0 or return;
142 read ($C, $buf, $reclen) == $reclen or return;
144 my ($posting, $thread, $views, $votings) = unpack 'L4',$buf;
145 $thread == $param->{thread
} or return;
146 seek $C, $pos, 0 or return;
147 print $C pack ('L4' => $posting, $thread, $views+1, $votings) or return;
153 my ($self, $param) = @_;
155 $self -> write_wrap
(
161 ### sub pick ###################################################################
163 # read information of one posting
165 # Params: $param - hash reference
168 # Return: hash reference or false
171 my ($self, $h, $param) = @_;
172 my ($C, $I) = ($h->{C
}, $h->{I
});
173 my $reclen = 4 * length pack 'L', 0;
177 defined($pos = find_pos
$I, $param->{posting
}) or return;
179 seek $C, $pos, 0 or return;
180 read ($C, $buf, $reclen) == $reclen or return;
182 my ($posting, $thread, $views, $votings) = unpack 'L4', $buf;
183 $buf = <$C>; chomp $buf;
191 time => $_->[0] || 0,
204 my ($self, $param) = @_;
206 $self -> read_wrap
(\
&r_pick
, $param)
211 ### sub summary ################################################################
213 # read out the cache and return a summary
217 # Return: hash reference or false
221 my ($C, $I) = ($h->{C
}, $h->{I
});
222 my $reclen = length pack 'L', 0;
223 my $ireclen = 2 * $reclen;
224 my $creclen = 4 * $reclen;
225 my ($buf, $pos, %hash);
228 while ($ireclen == read ($I, $buf, $ireclen)) {
229 (undef, $pos) = unpack 'L2', $buf;
231 seek $C, $pos, 0 or return;
232 read ($C, $buf, $creclen) == $creclen or return;
234 my ($posting, $thread, $views, $votings) = unpack 'L4', $buf;
235 $hash{$thread} = {} unless $hash{$thread};
236 $hash{$thread} -> {$posting} = {
242 $self -> {summary
} = \
%hash;
251 $self -> read_wrap
(\
&r_summary
)
256 ### sub repair_cache ###########################################################
258 # check on cache consistance and repair if broken
262 # Return: sucess code (Bool)
266 my ($C, $TC, $TI) = ($h->{C
}, $h->{TC
}, $h->{TI
});
269 my $reclen = 4 * length pack 'L',0;
273 while ($reclen == read $C, $block, $reclen) {
274 my $msg = unpack ('L' => $block);
277 print $TC $block. $rest. $/;
278 print $TI pack ('L2' => $msg, $pos);
288 return unless ($self->cachefile and $self->indexfile);
289 return 1 if (-f
$self->cachefile and -f
$self->indexfile);
291 unless (-f
$self->cachefile) {
292 return if (-f
$self->indexfile);
295 return unless (open FILE
, '>'.$self->cachefile);
296 return unless (close FILE
);
297 return unless (open FILE
, '>'.$self->indexfile);
298 return unless (close FILE
);
300 release_file
($self->cachefile);
301 release_file
($self->indexfile);
302 release_file
($self->temp_indexfile);
303 release_file
($self->temp_cachefile);
308 $self -> open_wrap
(\
&r_repair_cache
);
311 ### sub add_posting ############################################################
313 # add an empty cache entry of a posting
315 # Params: $param - hash reference
318 # Return: Status code (Bool)
321 my ($self, $h, $param) = @_;
322 my ($C, $TC, $TI) = ($h->{C
}, $h->{TC
}, $h->{TI
});
324 my ($block, $ins, $msg);
325 my $reclen = 4 * length pack 'L',0;
329 while ($reclen == read $C, $block, $reclen) {
330 $msg = unpack ('L' => $block);
332 if ($param -> {posting
} == $msg) {
333 $self->set_error("double defined posting id 'm$msg'");
336 next if ($param -> {posting
} > $msg or $ins);
338 print $TC pack('L4' => $param->{posting
}, $param->{thread
}, 0, 0), $/;
339 print $TI pack('L2' => $param->{posting
}, $pos);
346 print $TC $block. $rest. $/;
347 print $TI pack ('L2' => $msg, $pos);
351 print $TC pack('L4' => $param->{posting
}, $param->{thread
}, 0, 0), $/;
352 print $TI pack('L2' => $param->{posting
}, $pos);
366 ### sub add_voting #############################################################
368 # add a voting (increment vote counter and log the vote data)
370 # Params: $param - hash reference
371 # (thread, posting, IP, time, ID)
373 # Return: Status code (Bool)
376 my ($self, $h, $param) = @_;
377 my ($C, $TC, $TI) = ($h->{C
}, $h->{TC
}, $h->{TI
});
380 my $reclen = 4 * length pack 'L',0;
384 while ($reclen == read $C, $block, $reclen) {
387 my ($msg, $thread, $views, $votings) = unpack ('L4' => $block);
389 $param -> {posting
} != $msg or do {
390 $rest = join ' ' => (length $rest ?
$rest: (), join ';' => ($param->{time}, $param->{IP
}, $param->{ID
}));
394 print $TC pack ('L4' => ($msg, $thread, $views, $votings)), $rest, $/;
395 print $TI pack ('L2' => $msg, $pos);
410 ### sub open_wrap ##############################################################
412 # file lock, open, execute, close, unlock wrapper
413 # for writing into temp files
415 # Params: $gosub - sub reference (for execution)
416 # @param - params (for $gosub)
418 # Return: Status code (Bool)
421 my ($self, $gosub, @param) = @_;
424 unless (write_lock_file
($self->temp_cachefile)) {
425 violent_unlock_file
($self->temp_cachefile);
426 $self->set_error ('could not write-lock temp cache file '.$self->temp_cachefile);
429 unless (write_lock_file
($self->temp_indexfile)) {
430 violent_unlock_file
($self->temp_indexfile);
431 $self->set_error ('could not write-lock temp index file '.$self->temp_indexfile);
434 unless (lock_file
($self->cachefile)) {
435 violent_unlock_file
($self->cachefile);
436 $self->set_error ('could not read-lock cache file '.$self->cachefile);
439 unless (lock_file
($self->indexfile)) {
440 violent_unlock_file
($self->indexfile);
441 $self->set_error ('could not read-lock index file '.$self->indexfile);
444 local (*C
, *TC
, *TI
);
445 unless (sysopen (C
, $self->cachefile, O_RDONLY
| $O_BINARY)) {
446 $self->set_error ('could not open to read cache file '.$self->cachefile);
449 unless (sysopen (TC
, $self->temp_cachefile, O_WRONLY
| O_TRUNC
| O_CREAT
| $O_BINARY)) {
450 $self->set_error ('could not open to write temp cache file '.$self->temp_cachefile);
453 unless (sysopen (TI
, $self->temp_indexfile, O_WRONLY
| O_TRUNC
| O_CREAT
| $O_BINARY)) {
454 $self->set_error ('could not open to write temp index file '.$self->temp_indexfile);
457 $status = $gosub -> (
467 $self->set_error('could not close temp index file '.$self->temp_indexfile);
472 $self->set_error('could not close temp cache file '.$self->temp_cachefile);
477 $self->set_error('could not close cache file '.$self->cachefile);
480 unless (write_lock_file
($self->cachefile) and write_lock_file
($self->indexfile)) {
482 $self->set_error('could not write-lock cache or index file');
485 unless (unlink $self->indexfile or !-f
$self->indexfile) {
487 $self->set_error('could not unlink '.$self->indexfile);
490 unless (rename $self->temp_cachefile => $self->cachefile) {
492 $self->set_error('could not rename '.$self->temp_cachefile);
495 unless (rename $self->temp_indexfile => $self->indexfile) {
497 $self->set_error('could not rename '.$self->temp_indexfile);
504 violent_unlock_file
($self->indexfile) unless (unlock_file
($self->indexfile));
506 violent_unlock_file
($self->cachefile) unless (unlock_file
($self->cachefile));
508 violent_unlock_file
($self->temp_indexfile) unless (write_unlock_file
($self->temp_indexfile));
510 violent_unlock_file
($self->temp_cachefile) unless (write_unlock_file
($self->temp_cachefile));
517 ### sub read_wrap ##############################################################
519 # file lock, open, execute, close, unlock wrapper
522 # Params: $gosub - sub reference (for execution)
523 # @param - params (for $gosub)
525 # Return: Status code (Bool)
528 my ($self, $gosub, @param) = @_;
531 unless (lock_file
($self->cachefile)) {
532 violent_unlock_file
($self->cachefile);
533 $self->set_error ('could not read-lock cache file '.$self->cachefile);
536 unless (lock_file
($self->indexfile)) {
537 violent_unlock_file
($self->indexfile);
538 $self->set_error ('could not read-lock index file '.$self->indexfile);
542 unless (sysopen (C
, $self->cachefile, O_RDONLY
| $O_BINARY)) {
543 $self->set_error ('could not open to read cache file '.$self->cachefile);
546 unless (sysopen (I
, $self->indexfile, O_RDONLY
| $O_BINARY)) {
547 $self->set_error ('could not open to read index file '.$self->indexfile);
550 $status = $gosub -> (
559 $self->set_error('could not close index file '.$self->indexfile);
564 $self->set_error('could not close cache file '.$self->cachefile);
567 violent_unlock_file
($self->indexfile) unless (unlock_file
($self->indexfile));
569 violent_unlock_file
($self->cachefile) unless (unlock_file
($self->cachefile));
576 ### sub write_wrap ##############################################################
578 # file lock, open, execute, close, unlock wrapper
581 # Params: $gosub - sub reference (for execution)
582 # @param - params (for $gosub)
584 # Return: Status code (Bool)
587 my ($self, $gosub, @param) = @_;
590 unless (write_lock_file
($self->temp_cachefile)) {
591 violent_unlock_file
($self->temp_cachefile);
592 $self->set_error ('could not write-lock temp cache file '.$self->temp_cachefile);
595 unless (write_lock_file
($self->cachefile)) {
596 violent_unlock_file
($self->cachefile);
597 $self->set_error ('could not write-lock cache file '.$self->cachefile);
600 unless (lock_file
($self->indexfile)) {
601 violent_unlock_file
($self->indexfile);
602 $self->set_error ('could not read-lock index file '.$self->indexfile);
606 unless (sysopen (C
, $self->cachefile, O_RDWR
| $O_BINARY)) {
607 $self->set_error ('could not open to read/write cache file '.$self->cachefile);
610 unless (sysopen (I
, $self->indexfile, O_RDONLY
| $O_BINARY)) {
611 $self->set_error ('could not open to read index file '.$self->indexfile);
614 $status = $gosub -> (
623 $self->set_error('could not close index file '.$self->indexfile);
628 $self->set_error('could not close cache file '.$self->cachefile);
631 violent_unlock_file
($self->indexfile) unless (unlock_file
($self->indexfile));
633 violent_unlock_file
($self->cachefile) unless (write_unlock_file
($self->cachefile));
635 violent_unlock_file
($self->temp_cachefile) unless (write_unlock_file
($self->temp_cachefile));
642 # keep 'require' happy
648 ### end of Posting::Cache ######################################################
patrick-canterino.de