#-*- perl -*-
#
# Copyright (C) 2003,2004,2005,2006 Ken'ichi Fukamachi
# All rights reserved. This program is free software; you can
# redistribute it and/or modify it under the same terms as Perl itself.
#
# $FML: Sequence.pm,v 1.19 2006/10/14 00:43:46 fukachan Exp $
#
package FML::Article::Sequence;
use strict;
use vars qw(@ISA @EXPORT @EXPORT_OK $AUTOLOAD);
use Carp;
# XXX_LOCK_CHANNEL: article_sequence
my $lock_channel = 'article_sequence';
=head1 NAME
FML::Article::Sequence - article sequence manipulation.
=head1 SYNOPSIS
=head1 DESCRIPTION
=head1 METHODS
=head2 increment_id()
increment the sequence number of this article C<$self> and
save it to C<$sequence_file>.
=cut
# Descriptions: determine the next article id (sequence number).
# Arguments: OBJ($self)
# Side Effects: save and update the current article sequence number.
# Return Value: NUM(sequence identifier) or 0(failed)
sub increment_id
{
my ($self) = @_;
my $curproc = $self->{ _curproc };
my $config = $curproc->config();
my $pcb = $curproc->pcb();
my $seq_file = $config->{ article_sequence_file };
my $error = 0;
$curproc->lock($lock_channel);
# XXX-TODO: we should enhance sequence_file to all IO::Adapter classes.
use IO::Adapter;
my $io = new IO::Adapter "file:$seq_file";
my $id = $io->sequence_increment();
if ($io->error()) {
my $err = $io->error();
$curproc->logerror( "article_id: $err" );
$error = 1;
}
$curproc->unlock($lock_channel);
unless ($error) {
# XXX-TODO: use $curproc->article_set_id().
# save $id in pcb (process control block) and return $id
$pcb->set('article', 'id', $id);
return $id;
}
else {
return 0;
}
}
=head2 id()
return the current article sequence number.
=cut
# Descriptions: return the article id (sequence number).
# Arguments: OBJ($self)
# Side Effects: none
# Return Value: NUM(sequence number)
sub id
{
my ($self) = @_;
my $curproc = $self->{ _curproc };
my $config = $curproc->config();
my $pcb = $curproc->pcb();
# XXX-TODO: use $curproc->article_get_id().
my $n = $pcb->get('article', 'id');
# within Process::Distribute
if ($n) {
return $n;
}
# processes not Process::Distribute
else {
my $seq_file = $config->{ article_sequence_file };
my $map = sprintf("file:%s", $seq_file);
return( $self->get_number_from_map($map) || 0 );
}
}
# Descriptions: get number from map.
# Arguments: OBJ($self) STR($map)
# Side Effects: none
# Return Value: NUM
sub get_number_from_map
{
my ($self, $map) = @_;
my $n = 0;
use IO::Adapter;
my $io = new IO::Adapter $map;
if (defined $io) {
$io->open();
$n = $io->getline() || 0;
$n =~ s/^\s*//;
$n =~ s/\s*$//;
if ($n =~ /^\d+$/o) {
return $n;
}
else {
return 0;
}
}
else {
warn("cannot open map=$map");
}
return 0;
}
#
# XXX-TODO: speculate_max_id([$spool_dir]) NOT USED ?
#
=head2 speculate_max_id([$spool_dir])
scan the spool_dir and get the max number among files in it. It must
be the max (latest) article number in its folder.
=cut
# Descriptions: scan the spool_dir and get max number among files in it.
# It must be the max (latest) article number in its folder.
# Arguments: OBJ($curproc) STR($spool_dir)
# Side Effects: none
# Return Value: NUM(sequence number) or undef
sub speculate_max_id
{
my ($curproc, $spool_dir) = @_;
my $config = $curproc->config();
my $use_subdir = $config->{ spool_type } eq 'subdir' ? 1 : 0;
unless (defined $spool_dir) {
$spool_dir = $config->{ spool_dir };
}
$curproc->logdebug("max_id: scan $spool_dir subdir=$use_subdir");
if ($use_subdir) {
use DirHandle;
my $dh = new DirHandle $spool_dir;
if (defined $dh) {
my $fn = ''; # file name
my $subdir = '';
my $max_subdir = 0;
ENTRY:
while (defined($fn = $dh->read)) {
next ENTRY unless $fn =~ /^\d+$/o;
use File::Spec;
$subdir = File::Spec->catfile($spool_dir, $fn);
if (-d $subdir) {
my $max_subdir = $max_subdir > $fn ? $max_subdir : $fn;
}
}
$dh->close();
# XXX-TODO wrong? to speculate max_id in subdir spool?
$subdir = File::Spec->catfile($spool_dir, $max_subdir);
$curproc->logdebug("max_id: scan $subdir");
$curproc->speculate_max_id($subdir);
}
}
use DirHandle;
my $dh = new DirHandle $spool_dir;
if (defined $dh) {
my $max = 0;
my $fn = ''; # file name
ENTRY:
while (defined($fn = $dh->read)) {
next ENTRY unless $fn =~ /^\d+$/o;
$max = $max < $fn ? $fn : $max;
}
$dh->close();
return( $max > 0 ? $max : undef );
}
return undef;
}
=head1 CODING STYLE
See C on fml coding style guide.
=head1 AUTHOR
Ken'ichi Fukamachi
=head1 COPYRIGHT
Copyright (C) 2003,2004,2005,2006 Ken'ichi Fukamachi
All rights reserved. This program is free software; you can
redistribute it and/or modify it under the same terms as Perl itself.
=head1 HISTORY
FML::Article::Sequence appeared in fml8 mailing list driver package.
See C for more details.
=cut
1;