163 return $buffer; |
168 return $buffer; |
164 } |
169 } |
165 |
170 |
166 sub _readblock { |
171 sub _readblock { |
167 my ($finfo, $size, $offset) = @_; |
172 my ($finfo, $size, $offset) = @_; |
168 my ($block, $blockoffset, $length); |
173 my ($block, $blockoffset, $length); |
169 |
174 |
170 $debug->("<<< block offset:$offset size:$size\n"); |
175 $debug->("<<< block offset:$offset size:$size\n"); |
171 $debug->( " block @{[int($offset/BS)]} + @{[$offset % BS]}\n"); |
176 $debug->(" block @{[int($offset/BS)]} + @{[$offset % BS]}\n"); |
172 |
177 |
173 # first check if it's an dirty block |
178 # first check if it's an dirty block |
174 $block = int($offset / BS); |
179 $block = int($offset / BS); |
175 if (exists $DIRTY{ $finfo . $block }) { |
180 if (exists $DIRTY{ $finfo . $block }) { |
176 $blockoffset = $offset % BS; |
181 $blockoffset = $offset % BS; |
177 $length = min(BS - $blockoffset, $size); |
182 $length = min(BS - $blockoffset, $size); |
178 |
183 |
179 $debug->("+++ dirty offset:$block*@{[BS]} + $blockoffset size:$length\n"); |
184 $debug->( |
|
185 "+++ dirty offset:$block*@{[BS]} + $blockoffset size:$length\n" |
|
186 ); |
180 return substr $DIRTY{ $finfo . $block }, $blockoffset, $length; |
187 return substr $DIRTY{ $finfo . $block }, $blockoffset, $length; |
181 } |
188 } |
182 |
189 |
183 |
190 # if not dirty, we've to find it on disk |
184 # if not dirty, we've to find it on disk |
191 |
185 |
192 $block = int($offset / $finfo->{meta}{blocksize}); |
186 $block = int($offset / $finfo->{meta}{blocksize}); |
193 $blockoffset = $offset % $finfo->{meta}{blocksize}; |
187 $blockoffset = $offset % $finfo->{meta}{blocksize}; |
194 $length = min($finfo->{meta}{blocksize} - $blockoffset, $size); |
188 $length = min($finfo->{meta}{blocksize} - $blockoffset, $size); |
195 |
189 |
196 # find the max length we can satisfy w/o colliding |
190 # find the max length we can satisfy w/o colliding |
197 # with dirty blocks |
191 # with dirty blocks |
198 for (my $l = BS ; $l < $length ; $l += BS) { |
192 for (my $l = BS; $l < $length; $l += BS) { |
199 my $b = int(($offset + $l) / BS); |
193 my $b = int(($offset + $l)/BS); |
200 if ($DIRTY{ $finfo . $b }) { |
194 if ($DIRTY{$finfo . $b}) { |
201 $length = $l; |
195 $length = $l; |
202 last; |
196 last; |
203 } |
197 } |
204 } |
198 } |
205 |
199 |
206 $debug->("=== $length\n"); |
200 $debug->("=== $length\n"); |
207 $debug->( |
201 $debug->("+++ disk offset:$block*$finfo->{meta}{blocksize} + $blockoffset size:$length\n"); |
208 "+++ disk offset:$block*$finfo->{meta}{blocksize} + $blockoffset size:$length\n" |
|
209 ); |
202 |
210 |
203 my $fn = "$DATA/" . $finfo->{blocklist}{$block}; |
211 my $fn = "$DATA/" . $finfo->{blocklist}{$block}; |
204 |
212 |
205 state %cache; |
213 state %cache; |
206 if (not defined $cache{fn} |
214 if (not defined $cache{fn} |
207 or ($cache{fn} ne $fn)) { |
215 or ($cache{fn} ne $fn)) |
208 |
216 { |
209 if (-e $fn) { |
217 |
210 open(my $fh => $fn); |
218 if (-e $fn) { |
211 binmode($fh); |
219 open(my $fh => $fn); |
212 local $/ = undef; |
220 binmode($fh); |
213 $cache{data} = <$fh>; |
221 local $/ = undef; |
214 } |
222 $cache{data} = <$fh>; |
215 elsif (-e "$fn.gz") { |
223 } |
216 open(my $fh => "$fn.gz"); |
224 elsif (-e "$fn.gz") { |
217 binmode($fh); |
225 open(my $fh => "$fn.gz"); |
218 gunzip($fh => \$cache{data}) |
226 binmode($fh); |
219 or die $GunzipError; |
227 gunzip($fh => \$cache{data}) |
220 } |
228 or die $GunzipError; |
221 $cache{fn} = $fn; |
229 } |
222 } |
230 $cache{fn} = $fn; |
223 |
231 } |
224 return substr($cache{data}, $blockoffset, $size); |
232 |
225 die "$fn: $!\n"; |
233 return substr($cache{data}, $blockoffset, $size); |
226 |
234 die "$fn: $!\n"; |
|
235 |
227 } |
236 } |
228 |
237 |
229 sub writebuffer { |
238 sub writebuffer { |
230 my $path = $IDX . shift; |
239 my $path = $IDX . shift; |
231 my ($buffer, $offset) = @_; |
240 my ($buffer, $offset) = @_; |
244 return $size; |
253 return $size; |
245 } |
254 } |
246 |
255 |
247 sub _writeblock { |
256 sub _writeblock { |
248 my ($finfo, $buffer, $offset) = @_; |
257 my ($finfo, $buffer, $offset) = @_; |
249 my ($block, $blockoffset, $length); |
258 my ($block, $blockoffset, $length); |
250 my $size = length($buffer); |
259 my $size = length($buffer); |
251 |
260 |
252 $block = int($offset / BS); |
261 $block = int($offset / BS); |
253 $blockoffset = $offset % BS; |
262 $blockoffset = $offset % BS; |
254 $length = min(BS - $blockoffset, $size); |
263 $length = min(BS - $blockoffset, $size); |
255 |
264 |
256 $debug->(">>> offset:$offset size:$length of $size\n"); |
265 $debug->(">>> offset:$offset size:$length of $size\n"); |
257 $debug->(" block @{[int($offset/BS)]} + @{[$offset % BS]}\n"); |
266 $debug->(" block @{[int($offset/BS)]} + @{[$offset % BS]}\n"); |
258 |
267 |
259 if (not exists $DIRTY{ $finfo . $block }) { |
268 if (not exists $DIRTY{ $finfo . $block }) { |
260 $debug->("+++ missing $block+$blockoffset\n"); |
269 $debug->("+++ missing $block+$blockoffset\n"); |
261 $DIRTY{ $finfo . $block } = _readblock( |
270 $DIRTY{ $finfo . $block } = _readblock($finfo, BS, $block * BS); |
262 $finfo, BS, $block * BS); |
|
263 } |
271 } |
264 |
272 |
265 substr($DIRTY{ $finfo . $block }, $blockoffset, $length) = |
273 substr($DIRTY{ $finfo . $block }, $blockoffset, $length) = |
266 substr($buffer, 0, $length); |
274 substr($buffer, 0, $length); |
267 |
275 |