Browse Source

[3668] Install LFC callback to trigger LFC periodically.

Marcin Siodelski 10 years ago
parent
commit
b3bbea1bb1

+ 14 - 2
src/lib/dhcpsrv/lease_mgr.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013, 2015 Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -16,6 +16,7 @@
 #define LEASE_MGR_H
 
 #include <asiolink/io_address.h>
+#include <asiolink/io_service.h>
 #include <dhcp/duid.h>
 #include <dhcp/option.h>
 #include <dhcp/hwaddr.h>
@@ -133,7 +134,8 @@ public:
     ///
     /// @param parameters A data structure relating keywords and values
     ///        concerned with the database.
-    LeaseMgr(const ParameterMap& parameters) : parameters_(parameters)
+    LeaseMgr(const ParameterMap& parameters)
+        : parameters_(parameters), io_service_(new asiolink::IOService())
     {}
 
     /// @brief Destructor
@@ -379,6 +381,12 @@ public:
     /// @brief returns value of the parameter
     virtual std::string getParameter(const std::string& name) const;
 
+    /// @brief Returns a reference to the @c IOService object used
+    /// by the Lease Manager.
+    const asiolink::IOServicePtr& getIOService() const {
+        return (io_service_);
+    }
+
 private:
     /// @brief list of parameters passed in dbconfig
     ///
@@ -386,6 +394,10 @@ private:
     /// password and other parameters required for DB access. It is not
     /// intended to keep any DHCP-related parameters.
     ParameterMap parameters_;
+
+    /// @brief Pointer to the IO service object used by the derived classes
+    /// to trigger interval timers.
+    asiolink::IOServicePtr io_service_;
 };
 
 }; // end of isc::dhcp namespace

+ 32 - 1
src/lib/dhcpsrv/memfile_lease_mgr.cc

@@ -22,7 +22,7 @@
 using namespace isc::dhcp;
 
 Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
