]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[894-make-memfile-thread-safe] Made memfile code thread safe
authorFrancis Dupont <fdupont@isc.org>
Thu, 24 Oct 2019 14:09:19 +0000 (16:09 +0200)
committerRazvan Becheriu <razvan@isc.org>
Thu, 23 Jan 2020 13:26:40 +0000 (15:26 +0200)
src/lib/dhcpsrv/memfile_lease_mgr.cc
src/lib/dhcpsrv/memfile_lease_mgr.h
src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc

index 3f4aae6a29d2b9751f7cee61bf3c0d0ac8828a55..4064f156fef43540a0b2aa7f9dbd04358e7f18cc 100644 (file)
@@ -13,6 +13,7 @@
 #include <dhcpsrv/memfile_lease_mgr.h>
 #include <dhcpsrv/timer_mgr.h>
 #include <exceptions/exceptions.h>
+#include <util/multi_threading_mgr.h>
 #include <util/pid_file.h>
 #include <util/process_spawn.h>
 #include <util/signal_set.h>
@@ -629,8 +630,7 @@ const int Memfile_LeaseMgr::MAJOR_VERSION;
 const int Memfile_LeaseMgr::MINOR_VERSION;
 
 Memfile_LeaseMgr::Memfile_LeaseMgr(const DatabaseConnection::ParameterMap& parameters)
-    : LeaseMgr(), lfc_setup_(), conn_(parameters)
-    {
+    : LeaseMgr(), lfc_setup_(), conn_(parameters), mutex_() {
     bool conversion_needed = false;
 
     // Check the universe and use v4 file or v6 file.
@@ -657,8 +657,8 @@ Memfile_LeaseMgr::Memfile_LeaseMgr(const DatabaseConnection::ParameterMap& param
     // issue a warning. It is ok not to write leases to disk when
     // doing testing, but it should not be done in normal server
     // operation.
-   if (!persistLeases(V4) && !persistLeases(V6)) {
-        LOG_WARN(dhcpsrv_logger, DHCPSRV_MEMFILE_NO_STORAGE);
+    if (!persistLeases(V4) && !persistLeases(V6)) {
+       LOG_WARN(dhcpsrv_logger, DHCPSRV_MEMFILE_NO_STORAGE);
     } else  {
         if (conversion_needed) {
             LOG_WARN(dhcpsrv_logger, DHCPSRV_MEMFILE_CONVERTING_LEASE_FILES)
@@ -667,6 +667,7 @@ Memfile_LeaseMgr::Memfile_LeaseMgr(const DatabaseConnection::ParameterMap& param
         lfcSetup(conversion_needed);
     }
 
+    mutex_.reset(new std::mutex);
 }
 
 Memfile_LeaseMgr::~Memfile_LeaseMgr() {
@@ -689,11 +690,8 @@ Memfile_LeaseMgr::getDBVersion() {
 }
 
 bool
-Memfile_LeaseMgr::addLease(const Lease4Ptr& lease) {
-    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
-              DHCPSRV_MEMFILE_ADD_ADDR4).arg(lease->addr_.toText());
-
-    if (getLease4(lease->addr_)) {
+Memfile_LeaseMgr::addLeaseInternal(const Lease4Ptr& lease) {
+    if (getLease4Internal(lease->addr_)) {
         // there is a lease with specified address already
         return (false);
     }
@@ -710,11 +708,21 @@ Memfile_LeaseMgr::addLease(const Lease4Ptr& lease) {
 }
 
 bool
-Memfile_LeaseMgr::addLease(const Lease6Ptr& lease) {
+Memfile_LeaseMgr::addLease(const Lease4Ptr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
-              DHCPSRV_MEMFILE_ADD_ADDR6).arg(lease->addr_.toText());
+              DHCPSRV_MEMFILE_ADD_ADDR4).arg(lease->addr_.toText());
+
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        return (addLeaseInternal(lease));
+    } else {
+        return (addLeaseInternal(lease));
+    }
+}
 
-    if (getLease6(lease->type_, lease->addr_)) {
+bool
+Memfile_LeaseMgr::addLeaseInternal(const Lease6Ptr& lease) {
+    if (getLease6Internal(lease->type_, lease->addr_)) {
         // there is a lease with specified address already
         return (false);
     }
@@ -730,11 +738,21 @@ Memfile_LeaseMgr::addLease(const Lease6Ptr& lease) {
     return (true);
 }
 
-Lease4Ptr
-Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const {
+bool
+Memfile_LeaseMgr::addLease(const Lease6Ptr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
-              DHCPSRV_MEMFILE_GET_ADDR4).arg(addr.toText());
+              DHCPSRV_MEMFILE_ADD_ADDR6).arg(lease->addr_.toText());
+
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        return (addLeaseInternal(lease));
+    } else {
+        return (addLeaseInternal(lease));
+    }
+}
 
+Lease4Ptr
+Memfile_LeaseMgr::getLease4Internal(const isc::asiolink::IOAddress& addr) const {
     const Lease4StorageAddressIndex& idx = storage4_.get<AddressIndexTag>();
     Lease4StorageAddressIndex::iterator l = idx.find(addr);
     if (l == idx.end()) {
@@ -744,12 +762,22 @@ Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const {
     }
 }
 
-Lease4Collection
-Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr) const {
+Lease4Ptr
+Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
-              DHCPSRV_MEMFILE_GET_HWADDR).arg(hwaddr.toText());
-    Lease4Collection collection;
+              DHCPSRV_MEMFILE_GET_ADDR4).arg(addr.toText());
+
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        return (getLease4Internal(addr));
+    } else {
+        return (getLease4Internal(addr));
+    }
+}
 
+void
+Memfile_LeaseMgr::getLease4Internal(const HWAddr& hwaddr,
+                                    Lease4Collection& collection) const {
     // Using composite index by 'hw address' and 'subnet id'. It is
     // ok to use it for searching by the 'hw address' only.
     const Lease4StorageHWAddressSubnetIdIndex& idx =
@@ -761,16 +789,27 @@ Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr) const {
     for(auto lease = l.first; lease != l.second; ++lease) {
         collection.push_back(Lease4Ptr(new Lease4(**lease)));
     }
+}
+
+Lease4Collection
+Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr) const {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
+              DHCPSRV_MEMFILE_GET_HWADDR).arg(hwaddr.toText());
+    Lease4Collection collection;
+
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        getLease4Internal(hwaddr, collection);
+    } else {
+        getLease4Internal(hwaddr, collection);
+    }
 
     return (collection);
 }
 
 Lease4Ptr
-Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
-    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
-              DHCPSRV_MEMFILE_GET_SUBID_HWADDR).arg(subnet_id)
-        .arg(hwaddr.toText());
-
+Memfile_LeaseMgr::getLease4Internal(const HWAddr& hwaddr,
+                                    SubnetID subnet_id) const {
     // Get the index by HW Address and Subnet Identifier.
     const Lease4StorageHWAddressSubnetIdIndex& idx =
         storage4_.get<HWAddressSubnetIdIndexTag>();
@@ -786,11 +825,23 @@ Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
     return (Lease4Ptr(new Lease4(**lease)));
 }
 
