Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions benches/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,32 @@ fn criterion_benchmark(c: &mut Criterion) {
}
small.finish();

// streams just below the MiniFAT cutoff
let mut cutoff = c.benchmark_group("write MiniFAT max streams");
let size = (4 * 1024) - 1;
let n = 500;
let total_bytes = (n * size) as u64;
cutoff.sample_size(10);
cutoff.throughput(Throughput::Bytes(total_bytes));

for (buf, label) in buffer_sizes {
cutoff.bench_with_input(
BenchmarkId::new("total", *label),
&size,
|b, &s| {
b.iter(|| {
let out = write_many_streams(
black_box(n),
black_box(s),
buf.map(black_box),
);
black_box(out);
})
},
);
}
cutoff.finish();

// several medium streams with throughput reporting
let mut medium = c.benchmark_group("write several medium streams");
let size = 1024 * 1024usize;
Expand Down
3 changes: 3 additions & 0 deletions src/internal/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,9 @@ impl<F: Write + Seek> Allocator<F> {

/// Deallocates the specified sector.
fn free_sector(&mut self, sector_id: u32) -> io::Result<()> {
if self.fat.get(sector_id as usize) == Some(&consts::FREE_SECTOR) {
invalid_input!("sector {} freed twice", sector_id);
}
self.set_fat(sector_id, consts::FREE_SECTOR)?;
self.free_sectors.push(sector_id);
// TODO: Truncate FAT if last FAT sector is now all free.
Expand Down
31 changes: 24 additions & 7 deletions src/internal/minialloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub struct MiniAllocator<F> {
directory: Directory<F>,
minifat: Vec<u32>,
minifat_start_sector: u32,
free_mini_sectors: Vec<u32>,
}

impl<F> MiniAllocator<F> {
Expand All @@ -35,8 +36,12 @@ impl<F> MiniAllocator<F> {
minifat_start_sector: u32,
validation: Validation,
) -> io::Result<MiniAllocator<F>> {
let mut minialloc =
MiniAllocator { directory, minifat, minifat_start_sector };
let mut minialloc = MiniAllocator {
directory,
minifat,
minifat_start_sector,
free_mini_sectors: Vec::new(),
};
minialloc.validate(validation)?;
Ok(minialloc)
}
Expand Down Expand Up @@ -139,6 +144,13 @@ impl<F> MiniAllocator<F> {
pointees.insert(to_mini_sector);
}
}

self.free_mini_sectors.clear();
for (idx, &entry) in self.minifat.iter().enumerate() {
if entry == consts::FREE_SECTOR {
self.free_mini_sectors.push(idx as u32);
}
}
Ok(())
}
}
Expand Down Expand Up @@ -237,11 +249,10 @@ impl<F: Write + Seek> MiniAllocator<F> {
/// returns the new mini sector number.
fn allocate_mini_sector(&mut self, value: u32) -> io::Result<u32> {
// If there's an existing free mini sector, use that.
for mini_sector in 0..self.minifat.len() {
if self.minifat[mini_sector] == consts::FREE_SECTOR {
let mini_sector = mini_sector as u32;
self.set_minifat(mini_sector, value)?;
return Ok(mini_sector);
while let Some(free_idx) = self.free_mini_sectors.pop() {
if self.minifat[free_idx as usize] == consts::FREE_SECTOR {
self.set_minifat(free_idx, value)?;
return Ok(free_idx);
}
}
// Otherwise, we need a new mini sector; if there's not room in the
Expand Down Expand Up @@ -305,14 +316,20 @@ impl<F: Write + Seek> MiniAllocator<F> {

/// Deallocates the specified mini sector.
fn free_mini_sector(&mut self, mini_sector: u32) -> io::Result<()> {
if self.minifat[mini_sector as usize] == consts::FREE_SECTOR {
invalid_input!("sector {} freed twice", mini_sector);
}
self.set_minifat(mini_sector, consts::FREE_SECTOR)?;
self.free_mini_sectors.push(mini_sector);
let mut mini_stream_len = self.directory.root_dir_entry().stream_len;
debug_assert_eq!(mini_stream_len % consts::MINI_SECTOR_LEN as u64, 0);
while self.minifat.last() == Some(&consts::FREE_SECTOR) {
mini_stream_len -= consts::MINI_SECTOR_LEN as u64;
self.minifat.pop();
// TODO: Truncate MiniFAT if last MiniFAT sector is now all free.
}
let minifat_len = self.minifat.len();
self.free_mini_sectors.retain(|&idx| (idx as usize) < minifat_len);

if mini_stream_len != self.directory.root_dir_entry().stream_len {
self.directory.with_root_dir_entry_mut(|dir_entry| {
Expand Down