]>
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 ################################################################################
19 my $O_BINARY = eval "O_BINARY";
20 $O_BINARY = 0 if ($@
);
22 ### sub new ####################################################################
26 # Params: $pathname - full qualified cache path
28 # Return: Posting::Cache object
31 my $self = bless {} => shift;
34 $self -> set_path
(+shift);
39 ### sub clear_error ############################################################
41 # clear verbal error data
50 $self -> {verb_error
} = undef;
55 sub error
{$_[0]->{verb_error
}}
60 $self -> {verb_error
} = +shift;
64 ### sub set_path ###############################################################
68 # Params: $pathname - full qualified cache path
71 my ($self, $pathname) = @_;
73 $self -> {cachepath
} = $pathname;
78 sub cachepath
{$_[0] -> {cachepath
}}
79 sub threaddir
{$_[0] -> cachepath
. $_[1] -> {thread
}}
80 sub threadpath
{$_[0] -> threaddir
($_[1]) . '/'}
81 sub cachefile
{$_[0] -> threadpath
($_[1]) . $_[1] -> {posting
} . '.txt'}
82 sub summaryfile
{$_[0] -> cachepath
. 'summary.bin'}
84 ### sub delete_threads #########################################################
86 # remove threads from cache
88 # Params: @threads - list of threadnumbers
90 # Return: Status Code (Bool)
93 my ($self, @threads) = @_;
94 my %threads = map {$_ => 1} @threads;
101 sub r_delete_threads
{
102 my ($self, $handle, $threads) = @_;
103 my $l = length (pack 'L' => 0);
104 my $reclen = $l << 2;
105 my $len = -s
$handle;
106 my $num = int ($len / $reclen) -1;
112 seek $handle, $_ * $reclen + $l, 0 or return;
113 read ($handle, $buf, $l) == $l or return;
114 if ($threads->{unpack 'L' => $buf}) {
115 seek $handle, $_ * $reclen + $l, 0 or return;
116 print $handle pack ('L' => 0) or return;
120 rmtree
($self->threaddir({thread
=> $_}), 0, 0)
121 for (keys %$threads);
126 ### sub garbage_collection #####################################################
128 # remove old entrys from the beginning of the cache
134 sub garbage_collection
{
137 $self -> purge_wrap
(
138 \
&r_garbage_collection
141 sub r_garbage_collection
{
142 my ($self, $handle, $file) = @_;
144 my $reclen = length (pack 'L', 0) << 2;
145 my $len = -s
$handle;
146 my $num = int ($len / $reclen) -1;
147 my ($z, $buf, $h) = 0;
151 seek $handle, 0, 0 or return;
152 read ($handle, $buf, $len) or return;
154 (undef, $h) = (unpack 'L2' => substr ($buf, $_ * $reclen, $reclen));
156 return unless (defined $h);
159 substr ($buf, 0, $z * $reclen) = '';
161 seek $file, 0, 0 or return;
162 print $file $buf or return;
168 ### sub find_pos ($$) ##########################################################
170 # find position in cache file
172 # Params: $handle - summary file handle
173 # $posting - posting number
175 # Return: position or false (undef)
178 my ($handle, $posting) = @_;
179 my $reclen = length (pack 'L',0);
180 my $lreclen = $reclen << 2;
181 seek $handle, 0, 0 or return;
184 read ($handle, $buf, $reclen) == $reclen or return;
186 my $first = unpack ('L' => $buf);
187 $first <= $posting or return;
189 my $pos = ($posting - $first) * $lreclen;
190 seek $handle, $pos, 0 or return;
195 ### sub add_view ###############################################################
197 # increment the views-counter
199 # Params: hash reference
202 # Return: Status code (Bool)
205 my ($self, $param) = @_;
213 my ($self, $handle, $param) = @_;
214 my $reclen = length (pack 'L', 0) << 2;
216 defined ($pos = find_pos
$handle, $param->{posting
}) or return;
219 seek $handle, $pos, 0 or return;
220 read ($handle, $buf, $reclen) == $reclen or return;
222 my ($posting, $thread, $views, $votings) = unpack 'L4' => $buf;
223 $param->{thread
} == $thread or return;
224 $param->{posting
} == $posting or return;
226 seek $handle, $pos, 0 or return;
229 print $handle pack ('L4' => $posting, $thread, $views+1, $votings) or return;
234 ### sub pick ###################################################################
236 # read information of one posting
238 # Params: $param - hash reference
241 # Return: hash reference or false
244 my ($self, $param) = @_;
248 $self->cachefile($param),
254 my ($self, $handle, $file, $param) = @_;
255 my $reclen = 4 * length (pack 'L' => 0);
259 defined($pos = find_pos
$handle, $param->{posting
}) or return;
261 seek $handle, $pos, 0 or return;
262 read ($handle, $buf, $reclen) == $reclen or return;
264 my ($posting, $thread, $views, $votings) = unpack 'L4' => $buf;
265 $param->{thread
} == $thread or return;
266 $param->{posting
} == $posting or return;
268 seek $file, 0, 0 or return;
269 my @records = <$file>;
279 time => $_->[0] || 0,
291 ### sub summary ################################################################
293 # read out the cache and return a summary
297 # Return: hash reference or false
302 $self -> read_wrap
(\
&r_summary
)
307 my ($self, $handle) = @_;
308 my $reclen = length (pack 'L', 0) << 2;
309 my $len = -s
$handle;
310 my $num = int ($len / $reclen) -1;
314 seek $handle, 0, 0 or return;
315 read ($handle, $buf, $len) or return;
317 my ($posting, $thread, $views, $votings)
318 = (unpack 'L4' => substr ($buf, $_ * $reclen, $reclen));
320 $hash{$thread} = {} unless $hash{$thread};
321 $hash{$thread} -> {$posting} = {
327 $self -> {summary
} = \
%hash;
333 ### sub add_voting #############################################################
337 # Params: $param - hash reference
338 # (thread, posting, IP, ID, time)
340 # Return: Status code (Bool)
343 my ($self, $param) = @_;
347 $self->cachefile($param),
352 my ($self, $handle, $file, $param) = @_;
353 my $reclen = length (pack 'L', 0) << 2;
355 defined ($pos = find_pos
$handle, $param->{posting
}) or return;
358 seek $handle, $pos, 0 or return;
359 read ($handle, $buf, $reclen) == $reclen or return;
361 my ($posting, $thread, $views, $votings) = unpack 'L4' => $buf;
362 $param->{thread
} == $thread or return;
366 seek $file, 0, 2 or return;
368 join (' ' => $param->{time}, $param->{IP
}, $param->{ID
}) or return;
373 seek $handle, $pos, 0 or return;
375 pack ('L4' => $posting, $thread, $views, $votings+1) or return;
381 ### sub add_posting ############################################################
383 # add an empty cache entry of a posting
385 # Params: $param - hash reference
388 # Return: Status code (Bool)
398 my ($self, $handle, $param) = @_;
402 unless (-d
$self -> threaddir
($param)) {
403 mkdir $self->threaddir($param) or return;
407 $self->cachefile($param),
408 O_WRONLY
| O_CREAT
| O_TRUNC
410 close FILE
or return;
414 my $reclen = length (pack 'L' => 0) << 2;
415 seek $handle, 0-$reclen, 2 or return;
417 read ($handle, $buf, $reclen) == $reclen or return;
418 $z = unpack 'L' => $buf;
419 if ($z < $param->{posting
}) {
420 while (++$z < $param->{posting
}) {
421 seek $handle, 0, 2 or return;
431 $pos = find_pos
$handle, $param->{posting
}
433 seek $handle, $pos, 0 or return;
437 unless (defined $z) {
438 seek $handle, 0, 2 or return;
442 'L4' => $param->{posting
}, $param->{thread
}, 0, 0
445 release_file
($self->cachefile($param));
450 ### sub add_wrap ################################################################
452 # file lock, open, execute, close, unlock wrapper
453 # for adding an empty entry
455 # Params: $gosub - sub reference (for execution)
456 # @param - params (for $gosub)
458 # Return: Status code (Bool)
461 my ($self, $gosub, @param) = @_;
464 unless (write_lock_file
($self->summaryfile)) {
465 violent_unlock_file
($self->summaryfile);
466 $self->set_error ('could not write-lock summary file '.$self->summaryfile);
470 unless (sysopen (SUM
, $self->summaryfile, $O_BINARY | O_APPEND
| O_CREAT
| O_RDWR
)) {
472 ('could not open to read/write/append summary file '.$self->summaryfile);
475 $status = $gosub -> (
482 $self->set_error('could not close summary file '.$self->summaryfile);
485 violent_unlock_file
($self->summaryfile) unless (write_unlock_file
($self->summaryfile));
492 ### sub vote_wrap ###############################################################
494 # file lock, open, execute, close, unlock wrapper
497 # Params: $gosub - sub reference (for execution)
498 # @param - params (for $gosub)
500 # Return: Status code (Bool)
503 my ($self, $gosub, $filename, @param) = @_;
506 unless (write_lock_file
($filename)) {
507 violent_unlock_file
($filename);
508 $self->set_error ('could not write-lock cache file '.$filename);
512 unless (sysopen (CACHE
, $filename, O_APPEND
| O_CREAT
| O_RDWR
)) {
513 $self->set_error ('could not open to read/write/append cache file '.$filename);
516 $status = $self -> mod_wrap
(
521 unless (close CACHE
) {
523 $self->set_error('could not close cache file '.$filename);
526 violent_unlock_file
($filename) unless (write_unlock_file
($filename));
533 ### sub purge_wrap ##############################################################
535 # file lock, open, execute, close, unlock wrapper
536 # for garbage collection
538 # Params: $gosub - sub reference (for execution)
539 # @param - params (for $gosub)
541 # Return: Status code (Bool)
544 my ($self, $gosub, @param) = @_;
546 my $filename = $self -> summaryfile
. '.temp';
548 unless (write_lock_file
($self->summaryfile)) {
549 violent_unlock_file
($self->summaryfile);
550 $self->set_error ('could not write-lock summary file '.$self->summaryfile);
554 unless (sysopen (TEMP
, $filename, O_CREAT
| O_WRONLY
| O_TRUNC
| $O_BINARY)) {
555 $self->set_error ('could not open to write temp summary file '.$filename);
559 unless (sysopen (S
, $self->summaryfile, O_RDONLY
| $O_BINARY)) {
560 $self->set_error ('could not open to read summary file '.$self->summaryfile);
563 $status = $gosub -> (
571 $self->set_error('could not close summary file '.$self->summaryfile);
574 unless (close TEMP
) {
576 $self->set_error('could not close temp summary file '.$filename);
579 unless (rename $filename => $self->summaryfile) {
581 $self->set_error('could not rename temp summary file '.$filename);
585 violent_unlock_file
($self->summaryfile) unless (write_unlock_file
($self->summaryfile));
592 ### sub pick_wrap ###############################################################
594 # file lock, open, execute, close, unlock wrapper
595 # for picking a posting
597 # Params: $gosub - sub reference (for execution)
598 # @param - params (for $gosub)
600 # Return: Status code (Bool)
603 my ($self, $gosub, $filename, @param) = @_;
606 unless (lock_file
($filename)) {
607 violent_unlock_file
($filename);
608 $self->set_error ('could not lock cache file '.$filename);
612 unless (sysopen (CACHE
, $filename, O_RDONLY
)) {
613 $self->set_error ('could not open to read cache file '.$filename);
616 $status = $self -> read_wrap
(
621 unless (close CACHE
) {
623 $self->set_error('could not close cache file '.$filename);
626 violent_unlock_file
($filename) unless (unlock_file
($filename));
633 ### sub read_wrap ###############################################################
635 # file lock, open, execute, close, unlock wrapper
636 # for reading of summary file
638 # Params: $gosub - sub reference (for execution)
639 # @param - params (for $gosub)
641 # Return: Status code (Bool)
644 my ($self, $gosub, @param) = @_;
647 unless (lock_file
($self->summaryfile)) {
648 violent_unlock_file
($self->summaryfile);
649 $self->set_error ('could not read-lock summary file '.$self->summaryfile);
653 unless (sysopen (S
, $self->summaryfile, O_RDONLY
| $O_BINARY)) {
654 $self->set_error ('could not open to read summary file '.$self->summaryfile);
657 $status = $gosub -> (
664 $self->set_error('could not close summary file '.$self->summaryfile);
667 violent_unlock_file
($self->summaryfile) unless (unlock_file
($self->summaryfile));
674 ### sub mod_wrap ################################################################
676 # file lock, open, execute, close, unlock wrapper
677 # for modification of summary file
679 # Params: $gosub - sub reference (for execution)
680 # @param - params (for $gosub)
682 # Return: Status code (Bool)
685 my ($self, $gosub, @param) = @_;
688 unless (write_lock_file
($self->summaryfile)) {
689 violent_unlock_file
($self->summaryfile);
690 $self->set_error ('could not write-lock summary file '.$self->summaryfile);
694 unless (sysopen (S
, $self->summaryfile, O_RDWR
| $O_BINARY)) {
695 $self->set_error ('could not open to read/write summary file '.$self->summaryfile);
698 $status = $gosub -> (
705 $self->set_error('could not close summary file '.$self->summaryfile);
708 violent_unlock_file
($self->summaryfile) unless (write_unlock_file
($self->summaryfile));
715 # keep 'require' happy
721 ### end of Posting::Cache ######################################################
patrick-canterino.de