Jeroen T. Vermeulen wrote:
> On Wed, July 11, 2007 01:41, Fei Liu wrote:
>
>   
>>  I just realized my problem was using transactor model within a
>> multi-thread environment...Is there any tutorial or example code using
>> pqxx in a multi-thread application environment? Thanks
>>     
>
> Not yet, and we still need to do a lot of work to include locks.  Right
> now libpqxx itself doesn't do any locking.
>
> There are several ways to ensure thread safety for your use of libpqxx:
>
> 1. Do all your database work in a single thread.  It saves time on
> establishing multiple connections, too.
>
> 2. Give each thread its own connection, and don't interchange libpqxx
> objects between threads.  This may scale better or worse than using a
> single thread, depending on the job.
>
> 3. Lock whenever you access any libpqxx object that may also be accessed
> by other threads.  Think of each connection as a separate world, and all
> objects related to that connection are part of that world.  Whenever
> multiple threads can step into the same world at the same time, acquire a
> lock that you associate with that world.
>
> The last option is the most flexible, but that also means it's dangerous. 
> For example, you must make sure that you don't try to open a transaction
> on a connection while another thread still has a transaction open on the
> same connection.  I would use option 3 only for connection pooling.
>
>
> Jeroen
>
>
>   
Thanks Jeroen, I am trying to get around with a connection_pool model. I 
am getting this error:
what():  FATAL:  sorry, too many clients already

What's the upper limit of concurrent connection pqxx supports? what 
freedom do I have to adjust it?

Fei

P.S. My resource_pool implementation, might be useful for libpqxx to 
implement a concurrent model:

#ifndef UTILS_resource_POOL
#define UTILS_resource_POOL

#include <list>
#include <string>
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/thread/thread.hpp>

namespace utils{

    template <typename C, typename init_type = std::string>
    struct resource{
        C c;
        bool used;
        unsigned int id;
        static unsigned int sid;
        resource(const init_type & init): c(init), used(false) { id = 
sid++;}
        bool operator < (const resource<C, init_type> & cc) const {
            return id < cc.id;
        }
        bool operator == (const resource<C, init_type> & cc) const {
            return id == cc.id;
        }
    };

    template <typename C, typename init_type> unsigned int resource<C, 
init_type>::sid = 0;

    template <typename C, typename init_type = std::string>
    class resource_pool{
        typedef typename boost::shared_ptr<resource<C, init_type> > 
ele_type;
        typedef typename std::list<ele_type> pool_type;
        pool_type free_pool;
        pool_type used_pool;
        init_type init;
        boost::mutex mutex;

        typedef typename pool_type::const_iterator c_it_type;
        typedef typename pool_type::iterator it_type;
    public:
        resource_pool(const init_type & init) : init(init){ }

        C & alloc(unsigned int & id){
            boost::mutex::scoped_lock lock(mutex);
            if(free_pool.empty()){
                ele_type conn = ele_type(new resource<C, init_type>(init));
                conn->used = true;
                used_pool.push_front(conn);
                id = conn->id;
                return conn->c;
            }else{
                it_type it = free_pool.begin();
                ele_type conn = *it;
                conn->used = true;
                free_pool.erase(it);
                used_pool.push_front(conn);
                id = conn->id;
                return conn->c;
            }
            assert(0);
        }

        void release(unsigned int id){
            boost::mutex::scoped_lock lock(mutex);
            it_type it = used_pool.begin();
            while((*it)->id != id && it != used_pool.end()){
                //std::cerr << (*it)->id << std::endl;
                ++it;
            }
            assert(it != used_pool.end());

            ele_type conn = *it;
            conn->used = false;
            used_pool.erase(it);
            free_pool.push_front(conn);
        }

        void dump(){
            boost::mutex::scoped_lock lock(mutex);
            std::cerr << "free_pool: " << std::endl;
            c_it_type it = free_pool.begin();
            while(it != free_pool.end()) {
                std::cerr << (*it)->id << ": " << (*it)->used << std::endl;
                ++it;
            }

            std::cerr << "used_pool: " << std::endl;
            it = used_pool.begin();
            while(it != used_pool.end()) {
                std::cerr << (*it)->id << ": " << (*it)->used << std::endl;
                ++it;
            }
        }
    };
}

#endif


_______________________________________________
Libpqxx-general mailing list
[email protected]
http://gborg.postgresql.org/mailman/listinfo/libpqxx-general

Reply via email to