/[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 11 by dpavlin, Sun Aug 29 18:51:29 2004 UTC revision 21 by dpavlin, Sat Oct 2 15:29:02 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.01';  our $VERSION = '0.03';
17    
18  =head1 NAME  =head1 NAME
19    
# 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  sub mount {  sub mount {
68          my $class = shift;          my $class = shift;
# Line 76  sub mount { Line 76  sub mount {
76          carp "mount needs 'dsn' to connect to (e.g. dsn => 'DBI:Pg:dbname=test')" unless ($arg->{'dsn'});          carp "mount needs 'dsn' to connect to (e.g. dsn => 'DBI:Pg:dbname=test')" unless ($arg->{'dsn'});
77          carp "mount needs 'mount' as mountpoint" unless ($arg->{'mount'});          carp "mount needs 'mount' as mountpoint" unless ($arg->{'mount'});
78    
79            # save (some) arguments in self
80            $self->{$_} = $arg->{$_} foreach (qw(mount));
81    
82          foreach (qw(filenames read update)) {          foreach (qw(filenames read update)) {
83                  carp "mount needs '$_' SQL" unless ($arg->{$_});                  carp "mount needs '$_' SQL" unless ($arg->{$_});
84          }          }
85    
86          $dbh = DBI->connect($arg->{'dsn'},$arg->{'user'},$arg->{'password'}, { AutoCommit => 0 }) || die $DBI::errstr;          $ctime_start = time();
87    
88          print "start transaction\n";          if ($arg->{'fork'}) {
89          #$dbh->begin_work || die $dbh->errstr;                  my $pid = fork();
90                    die "fork() failed: $!" unless defined $pid;
91                    # child will return to caller
92                    if ($pid) {
93                            $self ? return $self : return undef;
94                    }
95            }
96    
97            $dbh = DBI->connect($arg->{'dsn'},$arg->{'user'},$arg->{'password'}, {AutoCommit => 0, RaiseError => 1}) || die $DBI::errstr;
98    
99          $sth->{filenames} = $dbh->prepare($arg->{'filenames'}) || die $dbh->errstr();          $sth->{filenames} = $dbh->prepare($arg->{'filenames'}) || die $dbh->errstr();
100    
101          $sth->{'read'} = $dbh->prepare($arg->{'read'}) || die $dbh->errstr();          $sth->{'read'} = $dbh->prepare($arg->{'read'}) || die $dbh->errstr();
102          $sth->{'update'} = $dbh->prepare($arg->{'update'}) || die $dbh->errstr();          $sth->{'update'} = $dbh->prepare($arg->{'update'}) || die $dbh->errstr();
103    
104          $ctime_start = time();          $self->read_filenames;
   
         read_filenames;  
   
         $self->{'proc'} = Proc::Simple->new();  
         $self->{'proc'}->kill_on_destroy(1);  
105    
106          $self->{'proc'}->start( sub {          my $mount = Fuse::main(
107                  Fuse::main(                  mountpoint=>$arg->{'mount'},
108                          mountpoint=>$arg->{'mount'},                  getattr=>\&e_getattr,
109                          getattr=>\&e_getattr,                  getdir=>\&e_getdir,
110                          getdir=>\&e_getdir,                  open=>\&e_open,
111                          open=>\&e_open,                  statfs=>\&e_statfs,
112                          statfs=>\&e_statfs,                  read=>\&e_read,
113                          read=>\&e_read,                  write=>\&e_write,
114                          write=>\&e_write,                  utime=>\&e_utime,
115                          utime=>\&e_utime,                  truncate=>\&e_truncate,
116                          truncate=>\&e_truncate,                  unlink=>\&e_unlink,
117                          debug=>0,                  debug=>0,
118                  );          );
         } );  
119    
120          $self ? return $self : return undef;          if (! $mount) {
121                    warn "mount on ",$arg->{'mount'}," failed!\n";
122                    return undef;
123            }
124  };  };
125    
126  =head2 umount  =head2 umount
# Line 129  database to filesystem. Line 137  database to filesystem.
137  sub umount {  sub umount {
138          my $self = shift;          my $self = shift;
139    
140          confess "no process running?" unless ($self->{'proc'});          system "fusermount -u ".$self->{'mount'} || croak "umount error: $!";
141          $self->{'proc'}->kill;  
142            return 1;
143  }  }
144    
145    =head2 fuse_module_loaded
146    
147    Checks if C<fuse> module is loaded in kernel.
148    
149      die "no fuse module loaded in kernel"
150            unless (Fuse::DBI::fuse_module_loaded);
151    
152    This function in called by L<mount>, but might be useful alone also.
153    
154    =cut
155    
156    sub fuse_module_loaded {
157            my $lsmod = `lsmod`;
158            die "can't start lsmod: $!" unless ($lsmod);
159            if ($lsmod =~ m/fuse/s) {
160                    return 1;
161            } else {
162                    return 0;
163            }
164    }
165    
166  my %files;  my %files;
167  my %dirs;  my %dirs;
# Line 222  sub e_getdir { Line 251  sub e_getdir {
251          # return as many text filenames as you like, followed by the retval.          # return as many text filenames as you like, followed by the retval.
252          print((scalar keys %files)." files total\n");          print((scalar keys %files)." files total\n");
253          my %out;          my %out;
254          foreach (keys %files) {          foreach my $f (sort keys %files) {
                 my $f = $_;  
                 $f =~ s/^\E$dirname\Q//;  
                 $f =~ s/^\///;  
255                  if ($dirname) {                  if ($dirname) {
256                          $out{$f}++ if (/^\E$dirname\Q/ && $f =~ /^[^\/]+$/);                          if ($f =~ s/^\E$dirname\Q\///) {
257                                    $out{$f}++ if ($f =~ /^[^\/]+$/);
258                            }
259                  } else {                  } else {
260                          $out{$f}++ if ($f =~ /^[^\/]+$/);                          $out{$f}++ if ($f =~ /^[^\/]+$/);
261                  }                  }
# Line 236  sub e_getdir { Line 264  sub e_getdir {
264                  $out{'no files? bug?'}++;                  $out{'no files? bug?'}++;
265          }          }
266          print scalar keys %out," files in dir '$dirname'\n";          print scalar keys %out," files in dir '$dirname'\n";
267            print "## ",join(" ",keys %out),"\n";
268          return (keys %out),0;          return (keys %out),0;
269  }  }
270    
271    sub read_content {
272            my ($file,$id) = @_;
273    
274            die "read_content needs file and id" unless ($file && $id);
275    
276            $sth->{'read'}->execute($id) || die $sth->{'read'}->errstr;
277            $files{$file}{cont} = $sth->{'read'}->fetchrow_array;
278            print "file '$file' content [",length($files{$file}{cont})," bytes] read in cache\n";
279    }
280    
281    
282  sub e_open {  sub e_open {
283          # 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.
284          my $file = filename_fixup(shift);          my $file = filename_fixup(shift);
# Line 247  sub e_open { Line 287  sub e_open {
287          return -ENOENT() unless exists($files{$file});          return -ENOENT() unless exists($files{$file});
288          return -EISDIR() unless exists($files{$file}{id});          return -EISDIR() unless exists($files{$file}{id});
289    
290          if (!exists($files{$file}{cont})) {          read_content($file,$files{$file}{id}) unless exists($files{$file}{cont});
291                  $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";  
         }  
292          print "open '$file' ",length($files{$file}{cont})," bytes\n";          print "open '$file' ",length($files{$file}{cont})," bytes\n";
293          return 0;          return 0;
294  }  }
# Line 272  sub e_read { Line 309  sub e_read {
309          return -EINVAL() if ($off > $len);          return -EINVAL() if ($off > $len);
310          return 0 if ($off == $len);          return 0 if ($off == $len);
311    
312          $buf_len = $buf_len-$off if ($off+$buf_len > $len);          $buf_len = $len-$off if ($len - $off < $buf_len);
313    
314          return substr($files{$file}{cont},$off,$buf_len);          return substr($files{$file}{cont},$off,$buf_len);
315  }  }
# Line 285  sub clear_cont { Line 322  sub clear_cont {
322                  delete $files{$f}{cont};                  delete $files{$f}{cont};
323          }          }
324          print "begin new transaction\n";          print "begin new transaction\n";
325          $dbh->begin_work || die $dbh->errstr;          #$dbh->begin_work || die $dbh->errstr;
326  }  }
327    
328    
# Line 294  sub update_db { Line 331  sub update_db {
331    
332          $files{$file}{ctime} = time();          $files{$file}{ctime} = time();
333    
334          if (!$sth->{'update'}->execute($files{$file}{cont},$files{$file}{id})) {          my ($cont,$id) = (
335                    $files{$file}{cont},
336                    $files{$file}{id}
337            );
338    
339            if (!$sth->{'update'}->execute($cont,$id)) {
340                  print "update problem: ",$sth->{'update'}->errstr;                  print "update problem: ",$sth->{'update'}->errstr;
341                  clear_cont;                  clear_cont;
342                  return 0;                  return 0;
# Line 311  sub update_db { Line 353  sub update_db {
353    
354  sub e_write {  sub e_write {
355          my $file = filename_fixup(shift);          my $file = filename_fixup(shift);
356          my ($buf_len,$off) = @_;          my ($buffer,$off) = @_;
357    
358          return -ENOENT() unless exists($files{$file});          return -ENOENT() unless exists($files{$file});
359    
360          my $len = length($files{$file}{cont});          my $cont = $files{$file}{cont};
361            my $len = length($cont);
362    
363          print "write '$file' [$len bytes] offset $off length\n";          print "write '$file' [$len bytes] offset $off length ",length($buffer),"\n";
364    
365          $files{$file}{cont} =          $files{$file}{cont} = "";
366                  substr($files{$file}{cont},0,$off) .  
367                  $buf_len .          $files{$file}{cont} .= substr($cont,0,$off) if ($off > 0);
368                  substr($files{$file}{cont},$off+length($buf_len));          $files{$file}{cont} .= $buffer;
369            $files{$file}{cont} .= substr($cont,$off+length($buffer),$len-$off-length($buffer)) if ($off+length($buffer) < $len);
370    
371            $files{$file}{size} = length($files{$file}{cont});
372    
373          if (! update_db($file)) {          if (! update_db($file)) {
374                  return -ENOSYS();                  return -ENOSYS();
375          } else {          } else {
376                  return length($buf_len);                  return length($buffer);
377          }          }
378  }  }
379    
# Line 335  sub e_truncate { Line 381  sub e_truncate {
381          my $file = filename_fixup(shift);          my $file = filename_fixup(shift);
382          my $size = shift;          my $size = shift;
383    
384            print "truncate to $size\n";
385    
386          $files{$file}{cont} = substr($files{$file}{cont},0,$size);          $files{$file}{cont} = substr($files{$file}{cont},0,$size);
387            $files{$file}{size} = $size;
388          return 0          return 0
389  };  };
390    
# Line 354  sub e_utime { Line 403  sub e_utime {
403    
404  sub e_statfs { return 255, 1, 1, 1, 1, 2 }  sub e_statfs { return 255, 1, 1, 1, 1, 2 }
405    
406    sub e_unlink {
407            my $file = filename_fixup(shift);
408    
409            return -ENOENT() unless exists($files{$file});
410    
411            print "unlink '$file' will invalidate cache\n";
412    
413            read_content($file,$files{$file}{id});
414    
415            return 0;
416    }
417  1;  1;
418  __END__  __END__
419    

Legend:
Removed from v.11  
changed lines
  Added in v.21

  ViewVC Help
Powered by ViewVC 1.1.26