-Lease4Collection
-Memfile_LeaseMgr::getLease4(const ClientId& client_id) const {
+Lease4Ptr
+Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
-              DHCPSRV_MEMFILE_GET_CLIENTID).arg(client_id.toText());
-    Lease4Collection collection;
+              DHCPSRV_MEMFILE_GET_SUBID_HWADDR).arg(subnet_id)
+        .arg(hwaddr.toText());
+
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        return (getLease4Internal(hwaddr, subnet_id));
+    } else {
+        return (getLease4Internal(hwaddr, subnet_id));
+    }
+}
+
+void
+Memfile_LeaseMgr::getLease4Internal(const ClientId& client_id,
+                                    Lease4Collection& collection) const {
     // Using composite index by 'client id' and 'subnet id'. It is ok
     // to use it to search by 'client id' only.
     const Lease4StorageClientIdSubnetIdIndex& idx =
@@ -799,22 +850,30 @@ Memfile_LeaseMgr::getLease4(const ClientId& client_id) const {
               Lease4StorageClientIdSubnetIdIndex::const_iterator> l
         = idx.equal_range(boost::make_tuple(client_id.getClientId()));
 
-    for(auto lease = l.first; lease != l.second; ++lease) {
+    for (auto lease = l.first; lease != l.second; ++lease) {
         collection.push_back(Lease4Ptr(new Lease4(**lease)));
     }
+}
+
+Lease4Collection
+Memfile_LeaseMgr::getLease4(const ClientId& client_id) const {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
+              DHCPSRV_MEMFILE_GET_CLIENTID).arg(client_id.toText());
+    Lease4Collection collection;
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        getLease4Internal(client_id, collection);
+    } else {
+        getLease4Internal(client_id, collection);
+    }
 
     return (collection);
 }
 
 Lease4Ptr
-Memfile_LeaseMgr::getLease4(const ClientId& client_id,
-                            const HWAddr& hwaddr,
-                            SubnetID subnet_id) const {
-    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
-              DHCPSRV_MEMFILE_GET_CLIENTID_HWADDR_SUBID).arg(client_id.toText())
-                                                        .arg(hwaddr.toText())
-                                                        .arg(subnet_id);
-
+Memfile_LeaseMgr::getLease4Internal(const ClientId& client_id,
+                                    const HWAddr& hwaddr,
+                                    SubnetID subnet_id) const {
     // Get the index by client id, HW address and subnet id.
     const Lease4StorageClientIdHWAddressSubnetIdIndex& idx =
         storage4_.get<ClientIdHWAddressSubnetIdIndexTag>();
@@ -834,11 +893,24 @@ Memfile_LeaseMgr::getLease4(const ClientId& client_id,
 
 Lease4Ptr
 Memfile_LeaseMgr::getLease4(const ClientId& client_id,
+                            const HWAddr& hwaddr,
                             SubnetID subnet_id) const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
-              DHCPSRV_MEMFILE_GET_SUBID_CLIENTID).arg(subnet_id)
-              .arg(client_id.toText());
+              DHCPSRV_MEMFILE_GET_CLIENTID_HWADDR_SUBID).arg(client_id.toText())
+                                                        .arg(hwaddr.toText())
+                                                        .arg(subnet_id);
 
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        return (getLease4Internal(client_id, hwaddr, subnet_id));
+    } else {
+        return (getLease4Internal(client_id, hwaddr, subnet_id));
+    }
+}
+
+Lease4Ptr
+Memfile_LeaseMgr::getLease4Internal(const ClientId& client_id,
+                                    SubnetID subnet_id) const {
     // Get the index by client and subnet id.
     const Lease4StorageClientIdSubnetIdIndex& idx =
         storage4_.get<ClientIdSubnetIdIndexTag>();
@@ -853,12 +925,24 @@ Memfile_LeaseMgr::getLease4(const ClientId& client_id,
     return (Lease4Ptr(new Lease4(**lease)));
 }
 
-Lease4Collection
-Memfile_LeaseMgr::getLeases4(SubnetID subnet_id) const {
-    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_SUBID4)
-        .arg(subnet_id);
+Lease4Ptr
+Memfile_LeaseMgr::getLease4(const ClientId& client_id,
+                            SubnetID subnet_id) const {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
+              DHCPSRV_MEMFILE_GET_SUBID_CLIENTID).arg(subnet_id)
+              .arg(client_id.toText());
 
-    Lease4Collection collection;
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        return (getLease4Internal(client_id, subnet_id));
+    } else {
+        return (getLease4Internal(client_id, subnet_id));
+    }
+}
+
+void
+Memfile_LeaseMgr::getLeases4Internal(SubnetID subnet_id,
+                                     Lease4Collection& collection) const {
     const Lease4StorageSubnetIdIndex& idx = storage4_.get<SubnetIdIndexTag>();
     std::pair<Lease4StorageSubnetIdIndex::const_iterator,
               Lease4StorageSubnetIdIndex::const_iterator> l =
@@ -867,10 +951,31 @@ Memfile_LeaseMgr::getLeases4(SubnetID subnet_id) const {
     for (auto lease = l.first; lease != l.second; ++lease) {
         collection.push_back(Lease4Ptr(new Lease4(**lease)));
     }
+}
+
+Lease4Collection
+Memfile_LeaseMgr::getLeases4(SubnetID subnet_id) const {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_SUBID4)
+        .arg(subnet_id);
+
+    Lease4Collection collection;
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        getLeases4Internal(subnet_id, collection);
+    } else {
+        getLeases4Internal(subnet_id, collection);
+    }
 
     return (collection);
 }
 
+void
+Memfile_LeaseMgr::getLeases4Internal(Lease4Collection& collection) const {
+   for (auto lease = storage4_.begin(); lease != storage4_.end(); ++lease ) {
+       collection.push_back(Lease4Ptr(new Lease4(**lease)));
+   }
+}
+
 Lease4Collection
 Memfile_LeaseMgr::getLeases4(const std::string& hostname) const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_HOSTNAME4)
@@ -894,13 +999,36 @@ Memfile_LeaseMgr::getLeases4() const {
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET4);
 
    Lease4Collection collection;
-   for (auto lease = storage4_.begin(); lease != storage4_.end(); ++lease ) {
-       collection.push_back(Lease4Ptr(new Lease4(**lease)));
+   if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        getLeases4Internal(collection);
+   } else {
+        getLeases4Internal(collection);
    }
 
    return (collection);
 }
 
