File Coverage

blib/lib/Purple/DB_File.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Purple::DB_File;
2              
3 1     1   5 use strict;
  1         3  
  1         38  
4 1     1   6 use warnings;
  1         2  
  1         28  
5              
6 1     1   941 use IO::File;
  1         10858  
  1         172  
7 1     1   1011 use DB_File;
  0            
  0            
8             use Purple::Sequence;
9              
10             my $ORIGIN = '0';
11             my $LOCK_WAIT = 1;
12             my $LOCK_TRIES = 5;
13              
14             my $DEFAULT_SEQUENCE = 'sequence';
15             my $DEFAULT_SEQUENCE_INDEX = 'sequence.index';
16             my $DEFAULT_SEQUENCE_RINDEX = 'sequence.rindex';
17              
18             sub _New {
19             my $class = shift;
20             my %p = @_;
21             my $self;
22              
23             my $datadir = $p{store};
24             $datadir =~ s{$}{/} if $datadir;
25              
26             $self->{datafile} = $datadir . $DEFAULT_SEQUENCE;
27             $self->{indexfile} = $datadir . $DEFAULT_SEQUENCE_INDEX;
28             $self->{revindexfile} = $datadir . $DEFAULT_SEQUENCE_RINDEX;
29              
30             bless($self, $class);
31             return $self;
32             }
33              
34             sub getNext {
35             my ($self, $url) = @_;
36              
37             $self->_lockFile();
38             my $value = $self->_retrieveNextValue();
39             $self->_unlockFile();
40             # update the NID to URL index
41             if ($url) {
42             $self->_updateIndex($value, $url);
43             }
44              
45             return $value;
46             }
47              
48             sub getURL {
49             my ($self, $nid) = @_;
50             my %index;
51             my $url;
52              
53             $self->_tieIndex(\%index);
54             $url = $index{$nid};
55              
56             untie %index;
57              
58             return $url;
59             }
60              
61             sub updateURL {
62             my ( $self, $url, @nids ) = @_;
63             my ( %index, %revidx, %oldnids );
64              
65             $self->_tieIndex( \%index );
66             $self->_tieRevIndex( \%revidx );
67             my @stored_nids = split( " ", $revidx{$url} );
68             foreach my $oldnid (@stored_nids) {
69             $oldnids{$oldnid} = 1;
70             }
71             my @newnids = ();
72             for my $new_nid (@nids) {
73             delete $oldnids{$new_nid};
74             $index{$new_nid} = $url;
75             push @newnids, $new_nid;
76             }
77             for my $old_nid ( keys %oldnids ) {
78             delete $index{$old_nid};
79              
80             #print STDERR "Delete($url) $old_nid\n";
81             }
82             my $new_info = join ( " ", @newnids, keys(%oldnids) );
83             $revidx{$url} = $new_info;
84              
85             untie %revidx;
86             untie %index;
87             }
88              
89             sub getNIDs {
90             my ($self, $url) = @_;
91              
92             my %revidx;
93             $self->_tieRevIndex(\%revidx);
94              
95             my @nids = split(" ", $revidx{$url});
96             untie %revidx;
97             return @nids;
98             }
99              
100             # XXX this is incomplete for this implementation
101             sub deleteNIDs {
102             my ($self, @nids) = @_;
103             my %index;
104             $self->_tieIndex(\%index);
105              
106             foreach my $nid (@nids) {
107             delete $index{$nid};
108             }
109              
110             untie %index;
111             }
112              
113             sub _tieIndex {
114             my $self = shift;
115             my $index = shift;
116             my $file = $self->{indexfile};
117              
118             ( (-f $file) and tie(%$index, 'DB_File', $file, O_RDWR, 0666, $DB_HASH) )
119             or tie(%$index, 'DB_File', $file, O_RDWR|O_CREAT, 0666, $DB_HASH)
120             or die "unable to tie " . $file . ' ' . $!;
121             }
122              
123             sub _tieRevIndex {
124             my $self = shift;
125             my $index = shift;
126             my $file = $self->{revindexfile};
127              
128             ( (-f $file) and tie(%$index, 'DB_File', $file, O_RDWR, 0666, $DB_HASH) )
129             or tie(%$index, 'DB_File', $file, O_RDWR|O_CREAT, 0666, $DB_HASH)
130             or die "unable to tie " . $file . ' ' . $!;
131             }
132              
133             sub _updateIndex {
134             my $self = shift;
135             my $value = shift;
136             my $url = shift;
137             my %index;
138             my %revindex;
139              
140             $self->_tieIndex(\%index);
141             $self->_tieRevIndex(\%revindex);
142             $index{$value} = $url;
143             my $new_info = '';
144             $new_info = $revindex{$url} if $revindex{$url};
145              
146             $revindex{$url} = join(" ", split(" ", $new_info), $value);
147             untie %index;
148             }
149              
150              
151             sub _lockFile {
152             my $self = shift;
153             # use simple directory locks for ease
154             my $dir = $self->{datafile} . '.lck';
155             my $tries = 0;
156              
157             # FIXME: copied from UseMod, relies on errno
158             while (mkdir($dir, 0555) == 0) {
159             if ($! != 17) {
160             die "Unable to create locking directory $dir";
161             }
162             $tries++;
163             if ($tries > $LOCK_TRIES) {
164             die "Timeout creating locking directory $dir";
165             }
166             sleep($LOCK_WAIT);
167             }
168             }
169            
170             sub _unlockFile {
171             my $self = shift;
172             my $dir = $self->{datafile} . '.lck';
173             rmdir($dir) or die "Unable to remove locking directory $dir: $!";
174             }
175              
176             sub _getCurrentValue {
177             my $self = shift;
178             my $file = $self->{datafile};
179             my $value;
180              
181             if (-f $file) {
182             my $fh = new IO::File;
183             $fh->open($file) || die "Unable to open $file: $!";
184             $value = $fh->getline();
185             $fh->close;
186             } else {
187             $value = $ORIGIN;
188             }
189              
190             return $value;
191             }
192              
193             sub _retrieveNextValue {
194             my $self = shift;
195              
196             my $newValue
197             = Purple::Sequence::increment_nid( $self->_getCurrentValue() );
198             $self->_setValue($newValue);
199             return $newValue;
200             }
201              
202             sub _setValue {
203             my $self = shift;
204             my $value = shift;
205              
206             my $fh = new IO::File;
207             if ($fh->open($self->{datafile}, 'w')) {
208             print $fh $value;
209             $fh->close;
210             } else {
211             die "unable to write value to " . $self->{datafile} . ": $!";
212             }
213             }
214              
215             # XXX docs are way out of date
216              
217             =head1 NAME
218              
219             Purple::DB_File - DB_File driver for Purple
220              
221             =head1 SYNOPSIS
222              
223             DB_File backend for storing and retrieving Purple nids.
224              
225             # XXX update this for factory stuff
226             use Purple::DB_File;
227              
228             my $p = Purple::DB_File->new('purple.db');
229             my $nid = $p->getNext('http://i.love.purple/');
230             my $url = $p->getURL($nid); # http://i.love.purple/
231              
232             =head1 METHODS
233              
234             =head2 new($db_loc)
235              
236             Initializes NID database at $db_loc, creating it if it does not
237             already exist. Defaults to "purple.db" in the current directory if
238             $db_loc is not specified.
239              
240             =head2 getNext($url)
241              
242             Gets the next available NID, assigning it $url in the database.
243              
244             =head2 getURL($nid)
245              
246             Gets the URL associated with NID $nid.
247              
248             =head2 updateURL($url, @nids)
249              
250             Updates the NIDs in @nids with the URL $url.
251              
252             =head2 getNIDs($url)
253              
254             Gets all NIDs associated with $url.
255              
256             =head2 deleteNIDs(@nids)
257              
258             Deletes all NIDs in @nids.
259              
260             =head1 AUTHORS
261              
262             Chris Dent, Ecdent@burningchrome.comE
263              
264             Eugene Eric Kim, Eeekim@blueoxen.comE
265              
266             Gerry Gleason, Egerry@geraldgleason.comE
267              
268             =head1 BUGS
269              
270             Please report any bugs or feature requests to
271             C, or through the web interface at
272             L.
273             I will be notified, and then you'll automatically be notified of progress on
274             your bug as I make changes.
275              
276             =head1 ACKNOWLEDGEMENTS
277              
278             Based on L, which it attempts to replace.
279              
280             =head1 COPYRIGHT & LICENSE
281              
282             (C) Copyright 2006 Blue Oxen Associates. All rights reserved.
283              
284             This program is free software; you can redistribute it and/or modify it
285             under the same terms as Perl itself.
286              
287             =cut
288              
289             1;