You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asyncband.apache.org by ti...@apache.org on 2026/10/03 15:25:48 UTC
(asyncband) 01/01: refactor(pool): borrow the pool during recycling
This is an automated email from the ASF dual-hosted git repository.
tisonkun pushed a commit to branch codex/deslopify-pool-recycling
in repository https://gitbox.apache.org/repos/asf/asyncband.git
commit 1d1d04e3d41a06d8c6b557d2715df06e2b7c264c
Author: tison <wa...@gmail.com>
AuthorDate: Sat Oct 3 23:25:39 2026 +0800
refactor(pool): borrow the pool during recycling
UnreadyObject only lives inside Pool::get, which already borrows an
Arc<Pool>. Hold that borrow directly, remove the copied cancellation
policy, and stop upgrading a Weak that cannot have expired.
Create the returned Object's Weak in ready(), preserving independent
checkout lifetimes. Cover both pool variants when a recycled object
outlives its pool and is then dropped or detached.
---
asyncband/src/pool/bounded.rs | 33 ++++++++++++----------------
asyncband/src/pool/unbounded.rs | 33 ++++++++++++----------------
tests-integration/tests/pool_test/recycle.rs | 22 +++++++++++++++++++
3 files changed, 50 insertions(+), 38 deletions(-)
diff --git a/asyncband/src/pool/bounded.rs b/asyncband/src/pool/bounded.rs
index c630991..9b3e2fd 100644
--- a/asyncband/src/pool/bounded.rs
+++ b/asyncband/src/pool/bounded.rs
@@ -293,8 +293,7 @@ impl<M: ManageObject> Pool<M> {
Some(object) => {
let mut unready_object = UnreadyObject {
state: Some(object),
- pool: Arc::downgrade(self),
- recycle_cancelled_strategy: self.config.recycle_cancelled_strategy,
+ pool: self,
};
let state = unready_object.state();
@@ -556,34 +555,32 @@ impl<M: ManageObject> Object<M> {
/// If the check fails, `detach()` should be called to permanently remove the object
/// from the pool. If dropped without calling either method (due to being cancelled),
/// the behavior depends on the pool's [`RecycleCancelledStrategy`] configuration.
-struct UnreadyObject<M: ManageObject> {
+struct UnreadyObject<'a, M: ManageObject> {
state: Option<ObjectState<M::Object>>,
- pool: Weak<Pool<M>>,
- recycle_cancelled_strategy: RecycleCancelledStrategy,
+ // The enclosing `get` call keeps the pool alive through cancellation cleanup.
+ pool: &'a Arc<Pool<M>>,
}
-impl<M: ManageObject> Drop for UnreadyObject<M> {
+impl<M: ManageObject> Drop for UnreadyObject<'_, M> {
fn drop(&mut self) {
if let Some(mut state) = self.state.take() {
- if let Some(pool) = self.pool.upgrade() {
- match self.recycle_cancelled_strategy {
- RecycleCancelledStrategy::Detach => {
- pool.detach_object(&mut state.o);
- }
- RecycleCancelledStrategy::ReturnToPool => {
- pool.restore_idle(state);
- }
+ match self.pool.config.recycle_cancelled_strategy {
+ RecycleCancelledStrategy::Detach => {
+ self.pool.detach_object(&mut state.o);
+ }
+ RecycleCancelledStrategy::ReturnToPool => {
+ self.pool.restore_idle(state);
}
}
}
}
}
-impl<M: ManageObject> UnreadyObject<M> {
+impl<M: ManageObject> UnreadyObject<'_, M> {
fn ready(mut self, permit: OwnedSemaphorePermit) -> Object<M> {
// INVARIANT: `state` is `Some` until this object becomes ready, detaches, or is dropped.
let state = Some(self.state.take().unwrap());
- let pool = self.pool.clone();
+ let pool = Arc::downgrade(self.pool);
Object {
state,
permit,
@@ -593,9 +590,7 @@ impl<M: ManageObject> UnreadyObject<M> {
fn detach(&mut self) {
if let Some(mut state) = self.state.take() {
- if let Some(pool) = self.pool.upgrade() {
- pool.detach_object(&mut state.o);
- }
+ self.pool.detach_object(&mut state.o);
}
}
diff --git a/asyncband/src/pool/unbounded.rs b/asyncband/src/pool/unbounded.rs
index ac0baff..44deef3 100644
--- a/asyncband/src/pool/unbounded.rs
+++ b/asyncband/src/pool/unbounded.rs
@@ -342,8 +342,7 @@ impl<T, M: ManageObject<Object = T>> Pool<T, M> {
Some(object) => {
let mut unready_object = UnreadyObject {
state: Some(object),
- pool: Arc::downgrade(self),
- recycle_cancelled_strategy: self.config.recycle_cancelled_strategy,
+ pool: self,
};
let state = unready_object.state();
@@ -571,42 +570,38 @@ impl<T, M: ManageObject<Object = T>> Object<T, M> {
/// If the check fails, `detach()` should be called to permanently remove the object
/// from the pool. If dropped without calling either method (due to being cancelled),
/// the behavior depends on the pool's [`RecycleCancelledStrategy`] configuration.
-struct UnreadyObject<T, M: ManageObject<Object = T>> {
+struct UnreadyObject<'a, T, M: ManageObject<Object = T>> {
state: Option<ObjectState<T>>,
- pool: Weak<Pool<T, M>>,
- recycle_cancelled_strategy: RecycleCancelledStrategy,
+ // The enclosing `get` call keeps the pool alive through cancellation cleanup.
+ pool: &'a Arc<Pool<T, M>>,
}
-impl<T, M: ManageObject<Object = T>> Drop for UnreadyObject<T, M> {
+impl<T, M: ManageObject<Object = T>> Drop for UnreadyObject<'_, T, M> {
fn drop(&mut self) {
if let Some(mut state) = self.state.take() {
- if let Some(pool) = self.pool.upgrade() {
- match self.recycle_cancelled_strategy {
- RecycleCancelledStrategy::Detach => {
- pool.detach_object(&mut state.o);
- }
- RecycleCancelledStrategy::ReturnToPool => {
- pool.restore_idle(state);
- }
+ match self.pool.config.recycle_cancelled_strategy {
+ RecycleCancelledStrategy::Detach => {
+ self.pool.detach_object(&mut state.o);
+ }
+ RecycleCancelledStrategy::ReturnToPool => {
+ self.pool.restore_idle(state);
}
}
}
}
}
-impl<T, M: ManageObject<Object = T>> UnreadyObject<T, M> {
+impl<T, M: ManageObject<Object = T>> UnreadyObject<'_, T, M> {
fn ready(mut self) -> Object<T, M> {
// INVARIANT: `state` is `Some` until this object becomes ready, detaches, or is dropped.
let state = Some(self.state.take().unwrap());
- let pool = self.pool.clone();
+ let pool = Arc::downgrade(self.pool);
Object { state, pool }
}
fn detach(&mut self) {
if let Some(mut state) = self.state.take() {
- if let Some(pool) = self.pool.upgrade() {
- pool.detach_object(&mut state.o);
- }
+ self.pool.detach_object(&mut state.o);
}
}
diff --git a/tests-integration/tests/pool_test/recycle.rs b/tests-integration/tests/pool_test/recycle.rs
index 03ff53e..d877cc6 100644
--- a/tests-integration/tests/pool_test/recycle.rs
+++ b/tests-integration/tests/pool_test/recycle.rs
@@ -113,6 +113,28 @@ macro_rules! recycle_contract {
}
}
+ #[test]
+ fn recycled_object_can_outlive_the_pool() {
+ for detach in [false, true] {
+ let manager = Manager::default();
+ let pool = pool(1, manager.clone(), None);
+ drop(ready(pool.get()).unwrap());
+ let object = ready(pool.get()).unwrap();
+ assert_eq!(object.status().recycle_count(), 1);
+
+ let weak_pool = Arc::downgrade(&pool);
+ drop(pool);
+ assert!(weak_pool.upgrade().is_none());
+ assert_eq!(*object, 0);
+ if detach {
+ assert_eq!(object.detach(), 0);
+ } else {
+ drop(object);
+ }
+ assert!(manager.detached().is_empty());
+ }
+ }
+
#[test]
fn cancelling_one_validation_leaves_other_idle_objects_available() {
let manager = Manager::default();
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@asyncband.apache.org
For additional commands, e-mail: commits-help@asyncband.apache.org