]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1239] csv lease file is now kea thread safe
authorRazvan Becheriu <razvan@isc.org>
Fri, 5 Jun 2020 08:13:29 +0000 (11:13 +0300)
committerRazvan Becheriu <razvan@isc.org>
Tue, 16 Jun 2020 09:02:52 +0000 (09:02 +0000)
src/hooks/dhcp/high_availability/communication_state.cc
src/hooks/dhcp/high_availability/communication_state.h
src/lib/dhcpsrv/csv_lease_file4.cc
src/lib/dhcpsrv/csv_lease_file4.h
src/lib/dhcpsrv/csv_lease_file6.cc
src/lib/dhcpsrv/csv_lease_file6.h
src/lib/http/client.cc

index 80f82e6352c55328d87e4ab7745eebb1893ee55b..d3898d762715eb1a7bfd73997b62a279aaf88d5e 100644 (file)
@@ -517,7 +517,7 @@ CommunicationState4::clearConnectingClientsInternal() {
 CommunicationState6::CommunicationState6(const IOServicePtr& io_service,
                                          const HAConfigPtr& config)
     : CommunicationState(io_service, config), connecting_clients_(),
-      mutex_(new mutex()){
+      mutex_(new mutex()) {
 }
 
 void
index fc0e0b8761c7371f14f7ccabd9265d5590b5df68..985854f7b7d18e1cada57e98d766effa5de08a7d 100644 (file)
@@ -352,26 +352,28 @@ public:
     ///
     /// Used in unittests only.
     ///
-    /// Should be called in a thread safe context.
-    ///
     /// @param secs number of seconds to be added to the poke time. If
     /// the value is negative it will set the poke time in the past
     /// comparing to current value.
     void modifyPokeTime(const long secs);
 
+protected:
+
     /// @brief Modifies poke time by adding seconds to it.
     ///
     /// Used in unittests only.
     ///
+    /// Should be called in a thread safe context.
+    ///
     /// @param secs number of seconds to be added to the poke time. If
     /// the value is negative it will set the poke time in the past
     /// comparing to current value.
     void modifyPokeTimeInternal(const long secs);
 
-protected:
-
     /// @brief Returns duration between the poke time and current time.
     ///
+    /// Should be called in a thread safe context.
+    ///
     /// @return Duration between the poke time and current time.
     int64_t getDurationInMillisecsInternal() const;
 
index 1fb8d19ca14b8091ff14136f3dc36e9c96eab258..a66da203213e963b2b37184b983ee34593af95e2 100644 (file)
@@ -5,7 +5,10 @@
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 #include <config.h>
+
 #include <dhcpsrv/csv_lease_file4.h>
+#include <util/multi_threading_mgr.h>
+
 #include <ctime>
 
 using namespace isc::asiolink;
@@ -22,6 +25,16 @@ CSVLeaseFile4::CSVLeaseFile4(const std::string& filename)
 
 void
 CSVLeaseFile4::open(const bool seek_to_end) {
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(mutex_);
+        openInternal(seek_to_end);
+    } else {
+        openInternal(seek_to_end);
+    }
+}
+
+void
+CSVLeaseFile4::openInternal(const bool seek_to_end) {
     // Call the base class to open the file
     VersionedCSVFile::open(seek_to_end);
 
@@ -31,6 +44,16 @@ CSVLeaseFile4::open(const bool seek_to_end) {
 
 void
 CSVLeaseFile4::append(const Lease4& lease) {
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(mutex_);
+        appendInternal(lease);
+    } else {
+        appendInternal(lease);
+    }
+}
+
+void
+CSVLeaseFile4::appendInternal(const Lease4& lease) {
     // Bump the number of write attempts
     ++writes_;
 
@@ -85,6 +108,16 @@ CSVLeaseFile4::append(const Lease4& lease) {
 
 bool
 CSVLeaseFile4::next(Lease4Ptr& lease) {
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(mutex_);
+        return (nextInternal(lease));
+    } else {
+        return (nextInternal(lease));
+    }
+}
+
+bool
+CSVLeaseFile4::nextInternal(Lease4Ptr& lease) {
     // Bump the number of read attempts
     ++reads_;
 
index 67df8465363e70bf2c1d2930a661e2e4f21724d6..477adf7561f6b562e83043d8a9c26f3850ebfa46 100644 (file)
@@ -30,7 +30,7 @@ namespace dhcp {
 /// The @c Lease4 is a structure that should be itself responsible for this
 /// validation (see http://oldkea.isc.org/ticket/2405). However, when #2405
 /// is implemented, the @c next function may need to be updated to use the
-/// validation capablity of @c Lease4.
+/// validation capability of @c Lease4.
 class CSVLeaseFile4 : public isc::util::VersionedCSVFile, public LeaseFileStats {
 public:
 
@@ -87,6 +87,56 @@ public:
 
 private:
 
+    /// @brief Opens a lease file.
+    ///
+    /// Should be called in a thread safe context.
+    ///
+    /// This function calls the base class open to do the
+    /// work of opening a file.  It is used to clear any
+    /// statistics associated with any previous use of the file
+    /// While it doesn't throw any exceptions of its own
+    /// the base class may do so.
+    virtual void openInternal(const bool seek_to_end = false);
+
+    /// @brief Appends the lease record to the CSV file.
+    ///
+    /// Should be called in a thread safe context.
+    ///
+    /// This function doesn't throw exceptions itself. In theory, exceptions
+    /// are possible when the index of the indexes of the values being written
+    /// to the file are invalid. However, this would have been a programming
+    /// error.
+    ///
+    /// @param lease Structure representing a DHCPv4 lease.
+    /// @throw BadValue if the lease has no hardware address, no client id and
+    /// is not in STATE_DECLINED.
+    void appendInternal(const Lease4& lease);
+
+    /// @brief Reads next lease from the CSV file.
+    ///
+    /// Should be called in a thread safe context.
+    ///
+    /// If this function hits an error during lease read, it sets the error
+    /// message using @c CSVFile::setReadMsg and returns false. The error
+    /// string may be read using @c CSVFile::getReadMsg.
+    ///
+    /// Treats rows without a hardware address or a client id when their
+    /// state is not STATE_DECLINED as an error.
+    ///
+    /// This function is exception safe.
+    ///
+    /// @param [out] lease Pointer to the lease read from CSV file or
+    /// NULL pointer if lease hasn't been read.
+    ///
+    /// @return Boolean value indicating that the new lease has been
+    /// read from the CSV file (if true), or that the error has occurred
+    /// (false).
+    ///
+    /// @todo Make sure that the values read from the file are correct.
+    /// The appropriate @c Lease4 validation mechanism should be used once
+    /// ticket http://oldkea.isc.org/ticket/2405 is implemented.
+    bool nextInternal(Lease4Ptr& lease);
+
     /// @brief Initializes columns of the CSV file holding leases.
     ///
     /// This function initializes the following columns:
@@ -164,6 +214,8 @@ private:
     data::ConstElementPtr readContext(const util::CSVRow& row);
     //@}
 
+    /// @brief Mutex to protect the internal state.
+    std::mutex mutex_;
 };
 
 } // namespace isc::dhcp
index cf2f0c0c5c7400f1b9089e479bf6bd8b27dae740..cb8ea894c85c6e9a8583626a2523e443ba7e7072 100644 (file)
@@ -5,8 +5,11 @@
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 #include <config.h>
+
 #include <dhcpsrv/dhcpsrv_log.h>
 #include <dhcpsrv/csv_lease_file6.h>
+#include <util/multi_threading_mgr.h>
+
 #include <ctime>
 
 using namespace isc::asiolink;
@@ -23,6 +26,16 @@ CSVLeaseFile6::CSVLeaseFile6(const std::string& filename)
 
 void
 CSVLeaseFile6::open(const bool seek_to_end) {
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(mutex_);
+        openInternal(seek_to_end);
+    } else {
+        openInternal(seek_to_end);
+    }
+}
+
+void
+CSVLeaseFile6::openInternal(const bool seek_to_end) {
     // Call the base class to open the file
     VersionedCSVFile::open(seek_to_end);
 
@@ -32,6 +45,16 @@ CSVLeaseFile6::open(const bool seek_to_end) {
 
 void
 CSVLeaseFile6::append(const Lease6& lease) {
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(mutex_);
+        appendInternal(lease);
+    } else {
+        appendInternal(lease);
+    }
+}
+
+void
+CSVLeaseFile6::appendInternal(const Lease6& lease) {
     // Bump the number of write attempts
     ++writes_;
 
@@ -79,6 +102,16 @@ CSVLeaseFile6::append(const Lease6& lease) {
 
 bool
 CSVLeaseFile6::next(Lease6Ptr& lease) {
+    if (MultiThreadingMgr::instance().getMode()) {
+        std::lock_guard<std::mutex> lock(mutex_);
+        return (nextInternal(lease));
+    } else {
+        return (nextInternal(lease));
+    }
+}
+
+bool
+CSVLeaseFile6::nextInternal(Lease6Ptr& lease) {
     // Bump the number of read attempts
     ++reads_;
 
index 84acbd0a85bdd4e078cffdfdf28b058ee2529f5b..41cc949efd5b88f0620eb1bfc37b2e850224383d 100644 (file)
@@ -29,7 +29,7 @@ namespace dhcp {
 /// The @c Lease6 is a structure that should be itself responsible for this
 /// validation (see http://oldkea.isc.org/ticket/2405). However, when #2405
 /// is implemented, the @c next function may need to be updated to use the
-/// validation capablity of @c Lease6.
+/// validation capability of @c Lease6.
 class CSVLeaseFile6 : public isc::util::VersionedCSVFile, public LeaseFileStats {
 public:
 
@@ -57,8 +57,8 @@ public:
     /// error.
     ///
     /// @param lease Structure representing a DHCPv6 lease.
-    /// @throw BadValue if the lease to be written has an empty DUID and is
-    /// whose state is not STATE_DECLINED.
+    /// @throw BadValue if the lease to be written has an empty DUID and is not
+    /// in STATE_DECLINED.
     void append(const Lease6& lease);
 
     /// @brief Reads next lease from the CSV file.
@@ -83,6 +83,53 @@ public:
 
 private:
 
+    /// @brief Opens a lease file.
+    ///
+    /// Should be called in a thread safe context.
+    ///
+    /// This function calls the base class open to do the
+    /// work of opening a file.  It is used to clear any
+    /// statistics associated with any previous use of the file
+    /// While it doesn't throw any exceptions of its own
+    /// the base class may do so.
+    virtual void openInternal(const bool seek_to_end = false);
+
+    /// @brief Appends the lease record to the CSV file.
+    ///
+    /// Should be called in a thread safe context.
+    ///
+    /// This function doesn't throw exceptions itself. In theory, exceptions
+    /// are possible when the index of the indexes of the values being written
+    /// to the file are invalid. However, this would have been a programming
+    /// error.
+    ///
+    /// @param lease Structure representing a DHCPv6 lease.
+    /// @throw BadValue if the lease to be written has an empty DUID and is not
+    /// in STATE_DECLINED.
+    void appendInternal(const Lease6& lease);
+
+    /// @brief Reads next lease from the CSV file.
+    ///
+    /// Should be called in a thread safe context.
+    ///
+    /// If this function hits an error during lease read, it sets the error
+    /// message using @c CSVFile::setReadMsg and returns false. The error
+    /// string may be read using @c CSVFile::getReadMsg.
+    ///
+    /// This function is exception safe.
+    ///
+    /// @param [out] lease Pointer to the lease read from CSV file or
+    /// NULL pointer if lease hasn't been read.
+    ///
+    /// @return Boolean value indicating that the new lease has been
+    /// read from the CSV file (if true), or that the error has occurred
+    /// (false).
+    ///
+    /// @todo Make sure that the values read from the file are correct.
+    /// The appropriate @c Lease6 validation mechanism should be used once
+    /// ticket http://oldkea.isc.org/ticket/2405 is implemented.
+    bool nextInternal(Lease6Ptr& lease);
+
     /// @brief Initializes columns of the CSV file holding leases.
     ///
     /// This function initializes the following columns:
@@ -185,6 +232,8 @@ private:
     data::ConstElementPtr readContext(const util::CSVRow& row);
     //@}
 
+    /// @brief Mutex to protect the internal state.
+    std::mutex mutex_;
 };
 
 } // namespace isc::dhcp
index 5fc9d63f09c86fbf990c5ba3f46b4de34bc1c939..6d777ad61e76a5064d2266fdf2e6e166124a126e 100644 (file)
@@ -971,6 +971,11 @@ Connection::terminateInternal(const boost::system::error_code& ec,
             }
         }
 
+        // unlock mutex so that the callback can be safely processed.
+        if (MultiThreadingMgr::instance().getMode()) {
+            mutex_.unlock();
+        }
+
         try {
             // The callback should take care of its own exceptions but one
             // never knows.
@@ -979,6 +984,11 @@ Connection::terminateInternal(const boost::system::error_code& ec,
         } catch (...) {
         }
 
+        // lock mutex so that processing can continue.
+        if (MultiThreadingMgr::instance().getMode()) {
+            mutex_.lock();
+        }
+
         // If we're not requesting connection persistence, we should close the socket.
         // We're going to reconnect for the next transaction.
         if (!current_request_->isPersistent()) {