Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion datafusion/execution/src/memory_pool/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
//! help with allocation accounting.

use datafusion_common::{Result, internal_datafusion_err};
use std::any::Any;
use std::fmt::Display;
use std::hash::{Hash, Hasher};
use std::{cmp::Ordering, sync::Arc, sync::atomic};
Expand Down Expand Up @@ -182,7 +183,7 @@ pub use pool::*;
///
/// * [`TrackConsumersPool`]: Wraps another [`MemoryPool`] and tracks consumers,
/// providing better error messages on the largest memory users.
pub trait MemoryPool: Send + Sync + std::fmt::Debug + Display {
pub trait MemoryPool: Any + Send + Sync + std::fmt::Debug + Display {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding Any as a supertrait adds a 'static requirement to every MemoryPool implementor. This might break downstream if they have implemented custom pools which borrowed state or lifetime parameters

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for mention this, i add upgrade guide in 344b52f

/// Return pool name
fn name(&self) -> &str;

Expand Down Expand Up @@ -224,6 +225,18 @@ pub trait MemoryPool: Send + Sync + std::fmt::Debug + Display {
}
}

impl dyn MemoryPool {
/// Returns `true` if this pool is of type `T`.
pub fn is<T: MemoryPool>(&self) -> bool {
(self as &dyn Any).is::<T>()
}

/// Attempts to downcast this pool to a concrete type `T`.
pub fn downcast_ref<T: MemoryPool>(&self) -> Option<&T> {
(self as &dyn Any).downcast_ref()
}
}

/// Memory limit of `MemoryPool`
pub enum MemoryLimit {
Infinite,
Expand Down Expand Up @@ -603,6 +616,18 @@ mod tests {
assert_eq!(pool.reserved(), 28);
}

#[test]
fn test_downcast() {
let pool: Arc<dyn MemoryPool> = Arc::new(GreedyMemoryPool::new(50));

assert!(pool.is::<GreedyMemoryPool>());
assert!(!pool.is::<UnboundedMemoryPool>());

let greedy: &GreedyMemoryPool = pool.downcast_ref().unwrap();
assert_eq!(greedy.reserved(), 0);
assert!(pool.downcast_ref::<UnboundedMemoryPool>().is_none());
}

#[test]
fn test_try_shrink() {
let pool = Arc::new(GreedyMemoryPool::new(100)) as _;
Expand Down
54 changes: 54 additions & 0 deletions docs/source/library-user-guide/upgrading/54.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -497,3 +497,57 @@ impl Default for MyTreeNode {
}
}
```

### `MemoryPool` now requires `'static` (adds `Any` as a supertrait)

To enable downcasting of `dyn MemoryPool` to concrete pool types (via
`is::<T>()` / `downcast_ref::<T>()`), the `MemoryPool` trait now has `Any`
as a supertrait:

```rust,ignore
// Before
pub trait MemoryPool: Send + Sync + std::fmt::Debug + Display { ... }

// After
pub trait MemoryPool: Any + Send + Sync + std::fmt::Debug + Display { ... }
```

Because `Any` is only implemented for `'static` types, this implicitly adds a
`'static` bound to every `MemoryPool` implementor.

**Who is affected:**

- Users who implement a custom `MemoryPool` whose type carries a lifetime
parameter or borrows state (e.g. `struct MyPool<'a> { inner: &'a State }`).
Existing implementations that are already `'static` (the common case) need
no changes.

**Migration guide:**

Replace borrowed references with owned handles so the pool type becomes
`'static`. The typical fix is to swap `&'a T` for `Arc<T>` (or `Rc<T>`, or an
owned value):

```rust,ignore
// Before — not 'static, no longer compiles
struct MyPool<'a> {
inner: &'a SomeState,
}

impl<'a> MemoryPool for MyPool<'a> { ... }

// After — owned handle makes MyPool: 'static
struct MyPool {
inner: Arc<SomeState>,
}

impl MemoryPool for MyPool { ... }
```

If the borrowed state truly cannot be made `'static`, you can wrap the
borrowed pool in a `'static` adapter that the pool consumer owns — for
example, store the underlying state in an `Arc` owned by the adapter, or
move the borrow behind an interior-mutability primitive such as `Arc<Mutex<_>>`
or `Arc<OnceLock<_>>`.

See [PR #21803](https://github.com/apache/datafusion/pull/21803) for details.
Loading