+void
+Memfile_LeaseMgr::getLeases4Internal(const asiolink::IOAddress& lower_bound_address,
+                                     const LeasePageSize& page_size,
+                                     Lease4Collection& collection) const {
+    const Lease4StorageAddressIndex& idx = storage4_.get<AddressIndexTag>();
+    Lease4StorageAddressIndex::const_iterator lb = idx.lower_bound(lower_bound_address);
+
+    // Exclude the lower bound address specified by the caller.
+    if ((lb != idx.end()) && ((*lb)->addr_ == lower_bound_address)) {
+        ++lb;
+    }
+
+    // Return all other leases being within the page size.
+    for (auto lease = lb;
+         (lease != idx.end()) && (std::distance(lb, lease) < page_size.page_size_);
+         ++lease) {
+        collection.push_back(Lease4Ptr(new Lease4(**lease)));
+    }
+}
+
 Lease4Collection
 Memfile_LeaseMgr::getLeases4(const asiolink::IOAddress& lower_bound_address,
                              const LeasePageSize& page_size) const {
@@ -916,24 +1044,27 @@ Memfile_LeaseMgr::getLeases4(const asiolink::IOAddress& lower_bound_address,
         .arg(lower_bound_address.toText());
 
     Lease4Collection collection;
-    const Lease4StorageAddressIndex& idx = storage4_.get<AddressIndexTag>();
-    Lease4StorageAddressIndex::const_iterator lb = idx.lower_bound(lower_bound_address);
-
-    // Exclude the lower bound address specified by the caller.
-    if ((lb != idx.end()) && ((*lb)->addr_ == lower_bound_address)) {
-        ++lb;
-    }
-
-    // Return all other leases being within the page size.
-    for (auto lease = lb;
-         (lease != idx.end()) && (std::distance(lb, lease) < page_size.page_size_);
-         ++lease) {
-        collection.push_back(Lease4Ptr(new Lease4(**lease)));
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        getLeases4Internal(lower_bound_address, page_size, collection);
+    } else {
+        getLeases4Internal(lower_bound_address, page_size, collection);
     }
 
     return (collection);
 }
 
+Lease6Ptr
+Memfile_LeaseMgr::getLease6Internal(Lease::Type type,
+                                    const isc::asiolink::IOAddress& addr) const {
+    Lease6Storage::iterator l = storage6_.find(addr);
+    if (l == storage6_.end() || !(*l) || ((*l)->type_ != type)) {
+        return (Lease6Ptr());
+    } else {
+        return (Lease6Ptr(new Lease6(**l)));
+    }
+}
+
 Lease6Ptr
 Memfile_LeaseMgr::getLease6(Lease::Type type,
                             const isc::asiolink::IOAddress& addr) const {
@@ -941,11 +1072,28 @@ Memfile_LeaseMgr::getLease6(Lease::Type type,
               DHCPSRV_MEMFILE_GET_ADDR6)
         .arg(addr.toText())
         .arg(Lease::typeToText(type));
-    Lease6Storage::iterator l = storage6_.find(addr);
-    if (l == storage6_.end() || !(*l) || ((*l)->type_ != type)) {
-        return (Lease6Ptr());
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        return (getLease6Internal(type, addr));
     } else {
-        return (Lease6Ptr(new Lease6(**l)));
+        return (getLease6Internal(type, addr));
+    }
+}
+
+void
+Memfile_LeaseMgr::getLeases6Internal(Lease::Type type,
+                                     const DUID& duid,
+                                     uint32_t iaid,
+                                     Lease6Collection& collection) const {
+    // Get the index by DUID, IAID, lease type.
+    const Lease6StorageDuidIaidTypeIndex& idx = storage6_.get<DuidIaidTypeIndexTag>();
+    // Try to get the lease using the DUID, IAID and lease type.
+    std::pair<Lease6StorageDuidIaidTypeIndex::const_iterator,
+              Lease6StorageDuidIaidTypeIndex::const_iterator> l =
+        idx.equal_range(boost::make_tuple(duid.getDuid(), iaid, type));
+    for (Lease6StorageDuidIaidTypeIndex::const_iterator lease =
+            l.first; lease != l.second; ++lease) {
+        collection.push_back(Lease6Ptr(new Lease6(**lease)));
     }
 }
 
@@ -958,19 +1106,36 @@ Memfile_LeaseMgr::getLeases6(Lease::Type type,
         .arg(duid.toText())
         .arg(Lease::typeToText(type));
 
+    Lease6Collection collection;
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        getLeases6Internal(type, duid, iaid, collection);
+    } else {
+        getLeases6Internal(type, duid, iaid, collection);
+    }
+
+    return (collection);
+}
+
+void
+Memfile_LeaseMgr::getLeases6Internal(Lease::Type type,
+                                     const DUID& duid,
+                                     uint32_t iaid,
+                                     SubnetID subnet_id,
+                                     Lease6Collection& collection) const {
     // Get the index by DUID, IAID, lease type.
     const Lease6StorageDuidIaidTypeIndex& idx = storage6_.get<DuidIaidTypeIndexTag>();
     // Try to get the lease using the DUID, IAID and lease type.
     std::pair<Lease6StorageDuidIaidTypeIndex::const_iterator,
               Lease6StorageDuidIaidTypeIndex::const_iterator> l =
         idx.equal_range(boost::make_tuple(duid.getDuid(), iaid, type));
-    Lease6Collection collection;
-    for(Lease6StorageDuidIaidTypeIndex::const_iterator lease =
+    for (Lease6StorageDuidIaidTypeIndex::const_iterator lease =
             l.first; lease != l.second; ++lease) {
-        collection.push_back(Lease6Ptr(new Lease6(**lease)));
+        // Filter out the leases which subnet id doesn't match.
+        if ((*lease)->subnet_id_ == subnet_id) {
+            collection.push_back(Lease6Ptr(new Lease6(**lease)));
+        }
     }
-
-    return (collection);
 }
 
 Lease6Collection
@@ -984,30 +1149,20 @@ Memfile_LeaseMgr::getLeases6(Lease::Type type,
         .arg(duid.toText())
         .arg(Lease::typeToText(type));
 
-    // Get the index by DUID, IAID, lease type.
-    const Lease6StorageDuidIaidTypeIndex& idx = storage6_.get<DuidIaidTypeIndexTag>();
-    // Try to get the lease using the DUID, IAID and lease type.
-    std::pair<Lease6StorageDuidIaidTypeIndex::const_iterator,
-              Lease6StorageDuidIaidTypeIndex::const_iterator> l =
-        idx.equal_range(boost::make_tuple(duid.getDuid(), iaid, type));
     Lease6Collection collection;
-    for(Lease6StorageDuidIaidTypeIndex::const_iterator lease =
-            l.first; lease != l.second; ++lease) {
-        // Filter out the leases which subnet id doesn't match.
-        if((*lease)->subnet_id_ == subnet_id) {
-            collection.push_back(Lease6Ptr(new Lease6(**lease)));
-        }
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        getLeases6Internal(type, duid, iaid, subnet_id, collection);
+    } else {
+        getLeases6Internal(type, duid, iaid, subnet_id, collection);
     }
 
     return (collection);
 }
 
-Lease6Collection
-Memfile_LeaseMgr::getLeases6(SubnetID subnet_id) const {
-    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_SUBID6)
-        .arg(subnet_id);
-
-    Lease6Collection collection;
+void
+Memfile_LeaseMgr::getLeases6Internal(SubnetID subnet_id,
+                                     Lease6Collection& collection) const {
     const Lease6StorageSubnetIdIndex& idx = storage6_.get<SubnetIdIndexTag>();
     std::pair<Lease6StorageSubnetIdIndex::const_iterator,
               Lease6StorageSubnetIdIndex::const_iterator> l =
@@ -1016,10 +1171,31 @@ Memfile_LeaseMgr::getLeases6(SubnetID subnet_id) const {
     for (auto lease = l.first; lease != l.second; ++lease) {
         collection.push_back(Lease6Ptr(new Lease6(**lease)));
     }
+}
+
+Lease6Collection
+Memfile_LeaseMgr::getLeases6(SubnetID subnet_id) const {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_SUBID6)
+        .arg(subnet_id);
+
+    Lease6Collection collection;
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        getLeases6Internal(subnet_id, collection);
+    } else {
+        getLeases6Internal(subnet_id, collection);
+    }
 
     return (collection);
 }
 
+void
+Memfile_LeaseMgr::getLeases6Internal(Lease6Collection& collection) const {
+   for (auto lease = storage6_.begin(); lease != storage6_.end(); ++lease ) {
+       collection.push_back(Lease6Ptr(new Lease6(**lease)));
+   }
+}
+
 Lease6Collection
 Memfile_LeaseMgr::getLeases6(const std::string& hostname) const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_HOSTNAME6)
@@ -1043,19 +1219,19 @@ Memfile_LeaseMgr::getLeases6() const {
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET6);
 
    Lease6Collection collection;
-   for (auto lease = storage6_.begin(); lease != storage6_.end(); ++lease ) {
-       collection.push_back(Lease6Ptr(new Lease6(**lease)));
+   if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        getLeases6Internal(collection);
+   } else {
+        getLeases6Internal(collection);
    }
 
    return (collection);
 }
 