-    : LeaseMgr(parameters) {
+    : LeaseMgr(parameters), lfc_timer_(*getIOService()) {
     // Check the universe and use v4 file or v6 file.
     std::string universe = getParameter("universe");
     if (universe == "4") {
@@ -47,6 +47,9 @@ Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
     // operation.
     if (!persistLeases(V4) && !persistLeases(V6)) {
         LOG_WARN(dhcpsrv_logger, DHCPSRV_MEMFILE_NO_STORAGE);
+
+    } else  {
+        initTimers(universe == "4" ? V4 : V6);
     }
 }
 
@@ -469,6 +472,34 @@ Memfile_LeaseMgr::initLeaseFilePath(Universe u) {
 }
 
 void
+Memfile_LeaseMgr::initTimers(const Universe& universe) {
+    std::string lfc_interval_str = "0";
+    try {
+        lfc_interval_str = getParameter("lfc-interval");
+    } catch (const std::exception& ex) {
+        // Ignore and default to 0.
+    }
+
+    uint32_t lfc_interval = 0;
+    try {
+        lfc_interval = boost::lexical_cast<uint32_t>(lfc_interval_str);
+    } catch (boost::bad_lexical_cast& ex) {
+        isc_throw(isc::BadValue, "invalid value of the LFC interval "
+                  << lfc_interval_str << " specified");
+    }
+
+    if (lfc_interval > 0) {
+        asiolink::IntervalTimer::Callback cb =
+            boost::bind(&Memfile_LeaseMgr::lfcCallback, this);
+        lfc_timer_.setup(cb, lfc_interval * 1000);
+    }
+}
+
+void
+Memfile_LeaseMgr::lfcCallback() {
+}
+
+void
 Memfile_LeaseMgr::load4() {
     // If lease file hasn't been opened, we are working in non-persistent mode.
     // That's fine, just leave.

+ 24 - 1
src/lib/dhcpsrv/memfile_lease_mgr.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -15,6 +15,8 @@
 #ifndef MEMFILE_LEASE_MGR_H
 #define MEMFILE_LEASE_MGR_H
 
+#include <asiolink/interval_timer.h>
+#include <asiolink/io_service.h>
 #include <dhcp/hwaddr.h>
 #include <dhcpsrv/csv_lease_file4.h>
 #include <dhcpsrv/csv_lease_file6.h>
@@ -335,6 +337,16 @@ public:
 
 protected:
 
+    /// @brief A callback function triggering Lease File Cleanup.
+    ///
+    /// This method is virtual so as it can be overriden and customized in
+    /// the unit tests. In particular, the unit test which checks that the
+    /// callback function has been executed would override this function
+    /// to increase the execution counter each time it is executed.
+    virtual void lfcCallback();
+
+private:
+
     /// @brief Load all DHCPv4 leases from the file.
     ///
     /// This method loads all DHCPv4 leases from a file to memory. It removes
@@ -396,6 +408,14 @@ protected:
     /// argument to this function.
     std::string initLeaseFilePath(Universe u);
 
+    /// @brief Initialize the timers used to perform repeating tasks.
+    ///
+    /// Currently only one timer is supported. This timer executes the
+    /// Lease File Cleanup periodically.
+    ///
+    /// @param universe A V4 or V6 value.
+    void initTimers(const Universe& universe);
+
     // This is a multi-index container, which holds elements that can
     // be accessed using different search indexes.
     typedef boost::multi_index_container<
@@ -514,6 +534,9 @@ protected:
     /// @brief Holds the pointer to the DHCPv6 lease file IO.
     boost::shared_ptr<CSVLeaseFile6> lease_file6_;
 
+    /// @brief A timer scheduled to perform Lease File Cleanup.
+    asiolink::IntervalTimer lfc_timer_;
+
 };
 
 }; // end of isc::dhcp namespace

+ 96 - 2
src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc

@@ -25,6 +25,8 @@
 #include <dhcpsrv/tests/generic_lease_mgr_unittest.h>
 #include <gtest/gtest.h>
 
+#include <boost/bind.hpp>
+
 #include <iostream>
 #include <fstream>
 #include <sstream>
@@ -37,7 +39,45 @@ using namespace isc::dhcp::test;
 
 namespace {
 
-// empty class for now, but may be extended once Addr6 becomes bigger
+/// @brief Class derived from @c Memfile_LeaseMgr to test timers.
+///
+/// This class provides a custom callback function which is invoked
+/// when the timer for Lease File Cleanup goes off. It is used to
+/// test that the timer is correctly installed.
+class TestMemfileLeaseMgr : public Memfile_LeaseMgr {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// Sets the counter for callbacks to 0.
+    TestMemfileLeaseMgr(const ParameterMap& parameters)
+        : Memfile_LeaseMgr(parameters) {
+    }
+
+    /// @brief Returns the number of callback executions.
+    int getLFCCount() {
+        return (lfc_cnt_);
+    }
+
+protected:
+
+    /// @brief Custom callback.
+    ///
+    /// This callback function increases the counter of callback executions.
+    /// By examining the counter value a test may verify that the callback
+    /// was triggered an expected number of times.
+    virtual void lfcCallback() {
+        ++lfc_cnt_;
+    }
+
+private:
+
+    /// @brief Counter of callback function executions.
+    int lfc_cnt_;
+
+};
+
+/// @brief Test fixture class for @c Memfile_LeaseMgr
 class MemfileLeaseMgrTest : public GenericLeaseMgrTest {
 public:
 
@@ -46,7 +86,9 @@ public:
     /// Creates memfile and stores it in lmptr_ pointer
     MemfileLeaseMgrTest() :
         io4_(getLeaseFilePath("leasefile4_0.csv")),
-        io6_(getLeaseFilePath("leasefile6_0.csv")) {
+        io6_(getLeaseFilePath("leasefile6_0.csv")),
+        io_service_(),
+        fail_on_callback_(false) {
 
         // Make sure there are no dangling files after previous tests.
         io4_.removeFile();
@@ -116,12 +158,36 @@ public:
         lmptr_ = &(LeaseMgrFactory::instance());
     }
 
+    void setTestTime(const uint32_t ms) {
+        IntervalTimer::Callback cb =
+            boost::bind(&MemfileLeaseMgrTest::testTimerCallback, this);
+        test_timer_.reset(new IntervalTimer(*io_service_));
+        test_timer_->setup(cb, ms, IntervalTimer::ONE_SHOT);
+    }
+
+    /// @brief Test timer callback function.
+    void testTimerCallback() {
+        io_service_->stop();
+        if (fail_on_callback_) {
+            FAIL() << "Test timeout reached";
+        }
+    }
+
     /// @brief Object providing access to v4 lease IO.
     LeaseFileIO io4_;
 
     /// @brief Object providing access to v6 lease IO.
     LeaseFileIO io6_;
 
+    /// @brief Test timer for the test.
+    boost::shared_ptr<IntervalTimer> test_timer_;
+
+    /// @brief IO service object used for the timer tests.
+    asiolink::IOServicePtr io_service_;
+
+    /// @brief Indicates if the @c testTimerCallback should cause test failure.
+    bool fail_on_callback_;
+
 };
 
 // This test checks if the LeaseMgr can be instantiated and that it
@@ -134,6 +200,7 @@ TEST_F(MemfileLeaseMgrTest, constructor) {
 
     EXPECT_NO_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)));
 
+    pmap["lfc-interval"] = "10";
     pmap["persist"] = "true";
     pmap["name"] = getLeaseFilePath("leasefile4_1.csv");
     EXPECT_NO_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)));
@@ -143,6 +210,10 @@ TEST_F(MemfileLeaseMgrTest, constructor) {
     pmap["persist"] = "bogus";
     pmap["name"] = getLeaseFilePath("leasefile4_1.csv");
     EXPECT_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)), isc::BadValue);
+
+    // The lfc-interval must be an integer.
+    pmap["lfc-interval"] = "bogus";
+    EXPECT_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)), isc::BadValue);
 }
 
 // Checks if the getType() and getName() methods both return "memfile".
@@ -204,6 +275,29 @@ TEST_F(MemfileLeaseMgrTest, persistLeases) {
     EXPECT_FALSE(lease_mgr->persistLeases(Memfile_LeaseMgr::V6));
 }
 
+// Check if it is possible to schedule the timer to perform the Lease
+// File Cleanup periodically.
+TEST_F(MemfileLeaseMgrTest, lfcTimer) {
+    LeaseMgr::ParameterMap pmap;
+    pmap["type"] = "memfile";
+    pmap["universe"] = "4";
+    // Specify the names of the lease files. Leases will be written.
+    pmap["name"] = getLeaseFilePath("leasefile4_0.csv");
+    pmap["lfc-interval"] = "1";
+
+    boost::shared_ptr<TestMemfileLeaseMgr>
+        lease_mgr(new TestMemfileLeaseMgr(pmap));
+
+    io_service_ = lease_mgr->getIOService();
+
+    // Run the test for at most 2.9 seconds.
+    setTestTime(2900);
+
+    io_service_->run();
+
+    // Within 2.9 we should record two LFC executions.
+    EXPECT_EQ(2, lease_mgr->getLFCCount());
+}
 
 // Checks that adding/getting/deleting a Lease6 object works.
 TEST_F(MemfileLeaseMgrTest, addGetDelete6) {