Comments (13)
You can do this with a small amount of trickiness:
struct SelfContainedConnection<M, T> {
// must be in this order to ensure the connection drops before the pool
conn: PooledConnection<'static, T>,
pool: Arc<Pool<M>>,
}
impl<M, T> SelfContainedConnection<M, T> where M: ConnectionManager, T: ConnectionManager::Connection {
pub fn new(pool: &Arc<Pool>) -> Result<SelfContainedConnection, GetTimeout> {
let conn = try!(pool.get());
let pool = pool.clone();
Ok(SelfContainedConnection {
conn: unsafe { mem::transmute(conn) },
pool: pool
})
}
}
impl<M, T> Deref for SelfContainedConnection<M, T> {
type Target = T;
fn deref(&self) -> &T {
&*self.conn
}
}
We define a new smart pointer that holds both the original PooledConnection pointer as well as a reference to the pool to make sure it stays alive.
from r2d2.
Which version of rust does that work on @sfackler? On nightly I get:
src/db_pool.rs:38:73: 38:102 error: `ConnectionManager::Connection` is not a trait
src/db_pool.rs:38 impl<M, T> SelfContainedConnection<M, T> where M: ConnectionManager, T: ConnectionManager::Connection {
I rewrote that with explicit Connection where needed and dropped T:
pub struct SelfContainedConnection<M> where M: ConnectionManager {
// must be in this order to ensure the connection drops before the pool
conn: PooledConnection<'static, M>,
pool: Arc<Pool<M>>,
}
impl<M> SelfContainedConnection<M> where M: ConnectionManager {
pub fn new(pool: &Arc<Pool<M>>) ⟶ Result<SelfContainedConnection<M>, GetTimeout> {
let conn = try!(pool.get());
let pool = pool.clone();
Ok(SelfContainedConnection {
conn: unsafe { mem::transmute(conn) },
pool: pool
})
}
}
impl<M> Deref for SelfContainedConnection<M> where M: ConnectionManager {
type Target = M::Connection;
fn deref(&self) ⟶ &M::Connection {
&*self.conn
}
}
But that still fails with:
src/db_pool.rs:43:28: 43:42 error: cannot transmute to or from a type that contains type parameters in its interior [E0139]
src/db_pool.rs:43 conn: unsafe { mem::transmute(conn) },
from r2d2.
I'm not sure it works on any version - I wrote it from memory. That transmute error can be worked around, but it requires more unsafe hackery than I'm really comfortable with.
The request for a lifetime-unrestricted PooledConnection
has come up before (maybe from @alexcrichton?). It might make sense to completely drop the lifetime parameter from PooledConnection
, but I'm not sure how I feel about that. In the meantime, I've added a Pool::get_arc
function that acts like the one in the code snippet above but avoids unsafe code if you're storing the Pool
in an Arc
:
let pool: &Arc<Pool<M>> = my_pool;
let conn = Pool::get_arc(pool.clone()).unwrap(); // conn has a 'static lifetime
I can publish the update to crates.io if this seems reasonable to you.
from r2d2.
@sfackler yeah crates.io currently has similar code to get a PooledConnnection<'static>
from r2d2.
Published v0.5.8 with get_arc
: http://sfackler.github.io/r2d2/doc/v0.5.8/r2d2/struct.Pool.html#method.get_arc
from r2d2.
cc me, this is an important API consideration for iron
from r2d2.
PooledConnection
is currently set up with a reference to the pool since that seems like the more "Rustic" thing to do, but it seems like it's more of a pain than it's worth. Pool
already has an internal Arc
that it shares with its worker threads, so it'd be easy to remove the lifetime constraint on PooledConnection
. It does make it a bit more unclear of when the pool will actually clean itself up, but I'd imagine it lives indefinitely anyway in basically all use cases.
Thoughts?
from r2d2.
I suspect that the "overhead" from using an Arc
here is negligible due to a DB connection being such a heavyweight object, and I wouldn't personally be too surprised by the lifetime semantics here. I would never shut down a pool of connections until the entire app dies anyway, so it's already super long lasting and unlikely to hit weird scoping problems.
This pattern is in use elsewhere, though, for example in Servo's work stealing deque. The BufferPool
is used to create Stealer
s and Worker
s, both of which have have a strong reference to the internal pool. Basically the original buffer pool can disappear but won't actually get deallocated until all stealers/workers are gone. (just a data point)
from r2d2.
A somewhat related question is how sharing across threads should be handled. Right now, you put the Pool into an Arc, but Pool could impl Clone itself. This seems a bit weird to me, but it does appear to be what Servo's BufferedPool does.
from r2d2.
Just tested get_arc()
and it's exactly what I needed. Thanks!
I'm not sure what the last comment meant. Something like pool.get_arc()
where it does Pool::get_arc(self.clone())
? That would be nice too.
from r2d2.
Right now, if you want to share a Pool
between threads, you have to stick it into an Arc
and then clone that:
let pool = Arc::new(Pool::new(...));
let pool2 = pool.clone();
thread::spawn(move || {
let pool = pool2;
// use the pool
});
// use the other pool
We could change Pool
so that it acts like an Arc
on its own:
let pool = Pool::new(...);
let pool2 = pool.clone();
thread::spawn(move || {
let pool = pool2;
// use the pool
});
// use the other pool
Pool itself is just a bare wrapper around an Arc
internally, so there's something to be said for removing a level of indirection: https://github.com/sfackler/r2d2/blob/master/src/lib.rs#L114-L116. It's an unrelated idea to the PooledConnection lifetime issue.
from r2d2.
I've made the changes discussed: PooledConnection
no longer has a lifetime bound and Pool
directly implements clone.
I'll be releasing those changes and some others as v0.6 in a couple days probably.
from r2d2.
v0.6.0's been released.
from r2d2.
Related Issues (20)
- roadmap to v1.0.0? HOT 3
- Will r2d2 create more connections than max_size when using builder()? HOT 3
- pool.get() returns Error(None) -- best debugging strategy? HOT 1
- Is there a way to not keep idle connections? HOT 8
- `get_timeout` exceeds timeout HOT 11
- Can be used in the future such as tokio, async_std? HOT 1
- Use `compare_exchange` or `compare_exchange_weak` instead
- Is there a way to drop or close an actual connection when I'm using PooldConnection? HOT 4
- "Named" connections HOT 3
- Why example use `let pool = pool.clone()` in a for loop ? HOT 2
- Document relationship between `min_idle`, `idle_timeout` and `max_lifetime` HOT 1
- How to set timezone when linking HOT 1
- Release? HOT 1
- Allow hooking on connection get-from-pool and release-to-pool HOT 8
- Using behind proxychains HOT 1
- Seg fault with Postgres HOT 14
- Remove parking_lot dependency now that std's Mutex is faster than before HOT 3
- [Bug] CI test failure on arm HOT 4
- r2d2::Error should derive PartialEq and Clone HOT 4
- Pool building freezes when connections drop during initial setup HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from r2d2.