-Lease6Collection
-Memfile_LeaseMgr::getLeases6(const DUID& duid) const {
-   LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET6_DUID)
-       .arg(duid.toText());
-
-    Lease6Collection collection;
+void
+Memfile_LeaseMgr::getLeases6Internal(const DUID& duid,
+                                     Lease6Collection& collection) const {
     const Lease6StorageDuidIndex& idx = storage6_.get<DuidIndexTag>();
     std::pair<Lease6StorageDuidIndex::const_iterator,
               Lease6StorageDuidIndex::const_iterator> l =
@@ -1064,25 +1240,28 @@ Memfile_LeaseMgr::getLeases6(const DUID& duid) const {
     for (auto lease = l.first; lease != l.second; ++lease) {
         collection.push_back(Lease6Ptr(new Lease6(**lease)));
     }
-
-    return (collection);
 }
 
 Lease6Collection
-Memfile_LeaseMgr::getLeases6(const asiolink::IOAddress& lower_bound_address,
-                             const LeasePageSize& page_size) const {
-    // Expecting IPv6 address.
-    if (!lower_bound_address.isV6()) {
-        isc_throw(InvalidAddressFamily, "expected IPv6 address while "
-                  "retrieving leases from the lease database, got "
-                  << lower_bound_address);
+Memfile_LeaseMgr::getLeases6(const DUID& duid) const {
+   LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET6_DUID)
+       .arg(duid.toText());
+
+    Lease6Collection collection;
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        getLeases6Internal(duid, collection);
+    } else {
+        getLeases6Internal(duid, collection);
     }
 
-    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_PAGE6)
-        .arg(page_size.page_size_)
-        .arg(lower_bound_address.toText());
+    return (collection);
+}
 
-    Lease6Collection collection;
+void
+Memfile_LeaseMgr::getLeases6Internal(const asiolink::IOAddress& lower_bound_address,
+                                     const LeasePageSize& page_size,
+                                     Lease6Collection& collection) const {
     const Lease6StorageAddressIndex& idx = storage6_.get<AddressIndexTag>();
     Lease6StorageAddressIndex::const_iterator lb = idx.lower_bound(lower_bound_address);
 
@@ -1097,16 +1276,36 @@ Memfile_LeaseMgr::getLeases6(const asiolink::IOAddress& lower_bound_address,
          ++lease) {
         collection.push_back(Lease6Ptr(new Lease6(**lease)));
     }
+}
+
+Lease6Collection
+Memfile_LeaseMgr::getLeases6(const asiolink::IOAddress& lower_bound_address,
+                             const LeasePageSize& page_size) const {
+    // Expecting IPv6 address.
+    if (!lower_bound_address.isV6()) {
+        isc_throw(InvalidAddressFamily, "expected IPv6 address while "
+                  "retrieving leases from the lease database, got "
+                  << lower_bound_address);
+    }
+
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_PAGE6)
+        .arg(page_size.page_size_)
+        .arg(lower_bound_address.toText());
+
+    Lease6Collection collection;
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        getLeases6Internal(lower_bound_address, page_size, collection);
+    } else {
+        getLeases6Internal(lower_bound_address, page_size, collection);
+    }
 
     return (collection);
 }
 
 void
-Memfile_LeaseMgr::getExpiredLeases4(Lease4Collection& expired_leases,
-                                    const size_t max_leases) const {
-    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_EXPIRED4)
-        .arg(max_leases);
-
+Memfile_LeaseMgr::getExpiredLeases4Internal(Lease4Collection& expired_leases,
+                                            const size_t max_leases) const {
     // Obtain the index which segragates leases by state and time.
     const Lease4StorageExpirationIndex& index = storage4_.get<ExpirationIndexTag>();
 
@@ -1127,11 +1326,22 @@ Memfile_LeaseMgr::getExpiredLeases4(Lease4Collection& expired_leases,
 }
 
 void
-Memfile_LeaseMgr::getExpiredLeases6(Lease6Collection& expired_leases,
+Memfile_LeaseMgr::getExpiredLeases4(Lease4Collection& expired_leases,
                                     const size_t max_leases) const {
-    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_EXPIRED6)
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_EXPIRED4)
         .arg(max_leases);
 
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        getExpiredLeases4Internal(expired_leases, max_leases);
+    } else {
+        getExpiredLeases4Internal(expired_leases, max_leases);
+    }
+}
+
+void
+Memfile_LeaseMgr::getExpiredLeases6Internal(Lease6Collection& expired_leases,
+                                            const size_t max_leases) const {
     // Obtain the index which segragates leases by state and time.
     const Lease6StorageExpirationIndex& index = storage6_.get<ExpirationIndexTag>();
 
@@ -1152,10 +1362,21 @@ Memfile_LeaseMgr::getExpiredLeases6(Lease6Collection& expired_leases,
 }
 
 void
-Memfile_LeaseMgr::updateLease4(const Lease4Ptr& lease) {
-    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
-              DHCPSRV_MEMFILE_UPDATE_ADDR4).arg(lease->addr_.toText());
+Memfile_LeaseMgr::getExpiredLeases6(Lease6Collection& expired_leases,
+                                    const size_t max_leases) const {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_EXPIRED6)
+        .arg(max_leases);
 
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        getExpiredLeases6Internal(expired_leases, max_leases);
+    } else {
+        getExpiredLeases6Internal(expired_leases, max_leases);
+    }
+}
+
+void
+Memfile_LeaseMgr::updateLease4Internal(const Lease4Ptr& lease) {
     // Obtain 'by address' index.
     Lease4StorageAddressIndex& index = storage4_.get<AddressIndexTag>();
 
@@ -1178,10 +1399,20 @@ Memfile_LeaseMgr::updateLease4(const Lease4Ptr& lease) {
 }
 
 void
-Memfile_LeaseMgr::updateLease6(const Lease6Ptr& lease) {
+Memfile_LeaseMgr::updateLease4(const Lease4Ptr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
-              DHCPSRV_MEMFILE_UPDATE_ADDR6).arg(lease->addr_.toText());
+              DHCPSRV_MEMFILE_UPDATE_ADDR4).arg(lease->addr_.toText());
+
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        updateLease4Internal(lease);
+    } else {
+        updateLease4Internal(lease);
+    }
+}
 
+void
+Memfile_LeaseMgr::updateLease6Internal(const Lease6Ptr& lease) {
     // Obtain 'by address' index.
     Lease6StorageAddressIndex& index = storage6_.get<AddressIndexTag>();
 
@@ -1203,8 +1434,21 @@ Memfile_LeaseMgr::updateLease6(const Lease6Ptr& lease) {
     index.replace(lease_it, Lease6Ptr(new Lease6(*lease)));
 }
 
+void
+Memfile_LeaseMgr::updateLease6(const Lease6Ptr& lease) {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
+              DHCPSRV_MEMFILE_UPDATE_ADDR6).arg(lease->addr_.toText());
+
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        updateLease6Internal(lease);
+    } else {
+        updateLease6Internal(lease);
+    }
+}
+
 bool
-Memfile_LeaseMgr::deleteLease(const Lease4Ptr& lease) {
+Memfile_LeaseMgr::deleteLeaseInternal(const Lease4Ptr& lease) {
     const isc::asiolink::IOAddress& addr = lease->addr_;
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_DELETE_ADDR)
@@ -1230,7 +1474,19 @@ Memfile_LeaseMgr::deleteLease(const Lease4Ptr& lease) {
 }
 
 bool
-Memfile_LeaseMgr::deleteLease(const Lease6Ptr& lease) {
+Memfile_LeaseMgr::deleteLease(const Lease4Ptr& lease) {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
+              DHCPSRV_MEMFILE_DELETE_ADDR).arg(addr.toText());
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        return (deleteLeaseInternal(lease));
+    } else {
+        return (deleteLeaseInternal(lease));
+    }
+}
+
+bool
+Memfile_LeaseMgr::deleteLeaseInternal(const Lease6Ptr& lease) {
     const isc::asiolink::IOAddress& addr = lease->addr_;
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_DELETE_ADDR)
@@ -1255,14 +1511,33 @@ Memfile_LeaseMgr::deleteLease(const Lease6Ptr& lease) {
     }
 }
 
