mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-16 23:34:11 +00:00
Fix entity map drop behavior
The entity map needs to be able to distinguish between the case when
the entity_id is waiting to be dropped, and when it is completely gone.
Before 8bc207141
, it assumed that entity_ids in dropped_entity_ids could
be re-used. This caused `take_dropped` to error because the slot had
been overwritten. The fix there caused weak handles to allow upgrading
a reference count from 0, which could resurrect items in
`dropped_entity_ids` which caused them to be dropped twice.
We could allow weak items to upgrade from 0, and delete from
dropped_entity_ids, but that seemed more complicated than necessary.
This commit is contained in:
parent
adc426b668
commit
3e5379526e
1 changed files with 72 additions and 6 deletions
|
@ -106,7 +106,12 @@ impl EntityMap {
|
||||||
dropped_entity_ids
|
dropped_entity_ids
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|entity_id| {
|
.map(|entity_id| {
|
||||||
ref_counts.counts.remove(entity_id);
|
let count = ref_counts.counts.remove(entity_id).unwrap();
|
||||||
|
debug_assert_eq!(
|
||||||
|
count.load(SeqCst),
|
||||||
|
0,
|
||||||
|
"dropped an entity that was referenced"
|
||||||
|
);
|
||||||
(entity_id, self.entities.remove(entity_id).unwrap())
|
(entity_id, self.entities.remove(entity_id).unwrap())
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -356,11 +361,15 @@ impl AnyWeakHandle {
|
||||||
|
|
||||||
pub fn upgrade(&self) -> Option<AnyHandle> {
|
pub fn upgrade(&self) -> Option<AnyHandle> {
|
||||||
let entity_map = self.entity_ref_counts.upgrade()?;
|
let entity_map = self.entity_ref_counts.upgrade()?;
|
||||||
entity_map
|
let entity_map = entity_map.read();
|
||||||
.read()
|
let ref_count = entity_map.counts.get(self.entity_id)?;
|
||||||
.counts
|
|
||||||
.get(self.entity_id)?
|
// entity_id is in dropped_entity_ids
|
||||||
.fetch_add(1, SeqCst);
|
if ref_count.load(SeqCst) == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
ref_count.fetch_add(1, SeqCst);
|
||||||
|
|
||||||
Some(AnyHandle {
|
Some(AnyHandle {
|
||||||
entity_id: self.entity_id,
|
entity_id: self.entity_id,
|
||||||
entity_type: self.entity_type,
|
entity_type: self.entity_type,
|
||||||
|
@ -460,3 +469,60 @@ impl<T> PartialEq<Handle<T>> for WeakHandle<T> {
|
||||||
self.entity_id() == other.entity_id()
|
self.entity_id() == other.entity_id()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::EntityMap;
|
||||||
|
|
||||||
|
struct TestEntity {
|
||||||
|
pub i: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_entity_map_slot_assignment_before_cleanup() {
|
||||||
|
// Tests that slots are not re-used before take_dropped.
|
||||||
|
let mut entity_map = EntityMap::new();
|
||||||
|
|
||||||
|
let slot = entity_map.reserve::<TestEntity>();
|
||||||
|
entity_map.insert(slot, TestEntity { i: 1 });
|
||||||
|
|
||||||
|
let slot = entity_map.reserve::<TestEntity>();
|
||||||
|
entity_map.insert(slot, TestEntity { i: 2 });
|
||||||
|
|
||||||
|
let dropped = entity_map.take_dropped();
|
||||||
|
assert_eq!(dropped.len(), 2);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
dropped
|
||||||
|
.into_iter()
|
||||||
|
.map(|(_, entity)| entity.downcast::<TestEntity>().unwrap().i)
|
||||||
|
.collect::<Vec<i32>>(),
|
||||||
|
vec![1, 2],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_entity_map_weak_upgrade_before_cleanup() {
|
||||||
|
// Tests that weak handles are not upgraded before take_dropped
|
||||||
|
let mut entity_map = EntityMap::new();
|
||||||
|
|
||||||
|
let slot = entity_map.reserve::<TestEntity>();
|
||||||
|
let handle = entity_map.insert(slot, TestEntity { i: 1 });
|
||||||
|
let weak = handle.downgrade();
|
||||||
|
drop(handle);
|
||||||
|
|
||||||
|
let strong = weak.upgrade();
|
||||||
|
assert_eq!(strong, None);
|
||||||
|
|
||||||
|
let dropped = entity_map.take_dropped();
|
||||||
|
assert_eq!(dropped.len(), 1);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
dropped
|
||||||
|
.into_iter()
|
||||||
|
.map(|(_, entity)| entity.downcast::<TestEntity>().unwrap().i)
|
||||||
|
.collect::<Vec<i32>>(),
|
||||||
|
vec![1],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue