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 )