]>
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 "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) or return;
423 $self->cachefile($param),
424 O_WRONLY
| O_CREAT
| O_TRUNC
426 close FILE
or return;
430 my $reclen = length (pack 'L' => 0) << 2;
431 seek $handle, 0-$reclen, 2 or return;
433 read ($handle, $buf, $reclen) == $reclen or return;
434 $z = unpack 'L' => $buf;
435 if ($z < $param->{posting
}) {
436 while (++$z < $param->{posting
}) {
437 seek $handle, 0, 2 or return;
439 'L4' => $z, 0xFFFFFFFF, 0, 0
447 $pos = find_pos
$handle, $param->{posting
}
449 seek $handle, $pos, 0 or return;
453 unless (defined $z) {
454 seek $handle, 0, 2 or return;
458 'L4' => $param->{posting
}, $param->{thread
}, 0, 0
461 release_file
($self->cachefile($param));
466 ### sub add_wrap ################################################################
468 # file lock, open, execute, close, unlock wrapper
469 # for adding an empty entry
471 # Params: $gosub - sub reference (for execution)
472 # @param - params (for $gosub)
474 # Return: Status code (Bool)
477 my ($self, $gosub, @param) = @_;
480 unless (write_lock_file
($self->summaryfile)) {
481 violent_unlock_file
($self->summaryfile);
482 $self->set_error ('could not write-lock summary file '.$self->summaryfile);
486 unless (sysopen (SUM
, $self->summaryfile, $O_BINARY | O_APPEND
| O_CREAT
| O_RDWR
)) {
488 ('could not open to read/write/append summary file '.$self->summaryfile);
491 $status = $gosub -> (
498 $self->set_error('could not close summary file '.$self->summaryfile);
501 violent_unlock_file
($self->summaryfile) unless (write_unlock_file
($self->summaryfile));
508 ### sub vote_wrap ###############################################################
510 # file lock, open, execute, close, unlock wrapper
513 # Params: $gosub - sub reference (for execution)
514 # @param - params (for $gosub)
516 # Return: Status code (Bool)
519 my ($self, $gosub, $param) = @_;
522 unless (write_lock_file
($self->summaryfile)) {
523 violent_unlock_file
($self->summaryfile);
524 $self->set_error ('could not write-lock summary file '.$self->summaryfile);
528 unless (sysopen (S
, $self->summaryfile, O_RDWR
| $O_BINARY)) {
529 $self->set_error ('could not open to read/write summary file '.$self->summaryfile);
532 unless (-d
$self->threaddir($param)) {
533 mkdir $self->threaddir($param) or return;
535 my $filename = $self->cachefile($param);
537 unless (write_lock_file
($filename)) {
538 violent_unlock_file
($filename);
539 $self->set_error ('could not write-lock cache file '.$filename);
543 unless (sysopen (CACHE
, $filename, O_APPEND
| O_CREAT
| O_RDWR
)) {
544 $self->set_error ('could not open to read/write/append cache file '.$filename);
547 $status = $gosub -> (
553 unless (close CACHE
) {
555 $self->set_error('could not close cache file '.$filename);
558 violent_unlock_file
($filename) unless (write_unlock_file
($filename));
562 $self->set_error('could not close summary file '.$self->summaryfile);
565 violent_unlock_file
($self->summaryfile) unless (write_unlock_file
($self->summaryfile));
572 ### sub purge_wrap ##############################################################
574 # file lock, open, execute, close, unlock wrapper
575 # for garbage collection
577 # Params: $gosub - sub reference (for execution)
578 # @param - params (for $gosub)
580 # Return: Status code (Bool)
583 my ($self, $gosub, @param) = @_;
585 my $filename = $self -> summaryfile
. '.temp';
587 unless (write_lock_file
($self->summaryfile)) {
588 violent_unlock_file
($self->summaryfile);
589 $self->set_error ('could not write-lock summary file '.$self->summaryfile);
593 unless (sysopen (TEMP
, $filename, O_CREAT
| O_WRONLY
| O_TRUNC
| $O_BINARY)) {
594 $self->set_error ('could not open to write temp summary file '.$filename);
598 unless (sysopen (S
, $self->summaryfile, O_RDONLY
| $O_BINARY)) {
599 $self->set_error ('could not open to read summary file '.$self->summaryfile);
602 $status = $gosub -> (
610 $self->set_error('could not close summary file '.$self->summaryfile);
613 unless (close TEMP
) {
615 $self->set_error('could not close temp summary file '.$filename);
618 unless (rename $filename => $self->summaryfile) {
620 $self->set_error('could not rename temp summary file '.$filename);
624 violent_unlock_file
($self->summaryfile) unless (write_unlock_file
($self->summaryfile));
631 ### sub pick_wrap ###############################################################
633 # file lock, open, execute, close, unlock wrapper
634 # for picking a posting
636 # Params: $gosub - sub reference (for execution)
637 # @param - params (for $gosub)
639 # Return: Status code (Bool)
642 my ($self, $gosub, $filename, @param) = @_;
645 unless (lock_file
($filename)) {
646 violent_unlock_file
($filename);
647 $self->set_error ('could not lock cache file '.$filename);
651 unless (sysopen (CACHE
, $filename, O_RDONLY
)) {
652 $self->set_error ('could not open to read cache file '.$filename);
655 $status = $self -> read_wrap
(
660 unless (close CACHE
) {
662 $self->set_error('could not close cache file '.$filename);
665 violent_unlock_file
($filename) unless (unlock_file
($filename));
672 ### sub read_wrap ###############################################################
674 # file lock, open, execute, close, unlock wrapper
675 # for reading of summary file
677 # Params: $gosub - sub reference (for execution)
678 # @param - params (for $gosub)
680 # Return: Status code (Bool)
683 my ($self, $gosub, @param) = @_;
686 unless (lock_file
($self->summaryfile)) {
687 violent_unlock_file
($self->summaryfile);
688 $self->set_error ('could not read-lock summary file '.$self->summaryfile);
692 unless (sysopen (S
, $self->summaryfile, O_RDONLY
| $O_BINARY)) {
693 $self->set_error ('could not open to read summary file '.$self->summaryfile);
696 $status = $gosub -> (
703 $self->set_error('could not close summary file '.$self->summaryfile);
706 violent_unlock_file
($self->summaryfile) unless (unlock_file
($self->summaryfile));
713 ### sub mod_wrap ################################################################
715 # file lock, open, execute, close, unlock wrapper
716 # for modification of summary file
718 # Params: $gosub - sub reference (for execution)
719 # @param - params (for $gosub)
721 # Return: Status code (Bool)
724 my ($self, $gosub, @param) = @_;
727 unless (write_lock_file
($self->summaryfile)) {
728 violent_unlock_file
($self->summaryfile);
729 $self->set_error ('could not write-lock summary file '.$self->summaryfile);
733 unless (sysopen (S
, $self->summaryfile, O_RDWR
| $O_BINARY)) {
734 $self->set_error ('could not open to read/write summary file '.$self->summaryfile);
737 $status = $gosub -> (
744 $self->set_error('could not close summary file '.$self->summaryfile);
747 violent_unlock_file
($self->summaryfile) unless (write_unlock_file
($self->summaryfile));
754 # keep 'require' happy
760 ### end of Posting::Cache ######################################################
patrick-canterino.de