]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1044] Made PgSql lease manager thread safe
authorFrancis Dupont <fdupont@isc.org>
Wed, 4 Dec 2019 23:12:41 +0000 (00:12 +0100)
committerFrancis Dupont <fdupont@isc.org>
Wed, 4 Dec 2019 23:12:41 +0000 (00:12 +0100)
src/lib/dhcpsrv/mysql_lease_mgr.h
src/lib/dhcpsrv/pgsql_lease_mgr.cc
src/lib/dhcpsrv/pgsql_lease_mgr.h
src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc

index 30bb844506ffab4a1034a5ff72c6f064a0529e93..e6ba8918970033e71a78628e3aaf3bb58d01dae4 100644 (file)
@@ -102,7 +102,7 @@ public:
     /// @brief Destructor (closes database)
     virtual ~MySqlLeaseMgr();
 
-    /// #brief Create a new context.
+    /// @brief Create a new context.
     ///
     /// The database is opened with all the SQL commands pre-compiled.
     ///
index 3ca1e3ed1643721047fc0d325950abe9df2e3afc..53366ccd704e21a4b72de6b2a8940649faa11499 100644 (file)
@@ -12,6 +12,7 @@
 #include <dhcpsrv/dhcpsrv_log.h>
 #include <dhcpsrv/dhcpsrv_exceptions.h>
 #include <dhcpsrv/pgsql_lease_mgr.h>
+#include <util/multi_threading_mgr.h>
 
 #include <boost/static_assert.hpp>
 
@@ -26,6 +27,7 @@ using namespace isc::asiolink;
 using namespace isc::db;
 using namespace isc::dhcp;
 using namespace isc::data;
+using namespace isc::util;
 using namespace std;
 
 namespace {
@@ -1113,10 +1115,48 @@ protected:
     bool fetch_type_;
 };
 
+// PgSqlLeaseContext Constructor
+
+PgSqlLeaseContext::PgSqlLeaseContext(
+    const DatabaseConnection::ParameterMap& parameters) : conn_(parameters) {
+}
+
+// PgSqlLeaseContextAlloc Constructor and Destructor
+
+PgSqlLeaseMgr::PgSqlLeaseContextAlloc::PgSqlLeaseContextAlloc(
+    const PgSqlLeaseMgr& mgr) : ctx_(), mgr_(mgr) {
+
+    if (MultiThreadingMgr::instance().getMode()) {
+        {
+            lock_guard<mutex> lock(mgr_.pool_->mutex_);
+            if (!mgr_.pool_->pool_.empty()) {
+                ctx_ = mgr_.pool_->pool_.back();
+                mgr_.pool_->pool_.pop_back();
+            }
+        }
+        if (!ctx_) {
+            ctx_ = mgr_.createContext();
+        }
+    } else {
+        if (mgr_.pool_->pool_.empty()) {
+            isc_throw(Unexpected, "No available PgSql lease context?!");
+        }
+        ctx_ = mgr_.pool_->pool_.back();
+    }
+}
+
+PgSqlLeaseMgr::PgSqlLeaseContextAlloc::~PgSqlLeaseContextAlloc() {
+    if (MultiThreadingMgr::instance().getMode()) {
+        lock_guard<mutex> lock(mgr_.pool_->mutex_);
+        mgr_.pool_->pool_.push_back(ctx_);
+    }
+}
+
+// PgSqlLeaseMgr Constructor and Destructor
+
 PgSqlLeaseMgr::PgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
-    : LeaseMgr(), exchange4_(new PgSqlLease4Exchange()),
-      exchange6_(new PgSqlLease6Exchange()), parameters_(parameters),
-      conn_(parameters) {
+    : LeaseMgr(), parameters_(parameters) {
+
     // Validate schema version first.
     std::pair<uint32_t, uint32_t> code_version(PG_SCHEMA_VERSION_MAJOR,
                                                PG_SCHEMA_VERSION_MINOR);
@@ -1129,13 +1169,28 @@ PgSqlLeaseMgr::PgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
                       << db_version.second);
     }
 
+    // Create an initial context.
+    pool_.reset(new PgSqlLeaseContextPool());
+    pool_->pool_.push_back(createContext());
+}
+
+PgSqlLeaseMgr::~PgSqlLeaseMgr() {
+}
+
+// Create context.
+
+PgSqlLeaseContextPtr
+PgSqlLeaseMgr::createContext() const {
+
+    PgSqlLeaseContextPtr ctx(new PgSqlLeaseContext(parameters_));
+
     // Open the database.
-    conn_.openDatabase();
+    ctx->conn_.openDatabase();
 
     // Now prepare the SQL statements.
-    int i = 0;
-    for( ; tagged_statements[i].text != NULL ; ++i) {
-        conn_.prepareStatement(tagged_statements[i]);
+    unsigned i = 0;
+    for ( ; tagged_statements[i].text != NULL ; ++i) {
+        ctx->conn_.prepareStatement(tagged_statements[i]);
     }
 
     // Just in case somebody foo-barred things
@@ -1143,9 +1198,13 @@ PgSqlLeaseMgr::PgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
         isc_throw(DbOpenError, "Number of statements prepared: " << i
                   << " does not match expected count:" << NUM_STATEMENTS);
     }
-}
 
-PgSqlLeaseMgr::~PgSqlLeaseMgr() {
+    // Create the exchange objects for use for transfer of data to/from
+    // the database.
+    ctx->exchange4_.reset(new PgSqlLease4Exchange());
+    ctx->exchange6_.reset(new PgSqlLease6Exchange());
+
+    return (ctx);
 }
 
 std::string
@@ -1158,9 +1217,10 @@ PgSqlLeaseMgr::getDBVersion() {
 }
 
 bool
