}
}
}
/// Allocate many contiguous pages, return the first one
fn alloc_contiguous(&mut self, length: u64) -> Result<MutPage, Error> {
// Check that length is a multiple of the page size.
assert_eq!(length & (PAGE_SIZE as u64 - 1), 0);
self.free_owned_pages.sort_by(|a, b| b.cmp(a));
self.initial_free.sort_by(|a, b| b.cmp(a));
let mut i = self.free_owned_pages.len();
let mut ni = 0;
let mut j = self.initial_free.len();
let mut nj = 0;
let mut result = 0u64;
let mut current = 0u64;
let mut current_p = std::ptr::null_mut();
while current + PAGE_SIZE as u64 - result < length {
// page allocated, consumed in i, consumed in j
let (m, ic, jc) = if i > 0 && j > 0 {
let a = self.free_owned_pages[i - 1];
let b = self.initial_free[j - 1];
if a < b {
i -= 1;
(a, 1, 0)
} else {
j -= 1;
(b, 0, 1)
}
} else if i > 0 {
i -= 1;
(self.free_owned_pages[i], 1, 0)
} else if j > 0 {
j -= 1;
let p = self.initial_free[j];
// Check whether p is available for all txns
if !self.free_for_all(p)? {
// Reset the current block, no free page was consumed.
ni = 0;
nj = 0;
current = result;
current_p = unsafe { self.env.borrow().find_offset(current)? };
continue;
}
(p, 0, 1)
} else if current == result {
// No current region, and we've reached the end of the file, just allocate there.
let offset = self.length;
let data = unsafe { self.env.borrow().find_offset(offset)? };
self.length += length;
return Ok(MutPage(CowPage { offset, data }));
} else if current + PAGE_SIZE as u64 == self.length {
// We've reached the end of the file, grow just one last time.
self.length += length - (current + PAGE_SIZE as u64 - result);
break;
} else {
unreachable!()
};
if current > 0 && m == current + PAGE_SIZE as u64 {
// We only have to check whether `current` is actually
// contiguous in terms of pointers.
let next_p = unsafe { self.env.borrow().find_offset(m)? };
if next_p as usize == current_p as usize + PAGE_SIZE {
ni += ic;
nj += jc;
} else {
// `m` is the first page in a new map, reset the block
result = m;
ni = ic;
nj = jc;
}
current = m;
current_p = next_p
} else {
// Initial region
result = m;
current = m;
current_p = unsafe { self.env.borrow().find_offset(m)? };
ni = ic;
nj = jc;