aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--odb/pgsql/connection-factory.cxx163
-rw-r--r--odb/pgsql/connection-factory.hxx154
-rw-r--r--odb/pgsql/connection.cxx87
-rw-r--r--odb/pgsql/connection.hxx121
-rw-r--r--odb/pgsql/exceptions.cxx4
-rw-r--r--odb/pgsql/makefile2
6 files changed, 529 insertions, 2 deletions
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 <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/pgsql/connection-factory.hxx>
+#include <odb/pgsql/exceptions.hxx>
+
+#include <odb/details/lock.hxx>
+
+using namespace std;
+
+namespace odb
+{
+ using namespace details;
+
+ namespace pgsql
+ {
+ //
+ // connection_factory
+ //
+
+ connection_factory::
+ ~connection_factory ()
+ {
+ }
+
+ //
+ // new_connection_factory
+ //
+
+ shared_ptr<connection> new_connection_factory::
+ connect ()
+ {
+ return shared_ptr<connection> (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> connection_pool_factory::
+ connect ()
+ {
+ lock l (mutex_);
+
+ while (true)
+ {
+ // See if we have a spare connection.
+ //
+ if (connections_.size () != 0)
+ {
+ shared_ptr<pooled_connection> 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<pooled_connection> 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<pooled_connection> (
+ 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<pooled_connection> (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<pooled_connection*> (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 <constantin@codesynthesis.com>
+// 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 <odb/pre.hxx>
+
+#include <vector>
+#include <cstddef> // std::size_t
+
+#include <odb/details/mutex.hxx>
+#include <odb/details/condition.hxx>
+#include <odb/details/shared-ptr.hxx>
+
+#include <odb/pgsql/version.hxx>
+#include <odb/pgsql/forward.hxx>
+#include <odb/pgsql/connection.hxx>
+
+#include <odb/pgsql/details/export.hxx>
+
+namespace odb
+{
+ namespace pgsql
+ {
+ class LIBODB_PGSQL_EXPORT connection_factory
+ {
+ public:
+ virtual details::shared_ptr<connection>
+ 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<connection>
+ 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<connection>
+ 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<details::shared_ptr<pooled_connection> > 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 <odb/post.hxx>
+
+#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 <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <new> // std::bad_alloc
+#include <string>
+
+#include <odb/pgsql/database.hxx>
+#include <odb/pgsql/connection.hxx>
+#include <odb/pgsql/error.hxx>
+#include <odb/pgsql/exceptions.hxx>
+
+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 <constantin@codesynthesis.com>
+// 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 <odb/pre.hxx>
+
+#include <vector>
+#include <memory> // std::auto_ptr
+
+#include <libpq-fe.h>
+
+#include <odb/forward.hxx>
+
+#include <odb/details/shared-ptr.hxx>
+
+#include <odb/pgsql/version.hxx>
+#include <odb/pgsql/forward.hxx>
+
+#include <odb/pgsql/details/export.hxx>
+
+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_type> statement_cache_;
+
+ // typedef std::vector<MYSQL_STMT*> stmt_handles;
+ // stmt_handles stmt_handles_;
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#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