Path: blob/main/crates/bevy_ecs/src/entity/remote_allocator.rs
9356 views
//! This module contains the guts of Bevy's entity allocator.1//!2//! Entity allocation needs to work concurrently and remotely.3//! Remote allocations (where no reference to the world is held) is needed for long running tasks, such as loading assets on separate threads.4//! Non-remote, "normal" allocation needs to be as fast as possible while still supporting remote allocation.5//!6//! The allocator fundamentally is made of a cursor for the next fresh, never used [`EntityIndex`] and a free list.7//! The free list is a collection that holds [`Entity`] values that were used and can be reused; they are "free"/available.8//! If the free list is empty, it's really simple to just increment the fresh index cursor.9//! The tricky part is implementing a remotely accessible free list.10//!11//! A naive free list could just a concurrent queue.12//! That would probably be fine for remote allocation but for non-remote, we can go much faster.13//! In particular, a concurrent queue must do additional work to handle cases where something is added concurrently with being removed.14//! But for non-remote allocation, we can guarantee that no free will happen during an allocation since `free` needs mutably access to the world already.15//! That means, we can skip a lot of those safety checks.16//! Plus, we know the maximum size of the free list ahead of time, since we can assume there are no duplicates.17//! That means, we can have a much more efficient allocation scheme, far better than a linked list.18//!19//! For the free list, the list needs to be pinned in memory and yet grow-able.20//! That's quite the pickle, but by splitting the growth over multiple arrays, this isn't so bad.21//! When the list needs to grow, we just *add* on another array to the buffer (instead of *replacing* the old one with a bigger one).22//! These arrays are called [`Chunk`]s.23//! This keeps everything pinned, and since we know the maximum size ahead of time, we can make this mapping very fast.24//!25//! Similar to how `Vec` is implemented, the free list is implemented as a [`FreeBuffer`] (handling allocations and implicit capacity)26//! and the [`FreeCount`] manages the length of the free list.27//! The free list's item is a [`Slot`], which manages accessing each item concurrently.28//!29//! These types are summed up in [`SharedAllocator`], which is highly unsafe.30//! The interfaces [`Allocator`] and [`RemoteAllocator`] provide safe interfaces to them.3132use arrayvec::ArrayVec;33use bevy_platform::{34cell::SyncUnsafeCell,35prelude::{Box, Vec},36sync::{37atomic::{AtomicBool, AtomicPtr, AtomicU32, AtomicU64, Ordering},38Arc,39},40};41use core::mem::ManuallyDrop;42use log::warn;43use nonmax::NonMaxU32;4445use crate::query::DebugCheckedUnwrap;4647use super::{Entity, EntityIndex, EntitySetIterator};4849/// This is the item we store in the free list.50/// Effectively, this is a `MaybeUninit<Entity>` where uninit is represented by `Entity::PLACEHOLDER`.51struct Slot {52inner: SyncUnsafeCell<Entity>,53}5455impl Slot {56/// Produces a meaningless empty value. This is a valid but incorrect `Entity`.57/// It's valid because the bits do represent a valid bit pattern of an `Entity`.58/// It's incorrect because this is in the free buffer even though the entity was never freed.59/// Importantly, [`FreeCount`] determines which part of the free buffer is the free list.60/// An empty slot may be in the free buffer, but should not be in the free list.61/// This can be thought of as the `MaybeUninit` uninit in `Vec`'s excess capacity.62const fn empty() -> Self {63let source = Entity::PLACEHOLDER;64Self {65inner: SyncUnsafeCell::new(source),66}67}6869/// Sets the entity at this slot.70///71/// # Safety72///73/// There must be a clear, strict order between this call and the previous uses of this [`Slot`].74/// Otherwise, the compiler will make unsound optimizations.75#[inline]76const unsafe fn set_entity(&self, entity: Entity) {77// SAFETY: Ensured by caller.78unsafe {79self.inner.get().write(entity);80}81}8283/// Gets the stored entity. The result will be [`Entity::PLACEHOLDER`] unless [`set_entity`](Self::set_entity) has been called.84///85/// # Safety86///87/// There must be a clear, strict order between this call and the previous uses of this [`Slot`].88/// Otherwise, the compiler will make unsound optimizations.89#[inline]90const unsafe fn get_entity(&self) -> Entity {91// SAFETY: Ensured by caller.92unsafe { self.inner.get().read() }93}94}9596/// Each chunk stores a buffer of [`Slot`]s at a fixed capacity.97struct Chunk {98/// Points to the first slot. If this is null, we need to allocate it.99first: AtomicPtr<Slot>,100}101102impl Chunk {103/// Constructs a null [`Chunk`].104const fn new() -> Self {105Self {106first: AtomicPtr::new(core::ptr::null_mut()),107}108}109110/// Gets the entity at the index within this chunk.111///112/// # Safety113///114/// [`Self::set`] must have been called on this index before, ensuring it is in bounds and the chunk is initialized.115/// There must be a clear, strict order between this call and the previous uses of this `index`.116/// Otherwise, the compiler will make unsound optimizations.117#[inline]118unsafe fn get(&self, index: u32) -> Entity {119// Relaxed is fine since caller has already assured memory ordering is satisfied.120let head = self.first.load(Ordering::Relaxed);121// SAFETY: caller ensures we are in bounds and init (because `set` must be in bounds)122let target = unsafe { &*head.add(index as usize) };123// SAFETY: Caller ensures ordering.124unsafe { target.get_entity() }125}126127/// Gets a slice of indices.128///129/// # Safety130///131/// [`Self::set`] must have been called on these indices before, ensuring it is in bounds and the chunk is initialized.132#[inline]133unsafe fn get_slice(&self, index: u32, ideal_len: u32, chunk_capacity: u32) -> &[Slot] {134let after_index_slice_len = chunk_capacity - index;135let len = after_index_slice_len.min(ideal_len) as usize;136137// Relaxed is fine since caller ensures we are initialized already.138// In order for the caller to guarantee that, they must have an ordering that orders this `get` after the required `set`.139let head = self.first.load(Ordering::Relaxed);140141// SAFETY: Caller ensures we are init, so the chunk was allocated via a `Vec` and the index is within the capacity.142unsafe { core::slice::from_raw_parts(head.add(index as usize), len) }143}144145/// Sets this entity at this index.146///147/// # Safety148///149/// Index must be in bounds.150/// There must be a clear, strict order between this call and the previous uses of this `index`.151/// Otherwise, the compiler will make unsound optimizations.152/// This must not be called on the same chunk concurrently.153#[inline]154unsafe fn set(&self, index: u32, entity: Entity, chunk_capacity: u32) {155// Relaxed is fine here since the caller ensures memory ordering.156let ptr = self.first.load(Ordering::Relaxed);157let head = if ptr.is_null() {158// SAFETY: Ensured by caller.159unsafe { self.init(chunk_capacity) }160} else {161ptr162};163164// SAFETY: caller ensures it is in bounds and we are not fighting with other `set` calls or `get` calls.165// A race condition is therefore impossible.166// The address can't wrap or pass isize max since this addition is within an allocation.167// For that to happen, you would first run out of memory in practice.168let target = unsafe { &*head.add(index as usize) };169170// SAFETY: Ensured by caller.171unsafe {172target.set_entity(entity);173}174}175176/// Initializes the chunk to be valid, returning the pointer.177///178/// # Safety179///180/// This must not be called concurrently with itself.181#[cold]182unsafe fn init(&self, chunk_capacity: u32) -> *mut Slot {183let mut buff = ManuallyDrop::new(Vec::new());184buff.reserve_exact(chunk_capacity as usize);185buff.resize_with(chunk_capacity as usize, Slot::empty);186let ptr = buff.as_mut_ptr();187// Relaxed is fine here since this is not called concurrently.188self.first.store(ptr, Ordering::Relaxed);189ptr190}191192/// Frees memory193///194/// # Safety195///196/// `chunk_capacity` must be the same as it was initialized with.197unsafe fn dealloc(&mut self, chunk_capacity: u32) {198let to_drop = *self.first.get_mut();199if !to_drop.is_null() {200// SAFETY: This was created in [`Self::init`] from a standard Vec.201unsafe {202Vec::from_raw_parts(to_drop, chunk_capacity as usize, chunk_capacity as usize);203}204}205}206}207208/// This is a buffer that has been split into power-of-two sized chunks, so that each chunk is pinned in memory.209/// Conceptually, each chunk is put end-to-end to form the buffer. This ultimately avoids copying elements on resize,210/// while allowing it to expand in capacity as needed. A separate system must track the length of the list in the buffer.211/// Each chunk is twice as large as the last, except for the first two which have a capacity of 512.212struct FreeBuffer([Chunk; Self::NUM_CHUNKS as usize]);213214impl FreeBuffer {215const NUM_CHUNKS: u32 = 24;216const NUM_SKIPPED: u32 = u32::BITS - Self::NUM_CHUNKS;217218/// Constructs an empty [`FreeBuffer`].219const fn new() -> Self {220Self([const { Chunk::new() }; Self::NUM_CHUNKS as usize])221}222223/// Computes the capacity of the chunk at this index within [`Self::NUM_CHUNKS`].224/// The first 2 have length 512 (2^9) and the last has length (2^31)225#[inline]226const fn capacity_of_chunk(chunk_index: u32) -> u32 {227// We do this because we're skipping the first `NUM_SKIPPED` powers, so we need to make up for them by doubling the first index.228// This is why the first 2 indices both have a capacity of 512.229let corrected = if chunk_index == 0 { 1 } else { chunk_index };230// We add NUM_SKIPPED because the total capacity should be as if [`Self::NUM_CHUNKS`] were 32.231// This skips the first NUM_SKIPPED powers.232let corrected = corrected + Self::NUM_SKIPPED;233// This bit shift is just 2^corrected.2341 << corrected235}236237/// For this index in the whole buffer, returns the index of the [`Chunk`], the index within that chunk, and the capacity of that chunk.238#[inline]239const fn index_info(full_index: u32) -> (u32, u32, u32) {240// We do a `saturating_sub` because we skip the first `NUM_SKIPPED` powers to make space for the first chunk's entity count.241// The -1 is because this is the number of chunks, but we want the index in the end.242// We store chunks in smallest to biggest order, so we need to reverse it.243let chunk_index = (Self::NUM_CHUNKS - 1).saturating_sub(full_index.leading_zeros());244let chunk_capacity = Self::capacity_of_chunk(chunk_index);245// We only need to cut off this particular bit.246// The capacity is only one bit, and if other bits needed to be dropped, `leading` would have been greater247let index_in_chunk = full_index & !chunk_capacity;248249(chunk_index, index_in_chunk, chunk_capacity)250}251252/// For this index in the whole buffer, returns the [`Chunk`], the index within that chunk, and the capacity of that chunk.253#[inline]254fn index_in_chunk(&self, full_index: u32) -> (&Chunk, u32, u32) {255let (chunk_index, index_in_chunk, chunk_capacity) = Self::index_info(full_index);256// SAFETY: The `index_info` is correct.257let chunk = unsafe { self.0.get_unchecked(chunk_index as usize) };258(chunk, index_in_chunk, chunk_capacity)259}260261/// Gets the entity at an index.262///263/// # Safety264///265/// [`set`](Self::set) must have been called on this index to initialize its memory.266/// There must be a clear, strict order between this call and the previous uses of this `full_index`.267/// Otherwise, the compiler will make unsound optimizations.268unsafe fn get(&self, full_index: u32) -> Entity {269let (chunk, index, _) = self.index_in_chunk(full_index);270// SAFETY: Ensured by caller.271unsafe { chunk.get(index) }272}273274/// Sets an entity at an index.275///276/// # Safety277///278/// There must be a clear, strict order between this call and the previous uses of this `full_index`.279/// Otherwise, the compiler will make unsound optimizations.280/// This must not be called on the same buffer concurrently.281#[inline]282unsafe fn set(&self, full_index: u32, entity: Entity) {283let (chunk, index, chunk_capacity) = self.index_in_chunk(full_index);284// SAFETY: Ensured by caller and that the index is correct.285unsafe { chunk.set(index, entity, chunk_capacity) }286}287288/// Iterates the entities in these indices.289///290/// # Safety291///292/// [`Self::set`] must have been called on these indices before to initialize memory.293/// There must be a clear, strict order between this call and the previous uses of these `indices`.294/// Note that until the returned value is dropped, these `indices` are still being accessed,295/// making safety for other operations afterward need careful justification.296/// Otherwise, the compiler will make unsound optimizations.297#[inline]298unsafe fn iter(&self, indices: core::ops::Range<u32>) -> FreeBufferIterator<'_> {299FreeBufferIterator {300buffer: self,301future_buffer_indices: indices,302current_chunk_slice: [].iter(),303}304}305}306307impl Drop for FreeBuffer {308fn drop(&mut self) {309for index in 0..Self::NUM_CHUNKS {310let capacity = Self::capacity_of_chunk(index);311// SAFETY: we have `&mut` and the capacity is correct.312unsafe { self.0[index as usize].dealloc(capacity) };313}314}315}316317/// An iterator over a [`FreeBuffer`].318///319/// # Safety320///321/// [`FreeBuffer::set`] must have been called on these indices beforehand to initialize memory.322struct FreeBufferIterator<'a> {323buffer: &'a FreeBuffer,324/// The part of the buffer we are iterating at the moment.325current_chunk_slice: core::slice::Iter<'a, Slot>,326/// The indices in the buffer that are not yet in `current_chunk_slice`.327future_buffer_indices: core::ops::Range<u32>,328}329330impl<'a> Iterator for FreeBufferIterator<'a> {331type Item = Entity;332333#[inline]334fn next(&mut self) -> Option<Self::Item> {335if let Some(found) = self.current_chunk_slice.next() {336// SAFETY: We have `&mut self`, so that memory order is certain.337// The caller of `FreeBuffer::iter` ensures the memory order of this value's lifetime.338return Some(unsafe { found.get_entity() });339}340341let still_need = self.future_buffer_indices.len() as u32;342if still_need == 0 {343return None;344}345let next_index = self.future_buffer_indices.start;346let (chunk, index, chunk_capacity) = self.buffer.index_in_chunk(next_index);347348// SAFETY: Assured by `FreeBuffer::iter`349let slice = unsafe { chunk.get_slice(index, still_need, chunk_capacity) };350self.future_buffer_indices.start += slice.len() as u32;351self.current_chunk_slice = slice.iter();352353// SAFETY: Constructor ensures these indices are valid in the buffer; the buffer is not sparse, and we just got the next slice.354// So the only way for the slice to be empty is if the constructor did not uphold safety.355let next = unsafe { self.current_chunk_slice.next().debug_checked_unwrap() };356// SAFETY: We have `&mut self`, so that memory order is certain.357// The caller of `FreeBuffer::iter` ensures the memory order of this value's lifetime.358Some(unsafe { next.get_entity() })359}360361#[inline]362fn size_hint(&self) -> (usize, Option<usize>) {363let len = self.future_buffer_indices.len() + self.current_chunk_slice.len();364(len, Some(len))365}366}367368impl<'a> ExactSizeIterator for FreeBufferIterator<'a> {}369impl<'a> core::iter::FusedIterator for FreeBufferIterator<'a> {}370371/// This tracks the state of a [`FreeCount`], which has lots of information packed into it.372///373/// This has three jobs:374///375/// - First, obviously, this needs to track the length of the free list.376/// When the length is 0, we use the [`FreshAllocator`]; otherwise, we pop.377/// The length also tells us where on the list to push freed entities to.378/// - Second, we need to be able to "freeze" the length for remote allocations.379/// This happens when pushing to the list; we need to prevent a push and remote pop from happening at the same time.380/// We call this "disabling the length".381/// When it is disabled, only the thing that disabled it is allowed to re-enable it.382/// This is like a mutex, but it's faster because we pack the mutex into the same bits as the state.383/// See [`FreeCount::disable_len_for_state`] and [`FreeCount::set_state_risky`] for how this can be done.384/// - Third, we need to track the generation of the free list.385/// That is, any two distinct states of the free list, even if they are the same length, must have different [`FreeCount`] values.386/// This becomes important when a remote allocator needs to know if the information it is working with has been outdated.387/// See [`FreeList::remote_alloc`] for why this is so important.388///389/// As if that isn't hard enough, we need to do all three of these things in the same [`AtomicU64`] for performance.390/// Not only that, but for memory ordering guarantees, we need to be able to change the length and generation in a single atomic operation.391/// We do that with a very specific bit layout:392///393/// - The least significant 33 bits store a signed 33 bit integer for the length.394/// This behaves like a u33, but we define `1 << 32` as 0.395/// - The 34th bit stores a flag that indicates if the length has been disabled.396/// - The remaining 30 bits are the generation.397/// The generation helps differentiates different versions of the state that happen to encode the same length.398///399/// Why this layout?400/// A few observations:401/// First, since the disabling mechanic acts as a mutex, we only need one bit for that, and we can use bit operations to interact with it.402/// That leaves the length and the generation (which we need to distinguish between two states of the free list that happen to be the same length).403/// Every change to the length must be/cause a change to the [`FreeCountState`] such that the new state does not equal any previous state.404/// The second observation is that we only need to change the generation when we move the length in one direction.405/// Here, we tie popping/allocation to a generation change.406/// When the length increases, the length part of the state changes, so a generation change is a moot point. (Ex `L0-G0` -> `L1G0`)407/// When the length decreases, we also need to change the generation to distinguish the states. (Ex `L1-G0` -> `L0G1`)408///409/// We need the generation to freely wrap.410/// In this case, the generation is 30 bits, so after 2 ^ 30 allocations, the generation will wrap.411/// That is technically a soundness concern,412/// but it would only cause a problem if the same [`FreeList::remote_alloc`] procedure had been sleeping for all 2 ^ 30 allocations and then when it woke up, all 2 ^ 30 allocations had been freed.413/// This is impossibly unlikely and is safely ignored in other concurrent queue implementations.414/// Still, we need the generation to wrap; it must not overflow into the length bits.415/// As a result, the generation bits *must* be the most significant; this allows them to wrap freely.416///417/// It is convenient to put the disabling bit next since that leaves the length bits already aligned to the least significant bits.418/// That saves us a bit shift!419///420/// But now we need to stop the length information from messing with the generation or disabling bits.421/// Preventing overflow is easy since we can assume the list is unique and there are only `u32::MAX` [`Entity`] values.422/// We can't prevent underflow with just 32 bits, and performance prevents us from running checks before a subtraction.423/// But we do know that it can't overflow more than `u32::MAX` times because that would cause the [`FreshAllocator`] to overflow and panic for allocating too many entities.424/// That means we need to represent "length" values in `±u32::MAX` range, which gives us an `i33` that we then saturatingly cast to `u32`.425/// As mentioned above, we represent this `i33` as a `u33` where we define `1 << 32` as 0.426/// This representation works slightly easier for the `saturating_sub` in [`FreeCountState::length`] than a true `i33` representation.427#[derive(Clone, Copy)]428struct FreeCountState(u64);429430impl FreeCountState {431/// When this bit is on, the count is disabled.432/// This is used to prevent remote allocations from running at the same time as a free operation.433const DISABLING_BIT: u64 = 1 << 33;434/// This is the mask for the length bits.435const LENGTH_MASK: u64 = (1 << 32) | u32::MAX as u64;436/// This is the value of the length mask we consider to be 0.437const LENGTH_0: u64 = 1 << 32;438/// This is the lowest bit in the u30 generation.439const GENERATION_LEAST_BIT: u64 = 1 << 34;440441/// Constructs a length of 0.442const fn new_zero_len() -> Self {443Self(Self::LENGTH_0)444}445446/// Gets the encoded length.447#[inline]448const fn length(self) -> u32 {449let unsigned_length = self.0 & Self::LENGTH_MASK;450unsigned_length.saturating_sub(Self::LENGTH_0) as u32451}452453/// Returns whether or not the count is disabled.454#[inline]455const fn is_disabled(self) -> bool {456(self.0 & Self::DISABLING_BIT) > 0457}458459/// Changes only the length of this count to `length`.460#[inline]461const fn with_length(self, length: u32) -> Self {462// Just turns on the "considered zero" bit since this is non-negative.463let length = length as u64 | Self::LENGTH_0;464Self(self.0 & !Self::LENGTH_MASK | length)465}466467/// For popping `num` off the count, subtract the resulting u64.468#[inline]469const fn encode_pop(num: u32) -> u64 {470let subtract_length = num as u64;471// Also subtract one from the generation bit.472subtract_length | Self::GENERATION_LEAST_BIT473}474475/// Returns the count after popping off `num` elements.476#[inline]477const fn pop(self, num: u32) -> Self {478Self(self.0.wrapping_sub(Self::encode_pop(num)))479}480}481482/// This is an atomic interface to [`FreeCountState`].483struct FreeCount(AtomicU64);484485impl FreeCount {486/// Constructs a length of 0.487const fn new_zero_len() -> Self {488Self(AtomicU64::new(FreeCountState::new_zero_len().0))489}490491/// Gets the current state of the buffer.492#[inline]493fn state(&self, order: Ordering) -> FreeCountState {494FreeCountState(self.0.load(order))495}496497/// Subtracts `num` from the length, returning the previous state.498///499/// **NOTE:** Caller should be careful that changing the state is allowed and that the state is not disabled.500#[inline]501fn pop_for_state(&self, num: u32, order: Ordering) -> FreeCountState {502let to_sub = FreeCountState::encode_pop(num);503let raw = self.0.fetch_sub(to_sub, order);504FreeCountState(raw)505}506507/// Marks the state as disabled, returning the previous state508/// When the length is disabled, [`try_set_state`](Self::try_set_state) will fail.509/// This is used to prevent remote allocation during a free.510#[inline]511fn disable_len_for_state(&self, order: Ordering) -> FreeCountState {512// We don't care about the generation here since this changes the value anyway.513FreeCountState(self.0.fetch_or(FreeCountState::DISABLING_BIT, order))514}515516/// Sets the state explicitly.517/// Caller must be careful that the state has not changed since getting the state and setting it.518/// If that happens, the state may not properly reflect the length of the free list or its generation,519/// causing entities to be skipped or given out twice.520/// This is not a safety concern, but it is a major correctness concern.521#[inline]522fn set_state_risky(&self, state: FreeCountState, order: Ordering) {523self.0.store(state.0, order);524}525526/// Attempts to update the state, returning the new [`FreeCountState`] if it fails.527#[inline]528fn try_set_state(529&self,530expected_current_state: FreeCountState,531target_state: FreeCountState,532success: Ordering,533failure: Ordering,534) -> Result<(), FreeCountState> {535match self536.0537.compare_exchange(expected_current_state.0, target_state.0, success, failure)538{539Ok(_) => Ok(()),540Err(val) => Err(FreeCountState(val)),541}542}543}544545/// This is conceptually like a `Vec<Entity>` that stores entities pending reuse.546struct FreeList {547/// The actual buffer of [`Slot`]s.548/// Conceptually, this is like the `RawVec` for this `Vec`.549buffer: FreeBuffer,550/// The length of the free buffer551len: FreeCount,552}553554impl FreeList {555/// Constructs a empty [`FreeList`].556fn new() -> Self {557Self {558buffer: FreeBuffer::new(),559len: FreeCount::new_zero_len(),560}561}562563/// Gets the number of free entities.564///565/// # Risk566///567/// For this to be accurate, this must not be called during a [`Self::free`].568#[inline]569fn num_free(&self) -> u32 {570// Relaxed ordering is fine since this doesn't act on the length value in memory.571self.len.state(Ordering::Relaxed).length()572}573574/// Frees the `entities` allowing them to be reused.575///576/// # Safety577///578/// There must be a clear, strict order between this call and calls to [`Self::free`], [`Self::alloc_many`], and [`Self::alloc`].579/// Otherwise, the compiler will make unsound optimizations.580#[inline]581unsafe fn free(&self, entities: &[Entity]) {582// Disable remote allocation.583// We don't need to acquire the most recent memory from remote threads because we never read it.584// We do not need to release to remote threads because we only changed the disabled bit,585// which the remote allocator would with relaxed ordering.586let state = self.len.disable_len_for_state(Ordering::Relaxed);587588// Append onto the buffer589let mut len = state.length();590// `for_each` is typically faster than `for` here.591entities.iter().for_each(|&entity| {592// SAFETY: Caller ensures this does not conflict with `free` or `alloc` calls,593// and we just disabled remote allocation with a strict memory ordering.594// We only call `set` during a free, and the caller ensures that is not called concurrently.595unsafe {596self.buffer.set(len, entity);597}598len += 1;599});600601// Update length602let new_state = state.with_length(len);603// This is safe because `alloc` is not being called and `remote_alloc` checks that it is not disabled.604// We don't need to change the generation since this will change the length, which changes the value anyway.605// If, from a `remote_alloc` perspective, this does not change the length (i.e. this changes it *back* to what it was),606// then `alloc` must have been called, which changes the generation.607self.len.set_state_risky(new_state, Ordering::Release);608}609610/// Allocates an [`Entity`] from the free list if one is available.611///612/// # Safety613///614/// There must be a clear, strict order between this call and calls to [`Self::free`].615/// Otherwise, the compiler will make unsound optimizations.616#[inline]617unsafe fn alloc(&self) -> Option<Entity> {618// SAFETY: This will get a valid index because caller ensures there is no way for `free` to be done at the same time.619// Relaxed is ok here since `free` is the only time memory is changed, and relaxed still gets the most recent state.620// The memory ordering to ensure we read the most recent value at the index is ensured by the caller.621let len = self.len.pop_for_state(1, Ordering::Relaxed).length();622let index = len.checked_sub(1)?;623624// SAFETY: This was less then `len`, so it must have been `set` via `free` before.625// There is a strict memory ordering of this use of the index because the length is only decreasing.626// That means there is only one use of this index since the last call to `free`.627// The only time the length increases is during `free`, which the caller ensures has a "happened before" relationship with this call.628Some(unsafe { self.buffer.get(index) })629}630631/// Allocates as many [`Entity`]s from the free list as are available, up to `count`.632///633/// # Safety634///635/// There must be a clear, strict order between this call and calls to [`Self::free`].636/// Otherwise, the compiler will make unsound optimizations.637///638/// Note that this allocation call doesn't end until the returned value is dropped.639/// So, calling [`Self::free`] while the returned value is live is unsound.640#[inline]641unsafe fn alloc_many(&self, count: u32) -> FreeBufferIterator<'_> {642// SAFETY: This will get a valid index because there is no way for `free` to be done at the same time.643// Relaxed is ok here since `free` is the only time memory is changed, and relaxed still gets the most recent state.644// The memory ordering to ensure we read the most recent value at the index is ensured by the caller.645let len = self.len.pop_for_state(count, Ordering::Relaxed).length();646let index = len.saturating_sub(count);647648// SAFETY: The iterator's items are all less than the length, so they are in bounds and have been previously set.649// There is a strict memory ordering of this use of the indices because the length is only decreasing.650// That means there is only one use of these indices since the last call to `free`.651// The only time it the length increases is during `free`, which the caller ensures has a "happened before" relationship with this call.652unsafe { self.buffer.iter(index..len) }653}654655/// Allocates an [`Entity`] from the free list if one is available and it is safe to do so.656#[inline]657fn remote_alloc(&self) -> Option<Entity> {658// The goal is the same as `alloc`, so what's the difference?659// `alloc` knows `free` is not being called, but this does not.660// What if we `len.fetch_sub(1)` but then `free` overwrites the entity before we could read it?661// That would mean we would leak an entity and give another entity out twice.662// We get around this by only updating `len` after the read is complete.663// But that means something else could be trying to allocate the same index!664// So we need a `len.compare_exchange` loop to ensure the index is unique.665// Because we keep a generation value in the `FreeCount`, if any of these things happen, we simply try again.666// We also need to prevent this from conflicting with a `free` call, so we check to ensure the state is not disabled.667668// We keep track of the attempts so we can yield the thread on std after a few fails.669#[cfg(feature = "std")]670let mut attempts = 1u32;671// We need an acquire ordering to acquire the most recent memory of `free` calls.672let mut state = self.len.state(Ordering::Acquire);673loop {674// The state is only disabled when freeing.675// If a free is happening, we need to wait for the new entity to be ready on the free buffer.676// That means we will also need to re-fetch the state and acquire the new memory.677// Then, we can allocate it.678if state.is_disabled() {679// Spin 64 times before yielding.680#[cfg(feature = "std")]681{682attempts += 1;683if attempts.is_multiple_of(64) {684// scheduler probably isn't running the thread doing the `free` call, so yield so it can finish.685std::thread::yield_now();686} else {687core::hint::spin_loop();688}689}690691#[cfg(not(feature = "std"))]692core::hint::spin_loop();693694// Retry with the fresh state and acquired memory order.695state = self.len.state(Ordering::Acquire);696continue;697}698699// At this point, we know a `free` was not happening when we started.700701let len = state.length();702let index = len.checked_sub(1)?;703704// SAFETY:705//706// If no `free` call has started, this safety follows the same logic as in non-remote `alloc`.707// That is, the len always counts down, so this is the only use of this index since the last `free`,708// and another `free` hasn't happened.709//710// But if a `free` did start at this point, it would be operating on indices greater than `index`.711// We haven't updated the `FreeCount` yet, so the `free` call would be adding to it, while we've been subtracting from it.712// That means this is still the only time this index is used since the last `free`!713// So, even though we can't guarantee when the concurrent `free` is happening in memory order, it doesn't matter since that `free` doesn't use this index.714// We can still establish a clear, strict ordering for this slot because 1) any concurrent `free` doesn't use this index and 2) we have an `Acquire` relationship with the `free` before it.715//716// So yeah, we could be reading from outdated memory (the free buffer), but the part that we are reading, hasn't changed, so that's ok.717// That satisfies safety but not correctness.718// We still need to double check that a free didn't happen, and retry if it did.719// Otherwise, this entity might be given out twice.720let entity = unsafe { self.buffer.get(index) };721722let ideal_state = state.pop(1);723// If we fail, we need to acquire the new state.724// If we succeed, we are finished, and we haven't changed any memory, so we can used relaxed ordering.725match self726.len727.try_set_state(state, ideal_state, Ordering::Relaxed, Ordering::Acquire)728{729Ok(_) => return Some(entity),730Err(new_state) => state = new_state,731}732}733}734}735736struct FreshAllocator {737/// The next value of [`Entity::index`] to give out if needed.738next_entity_index: AtomicU32,739}740741impl FreshAllocator {742/// This exists because it may possibly change depending on platform.743/// Ex: We may want this to be smaller on 32 bit platforms at some point.744const MAX_ENTITIES: u32 = u32::MAX;745746/// The total number of indices given out.747#[inline]748fn total_entity_indices(&self) -> u32 {749self.next_entity_index.load(Ordering::Relaxed)750}751752/// This just panics.753/// It is included to help with branch prediction, and put the panic message in one spot.754#[cold]755#[inline]756fn on_overflow() -> ! {757panic!("too many entities")758}759760/// Allocates a fresh [`EntityIndex`].761/// This row has never been given out before.762#[inline]763fn alloc(&self) -> Entity {764let index = self.next_entity_index.fetch_add(1, Ordering::Relaxed);765if index == Self::MAX_ENTITIES {766Self::on_overflow();767}768// SAFETY: We just checked that this was not max and we only added 1, so we can't have missed it.769Entity::from_index(unsafe { EntityIndex::new(NonMaxU32::new_unchecked(index)) })770}771772/// Allocates `count` [`EntityIndex`]s.773/// These rows will be fresh.774/// They have never been given out before.775fn alloc_many(&self, count: u32) -> AllocUniqueEntityIndexIterator {776let start_new = self.next_entity_index.fetch_add(count, Ordering::Relaxed);777let new = match start_new778.checked_add(count)779.filter(|new| *new < Self::MAX_ENTITIES)780{781Some(new_next_entity_index) => start_new..new_next_entity_index,782None => Self::on_overflow(),783};784AllocUniqueEntityIndexIterator(new)785}786}787788/// An [`Iterator`] returning a sequence of [`EntityIndex`] values from an [`Allocator`] that are never aliased.789/// These rows have never been given out before.790///791/// **NOTE:** Dropping will leak the remaining entity rows!792pub(super) struct AllocUniqueEntityIndexIterator(core::ops::Range<u32>);793794impl Iterator for AllocUniqueEntityIndexIterator {795type Item = Entity;796797#[inline]798fn next(&mut self) -> Option<Self::Item> {799self.0800.next()801// SAFETY: This came from an *exclusive* range. It can never be max.802.map(|idx| unsafe { EntityIndex::new(NonMaxU32::new_unchecked(idx)) })803.map(Entity::from_index)804}805806#[inline]807fn size_hint(&self) -> (usize, Option<usize>) {808self.0.size_hint()809}810}811812impl ExactSizeIterator for AllocUniqueEntityIndexIterator {}813impl core::iter::FusedIterator for AllocUniqueEntityIndexIterator {}814815/// This stores allocation data shared by all entity allocators.816struct SharedAllocator {817/// The entities pending reuse818free: FreeList,819fresh: FreshAllocator,820/// Tracks whether or not the primary [`Allocator`] has been closed or not.821is_closed: AtomicBool,822}823824impl SharedAllocator {825/// Constructs a [`SharedAllocator`]826fn new() -> Self {827Self {828free: FreeList::new(),829fresh: FreshAllocator {830next_entity_index: AtomicU32::new(0),831},832is_closed: AtomicBool::new(false),833}834}835836/// Allocates a new [`Entity`], reusing a freed index if one exists.837///838/// # Safety839///840/// This must not conflict with [`FreeList::free`] calls.841#[inline]842unsafe fn alloc(&self) -> Entity {843// SAFETY: assured by caller844unsafe { self.free.alloc() }.unwrap_or_else(|| self.fresh.alloc())845}846847/// Allocates a `count` [`Entity`]s, reusing freed indices if they exist.848///849/// # Safety850///851/// This must not conflict with [`FreeList::free`] calls for the duration of the iterator.852#[inline]853unsafe fn alloc_many(&self, count: u32) -> AllocEntitiesIterator<'_> {854// SAFETY: Ensured by caller.855let reused = unsafe { self.free.alloc_many(count) };856let still_need = count - reused.len() as u32;857let new = self.fresh.alloc_many(still_need);858AllocEntitiesIterator { new, reused }859}860861/// Allocates a new [`Entity`].862/// This will only try to reuse a freed index if it is safe to do so.863#[inline]864fn remote_alloc(&self) -> Entity {865self.free866.remote_alloc()867.unwrap_or_else(|| self.fresh.alloc())868}869870/// Marks the allocator as closed, but it will still function normally.871fn close(&self) {872self.is_closed.store(true, Ordering::Release);873}874875/// Returns true if [`Self::close`] has been called.876fn is_closed(&self) -> bool {877self.is_closed.load(Ordering::Acquire)878}879}880881/// This keeps track of freed entities and allows the allocation of new ones.882///883/// Note that this must not implement [`Clone`].884/// The allocator assumes that it is the only one with [`FreeList::free`] permissions.885/// If this were cloned, that assumption would be broken, leading to undefined behavior.886/// This is in contrast to the [`RemoteAllocator`], which may be cloned freely.887pub(super) struct Allocator {888/// The shared allocator state, which we share with any [`RemoteAllocator`]s.889shared: Arc<SharedAllocator>,890/// The local free list.891/// We use this to amortize the cost of freeing to the shared allocator since that is expensive.892local_free: Box<ArrayVec<Entity, 128>>,893}894895impl Default for Allocator {896fn default() -> Self {897Self::new()898}899}900901impl Allocator {902/// Constructs a new [`Allocator`]903pub(super) fn new() -> Self {904Self {905shared: Arc::new(SharedAllocator::new()),906local_free: Box::new(ArrayVec::new()),907}908}909910/// Allocates a new [`Entity`], reusing a freed index if one exists.911#[inline]912pub(super) fn alloc(&self) -> Entity {913// SAFETY: violating safety requires a `&mut self` to exist, but rust does not allow that.914unsafe { self.shared.alloc() }915}916917/// The total number of indices given out.918#[inline]919fn total_entity_indices(&self) -> u32 {920self.shared.fresh.total_entity_indices()921}922923/// The number of free entities.924#[inline]925fn num_free(&self) -> u32 {926// RISK: `free` requires mutable access.927self.shared.free.num_free()928}929930/// Flushes the [`local_free`](Self::local_free) list to the shared allocator.931#[inline]932fn flush_freed(&mut self) {933// SAFETY: We have `&mut self`.934unsafe {935self.shared.free.free(self.local_free.as_slice());936}937self.local_free.clear();938}939940/// Frees the entity allowing it to be reused.941#[inline]942pub(super) fn free(&mut self, entity: Entity) {943if self.local_free.is_full() {944self.flush_freed();945}946// SAFETY: The `ArrayVec` is not full or has just been cleared.947unsafe {948self.local_free.push_unchecked(entity);949}950}951952/// Allocates `count` entities in an iterator.953#[inline]954pub(super) fn alloc_many(&self, count: u32) -> AllocEntitiesIterator<'_> {955// SAFETY: `free` takes `&mut self`, and this lifetime is captured by the iterator.956unsafe { self.shared.alloc_many(count) }957}958959/// Frees the entities allowing them to be reused.960#[inline]961pub(super) fn free_many(&mut self, entities: &[Entity]) {962if self.local_free.try_extend_from_slice(entities).is_err() {963// SAFETY: We have `&mut self`.964unsafe {965self.shared.free.free(entities);966}967}968}969}970971impl Drop for Allocator {972fn drop(&mut self) {973self.shared.close();974}975}976977impl core::fmt::Debug for Allocator {978fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {979f.debug_struct(core::any::type_name::<Self>())980.field("total_indices", &self.total_entity_indices())981.field("total_free", &self.num_free())982.finish()983}984}985986/// An [`Iterator`] returning a sequence of [`Entity`] values from an [`Allocator`].987///988/// **NOTE:** Dropping will leak the remaining entities!989pub(super) struct AllocEntitiesIterator<'a> {990new: AllocUniqueEntityIndexIterator,991reused: FreeBufferIterator<'a>,992}993994impl<'a> Iterator for AllocEntitiesIterator<'a> {995type Item = Entity;996997fn next(&mut self) -> Option<Self::Item> {998self.reused.next().or_else(|| self.new.next())999}10001001fn size_hint(&self) -> (usize, Option<usize>) {1002let len = self.reused.len() + self.new.len();1003(len, Some(len))1004}1005}10061007impl<'a> ExactSizeIterator for AllocEntitiesIterator<'a> {}1008impl<'a> core::iter::FusedIterator for AllocEntitiesIterator<'a> {}10091010// SAFETY: Newly reserved entity values are unique.1011unsafe impl EntitySetIterator for AllocEntitiesIterator<'_> {}10121013impl Drop for AllocEntitiesIterator<'_> {1014fn drop(&mut self) {1015let leaking = self.len();1016if leaking > 0 {1017warn!(1018"{} entities being leaked via unfinished `AllocEntitiesIterator`",1019leaking1020);1021}1022}1023}10241025/// This is a stripped down entity allocator that operates on fewer assumptions than [`EntityAllocator`](super::EntityAllocator).1026/// As a result, using this will be slower than than the main allocator but this offers additional freedoms.1027/// In particular, this type is fully owned, allowing you to allocate entities for a world without locking or holding reference to the world.1028/// This is especially useful in async contexts.1029#[derive(Clone)]1030pub struct RemoteAllocator {1031shared: Arc<SharedAllocator>,1032}10331034impl RemoteAllocator {1035/// Creates a new [`RemoteAllocator`] with the provided [`Allocator`] source.1036/// If the source is ever destroyed, [`Self::alloc`] will yield garbage values.1037/// Be sure to use [`Self::is_closed`] to determine if it is safe to use these entities.1038pub(super) fn new(source: &Allocator) -> Self {1039Self {1040shared: source.shared.clone(),1041}1042}10431044/// Returns whether or not this [`RemoteAllocator`] is connected to this source [`Allocator`].1045pub(super) fn is_connected_to(&self, source: &Allocator) -> bool {1046Arc::ptr_eq(&self.shared, &source.shared)1047}10481049/// Allocates an entity remotely.1050///1051/// This comes with a major downside:1052/// Because this does not hold reference to the world, the world may be cleared or destroyed before you get a chance to use the result.1053/// If that happens, these entities will be garbage!1054/// They will not be unique in the world anymore and you should not spawn them!1055/// Before using the returned values in the world, first check that it is ok with [`EntityAllocator::has_remote_allocator`](super::EntityAllocator::has_remote_allocator).1056#[inline]1057pub fn alloc(&self) -> Entity {1058self.shared.remote_alloc()1059}10601061/// Returns whether or not this [`RemoteAllocator`] is still connected to its source [`EntityAllocator`](super::EntityAllocator).1062///1063/// Note that this could close immediately after the function returns false, so be careful.1064/// The best way to ensure that does not happen is to only trust the returned value while holding a reference to the world1065/// and to ensure it is the right world through [`EntityAllocator::has_remote_allocator`](super::EntityAllocator::has_remote_allocator).1066///1067/// This is generally best used as a diagnostic.1068/// [`EntityAllocator::has_remote_allocator`](super::EntityAllocator::has_remote_allocator) is a better check for correctness.1069pub fn is_closed(&self) -> bool {1070self.shared.is_closed()1071}1072}10731074#[cfg(test)]1075mod tests {1076use super::*;1077use alloc::vec;10781079/// Ensure the total capacity of [`OwnedBuffer`] is `u32::MAX + 1`.1080#[test]1081fn chunk_capacity_sums() {1082let total: u64 = (0..FreeBuffer::NUM_CHUNKS)1083.map(FreeBuffer::capacity_of_chunk)1084.map(|x| x as u64)1085.sum();1086// The last 2 won't be used, but that's ok.1087// Keeping them powers of 2 makes things faster.1088let expected = u32::MAX as u64 + 1;1089assert_eq!(total, expected);1090}10911092/// Ensure [`OwnedBuffer`] can be properly indexed1093#[test]1094fn chunk_indexing() {1095let to_test = vec![1096(0, (0, 0, 512)), // index 0 cap = 5121097(1, (0, 1, 512)),1098(256, (0, 256, 512)),1099(511, (0, 511, 512)),1100(512, (1, 0, 512)), // index 1 cap = 5121101(1023, (1, 511, 512)),1102(1024, (2, 0, 1024)), // index 2 cap = 10241103(1025, (2, 1, 1024)),1104(2047, (2, 1023, 1024)),1105(2048, (3, 0, 2048)), // index 3 cap = 20481106(4095, (3, 2047, 2048)),1107(4096, (4, 0, 4096)), // index 3 cap = 40961108];11091110for (input, output) in to_test {1111assert_eq!(FreeBuffer::index_info(input), output);1112}1113}11141115#[test]1116fn buffer_len_encoding() {1117let len = FreeCount::new_zero_len();1118assert_eq!(len.state(Ordering::Relaxed).length(), 0);1119assert_eq!(len.pop_for_state(200, Ordering::Relaxed).length(), 0);1120len.set_state_risky(1121FreeCountState::new_zero_len().with_length(5),1122Ordering::Relaxed,1123);1124assert_eq!(len.pop_for_state(2, Ordering::Relaxed).length(), 5);1125assert_eq!(len.pop_for_state(2, Ordering::Relaxed).length(), 3);1126assert_eq!(len.pop_for_state(2, Ordering::Relaxed).length(), 1);1127assert_eq!(len.pop_for_state(2, Ordering::Relaxed).length(), 0);1128}11291130#[test]1131fn uniqueness() {1132let mut entities = Vec::with_capacity(2000);1133let mut allocator = Allocator::new();1134entities.extend(allocator.alloc_many(1000));11351136let pre_len = entities.len();1137entities.dedup();1138assert_eq!(pre_len, entities.len());11391140for e in entities.drain(..) {1141allocator.free(e);1142}11431144entities.extend(allocator.alloc_many(500));1145for _ in 0..1000 {1146entities.push(allocator.alloc());1147}1148entities.extend(allocator.alloc_many(500));11491150let pre_len = entities.len();1151entities.dedup();1152assert_eq!(pre_len, entities.len());1153}11541155/// Bevy's allocator doesn't make guarantees about what order entities will be allocated in.1156/// This test just exists to make sure allocations don't step on each other's toes.1157#[test]1158fn allocation_order_correctness() {1159let mut allocator = Allocator::new();1160let e0 = allocator.alloc();1161let e1 = allocator.alloc();1162let e2 = allocator.alloc();1163let e3 = allocator.alloc();1164allocator.free(e0);1165allocator.free(e1);1166allocator.free(e2);1167allocator.free(e3);1168allocator.flush_freed();11691170let r0 = allocator.alloc();1171let mut many = allocator.alloc_many(2);1172let r1 = many.next().unwrap();1173let r2 = many.next().unwrap();1174assert!(many.next().is_none());1175drop(many);1176let r3 = allocator.alloc();11771178assert_eq!(r0, e3);1179assert_eq!(r1, e1);1180assert_eq!(r2, e2);1181assert_eq!(r3, e0);1182}1183}118411851186