]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[optimize_query] Add new index for query by DUID
authormayya <sunilmayya@gmail.com>
Sun, 22 Jul 2018 15:00:50 +0000 (17:00 +0200)
committerTomek Mrugalski <tomasz@isc.org>
Mon, 13 Aug 2018 18:18:04 +0000 (20:18 +0200)
 Fixes #98

17 files changed:
AUTHORS
ChangeLog
src/lib/dhcpsrv/cql_lease_mgr.cc
src/lib/dhcpsrv/lease_mgr.h
src/lib/dhcpsrv/memfile_lease_mgr.cc
src/lib/dhcpsrv/memfile_lease_mgr.h
src/lib/dhcpsrv/memfile_lease_storage.h
src/lib/dhcpsrv/mysql_lease_mgr.cc
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/cql_lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.h
src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc

diff --git a/AUTHORS b/AUTHORS
index f76dd4fbda0646cbe7ebb71783ad4dbcb71eaf06..0a56cee9626f13a40ee449ddf545f85befaa49fb 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -172,6 +172,7 @@ We have received the following contributions:
  - Sunil Mayya
    2018-07: support for Authentication option in DHCPv6
    2018-07: support storage of Authentication keys in host structure
+   2018-07: Optimized query for host reservation from the backends
 
 Kea uses log4cplus (http://sourceforge.net/projects/log4cplus/) for logging,
 Boost (http://www.boost.org/) library for almost everything, and can use Botan
index b54e5bcdefcbad91f247c7d854855c78a933166c..273bf4d33fed61f71a79913a3660270266dc0368 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+1436.   [func]      MayyaSunil
+       Implemented new index for queries host reservations by DUID.
+       (Github #98, git c20b5248da1283e596e35ad057ae242f4d613965)
+
 1435.  [func]          marcin
        Implemented ha-continue command in HA hooks library and
        updated the Kea User's Guide with the information how to
index 7ae9dc02d8e830ab9e68ab601e008fd8cda01352..6c04fd8adc4f7d582fadeb1a97ce4428b8e93ce1 100644 (file)
@@ -2306,10 +2306,10 @@ CqlLeaseMgr::getLeases6(const DUID& duid) const {
     // Get the data.
     Lease6Collection result;
     std::unique_ptr<CqlLease6Exchange> exchange6(new CqlLease6Exchange(dbconn_));
-    exchange6->getLeaseCollection(CqlLease6Exchange::GET_LEASE6_DUID, data, result);
+    exchange6->getLeaseCollection(CqlLease6Exchange::GET_LEASE6_DUID,
+                                  data, result);
 
     return (result);
-    
 }
 
 Lease6Collection
index 474b4badc172e50494f70949d042daf9c59e4f8b..e6b05b07c65d5aca43b86e9010c28102813475d4 100644 (file)
@@ -460,9 +460,10 @@ public:
 
     /// @brief Returns collection of lease for matching DUID
     ///
-    /// @return Lease collection (may be empty if no IPv6 lease found for the DUID).
+    /// @return Lease collection 
+    /// (may be empty if no IPv6 lease found for the DUID).
     virtual Lease6Collection getLeases6(const DUID& duid) const = 0; 
-    
+
     /// @brief Returns range of IPv6 leases using paging.
     ///
     /// This method implements paged browsing of the lease database. The first
index b05dce55974067670dc0f330920c960a7e4f1c16..57563edd9b7e075450dae3438ab7c4070ad1d8a8 100644 (file)
@@ -1020,13 +1020,17 @@ Memfile_LeaseMgr::getLeases6(const DUID& duid) const {
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET6_DUID)
        .arg(duid.toText());
 
-   Lease6Collection collection;
-   for (auto lease = storage6_.begin(); lease != storage6_.end(); ++lease ) {
-       if ( (**lease).duid_->getDuid() == duid.getDuid() )
-            collection.push_back(Lease6Ptr(new Lease6(**lease)));
-   }
+    Lease6Collection collection;
+    const Lease6StorageDuidIndex& idx = storage6_.get<DuidIndexTag>();
+    std::pair<Lease6StorageDuidIndex::const_iterator,
+              Lease6StorageDuidIndex::const_iterator> l =
+        idx.equal_range(duid.getDuid());
 
-   return (collection);
+    for (auto lease = l.first; lease != l.second; ++lease) {
+        collection.push_back(Lease6Ptr(new Lease6(**lease)));
+    }
+
+    return (collection);
 }
 
 Lease6Collection
index f14cc5c96454e621bde7b0c50454eacbd839e553..2db242b0b684b24b0ac0de38793ea90605ae80f8 100644 (file)
@@ -315,7 +315,8 @@ 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.
+    /// @return Lease collection (may be empty if no IPv6 lease found) 
+    /// for the DUID.
     virtual Lease6Collection getLeases6(const DUID& duid) const;
     
     /// @brief Returns range of IPv6 leases using paging.
index 059210f8aa5082744b87584ba722151bb9c98a53..1c4a75b4826a8e7af7064594d49306afd4470fe0 100644 (file)
@@ -45,6 +45,8 @@ struct ClientIdHWAddressSubnetIdIndexTag { };
 /// @brief Tag for indexs by subnet-id.
 struct SubnetIdIndexTag { };
 
+/// @brief Tag for index using DUID.
+struct DuidIndexTag { }; 
 /// @name Multi index containers holding DHCPv4 and DHCPv6 leases.
 ///
 //@{
@@ -112,9 +114,19 @@ typedef boost::multi_index_container<
         // This index sorts leases by SubnetID.
         boost::multi_index::ordered_non_unique<
             boost::multi_index::tag<SubnetIdIndexTag>,
-            boost::multi_index::member<Lease, isc::dhcp::SubnetID, &Lease::subnet_id_>
+            boost::multi_index::member<Lease, isc::dhcp::SubnetID,
+            &Lease::subnet_id_>
+        >,
+
+        // Specification of the fifth index starts here
+        // This index is used to retrieve leases for matching duid.
+        boost::multi_index::ordered_non_unique<
+            boost::multi_index::tag<DuidIndexTag>,
+            boost::multi_index::const_mem_fun<Lease6,
+                                              const std::vector<uint8_t>&,
+                                              &Lease6::getDuidVector>
         >
-     >
+    >
 > Lease6Storage; // Specify the type name of this container.
 
 /// @brief A multi index container holding DHCPv4 leases.
@@ -250,6 +262,9 @@ typedef Lease6Storage::index<ExpirationIndexTag>::type Lease6StorageExpirationIn
 /// @brief DHCPv6 lease storage index by Subnet-id.
 typedef Lease6Storage::index<SubnetIdIndexTag>::type Lease6StorageSubnetIdIndex;
 
+/// @brief DHCPv6 lease storage index by Subnet-id.
+typedef Lease6Storage::index<DuidIndexTag>::type Lease6StorageDuidIndex;
+
 /// @brief DHCPv4 lease storage index by address.
 typedef Lease4Storage::index<AddressIndexTag>::type Lease4StorageAddressIndex;
 
index 8db556c1c3d5c2fc2ed38833741c9a1d1d65a6eb..675bc7a9ce112b4549fd7f9b324685cd626b3730 100644 (file)
@@ -223,6 +223,15 @@ tagged_statements = { {
                         "state, user_context "
                             "FROM lease6 "
                             "WHERE subnet_id = ?"},
+    {MySqlLeaseMgr::GET_LEASE6_DUID,
+                    "SELECT address, duid, valid_lifetime, "
+                        "expire, subnet_id, pref_lifetime, "
+                        "lease_type, iaid, prefix_len, "
+                        "fqdn_fwd, fqdn_rev, hostname, "
+                        "hwaddr, hwtype, hwaddr_source, "
+                        "state, user_context "
+                            "FROM lease6 "
+                            "WHERE duid = ?"},
     {MySqlLeaseMgr::GET_LEASE6_EXPIRE,
                     "SELECT address, duid, valid_lifetime, "
                         "expire, subnet_id, pref_lifetime, "
@@ -2224,15 +2233,22 @@ Lease6Collection
 MySqlLeaseMgr::getLeases6(const DUID& duid) const {
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MYSQL_GET_DUID);
    
-    Lease6Collection result =  getLeases6();
+    // Set up the WHERE clause value
+    MYSQL_BIND inbind[1];
+    memset(inbind, 0, sizeof(inbind));
+
+    const vector<uint8_t>& duid_vector = duid.getDuid();
+    unsigned long duid_length = duid_vector.size();
+
+    inbind[0].buffer_type = MYSQL_TYPE_BLOB;
+    inbind[0].buffer = reinterpret_cast<char*>(
+            const_cast<uint8_t*>(&duid_vector[0]));
+    inbind[0].buffer_length = duid_length;
+    inbind[0].length = &duid_length;
     
-    //erase the ones not containing the matching DUID
-    for (auto iter = result.begin(); iter != result.end();
-            iter++) {
-        if ((*iter)->duid_->getDuid() != duid.getDuid()) {
-            result.erase(iter);
-        }
-    }
+    Lease6Collection result;
+    
+    getLeaseCollection(GET_LEASE6_DUID, inbind, result);
 
     return result;
 }
index 332a9129f3b7cb36eb191cf22a69bd2507ca9afa..4a3975359f5faa4a04ff19a009fbfbbb5ae69d65 100644 (file)
@@ -312,7 +312,8 @@ public:
     /// @brief Returns all 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.
+    /// @return Lease collection (may be empty if no IPv6 lease found)
+    /// for the DUID.
     virtual Lease6Collection getLeases6(const DUID& duid) const;
     
     /// @brief Returns range of IPv6 leases using paging.
@@ -586,6 +587,7 @@ public:
         GET_LEASE6_DUID_IAID_SUBID,  // Get lease6 by DUID, IAID and subnet ID
         GET_LEASE6_PAGE,             // Get page of leases beginning with an address
         GET_LEASE6_SUBID,            // Get IPv6 leases by subnet ID
+        GET_LEASE6_DUID,             // Get IPv6 leases by DUID
         GET_LEASE6_EXPIRE,           // Get lease6 by expiration.
         INSERT_LEASE4,               // Add entry to lease4 table
         INSERT_LEASE6,               // Add entry to lease6 table
index a2ac2b746564e13698314e1356a63d1bc2936edb..3ec3d50bf92c0e10a068d7b69feb974b31d61e4b 100644 (file)
@@ -215,6 +215,17 @@ PgSqlTaggedStatement tagged_statements[] = {
       "FROM lease6 "
       "WHERE subnet_id = $1"},
 
+    // GET_LEASE6_DUID
+    { 1, { OID_BYTEA },
+      "get_lease6_duid",
+      "SELECT address, duid, valid_lifetime, "
+        "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
+        "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
+        "hwaddr, hwtype, hwaddr_source, "
+        "state, user_context "
+      "FROM lease6 "
+      "WHERE duid = $1"},
+
     // GET_LEASE6_EXPIRE
     { 3, { OID_INT8, OID_TIMESTAMP, OID_INT8 },
       "get_lease6_expire",
@@ -1507,20 +1518,20 @@ PgSqlLeaseMgr::getLeases6(SubnetID subnet_id) const {
 }
 
 Lease6Collection
-PgSqlLeaseMgr::getLeases6( const DUID& duid ) const {
+PgSqlLeaseMgr::getLeases6(const DUID& duid) const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_PGSQL_GET_DUID)
               .arg(duid.toText());
 
-    Lease6Collection result = getLeases6();
+    // Set up the WHERE clause value
+    PsqlBindArray bind_array;
 
-    //erase the ones not containing the matching DUID
-    for (auto iter = result.begin(); iter != result.end();
-            iter++) {
-        if ((*iter)->duid_->getDuid() != duid.getDuid()) {
-            result.erase(iter);
-        }
-    }
+    // DUID
+    bind_array.add(duid.getDuid());
+    Lease6Collection result;
+
+    // query to fetch the data
+    getLeaseCollection(GET_LEASE6_DUID, bind_array, result);
 
     return (result);
 }
index 15bd714a7df7ae72c86e3e1062ea35e22bdfd3ca..e6ea5242437741f07058335abc8f34f275d5d8f1 100644 (file)
@@ -284,7 +284,8 @@ 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
+    /// @return Lease collection (may be empty if no IPv6 lease found)
+    /// for the DUID
     virtual Lease6Collection getLeases6(const DUID& duid) const;
     
     /// @brief Returns range of IPv6 leases using paging.
@@ -554,6 +555,7 @@ public:
         GET_LEASE6_DUID_IAID_SUBID, // Get lease6 by DUID, IAID and subnet ID
         GET_LEASE6_PAGE,            // Get page of IPv6 leases beginning with an address
         GET_LEASE6_SUBID,           // Get IPv6 leases by subnet ID
+        GET_LEASE6_DUID,           // Get IPv6 leases by DUID
         GET_LEASE6_EXPIRE,          // Get expired lease6
         INSERT_LEASE4,              // Add entry to lease4 table
         INSERT_LEASE6,              // Add entry to lease6 table
index dca9146727b6f6e89ade46981ccc12dbc7e7b4cb..43984bcdf7064b40bf979abdcc0dcdf8a722961b 100644 (file)
@@ -679,6 +679,14 @@ TEST_F(CqlLeaseMgrTest, lease6LeaseTypeCheck) {
     testLease6LeaseTypeCheck();
 }
 
+/// @brief Verifies the getLeases6(DUID) method
+///
+/// Adds 3 lease and verifies fetch by DUID.
+/// Verifies retrival of non existant DUID fails
+TEST_F(CqlLeaseMgrTest, getLeases6Duid) {
+   testGetLeases6Duid(); 
+}
+
 /// @brief Check GetLease6 methods - access by DUID/IAID/SubnetID
 ///
 /// Adds leases to the database and checks that they can be accessed via
index d27ad401e9deacbbe92572f4d1828b402dbdb4de..f9619437533ee67d45abe7434dc40fd4d81cec78 100644 (file)
@@ -1620,6 +1620,62 @@ GenericLeaseMgrTest::testGetLease6DuidIaidSubnetId() {
     EXPECT_FALSE(returned);
 }
 
+/// @brief verifies getLeases6(DUID)
+void
+GenericLeaseMgrTest::testGetLeases6Duid() {
+    //add leases
+    IOAddress addr1(std::string("2001:db8:1::111"));
+    IOAddress addr2(std::string("2001:db8:1::222"));
+    IOAddress addr3(std::string("2001:db8:1::333"));
+
+    DuidPtr duid1(new DUID({0, 1, 1, 1, 1, 1, 1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}));
+    DuidPtr duid2(new DUID({0, 2, 2, 2, 2, 2, 2, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}));
+    DuidPtr duid3(new DUID({0, 3, 3, 3, 3, 3, 3, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}));
+    DuidPtr duid4(new DUID({0, 4, 4, 4, 4, 4, 4, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}));
+
+    uint32_t iaid = 7; // random number
+
+    SubnetID subnet_id = 8; // radom number
+
+    Lease6Ptr lease1(new Lease6(Lease::TYPE_NA, addr1, duid1, iaid, 100, 200, 50,
+                               80, subnet_id));
+    Lease6Ptr lease2(new Lease6(Lease::TYPE_NA, addr2, duid2, iaid, 100, 200, 50,
+                               80, subnet_id));
+    Lease6Ptr lease3(new Lease6(Lease::TYPE_NA, addr3, duid3, iaid, 100, 200, 50,
+                               80, subnet_id));
+
+    EXPECT_TRUE(lmptr_->addLease(lease1));
+    EXPECT_TRUE(lmptr_->addLease(lease2));
+    EXPECT_TRUE(lmptr_->addLease(lease3));
+    
+    Lease6Collection returned1 = lmptr_->getLeases6(*(lease1->duid_));
+    Lease6Collection returned2 = lmptr_->getLeases6(*(lease2->duid_));
+    Lease6Collection returned3 = lmptr_->getLeases6(*(lease3->duid_));
+  
+    //verify if the returned lease mathces 
+    EXPECT_EQ(returned1.size(), 1);
+    EXPECT_EQ(returned2.size(), 1);
+    EXPECT_EQ(returned3.size(), 1);
+
+    //verify that the returned lease are same
+    EXPECT_TRUE(returned1[0]->addr_ == lease1->addr_); 
+    EXPECT_TRUE(returned2[0]->addr_ == lease2->addr_);
+    EXPECT_TRUE(returned3[0]->addr_ == lease3->addr_);
+    
+    //now verify we return empty for a lease that has not been stored
+    returned3 = lmptr_->getLeases6(*duid4);
+    EXPECT_TRUE(returned3.empty());
+   
+    //clean up
+    (void) lmptr_->deleteLease(addr1);
+    (void) lmptr_->deleteLease(addr2);
+    (void) lmptr_->deleteLease(addr3);
+   
+    //now verify we return empty for a lease that has not been stored
+    returned3 = lmptr_->getLeases6(*duid4);
+    EXPECT_TRUE(returned3.empty());
+}
+
 /// @brief Checks that getLease6() works with different DUID sizes
 void
 GenericLeaseMgrTest::testGetLease6DuidIaidSubnetIdSize() {
index 77ef96dd7095f2ee62f6568bb1e28bfc64a17de9..fe7ecdce0c33425647dcd15c3a80be50c9d1e2c4 100644 (file)
@@ -278,6 +278,12 @@ public:
     /// Adds leases to the database and checks that they can be accessed via
     /// a combination of DIUID and IAID.
     void testGetLease6DuidIaidSubnetId();
+    
+    /// @brief verifies getLeases6 method by DUID
+    ///
+    /// Adds 3 leases to backend and retrieves, verifes empty
+    /// retrival of non existent DUID.
+    void testGetLeases6Duid();
 
     /// @brief Checks that getLease6() works with different DUID sizes
     void testGetLease6DuidIaidSubnetIdSize();
index b70d0d8589bed96b78110685acfcfe4c4529e640..2dfc829769e3c8d6ffeb620abf61120734b8056c 100644 (file)
@@ -942,6 +942,13 @@ TEST_F(MemfileLeaseMgrTest, getLeases6SubnetId) {
     testGetLeases6SubnetId();
 }
 
+// This test adds 3 leases  and verifies fetch by DUID.
+// Verifies retrival of non existant DUID fails
+TEST_F(MemfileLeaseMgrTest, getLeases6Duid) {
+    startBackend(V6);
+    testGetLeases6Duid();
+}
+
 // This test checks that all IPv6 leases are returned.
 TEST_F(MemfileLeaseMgrTest, getLeases6) {
     startBackend(V6);
index 35aeaaaffc80245e8866b410c937267d000b2d9e..af9f5725708906352958b775812ead3a7ecc8268 100644 (file)
@@ -475,6 +475,14 @@ TEST_F(MySqlLeaseMgrTest, getLease6DuidIaidSubnetIdSize) {
     testGetLease6DuidIaidSubnetIdSize();
 }
 
+// @brief check leases could be retrieved by DUID
+///
+/// Create leases, add them to backend and verify if it can be queried
+/// using DUID index
+TEST_F(MySqlLeaseMgrTest, getLeases6Duid) {
+    testGetLeases6Duid();
+}
+
 /// @brief Lease6 update tests
 ///
 /// Checks that we are able to update a lease in the database.
index e288e96ea10fa2e03718171a323f1d372ea51e65..47fed015808bb5e2938bd98a6fe6fe1e9c693ff4 100644 (file)
@@ -451,6 +451,14 @@ TEST_F(PgSqlLeaseMgrTest, lease6LeaseTypeCheck) {
     testLease6LeaseTypeCheck();
 }
 
+/// @brief Verifies the getLeases6(DUID) method
+///
+/// Adds 3 lease and verifies fetch by DUID.
+/// Verifies retrival of non existant DUID fails
+TEST_F(PgSqlLeaseMgrTest, getLeases6Duid) {
+   testGetLeases6Duid(); 
+}
+
 /// @brief Check GetLease6 methods - access by DUID/IAID/SubnetID
 ///
 /// Adds leases to the database and checks that they can be accessed via