+bool
+Memfile_LeaseMgr::deleteLease(const Lease6Ptr& lease) {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
+              DHCPSRV_MEMFILE_DELETE_ADDR).arg(addr.toText());
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        return (deleteLeaseInternal(lease));
+    } else {
+        return (deleteLeaseInternal(lease));
+    }
+}
+
 uint64_t
 Memfile_LeaseMgr::deleteExpiredReclaimedLeases4(const uint32_t secs) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED4)
         .arg(secs);
-    return (deleteExpiredReclaimedLeases<
-            Lease4StorageExpirationIndex, Lease4
-            >(secs, V4, storage4_, lease_file4_));
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        return (deleteExpiredReclaimedLeases<
+                Lease4StorageExpirationIndex, Lease4
+                >(secs, V4, storage4_, lease_file4_));
+    } else {
+        return (deleteExpiredReclaimedLeases<
+                Lease4StorageExpirationIndex, Lease4
+                >(secs, V4, storage4_, lease_file4_));
+    }
 }
 
 uint64_t
@@ -1270,9 +1545,16 @@ Memfile_LeaseMgr::deleteExpiredReclaimedLeases6(const uint32_t secs) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED6)
         .arg(secs);
-    return (deleteExpiredReclaimedLeases<
-            Lease6StorageExpirationIndex, Lease6
-            >(secs, V6, storage6_, lease_file6_));
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(*mutex_);
+        return (deleteExpiredReclaimedLeases<
+                Lease6StorageExpirationIndex, Lease6
+                >(secs, V6, storage6_, lease_file6_));
+    } else {
+        return (deleteExpiredReclaimedLeases<
+                Lease6StorageExpirationIndex, Lease6
+                >(secs, V6, storage6_, lease_file6_));
+    }
 }
 
 template<typename IndexType, typename LeaseType, typename StorageType,
index accb2cfa4076f07dbc29e1405c0bfee958d22017..bf1f3a7961e9ab4c124f65e7f97d2946d5f0dea4 100644 (file)
@@ -19,6 +19,8 @@
 #include <boost/scoped_ptr.hpp>
 #include <boost/shared_ptr.hpp>
 
+#include <mutex>
+
 namespace isc {
 namespace dhcp {
 
@@ -329,9 +331,7 @@ public:
 
     /// @brief Returns IPv6 leases for the DUID.
     ///
-    /// @todo: implement an optimised of the query using index.
-    /// @return Lease collection (may be empty if no IPv6 lease found)
-    /// for the DUID.
+    /// @param duid client DUID
     virtual Lease6Collection getLeases6(const DUID& duid) const;
 
     /// @brief Returns range of IPv6 leases using paging.
@@ -460,6 +460,192 @@ public:
 
 private:
 
+    /// @name Internal methods called holding the mutex in multi threading
+    /// mode.
+    ///@{
+
+    /// @brief Adds an IPv4 lease,
+    ///
+    /// @param lease lease to be added
+    bool addLeaseInternal(const Lease4Ptr& lease);
+
+    /// @brief Adds an IPv6 lease.
+    ///
+    /// @param lease lease to be added
+    bool addLeaseInternal(const Lease6Ptr& lease);
+
+    /// @brief Returns existing IPv4 lease for specified IPv4 address.
+    ///
+    /// @param addr An address of the searched lease.
+    Lease4Ptr getLease4Internal(const isc::asiolink::IOAddress& addr) const;
+
+    /// @brief Gets existing IPv4 leases for specified hardware address.
+    ///
+    /// @param hwaddr hardware address of the client
+    /// @param collection lease collection
+    void getLease4Internal(const isc::dhcp::HWAddr& hwaddr,
+                           Lease4Collection& collection) const;
+
+    /// @brief Returns existing IPv4 lease for specified hardware address
+    ///        and a subnet
+    ///
+    /// @param hwaddr hardware address of the client
+    /// @param subnet_id identifier of the subnet that lease must belong to
+    Lease4Ptr getLease4Internal(const HWAddr& hwaddr,
+                                SubnetID subnet_id) const;
+
+    /// @brief Gets existing IPv4 lease for specified client-id
+    ///
+    /// @param client_id client identifier
+    /// @param collection lease collection
+    void getLease4Internal(const ClientId& client_id,
+                           Lease4Collection& collection) const;
+
+    /// @brief Returns IPv4 lease for specified client-id/hwaddr/subnet-id tuple
+    ///
+    /// @param clientid client identifier
+    /// @param hwaddr hardware address of the client
+    /// @param subnet_id identifier of the subnet that lease must belong to
+    Lease4Ptr getLease4Internal(const ClientId& clientid,
+                                const HWAddr& hwaddr,
+                                SubnetID subnet_id) const;
+
+    /// @brief Returns existing IPv4 lease for specified client-id
+    ///
+    /// @param clientid client identifier
+    /// @param subnet_id identifier of the subnet that lease must belong to
+    Lease4Ptr getLease4Internal(const ClientId& clientid,
+                                SubnetID subnet_id) const;
+
+    /// @brief Gets all IPv4 leases for the particular subnet identifier.
+    ///
+    /// @param subnet_id subnet identifier.
+    /// @param collection lease collection
+    void getLeases4Internal(SubnetID subnet_id,
+                            Lease4Collection& collection) const;
+
+    /// @brief Gets all IPv4 leases.
+    ///
+    /// @param collection lease collection
+    void getLeases4Internal(Lease4Collection& collection) const;
+
+    /// @brief Returns range of IPv4 leases using paging.
+    ///
+    /// @param lower_bound_address IPv4 address used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    /// @param collection lease collection
+    void getLeases4Internal(const asiolink::IOAddress& lower_bound_address,
+                            const LeasePageSize& page_size,
+                            Lease4Collection& collection) const;
+
+    /// @brief Returns existing IPv6 lease for a given IPv6 address.
+    ///
+    /// @param type specifies lease type: (NA, TA or PD)
+    /// @param addr An address of the searched lease.
+    Lease6Ptr getLease6Internal(Lease::Type type,
+                                const isc::asiolink::IOAddress& addr) const;
+
+    /// @brief Returns existing IPv6 lease for a given DUID + IA + lease type
+    /// combination
+    ///
+    /// @param type specifies lease type: (NA, TA or PD)
+    /// @param duid client DUID
+    /// @param iaid IA identifier
+    /// @param collection lease collection
+    void getLeases6Internal(Lease::Type type,
+                            const DUID& duid,
+                            uint32_t iaid,
+                            Lease6Collection& collection) const;
+
+    /// @brief Returns existing IPv6 lease for a given DUID + IA + subnet-id +
+    /// lease type combination.
+    ///
+    /// @param type specifies lease type: (NA, TA or PD)
+    /// @param duid client DUID
+    /// @param iaid IA identifier
+    /// @param subnet_id identifier of the subnet the lease must belong to
+    /// @param collection lease collection
+    void getLeases6Internal(Lease::Type type,
+                            const DUID& duid,
+                            uint32_t iaid,
+                            SubnetID subnet_id,
+                            Lease6Collection& collection) const;
+
+    /// @brief Returns all IPv6 leases for the particular subnet identifier.
+    ///
+    /// @param subnet_id subnet identifier.
+    /// @param collection lease collection
+    void getLeases6Internal(SubnetID subnet_id,
+                            Lease6Collection& collection) const;
+
+    /// @brief Returns all IPv6 leases.
+    ///
+    /// @param collection lease collection
+    void getLeases6Internal(Lease6Collection& collection) const;
+
+    /// @brief Returns IPv6 leases for the DUID.
+    ///
+    /// @param duid client DUID
+    /// @param collection lease collection
+    void getLeases6Internal(const DUID& duid,
+                            Lease6Collection& collection) const;
+
+    /// @brief Returns range of IPv6 leases using paging.
+    ///
+    /// @param lower_bound_address IPv6 address used as lower bound for the
+    /// returned range.
+    /// @param page_size maximum size of the page returned.
+    /// @param collection lease collection
+    void getLeases6Internal(const asiolink::IOAddress& lower_bound_address,
+                            const LeasePageSize& page_size,
+                            Lease6Collection& collection) const;
+
+    /// @brief Returns a collection of expired DHCPv4 leases.
+    ///
+    /// @param [out] expired_leases A container to which expired leases returned
+    /// by the database backend are added.
+    /// @param max_leases A maximum number of leases to be returned. If this
+    /// value is set to 0, all expired (but not reclaimed) leases are returned.
+    void getExpiredLeases4Internal(Lease4Collection& expired_leases,
+                                   const size_t max_leases) const;
+
+    /// @brief Returns a collection of expired DHCPv6 leases.
+    ///
+    /// @param [out] expired_leases A container to which expired leases returned
+    /// by the database backend are added.
+    /// @param max_leases A maximum number of leases to be returned. If this
+    /// value is set to 0, all expired (but not reclaimed) leases are returned.
+    void getExpiredLeases6Internal(Lease6Collection& expired_leases,
+                                   const size_t max_leases) const;
+
+    /// @brief Updates IPv4 lease.
+    ///
+    /// @param lease4 The lease to be updated.
+    void updateLease4Internal(const Lease4Ptr& lease4);
+
+    /// @brief Updates IPv6 lease.
+    ///
+    /// @param lease6 The lease to be updated.
+    void updateLease6Internal(const Lease6Ptr& lease6);
+
+    /// @brief Deletes a lease.
+    ///
+    /// @param addr Address of the lease to be deleted. (This can be IPv4 or
+    ///        IPv6.)
+    bool deleteLeaseInternal(const isc::asiolink::IOAddress& addr);
+
+    /// @brief Removes specified IPv4 leases.
+    ///
+    /// @param subnet_id identifier of the subnet
+    size_t wipeLeases4Internal(const SubnetID& subnet_id);
+
+    /// @brief Removed specified IPv6 leases.
+    ///
+    /// @param subnet_id identifier of the subnet
+    size_t wipeLeases6Internal(const SubnetID& subnet_id);
+    ///@}
+
     /// @brief Deletes all expired-reclaimed leases.
     ///
     /// This private method is called by both of the public methods:
@@ -866,6 +1052,9 @@ private:
     db::DatabaseConnection conn_;
 
     //@}
+
+    /// @brief Manager mutex
+    boost::scoped_ptr<std::mutex> mutex_;
 };
 
 }  // namespace dhcp
