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; |
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 = {}; |
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'}, |
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'}); |
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) { |
if ($self->is_mounted) { |
284 |
system "sudo umount ".$self->{'mount'} || |
system "sudo umount ".$self->{'mount'} || |
285 |
return 0; |
return 0; |
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 |
}; |
}; |
363 |
$files->{$row->{'filename'}} = { |
$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 |
|
|
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"; |
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 |
|
|
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 |
} |
} |
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"; |