bin/fuse-imager
branchtesting
changeset 31 221af7ffe050
parent 21 e0f19213f8b6
--- a/bin/fuse-imager	Thu Jul 28 16:32:18 2011 +0200
+++ b/bin/fuse-imager	Fri Jul 29 14:04:19 2011 +0200
@@ -22,9 +22,18 @@
 lock_keys %o;
 
 use constant ME => basename $0;
+use constant BS => 4 * 1024;
+
 my ($DATA, $IDX);
 
 sub tie_vars;
+sub min { (sort {$a <=> $b} @_)[0] }
+sub max { (sort {$a <=> $b} @_)[-1] }
+my $debug = sub { print STDERR @_ };
+   $debug = sub { };
+
+
+#$SIG{INT} = sub { warn "Got ^C or INT signal\n"; exit 1; };
 
 MAIN: {
 
@@ -57,7 +66,6 @@
         $0 = "FUSE $src $mp";
         open(STDOUT => ">/dev/null");
         open(STDIN  => "/dev/null");
-
         setpgid($$ => $$);
     }
 
@@ -71,6 +79,7 @@
         open       => \&openfile,
         read       => \&readbuffer,
         write      => \&writebuffer,
+	release	   => \&release,
     );
 
     exit;
@@ -133,6 +142,13 @@
         return 0;
     }
 
+    sub release {
+	my $path = $IDX . shift;
+	return 0 if not exists $IMAGE{$path};
+	$debug->("Currently we have " . keys(%DIRTY) . " dirty blocks\n");
+	return 0;
+    }
+
     sub readbuffer {
         my $path = $IDX . shift;
         my ($size, $offset) = @_;
@@ -149,36 +165,65 @@
 
     sub _readblock {
         my ($finfo, $size, $offset) = @_;
+	my ($block, $blockoffset, $length);
 
-        my $block       = int($offset / $finfo->{meta}{blocksize});
-        my $blockoffset = $offset % $finfo->{meta}{blocksize};
+	$debug->("<<< block offset:$offset size:$size\n");
+	$debug->( "    block @{[int($offset/BS)]} + @{[$offset % BS]}\n");
 
-        my $length = $finfo->{meta}{blocksize} - $blockoffset;
-        $length = $size if $size <= $length;
+	# first check if it's an dirty block
+        $block       = int($offset / BS);
+        if (exists $DIRTY{ $finfo . $block }) {
+	    $blockoffset = $offset % BS;
+	    $length = min(BS - $blockoffset, $size);
 
-        if (exists $DIRTY{ $finfo . $block }) {
+	    $debug->("+++ dirty offset:$block*@{[BS]} + $blockoffset size:$length\n");
             return substr $DIRTY{ $finfo . $block }, $blockoffset, $length;
         }
 
+
+	# if not dirty, we've to find it on disk
+
+	$block = int($offset / $finfo->{meta}{blocksize});
+	$blockoffset = $offset % $finfo->{meta}{blocksize};
+	$length = min($finfo->{meta}{blocksize} - $blockoffset, $size);
+
+	# find the max length we can satisfy w/o colliding 
+	# with dirty blocks
+	for (my $l = BS; $l < $length; $l += BS) {
+	    my $b = int(($offset + $l)/BS);
+	    if ($DIRTY{$finfo . $b}) {
+		$length = $l;
+		last;
+	    }
+	}
+
+	$debug->("=== $length\n");
+	$debug->("+++ disk offset:$block*$finfo->{meta}{blocksize} + $blockoffset size:$length\n");
+
         my $fn = "$DATA/" . $finfo->{blocklist}{$block};
-        if (-e $fn) {
-            open(my $fh => $fn);
-            binmode($fh);
-            seek($fh => $blockoffset, 0) or die "seek: $!";
-            local $/ = \$length;
-            return scalar <$fh>;
-        }
-        elsif (-e "$fn.gz") {
-            open(my $fh => "$fn.gz");
-            binmode($fh);
-            my $buffer;
-            gunzip($fh => \$buffer)
-              or die $GunzipError;
-            close($fh);
-            return substr($buffer, $blockoffset, $size);
-        }
+
+	state %cache;
+	if (not defined $cache{fn} 
+	    or ($cache{fn} ne $fn)) {
 
-        die "$fn: $!\n";
+	    if (-e $fn) {
+		open(my $fh => $fn);
+		binmode($fh);
+		local $/ = undef;
+		$cache{data} = <$fh>;
+	    }
+	    elsif (-e "$fn.gz") {
+		open(my $fh => "$fn.gz");
+		binmode($fh);
+		gunzip($fh => \$cache{data})
+		      or die $GunzipError;
+	    }
+	    $cache{fn} = $fn;
+	}
+
+	return substr($cache{data}, $blockoffset, $size);
+	die "$fn: $!\n";
+        
     }
 
     sub writebuffer {
@@ -201,22 +246,22 @@
 
     sub _writeblock {
         my ($finfo, $buffer, $offset) = @_;
+	my ($block, $blockoffset, $length);
         my $size = length($buffer);
 
-        my $block       = int($offset / $finfo->{meta}{blocksize});
-        my $blockoffset = $offset % $finfo->{meta}{blocksize};
+	$block = int($offset / BS);
+	$blockoffset = $offset % BS;
+        $length = min(BS - $blockoffset, $size);
+
+	$debug->(">>> offset:$offset size:$length of $size\n");
+	$debug->("    block @{[int($offset/BS)]} + @{[$offset % BS]}\n");
 
         if (not exists $DIRTY{ $finfo . $block }) {
+	    $debug->("+++ missing $block+$blockoffset\n");
             $DIRTY{ $finfo . $block } = _readblock(
-                $finfo,
-                $finfo->{meta}{blocksize},
-                $block * $finfo->{meta}{blocksize}
-            );
+                $finfo, BS, $block * BS);
         }
 
-        my $length = $finfo->{meta}{blocksize} - $blockoffset;
-        $length = $size if $size < $length;
-
         substr($DIRTY{ $finfo . $block }, $blockoffset, $length) =
           substr($buffer, 0, $length);