Author: jzucker
Date: Thu Mar  4 21:24:19 2004
New Revision: 188

Modified:
   dbi/trunk/lib/DBD/DBM.pm
   dbi/trunk/lib/DBD/File.pm
Log:
added file locking with flock(), tested on Debian

Modified: dbi/trunk/lib/DBD/DBM.pm
==============================================================================
--- dbi/trunk/lib/DBD/DBM.pm    (original)
+++ dbi/trunk/lib/DBD/DBM.pm    Thu Mar  4 21:24:19 2004
@@ -247,6 +247,7 @@
 package DBD::DBM::Statement;
 ############################
 use base qw( DBD::File::Statement );
+use IO::File;  # for locking only
 use Fcntl;
 
 # you must define open_table;
@@ -261,7 +262,6 @@
 # between global, per-table, and default settings
 #
 sub open_table ($$$$$) {
-    # NEED TO ADD FILE LOCKING
     my($self, $data, $table, $createMode, $lockMode) = @_;
     my $dbh = $data->{Database};
 
@@ -322,6 +322,12 @@
        $tie_type = $dbm_type;
     }
 
+    # open and flock the lockfile, creating it if necessary
+    #
+    my $lock_table = $self->DBD::File::Statement::open_table(
+        $data, "$table.lck", $createMode, $lockMode
+    ) or die "Couldn't open lockfile!\n";
+
     eval { tie(%h, $tie_type, $file, $open_mode, 0666) }
        unless $self->{command} eq 'DROP';
     die "Cannot tie file '$file': $@" if $@;
@@ -350,6 +356,7 @@
         dbm_type       => $dbm_type,
         store_metadata => $store,
         mldbm          => $serializer,
+        lock_fh        => $lock_table->{fh},
        col_nums       => \%col_nums,
        col_names      => $col_names
     };
@@ -438,7 +445,8 @@
     unlink $self->{file}.$ext if -f $self->{file}.$ext;
     unlink $self->{file}.'.dir' if -f $self->{file}.'.dir'
                                and $ext eq '.pag';
-    # put code to delete lockfile here
+    $self->{lock_fh}->close if $self->{lock_fh};
+    unlink $self->{file}.'.lck' if -f $self->{file}.'.lck';
     return 1;
 }
 
@@ -464,26 +472,25 @@
     }
     return (@ary) if wantarray;
     return [EMAIL PROTECTED];
-=pod
+
     # fetch without %each
     #
-    $self->{keys} = [sort keys %{$self->{hash}}] unless $self->{keys};
-    my $key = shift @{$self->{keys}};
-    $key = shift @{$self->{keys}} if $self->{store_metadata}
-                                 and $key
-                                 and $key eq "_metadata \0";
-    return undef unless defined $key;
-    my @ary;
-    $row = $self->{hash}->{$key};
-    if (ref $row eq 'ARRAY') {
-       @ary = ( $key, @{$row} );
-    }
-    else {
-       @ary = ($key,$row);
-    }
-    return (@ary) if wantarray;
-    return [EMAIL PROTECTED];
-=cut
+    # $self->{keys} = [sort keys %{$self->{hash}}] unless $self->{keys};
+    # my $key = shift @{$self->{keys}};
+    # $key = shift @{$self->{keys}} if $self->{store_metadata}
+    #                             and $key
+    #                             and $key eq "_metadata \0";
+    # return undef unless defined $key;
+    # my @ary;
+    # $row = $self->{hash}->{$key};
+    # if (ref $row eq 'ARRAY') {
+    #   @ary = ( $key, @{$row} );
+    # }
+    # else {
+    #    @ary = ($key,$row);
+    # }
+    # return (@ary) if wantarray;
+    # return [EMAIL PROTECTED];
 }
 
 # you must define push_row