index d9548aeb81da7e9ddf2c540b5c8be10e687d394b..c361c377950ad01d991c1a2adaa14df3a4421af3 100644 (file)
@@ -18,6 +18,7 @@
 #include <dhcpsrv/testutils/lease_file_io.h>
 #include <dhcpsrv/tests/test_utils.h>
 #include <dhcpsrv/tests/generic_lease_mgr_unittest.h>
+#include <util/multi_threading_mgr.h>
 #include <util/pid_file.h>
 #include <util/range_utilities.h>
 #include <util/stopwatch.h>
@@ -116,6 +117,8 @@ public:
         // Remove lease files and products of Lease File Cleanup.
         removeFiles(getLeaseFilePath("leasefile4_0.csv"));
         removeFiles(getLeaseFilePath("leasefile6_0.csv"));
+
+        MultiThreadingMgr::instance().setMode(false);
     }
 
     /// @brief Reopens the connection to the backend.
@@ -141,6 +144,8 @@ public:
         // Remove lease files and products of Lease File Cleanup.
         removeFiles(getLeaseFilePath("leasefile4_0.csv"));
         removeFiles(getLeaseFilePath("leasefile6_0.csv"));
+        // Disable multi-threading.
+        MultiThreadingMgr::instance().setMode(false);
     }
 
 
@@ -829,6 +834,13 @@ TEST_F(MemfileLeaseMgrTest, addGetDelete6) {
     testAddGetDelete6();
 }
 
+// Checks that adding/getting/deleting a Lease6 object works.
+TEST_F(MemfileLeaseMgrTest, addGetDelete6MultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testAddGetDelete6();
+}
+
 /// @brief Basic Lease4 Checks
 ///
 /// Checks that the addLease, getLease4 (by address) and deleteLease (with an
@@ -838,6 +850,13 @@ TEST_F(MemfileLeaseMgrTest, basicLease4) {
     testBasicLease4();
 }
 
+/// @brief Basic Lease4 Checks
+TEST_F(MemfileLeaseMgrTest, basicLease4MultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testBasicLease4();
+}
+
 /// @todo Write more memfile tests
 
 // Simple test about lease4 retrieval through client id method
@@ -846,18 +865,39 @@ TEST_F(MemfileLeaseMgrTest, getLease4ClientId) {
     testGetLease4ClientId();
 }
 
+// Simple test about lease4 retrieval through client id method
+TEST_F(MemfileLeaseMgrTest, getLease4ClientIdMultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease4ClientId();
+}
+
 // Checks that lease4 retrieval client id is null is working
 TEST_F(MemfileLeaseMgrTest, getLease4NullClientId) {
     startBackend(V4);
     testGetLease4NullClientId();
 }
 
+// Checks that lease4 retrieval client id is null is working
+TEST_F(MemfileLeaseMgrTest, getLease4NullClientIdMultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease4NullClientId();
+}
+
 // Checks lease4 retrieval through HWAddr
 TEST_F(MemfileLeaseMgrTest, getLease4HWAddr1) {
     startBackend(V4);
     testGetLease4HWAddr1();
 }
 
+// Checks lease4 retrieval through HWAddr
+TEST_F(MemfileLeaseMgrTest, getLease4HWAddr1MultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease4HWAddr1();
+}
+
 /// @brief Check GetLease4 methods - access by Hardware Address
 ///
 /// Adds leases to the database and checks that they can be accessed via
@@ -867,12 +907,26 @@ TEST_F(MemfileLeaseMgrTest, getLease4HWAddr2) {
     testGetLease4HWAddr2();
 }
 
+/// @brief Check GetLease4 methods - access by Hardware Address
+TEST_F(MemfileLeaseMgrTest, getLease4HWAddr2MultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease4HWAddr2();
+}
+
 // Checks lease4 retrieval with clientId, HWAddr and subnet_id
 TEST_F(MemfileLeaseMgrTest, getLease4ClientIdHWAddrSubnetId) {
     startBackend(V4);
     testGetLease4ClientIdHWAddrSubnetId();
 }
 
+// Checks lease4 retrieval with clientId, HWAddr and subnet_id
+TEST_F(MemfileLeaseMgrTest, getLease4ClientIdHWAddrSubnetIdMultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease4ClientIdHWAddrSubnetId();
+}
+
 /// @brief Basic Lease4 Checks
 ///
 /// Checks that the addLease, getLease4(by address), getLease4(hwaddr,subnet_id),
