Refactor proto::streams::store indices
- Removes incrementing counter, instead just using the StreamId as a slab ABA guard. - Adjusts Ptr::deref to use Store::index, as before it was skipping to check the ABA guard. - Rename fields and types to clarify it actually is an ABA guard. - Improve panic message in case a dangling Ptr is accessed.
This commit is contained in:
@@ -11,9 +11,8 @@ use std::ops;
|
|||||||
/// Storage for streams
|
/// Storage for streams
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct Store {
|
pub(super) struct Store {
|
||||||
slab: slab::Slab<(StoreId, Stream)>,
|
slab: slab::Slab<Stream>,
|
||||||
ids: IndexMap<StreamId, (usize, StoreId)>,
|
ids: IndexMap<StreamId, SlabIndex>,
|
||||||
counter: StoreId,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// "Pointer" to an entry in the store
|
/// "Pointer" to an entry in the store
|
||||||
@@ -25,11 +24,14 @@ pub(super) struct Ptr<'a> {
|
|||||||
/// References an entry in the store.
|
/// References an entry in the store.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub(crate) struct Key {
|
pub(crate) struct Key {
|
||||||
index: usize,
|
index: SlabIndex,
|
||||||
store_id: StoreId,
|
/// Keep the stream ID in the key as an ABA guard, since slab indices
|
||||||
|
/// could be re-used with a new stream.
|
||||||
|
stream_id: StreamId,
|
||||||
}
|
}
|
||||||
|
|
||||||
type StoreId = usize;
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
struct SlabIndex(usize);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct Queue<N> {
|
pub(super) struct Queue<N> {
|
||||||
@@ -62,13 +64,12 @@ pub(super) enum Entry<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct OccupiedEntry<'a> {
|
pub(super) struct OccupiedEntry<'a> {
|
||||||
ids: indexmap::map::OccupiedEntry<'a, StreamId, (usize, StoreId)>,
|
ids: indexmap::map::OccupiedEntry<'a, StreamId, SlabIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct VacantEntry<'a> {
|
pub(super) struct VacantEntry<'a> {
|
||||||
ids: indexmap::map::VacantEntry<'a, StreamId, (usize, StoreId)>,
|
ids: indexmap::map::VacantEntry<'a, StreamId, SlabIndex>,
|
||||||
slab: &'a mut slab::Slab<(StoreId, Stream)>,
|
slab: &'a mut slab::Slab<Stream>,
|
||||||
counter: &'a mut usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) trait Resolve {
|
pub(super) trait Resolve {
|
||||||
@@ -82,35 +83,32 @@ impl Store {
|
|||||||
Store {
|
Store {
|
||||||
slab: slab::Slab::new(),
|
slab: slab::Slab::new(),
|
||||||
ids: IndexMap::new(),
|
ids: IndexMap::new(),
|
||||||
counter: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_mut(&mut self, id: &StreamId) -> Option<Ptr> {
|
pub fn find_mut(&mut self, id: &StreamId) -> Option<Ptr> {
|
||||||
let key = match self.ids.get(id) {
|
let index = match self.ids.get(id) {
|
||||||
Some(key) => *key,
|
Some(key) => *key,
|
||||||
None => return None,
|
None => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(Ptr {
|
Some(Ptr {
|
||||||
key: Key {
|
key: Key {
|
||||||
index: key.0,
|
index,
|
||||||
store_id: key.1,
|
stream_id: *id,
|
||||||
},
|
},
|
||||||
store: self,
|
store: self,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, id: StreamId, val: Stream) -> Ptr {
|
pub fn insert(&mut self, id: StreamId, val: Stream) -> Ptr {
|
||||||
let store_id = self.counter;
|
let index = SlabIndex(self.slab.insert(val));
|
||||||
self.counter = self.counter.wrapping_add(1);
|
assert!(self.ids.insert(id, index).is_none());
|
||||||
let key = self.slab.insert((store_id, val));
|
|
||||||
assert!(self.ids.insert(id, (key, store_id)).is_none());
|
|
||||||
|
|
||||||
Ptr {
|
Ptr {
|
||||||
key: Key {
|
key: Key {
|
||||||
index: key,
|
index,
|
||||||
store_id,
|
stream_id: id,
|
||||||
},
|
},
|
||||||
store: self,
|
store: self,
|
||||||
}
|
}
|
||||||
@@ -126,7 +124,6 @@ impl Store {
|
|||||||
Vacant(e) => Entry::Vacant(VacantEntry {
|
Vacant(e) => Entry::Vacant(VacantEntry {
|
||||||
ids: e,
|
ids: e,
|
||||||
slab: &mut self.slab,
|
slab: &mut self.slab,
|
||||||
counter: &mut self.counter,
|
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,12 +137,15 @@ impl Store {
|
|||||||
|
|
||||||
while i < len {
|
while i < len {
|
||||||
// Get the key by index, this makes the borrow checker happy
|
// Get the key by index, this makes the borrow checker happy
|
||||||
let key = *self.ids.get_index(i).unwrap().1;
|
let (stream_id, index) = {
|
||||||
|
let entry = self.ids.get_index(i).unwrap();
|
||||||
|
(*entry.0, *entry.1)
|
||||||
|
};
|
||||||
|
|
||||||
f(Ptr {
|
f(Ptr {
|
||||||
key: Key {
|
key: Key {
|
||||||
index: key.0,
|
index,
|
||||||
store_id: key.1,
|
stream_id,
|
||||||
},
|
},
|
||||||
store: self,
|
store: self,
|
||||||
})?;
|
})?;
|
||||||
@@ -178,17 +178,23 @@ impl ops::Index<Key> for Store {
|
|||||||
type Output = Stream;
|
type Output = Stream;
|
||||||
|
|
||||||
fn index(&self, key: Key) -> &Self::Output {
|
fn index(&self, key: Key) -> &Self::Output {
|
||||||
let slot = self.slab.index(key.index);
|
self.slab
|
||||||
assert_eq!(slot.0, key.store_id);
|
.get(key.index.0)
|
||||||
&slot.1
|
.filter(|s| s.id == key.stream_id)
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
panic!("dangling store key for stream_id={:?}", key.stream_id);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::IndexMut<Key> for Store {
|
impl ops::IndexMut<Key> for Store {
|
||||||
fn index_mut(&mut self, key: Key) -> &mut Self::Output {
|
fn index_mut(&mut self, key: Key) -> &mut Self::Output {
|
||||||
let slot = self.slab.index_mut(key.index);
|
self.slab
|
||||||
assert_eq!(slot.0, key.store_id);
|
.get_mut(key.index.0)
|
||||||
&mut slot.1
|
.filter(|s| s.id == key.stream_id)
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
panic!("dangling store key for stream_id={:?}", key.stream_id);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,10 +335,12 @@ impl<'a> Ptr<'a> {
|
|||||||
/// Remove the stream from the store
|
/// Remove the stream from the store
|
||||||
pub fn remove(self) -> StreamId {
|
pub fn remove(self) -> StreamId {
|
||||||
// The stream must have been unlinked before this point
|
// The stream must have been unlinked before this point
|
||||||
debug_assert!(!self.store.ids.contains_key(&self.id));
|
debug_assert!(!self.store.ids.contains_key(&self.key.stream_id));
|
||||||
|
|
||||||
// Remove the stream state
|
// Remove the stream state
|
||||||
self.store.slab.remove(self.key.index).1.id
|
let stream = self.store.slab.remove(self.key.index.0);
|
||||||
|
assert_eq!(stream.id, self.key.stream_id);
|
||||||
|
stream.id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove the StreamId -> stream state association.
|
/// Remove the StreamId -> stream state association.
|
||||||
@@ -340,7 +348,7 @@ impl<'a> Ptr<'a> {
|
|||||||
/// This will effectively remove the stream as far as the H2 protocol is
|
/// This will effectively remove the stream as far as the H2 protocol is
|
||||||
/// concerned.
|
/// concerned.
|
||||||
pub fn unlink(&mut self) {
|
pub fn unlink(&mut self) {
|
||||||
let id = self.id;
|
let id = self.key.stream_id;
|
||||||
self.store.ids.remove(&id);
|
self.store.ids.remove(&id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -358,13 +366,13 @@ impl<'a> ops::Deref for Ptr<'a> {
|
|||||||
type Target = Stream;
|
type Target = Stream;
|
||||||
|
|
||||||
fn deref(&self) -> &Stream {
|
fn deref(&self) -> &Stream {
|
||||||
&self.store.slab[self.key.index].1
|
&self.store[self.key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ops::DerefMut for Ptr<'a> {
|
impl<'a> ops::DerefMut for Ptr<'a> {
|
||||||
fn deref_mut(&mut self) -> &mut Stream {
|
fn deref_mut(&mut self) -> &mut Stream {
|
||||||
&mut self.store.slab[self.key.index].1
|
&mut self.store[self.key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,10 +386,11 @@ impl<'a> fmt::Debug for Ptr<'a> {
|
|||||||
|
|
||||||
impl<'a> OccupiedEntry<'a> {
|
impl<'a> OccupiedEntry<'a> {
|
||||||
pub fn key(&self) -> Key {
|
pub fn key(&self) -> Key {
|
||||||
let tup = self.ids.get();
|
let stream_id = *self.ids.key();
|
||||||
|
let index = *self.ids.get();
|
||||||
Key {
|
Key {
|
||||||
index: tup.0,
|
index,
|
||||||
store_id: tup.1,
|
stream_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -391,16 +400,15 @@ impl<'a> OccupiedEntry<'a> {
|
|||||||
impl<'a> VacantEntry<'a> {
|
impl<'a> VacantEntry<'a> {
|
||||||
pub fn insert(self, value: Stream) -> Key {
|
pub fn insert(self, value: Stream) -> Key {
|
||||||
// Insert the value in the slab
|
// Insert the value in the slab
|
||||||
let store_id = *self.counter;
|
let stream_id = value.id;
|
||||||
*self.counter = store_id.wrapping_add(1);
|
let index = SlabIndex(self.slab.insert(value));
|
||||||
let index = self.slab.insert((store_id, value));
|
|
||||||
|
|
||||||
// Insert the handle in the ID map
|
// Insert the handle in the ID map
|
||||||
self.ids.insert((index, store_id));
|
self.ids.insert(index);
|
||||||
|
|
||||||
Key {
|
Key {
|
||||||
index,
|
index,
|
||||||
store_id,
|
stream_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user