]>
git.p6c8.net - selfforum.git/blob - selfforum-cgi/shared/Posting/Cache.pm
b940f35cb4a33de54bc23851f83aaac9d053ac8f
1 package Posting
::Cache
;
3 ################################################################################
5 # File: shared/Posting/Cache.pm #
7 # Authors: André Malo <nd@o3media.de> #
9 # Description: Views/Voting Cache class #
11 ################################################################################
18 ################################################################################
26 sub VERSION
{(q
$Revision$ =~ /([\d.]+)\s*$/)[0] or '0.0'}
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) = @_;
415 my $newfile = new Lock
($self->cachefile($param));
418 unless (-d
$self -> threaddir
($param)) {
419 mkdir $self->threaddir($param), 0777 or return;
421 $newfile -> open (O_WRONLY
| O_CREAT
| O_TRUNC
) or return;
422 $newfile -> close or return;
426 my $reclen = length (pack 'L' => 0) << 2;
427 seek $handle, 0-$reclen, 2 or return;
429 read ($handle, $buf, $reclen) == $reclen or return;
430 $z = unpack 'L' => $buf;
431 if ($z < $param->{posting
}) {
432 while (++$z < $param->{posting
}) {
433 seek $handle, 0, 2 or return;
435 'L4' => $z, 0xFFFFFFFF, 0, 0
443 $pos = find_pos
$handle, $param->{posting
}
445 seek $handle, $pos, 0 or return;
449 unless (defined $z) {
450 seek $handle, 0, 2 or return;
454 'L4' => $param->{posting
}, $param->{thread
}, 0, 0
462 ### sub add_wrap ################################################################
464 # file lock, open, execute, close, unlock wrapper
465 # for adding an empty entry
467 # Params: $gosub - sub reference (for execution)
468 # @param - params (for $gosub)
470 # Return: Status code (Bool)
473 my ($self, $gosub, @param) = @_;
475 my $summary = new Lock
($self -> summaryfile
);
477 unless ($summary -> lock (LH_EXCL
)) {
478 $self->set_error ('could not write-lock summary file '.$summary -> filename
);
481 unless ($summary -> open($O_BINARY | O_APPEND
| O_CREAT
| O_RDWR
)) {
483 ('could not open to read/write/append summary file '.$summary->filename);
486 $status = $gosub -> (
491 unless ($summary -> close) {
493 $self->set_error('could not close summary file '.$summary -> filename
);
503 ### sub vote_wrap ###############################################################
505 # file lock, open, execute, close, unlock wrapper
508 # Params: $gosub - sub reference (for execution)
509 # @param - params (for $gosub)
511 # Return: Status code (Bool)
514 my ($self, $gosub, $param) = @_;
516 my $summary = new Lock
($self -> summaryfile
);
518 unless ($summary -> lock (LH_EXCL
)) {
519 $self->set_error ('could not write-lock summary file '.$summary -> filename
);
522 unless ($summary -> open (O_RDWR
| $O_BINARY)) {
523 $self->set_error ('could not open to read/write summary file '.$summary -> filename
);
526 unless (-d
$self->threaddir($param)) {
527 mkdir $self->threaddir($param), 0777 or return;
529 my $cache = new Lock
($self->cachefile($param));
531 unless ($cache -> lock (LH_EXCL
)) {
532 $self->set_error ('could not write-lock cache file '.$cache -> filename
);
535 unless ($cache -> open (O_APPEND
| O_CREAT
| O_RDWR
)) {
536 $self->set_error ('could not open to read/write/append cache file '.$cache -> filename
);
539 $status = $gosub -> (
545 unless ($cache -> close) {
547 $self->set_error('could not close cache file '.$cache -> filename
);
552 unless ($summary -> close) {
554 $self->set_error('could not close summary file '.$summary -> filename
);
564 ### sub purge_wrap ##############################################################
566 # file lock, open, execute, close, unlock wrapper
567 # for garbage collection
569 # Params: $gosub - sub reference (for execution)
570 # @param - params (for $gosub)
572 # Return: Status code (Bool)
575 my ($self, $gosub, @param) = @_;
577 my $summary = new Lock
($self -> summaryfile
);
579 unless ($summary -> lock (LH_EXSH
)) {
580 $self->set_error ('could not write-lock summary file '.$summary -> filename
);
583 my $temp = new Lock
::Handle
($summary -> filename
. '.temp');
584 unless ($temp -> open (O_CREAT
| O_WRONLY
| O_TRUNC
| $O_BINARY)) {
585 $self->set_error ('could not open to write temp summary file '.$temp -> filename
);
588 unless ($summary -> open (O_RDONLY
| $O_BINARY)) {
589 $self->set_error ('could not open to read summary file '.$summary -> filename
);
592 $status = $gosub -> (
598 unless ($summary -> close) {
600 $self->set_error('could not close summary file '.$summary -> filename
);
603 unless ($temp -> close) {
605 $self->set_error('could not close temp summary file '.$temp -> filename
);
607 unless ($summary -> lock (LH_EXCL
)) {
609 $self->set_error ('could not write-lock summary file '.$summary -> filename
);
612 unless (rename $temp -> filename
=> $summary -> filename
) {
614 $self->set_error('could not rename temp summary file '.$temp -> filename
);
625 ### sub pick_wrap ###############################################################
627 # file lock, open, execute, close, unlock wrapper
628 # for picking a posting
630 # Params: $gosub - sub reference (for execution)
631 # @param - params (for $gosub)
633 # Return: Status code (Bool)
636 my ($self, $gosub, $filename, @param) = @_;
638 my $cache = new Lock
($filename);
640 unless ($cache -> lock (LH_SHARED
)) {
641 $self->set_error ('could not lock cache file '.$cache -> filename
);
644 unless ($cache -> open (O_RDONLY
)) {
645 $self->set_error ('could not open to read cache file '.$cache -> filename
);
648 $status = $self -> read_wrap
(
653 unless ($cache -> close) {
655 $self->set_error('could not close cache file '.$cache -> filename
);
665 ### sub read_wrap ###############################################################
667 # file lock, open, execute, close, unlock wrapper
668 # for reading of summary file
670 # Params: $gosub - sub reference (for execution)
671 # @param - params (for $gosub)
673 # Return: Status code (Bool)
676 my ($self, $gosub, @param) = @_;
678 my $summary = new Lock
($self -> summaryfile
);
680 unless ($summary -> lock (LH_SHARED
)) {
681 $self->set_error ('could not read-lock summary file '.$summary -> filename
);
684 unless ($summary -> open (O_RDONLY
| $O_BINARY)) {
685 $self->set_error ('could not open to read summary file '.$summary -> filename
);
688 $status = $gosub -> (
693 unless ($summary -> close) {
695 $self->set_error('could not close summary file '.$summary -> filename
);
705 ### sub mod_wrap ################################################################
707 # file lock, open, execute, close, unlock wrapper
708 # for modification of summary file
710 # Params: $gosub - sub reference (for execution)
711 # @param - params (for $gosub)
713 # Return: Status code (Bool)
716 my ($self, $gosub, @param) = @_;
718 my $summary = new Lock
($self -> summaryfile
);
720 unless ($summary -> lock (LH_EXCL
)) {
721 $self->set_error ('could not write-lock summary file '.$summary -> filename
);
724 unless ($summary -> open (O_RDWR
| $O_BINARY)) {
725 $self->set_error ('could not open to read/write summary file '.$summary -> filename
);
728 $status = $gosub -> (
733 unless ($summary -> close) {
735 $self->set_error('could not close summary file '.$summary -> filename
);
745 # keep 'require' happy
751 ### end of Posting::Cache ######################################################
patrick-canterino.de