################################################################################### # # DBIx::Recordset - Copyright (c) 1997-2000 Gerald Richter / ECOS # # You may distribute under the terms of either the GNU General Public # License or the Artistic License, as specified in the Perl README file. # # THIS IS BETA SOFTWARE! # # THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED # WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. # # $Id: FileSeq.pm,v 1.4 2000/06/26 05:16:18 richter Exp $ # ################################################################################### package DBIx::Recordset::FileSeq ; use strict 'vars' ; use Cwd ; ## ---------------------------------------------------------------------------- ## ## new ## ## creates a new DBIx::Recordset::FileSeq object. ## ## $dir = Directory which holds the sequences ## sub new { my ($class, $dummy, $dir, $min, $max) = @_ ; mkdir $dir, 0755 or die "Cannot create $dir ($!)" if (!-e $dir) ; die "$dir is not a directory" if (!-d $dir) ; my $self = { '*Debug' => $DBIx::Recordset::Debug, '*Dir' => Cwd::abs_path ($dir), '*DefaultMin' => $min || 1, '*DefaultMax' => $max || '', } ; bless ($self, $class) ; $self -> ReadCounter ; return $self ; } ## ---------------------------------------------------------------------------- ## ## ReadCounter ## ## read current counters form filesystem ## ## sub ReadCounter { my $self = shift ; my %counter ; my %max ; opendir DH, $self -> {'*Dir'} or die "Cannot open directory $self->{'*Dir'} ($!)" ; while ($_ = readdir DH) { if (/seq\.(.*?)\.(\d*?)\.(\d+)$/) { $counter{$1}=$3 ; $max{$1}=$2 ; } } $self -> {'*Counter'} = \%counter ; $self -> {'*Max'} = \%max ; } ## ---------------------------------------------------------------------------- ## ## NextVal ## ## get next value from counter ## ## in $name = counter name ## sub NextVal { my ($self, $name) = @_ ; my $dir = $self -> {'*Dir'} ; my $lastcnt ; local $^W = 0 ; while (1) { my $cnt = $self -> {'*Counter'}{$name} ; my $max = $self -> {'*Max'}{$name} ; if (!defined ($cnt)) { $cnt = $self->{'*DefaultMin'} ; $max = $self->{'*DefaultMax'} ; open FH, ">$dir/seq.$name.$max.$cnt" or die "Cannot create seq.$name..1 ($!)" ; close FH ; } my $cnt1 = $cnt + 1 ; die "Max count reached for Sequence $name" if ($max ne '' && $cnt1 > $max) ; if (rename ("$dir/seq.$name.$max.$cnt", "$dir/seq.$name.$max.$cnt1")) { $self -> {'*Counter'}{$name} = $cnt1 ; return $cnt ; } my $lastcnt = $cnt ; $self -> ReadCounter ; die "Problems updating Sequence $name (File $dir/seq.$name.$max.$cnt)" if ($lastcnt == $self -> {'*Counter'}{$name} ) ; } } 1; __END__ =pod =head1 NAME DBIx::Recordset::FileSeq - Sequence generator in Filesystem =head1 SYNOPSIS use DBIx::Recordset::FileSeq ; $self = DBIx::Recordset::FileSeq (undef, '/tmp/seq', $min, $max) ; $val1 = $self -> NextVal ('foo') ; $val2 = $self -> NextVal ('foo') ; $val3 = $self -> NextVal ('bar') ; =head1 DESCRIPTION DBIx::Recordset::FileSeq generates unique numbers. State is kept in the filesystem. With the new constructor you sepcify the directory where the state is kept. (First parameter is a dummy values, that will receive the database handle from DBIx::Recordset, but you don't need it when you use it without DBIx::Recordset). Optionaly you can give a min and a max values, which will be used for new sequences. With B you can get the next value for the sequence of the given name. The state if kept by haveing a file with the name seq... Each time the sequnce value increments the file is renamed. If the if a numeric value the new value is checked against and NextVal dies if the sequnce value increment above max. =head1 AUTHOR G.Richter (richter@dev.ecos.de) =head1 SEE ALSO =item DBIx::Recordset =cut