@@ -541,8 +548,9 @@
 #
 sub DESTROY ($) {
     my $self=shift;
-    # code to release lock goes here
     untie %{$self->{hash}} if $self->{hash};
+    # release the flock on the lock file
+    $self->{lock_fh}->close if $self->{lock_fh};
 }
 
 # truncate() and seek() must be defined to satisfy DBI::SQL::Nano
@@ -684,6 +692,14 @@
 
 See the L<GOTCHAS AND WARNINGS> for using DROP on tables.
 
+=head2 Table locking and flock()
+
+Table locking is accomplished using a lockfile which has the same name as the table's 
file but with the file extension '.lck'.  This file is created along with the table 
during a CREATE and removed during a DROP.  Every time the table itself is opened, the 
lockfile is flocked().  For SELECT, this is an shared lock.  For all other operations, 
it is an exclusive lock.
+
+Since the locking depends on flock(), it only works on operating systems that support 
flock().  In cases where flock() is not implemented, DBD::DBM will not complain, it 
will simply behave as if the flock() had occurred although no actual locking will 
happen.  Read the documentation for flock() if you need to understand this.
+
+Even on those systems that do support flock(), the locking is only advisory - as is 
allways the case with flock().  This means that if some other program tries to access 
the table while DBD::DBM has the table locked, that other program will *succeed* at 
opening the table.  DBD::DBM's locking only applies to DBD::DBM.
+
 =head2 Specifying the DBM type
 
 Each "flavor" of DBM stores its files in a different format and has different 
capabilities and different limitations.  See L<AnyDBM_File> for a comparison of DBM 
types.
@@ -863,6 +879,8 @@
 
 When using MLDBM, there is a very powerful serializer - it will allow you to store 
Perl code or objects in database columns.  When these get de-serialized, they may be 
evaled - in other words MLDBM (or actually Data::Dumper when used by MLDBM) may take 
the values and try to execute them in Perl.  Obviously, this can present dangers, so 
if you don't know what's in a file, be careful before you access it with MLDBM turned 
on!
 
+See the entire section on L<Table locking and flock()> for gotchas and warnings about 
the use of flock().
+
 =head1 GETTING HELP, MAKING SUGGESTIONS, AND REPORTING BUGS
 
 If you need help installing or using DBD::DBM, please write to the DBI users mailing 
list at [EMAIL PROTECTED] or to the comp.lang.perl.modules newsgroup on usenet.  I'm 
afraid I can't always answer these kinds of questions quickly and there are many on 
the mailing list or in the newsgroup who can.

Modified: dbi/trunk/lib/DBD/File.pm
==============================================================================
--- dbi/trunk/lib/DBD/File.pm   (original)
+++ dbi/trunk/lib/DBD/File.pm   Thu Mar  4 21:24:19 2004
@@ -243,8 +243,6 @@
     } elsif ($attrib eq (lc $attrib)) {
        # Driver private attributes are lower cased
 
-=pod
-
   # I'm not implementing this yet becuase other drivers may be
   # setting f_ and sql_ attrs I don't know about
   # I'll investigate and publicize warnings to DBD authors
@@ -254,15 +252,15 @@
         # not implemented yet
         # my $class = $dbh->FETCH('ImplementorClass');
         #
-        if ( !$dbh->{f_valid_attrs}->{$attrib}
-         and !$dbh->{sql_valid_attrs}->{$attrib}
-         ) {
-           return $dbh->set_err( 1,"Invalid attribute '$attrib'!");
-        }
-        else {
-           $dbh->{$attrib} = $value;
-       }
-=cut
+        # if ( !$dbh->{f_valid_attrs}->{$attrib}
+        # and !$dbh->{sql_valid_attrs}->{$attrib}
+        # ) {
+       #    return $dbh->set_err( 1,"Invalid attribute '$attrib'!");
+        # }
+        # else {
+       #    $dbh->{$attrib} = $value;
+       # }
+
         if ($attrib eq 'f_dir') {
            return $dbh->set_err( 1,"No such directory '$value'!")
                 unless -d $value;

Reply via email to