Simplify allocation strategy for now

Not having `unsafe_no_drop_flag` caused some weirdness with optimizing buffers
and bytes. For now, remeove it.
This commit is contained in:
Carl Lerche
2016-08-11 01:36:16 -07:00
parent 04e0ac75e2
commit fbebb19a02
11 changed files with 144 additions and 302 deletions
+13 -28
View File
@@ -16,32 +16,14 @@ pub struct AppendBuf {
impl AppendBuf {
pub fn with_capacity(mut capacity: u32) -> AppendBuf {
// Handle 0 capacity case
if capacity == 0 {
return AppendBuf::none();
}
// Round the capacity to the closest power of 2
capacity = capacity.next_power_of_two();
// Allocate the memory
let mem = alloc::heap(capacity as usize);
unsafe {
// Allocate the memory
let mem = alloc::heap(capacity as usize);
// If the allocation failed, return a blank buf
if mem.is_none() {
return AppendBuf::none();
}
unsafe { AppendBuf::from_mem_ref(mem, capacity, 0) }
}
/// Returns an AppendBuf with no capacity
pub fn none() -> AppendBuf {
AppendBuf {
mem: alloc::MemRef::none(),
rd: Cell::new(0),
wr: 0,
cap: 0,
AppendBuf::from_mem_ref(mem, capacity, 0)
}
}
@@ -73,6 +55,7 @@ impl AppendBuf {
pub fn shift(&self, n: usize) -> Bytes {
let ret = self.slice(0, n);
self.rd.set(self.rd.get() + ret.len() as u32);
assert!(self.rd.get() <= self.wr, "buffer overflow");
ret
}
@@ -82,13 +65,15 @@ impl AppendBuf {
}
pub fn slice(&self, begin: usize, end: usize) -> Bytes {
let rd = self.rd.get() as usize;
let wr = self.wr as usize;
// TODO: Fix overflow potential
assert!(begin <= end && end <= wr - rd, "invalid range");
let rd = self.rd.get();
let wr = self.wr;
let begin = (begin + rd) as u32;
let end = (end + rd) as u32;
let begin = begin as u32 + rd;
let end = end as u32 + rd;
assert!(begin <= end && end <= wr, "invalid range");
unsafe { Bytes::from_mem_ref(self.mem.clone(), begin, end - begin) }
}
@@ -111,7 +96,7 @@ impl MutBuf for AppendBuf {
self.wr += cnt as u32;
if self.wr > self.cap {
self.wr = self.cap;
panic!("buffer overflow");
}
}
+70 -24
View File
@@ -1,7 +1,7 @@
#![allow(warnings)]
use {Buf, MutBuf, AppendBuf, Bytes};
use alloc::{self, Pool};
use alloc::{self, /* Pool */};
use std::{cmp, ptr, slice};
use std::io::Cursor;
use std::rc::Rc;
@@ -19,9 +19,9 @@ pub struct BlockBuf {
new_block: NewBlock,
}
pub enum NewBlock {
enum NewBlock {
Heap(usize),
Pool(Rc<Pool>),
// Pool(Rc<Pool>),
}
pub struct BlockBufCursor<'a> {
@@ -37,9 +37,11 @@ pub struct BlockBufCursor<'a> {
//
impl BlockBuf {
/// Create BlockBuf
pub fn new(max_blocks: usize, new_block: NewBlock) -> BlockBuf {
pub fn new(max_blocks: usize, block_size: usize) -> BlockBuf {
assert!(max_blocks > 1, "at least 2 blocks required");
let new_block = NewBlock::Heap(block_size);
BlockBuf {
len: 0,
cap: max_blocks * new_block.block_size(),
@@ -51,7 +53,7 @@ impl BlockBuf {
/// Returns the number of buffered bytes
#[inline]
pub fn len(&self) -> usize {
debug_assert!(self.len == self.blocks.iter().map(|b| b.len()).fold(0, |a, b| a+b));
debug_assert_eq!(self.len, self.blocks.iter().map(|b| b.len()).fold(0, |a, b| a+b));
self.len
}
@@ -83,9 +85,39 @@ impl BlockBuf {
/// # Panics
///
/// Panics if `n` is greater than the number of buffered bytes.
pub fn shift(&mut self, mut n: usize) -> Bytes {
#[inline]
pub fn shift(&mut self, n: usize) -> Bytes {
trace!("BlockBuf::shift; n={}", n);
// Fast path
match self.blocks.len() {
0 => {
assert!(n == 0, "buffer overflow");
Bytes::empty()
}
1 => {
let (ret, pop) = {
let block = self.blocks.front().expect("unexpected state");
let ret = block.shift(n);
self.len -= n;
(ret, self.len == 0 && !MutBuf::has_remaining(block))
};
if pop {
let _ = self.blocks.pop_front();
}
ret
}
_ => {
self.shift_multi(n)
}
}
}
fn shift_multi(&mut self, mut n: usize) -> Bytes {
let mut ret: Option<Bytes> = None;
while n > 0 {
@@ -96,11 +128,15 @@ impl BlockBuf {
let (segment, pop) = {
let block = self.blocks.front().expect("unexpected state");
let segment_n = cmp::min(n, block.len());
let block_len = block.len();
let segment_n = cmp::min(n, block_len);
n -= segment_n;
self.len -= segment_n;
(block.shift(segment_n), !MutBuf::has_remaining(block))
let pop = block_len == segment_n && !MutBuf::has_remaining(block);
(block.shift(segment_n), pop)
};
if pop {
@@ -108,13 +144,15 @@ impl BlockBuf {
}
ret = Some(match ret.take() {
Some(curr) => curr.concat(&segment),
Some(curr) => {
curr.concat(&segment)
}
None => segment,
});
}
ret.unwrap_or(Bytes::empty())
ret.unwrap_or_else(|| Bytes::empty())
}
/// Drop the first `n` buffered bytes
@@ -146,6 +184,10 @@ impl BlockBuf {
}
}
pub fn is_compact(&mut self) -> bool {
self.blocks.len() <= 1
}
/// Moves all buffered bytes into a single block.
///
/// # Panics
@@ -208,6 +250,19 @@ impl BlockBuf {
fn have_buffered_data(&self) -> bool {
self.len() > 0
}
#[inline]
fn needs_alloc(&self) -> bool {
if let Some(buf) = self.blocks.back() {
// `unallocated_blocks` is checked here because if further blocks
// cannot be allocated, an empty slice should be returned.
if MutBuf::has_remaining(buf) {
return false;
}
}
true
}
}
impl MutBuf for BlockBuf {
@@ -236,18 +291,9 @@ impl MutBuf for BlockBuf {
}
}
#[inline]
unsafe fn mut_bytes(&mut self) -> &mut [u8] {
let mut need_alloc = true;
if let Some(buf) = self.blocks.back() {
// `unallocated_blocks` is checked here because if further blocks
// cannot be allocated, an empty slice should be returned.
if MutBuf::has_remaining(buf) {
need_alloc = false
}
}
if need_alloc {
if self.needs_alloc() {
if self.blocks.len() != self.blocks.capacity() {
self.allocate_block()
}
@@ -261,7 +307,7 @@ impl MutBuf for BlockBuf {
impl Default for BlockBuf {
fn default() -> BlockBuf {
BlockBuf::new(16, NewBlock::Heap(8_192))
BlockBuf::new(16, 8_192)
}
}
@@ -307,7 +353,7 @@ impl NewBlock {
fn block_size(&self) -> usize {
match *self {
NewBlock::Heap(size) => size,
NewBlock::Pool(ref pool) => pool.buffer_len(),
// NewBlock::Pool(ref pool) => pool.buffer_len(),
}
}
@@ -315,7 +361,7 @@ impl NewBlock {
fn new_block(&self) -> Option<AppendBuf> {
match *self {
NewBlock::Heap(size) => Some(AppendBuf::with_capacity(size as u32)),
NewBlock::Pool(ref pool) => pool.new_append_buf(),
// NewBlock::Pool(ref pool) => pool.new_append_buf(),
}
}
}
+10 -28
View File
@@ -32,16 +32,6 @@ impl ByteBuf {
MutByteBuf { buf: ByteBuf::new(capacity as u32) }
}
pub fn none() -> ByteBuf {
ByteBuf {
mem: alloc::MemRef::none(),
cap: 0,
pos: 0,
lim: 0,
mark: None,
}
}
pub unsafe fn from_mem_ref(mem: alloc::MemRef, cap: u32, pos: u32, lim: u32) -> ByteBuf {
debug_assert!(pos <= lim && lim <= cap, "invalid arguments; cap={}; pos={}; lim={}", cap, pos, lim);
@@ -55,28 +45,20 @@ impl ByteBuf {
}
fn new(mut capacity: u32) -> ByteBuf {
// Handle 0 capacity case
if capacity == 0 {
return ByteBuf::none();
}
// Round the capacity to the closest power of 2
capacity = capacity.next_power_of_two();
// Allocate the memory
let mem = alloc::heap(capacity as usize);
unsafe {
// Allocate the memory
let mem = alloc::heap(capacity as usize);
// If the allocation failed, return a blank buf
if mem.is_none() {
return ByteBuf::none();
}
ByteBuf {
mem: mem,
cap: capacity,
pos: 0,
lim: capacity,
mark: None,
ByteBuf {
mem: mem,
cap: capacity,
pos: 0,
lim: capacity,
mark: None,
}
}
}
+9 -18
View File
@@ -23,29 +23,20 @@ pub struct RingBuf {
impl RingBuf {
/// Allocates a new `RingBuf` with the specified capacity.
pub fn new(mut capacity: usize) -> RingBuf {
// Handle the 0 length buffer case
if capacity == 0 {
return RingBuf {
ptr: alloc::MemRef::none(),
cap: 0,
// Round to the next power of 2 for better alignment
capacity = capacity.next_power_of_two();
unsafe {
let mem = alloc::heap(capacity as usize);
RingBuf {
ptr: mem,
cap: capacity,
pos: 0,
len: 0,
mark: Mark::NoMark,
}
}
// Round to the next power of 2 for better alignment
capacity = capacity.next_power_of_two();
let mem = alloc::heap(capacity as usize);
RingBuf {
ptr: mem,
cap: capacity,
pos: 0,
len: 0,
mark: Mark::NoMark,
}
}
/// Returns `true` if the buf cannot accept any further writes.