From f26337fb02c2f01382486407c2b3d7432df9bd37 Mon Sep 17 00:00:00 2001 From: Constantin Michael Date: Mon, 9 May 2011 16:45:31 +0200 Subject: Add connection and connection factory implementations --- odb/pgsql/connection-factory.cxx | 163 +++++++++++++++++++++++++++++++++++++++ odb/pgsql/connection-factory.hxx | 154 ++++++++++++++++++++++++++++++++++++ odb/pgsql/connection.cxx | 87 +++++++++++++++++++++ odb/pgsql/connection.hxx | 121 +++++++++++++++++++++++++++++ odb/pgsql/exceptions.cxx | 4 +- odb/pgsql/makefile | 2 + 6 files changed, 529 insertions(+), 2 deletions(-) create mode 100644 odb/pgsql/connection-factory.cxx create mode 100644 odb/pgsql/connection-factory.hxx create mode 100644 odb/pgsql/connection.cxx create mode 100644 odb/pgsql/connection.hxx (limited to 'odb/pgsql') diff --git a/odb/pgsql/connection-factory.cxx b/odb/pgsql/connection-factory.cxx new file mode 100644 index 0000000..45d86cd --- /dev/null +++ b/odb/pgsql/connection-factory.cxx @@ -0,0 +1,163 @@ +// file : odb/pgsql/connection-factory.cxx +// author : Constantin Michael +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include +#include + +#include + +using namespace std; + +namespace odb +{ + using namespace details; + + namespace pgsql + { + // + // connection_factory + // + + connection_factory:: + ~connection_factory () + { + } + + // + // new_connection_factory + // + + shared_ptr new_connection_factory:: + connect () + { + return shared_ptr (new (shared) connection (*db_)); + } + + void new_connection_factory:: + database (database_type& db) + { + db_ = &db; + } + + // + // connection_pool_factory + // + + connection_pool_factory:: + ~connection_pool_factory () + { + // Wait for all the connections currently in use to return to + // the pool. + // + lock l (mutex_); + while (in_use_ != 0) + { + waiters_++; + cond_.wait (); + waiters_--; + } + } + + shared_ptr connection_pool_factory:: + connect () + { + lock l (mutex_); + + while (true) + { + // See if we have a spare connection. + // + if (connections_.size () != 0) + { + shared_ptr c (connections_.back ()); + connections_.pop_back (); + + c->pool_ = this; + in_use_++; + return c; + } + + // See if we can create a new one. + // + if (max_ == 0 || in_use_ < max_) + { + shared_ptr c ( + new (shared) pooled_connection (*db_, this)); + in_use_++; + return c; + } + + // Wait until someone releases a connection. + // + waiters_++; + cond_.wait (); + waiters_--; + } + } + + void connection_pool_factory:: + database (database_type& db) + { + db_ = &db; + + if (min_ > 0) + { + connections_.reserve (min_); + + for (size_t i (0); i < min_; ++i) + { + connections_.push_back ( + shared_ptr ( + new (shared) pooled_connection (*db_, 0))); + } + } + } + + bool connection_pool_factory:: + release (pooled_connection* c) + { + c->pool_ = 0; + + lock l (mutex_); + + // Determine if we need to keep or free this connection. + // + bool keep (waiters_ != 0 || + min_ == 0 || + (connections_.size () + in_use_ <= min_)); + + in_use_--; + + if (keep) + connections_.push_back ( + shared_ptr (inc_ref (c))); + + if (waiters_ != 0) + cond_.signal (); + + return !keep; + } + + // + // connection_pool_factory::pooled_connection + // + + connection_pool_factory::pooled_connection:: + pooled_connection (database_type& db, connection_pool_factory* pool) + : connection (db), pool_ (pool) + { + callback_.arg = this; + callback_.zero_counter = &zero_counter; + shared_base::callback_ = &callback_; + } + + bool connection_pool_factory::pooled_connection:: + zero_counter (void* arg) + { + pooled_connection* c (static_cast (arg)); + return c->pool_ ? c->pool_->release (c) : true; + } + } +} diff --git a/odb/pgsql/connection-factory.hxx b/odb/pgsql/connection-factory.hxx new file mode 100644 index 0000000..d90b7cb --- /dev/null +++ b/odb/pgsql/connection-factory.hxx @@ -0,0 +1,154 @@ +// file : odb/pgsql/connection-factory.hxx +// author : Constantin Michael +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_PGSQL_CONNECTION_FACTORY_HXX +#define ODB_PGSQL_CONNECTION_FACTORY_HXX + +#include + +#include +#include // std::size_t + +#include +#include +#include + +#include +#include +#include + +#include + +namespace odb +{ + namespace pgsql + { + class LIBODB_PGSQL_EXPORT connection_factory + { + public: + virtual details::shared_ptr + connect () = 0; + + public: + typedef pgsql::database database_type; + + virtual void + database (database_type&) = 0; + + virtual + ~connection_factory (); + }; + + class LIBODB_PGSQL_EXPORT new_connection_factory: public connection_factory + { + public: + new_connection_factory () + : db_ (0) + { + } + + virtual details::shared_ptr + connect (); + + virtual void + database (database_type&); + + private: + new_connection_factory (const new_connection_factory&); + new_connection_factory& operator= (const new_connection_factory&); + + private: + database_type* db_; + }; + + class LIBODB_PGSQL_EXPORT connection_pool_factory: + public connection_factory + { + public: + // The max_connections argument specifies the maximum number of + // concurrent connections this pool will maintain. If this value + // is 0 then the pool will create a new connection every time all + // of the existing connections are in use. + // + // The min_connections argument specifies the minimum number of + // connections that should be maintained by the pool. If the + // number of connections maintained by the pool exceeds this + // number and there are no active waiters for a new connection, + // then the pool will release the excess connections. If this + // value is 0 then the pool will maintain all the connections + // that were ever created. + // + connection_pool_factory (std::size_t max_connections = 0, + std::size_t min_connections = 0) + : max_ (max_connections), + min_ (min_connections), + in_use_ (0), + waiters_ (0), + db_ (0), + cond_ (mutex_) + { + // @@ check min_ <= max_ + } + + virtual details::shared_ptr + connect (); + + virtual void + database (database_type&); + + virtual + ~connection_pool_factory (); + + private: + connection_pool_factory (const connection_pool_factory&); + connection_pool_factory& operator= (const connection_pool_factory&); + + private: + class pooled_connection: public connection + { + public: + // NULL pool value indicates that the connection is not in use. + // + pooled_connection (database_type&, connection_pool_factory*); + + private: + static bool + zero_counter (void*); + + private: + friend class connection_pool_factory; + + shared_base::refcount_callback callback_; + connection_pool_factory* pool_; + }; + + friend class pooled_connection; + typedef std::vector > connections; + + private: + // Return true if the connection should be deleted, false otherwise. + // + bool + release (pooled_connection*); + + private: + const std::size_t max_; + const std::size_t min_; + + std::size_t in_use_; // Number of connections currently in use. + std::size_t waiters_; // Number of threads waiting for a connection. + + database_type* db_; + connections connections_; + + details::mutex mutex_; + details::condition cond_; + }; + } +} + +#include + +#endif // ODB_PGSQL_CONNECTION_FACTORY_HXX diff --git a/odb/pgsql/connection.cxx b/odb/pgsql/connection.cxx new file mode 100644 index 0000000..37f359f --- /dev/null +++ b/odb/pgsql/connection.cxx @@ -0,0 +1,87 @@ +// file : odb/pgsql/connection.cxx +// author : Constantin Michael +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include // std::bad_alloc +#include + +#include +#include +#include +#include + +using namespace std; + +namespace odb +{ + namespace pgsql + { + connection:: + connection (database_type& db) + : db_ (db), + handle_ (0) + // active_ (0), + // statement_cache_ (new statement_cache_type (*this)) + { + handle_ = PQconnectdb (db.conninfo ().c_str ()); + + if (handle_ == 0) + throw bad_alloc (); + else if (PQstatus (handle_) == CONNECTION_BAD) + { + std::string m (PQerrorMessage (handle_)); + PQfinish (handle_); + + throw database_exception (m); + } + } + + connection:: + ~connection () + { + // if (stmt_handles_.size () > 0) + // free_stmt_handles (); + + PQfinish (handle_); + } + + // void connection:: + // clear_ () + // { + // active_->cancel (); // Should clear itself from active_. + // } + + // MYSQL_STMT* connection:: + // alloc_stmt_handle () + // { + // MYSQL_STMT* stmt (mysql_stmt_init (handle_)); + + // if (stmt == 0) + // throw bad_alloc (); + + // return stmt; + // } + + // void connection:: + // free_stmt_handle (MYSQL_STMT* stmt) + // { + // if (active_ == 0) + // mysql_stmt_close (stmt); + // else + // stmt_handles_.push_back (stmt); + // } + + // void connection:: + // free_stmt_handles () + // { + // for (stmt_handles::iterator i (stmt_handles_.begin ()), + // e (stmt_handles_.end ()); i != e; ++i) + // { + // mysql_stmt_close (*i); + // } + + // stmt_handles_.clear (); + // } + } +} diff --git a/odb/pgsql/connection.hxx b/odb/pgsql/connection.hxx new file mode 100644 index 0000000..038ce70 --- /dev/null +++ b/odb/pgsql/connection.hxx @@ -0,0 +1,121 @@ +// file : odb/pgsql/connection.hxx +// author : Constantin Michael +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_PGSQL_CONNECTION_HXX +#define ODB_PGSQL_CONNECTION_HXX + +#include + +#include +#include // std::auto_ptr + +#include + +#include + +#include + +#include +#include + +#include + +namespace odb +{ + namespace pgsql + { + class statement; + class statement_cache; + + class LIBODB_PGSQL_EXPORT connection: public details::shared_base + { + public: + // typedef pgsql::statement_cache statement_cache_type; + typedef pgsql::database database_type; + + virtual + ~connection (); + + connection (database_type&); + + database_type& + database () + { + return db_; + } + + public: + PGconn* + handle () + { + return handle_; + } + + // statement_cache_type& + // statement_cache () + // { + // return *statement_cache_; + // } + + public: + // statement* + // active () + // { + // return active_; + // } + + // void + // active (statement* s) + // { + // active_ = s; + + // if (s == 0 && stmt_handles_.size () > 0) + // free_stmt_handles (); + // } + + // // Cancel and clear the active statement, if any. + // // + // void + // clear () + // { + // if (active_ != 0) + // clear_ (); + // } + + public: + // MYSQL_STMT* + // alloc_stmt_handle (); + + // void + // free_stmt_handle (MYSQL_STMT*); + + private: + connection (const connection&); + connection& operator= (const connection&); + + private: + // void + // free_stmt_handles (); + + // void + // clear_ (); + + private: + database_type& db_; + + PGconn* handle_; + + // statement* active_; + // std::auto_ptr statement_cache_; + + // typedef std::vector stmt_handles; + // stmt_handles stmt_handles_; + }; + } +} + +#include + +#endif // ODB_PGSQL_CONNECTION_HXX diff --git a/odb/pgsql/exceptions.cxx b/odb/pgsql/exceptions.cxx index bec4ba7..e37d5f2 100644 --- a/odb/pgsql/exceptions.cxx +++ b/odb/pgsql/exceptions.cxx @@ -47,8 +47,8 @@ namespace odb // cli_exception:: - cli_exception (const string& w) - : what_ (w) + cli_exception (const string& what) + : what_ (what) { } diff --git a/odb/pgsql/makefile b/odb/pgsql/makefile index bf911db..722a34d 100644 --- a/odb/pgsql/makefile +++ b/odb/pgsql/makefile @@ -7,6 +7,8 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../../build/bootstrap.make cxx := \ +connection.cxx \ +connection-factory.cxx \ database.cxx \ error.cxx \ exceptions.cxx -- cgit v1.1