]>
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 ################################################################################
22 ################################################################################
26 $VERSION = do { my @r =(q
$Revision$ =~ /\d+/g); sprintf "%d."."%02d" x
$#r, @r };
28 my $O_BINARY = eval 'local $SIG{__DIE__}; O_BINARY';
29 $O_BINARY = 0 if ($@
);
31 ### sub new ####################################################################
35 # Params: $pathname - full qualified cache path
37 # Return: Posting::Cache object
40 my $self = bless {} => shift;
43 $self -> set_path
(+shift);
48 ### sub clear_error ############################################################
50 # clear verbal error data
59 $self -> {verb_error
} = undef;
64 sub error
{$_[0]->{verb_error
}}
69 $self -> {verb_error
} = +shift;
73 ### sub set_path ###############################################################
77 # Params: $pathname - full qualified cache path
80 my ($self, $pathname) = @_;
82 $self -> {cachepath
} = $pathname;
87 sub cachepath
{$_[0] -> {cachepath
}}
88 sub threaddir
{$_[0] -> cachepath
. $_[1] -> {thread
}}
89 sub threadpath
{$_[0] -> threaddir
($_[1]) . '/'}
90 sub cachefile
{$_[0] -> threadpath
($_[1]) . $_[1] -> {posting
} . '.txt'}
91 sub summaryfile
{$_[0] -> cachepath
. 'summary.bin'}
93 ### sub delete_threads #########################################################
95 # remove threads from cache
97 # Params: @threads - list of threadnumbers
99 # Return: Status Code (Bool)
102 my ($self, @threads) = @_;
103 my %threads = map {$_ => 1} @threads;
110 sub r_delete_threads
{
111 my ($self, $handle, $threads) = @_;
112 my $l = length (pack 'L' => 0);
113 my $reclen = $l << 2;
114 my $len = -s
$handle;
115 my $num = int ($len / $reclen) -1;
121 seek $handle, $_ * $reclen + $l, 0 or return;
122 read ($handle, $buf, $l) == $l or return;
123 if ($threads->{unpack 'L' => $buf}) {
124 seek $handle, $_ * $reclen + $l, 0 or return;
125 print $handle pack ('L' => 0) or return;
129 rmtree
($self->threaddir({thread
=> $_}), 0, 0)
130 for (keys %$threads);
135 ### sub garbage_collection #####################################################
137 # remove old entrys from the beginning of the cache
143 sub garbage_collection
{
146 $self -> purge_wrap
(
147 \
&r_garbage_collection
150 sub r_garbage_collection
{
151 my ($self, $handle, $file) = @_;
153 my $reclen = length (pack 'L', 0) << 2;
154 my $len = -s
$handle;
155 my $num = int ($len / $reclen) -1;
156 my ($z, $buf, $h) = 0;
162 seek $handle, 0, 0 or return;
163 read ($handle, $buf, $len) or return;
165 (undef, $h) = (unpack 'L2' => substr ($buf, $_ * $reclen, $reclen));
167 return unless (defined $h);
170 substr ($buf, 0, $z * $reclen) = '';
172 seek $file, 0, 0 or return;
173 print $file $buf or return;
179 ### sub find_pos ($$) ##########################################################
181 # find position in cache file
183 # Params: $handle - summary file handle
184 # $posting - posting number
186 # Return: position or false (undef)
189 my ($handle, $posting) = @_;
190 my $reclen = length (pack 'L',0);
191 my $lreclen = $reclen << 2;
192 seek $handle, 0, 0 or return;
195 read ($handle, $buf, $reclen) == $reclen or return;
197 my $first = unpack ('L' => $buf);
198 $first <= $posting or return;
200 my $pos = ($posting - $first) * $lreclen;
201 seek $handle, $pos, 0 or return;
206 ### sub add_view ###############################################################
208 # increment the views-counter
210 # Params: hash reference
213 # Return: Status code (Bool)
216 my ($self, $param) = @_;
224 my ($self, $handle, $param) = @_;
225 my $reclen = length (pack 'L', 0) << 2;
227 defined ($pos = find_pos
$handle, $param->{posting
}) or return;
230 seek $handle, $pos, 0 or return;
231 read ($handle, $buf, $reclen) == $reclen or return;
233 my ($posting, $thread, $views, $votings) = unpack 'L4' => $buf;
234 $thread == 0xFFFFFFFF and $thread = $param->{thread
};
236 $param->{thread
} == $thread or return;
237 $param->{posting
} == $posting or return;
239 seek $handle, $pos, 0 or return;
242 print $handle pack ('L4' => $posting, $thread, $views+1, $votings) or return;
247 ### sub pick ###################################################################
249 # read information of one posting
251 # Params: $param - hash reference
254 # Return: hash reference or false
257 my ($self, $param) = @_;
261 $self->cachefile($param),
267 my ($self, $handle, $file, $param) = @_;
268 my $reclen = 4 * length (pack 'L' => 0);
272 defined($pos = find_pos
$handle, $param->{posting
}) or return;
274 seek $handle, $pos, 0 or return;
275 read ($handle, $buf, $reclen) == $reclen or return;
277 my ($posting, $thread, $views, $votings) = unpack 'L4' => $buf;
278 $thread == 0xFFFFFFFF and $thread = $param->{thread
};
280 $param->{thread
} == $thread or return;
281 $param->{posting
} == $posting or return;
283 seek $file, 0, 0 or return;
284 my @records = <$file>;
294 time => $_->[0] || 0,
297 } [split ' ' => $_,3]
306 ### sub summary ################################################################
308 # read out the cache and return a summary
312 # Return: hash reference or false
317 $self -> read_wrap
(\
&r_summary
)
322 my ($self, $handle) = @_;
323 my $reclen = length (pack 'L', 0) << 2;
324 my $len = -s
$handle;
325 my $num = int ($len / $reclen) -1;
329 seek $handle, 0, 0 or return;
330 read ($handle, $buf, $len) or return;
332 my ($posting, $thread, $views, $votings)
333 = (unpack 'L4' => substr ($buf, $_ * $reclen, $reclen));
335 $hash{$thread} = {} unless $hash{$thread};
336 $hash{$thread} -> {$posting} = {
342 $self -> {summary
} = \
%hash;
348 ### sub add_voting #############################################################
352 # Params: $param - hash reference
353 # (thread, posting, IP, ID, time)
355 # Return: Status code (Bool)
358 my ($self, $param) = @_;
366 my ($self, $handle, $file, $param) = @_;
367 my $reclen = length (pack 'L', 0) << 2;
369 defined ($pos = find_pos
$handle, $param->{posting
}) or return;
372 seek $handle, $pos, 0 or return;
373 read ($handle, $buf, $reclen) == $reclen or return;
375 my ($posting, $thread, $views, $votings) = unpack 'L4' => $buf;
376 $thread == 0xFFFFFFFF and $thread = $param->{thread
};
378 $param->{thread
} == $thread or return;
382 seek $file, 0, 2 or return;
384 join (' ' => $param->{time}, $param->{IP
}, $param->{ID
}) or return;
389 seek $handle, $pos, 0 or return;
391 pack ('L4' => $posting, $thread, $views, $votings+1) or return;
397 ### sub add_posting ############################################################
399 # add an empty cache entry of a posting
401 # Params: $param - hash reference
404 # Return: Status code (Bool)
414 my ($self, $handle, $param) = @_;
418 unless (-d
$self -> threaddir
($param)) {
419 mkdir $self->threaddir($param), 0777 or return;
422 $self->cachefile($param),
423 O_WRONLY
| O_CREAT
| O_TRUNC
425 close FILE
or return;
429 my $reclen = length (pack 'L' => 0) << 2;
430 seek $handle, 0-$reclen, 2 or return;
432 read ($handle, $buf, $reclen) == $reclen or return;
433 $z = unpack 'L' => $buf;
434 if ($z < $param->{posting
}) {
435 while (++$z < $param->{posting
}) {
436 seek $handle, 0, 2 or return;
438 'L4' => $z, 0xFFFFFFFF, 0, 0
446 $pos = find_pos
$handle, $param->{posting
}
448 seek $handle, $pos, 0 or return;
452 unless (defined $z) {
453 seek $handle, 0, 2 or return;
457 'L4' => $param->{posting
}, $param->{thread
}, 0, 0
460 release_file
($self->cachefile($param));
465 ### sub add_wrap ################################################################
467 # file lock, open, execute, close, unlock wrapper
468 # for adding an empty entry
470 # Params: $gosub - sub reference (for execution)
471 # @param - params (for $gosub)
473 # Return: Status code (Bool)
476 my ($self, $gosub, @param) = @_;
479 unless (write_lock_file
($self->summaryfile)) {
480 violent_unlock_file
($self->summaryfile);
481 $self->set_error ('could not write-lock summary file '.$self->summaryfile);
485 unless (sysopen (SUM
, $self->summaryfile, $O_BINARY | O_APPEND
| O_CREAT
| O_RDWR
)) {
487 ('could not open to read/write/append summary file '.$self->summaryfile);
490 $status = $gosub -> (
497 $self->set_error('could not close summary file '.$self->summaryfile);
500 violent_unlock_file
($self->summaryfile) unless (write_unlock_file
($self->summaryfile));
507 ### sub vote_wrap ###############################################################
509 # file lock, open, execute, close, unlock wrapper
512 # Params: $gosub - sub reference (for execution)
513 # @param - params (for $gosub)
515 # Return: Status code (Bool)
518 my ($self, $gosub, $param) = @_;
521 unless (write_lock_file
($self->summaryfile)) {
522 violent_unlock_file
($self->summaryfile);
523 $self->set_error ('could not write-lock summary file '.$self->summaryfile);
527 unless (sysopen (S
, $self->summaryfile, O_RDWR
| $O_BINARY)) {
528 $self->set_error ('could not open to read/write summary file '.$self->summaryfile);
531 unless (-d
$self->threaddir($param)) {
532 mkdir $self->threaddir($param), 0777 or return;
534 my $filename = $self->cachefile($param);
536 unless (write_lock_file
($filename)) {
537 violent_unlock_file
($filename);
538 $self->set_error ('could not write-lock cache file '.$filename);
542 unless (sysopen (CACHE
, $filename, O_APPEND
| O_CREAT
| O_RDWR
)) {
543 $self->set_error ('could not open to read/write/append cache file '.$filename);
546 $status = $gosub -> (
552 unless (close CACHE
) {
554 $self->set_error('could not close cache file '.$filename);
557 violent_unlock_file
($filename) unless (write_unlock_file
($filename));
561 $self->set_error('could not close summary file '.$self->summaryfile);
564 violent_unlock_file
($self->summaryfile) unless (write_unlock_file
($self->summaryfile));
571 ### sub purge_wrap ##############################################################
573 # file lock, open, execute, close, unlock wrapper
574 # for garbage collection
576 # Params: $gosub - sub reference (for execution)
577 # @param - params (for $gosub)
579 # Return: Status code (Bool)
582 my ($self, $gosub, @param) = @_;
584 my $filename = $self -> summaryfile
. '.temp';
586 unless (write_lock_file
($self->summaryfile)) {
587 violent_unlock_file
($self->summaryfile);
588 $self->set_error ('could not write-lock summary file '.$self->summaryfile);
592 unless (sysopen (TEMP
, $filename, O_CREAT
| O_WRONLY
| O_TRUNC
| $O_BINARY)) {
593 $self->set_error ('could not open to write temp summary file '.$filename);
597 unless (sysopen (S
, $self->summaryfile, O_RDONLY
| $O_BINARY)) {
598 $self->set_error ('could not open to read summary file '.$self->summaryfile);
601 $status = $gosub -> (
609 $self->set_error('could not close summary file '.$self->summaryfile);
612 unless (close TEMP
) {
614 $self->set_error('could not close temp summary file '.$filename);
617 unless (rename $filename => $self->summaryfile) {
619 $self->set_error('could not rename temp summary file '.$filename);
623 violent_unlock_file
($self->summaryfile) unless (write_unlock_file
($self->summaryfile));
630 ### sub pick_wrap ###############################################################
632 # file lock, open, execute, close, unlock wrapper
633 # for picking a posting
635 # Params: $gosub - sub reference (for execution)
636 # @param - params (for $gosub)
638 # Return: Status code (Bool)
641 my ($self, $gosub, $filename, @param) = @_;
644 unless (lock_file
($filename)) {
645 violent_unlock_file
($filename);
646 $self->set_error ('could not lock cache file '.$filename);
650 unless (sysopen (CACHE
, $filename, O_RDONLY
)) {
651 $self->set_error ('could not open to read cache file '.$filename);
654 $status = $self -> read_wrap
(
659 unless (close CACHE
) {
661 $self->set_error('could not close cache file '.$filename);
664 violent_unlock_file
($filename) unless (unlock_file
($filename));
671 ### sub read_wrap ###############################################################
673 # file lock, open, execute, close, unlock wrapper
674 # for reading of summary file
676 # Params: $gosub - sub reference (for execution)
677 # @param - params (for $gosub)
679 # Return: Status code (Bool)
682 my ($self, $gosub, @param) = @_;
685 unless (lock_file
($self->summaryfile)) {
686 violent_unlock_file
($self->summaryfile);
687 $self->set_error ('could not read-lock summary file '.$self->summaryfile);
691 unless (sysopen (S
, $self->summaryfile, O_RDONLY
| $O_BINARY)) {
692 $self->set_error ('could not open to read summary file '.$self->summaryfile);
695 $status = $gosub -> (
702 $self->set_error('could not close summary file '.$self->summaryfile);
705 violent_unlock_file
($self->summaryfile) unless (unlock_file
($self->summaryfile));
712 ### sub mod_wrap ################################################################
714 # file lock, open, execute, close, unlock wrapper
715 # for modification of summary file
717 # Params: $gosub - sub reference (for execution)
718 # @param - params (for $gosub)
720 # Return: Status code (Bool)
723 my ($self, $gosub, @param) = @_;
726 unless (write_lock_file
($self->summaryfile)) {
727 violent_unlock_file
($self->summaryfile);
728 $self->set_error ('could not write-lock summary file '.$self->summaryfile);
732 unless (sysopen (S
, $self->summaryfile, O_RDWR
| $O_BINARY)) {
733 $self->set_error ('could not open to read/write summary file '.$self->summaryfile);
736 $status = $gosub -> (
743 $self->set_error('could not close summary file '.$self->summaryfile);
746 violent_unlock_file
($self->summaryfile) unless (write_unlock_file
($self->summaryfile));
753 # keep 'require' happy
759 ### end of Posting::Cache ######################################################
patrick-canterino.de