Coder Social home page Coder Social logo

Comments (13)

sfackler avatar sfackler commented on July 30, 2024

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.

viraptor avatar viraptor commented on July 30, 2024

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.

sfackler avatar sfackler commented on July 30, 2024

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.

9d786e3

from r2d2.

alexcrichton avatar alexcrichton commented on July 30, 2024

@sfackler yeah crates.io currently has similar code to get a PooledConnnection<'static>

from r2d2.

sfackler avatar sfackler commented on July 30, 2024

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.

reem avatar reem commented on July 30, 2024

cc me, this is an important API consideration for iron

from r2d2.

sfackler avatar sfackler commented on July 30, 2024

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.

alexcrichton avatar alexcrichton commented on July 30, 2024

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 Stealers and Workers, 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.

sfackler avatar sfackler commented on July 30, 2024

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.

viraptor avatar viraptor commented on July 30, 2024

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.

sfackler avatar sfackler commented on July 30, 2024

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.

sfackler avatar sfackler commented on July 30, 2024

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.

sfackler avatar sfackler commented on July 30, 2024

v0.6.0's been released.

from r2d2.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.