Files
Mazdak Farrokhzad e93de33111 datastore: add clear_table and fix drop_table (#3214)
# Description of Changes

Aternative to and closes
https://github.com/clockworklabs/SpacetimeDB/pull/3210.
This version relies on `pending_schema_changes`.
The first commit adds `clear_table` to the datastore that's efficient
and can be exposed to the module ABI in a follow up.
The second commit fixes `drop_table`.

# API and ABI breaking changes

None

# Expected complexity level and risk

3?

# Testing

`test_drop_table_is_transactional` is amended to check `TxData`.

---------

Signed-off-by: Mazdak Farrokhzad <twingoow@gmail.com>
Co-authored-by: Shubham Mishra <shubham@clockworklabs.io>
Co-authored-by: Shubham Mishra <shivam828787@gmail.com>
2025-09-23 11:48:49 +00:00

143 lines
4.1 KiB
Rust

use core::mem;
use core::sync::atomic::AtomicUsize;
/// For inspecting how much memory a value is using.
///
/// This trait specifically measures heap memory. If you want to measure stack memory too, add
/// `mem::size_of_val()` to it. (This only really matters for the outermost type in a hierarchy.)
pub trait MemoryUsage {
/// The **heap** memory usage of this type. The default implementation returns 0.
#[inline(always)]
fn heap_usage(&self) -> usize {
0
}
}
impl MemoryUsage for () {}
impl MemoryUsage for bool {}
impl MemoryUsage for u8 {}
impl MemoryUsage for u16 {}
impl MemoryUsage for u32 {}
impl MemoryUsage for u64 {}
impl MemoryUsage for u128 {}
#[cfg(feature = "ethnum")]
impl MemoryUsage for ethnum::u256 {}
impl MemoryUsage for usize {}
impl MemoryUsage for AtomicUsize {}
impl MemoryUsage for i8 {}
impl MemoryUsage for i16 {}
impl MemoryUsage for i32 {}
impl MemoryUsage for i64 {}
impl MemoryUsage for i128 {}
#[cfg(feature = "ethnum")]
impl MemoryUsage for ethnum::i256 {}
impl MemoryUsage for isize {}
impl MemoryUsage for f32 {}
impl MemoryUsage for f64 {}
#[cfg(feature = "decorum")]
impl MemoryUsage for decorum::Total<f32> {}
#[cfg(feature = "decorum")]
impl MemoryUsage for decorum::Total<f64> {}
impl<T: MemoryUsage + ?Sized> MemoryUsage for &T {
fn heap_usage(&self) -> usize {
(*self).heap_usage()
}
}
impl<T: MemoryUsage + ?Sized> MemoryUsage for Box<T> {
fn heap_usage(&self) -> usize {
mem::size_of_val::<T>(self) + T::heap_usage(self)
}
}
impl<T: MemoryUsage + ?Sized> MemoryUsage for std::sync::Arc<T> {
fn heap_usage(&self) -> usize {
let refcounts = mem::size_of::<usize>() * 2;
refcounts + mem::size_of_val::<T>(self) + T::heap_usage(self)
}
}
impl<T: MemoryUsage + ?Sized> MemoryUsage for std::rc::Rc<T> {
fn heap_usage(&self) -> usize {
let refcounts = mem::size_of::<usize>() * 2;
refcounts + mem::size_of_val::<T>(self) + T::heap_usage(self)
}
}
impl<T: MemoryUsage> MemoryUsage for [T] {
fn heap_usage(&self) -> usize {
self.iter().map(T::heap_usage).sum()
}
}
impl<T: MemoryUsage, const N: usize> MemoryUsage for [T; N] {
fn heap_usage(&self) -> usize {
self.iter().map(T::heap_usage).sum()
}
}
impl MemoryUsage for str {}
impl<T: MemoryUsage> MemoryUsage for Option<T> {
fn heap_usage(&self) -> usize {
self.as_ref().map_or(0, T::heap_usage)
}
}
impl<A: MemoryUsage, B: MemoryUsage> MemoryUsage for (A, B) {
fn heap_usage(&self) -> usize {
self.0.heap_usage() + self.1.heap_usage()
}
}
impl MemoryUsage for String {
fn heap_usage(&self) -> usize {
self.capacity()
}
}
impl<T: MemoryUsage> MemoryUsage for Vec<T> {
fn heap_usage(&self) -> usize {
self.capacity() * mem::size_of::<T>() + self.iter().map(T::heap_usage).sum::<usize>()
}
}
#[cfg(feature = "hashbrown")]
impl<K: MemoryUsage + Eq + core::hash::Hash, V: MemoryUsage, S: core::hash::BuildHasher> MemoryUsage
for hashbrown::HashMap<K, V, S>
{
fn heap_usage(&self) -> usize {
self.allocation_size() + self.iter().map(|(k, v)| k.heap_usage() + v.heap_usage()).sum::<usize>()
}
}
#[cfg(feature = "hashbrown")]
impl<K: MemoryUsage + Eq + core::hash::Hash, S: core::hash::BuildHasher> MemoryUsage for hashbrown::HashSet<K, S> {
fn heap_usage(&self) -> usize {
self.allocation_size() + self.iter().map(|k| k.heap_usage()).sum::<usize>()
}
}
impl<K: MemoryUsage, V: MemoryUsage> MemoryUsage for std::collections::BTreeMap<K, V> {
fn heap_usage(&self) -> usize {
// NB: this is best-effort, since we don't have a `capacity()` method on `BTreeMap`.
self.len() * mem::size_of::<(K, V)>() + self.iter().map(|(k, v)| k.heap_usage() + v.heap_usage()).sum::<usize>()
}
}
#[cfg(feature = "smallvec")]
impl<A: smallvec::Array> MemoryUsage for smallvec::SmallVec<A>
where
A::Item: MemoryUsage,
{
fn heap_usage(&self) -> usize {
self.as_slice().heap_usage()
+ if self.spilled() {
self.capacity() * mem::size_of::<A::Item>()
} else {
0
}
}
}