/[fuse_dbi]/trunk/DBI.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

Diff of /trunk/DBI.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 18 by dpavlin, Sun Sep 5 16:59:41 2004 UTC revision 24 by dpavlin, Fri Oct 8 20:07:12 2004 UTC
# Line 10  use POSIX qw(ENOENT EISDIR EINVAL ENOSYS Line 10  use POSIX qw(ENOENT EISDIR EINVAL ENOSYS
10  use Fuse;  use Fuse;
11  use DBI;  use DBI;
12  use Carp;  use Carp;
 use Proc::Simple;  
13  use Data::Dumper;  use Data::Dumper;
14    
15    
16  our $VERSION = '0.02';  our $VERSION = '0.03';
17    
18  =head1 NAME  =head1 NAME
19    
# Line 25  Fuse::DBI - mount your database as files Line 24  Fuse::DBI - mount your database as files
24    use Fuse::DBI;    use Fuse::DBI;
25    Fuse::DBI->mount( ... );    Fuse::DBI->mount( ... );
26    
27  See L<run> below for examples how to set parametars.  See C<run> below for examples how to set parametars.
28    
29  =head1 DESCRIPTION  =head1 DESCRIPTION
30    
31  This module will use L<Fuse> module, part of C<FUSE (Filesystem in USErspace)>  This module will use C<Fuse> module, part of C<FUSE (Filesystem in USErspace)>
32  available at L<http://sourceforge.net/projects/avf> to mount  available at L<http://sourceforge.net/projects/avf> to mount
33  your database as file system.  your database as file system.
34    
# Line 48  It's actually opposite of Oracle's inten Line 47  It's actually opposite of Oracle's inten
47  Mount your database as filesystem.  Mount your database as filesystem.
48    
49    my $mnt = Fuse::DBI->mount({    my $mnt = Fuse::DBI->mount({
50          filenames => 'select name from filenamefilenames,          filenames => 'select name from files_table as filenames',
51          read => 'sql read',          read => 'sql read',
52          update => 'sql update',          update => 'sql update',
53          dsn => 'DBI:Pg:dbname=webgui',          dsn => 'DBI:Pg:dbname=webgui',
# Line 63  my $sth; Line 62  my $sth;
62  my $ctime_start;  my $ctime_start;
63    
64  sub read_filenames;  sub read_filenames;
65    sub fuse_module_loaded;
66    
67    # evil, evil way to solve this. It makes this module non-reentrant. But, since
68    # fuse calls another copy of this script for each mount anyway, this shouldn't
69    # be a problem.
70    my $fuse_self;
71    
72  sub mount {  sub mount {
73          my $class = shift;          my $class = shift;
# Line 77  sub mount { Line 82  sub mount {
82          carp "mount needs 'mount' as mountpoint" unless ($arg->{'mount'});          carp "mount needs 'mount' as mountpoint" unless ($arg->{'mount'});
83    
84          # save (some) arguments in self          # save (some) arguments in self
85          $self->{$_} = $arg->{$_} foreach (qw(mount));          foreach (qw(mount invalidate)) {
86                    $self->{$_} = $arg->{$_};
87                    $fuse_self->{$_} = $arg->{$_};
88            }
89    
90          foreach (qw(filenames read update)) {          foreach (qw(filenames read update)) {
91                  carp "mount needs '$_' SQL" unless ($arg->{$_});                  carp "mount needs '$_' SQL" unless ($arg->{$_});
92          }          }
93    
94          $dbh = DBI->connect($arg->{'dsn'},$arg->{'user'},$arg->{'password'}, { AutoCommit => 0 }) || die $DBI::errstr;          $ctime_start = time();
95    
96            my $pid;
97            if ($arg->{'fork'}) {
98                    $pid = fork();
99                    die "fork() failed: $!" unless defined $pid;
100                    # child will return to caller
101                    if ($pid) {
102                            return $self;
103                    }
104            }
105    
106          print "start transaction\n";          $dbh = DBI->connect($arg->{'dsn'},$arg->{'user'},$arg->{'password'}, {AutoCommit => 0, RaiseError => 1}) || die $DBI::errstr;
         $dbh->begin_work || die $dbh->errstr;  
107    
108          $sth->{filenames} = $dbh->prepare($arg->{'filenames'}) || die $dbh->errstr();          $sth->{filenames} = $dbh->prepare($arg->{'filenames'}) || die $dbh->errstr();
109    
110          $sth->{'read'} = $dbh->prepare($arg->{'read'}) || die $dbh->errstr();          $sth->{'read'} = $dbh->prepare($arg->{'read'}) || die $dbh->errstr();
111          $sth->{'update'} = $dbh->prepare($arg->{'update'}) || die $dbh->errstr();          $sth->{'update'} = $dbh->prepare($arg->{'update'}) || die $dbh->errstr();
112    
113          $ctime_start = time();          $self->read_filenames;
   
         read_filenames;  
114    
115          $self->{'proc'} = Proc::Simple->new();          Fuse::main(
116          $self->{'proc'}->kill_on_destroy(1);                  mountpoint=>$arg->{'mount'},
117                    getattr=>\&e_getattr,
118                    getdir=>\&e_getdir,
119                    open=>\&e_open,
120                    statfs=>\&e_statfs,
121                    read=>\&e_read,
122                    write=>\&e_write,
123                    utime=>\&e_utime,
124                    truncate=>\&e_truncate,
125                    unlink=>\&e_unlink,
126                    debug=>0,
127            );
128    
129          $self->{'proc'}->start( sub {          exit(0) if ($arg->{'fork'});
                 Fuse::main(  
                         mountpoint=>$arg->{'mount'},  
                         getattr=>\&e_getattr,  
                         getdir=>\&e_getdir,  
                         open=>\&e_open,  
                         statfs=>\&e_statfs,  
                         read=>\&e_read,  
                         write=>\&e_write,  
                         utime=>\&e_utime,  
                         truncate=>\&e_truncate,  
                         debug=>0,  
                 );  
         } );  
130    
131          confess "Fuse::main failed" if (! $self->{'proc'}->poll);          return 1;
132    
         $self ? return $self : return undef;  
133  };  };
134    
135  =head2 umount  =head2 umount
# Line 134  database to filesystem. Line 146  database to filesystem.
146  sub umount {  sub umount {
147          my $self = shift;          my $self = shift;
148    
         confess "no process running?" unless ($self->{'proc'});  
   
149          system "fusermount -u ".$self->{'mount'} || croak "umount error: $!";          system "fusermount -u ".$self->{'mount'} || croak "umount error: $!";
150    
151          if ($self->{'proc'}->poll) {          return 1;
152                  $self->{'proc'}->kill;  }
153                  return 1 if (! $self->{'proc'}->poll);  
154          } else {  #$SIG{'INT'} = sub {
155    #       print STDERR "umount called by SIG INT\n";
156    #       umount;
157    #};
158    
159    sub DESTROY {
160            my $self = shift;
161            print STDERR "umount called by DESTROY\n";
162            $self->umount;
163    }
164    
165    =head2 fuse_module_loaded
166    
167    Checks if C<fuse> module is loaded in kernel.
168    
169      die "no fuse module loaded in kernel"
170            unless (Fuse::DBI::fuse_module_loaded);
171    
172    This function in called by L<mount>, but might be useful alone also.
173    
174    =cut
175    
176    sub fuse_module_loaded {
177            my $lsmod = `lsmod`;
178            die "can't start lsmod: $!" unless ($lsmod);
179            if ($lsmod =~ m/fuse/s) {
180                  return 1;                  return 1;
181            } else {
182                    return 0;
183          }          }
184  }  }
185    
   
186  my %files;  my %files;
187  my %dirs;  my %dirs;
188    
# Line 252  sub e_getdir { Line 288  sub e_getdir {
288          return (keys %out),0;          return (keys %out),0;
289  }  }
290    
291    sub read_content {
292            my ($file,$id) = @_;
293    
294            die "read_content needs file and id" unless ($file && $id);
295    
296            $sth->{'read'}->execute($id) || die $sth->{'read'}->errstr;
297            $files{$file}{cont} = $sth->{'read'}->fetchrow_array;
298            print "file '$file' content [",length($files{$file}{cont})," bytes] read in cache\n";
299    }
300    
301    
302  sub e_open {  sub e_open {
303          # VFS sanity check; it keeps all the necessary state, not much to do here.          # VFS sanity check; it keeps all the necessary state, not much to do here.
304          my $file = filename_fixup(shift);          my $file = filename_fixup(shift);
# Line 260  sub e_open { Line 307  sub e_open {
307          return -ENOENT() unless exists($files{$file});          return -ENOENT() unless exists($files{$file});
308          return -EISDIR() unless exists($files{$file}{id});          return -EISDIR() unless exists($files{$file}{id});
309    
310          if (!exists($files{$file}{cont})) {          read_content($file,$files{$file}{id}) unless exists($files{$file}{cont});
311                  $sth->{'read'}->execute($files{$file}{id}) || die $sth->{'read'}->errstr;  
                 $files{$file}{cont} = $sth->{'read'}->fetchrow_array;  
                 print "file '$file' content read in cache\n";  
         }  
312          print "open '$file' ",length($files{$file}{cont})," bytes\n";          print "open '$file' ",length($files{$file}{cont})," bytes\n";
313          return 0;          return 0;
314  }  }
# Line 285  sub e_read { Line 329  sub e_read {
329          return -EINVAL() if ($off > $len);          return -EINVAL() if ($off > $len);
330          return 0 if ($off == $len);          return 0 if ($off == $len);
331    
332          $buf_len = $buf_len-$off if ($off+$buf_len > $len);          $buf_len = $len-$off if ($len - $off < $buf_len);
333    
334          return substr($files{$file}{cont},$off,$buf_len);          return substr($files{$file}{cont},$off,$buf_len);
335  }  }
# Line 298  sub clear_cont { Line 342  sub clear_cont {
342                  delete $files{$f}{cont};                  delete $files{$f}{cont};
343          }          }
344          print "begin new transaction\n";          print "begin new transaction\n";
345          $dbh->begin_work || die $dbh->errstr;          #$dbh->begin_work || die $dbh->errstr;
346  }  }
347    
348    
# Line 307  sub update_db { Line 351  sub update_db {
351    
352          $files{$file}{ctime} = time();          $files{$file}{ctime} = time();
353    
354          if (!$sth->{'update'}->execute($files{$file}{cont},$files{$file}{id})) {          my ($cont,$id) = (
355                    $files{$file}{cont},
356                    $files{$file}{id}
357            );
358    
359            if (!$sth->{'update'}->execute($cont,$id)) {
360                  print "update problem: ",$sth->{'update'}->errstr;                  print "update problem: ",$sth->{'update'}->errstr;
361                  clear_cont;                  clear_cont;
362                  return 0;                  return 0;
# Line 318  sub update_db { Line 367  sub update_db {
367                          return 0;                          return 0;
368                  }                  }
369                  print "updated '$file' [",$files{$file}{id},"]\n";                  print "updated '$file' [",$files{$file}{id},"]\n";
370    
371                    $fuse_self->{'invalidate'}->() if (ref $fuse_self->{'invalidate'});
372          }          }
373          return 1;          return 1;
374  }  }
# Line 337  sub e_write { Line 388  sub e_write {
388    
389          $files{$file}{cont} .= substr($cont,0,$off) if ($off > 0);          $files{$file}{cont} .= substr($cont,0,$off) if ($off > 0);
390          $files{$file}{cont} .= $buffer;          $files{$file}{cont} .= $buffer;
391          $files{$file}{cont} .= substr($cont,-($off+length($buffer))) if ($off+length($buffer) > $len);          $files{$file}{cont} .= substr($cont,$off+length($buffer),$len-$off-length($buffer)) if ($off+length($buffer) < $len);
392    
393          $files{$file}{size} = length($files{$file}{cont});          $files{$file}{size} = length($files{$file}{cont});
394    
# Line 374  sub e_utime { Line 425  sub e_utime {
425    
426  sub e_statfs { return 255, 1, 1, 1, 1, 2 }  sub e_statfs { return 255, 1, 1, 1, 1, 2 }
427    
428    sub e_unlink {
429            my $file = filename_fixup(shift);
430    
431            return -ENOENT() unless exists($files{$file});
432    
433            print "unlink '$file' will invalidate cache\n";
434    
435            read_content($file,$files{$file}{id});
436    
437            return 0;
438    }
439  1;  1;
440  __END__  __END__
441    

Legend:
Removed from v.18  
changed lines
  Added in v.24

  ViewVC Help
Powered by ViewVC 1.1.26