/[wait]/trunk/lib/WAIT/Database.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/lib/WAIT/Database.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (hide annotations)
Fri Apr 28 15:40:52 2000 UTC (24 years ago) by ulpfr
Original Path: cvs-head/lib/WAIT/Database.pm
File size: 7909 byte(s)
Initial revision

1 ulpfr 10 # -*- Mode: Perl -*-
2     # Database --
3     # ITIID : $ITI$ $Header $__Header$
4     # Author : Ulrich Pfeifer
5     # Created On : Thu Aug 8 09:44:13 1996
6     # Last Modified By: Ulrich Pfeifer
7     # Last Modified On: Sun Nov 22 18:44:48 1998
8     # Language : CPerl
9     # Update Count : 249
10     # Status : Unknown, Use with caution!
11     #
12     # Copyright (c) 1996-1997, Ulrich Pfeifer
13     #
14    
15     =head1 NAME
16    
17     WAIT::Database - Module fo maintaining WAIT databases
18    
19     =head1 SYNOPSIS
20    
21     require WAIT::Database;
22    
23     =head1 DESCRIPTION
24    
25     The modules handles creating, opening, and deleting of databases and
26     tables.
27    
28     =cut
29    
30     package WAIT::Database;
31    
32     use strict;
33     use FileHandle ();
34     use File::Path qw(rmtree);
35     use WAIT::Table ();
36     use Fcntl;
37     use Carp;
38     my ($HAVE_DATA_DUMPER, $HAVE_STORABLE);
39    
40     BEGIN {
41     eval { require Data::Dumper };
42     $HAVE_DATA_DUMPER = 1 if $@ eq '';
43     eval { require Storable };
44     $HAVE_STORABLE = 1 if $@ eq '';
45     $HAVE_DATA_DUMPER || $HAVE_STORABLE ||
46     die "Could not find Data::Dumper nor Storable";
47     $Storable::forgive_me = 1;
48     }
49    
50    
51     =head2 C<$db = create WAIT::Database name =>E<gt> I<name> C<directory =E<gt>> I<dir>C<;>
52    
53     =over 10
54    
55     =item B<name> I<name>
56    
57     mandatory
58    
59     =item B<directory> I<directory>
60    
61     Directory which should contain the database (defaults to the current
62     directory).
63    
64     =item B<uniqueatt> I<true>
65    
66     If given, the database will require unique attributes over all tables.
67    
68     The function will return undef and set C<$@> on failure.
69    
70     =cut
71    
72     sub create {
73     my $type = shift;
74     my %parm = @_;
75     my $self = {};
76     my $dir = $parm{directory} || '.';
77     my $name = $parm{name} or croak "No name specified";
78    
79     croak "Directory '$dir' does not exits: $!" unless -d $dir;
80     croak "Directory '$name' already exists" if -d "$dir/$name";
81     mkdir "$dir/$name", 0775 or croak "Could not mkdir '$dir/$name': $!";
82    
83     $self->{name} = $name;
84     $self->{file} = "$dir/$name";
85     $self->{uniqueatt} = $parm{uniqueatt};
86     $self->{mode} = O_CREAT;
87     bless $self => ref($type) || $type;
88     }
89    
90    
91     =head2 C<$db = open WAIT::Database name =E<gt>> I<name> C<directory =E<gt>> I<dir>C<;>
92    
93     Open an existing database I<foo> in directory I<bar>.
94    
95     =cut
96    
97     sub open {
98     my $type = shift;
99     my %parm = @_;
100     my $dir = $parm{directory} || '.';
101     my $name = $parm{name} or croak "No name specified";
102     my $catalog = "$dir/$name/catalog";
103     my $meta = "$dir/$name/meta";
104     my $self;
105    
106     if ($HAVE_STORABLE and -e $catalog
107     and (!-e $meta or -M $meta >= -M $catalog)) {
108     $self = Storable::retrieve($catalog);
109     } else {
110     return undef unless -f $meta;
111    
112     $self = do $meta;
113     unless (defined $self) {
114     warn "\ado '$meta' did not work. Mysterious! Reverting to eval `cat $meta`\n";
115     sleep(4);
116     $self = eval `cat $meta`;
117     }
118     }
119    
120     return $self unless defined $self;
121     $self->{mode} = (exists $parm{mode})?$parm{mode}:(O_CREAT | O_RDWR);
122     $self;
123     }
124    
125    
126     =head2 C<$db-E<gt>dispose;>
127    
128     Dispose a database. Remove all associated files. This may fail if the
129     database or one of its tables is still open. Failure will be indicated
130     by a false return value.
131    
132     =cut
133    
134     sub dispose {
135     my $dir;
136    
137     if (ref $_[0]) { # called with instance
138     croak "Database readonly" unless $_[0]->{mode} & (O_CREAT | O_RDWR);
139     $dir = $_[0]->{file};
140     $_[0]->close;
141     } else {
142     my $type = shift;
143     my %parm = @_;
144     my $base = $parm{directory} || '.';
145     my $name = $parm{name} || croak "No name specified";
146     $dir = "$base/$name";
147     }
148     croak "No such database '$dir'" unless -e "$dir/meta";
149    
150     rmtree($dir, 0, 1);
151     }
152    
153    
154     =head2 C<$db-E<gt>close;>
155    
156     Close a database saving all meta data after closing all associated tables.
157    
158     =cut
159    
160     sub close {
161     my $self = $_[0];
162     my $file = $self->{file};
163     my $table;
164     my $did_save;
165    
166     for $table (values %{$self->{tables}}) {
167     $table->close if ref($table);
168     }
169     return 1 unless $self->{mode} & (O_RDWR | O_CREAT);
170    
171     if ($HAVE_DATA_DUMPER) {
172     my $fh = new FileHandle "> $file/meta";
173     if ($fh) {
174     my $dumper = new Data::Dumper [$self],['self'];
175     $fh->print('my ');
176     $fh->print($dumper->Dumpxs);
177     $fh->close;
178     $did_save = 1;
179     } else {
180     croak "Could not open '$file/meta' for writing: $!";
181     return unless $HAVE_STORABLE;
182     }
183     }
184    
185     if ($HAVE_STORABLE) {
186     if (!eval {Storable::store($self, "$file/catalog")}) {
187     fail ("Could not open '$file/catalog' for writing: $!");
188     return unless $did_save;
189     } else {
190     $did_save++;
191     }
192     }
193     undef $_[0];
194     $did_save;
195     }
196    
197    
198     =head2 C<$db-E<gt>create_table name =E<gt>> I<tname> ... C<;>
199    
200     Create a new table with name I<tname>. All paraeters are passed to
201     C<WAIT::Table::new> together with a filename to use. The function
202     returns a table handle (C<WAIT::Table::Handle>).
203    
204     =cut
205    
206     sub create_table {
207     my $self = shift;
208     my %parm = @_;
209     my $name = $parm{name} || return fail("No name specified");
210     my $file = $self->{file};
211    
212     croak "Database readonly" unless $self->{mode} & (O_CREAT | O_RDWR);
213    
214     if (defined $self->{tables}->{$name}) {
215     die "Table '$name' already exists";
216     }
217    
218     if ($self->{uniqueatt}) {
219     for (@{$parm{attr}}) { # attribute names must be uniqe
220     if ($self->{attr}->{$_}) {
221     return fail ("Attribute '$_' is not unique")
222     }
223     }
224     }
225     $self->{tables}->{$name} = WAIT::Table->new(file => "$file/$name",
226     database => $self,
227     %parm);
228     unless (defined $self->{tables}->{$name}) {# fail gracefully
229     delete $self->{tables}->{$name};
230     return undef;
231     }
232    
233     if ($self->{uniqueatt}) {
234     # remember table name for each attribute
235     map ($self->{attr}->{$_} = $name, @{$parm{attr}});
236     }
237     WAIT::Table::Handle->new($self, $name);
238     }
239    
240    
241     =head2 <$db-E<gt>table name =E<gt>> I<tname>C<;>
242    
243     Open a new table with name I<tname>. The function
244     returns a table handle (C<WAIT::Table::Handle).
245    
246     =cut
247    
248     sub sync {
249     my $self = shift;
250    
251     for (values %{$self->{tables}}) {
252     $_->sync;
253     }
254     }
255    
256     sub table {
257     my $self = shift;
258     my %parm = @_;
259     my $name = $parm{name} or croak "No name specified";
260    
261     if (defined $self->{tables}->{$name}) {
262     if (exists $parm{mode}) {
263     $self->{tables}->{$name}->{mode} = $parm{mode};
264     } else {
265     $self->{tables}->{$name}->{mode} = $self->{mode};
266     }
267     WAIT::Table::Handle->new($self,$name);
268     } else {
269     croak "No such table '$name'";
270     }
271     }
272    
273    
274     =head2 C<$db-E<gt>drop name =E<gt>> I<tname>C<;>
275    
276     Drop the table named I<tname>. The table should be closed before
277     calling B<drop>.
278    
279     =cut
280    
281     sub drop_table {
282     my $self = shift;
283     my %parm = @_;
284     my $name = $parm{name} or croak "No name specified";
285    
286     croak "Database readonly" unless $self->{mode} & (O_CREAT | O_RDWR);
287     if (!defined $self->{tables}->{$name}) {
288     croak "Table '$name' does not exist";
289     }
290     $self->{tables}->{$name}->drop;
291    
292     if ($self->{uniqueatt}) {
293     # recycle attribute names
294     for (keys %{$self->{attr}}) {
295     delete $self->{attr}->{$_} if $self->{attr}->{$_} eq $name;
296     }
297     }
298     undef $self->{tables}->{$name}; # Call WAIT::Table::DESTROY here;
299     1;
300     }
301    
302    
303     package WAIT::Table::Handle;
304    
305     use Carp;
306    
307    
308     sub new {
309     my ($type, $database, $name) = @_;
310    
311     bless [$database, $name], $type;
312     }
313    
314    
315     sub AUTOLOAD {
316     my $func = $WAIT::Table::Handle::AUTOLOAD; $func =~ s/.*:://;
317     my $self = $_[0];
318     my ($database, $name) = @{$self};
319     if (defined $database->{tables}->{$name}) {
320     if ($func eq 'drop') {
321     $database->drop_table(name => $name);
322     undef $_[0];
323     1;
324     } elsif ($func ne 'DESTROY') {
325     shift @_;
326     if ($func eq 'open') {
327     $database->{tables}->{$name}->$func(mode => $database->{mode}, @_);
328     } else {
329     $database->{tables}->{$name}->$func(@_);
330     }
331     }
332     } else {
333     return fail("Invalid handle\n");
334     }
335     }
336    
337    
338     1;
339    
340    
341     =head1 AUTHOR
342    
343     Ulrich Pfeifer E<lt>F<pfeifer@ls6.informatik.uni-dortmund.de>E<gt>
344    
345     =cut
346    
347    

Properties

Name Value
cvs2svn:cvs-rev 1.1

  ViewVC Help
Powered by ViewVC 1.1.26