-PgSqlLeaseMgr::addLeaseCommon(StatementIndex stindex,
+PgSqlLeaseMgr::addLeaseCommon(PgSqlLeaseContextPtr ctx,
+                              StatementIndex stindex,
                               PsqlBindArray& bind_array) {
-    PgSqlResult r(PQexecPrepared(conn_, tagged_statements[stindex].name,
+    PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
                                  tagged_statements[stindex].nbparams,
                                  &bind_array.values_[0],
                                  &bind_array.lengths_[0],
@@ -1172,11 +1232,11 @@ PgSqlLeaseMgr::addLeaseCommon(StatementIndex stindex,
         // Failure: check for the special case of duplicate entry.  If this is
         // the case, we return false to indicate that the row was not added.
         // Otherwise we throw an exception.
-        if (conn_.compareError(r, PgSqlConnection::DUPLICATE_KEY)) {
+        if (ctx->conn_.compareError(r, PgSqlConnection::DUPLICATE_KEY)) {
             return (false);
         }
 
-        conn_.checkStatementError(r, tagged_statements[stindex]);
+        ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
     }
 
     return (true);
@@ -1187,34 +1247,45 @@ PgSqlLeaseMgr::addLease(const Lease4Ptr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_PGSQL_ADD_ADDR4).arg(lease->addr_.toText());
 
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
     PsqlBindArray bind_array;
-    exchange4_->createBindForSend(lease, bind_array);
-    return (addLeaseCommon(INSERT_LEASE4, bind_array));
+    ctx->exchange4_->createBindForSend(lease, bind_array);
+    return (addLeaseCommon(ctx, INSERT_LEASE4, bind_array));
 }
 
 bool
 PgSqlLeaseMgr::addLease(const Lease6Ptr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_PGSQL_ADD_ADDR6).arg(lease->addr_.toText());
+
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
     PsqlBindArray bind_array;
-    exchange6_->createBindForSend(lease, bind_array);
+    ctx->exchange6_->createBindForSend(lease, bind_array);
 
-    return (addLeaseCommon(INSERT_LEASE6, bind_array));
+    return (addLeaseCommon(ctx, INSERT_LEASE6, bind_array));
 }
 
 template <typename Exchange, typename LeaseCollection>
-void PgSqlLeaseMgr::getLeaseCollection(StatementIndex stindex,
+void PgSqlLeaseMgr::getLeaseCollection(PgSqlLeaseContextPtr ctx,
+                                       StatementIndex stindex,
                                        PsqlBindArray& bind_array,
                                        Exchange& exchange,
                                        LeaseCollection& result,
                                        bool single) const {
     const int n = tagged_statements[stindex].nbparams;
-    PgSqlResult r(PQexecPrepared(conn_, tagged_statements[stindex].name, n,
+    PgSqlResult r(PQexecPrepared(ctx->conn_,
+                                 tagged_statements[stindex].name, n,
                                  n > 0 ? &bind_array.values_[0] : NULL,
                                  n > 0 ? &bind_array.lengths_[0] : NULL,
                                  n > 0 ? &bind_array.formats_[0] : NULL, 0));
 
-    conn_.checkStatementError(r, tagged_statements[stindex]);
+    ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
 
     int rows = PQntuples(r);
     if (single && rows > 1) {
@@ -1229,15 +1300,17 @@ void PgSqlLeaseMgr::getLeaseCollection(StatementIndex stindex,
 }
 
 void
-PgSqlLeaseMgr::getLease(StatementIndex stindex, PsqlBindArray& bind_array,
-                             Lease4Ptr& result) const {
+PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr ctx,
+                        StatementIndex stindex, PsqlBindArray& bind_array,
+                        Lease4Ptr& result) const {
     // Create appropriate collection object and get all leases matching
     // the selection criteria.  The "single" parameter is true to indicate
     // that the called method should throw an exception if multiple
     // matching records are found: this particular method is called when only
     // one or zero matches is expected.
     Lease4Collection collection;
-    getLeaseCollection(stindex, bind_array, exchange4_, collection, true);
+    getLeaseCollection(ctx, stindex, bind_array, ctx->exchange4_,
+                       collection, true);
 
     // Return single record if present, else clear the lease.
     if (collection.empty()) {
@@ -1248,15 +1321,17 @@ PgSqlLeaseMgr::getLease(StatementIndex stindex, PsqlBindArray& bind_array,
 }
 
 void
-PgSqlLeaseMgr::getLease(StatementIndex stindex, PsqlBindArray& bind_array,
-                             Lease6Ptr& result) const {
+PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr ctx,
+                        StatementIndex stindex, PsqlBindArray& bind_array,
+                        Lease6Ptr& result) const {
     // Create appropriate collection object and get all leases matching
     // the selection criteria.  The "single" parameter is true to indicate
     // that the called method should throw an exception if multiple
     // matching records are found: this particular method is called when only
     // one or zero matches is expected.
     Lease6Collection collection;
-    getLeaseCollection(stindex, bind_array, exchange6_, collection, true);
+    getLeaseCollection(ctx, stindex, bind_array, ctx->exchange6_,
+                       collection, true);
 
     // Return single record if present, else clear the lease.
     if (collection.empty()) {
@@ -1281,7 +1356,12 @@ PgSqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const {
 
     // Get the data
     Lease4Ptr result;
-    getLease(GET_LEASE4_ADDR, bind_array, result);
+
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    getLease(ctx, GET_LEASE4_ADDR, bind_array, result);
 
     return (result);
 }
@@ -1303,7 +1383,12 @@ PgSqlLeaseMgr::getLease4(const HWAddr& hwaddr) const {
 
     // Get the data
     Lease4Collection result;
-    getLeaseCollection(GET_LEASE4_HWADDR, bind_array, result);
+
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    getLeaseCollection(ctx, GET_LEASE4_HWADDR, bind_array, result);
 
     return (result);
 }
@@ -1330,7 +1415,12 @@ PgSqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
 
     // Get the data
     Lease4Ptr result;
-    getLease(GET_LEASE4_HWADDR_SUBID, bind_array, result);
+
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    getLease(ctx, GET_LEASE4_HWADDR_SUBID, bind_array, result);
 
     return (result);
 }
@@ -1348,7 +1438,12 @@ PgSqlLeaseMgr::getLease4(const ClientId& clientid) const {
 
     // Get the data
     Lease4Collection result;
-    getLeaseCollection(GET_LEASE4_CLIENTID, bind_array, result);
+
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    getLeaseCollection(ctx, GET_LEASE4_CLIENTID, bind_array, result);
 
     return (result);
 }
@@ -1381,7 +1476,12 @@ PgSqlLeaseMgr::getLease4(const ClientId& clientid, SubnetID subnet_id) const {
 
     // Get the data
     Lease4Ptr result;
-    getLease(GET_LEASE4_CLIENTID_SUBID, bind_array, result);
+
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    getLease(ctx, GET_LEASE4_CLIENTID_SUBID, bind_array, result);
 
     return (result);
 }
@@ -1400,7 +1500,12 @@ PgSqlLeaseMgr::getLeases4(SubnetID subnet_id) const {
 
     // ... and get the data
     Lease4Collection result;
-    getLeaseCollection(GET_LEASE4_SUBID, bind_array, result);
+
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    getLeaseCollection(ctx, GET_LEASE4_SUBID, bind_array, result);
 
     return (result);
 }
@@ -1418,7 +1523,12 @@ PgSqlLeaseMgr::getLeases4(const string& hostname) const {
 
     // ... and get the data
     Lease4Collection result;
-    getLeaseCollection(GET_LEASE4_HOSTNAME, bind_array, result);
+
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    getLeaseCollection(ctx, GET_LEASE4_HOSTNAME, bind_array, result);
 
     return (result);
 }
@@ -1431,7 +1541,12 @@ PgSqlLeaseMgr::getLeases4() const {
     // WHERE clause.
     PsqlBindArray bind_array;
     Lease4Collection result;
-    getLeaseCollection(GET_LEASE4, bind_array, result);
+
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    getLeaseCollection(ctx, GET_LEASE4, bind_array, result);
 
     return (result);
 }
@@ -1464,7 +1579,12 @@ PgSqlLeaseMgr::getLeases4(const asiolink::IOAddress& lower_bound_address,
 
     // Get the leases
     Lease4Collection result;
-    getLeaseCollection(GET_LEASE4_PAGE, bind_array, result);
+
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    getLeaseCollection(ctx, GET_LEASE4_PAGE, bind_array, result);
 
     return (result);
 }
@@ -1488,7 +1608,12 @@ PgSqlLeaseMgr::getLease6(Lease::Type lease_type,
 
     // ... and get the data
     Lease6Ptr result;
-    getLease(GET_LEASE6_ADDR, bind_array, result);
+
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    getLease(ctx, GET_LEASE6_ADDR, bind_array, result);
 
     return (result);
 }
@@ -1516,7 +1641,12 @@ PgSqlLeaseMgr::getLeases6(Lease::Type lease_type, const DUID& duid,
 
     // ... and get the data
     Lease6Collection result;
-    getLeaseCollection(GET_LEASE6_DUID_IAID, bind_array, result);
+
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    getLeaseCollection(ctx, GET_LEASE6_DUID_IAID, bind_array, result);
 
     return (result);
 }
@@ -1548,7 +1678,12 @@ PgSqlLeaseMgr::getLeases6(Lease::Type lease_type, const DUID& duid,
 
     // ... and get the data
     Lease6Collection result;
-    getLeaseCollection(GET_LEASE6_DUID_IAID_SUBID, bind_array, result);
+
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    getLeaseCollection(ctx, GET_LEASE6_DUID_IAID_SUBID, bind_array, result);
 
     return (result);
 }
@@ -1567,7 +1702,12 @@ PgSqlLeaseMgr::getLeases6(SubnetID subnet_id) const {
 
     // ... and get the data
     Lease6Collection result;
-    getLeaseCollection(GET_LEASE6_SUBID, bind_array, result);
+
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    getLeaseCollection(ctx, GET_LEASE6_SUBID, bind_array, result);
 
     return (result);
 }
@@ -1585,8 +1725,12 @@ PgSqlLeaseMgr::getLeases6(const DUID& duid) const {
     bind_array.add(duid.getDuid());
     Lease6Collection result;
 
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
     // query to fetch the data
-    getLeaseCollection(GET_LEASE6_DUID, bind_array, result);
+    getLeaseCollection(ctx, GET_LEASE6_DUID, bind_array, result);
 
     return (result);
 }
@@ -1604,7 +1748,12 @@ PgSqlLeaseMgr::getLeases6(const string& hostname) const {
 
     // ... and get the data
     Lease6Collection result;
-    getLeaseCollection(GET_LEASE6_HOSTNAME, bind_array, result);
+
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    getLeaseCollection(ctx, GET_LEASE6_HOSTNAME, bind_array, result);
 
     return (result);
 }
@@ -1617,7 +1766,12 @@ PgSqlLeaseMgr::getLeases6() const {
     // WHERE clause.
     PsqlBindArray bind_array;
     Lease6Collection result;
-    getLeaseCollection(GET_LEASE6, bind_array, result);
+
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    getLeaseCollection(ctx, GET_LEASE6, bind_array, result);
 
     return (result);
 }
@@ -1656,7 +1810,12 @@ PgSqlLeaseMgr::getLeases6(const asiolink::IOAddress& lower_bound_address,
 
     // Get the leases
     Lease6Collection result;
-    getLeaseCollection(GET_LEASE6_PAGE, bind_array, result);
+
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    getLeaseCollection(ctx, GET_LEASE6_PAGE, bind_array, result);
 
     return (result);
 }
@@ -1699,31 +1858,36 @@ PgSqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases,
     std::string limit_str = boost::lexical_cast<std::string>(limit);
     bind_array.add(limit_str);
 
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
     // Retrieve leases from the database.
-    getLeaseCollection(statement_index, bind_array, expired_leases);
+    getLeaseCollection(ctx, statement_index, bind_array, expired_leases);
 }
 
 template<typename LeasePtr>
 void
-PgSqlLeaseMgr::updateLeaseCommon(StatementIndex stindex,
+PgSqlLeaseMgr::updateLeaseCommon(PgSqlLeaseContextPtr ctx,
+                                 StatementIndex stindex,
                                  PsqlBindArray& bind_array,
                                  const LeasePtr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_PGSQL_ADD_ADDR4).arg(tagged_statements[stindex].name);
 
-    PgSqlResult r(PQexecPrepared(conn_, tagged_statements[stindex].name,
+    PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
                                  tagged_statements[stindex].nbparams,
                                  &bind_array.values_[0],
                                  &bind_array.lengths_[0],
                                  &bind_array.formats_[0], 0));
 
-    conn_.checkStatementError(r, tagged_statements[stindex]);
+    ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
 
     int affected_rows = boost::lexical_cast<int>(PQcmdTuples(r));
 
     // Check success case first as it is the most likely outcome.
     if (affected_rows == 1) {
-      return;
+        return;
     }
 
     // If no rows affected, lease doesn't exist.
@@ -1745,9 +1909,13 @@ PgSqlLeaseMgr::updateLease4(const Lease4Ptr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_PGSQL_UPDATE_ADDR4).arg(lease->addr_.toText());
 
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
     // Create the BIND array for the data being updated
     PsqlBindArray bind_array;
-    exchange4_->createBindForSend(lease, bind_array);
+    ctx->exchange4_->createBindForSend(lease, bind_array);
 
     // Set up the WHERE clause and append it to the SQL_BIND array
     std::string addr4_ = boost::lexical_cast<std::string>
@@ -1755,7 +1923,7 @@ PgSqlLeaseMgr::updateLease4(const Lease4Ptr& lease) {
     bind_array.add(addr4_);
 
     // Drop to common update code
-    updateLeaseCommon(stindex, bind_array, lease);
+    updateLeaseCommon(ctx, stindex, bind_array, lease);
 }
 
 void
@@ -1765,28 +1933,36 @@ PgSqlLeaseMgr::updateLease6(const Lease6Ptr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_PGSQL_UPDATE_ADDR6).arg(lease->addr_.toText());
 
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
     // Create the BIND array for the data being updated
     PsqlBindArray bind_array;
-    exchange6_->createBindForSend(lease, bind_array);
+    ctx->exchange6_->createBindForSend(lease, bind_array);
 
     // Set up the WHERE clause and append it to the BIND array
     std::string addr_str = lease->addr_.toText();
     bind_array.add(addr_str);
 
     // Drop to common update code
-    updateLeaseCommon(stindex, bind_array, lease);
+    updateLeaseCommon(ctx, stindex, bind_array, lease);
 }
 
 uint64_t
 PgSqlLeaseMgr::deleteLeaseCommon(StatementIndex stindex,
                                  PsqlBindArray& bind_array) {
-    PgSqlResult r(PQexecPrepared(conn_, tagged_statements[stindex].name,
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
                                  tagged_statements[stindex].nbparams,
                                  &bind_array.values_[0],
                                  &bind_array.lengths_[0],
                                  &bind_array.formats_[0], 0));
 
-    conn_.checkStatementError(r, tagged_statements[stindex]);
+    ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
     int affected_rows = boost::lexical_cast<int>(PQcmdTuples(r));
 
     return (affected_rows);
@@ -1848,16 +2024,27 @@ PgSqlLeaseMgr::deleteExpiredReclaimedLeasesCommon(const uint32_t secs,
 
 LeaseStatsQueryPtr
 PgSqlLeaseMgr::startLeaseStatsQuery4() {
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
     LeaseStatsQueryPtr query(
-        new PgSqlLeaseStatsQuery(conn_, tagged_statements[ALL_LEASE4_STATS], false));
+        new PgSqlLeaseStatsQuery(ctx->conn_,
+                                 tagged_statements[ALL_LEASE4_STATS],
+                                 false));
     query->start();
     return(query);
 }
 
 LeaseStatsQueryPtr
 PgSqlLeaseMgr::startSubnetLeaseStatsQuery4(const SubnetID& subnet_id) {
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
     LeaseStatsQueryPtr query(
-        new PgSqlLeaseStatsQuery(conn_, tagged_statements[SUBNET_LEASE4_STATS],
+        new PgSqlLeaseStatsQuery(ctx->conn_,
+                                 tagged_statements[SUBNET_LEASE4_STATS],
                                  false, subnet_id));
     query->start();
     return(query);
@@ -1865,9 +2052,14 @@ PgSqlLeaseMgr::startSubnetLeaseStatsQuery4(const SubnetID& subnet_id) {
 
 LeaseStatsQueryPtr
 PgSqlLeaseMgr::startSubnetRangeLeaseStatsQuery4(const SubnetID& first_subnet_id,
-                                                   const SubnetID& last_subnet_id) {
+                                                const SubnetID& last_subnet_id) {
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
     LeaseStatsQueryPtr query(
-        new PgSqlLeaseStatsQuery(conn_, tagged_statements[SUBNET_RANGE_LEASE4_STATS],
+        new PgSqlLeaseStatsQuery(ctx->conn_,
+                                 tagged_statements[SUBNET_RANGE_LEASE4_STATS],
                                  false, first_subnet_id, last_subnet_id));
     query->start();
     return(query);
@@ -1875,16 +2067,27 @@ PgSqlLeaseMgr::startSubnetRangeLeaseStatsQuery4(const SubnetID& first_subnet_id,
 
 LeaseStatsQueryPtr
 PgSqlLeaseMgr::startLeaseStatsQuery6() {
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
     LeaseStatsQueryPtr query(
-        new PgSqlLeaseStatsQuery(conn_, tagged_statements[ALL_LEASE6_STATS], true));
+        new PgSqlLeaseStatsQuery(ctx->conn_,
+                                 tagged_statements[ALL_LEASE6_STATS],
+                                 true));
     query->start();
     return(query);
 }
 
 LeaseStatsQueryPtr
 PgSqlLeaseMgr::startSubnetLeaseStatsQuery6(const SubnetID& subnet_id) {
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
     LeaseStatsQueryPtr query(
-        new PgSqlLeaseStatsQuery(conn_, tagged_statements[SUBNET_LEASE6_STATS],
+        new PgSqlLeaseStatsQuery(ctx->conn_,
+                                 tagged_statements[SUBNET_LEASE6_STATS],
                                  true, subnet_id));
     query->start();
     return(query);
@@ -1893,8 +2096,13 @@ PgSqlLeaseMgr::startSubnetLeaseStatsQuery6(const SubnetID& subnet_id) {
 LeaseStatsQueryPtr
 PgSqlLeaseMgr::startSubnetRangeLeaseStatsQuery6(const SubnetID& first_subnet_id,
                                                 const SubnetID& last_subnet_id) {
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
     LeaseStatsQueryPtr query(
-        new PgSqlLeaseStatsQuery(conn_, tagged_statements[SUBNET_RANGE_LEASE6_STATS],
+        new PgSqlLeaseStatsQuery(ctx->conn_,
+                                 tagged_statements[SUBNET_RANGE_LEASE6_STATS],
                                  true, first_subnet_id, last_subnet_id));
     query->start();
     return(query);
@@ -1912,9 +2120,13 @@ PgSqlLeaseMgr::wipeLeases6(const SubnetID& /*subnet_id*/) {
 
 string
 PgSqlLeaseMgr::getName() const {
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
     string name = "";
     try {
-        name = conn_.getParameter("name");
+        name = ctx->conn_.getParameter("name");
     } catch (...) {
         // Return an empty name
     }
@@ -1936,12 +2148,10 @@ PgSqlLeaseMgr::getVersion() const {
 
 void
 PgSqlLeaseMgr::commit() {
-    conn_.commit();
 }
 
 void
 PgSqlLeaseMgr::rollback() {
-    conn_.rollback();
 }
 
 }; // end of isc::dhcp namespace
index 8fdbe9a75ebaaf0feb014d1bde471a3c05a7bcf7..f6496cf5e5409bddc1b49a1cb9aa2002b11ec0ca 100644 (file)
@@ -17,6 +17,7 @@
 #include <boost/utility.hpp>
 
 #include <vector>
+#include <mutex>
 
 namespace isc {
 namespace dhcp {
@@ -26,6 +27,45 @@ namespace dhcp {
 class PgSqlLease4Exchange;
 class PgSqlLease6Exchange;
 
+/// @brief PostgreSQL Lease Context
+class PgSqlLeaseContext {
+public:
+
+    /// @brief Constructor
+    ///
+    /// @param parameters See PgSqlLeaseMgr constructor.
+    PgSqlLeaseContext(const db::DatabaseConnection::ParameterMap& parameters);
+
+    /// The exchange objects are used for transfer of data to/from the database.
+    /// They are pointed-to objects as the contents may change in "const" calls,
+    /// while the rest of this object does not.  (At alternative would be to
+    /// declare them as "mutable".)
+    boost::scoped_ptr<PgSqlLease4Exchange> exchange4_; ///< Exchange object
+    boost::scoped_ptr<PgSqlLease6Exchange> exchange6_; ///< Exchange object
+
+    /// PostgreSQL connection handle
+    db::PgSqlConnection conn_;
+};
+
+/// @brief Type of pointers to contexts.
+typedef boost::shared_ptr<PgSqlLeaseContext> PgSqlLeaseContextPtr;
+
+/// @brief PostgreSQL Lease Context Pool
+///
+/// This class provides a pool of contexts.
+class PgSqlLeaseContextPool {
+public:
+
+    /// @brief The vector of available contexts.
+    std::vector<PgSqlLeaseContextPtr> pool_;
+
+    /// @brief The mutex to protect pool access.
+    std::mutex mutex_;
+};
+
+/// @brief Type of pointers to context pools.
+typedef boost::shared_ptr<PgSqlLeaseContextPool> PgSqlLeaseContextPoolPtr;
+
 /// @brief PostgreSQL Lease Manager
 ///
 /// This class provides the \ref isc::dhcp::LeaseMgr interface to the PostgreSQL
@@ -43,11 +83,7 @@ public:
     /// - user - Username under which to connect (optional)
     /// - password - Password for "user" on the database (optional)
     ///
-    /// If the database is successfully opened, the version number in the
-    /// schema_version table will be checked against hard-coded value in
-    /// the implementation file.
-    ///
-    /// Finally, all the SQL commands are pre-compiled.
+    /// Check the schema version and create an initial context.
     ///
     /// @param parameters A data structure relating keywords and values
     ///        concerned with the database.
@@ -61,6 +97,16 @@ public:
     /// @brief Destructor (closes database)
     virtual ~PgSqlLeaseMgr();
 
+    /// @brief Create a new context.
+    ///
+    /// The database is opened with all the SQL commands pre-compiled.
+    ///
+    /// @return A new (never null) context.
+    /// @throw isc::dhcp::NoDatabaseName Mandatory database name not given.
+    /// @throw isc::db::DbOperationError An operation on the open database has
+    /// failed.
+    PgSqlLeaseContextPtr createContext() const;
+
     /// @brief Local version of getDBVersion() class method
     static std::string getDBVersion();
 
@@ -595,6 +641,7 @@ private:
     /// of the addLease method.  It binds the contents of the lease object to
     /// the prepared statement and adds it to the database.
     ///
+    /// @param ctx Context
     /// @param stindex Index of statement being executed
     /// @param bind_array array that has been created for the type
     ///        of lease in question.
@@ -604,13 +651,15 @@ private:
     ///
     /// @throw isc::db::DbOperationError An operation on the open database has
     ///        failed.
-    bool addLeaseCommon(StatementIndex stindex, db::PsqlBindArray& bind_array);
+    bool addLeaseCommon(PgSqlLeaseContextPtr ctx,
+                        StatementIndex stindex, db::PsqlBindArray& bind_array);
 
     /// @brief Get Lease Collection Common Code
     ///
     /// This method performs the common actions for obtaining multiple leases
     /// from the database.
     ///
+    /// @param ctx Context
     /// @param stindex Index of statement being executed
     /// @param bind_array array containing the where clause input parameters
     /// @param exchange Exchange object to use
@@ -627,7 +676,9 @@ private:
     /// @throw isc::db::MultipleRecords Multiple records were retrieved
     ///        from the database where only one was expected.
     template <typename Exchange, typename LeaseCollection>
-    void getLeaseCollection(StatementIndex stindex, db::PsqlBindArray& bind_array,
+    void getLeaseCollection(PgSqlLeaseContextPtr ctx,
+                            StatementIndex stindex,
+                            db::PsqlBindArray& bind_array,
                             Exchange& exchange, LeaseCollection& result,
                             bool single = false) const;
 
@@ -636,6 +687,7 @@ private:
     /// Gets a collection of Lease4 objects.  This is just an interface to
     /// the get lease collection common code.
     ///
+    /// @param ctx Context
     /// @param stindex Index of statement being executed
     /// @param bind_array array containing the where clause input parameters
     /// @param lease LeaseCollection object returned.  Note that any leases in
@@ -647,9 +699,11 @@ private:
     ///        failed.
     /// @throw isc::db::MultipleRecords Multiple records were retrieved
     ///        from the database where only one was expected.
-    void getLeaseCollection(StatementIndex stindex, db::PsqlBindArray& bind_array,
+    void getLeaseCollection(PgSqlLeaseContextPtr ctx,
+                            StatementIndex stindex,
+                            db::PsqlBindArray& bind_array,
                             Lease4Collection& result) const {
-        getLeaseCollection(stindex, bind_array, exchange4_, result);
+        getLeaseCollection(ctx, stindex, bind_array, ctx->exchange4_, result);
     }
 
     /// @brief Get Lease6 Collection
@@ -657,6 +711,7 @@ private:
     /// Gets a collection of Lease6 objects.  This is just an interface to
     /// the get lease collection common code.
     ///
+    /// @param ctx Context
     /// @param stindex Index of statement being executed
     /// @param bind_array array containing input parameters for the query
     /// @param lease LeaseCollection object returned.  Note that any existing
@@ -667,9 +722,11 @@ private:
     ///        failed.
     /// @throw isc::db::MultipleRecords Multiple records were retrieved
     ///        from the database where only one was expected.
-    void getLeaseCollection(StatementIndex stindex, db::PsqlBindArray& bind_array,
+    void getLeaseCollection(PgSqlLeaseContextPtr ctx,
+                            StatementIndex stindex,
+                            db::PsqlBindArray& bind_array,
                             Lease6Collection& result) const {
-        getLeaseCollection(stindex, bind_array, exchange6_, result);
+        getLeaseCollection(ctx, stindex, bind_array, ctx->exchange6_, result);
     }
 
     /// @brief Get Lease4 Common Code
@@ -678,10 +735,12 @@ private:
     /// methods.  It acts as an interface to the getLeaseCollection() method,
     /// but retrieving only a single lease.
     ///
+    /// @param ctx Context
     /// @param stindex Index of statement being executed
     /// @param bind_array array containing input parameters for the query
     /// @param lease Lease4 object returned
-    void getLease(StatementIndex stindex, db::PsqlBindArray& bind_array,
+    void getLease(PgSqlLeaseContextPtr ctx,
+                  StatementIndex stindex, db::PsqlBindArray& bind_array,
                   Lease4Ptr& result) const;
 
     /// @brief Get Lease6 Common Code
@@ -690,10 +749,12 @@ private:
     /// methods.  It acts as an interface to the getLeaseCollection() method,
     /// but retrieving only a single lease.
     ///
+    /// @param ctx Context
     /// @param stindex Index of statement being executed
     /// @param bind_array array containing input parameters for the query
     /// @param lease Lease6 object returned
-    void getLease(StatementIndex stindex, db::PsqlBindArray& bind_array,
+    void getLease(PgSqlLeaseContextPtr ctx,
+                  StatementIndex stindex, db::PsqlBindArray& bind_array,
                   Lease6Ptr& result) const;
 
     /// @brief Get expired leases common code.
@@ -721,6 +782,7 @@ private:
     /// to the prepared statement, executes it, then checks how many rows
     /// were affected.
     ///
+    /// @param ctx Context
     /// @param stindex Index of prepared statement to be executed
     /// @param bind_array array containing lease values and where clause
     /// parameters for the update.
@@ -731,7 +793,9 @@ private:
     /// @throw isc::db::DbOperationError An operation on the open database has
     ///        failed.
     template <typename LeasePtr>
-    void updateLeaseCommon(StatementIndex stindex, db::PsqlBindArray& bind_array,
+    void updateLeaseCommon(PgSqlLeaseContextPtr ctx,
+                           StatementIndex stindex,
+                           db::PsqlBindArray& bind_array,
                            const LeasePtr& lease);
 
     /// @brief Delete lease common code
@@ -763,18 +827,38 @@ private:
     uint64_t deleteExpiredReclaimedLeasesCommon(const uint32_t secs,
                                                 StatementIndex statement_index);
 
-    /// The exchange objects are used for transfer of data to/from the database.
-    /// They are pointed-to objects as the contents may change in "const" calls,
-    /// while the rest of this object does not.  (At alternative would be to
-    /// declare them as "mutable".)
-    boost::scoped_ptr<PgSqlLease4Exchange> exchange4_; ///< Exchange object
-    boost::scoped_ptr<PgSqlLease6Exchange> exchange6_; ///< Exchange object
+    /// @brief Context RAII Allocator.
+    class PgSqlLeaseContextAlloc {
+    public:
+
+        /// @brief Constructor
+        ///
+        /// This constructor takes a context of the pool if one is available
+        /// or creates a new one.
+        ///
+        /// @param mgr A parent instance
+        PgSqlLeaseContextAlloc(const PgSqlLeaseMgr& mgr);
+
+        /// @brief Destructor
+        ///
+        /// This destructor puts back the context in the pool.
+        ~PgSqlLeaseContextAlloc();
+
+        /// @brief The context
+        PgSqlLeaseContextPtr ctx_;
+
+    private:
+        /// @brief The manager
+        const PgSqlLeaseMgr& mgr_;
+    };
+
+    // Members
 
     /// The parameters.
     db::DatabaseConnection::ParameterMap parameters_;
 
-    /// PostgreSQL connection handle
-    db::PgSqlConnection conn_;
+    /// @brief The pool of contexts
+    PgSqlLeaseContextPoolPtr pool_;
 };
 
 }  // namespace dhcp
index 1856186cd7f62b29f77e10158717c8a7deed8c5b..18322a6e239356d87d9f2352d7fd71c7177b8b9c 100644 (file)
@@ -14,6 +14,7 @@
 #include <dhcpsrv/tests/generic_lease_mgr_unittest.h>
 #include <pgsql/pgsql_connection.h>
 #include <pgsql/testutils/pgsql_schema.h>
+#include <util/multi_threading_mgr.h>
 
 #include <gtest/gtest.h>
 
@@ -29,6 +30,7 @@ using namespace isc::db;
 using namespace isc::db::test;
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
+using namespace isc::util;
 using namespace std;
 
 namespace {
@@ -59,6 +61,8 @@ public:
         }
 
         lmptr_ = &(LeaseMgrFactory::instance());
+
+        MultiThreadingMgr::instance().setMode(false);
     }
 
     /// @brief Destroys the LM and the schema.
@@ -71,6 +75,9 @@ public:
         LeaseMgrFactory::destroy();
         // If data wipe enabled, delete transient data otherwise destroy the schema
         destroyPgSQLSchema();
+
+        // Disable Multi-Threading.
+        MultiThreadingMgr::instance().setMode(false);
     }
 
     /// @brief Constructor
@@ -110,6 +117,9 @@ public:
 /// opened: the fixtures assume that and check basic operations.
 
 TEST(PgSqlOpenTest, OpenDatabase) {
+    // Explicitely disable Multi-Threading.
+    MultiThreadingMgr::instance().setMode(false);
+
     // Schema needs to be created for the test to work.
     createPgSQLSchema();
 
@@ -194,6 +204,34 @@ TEST(PgSqlOpenTest, OpenDatabase) {
     destroyPgSQLSchema();
 }
 
+/// @brief Check that database can be opened with Multi-Threading
+TEST(PgSqlOpenTest, OpenDatabaseMultiThreading) {
+    // Enable Multi-Threading.
+    MultiThreadingMgr::instance().setMode(true);
+
+    // Schema needs to be created for the test to work.
+    createPgSQLSchema();
+
+    // Check that lease manager open the database opens correctly and tidy up.
+    // If it fails, print the error message.
+    try {
+        LeaseMgrFactory::create(validPgSQLConnectionString());
+        EXPECT_NO_THROW((void)LeaseMgrFactory::instance());
+        LeaseMgrFactory::destroy();
+    } catch (const isc::Exception& ex) {
+        FAIL() << "*** ERROR: unable to open database, reason:\n"
+               << "    " << ex.what() << "\n"
+               << "*** The test environment is broken and must be fixed\n"
+               << "*** before the PostgreSQL tests will run correctly.\n";
+    }
+
+    // Tidy up after the test
+    destroyPgSQLSchema();
+
+    // Disable Multi-Threading.
+    MultiThreadingMgr::instance().setMode(false);
+}
+
 /// @brief Test fixture class for validating @c LeaseMgr using
 /// PostgreSQL as back end and PostgreSQL connectivity loss.
 class PgSqlLeaseMgrDbLostCallbackTest : public LeaseMgrDbLostCallbackTest {
@@ -220,11 +258,25 @@ public:
 
 // Verifies that db lost callback is not invoked on an open failure
 TEST_F(PgSqlLeaseMgrDbLostCallbackTest, testNoCallbackOnOpenFailure) {
+    MultiThreadingMgr::instance().setMode(false);
+    testDbLostCallback();
+}
+
+// Verifies that db lost callback is not invoked on an open failure
+TEST_F(PgSqlLeaseMgrDbLostCallbackTest, testNoCallbackOnOpenFailureMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
     testDbLostCallback();
 }
 
 // Verifies that loss of connectivity to PostgreSQL is handled correctly.
 TEST_F(PgSqlLeaseMgrDbLostCallbackTest, testDbLostCallback) {
+    MultiThreadingMgr::instance().setMode(false);
+    testDbLostCallback();
+}
+
+// Verifies that loss of connectivity to PostgreSQL is handled correctly.
+TEST_F(PgSqlLeaseMgrDbLostCallbackTest, testDbLostCallbackMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
     testDbLostCallback();
 }
 
@@ -262,11 +314,23 @@ TEST_F(PgSqlLeaseMgrTest, basicLease4) {
     testBasicLease4();
 }
 
+/// @brief Basic Lease4 Checks
+TEST_F(PgSqlLeaseMgrTest, basicLease4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testBasicLease4();
+}
+
 /// @brief Check that Lease4 code safely handles invalid dates.
 TEST_F(PgSqlLeaseMgrTest, maxDate4) {
     testMaxDate4();
 }
 
+/// @brief Check that Lease4 code safely handles invalid dates.
+TEST_F(PgSqlLeaseMgrTest, maxDate4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testMaxDate4();
+}
+
 /// @brief Lease4 update tests
 ///
 /// Checks that we are able to update a lease in the database.
@@ -274,16 +338,34 @@ TEST_F(PgSqlLeaseMgrTest, updateLease4) {
     testUpdateLease4();
 }
 
+/// @brief Lease4 update tests
+TEST_F(PgSqlLeaseMgrTest, updateLease4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testUpdateLease4();
+}
+
 /// @brief Check GetLease4 methods - access by Hardware Address
 TEST_F(PgSqlLeaseMgrTest, getLease4HWAddr1) {
     testGetLease4HWAddr1();
 }
 
+/// @brief Check GetLease4 methods - access by Hardware Address
+TEST_F(PgSqlLeaseMgrTest, getLease4HWAddr1MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease4HWAddr1();
+}
+
 /// @brief Check GetLease4 methods - access by Hardware Address
 TEST_F(PgSqlLeaseMgrTest, getLease4HWAddr2) {
     testGetLease4HWAddr2();
 }
 
+/// @brief Check GetLease4 methods - access by Hardware Address
+TEST_F(PgSqlLeaseMgrTest, getLease4HWAddr2MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease4HWAddr2();
+}
+
 // @brief Get lease4 by hardware address (2)
 //
 // Check that the system can cope with getting a hardware address of
@@ -292,6 +374,12 @@ TEST_F(PgSqlLeaseMgrTest, getLease4HWAddrSize) {
     testGetLease4HWAddrSize();
 }
 
+// @brief Get lease4 by hardware address (2)
+TEST_F(PgSqlLeaseMgrTest, getLease4HWAddrSizeMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease4HWAddrSize();
+}
+
 /// @brief Check GetLease4 methods - access by Hardware Address & Subnet ID
 ///
 /// Adds leases to the database and checks that they can be accessed via
@@ -300,6 +388,12 @@ TEST_F(PgSqlLeaseMgrTest, getLease4HwaddrSubnetId) {
     testGetLease4HWAddrSubnetId();
 }
 
+/// @brief Check GetLease4 methods - access by Hardware Address & Subnet ID
+TEST_F(PgSqlLeaseMgrTest, getLease4HwaddrSubnetIdMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease4HWAddrSubnetId();
+}
+
 // @brief Get lease4 by hardware address and subnet ID (2)
 //
 // Check that the system can cope with getting a hardware address of
@@ -308,11 +402,23 @@ TEST_F(PgSqlLeaseMgrTest, getLease4HWAddrSubnetIdSize) {
     testGetLease4HWAddrSubnetIdSize();
 }
 
+// @brief Get lease4 by hardware address and subnet ID (2)
+TEST_F(PgSqlLeaseMgrTest, getLease4HWAddrSubnetIdSizeMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease4HWAddrSubnetIdSize();
+}
+
 // This test was derived from memfile.
 TEST_F(PgSqlLeaseMgrTest, getLease4ClientId) {
     testGetLease4ClientId();
 }
 
+// This test was derived from memfile.
+TEST_F(PgSqlLeaseMgrTest, getLease4ClientIdMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease4ClientId();
+}
+
 /// @brief Check GetLease4 methods - access by Client ID
 ///
 /// Adds leases to the database and checks that they can be accessed via
@@ -321,6 +427,12 @@ TEST_F(PgSqlLeaseMgrTest, getLease4ClientId2) {
     testGetLease4ClientId2();
 }
 
+/// @brief Check GetLease4 methods - access by Client ID
+TEST_F(PgSqlLeaseMgrTest, getLease4ClientId2MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease4ClientId2();
+}
+
 // @brief Get Lease4 by client ID (2)
 //
 // Check that the system can cope with a client ID of any size.
@@ -328,6 +440,12 @@ TEST_F(PgSqlLeaseMgrTest, getLease4ClientIdSize) {
     testGetLease4ClientIdSize();
 }
 
+// @brief Get Lease4 by client ID (2)
+TEST_F(PgSqlLeaseMgrTest, getLease4ClientIdSizeMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease4ClientIdSize();
+}
+
 /// @brief Check GetLease4 methods - access by Client ID & Subnet ID
 ///
 /// Adds leases to the database and checks that they can be accessed via
@@ -336,46 +454,100 @@ TEST_F(PgSqlLeaseMgrTest, getLease4ClientIdSubnetId) {
     testGetLease4ClientIdSubnetId();
 }
 
+/// @brief Check GetLease4 methods - access by Client ID & Subnet ID
+TEST_F(PgSqlLeaseMgrTest, getLease4ClientIdSubnetIdMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease4ClientIdSubnetId();
+}
+
 // This test checks that all IPv4 leases for a specified subnet id are returned.
 TEST_F(PgSqlLeaseMgrTest, getLeases4SubnetId) {
     testGetLeases4SubnetId();
 }
 
+// This test checks that all IPv4 leases for a specified subnet id are returned.
+TEST_F(PgSqlLeaseMgrTest, getLeases4SubnetIdMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases4SubnetId();
+}
+
 // This test checks that all IPv4 leases with a specified hostname are returned.
 TEST_F(PgSqlLeaseMgrTest, getLeases4Hostname) {
     testGetLeases4Hostname();
 }
 
+// This test checks that all IPv4 leases with a specified hostname are returned.
+TEST_F(PgSqlLeaseMgrTest, getLeases4HostnameMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases4Hostname();
+}
+
 // This test checks that all IPv4 leases are returned.
 TEST_F(PgSqlLeaseMgrTest, getLeases4) {
     testGetLeases4();
 }
 
+// This test checks that all IPv4 leases are returned.
+TEST_F(PgSqlLeaseMgrTest, getLeases4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases4();
+}
+
 // Test that a range of IPv4 leases is returned with paging.
 TEST_F(PgSqlLeaseMgrTest, getLeases4Paged) {
     testGetLeases4Paged();
 }
 
+// Test that a range of IPv4 leases is returned with paging.
+TEST_F(PgSqlLeaseMgrTest, getLeases4PagedMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases4Paged();
+}
+
 // This test checks that all IPv6 leases for a specified subnet id are returned.
 TEST_F(PgSqlLeaseMgrTest, getLeases6SubnetId) {
     testGetLeases6SubnetId();
 }
 
+// This test checks that all IPv6 leases for a specified subnet id are returned.
+TEST_F(PgSqlLeaseMgrTest, getLeases6SubnetIdMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases6SubnetId();
+}
+
 // This test checks that all IPv6 leases with a specified hostname are returned.
 TEST_F(PgSqlLeaseMgrTest, getLeases6Hostname) {
     testGetLeases6Hostname();
 }
 
+// This test checks that all IPv6 leases with a specified hostname are returned.
+TEST_F(PgSqlLeaseMgrTest, getLeases6HostnameMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases6Hostname();
+}
+
 // This test checks that all IPv6 leases are returned.
 TEST_F(PgSqlLeaseMgrTest, getLeases6) {
     testGetLeases6();
 }
 
+// This test checks that all IPv6 leases are returned.
+TEST_F(PgSqlLeaseMgrTest, getLeases6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases6();
+}
+
 // Test that a range of IPv6 leases is returned with paging.
 TEST_F(PgSqlLeaseMgrTest, getLeases6Paged) {
     testGetLeases6Paged();
 }
 
+// Test that a range of IPv6 leases is returned with paging.
+TEST_F(PgSqlLeaseMgrTest, getLeases6PagedMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases6Paged();
+}
+
 /// @brief Basic Lease4 Checks
 ///
 /// Checks that the addLease, getLease4(by address), getLease4(hwaddr,subnet_id),
@@ -385,6 +557,12 @@ TEST_F(PgSqlLeaseMgrTest, lease4NullClientId) {
     testLease4NullClientId();
 }
 
+/// @brief Basic Lease4 Checks
+TEST_F(PgSqlLeaseMgrTest, lease4NullClientIdMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testLease4NullClientId();
+}
+
 /// @brief Verify that too long hostname for Lease4 is not accepted.
 ///
 /// Checks that the it is not possible to create a lease when the hostname
@@ -393,6 +571,12 @@ TEST_F(PgSqlLeaseMgrTest, lease4InvalidHostname) {
     testLease4InvalidHostname();
 }
 
+/// @brief Verify that too long hostname for Lease4 is not accepted.
+TEST_F(PgSqlLeaseMgrTest, lease4InvalidHostnameMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testLease4InvalidHostname();
+}
+
 /// @brief Check that the expired DHCPv4 leases can be retrieved.
 ///
 /// This test adds a number of leases to the lease database and marks
@@ -404,11 +588,23 @@ TEST_F(PgSqlLeaseMgrTest, getExpiredLeases4) {
     testGetExpiredLeases4();
 }
 
+/// @brief Check that the expired DHCPv4 leases can be retrieved.
+TEST_F(PgSqlLeaseMgrTest, getExpiredLeases4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetExpiredLeases4();
+}
+
 /// @brief Check that expired reclaimed DHCPv4 leases are removed.
 TEST_F(PgSqlLeaseMgrTest, deleteExpiredReclaimedLeases4) {
     testDeleteExpiredReclaimedLeases4();
 }
 
+/// @brief Check that expired reclaimed DHCPv4 leases are removed.
+TEST_F(PgSqlLeaseMgrTest, deleteExpiredReclaimedLeases4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testDeleteExpiredReclaimedLeases4();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 /// LEASE6 /////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
@@ -419,6 +615,13 @@ TEST_F(PgSqlLeaseMgrTest, testAddGetDelete6) {
     testAddGetDelete6();
 }
 
+// Test checks whether simple add, get and delete operations are possible
+// on Lease6
+TEST_F(PgSqlLeaseMgrTest, testAddGetDelete6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testAddGetDelete6();
+}
+
 /// @brief Basic Lease6 Checks
 ///
 /// Checks that the addLease, getLease6 (by address) and deleteLease (with an
@@ -427,11 +630,23 @@ TEST_F(PgSqlLeaseMgrTest, basicLease6) {
     testBasicLease6();
 }
 
+/// @brief Basic Lease6 Checks
+TEST_F(PgSqlLeaseMgrTest, basicLease6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testBasicLease6();
+}
+
 /// @brief Check that Lease6 code safely handles invalid dates.
 TEST_F(PgSqlLeaseMgrTest, maxDate6) {
     testMaxDate6();
 }
 
+/// @brief Check that Lease6 code safely handles invalid dates.
+TEST_F(PgSqlLeaseMgrTest, maxDate6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testMaxDate6();
+}
+
 /// @brief Verify that too long hostname for Lease6 is not accepted.
 ///
 /// Checks that the it is not possible to create a lease when the hostname
@@ -440,6 +655,12 @@ TEST_F(PgSqlLeaseMgrTest, lease6InvalidHostname) {
     testLease6InvalidHostname();
 }
 
+/// @brief Verify that too long hostname for Lease6 is not accepted.
+TEST_F(PgSqlLeaseMgrTest, lease6InvalidHostnameMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testLease6InvalidHostname();
+}
+
 /// @brief Verify that large IAID values work correctly.
 ///
 /// Adds lease with a large IAID to the database and verifies it can
@@ -448,6 +669,12 @@ TEST_F(PgSqlLeaseMgrTest, leases6LargeIaidCheck) {
     testLease6LargeIaidCheck();
 }
 
+/// @brief Verify that large IAID values work correctly.
+TEST_F(PgSqlLeaseMgrTest, leases6LargeIaidCheckMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testLease6LargeIaidCheck();
+}
+
 /// @brief Check GetLease6 methods - access by DUID/IAID
 ///
 /// Adds leases to the database and checks that they can be accessed via
@@ -456,11 +683,23 @@ TEST_F(PgSqlLeaseMgrTest, getLeases6DuidIaid) {
     testGetLeases6DuidIaid();
 }
 
+/// @brief Check GetLease6 methods - access by DUID/IAID
+TEST_F(PgSqlLeaseMgrTest, getLeases6DuidIaidMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases6DuidIaid();
+}
+
 // Check that the system can cope with a DUID of allowed size.
 TEST_F(PgSqlLeaseMgrTest, getLeases6DuidSize) {
     testGetLeases6DuidSize();
 }
 
+// Check that the system can cope with a DUID of allowed size.
+TEST_F(PgSqlLeaseMgrTest, getLeases6DuidSizeMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases6DuidSize();
+}
+
 /// @brief Check that getLease6 methods discriminate by lease type.
 ///
 /// Adds six leases, two per lease type all with the same duid and iad but
@@ -471,6 +710,12 @@ TEST_F(PgSqlLeaseMgrTest, lease6LeaseTypeCheck) {
     testLease6LeaseTypeCheck();
 }
 
+/// @brief Check that getLease6 methods discriminate by lease type.
+TEST_F(PgSqlLeaseMgrTest, lease6LeaseTypeCheckMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testLease6LeaseTypeCheck();
+}
+
 /// @brief Verifies the getLeases6(DUID) method
 ///
 /// Adds 3 lease and verifies fetch by DUID.
@@ -479,6 +724,12 @@ TEST_F(PgSqlLeaseMgrTest, getLeases6Duid) {
     testGetLeases6Duid();
 }
 
+/// @brief Verifies the getLeases6(DUID) method
+TEST_F(PgSqlLeaseMgrTest, getLeases6DuidMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases6Duid();
+}
+
 /// @brief Check GetLease6 methods - access by DUID/IAID/SubnetID
 ///
 /// Adds leases to the database and checks that they can be accessed via
@@ -487,11 +738,23 @@ TEST_F(PgSqlLeaseMgrTest, getLease6DuidIaidSubnetId) {
     testGetLease6DuidIaidSubnetId();
 }
 
+/// @brief Check GetLease6 methods - access by DUID/IAID/SubnetID
+TEST_F(PgSqlLeaseMgrTest, getLease6DuidIaidSubnetIdMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease6DuidIaidSubnetId();
+}
+
 // Test checks that getLease6() works with different DUID sizes
 TEST_F(PgSqlLeaseMgrTest, getLease6DuidIaidSubnetIdSize) {
     testGetLease6DuidIaidSubnetIdSize();
 }
 
+// Test checks that getLease6() works with different DUID sizes
+TEST_F(PgSqlLeaseMgrTest, getLease6DuidIaidSubnetIdSizeMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease6DuidIaidSubnetIdSize();
+}
+
 /// @brief Lease6 update tests
 ///
 /// Checks that we are able to update a lease in the database.
@@ -499,6 +762,12 @@ TEST_F(PgSqlLeaseMgrTest, updateLease6) {
     testUpdateLease6();
 }
 
+/// @brief Lease6 update tests
+TEST_F(PgSqlLeaseMgrTest, updateLease6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testUpdateLease6();
+}
+
 /// @brief DHCPv4 Lease recreation tests
 ///
 /// Checks that the lease can be created, deleted and recreated with
@@ -508,6 +777,12 @@ TEST_F(PgSqlLeaseMgrTest, testRecreateLease4) {
     testRecreateLease4();
 }
 
+/// @brief DHCPv4 Lease recreation tests
+TEST_F(PgSqlLeaseMgrTest, testRecreateLease4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testRecreateLease4();
+}
+
 /// @brief DHCPv6 Lease recreation tests
 ///
 /// Checks that the lease can be created, deleted and recreated with
@@ -517,21 +792,45 @@ TEST_F(PgSqlLeaseMgrTest, testRecreateLease6) {
     testRecreateLease6();
 }
 
+/// @brief DHCPv6 Lease recreation tests
+TEST_F(PgSqlLeaseMgrTest, testRecreateLease6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testRecreateLease6();
+}
+
 /// @brief Checks that null DUID is not allowed.
 TEST_F(PgSqlLeaseMgrTest, nullDuid) {
     testNullDuid();
 }
 
+/// @brief Checks that null DUID is not allowed.
+TEST_F(PgSqlLeaseMgrTest, nullDuidMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testNullDuid();
+}
+
 /// @brief Tests whether PostgreSQL can store and retrieve hardware addresses
 TEST_F(PgSqlLeaseMgrTest, testLease6Mac) {
     testLease6MAC();
 }
 
+/// @brief Tests whether PostgreSQL can store and retrieve hardware addresses
+TEST_F(PgSqlLeaseMgrTest, testLease6MacMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testLease6MAC();
+}
+
 /// @brief Tests whether PostgreSQL can store and retrieve hardware addresses
 TEST_F(PgSqlLeaseMgrTest, testLease6HWTypeAndSource) {
     testLease6HWTypeAndSource();
 }
 
+/// @brief Tests whether PostgreSQL can store and retrieve hardware addresses
+TEST_F(PgSqlLeaseMgrTest, testLease6HWTypeAndSourceMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testLease6HWTypeAndSource();
+}
+
 /// @brief Check that the expired DHCPv6 leases can be retrieved.
 ///
 /// This test adds a number of leases to the lease database and marks
@@ -543,39 +842,87 @@ TEST_F(PgSqlLeaseMgrTest, getExpiredLeases6) {
     testGetExpiredLeases6();
 }
 
+/// @brief Check that the expired DHCPv6 leases can be retrieved.
+TEST_F(PgSqlLeaseMgrTest, getExpiredLeases6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetExpiredLeases6();
+}
+
 /// @brief Check that expired reclaimed DHCPv6 leases are removed.
 TEST_F(PgSqlLeaseMgrTest, deleteExpiredReclaimedLeases6) {
     testDeleteExpiredReclaimedLeases6();
 }
 
+/// @brief Check that expired reclaimed DHCPv6 leases are removed.
+TEST_F(PgSqlLeaseMgrTest, deleteExpiredReclaimedLeases6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testDeleteExpiredReclaimedLeases6();
+}
+
 /// @brief Verifies that IPv4 lease statistics can be recalculated.
 TEST_F(PgSqlLeaseMgrTest, recountLeaseStats4) {
     testRecountLeaseStats4();
 }
 
+/// @brief Verifies that IPv4 lease statistics can be recalculated.
+TEST_F(PgSqlLeaseMgrTest, recountLeaseStats4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testRecountLeaseStats4();
+}
+
 /// @brief Verifies that IPv6 lease statistics can be recalculated.
 TEST_F(PgSqlLeaseMgrTest, recountLeaseStats6) {
     testRecountLeaseStats6();
 }
 
+/// @brief Verifies that IPv6 lease statistics can be recalculated.
+TEST_F(PgSqlLeaseMgrTest, recountLeaseStats6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testRecountLeaseStats6();
+}
+
 /// @brief Tests that leases from specific subnet can be removed.
 TEST_F(PgSqlLeaseMgrTest, DISABLED_wipeLeases4) {
     testWipeLeases4();
 }
 
+/// @brief Tests that leases from specific subnet can be removed.
+TEST_F(PgSqlLeaseMgrTest, DISABLED_wipeLeases4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testWipeLeases4();
+}
+
 /// @brief Tests that leases from specific subnet can be removed.
 TEST_F(PgSqlLeaseMgrTest, DISABLED_wipeLeases6) {
     testWipeLeases6();
 }
 
+/// @brief Tests that leases from specific subnet can be removed.
+TEST_F(PgSqlLeaseMgrTest, DISABLED_wipeLeases6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testWipeLeases6();
+}
+
 // Tests v4 lease stats query variants.
 TEST_F(PgSqlLeaseMgrTest, leaseStatsQuery4) {
     testLeaseStatsQuery4();
 }
 
+// Tests v4 lease stats query variants.
+TEST_F(PgSqlLeaseMgrTest, leaseStatsQuery4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testLeaseStatsQuery4();
+}
+
 // Tests v6 lease stats query variants.
 TEST_F(PgSqlLeaseMgrTest, leaseStatsQuery6) {
     testLeaseStatsQuery6();
 }
 
+// Tests v6 lease stats query variants.
+TEST_F(PgSqlLeaseMgrTest, leaseStatsQuery6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testLeaseStatsQuery6();
+}
+
 }  // namespace