@@ -883,6 +937,13 @@ TEST_F(MemfileLeaseMgrTest, lease4NullClientId) {
     testLease4NullClientId();
 }
 
+/// @brief Basic Lease4 Checks
+TEST_F(MemfileLeaseMgrTest, lease4NullClientIdMultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testLease4NullClientId();
+}
+
 /// @brief Check GetLease4 methods - access by Hardware Address & Subnet ID
 ///
 /// Adds leases to the database and checks that they can be accessed via
@@ -894,6 +955,15 @@ TEST_F(MemfileLeaseMgrTest, DISABLED_getLease4HwaddrSubnetId) {
     testGetLease4HWAddrSubnetId();
 }
 
+/// @brief Check GetLease4 methods - access by Hardware Address & Subnet ID
+TEST_F(MemfileLeaseMgrTest, DISABLED_getLease4HwaddrSubnetIdMultiThread) {
+
+    /// @todo: fails on memfile. It's probably a memfile bug.
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease4HWAddrSubnetId();
+}
+
 /// @brief Check GetLease4 methods - access by Client ID
 ///
 /// Adds leases to the database and checks that they can be accessed via
@@ -903,6 +973,13 @@ TEST_F(MemfileLeaseMgrTest, getLease4ClientId2) {
     testGetLease4ClientId2();
 }
 
+/// @brief Check GetLease4 methods - access by Client ID
+TEST_F(MemfileLeaseMgrTest, getLease4ClientId2MultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease4ClientId2();
+}
+
 // @brief Get Lease4 by client ID
 //
 // Check that the system can cope with a client ID of any size.
@@ -911,6 +988,13 @@ TEST_F(MemfileLeaseMgrTest, getLease4ClientIdSize) {
     testGetLease4ClientIdSize();
 }
 
