]>
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;
68 ### sub set_file ###############################################################
72 # Params: $filename - full qualified cache file name
75 my ($self, $filename) = @_;
77 $self -> {cachefile
} = $filename;
82 sub cachefile
{$_[0] -> {cachefile
}}
83 sub indexfile
{$_[0] -> cachefile
. '.index'}
84 sub temp_cachefile
{$_[0] -> cachefile
. '.temp'}
85 sub temp_indexfile
{$_[0] -> indexfile
. '.temp'}
87 ### sub find_pos ($$) ##########################################################
89 # find position in cache file
90 # (binary search in index file)
92 # Params: $handle - index file handle
93 # $posting - posting number
95 # Return: position or false (undef)
98 my ($I, $posting) = @_;
99 my $reclen = 2 * length pack 'L',0;
100 my $end = (-s
$I) / $reclen;
102 $end == int $end or return;
104 my ($start, $buf, $current) = 0;
106 while ($start <= $end) {
107 seek $I, ($current = ($start + $end) >> 1)*$reclen, 0 or return;
108 $reclen == read ($I, $buf, $reclen) or return;
110 my ($num, $found) = unpack 'L2',$buf;
112 if ($num == $posting) {
115 elsif ($num < $posting) {
126 ### sub add_view ###############################################################
128 # increment the views-counter
132 # Return: Status code (Bool)
135 my ($self, $h, $param) = @_;
136 my ($C, $I) = ($h->{C
}, $h->{I
});
137 my $reclen = 4 * length pack 'L', 0;
139 defined ($pos = find_pos
$I, $param->{posting
}) or return;
142 seek $C, $pos, 0 or return;
143 read ($C, $buf, $reclen) == $reclen or return;
145 my ($posting, $thread, $views, $votings) = unpack 'L4',$buf;
146 $thread == $param->{thread
} or return;
147 seek $C, $pos, 0 or return;
148 print $C pack ('L4' => $posting, $thread, $views+1, $votings) or return;
154 my ($self, $param) = @_;
156 $self -> write_wrap
(
162 ### sub pick ###################################################################
164 # read information of one posting
166 # Params: $param - hash reference
169 # Return: hash reference or false
172 my ($self, $h, $param) = @_;
173 my ($C, $I) = ($h->{C
}, $h->{I
});
174 my $reclen = 4 * length pack 'L', 0;
178 defined($pos = find_pos
$I, $param->{posting
}) or return;
180 seek $C, $pos, 0 or return;
181 read ($C, $buf, $reclen) == $reclen or return;
183 my ($posting, $thread, $views, $votings) = unpack 'L4', $buf;
184 $buf = <$C>; chomp $buf;
192 time => $_->[0] || 0,
205 my ($self, $param) = @_;
207 $self -> read_wrap
(\
&r_pick
, $param)
212 ### sub summary ################################################################
214 # read out the cache and return a summary
218 # Return: hash reference or false
222 my ($C, $I) = ($h->{C
}, $h->{I
});
223 my $reclen = length pack 'L', 0;
224 my $ireclen = 2 * $reclen;
225 my $creclen = 4 * $reclen;
226 my ($buf, $pos, %hash);
229 while ($ireclen == read ($I, $buf, $ireclen)) {
230 (undef, $pos) = unpack 'L2', $buf;
232 seek $C, $pos, 0 or return;
233 read ($C, $buf, $creclen) == $creclen or return;
235 my ($posting, $thread, $views, $votings) = unpack 'L4', $buf;
236 $hash{$thread} = {} unless $hash{$thread};
237 $hash{$thread} -> {$posting} = {
243 $self -> {summary
} = \
%hash;
252 $self -> read_wrap
(\
&r_summary
)
257 ### sub repair_cache ###########################################################
259 # check on cache consistance and repair if broken
263 # Return: sucess code (Bool)
267 my ($C, $TC, $TI) = ($h->{C
}, $h->{TC
}, $h->{TI
});
270 my $reclen = 4 * length pack 'L',0;
274 while ($reclen == read $C, $block, $reclen) {
275 my $msg = unpack ('L' => $block);
278 print $TC $block. $rest. $/;
279 print $TI pack ('L2' => $msg, $pos);
289 return unless ($self->cachefile and $self->indexfile);
290 return 1 if (-f
$self->cachefile and -f
$self->indexfile);
292 unless (-f
$self->cachefile) {
293 return if (-f
$self->indexfile);
296 return unless (open FILE
, '>'.$self->cachefile);
297 return unless (close FILE
);
298 return unless (open FILE
, '>'.$self->indexfile);
299 return unless (close FILE
);
301 release_file
($self->cachefile);
302 release_file
($self->indexfile);
303 release_file
($self->temp_indexfile);
304 release_file
($self->temp_cachefile);
309 $self -> open_wrap
(\
&r_repair_cache
);
312 ### sub add_posting ############################################################
314 # add an empty cache entry of a posting
316 # Params: $param - hash reference
319 # Return: Status code (Bool)
322 my ($self, $h, $param) = @_;
323 my ($C, $TC, $TI) = ($h->{C
}, $h->{TC
}, $h->{TI
});
325 my ($block, $ins, $msg);
326 my $reclen = 4 * length pack 'L',0;
330 while ($reclen == read $C, $block, $reclen) {
331 $msg = unpack ('L' => $block);
333 if ($param -> {posting
} == $msg) {
334 $self->set_error("double defined posting id 'm$msg'");
337 next if ($param -> {posting
} > $msg or $ins);
339 print $TC pack('L4' => $param->{posting
}, $param->{thread
}, 0, 0), $/;
340 print $TI pack('L2' => $param->{posting
}, $pos);
347 print $TC $block. $rest. $/;
348 print $TI pack ('L2' => $msg, $pos);
352 print $TC pack('L4' => $param->{posting
}, $param->{thread
}, 0, 0), $/;
353 print $TI pack('L2' => $param->{posting
}, $pos);
367 ### sub add_voting #############################################################
369 # add a voting (increment vote counter and log the vote data)
371 # Params: $param - hash reference
372 # (thread, posting, IP, time, ID)
374 # Return: Status code (Bool)
377 my ($self, $h, $param) = @_;
378 my ($C, $TC, $TI) = ($h->{C
}, $h->{TC
}, $h->{TI
});
381 my $reclen = 4 * length pack 'L',0;
385 while ($reclen == read $C, $block, $reclen) {
388 my ($msg, $thread, $views, $votings) = unpack ('L4' => $block);
390 $param -> {posting
} != $msg or do {
391 $rest = join ' ' => (length $rest ?
$rest: (), join ';' => ($param->{time}, $param->{IP
}, $param->{ID
}));
395 print $TC pack ('L4' => ($msg, $thread, $views, $votings)), $rest, $/;
396 print $TI pack ('L2' => $msg, $pos);
411 ### sub open_wrap ##############################################################
413 # file lock, open, execute, close, unlock wrapper
414 # for writing into temp files
416 # Params: $gosub - sub reference (for execution)
417 # @param - params (for $gosub)
419 # Return: Status code (Bool)
422 my ($self, $gosub, @param) = @_;
425 unless (write_lock_file
($self->temp_cachefile)) {
426 violent_unlock_file
($self->temp_cachefile);
427 $self->set_error ('could not write-lock temp cache file '.$self->temp_cachefile);
430 unless (write_lock_file
($self->temp_indexfile)) {
431 violent_unlock_file
($self->temp_indexfile);
432 $self->set_error ('could not write-lock temp index file '.$self->temp_indexfile);
435 unless (lock_file
($self->cachefile)) {
436 violent_unlock_file
($self->cachefile);
437 $self->set_error ('could not read-lock cache file '.$self->cachefile);
440 unless (lock_file
($self->indexfile)) {
441 violent_unlock_file
($self->indexfile);
442 $self->set_error ('could not read-lock index file '.$self->indexfile);
445 local (*C
, *TC
, *TI
);
446 unless (sysopen (C
, $self->cachefile, O_RDONLY
| $O_BINARY)) {
447 $self->set_error ('could not open to read cache file '.$self->cachefile);
450 unless (sysopen (TC
, $self->temp_cachefile, O_WRONLY
| O_TRUNC
| O_CREAT
| $O_BINARY)) {
451 $self->set_error ('could not open to write temp cache file '.$self->temp_cachefile);
454 unless (sysopen (TI
, $self->temp_indexfile, O_WRONLY
| O_TRUNC
| O_CREAT
| $O_BINARY)) {
455 $self->set_error ('could not open to write temp index file '.$self->temp_indexfile);
458 $status = $gosub -> (
468 $self->set_error('could not close temp index file '.$self->temp_indexfile);
473 $self->set_error('could not close temp cache file '.$self->temp_cachefile);
478 $self->set_error('could not close cache file '.$self->cachefile);
481 unless (write_lock_file
($self->cachefile) and write_lock_file
($self->indexfile)) {
483 $self->set_error('could not write-lock cache or index file');
486 unless (unlink $self->indexfile or !-f
$self->indexfile) {
488 $self->set_error('could not unlink '.$self->indexfile);
491 unless (rename $self->temp_cachefile => $self->cachefile) {
493 $self->set_error('could not rename '.$self->temp_cachefile);
496 unless (rename $self->temp_indexfile => $self->indexfile) {
498 $self->set_error('could not rename '.$self->temp_indexfile);
505 violent_unlock_file
($self->indexfile) unless (unlock_file
($self->indexfile));
507 violent_unlock_file
($self->cachefile) unless (unlock_file
($self->cachefile));
509 violent_unlock_file
($self->temp_indexfile) unless (write_unlock_file
($self->temp_indexfile));
511 violent_unlock_file
($self->temp_cachefile) unless (write_unlock_file
($self->temp_cachefile));
518 ### sub read_wrap ##############################################################
520 # file lock, open, execute, close, unlock wrapper
523 # Params: $gosub - sub reference (for execution)
524 # @param - params (for $gosub)
526 # Return: Status code (Bool)
529 my ($self, $gosub, @param) = @_;
532 unless (lock_file
($self->cachefile)) {
533 violent_unlock_file
($self->cachefile);
534 $self->set_error ('could not read-lock cache file '.$self->cachefile);
537 unless (lock_file
($self->indexfile)) {
538 violent_unlock_file
($self->indexfile);
539 $self->set_error ('could not read-lock index file '.$self->indexfile);
543 unless (sysopen (C
, $self->cachefile, O_RDONLY
| $O_BINARY)) {
544 $self->set_error ('could not open to read cache file '.$self->cachefile);
547 unless (sysopen (I
, $self->indexfile, O_RDONLY
| $O_BINARY)) {
548 $self->set_error ('could not open to read index file '.$self->indexfile);
551 $status = $gosub -> (
560 $self->set_error('could not close index file '.$self->indexfile);
565 $self->set_error('could not close cache file '.$self->cachefile);
568 violent_unlock_file
($self->indexfile) unless (unlock_file
($self->indexfile));
570 violent_unlock_file
($self->cachefile) unless (unlock_file
($self->cachefile));
577 ### sub write_wrap ##############################################################
579 # file lock, open, execute, close, unlock wrapper
582 # Params: $gosub - sub reference (for execution)
583 # @param - params (for $gosub)
585 # Return: Status code (Bool)
588 my ($self, $gosub, @param) = @_;
591 unless (write_lock_file
($self->temp_cachefile)) {
592 violent_unlock_file
($self->temp_cachefile);
593 $self->set_error ('could not write-lock temp cache file '.$self->temp_cachefile);
596 unless (write_lock_file
($self->cachefile)) {
597 violent_unlock_file
($self->cachefile);
598 $self->set_error ('could not write-lock cache file '.$self->cachefile);
601 unless (lock_file
($self->indexfile)) {
602 violent_unlock_file
($self->indexfile);
603 $self->set_error ('could not read-lock index file '.$self->indexfile);
607 unless (sysopen (C
, $self->cachefile, O_RDWR
| $O_BINARY)) {
608 $self->set_error ('could not open to read/write cache file '.$self->cachefile);
611 unless (sysopen (I
, $self->indexfile, O_RDONLY
| $O_BINARY)) {
612 $self->set_error ('could not open to read index file '.$self->indexfile);
615 $status = $gosub -> (
624 $self->set_error('could not close index file '.$self->indexfile);
629 $self->set_error('could not close cache file '.$self->cachefile);
632 violent_unlock_file
($self->indexfile) unless (unlock_file
($self->indexfile));
634 violent_unlock_file
($self->cachefile) unless (write_unlock_file
($self->cachefile));
636 violent_unlock_file
($self->temp_cachefile) unless (write_unlock_file
($self->temp_cachefile));
643 # keep 'require' happy
649 ### end of Posting::Cache ######################################################
patrick-canterino.de