/[fuse_dbi]/fuse-couchdb/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 /fuse-couchdb/DBI.pm

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

revision 52 by dpavlin, Sat Nov 27 15:08:10 2004 UTC revision 64 by dpavlin, Sun Nov 26 22:29:23 2006 UTC
# Line 12  use DBI; Line 12  use DBI;
12  use Carp;  use Carp;
13  use Data::Dumper;  use Data::Dumper;
14    
15  our $VERSION = '0.07';  our $VERSION = '0.09_1';
16    
17  # block size for this filesystem  # block size for this filesystem
18  use constant BLOCK => 1024;  use constant BLOCK => 1024;
# Line 111  running. Implementation is experimental. Line 111  running. Implementation is experimental.
111    
112  =back  =back
113    
114    There is also alternative way which can generate C<read> and C<update>
115    queries on the fly:
116    
117      my $mnt = Fuse::DBI->mount({
118            'filenames' => 'select id,filename,size,writable from files',
119            'read' => sub {
120                    my ($path,$file) = @_;
121                    return( 'select content from files where id = ?', $file->{row}->{id} );
122            },
123            'update' => sub {
124                    my ($path,$file) = @_;
125                    return( 'update files set content = ? where id = ?', $file->{row}->{id} );
126            },
127            'dsn' => 'DBI:Pg:dbname=test_db',
128            'user' => 'database_user',
129            'password' => 'database_password',
130            'invalidate' => sub { ... },
131      });
132    
133  =cut  =cut
134    
135  my $dbh;  my $dbh;
# Line 125  sub fuse_module_loaded; Line 144  sub fuse_module_loaded;
144  # be a problem.  # be a problem.
145  my $fuse_self;  my $fuse_self;
146    
147    my $debug = 0;
148    
149  sub mount {  sub mount {
150          my $class = shift;          my $class = shift;
151          my $self = {};          my $self = {};
# Line 176  sub mount { Line 197  sub mount {
197    
198          $sth->{'filenames'} = $dbh->prepare($arg->{'filenames'}) || die $dbh->errstr();          $sth->{'filenames'} = $dbh->prepare($arg->{'filenames'}) || die $dbh->errstr();
199    
         $sth->{'read'} = $dbh->prepare($arg->{'read'}) || die $dbh->errstr();  
         $sth->{'update'} = $dbh->prepare($arg->{'update'}) || die $dbh->errstr();  
   
   
200          $self->{'sth'} = $sth;          $self->{'sth'} = $sth;
201            $self->{'dbh'} = $dbh;
202    
203          $self->{'read_filenames'} = sub { $self->read_filenames };          $self->{'read_filenames'} = sub { $self->read_filenames };
204          $self->read_filenames;          $self->read_filenames;
205    
206          $fuse_self = \$self;          foreach my $op (qw/read update/) {
207                    if (ref($arg->{ $op }) ne 'CODE') {
208                            $self->{ $op . '_ref' } = sub {
209                                    my $row = shift;
210                                    return ($arg->{ $op }, $row->{'id'});
211                            }
212                    } else {
213                            $self->{ $op . '_ref' } = $arg->{ $op };
214                    }
215            }
216    
217            $fuse_self = $self;
218    
219          Fuse::main(          Fuse::main(
220                  mountpoint=>$arg->{'mount'},                  mountpoint=>$arg->{'mount'},
# Line 199  sub mount { Line 228  sub mount {
228                  truncate=>\&e_truncate,                  truncate=>\&e_truncate,
229                  unlink=>\&e_unlink,                  unlink=>\&e_unlink,
230                  rmdir=>\&e_unlink,                  rmdir=>\&e_unlink,
231                  debug=>0,                  debug=>$debug,
232          );          );
233                    
234          exit(0) if ($arg->{'fork'});          exit(0) if ($arg->{'fork'});
# Line 249  sub umount { Line 278  sub umount {
278          my $self = shift;          my $self = shift;
279    
280          if ($self->{'mount'} && $self->is_mounted) {          if ($self->{'mount'} && $self->is_mounted) {
281                  system "( fusermount -u ".$self->{'mount'}." 2>&1 ) >/dev/null" ||                  system "( fusermount -u ".$self->{'mount'}." 2>&1 ) >/dev/null";
282                    sleep 1;
283                    if ($self->is_mounted) {
284                          system "sudo umount ".$self->{'mount'} ||                          system "sudo umount ".$self->{'mount'} ||
285                          return 0;                          return 0;
286                    }
287                  return 1;                  return 1;
288          }          }
289    
# Line 259  sub umount { Line 291  sub umount {
291  }  }
292    
293  $SIG{'INT'} = sub {  $SIG{'INT'} = sub {
294          if ($fuse_self && $$fuse_self->umount) {          if ($fuse_self && $fuse_self->can('umount')) {
295                  print STDERR "umount called by SIG INT\n";                  print STDERR "umount called by SIG INT\n";
296          }          }
297  };  };
298    
299  $SIG{'QUIT'} = sub {  $SIG{'QUIT'} = sub {
300          if ($fuse_self && $$fuse_self->umount) {          if ($fuse_self && $fuse_self->can('umount')) {
301                  print STDERR "umount called by SIG QUIT\n";                  print STDERR "umount called by SIG QUIT\n";
302          }          }
303  };  };
# Line 298  sub fuse_module_loaded { Line 330  sub fuse_module_loaded {
330          }          }
331  }  }
332    
333  my %files;  my $files;
334    
335  sub read_filenames {  sub read_filenames {
336          my $self = shift;          my $self = shift;
# Line 306  sub read_filenames { Line 338  sub read_filenames {
338          my $sth = $self->{'sth'} || die "no sth argument";          my $sth = $self->{'sth'} || die "no sth argument";
339    
340          # create empty filesystem          # create empty filesystem
341          (%files) = (          $files = {
342                  '.' => {                  '.' => {
343                          type => 0040,                          type => 0040,
344                          mode => 0755,                          mode => 0755,
# Line 320  sub read_filenames { Line 352  sub read_filenames {
352          #               type => 0100,          #               type => 0100,
353          #               ctime => time()-2000          #               ctime => time()-2000
354          #       },          #       },
355          );          };
356    
357          # fetch new filename list from database          # fetch new filename list from database
358          $sth->{'filenames'}->execute() || die $sth->{'filenames'}->errstr();          $sth->{'filenames'}->execute() || die $sth->{'filenames'}->errstr();
359    
360          # read them in with sesible defaults          # read them in with sesible defaults
361          while (my $row = $sth->{'filenames'}->fetchrow_hashref() ) {          while (my $row = $sth->{'filenames'}->fetchrow_hashref() ) {
362                  $files{$row->{'filename'}} = {                  $row->{'filename'} ||= 'NULL-'.$row->{'id'};
363                    $files->{$row->{'filename'}} = {
364                          size => $row->{'size'},                          size => $row->{'size'},
365                          mode => $row->{'writable'} ? 0644 : 0444,                          mode => $row->{'writable'} ? 0644 : 0444,
366                          id => $row->{'id'} || 99,                          id => $row->{'id'} || undef,
367                            row => $row,
368                  };                  };
369    
370    
371                  my $d;                  my $d;
372                  foreach (split(m!/!, $row->{'filename'})) {                  foreach (split(m!/!, $row->{'filename'})) {
373                          # first, entry is assumed to be file                          # first, entry is assumed to be file
374                          if ($d) {                          if ($d) {
375                                  $files{$d} = {                                  $files->{$d} = {
376                                                  mode => 0755,                                                  mode => 0755,
377                                                  type => 0040                                                  type => 0040
378                                  };                                  };
379                                  $files{$d.'/.'} = {                                  $files->{$d.'/.'} = {
380                                                  mode => 0755,                                                  mode => 0755,
381                                                  type => 0040                                                  type => 0040
382                                  };                                  };
383                                  $files{$d.'/..'} = {                                  $files->{$d.'/..'} = {
384                                                  mode => 0755,                                                  mode => 0755,
385                                                  type => 0040                                                  type => 0040
386                                  };                                  };
# Line 355  sub read_filenames { Line 390  sub read_filenames {
390                  }                  }
391          }          }
392    
393          print "found ",scalar(keys %files)," files\n";          print "found ",scalar(keys %{$files})," files\n";
394  }  }
395    
396    
# Line 370  sub e_getattr { Line 405  sub e_getattr {
405          my ($file) = filename_fixup(shift);          my ($file) = filename_fixup(shift);
406          $file =~ s,^/,,;          $file =~ s,^/,,;
407          $file = '.' unless length($file);          $file = '.' unless length($file);
408          return -ENOENT() unless exists($files{$file});          return -ENOENT() unless exists($files->{$file});
409          my ($size) = $files{$file}{size} || BLOCK;          my ($size) = $files->{$file}->{size} || 0;
410          my ($dev, $ino, $rdev, $blocks, $gid, $uid, $nlink, $blksize) = (0,0,0,int(($size+BLOCK-1)/BLOCK),0,0,1,BLOCK);          my ($dev, $ino, $rdev, $blocks, $gid, $uid, $nlink, $blksize) = (0,0,0,int(($size+BLOCK-1)/BLOCK),0,0,1,BLOCK);
411          my ($atime, $ctime, $mtime);          my ($atime, $ctime, $mtime);
412          $atime = $ctime = $mtime = $files{$file}{ctime} || $ctime_start;          $atime = $ctime = $mtime = $files->{$file}->{ctime} || $ctime_start;
413    
414          my ($modes) = (($files{$file}{type} || 0100)<<9) + $files{$file}{mode};          my ($modes) = (($files->{$file}->{type} || 0100)<<9) + $files->{$file}->{mode};
415    
416          # 2 possible types of return values:          # 2 possible types of return values:
417          #return -ENOENT(); # or any other error you care to          #return -ENOENT(); # or any other error you care to
418          print "getattr($file) ",join(",",($dev,$ino,$modes,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks)),"\n";          #print "getattr($file) ",join(",",($dev,$ino,$modes,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks)),"\n";
419          return ($dev,$ino,$modes,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks);          return ($dev,$ino,$modes,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks);
420  }  }
421    
# Line 388  sub e_getdir { Line 423  sub e_getdir {
423          my ($dirname) = shift;          my ($dirname) = shift;
424          $dirname =~ s!^/!!;          $dirname =~ s!^/!!;
425          # return as many text filenames as you like, followed by the retval.          # return as many text filenames as you like, followed by the retval.
426          print((scalar keys %files)." files total\n");          print((scalar keys %{$files})." files total\n");
427          my %out;          my %out;
428          foreach my $f (sort keys %files) {          foreach my $f (sort keys %{$files}) {
429                  if ($dirname) {                  if ($dirname) {
430                          if ($f =~ s/^\Q$dirname\E\///) {                          if ($f =~ s/^\Q$dirname\E\///) {
431                                  $out{$f}++ if ($f =~ /^[^\/]+$/);                                  $out{$f}++ if ($f =~ /^[^\/]+$/);
# Line 408  sub e_getdir { Line 443  sub e_getdir {
443  }  }
444    
445  sub read_content {  sub read_content {
446          my ($file,$id) = @_;          my $file = shift || die "need file";
447    
448            warn "file: $file\n", Dumper($fuse_self);
449    
450          die "read_content needs file and id" unless ($file && $id);          my @args = $fuse_self->{'read_ref'}->($files->{$file});
451            my $sql = shift @args || die "need SQL for $file";
452    
453          $sth->{'read'}->execute($id) || die $sth->{'read'}->errstr;          $fuse_self->{'read_sth'}->{$sql} ||= $fuse_self->{dbh}->prepare($sql) || die $dbh->errstr();
454          $files{$file}{cont} = $sth->{'read'}->fetchrow_array;          my $sth = $fuse_self->{'read_sth'}->{$sql} || die;
455    
456            $sth->execute(@args) || die $sth->errstr;
457            $files->{$file}->{cont} = $sth->fetchrow_array;
458          # I should modify ctime only if content in database changed          # I should modify ctime only if content in database changed
459          #$files{$file}{ctime} = time() unless ($files{$file}{ctime});          #$files->{$file}->{ctime} = time() unless ($files->{$file}->{ctime});
460          print "file '$file' content [",length($files{$file}{cont})," bytes] read in cache\n";          print "file '$file' content [",length($files->{$file}->{cont})," bytes] read in cache\n";
461  }  }
462    
463    
# Line 425  sub e_open { Line 466  sub e_open {
466          my $file = filename_fixup(shift);          my $file = filename_fixup(shift);
467          my $flags = shift;          my $flags = shift;
468    
469          return -ENOENT() unless exists($files{$file});          return -ENOENT() unless exists($files->{$file});
470          return -EISDIR() unless exists($files{$file}{id});          return -EISDIR() unless exists($files->{$file}->{id});
471    
472          read_content($file,$files{$file}{id}) unless exists($files{$file}{cont});          read_content($file,$files->{$file}->{id}) unless exists($files->{$file}->{cont});
473    
474          print "open '$file' ",length($files{$file}{cont})," bytes\n";          $files->{$file}->{cont} ||= '';
475            print "open '$file' ",length($files->{$file}->{cont})," bytes\n";
476          return 0;          return 0;
477  }  }
478    
# Line 441  sub e_read { Line 483  sub e_read {
483          my ($file) = filename_fixup(shift);          my ($file) = filename_fixup(shift);
484          my ($buf_len,$off) = @_;          my ($buf_len,$off) = @_;
485    
486          return -ENOENT() unless exists($files{$file});          return -ENOENT() unless exists($files->{$file});
487    
488          my $len = length($files{$file}{cont});          my $len = length($files->{$file}->{cont});
489    
490          print "read '$file' [$len bytes] offset $off length $buf_len\n";          print "read '$file' [$len bytes] offset $off length $buf_len\n";
491    
# Line 452  sub e_read { Line 494  sub e_read {
494    
495          $buf_len = $len-$off if ($len - $off < $buf_len);          $buf_len = $len-$off if ($len - $off < $buf_len);
496    
497          return substr($files{$file}{cont},$off,$buf_len);          return substr($files->{$file}->{cont},$off,$buf_len);
498  }  }
499    
500  sub clear_cont {  sub clear_cont {
501          print "transaction rollback\n";          print "transaction rollback\n";
502          $dbh->rollback || die $dbh->errstr;          $dbh->rollback || die $dbh->errstr;
503          print "invalidate all cached content\n";          print "invalidate all cached content\n";
504          foreach my $f (keys %files) {          foreach my $f (keys %{$files}) {
505                  delete $files{$f}{cont};                  delete $files->{$f}->{cont};
506                  delete $files{$f}{ctime};                  delete $files->{$f}->{ctime};
507          }          }
508          print "begin new transaction\n";          print "begin new transaction\n";
509          #$dbh->begin_work || die $dbh->errstr;          #$dbh->begin_work || die $dbh->errstr;
# Line 469  sub clear_cont { Line 511  sub clear_cont {
511    
512    
513  sub update_db {  sub update_db {
514          my $file = shift || die;          my $file = shift || die "need file";
515    
516          $files{$file}{ctime} = time();          $files->{$file}->{ctime} = time();
517    
518          my ($cont,$id) = (          my ($cont,$id) = (
519                  $files{$file}{cont},                  $files->{$file}->{cont},
520                  $files{$file}{id}                  $files->{$file}->{id}
521          );          );
522    
523          if (!$sth->{'update'}->execute($cont,$id)) {          my @args = $fuse_self->{'update_ref'}->($files->{$file});
524                  print "update problem: ",$sth->{'update'}->errstr;  
525            my $sql = shift @args || die "need SQL for $file";
526    
527            unshift @args, $files->{$file}->{cont} if ($#args == 0);
528    
529            warn "## SQL: $sql\n# files->{$file} = ", Dumper($files->{$file}), $/ if ($debug);
530    
531            my $sth = $fuse_self->{'update_sth'}->{$sql}
532                    ||= $fuse_self->{dbh}->prepare($sql)
533                    || die $dbh->errstr();
534    
535            if (!$sth->execute(@args)) {
536                    print "update problem: ",$sth->errstr;
537                  clear_cont;                  clear_cont;
538                  return 0;                  return 0;
539          } else {          } else {
540                  if (! $dbh->commit) {                  if (! $dbh->commit) {
541                          print "ERROR: commit problem: ",$sth->{'update'}->errstr;                          print "ERROR: commit problem: ",$sth->errstr;
542                          clear_cont;                          clear_cont;
543                          return 0;                          return 0;
544                  }                  }
545                  print "updated '$file' [",$files{$file}{id},"]\n";                  print "updated '$file' [",$files->{$file}->{id},"]\n";
546    
547                  $$fuse_self->{'invalidate'}->() if (ref $$fuse_self->{'invalidate'});                  $fuse_self->{'invalidate'}->() if ($fuse_self->can('invalidate'));
548          }          }
549          return 1;          return 1;
550  }  }
# Line 499  sub e_write { Line 553  sub e_write {
553          my $file = filename_fixup(shift);          my $file = filename_fixup(shift);
554          my ($buffer,$off) = @_;          my ($buffer,$off) = @_;
555    
556          return -ENOENT() unless exists($files{$file});          return -ENOENT() unless exists($files->{$file});
557    
558          my $cont = $files{$file}{cont};          my $cont = $files->{$file}->{cont};
559          my $len = length($cont);          my $len = length($cont);
560    
561          print "write '$file' [$len bytes] offset $off length ",length($buffer),"\n";          print "write '$file' [$len bytes] offset $off length ",length($buffer),"\n";
562    
563          $files{$file}{cont} = "";          $files->{$file}->{cont} = "";
564    
565          $files{$file}{cont} .= substr($cont,0,$off) if ($off > 0);          $files->{$file}->{cont} .= substr($cont,0,$off) if ($off > 0);
566          $files{$file}{cont} .= $buffer;          $files->{$file}->{cont} .= $buffer;
567          $files{$file}{cont} .= substr($cont,$off+length($buffer),$len-$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);
568    
569          $files{$file}{size} = length($files{$file}{cont});          $files->{$file}->{size} = length($files->{$file}->{cont});
570    
571          if (! update_db($file)) {          if (! update_db($file)) {
572                  return -ENOSYS();                  return -ENOSYS();
# Line 527  sub e_truncate { Line 581  sub e_truncate {
581    
582          print "truncate to $size\n";          print "truncate to $size\n";
583    
584          $files{$file}{cont} = substr($files{$file}{cont},0,$size);          $files->{$file}->{cont} = substr($files->{$file}->{cont},0,$size);
585          $files{$file}{size} = $size;          $files->{$file}->{size} = $size;
586          return 0          return 0
587  };  };
588    
# Line 537  sub e_utime { Line 591  sub e_utime {
591          my ($atime,$mtime,$file) = @_;          my ($atime,$mtime,$file) = @_;
592          $file = filename_fixup($file);          $file = filename_fixup($file);
593    
594          return -ENOENT() unless exists($files{$file});          return -ENOENT() unless exists($files->{$file});
595    
596          print "utime '$file' $atime $mtime\n";          print "utime '$file' $atime $mtime\n";
597    
598          $files{$file}{time} = $mtime;          $files->{$file}->{time} = $mtime;
599          return 0;          return 0;
600  }  }
601    
# Line 550  sub e_statfs { Line 604  sub e_statfs {
604          my $size = 0;          my $size = 0;
605          my $inodes = 0;          my $inodes = 0;
606    
607          foreach my $f (keys %files) {          foreach my $f (keys %{$files}) {
608                  if ($f !~ /(^|\/)\.\.?$/) {                  if ($f !~ /(^|\/)\.\.?$/) {
609                          $size += $files{$f}{size} || 0;                          $size += $files->{$f}->{size} || 0;
610                          $inodes++;                          $inodes++;
611                  }                  }
612                  print "$inodes: $f [$size]\n";                  print "$inodes: $f [$size]\n";
# Line 562  sub e_statfs { Line 616  sub e_statfs {
616    
617          my @ret = (255, $inodes, 1, $size, $size-1, BLOCK);          my @ret = (255, $inodes, 1, $size, $size-1, BLOCK);
618    
619          print "statfs: ",join(",",@ret),"\n";          #print "statfs: ",join(",",@ret),"\n";
620    
621          return @ret;          return @ret;
622  }  }
# Line 573  sub e_unlink { Line 627  sub e_unlink {
627  #       if (exists( $dirs{$file} )) {  #       if (exists( $dirs{$file} )) {
628  #               print "unlink '$file' will re-read template names\n";  #               print "unlink '$file' will re-read template names\n";
629  #               print Dumper($fuse_self);  #               print Dumper($fuse_self);
630  #               $$fuse_self->{'read_filenames'}->();  #               $fuse_self->{'read_filenames'}->();
631  #               return 0;  #               return 0;
632          if (exists( $files{$file} )) {          if (exists( $files->{$file} )) {
633                  print "unlink '$file' will invalidate cache\n";                  print "unlink '$file' will invalidate cache\n";
634                  read_content($file,$files{$file}{id});                  read_content($file,$files->{$file}->{id});
635                  return 0;                  return 0;
636          }          }
637    

Legend:
Removed from v.52  
changed lines
  Added in v.64

  ViewVC Help
Powered by ViewVC 1.1.26