Muck
view release on metacpan or search on metacpan
lib/Muck/FS/VFS.pm view on Meta::CPAN
package Muck::FS::VFS;
# Virtual File System operations
# needs to be able to see $fuse_self
use File::Basename;
use IO::File;
use POSIX qw(ENOENT ENOSYS EEXIST EPERM O_RDONLY O_RDWR O_APPEND O_CREAT);
use Fcntl qw(S_ISBLK S_ISCHR S_ISFIFO S_IFDIR S_IFLNK SEEK_SET);
use Data::Dumper;
use POE::Component::IKC::ClientLite;
#use threads;
#use threads::shared;
use strict;
use constant BLOCK => 4096;
# these are up front in an array so the Muck::FS can pre-prepare these
# and cache the resulting statement handles for re-use
our @statements = (
{ name => 'chown_uid',
sql => 'UPDATE inodes SET uid=? WHERE inode=?' },
{ name => 'chown_gid',
sql => 'UPDATE inodes SET gid=? WHERE inode=?' },
{ name => 'chown_uid_gid',
sql => 'UPDATE inodes SET uid=?, gid=? WHERE inode=?' },
{ name => 'chmod',
sql => 'UPDATE inodes SET mode=? WHERE inode=?' },
{ name => 'getattr',
sql => 'SELECT inode, mode, uid, gid, atime, mtime, ctime, ' .
'size, dirty, cachetime ' .
'FROM inodes WHERE inode=? AND deleted = 0' },
{ name => 'inuse',
sql => 'UPDATE inodes SET inuse = inuse + ? WHERE inode = ?' },
{ name => 'last_id',
sql => 'SELECT LAST_INSERT_ID()'},
{ name => 'mkdir',
sql => 'INSERT INTO tree (name, parent, inode) VALUES (?,?,?)' },
{ name => 'mknod_tree',
sql => 'INSERT INTO tree (name, parent) VALUES (?,?)' },
{ name => 'mknod_inode',
sql => 'INSERT INTO inodes ' .
'(inode, mode, uid, gid, atime, ctime, mtime, dirty, cachetime) '.
'VALUES(?, ?, ?, ?, UNIX_TIMESTAMP(NOW()), ' .
'UNIX_TIMESTAMP(NOW()), UNIX_TIMESTAMP(NOW()), 1, ' .
'UNIX_TIMESTAMP(NOW()) )' },
{ name => 'mksym',
sql => 'INSERT INTO symlinks (inode, data) VALUES (?,?)' },
{ name => 'readdir',
sql => 'SELECT name FROM tree WHERE parent = ?' },
{ name => 'read_symlink',
sql => 'SELECT data FROM symlinks WHERE inode = ?' },
{ name => 'rename',
sql => 'UPDATE tree SET name = ?, parent = ? ' .
'WHERE inode = ? AND name = ? and parent = ?'},
{ name => 'rmdir',
sql => 'DELETE FROM tree WHERE name=? AND parent=?' },
{ name => 'set_clean',
sql => 'UPDATE inodes SET dirty=0 WHERE inode=?' },
{ name => 'set_deleted',
sql => 'UPDATE inodes SET deleted=1 WHERE inode = ?' },
{ name => 'set_dirty',
sql => 'UPDATE inodes SET size=?, dirty=1 WHERE inode=?' },
{ name => 'statfs',
sql => 'SELECT count(*) AS inodes, sum(size) AS size ' .
'FROM inodes WHERE deleted = 0' },
{ name => 'truncate',
sql => 'UPDATE inodes SET size=? WHERE inode=?' },
{ name => 'update_utime',
sql => 'UPDATE inodes SET atime=?, mtime=? WHERE inode=?' },
);
sub err {
my $msg = shift;
$msg = "ERROR: " . $msg;
return (-shift || -$!);
}
sub debug {
my ( $msg, $lvl ) = @_;
$lvl ||= 1;
my $debug = $Muck::FS::fuse_self->{debug};
warn "DEBUG: $msg\n" if $debug >= $lvl;
}
lib/Muck/FS/VFS.pm view on Meta::CPAN
db_execute('set_deleted', $inode );
# no datastore purging since we want to have undelete
return 0;
}
#----------------------------------------------------------------------------
sub x_symlink {
#----------------------------------------------------------------------------
debug("CALLBACK: x_symlink(@_)");
my ( $from, $to ) = @_;
x_mknod( $to, S_IFLNK | 0755 );
my ( $to_inode ) = path2inode( $to );
db_execute('mksym', $to_inode, $from );
return 0;
}
#----------------------------------------------------------------------------
sub x_rename {
#----------------------------------------------------------------------------
# update tree to point to same old inode content
debug("CALLBACK: x_rename(@_)");
my ( $oldpath, $newpath ) = @_;
my ( $inode ) = path2inode($oldpath);
my ( $parent_from ) = path2inode( dirname( $oldpath ) );
my $oldname = basename( $oldpath );
my ( $parent_to ) = path2inode( $newpath );
my $newname = basename( $newpath );
x_unlink( $oldpath );
db_execute('rename', $newname, $parent_to, $inode, $oldname, $parent_from);
my $memcache = $Muck::FS::fuse_self->{memcached};
$memcache->delete($oldpath);
return 0;
}
#----------------------------------------------------------------------------
sub x_link {
#----------------------------------------------------------------------------
# update db to link the two inodes - no cachefile/S3 changes needed
debug("CALLBACK: x_link(@_)");
my ( $from, $to ) = @_;
my ( $source_inode ) = path2inode($from);
my $targetdir = dirname($to);
my ( $new_parent ) = path2inode($targetdir);
db_execute('mkdir', basename($to), $new_parent, $source_inode );
my $memcache = $Muck::FS::fuse_self->{memcached};
$memcache->delete($from); # purge from cache to allow regen of nlinks
# TODO - should really look for any other paths that use this same inode
# and delete their caches too so that nlinks will get fixed in cache
return 0;
}
#----------------------------------------------------------------------------
sub x_chown {
#----------------------------------------------------------------------------
# update db only - no cachefile/s3 changes needed
debug("CALLBACK: x_chown(@_)");
my ( $file, $uid, $gid ) = @_;
my ( $inode ) = path2inode( $file );
if ( $uid and $gid ) {
db_execute('chown_uid_gid', $uid, $gid, $inode);
} elsif ( $uid ) {
db_execute('chown_uid', $uid, $inode);
} elsif ( $gid ) {
db_execute('chown_gid', $gid, $inode);
}
return 0;
}
#----------------------------------------------------------------------------
sub x_chmod {
#----------------------------------------------------------------------------
# update db only - no cachefile/s3 changes needed
debug("CALLBACK: x_chmod(@_)");
my ( $file, $mode ) = @_;
my ( $inode ) = path2inode($file);
db_execute('chmod', $mode, $inode);
return 0;
}
#----------------------------------------------------------------------------
sub x_truncate {
#----------------------------------------------------------------------------
# - update db,
# - truncate cachefile
# - let release handle asynch to S3
debug("CALLBACK: x_truncate(@_)");
my ( $file, $length ) = @_;
my ( $inode ) = path2inode($file);
db_execute('truncate', $length, $inode);
my ( $cachefile, $inod2, $cachetime, $dirty, $current ) = path2cache($file);
#TODO - this should be trunacting a new snapshot
return truncate($cachefile,$length) ? 0 : -$! ;
}
#----------------------------------------------------------------------------
sub x_utime {
#----------------------------------------------------------------------------
# - update db only
debug("CALLBACK: x_utime(@_)");
my ($file, $atime, $mtime) = @_;
my ( $inode ) = path2inode($file);
my $ok = db_execute('update_utime',$atime, $mtime, $inode);
return ($ok ? 0 : 1 );
}
#----------------------------------------------------------------------------
sub x_mkdir {
#----------------------------------------------------------------------------
# update db only
debug("CALLBACK: x_mkdir(@_)");
my ($file, $mode) = @_;
err("Directory name is too long: $file") if too_long($file);
my $parentpath = dirname($file);
my ( $parent ) = path2inode($parentpath);
db_execute('mknod_tree', basename($file), $parent );
my $inode = db_retrieve('last_id', 1);
my ( $uid, $gid ) = get_current_user();
db_execute('mknod_inode', $inode, S_IFDIR | $mode, $uid, $gid );
return 0;
}
#----------------------------------------------------------------------------
sub x_mknod {
( run in 0.538 second using v1.01-cache-2.11-cpan-71847e10f99 )