+// @brief Get Lease4 by client ID
+TEST_F(MemfileLeaseMgrTest, getLease4ClientIdSizeMultiThread) {
+    startBackend(V4);
+    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
@@ -920,42 +1004,91 @@ TEST_F(MemfileLeaseMgrTest, getLease4ClientIdSubnetId) {
     testGetLease4ClientIdSubnetId();
 }
 
+/// @brief Check GetLease4 methods - access by Client ID & Subnet ID
+TEST_F(MemfileLeaseMgrTest, getLease4ClientIdSubnetIdMultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease4ClientIdSubnetId();
+}
+
 // This test checks that all IPv4 leases for a specified subnet id are returned.
 TEST_F(MemfileLeaseMgrTest, getLeases4SubnetId) {
     startBackend(V4);
     testGetLeases4SubnetId();
 }
 
+// This test checks that all IPv4 leases for a specified subnet id are returned.
+TEST_F(MemfileLeaseMgrTest, getLeases4SubnetIdMultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases4SubnetId();
+}
+
 // This test checks that all IPv4 leases with a specified hostname are returned.
 TEST_F(MemfileLeaseMgrTest, getLeases4Hostname) {
     startBackend(V4);
     testGetLeases4Hostname();
 }
 
+// This test checks that all IPv4 leases with a specified hostname are returned.
+TEST_F(MemfileLeaseMgrTest, getLeases4HostnameMultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases4Hostname();
+}
+
 // This test checks that all IPv4 leases are returned.
 TEST_F(MemfileLeaseMgrTest, getLeases4) {
     startBackend(V4);
     testGetLeases4();
 }
 
+// This test checks that all IPv4 leases are returned.
+TEST_F(MemfileLeaseMgrTest, getLeases4MultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases4();
+}
+
 // Test that a range of IPv4 leases is returned with paging.
 TEST_F(MemfileLeaseMgrTest, getLeases4Paged) {
     startBackend(V4);
     testGetLeases4Paged();
 }
 
+// Test that a range of IPv4 leases is returned with paging.
+TEST_F(MemfileLeaseMgrTest, getLeases4PagedMultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases4Paged();
+}
+
 // This test checks that all IPv6 leases for a specified subnet id are returned.
 TEST_F(MemfileLeaseMgrTest, getLeases6SubnetId) {
     startBackend(V6);
     testGetLeases6SubnetId();
 }
 
+// This test checks that all IPv6 leases for a specified subnet id are returned.
+TEST_F(MemfileLeaseMgrTest, getLeases6SubnetIdMultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases6SubnetId();
+}
+
 // This test checks that all IPv6 leases with a specified hostname are returned.
 TEST_F(MemfileLeaseMgrTest, getLeases6Hostname) {
     startBackend(V6);
     testGetLeases6Hostname();
 }
 
+// This test checks that all IPv6 leases with a specified hostname are returned.
+TEST_F(MemfileLeaseMgrTest, getLeases6HostnameMultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases6Hostname();
+}
+
 // This test adds 3 leases  and verifies fetch by DUID.
 // Verifies retrival of non existant DUID fails
 TEST_F(MemfileLeaseMgrTest, getLeases6Duid) {
@@ -963,18 +1096,39 @@ TEST_F(MemfileLeaseMgrTest, getLeases6Duid) {
     testGetLeases6Duid();
 }
 
+// This test adds 3 leases  and verifies fetch by DUID.
+TEST_F(MemfileLeaseMgrTest, getLeases6DuidMultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases6Duid();
+}
+
 // This test checks that all IPv6 leases are returned.
 TEST_F(MemfileLeaseMgrTest, getLeases6) {
     startBackend(V6);
     testGetLeases6();
 }
 
+// This test checks that all IPv6 leases are returned.
+TEST_F(MemfileLeaseMgrTest, getLeases6MultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases6();
+}
+
 // Test that a range of IPv6 leases is returned with paging.
 TEST_F(MemfileLeaseMgrTest, getLeases6Paged) {
     startBackend(V6);
     testGetLeases6Paged();
 }
 
+// Test that a range of IPv6 leases is returned with paging.
+TEST_F(MemfileLeaseMgrTest, getLeases6PagedMultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases6Paged();
+}
+
 /// @brief Basic Lease6 Checks
 ///
 /// Checks that the addLease, getLease6 (by address) and deleteLease (with an
@@ -984,6 +1138,13 @@ TEST_F(MemfileLeaseMgrTest, basicLease6) {
     testBasicLease6();
 }
 
+/// @brief Basic Lease6 Checks
+TEST_F(MemfileLeaseMgrTest, basicLease6MultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testBasicLease6();
+}
+
 
 /// @brief Check GetLease6 methods - access by DUID/IAID
 ///
@@ -996,12 +1157,26 @@ TEST_F(MemfileLeaseMgrTest, getLeases6DuidIaid) {
     testGetLeases6DuidIaid();
 }
 
+/// @brief Check GetLease6 methods - access by DUID/IAID
+TEST_F(MemfileLeaseMgrTest, getLeases6DuidIaidMultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases6DuidIaid();
+}
+
 /// @brief Check that the system can cope with a DUID of allowed size.
 TEST_F(MemfileLeaseMgrTest, getLeases6DuidSize) {
     startBackend(V6);
     testGetLeases6DuidSize();
 }
 
+/// @brief Check that the system can cope with a DUID of allowed size.
+TEST_F(MemfileLeaseMgrTest, getLeases6DuidSizeMultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLeases6DuidSize();
+}
+
 /// @brief Check that the expired DHCPv4 leases can be retrieved.
 ///
 /// This test adds a number of leases to the lease database and marks
@@ -1014,6 +1189,13 @@ TEST_F(MemfileLeaseMgrTest, getExpiredLeases4) {
     testGetExpiredLeases4();
 }
 
+/// @brief Check that the expired DHCPv4 leases can be retrieved.
+TEST_F(MemfileLeaseMgrTest, getExpiredLeases4MultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetExpiredLeases4();
+}
+
 /// @brief Check that the expired DHCPv6 leases can be retrieved.
 ///
 /// This test adds a number of leases to the lease database and marks
@@ -1026,18 +1208,39 @@ TEST_F(MemfileLeaseMgrTest, getExpiredLeases6) {
     testGetExpiredLeases6();
 }
 
+/// @brief Check that the expired DHCPv6 leases can be retrieved.
+TEST_F(MemfileLeaseMgrTest, getExpiredLeases6MultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetExpiredLeases6();
+}
+
 /// @brief Check that expired reclaimed DHCPv6 leases are removed.
 TEST_F(MemfileLeaseMgrTest, deleteExpiredReclaimedLeases6) {
     startBackend(V6);
     testDeleteExpiredReclaimedLeases6();
 }
 
+/// @brief Check that expired reclaimed DHCPv6 leases are removed.
+TEST_F(MemfileLeaseMgrTest, deleteExpiredReclaimedLeases6MultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testDeleteExpiredReclaimedLeases6();
+}
+
 /// @brief Check that expired reclaimed DHCPv4 leases are removed.
 TEST_F(MemfileLeaseMgrTest, deleteExpiredReclaimedLeases4) {
     startBackend(V4);
     testDeleteExpiredReclaimedLeases4();
 }
 
+/// @brief Check that expired reclaimed DHCPv4 leases are removed.
+TEST_F(MemfileLeaseMgrTest, deleteExpiredReclaimedLeases4MultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testDeleteExpiredReclaimedLeases4();
+}
+
 /// @brief Check that getLease6 methods discriminate by lease type.
 ///
 /// Adds six leases, two per lease type all with the same duid and iad but
@@ -1051,6 +1254,13 @@ TEST_F(MemfileLeaseMgrTest, lease6LeaseTypeCheck) {
     testLease6LeaseTypeCheck();
 }
 
+/// @brief Check that getLease6 methods discriminate by lease type.
+TEST_F(MemfileLeaseMgrTest, lease6LeaseTypeCheckMultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testLease6LeaseTypeCheck();
+}
+
 /// @brief Check GetLease6 methods - access by DUID/IAID/SubnetID
 ///
 /// Adds leases to the database and checks that they can be accessed via
@@ -1060,6 +1270,13 @@ TEST_F(MemfileLeaseMgrTest, getLease6DuidIaidSubnetId) {
     testGetLease6DuidIaidSubnetId();
 }
 
+/// @brief Check GetLease6 methods - access by DUID/IAID/SubnetID
+TEST_F(MemfileLeaseMgrTest, getLease6DuidIaidSubnetIdMultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease6DuidIaidSubnetId();
+}
+
 /// Checks that getLease6(type, duid, iaid, subnet-id) works with different
 /// DUID sizes
 TEST_F(MemfileLeaseMgrTest, getLease6DuidIaidSubnetIdSize) {
@@ -1067,6 +1284,14 @@ TEST_F(MemfileLeaseMgrTest, getLease6DuidIaidSubnetIdSize) {
     testGetLease6DuidIaidSubnetIdSize();
 }
 
+/// Checks that getLease6(type, duid, iaid, subnet-id) works with different
+/// DUID sizes
+TEST_F(MemfileLeaseMgrTest, getLease6DuidIaidSubnetIdSizeMultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetLease6DuidIaidSubnetIdSize();
+}
+
 /// @brief Lease4 update tests
 ///
 /// Checks that we are able to update a lease in the database.
@@ -1078,6 +1303,13 @@ TEST_F(MemfileLeaseMgrTest, DISABLED_updateLease4) {
     testUpdateLease4();
 }
 
+/// @brief Lease4 update tests
+TEST_F(MemfileLeaseMgrTest, DISABLED_updateLease4MultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testUpdateLease4();
+}
+
 /// @brief Lease6 update tests
 ///
 /// Checks that we are able to update a lease in the database.
@@ -1089,6 +1321,13 @@ TEST_F(MemfileLeaseMgrTest, DISABLED_updateLease6) {
     testUpdateLease6();
 }
 
+/// @brief Lease6 update tests
+TEST_F(MemfileLeaseMgrTest, DISABLED_updateLease6MultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testUpdateLease6();
+}
+
 /// @brief DHCPv4 Lease recreation tests
 ///
 /// Checks that the lease can be created, deleted and recreated with
@@ -1099,6 +1338,13 @@ TEST_F(MemfileLeaseMgrTest, testRecreateLease4) {
     testRecreateLease4();
 }
 
+/// @brief DHCPv4 Lease recreation tests
+TEST_F(MemfileLeaseMgrTest, testRecreateLease4MultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testRecreateLease4();
+}
+
 /// @brief DHCPv6 Lease recreation tests
 ///
 /// Checks that the lease can be created, deleted and recreated with
@@ -1109,6 +1355,13 @@ TEST_F(MemfileLeaseMgrTest, testRecreateLease6) {
     testRecreateLease6();
 }
 
+/// @brief DHCPv6 Lease recreation tests
+TEST_F(MemfileLeaseMgrTest, testRecreateLease6MultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testRecreateLease6();
+}
+
 // The following tests are not applicable for memfile. When adding
 // new tests to the list here, make sure to provide brief explanation
 // why they are not applicable:
@@ -1126,12 +1379,29 @@ TEST_F(MemfileLeaseMgrTest, DISABLED_nullDuid) {
     ASSERT_THROW(lmptr_->addLease(leases[1]), DbOperationError);
 }
 
+/// @brief Checks that null DUID is not allowed.
+TEST_F(MemfileLeaseMgrTest, DISABLED_nullDuidMultiThread) {
+    MultiThreadingMgr::instance().setMode(true);
+    // Create leases, although we need only one.
+    vector<Lease6Ptr> leases = createLeases6();
+
+    leases[1]->duid_.reset();
+    ASSERT_THROW(lmptr_->addLease(leases[1]), DbOperationError);
+}
+
 /// @brief Tests whether memfile can store and retrieve hardware addresses
 TEST_F(MemfileLeaseMgrTest, testLease6Mac) {
     startBackend(V6);
     testLease6MAC();
 }
 
+/// @brief Tests whether memfile can store and retrieve hardware addresses
+TEST_F(MemfileLeaseMgrTest, testLease6MacMultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testLease6MAC();
+}
+
 // Check that memfile reports version correctly.
 TEST_F(MemfileLeaseMgrTest, versionCheck) {
 
@@ -1154,12 +1424,26 @@ TEST_F(MemfileLeaseMgrTest, getDeclined4) {
     testGetDeclinedLeases4();
 }
 
+// Checks that declined IPv4 leases can be returned correctly.
+TEST_F(MemfileLeaseMgrTest, getDeclined4MultiThread) {
+    startBackend(V4);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetDeclinedLeases4();
+}
+
 // Checks that declined IPv6 leases can be returned correctly.
 TEST_F(MemfileLeaseMgrTest, getDeclined6) {
     startBackend(V6);
     testGetDeclinedLeases6();
 }
 
+// Checks that declined IPv6 leases can be returned correctly.
+TEST_F(MemfileLeaseMgrTest, getDeclined6MultiThread) {
+    startBackend(V6);
+    MultiThreadingMgr::instance().setMode(true);
+    testGetDeclinedLeases6();
+}
+
 // This test checks that the backend reads DHCPv4 lease data from multiple
 // files.
 TEST_F(MemfileLeaseMgrTest, load4MultipleLeaseFiles) {