--- 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);