]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5487] checkpoint commit
authorThomas Markwalder <tmark@isc.org>
Tue, 23 Jan 2018 18:51:19 +0000 (13:51 -0500)
committerThomas Markwalder <tmark@isc.org>
Tue, 23 Jan 2018 18:51:19 +0000 (13:51 -0500)
    recount4/6 both work, using queries that return rows for all leases.
    Needs cleanup and optimization

src/lib/dhcpsrv/cql_lease_mgr.cc
    added new class CqlLeaseStatsQuery : public LeaseStatsQuery, CqlExchange

    CqlLeaseMgr::CqlLeaseMgr()
        prepares CqlLeaseStatsQuery statements

    CqlLeaseMgr::startLeaseStatsQuery4()
    CqlLeaseMgr::startLeaseStatsQuery6()
        Create and start CqlLeaseStatsQuery()

src/lib/dhcpsrv/lease_mgr.h
    Added LeaseStatsRows::operator<

src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc
    Enabled CqlLeaseMgrTest.recountLeaseStats4/6

src/lib/dhcpsrv/cql_lease_mgr.cc
src/lib/dhcpsrv/cql_lease_mgr.h
src/lib/dhcpsrv/lease_mgr.h
src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc

index 5036044b75b5d7cf4abb65eed106e6f1c03d8985..ca87638aa8458995b2593e24f327073892f6cb06 100644 (file)
@@ -1438,12 +1438,190 @@ CqlLease6Exchange::getExpiredLeases(const size_t &max_leases,
     }
 }
 
+/// @brief Base CQL derivation of the statistical lease data query
+///
+/// This class provides the functionality such as results storage and row
+/// fetching common to fulfilling the statistical lease data query.
+///
+class CqlLeaseStatsQuery : public LeaseStatsQuery, CqlExchange {
+public:
+    /// @brief Constructor
+    ///
+    /// @param conn A open connection to the database housing the lease data
+    /// @param statement The lease data SQL prepared statement tag to execute
+    /// @param fetch_type Indicates whether or not lease_type should be
+    /// fetched from the result set
+    CqlLeaseStatsQuery(CqlConnection& conn, StatementTag& statement,
+                         const bool fetch_type)
+        : conn_(conn), statement_(statement), fetch_type_(fetch_type),
+          cummulative_rows_(), next_row_(cummulative_rows_.begin()),
+          subnet_id_(0), type_(0), state_(0) {
+    }
+
+    /// @brief Destructor
+    virtual ~CqlLeaseStatsQuery() {};
+
+    /// @brief Creates the lease statistical data result set
+    ///
+    /// The result set is populated by executing a  prepared SQL query
+    /// against the database which sums the leases per lease state per
+    /// subnet id.
+    void start() {
+        AnyArray data; // there are no where clause parameters
+
+        // This gets a collection of data for ALL leases, ugh
+        AnyArray collection = executeSelect(conn_, data, statement_);
+
+        // Now we need to coaelesce the raw rows
+        for (boost::any &element : collection) {
+            LeaseStatsRowPtr raw_row = boost::any_cast<LeaseStatsRowPtr>(element);
+            auto cum_row = cummulative_rows_.find(*raw_row);
+            if (cum_row != cummulative_rows_.end()) {
+                cummulative_rows_[*raw_row] = cum_row->second + 1;
+            } else {
+                cummulative_rows_.emplace(std::make_pair(*raw_row, 1));
+            }
+        }
+
+        next_row_ = cummulative_rows_.begin();
+    }
+
+
+    /// @brief Fetches the next row in the result set
+    ///
+    /// Once the internal result set has been populated by invoking the
+    /// the start() method, this method is used to iterate over the
+    /// result set rows. Once the last row has been fetched, subsequent
+    /// calls will return false.
+    ///
+    /// @param row Storage for the fetched row
+    ///
+    /// @return True if the fetch succeeded, false if there are no more
+    /// rows to fetch.
+    bool getNextRow(LeaseStatsRow& row) {
+        // If we're past the end, punt.
+        if (next_row_ == cummulative_rows_.end()) {
+            return (false);
+        }
+
+        row = next_row_->first;
+        row.state_count_ = next_row_->second;
+
+
+        // Point to the next row.
+        ++next_row_;
+        return (true);
+    }
+
+    /// @brief Create BIND array to receive C++ data.
+    ///
+    /// Used in executeSelect() to retrieve from database
+    ///
+    /// @param data array of bound objects representing data to be retrieved
+    /// @param statement_tag prepared statement being executed; defaults to an
+    ///     invalid index
+    virtual void
+    createBindForSelect(AnyArray& data, StatementTag statement_tag = NULL) override;
+
+    /// @brief Copy received data into the <version,minor> pair.
+    ///
+    /// Copies information about the version to be retrieved into a pair. Called
+    /// in executeSelect().
+    ///
+    /// @return a pointer to the object retrieved.
+    virtual boost::any retrieve() override;
+    
+    /// @brief Statement tags definitions
+    /// @{
+    // Return recalculated lease4 lease statistics
+    static constexpr StatementTag RECOUNT_LEASE4_STATS = "RECOUNT_LEASE4_STATS";
+    // Return recalculated lease6 lease statistics
+    static constexpr StatementTag RECOUNT_LEASE6_STATS = "RECOUNT_LEASE6_STATS";
+    /// @}
+   
+    /// @brief Cassandra statements
+    static StatementMap tagged_statements_;
+
+private:
+    /// @brief Database connection to use to execute the query
+    CqlConnection& conn_;
+
+    /// @brief The query's prepared statement tag
+    StatementTag statement_;
+
+    /// @brief Indicates if query supplies lease type
+    bool fetch_type_;
+
+    std::map<LeaseStatsRow, int> cummulative_rows_;
+
+    std::map<LeaseStatsRow, int>::iterator next_row_;
+
+    int subnet_id_;
+    int type_;
+    int state_;
+};
+
+constexpr StatementTag CqlLeaseStatsQuery::RECOUNT_LEASE4_STATS;
+constexpr StatementTag CqlLeaseStatsQuery::RECOUNT_LEASE6_STATS;
+
+StatementMap CqlLeaseStatsQuery::tagged_statements_{
+    // Return recalculated lease4 lease statistics
+    {RECOUNT_LEASE4_STATS, 
+        {RECOUNT_LEASE4_STATS, 
+        "SELECT "
+        "subnet_id, state "
+        "FROM lease4 "
+#if 0
+        "GROUP BY subnet_id, state "
+        "ORDER BY subnet_id"
+#endif
+    }},
+
+    // Return recalculated lease6 lease statistics
+    {RECOUNT_LEASE6_STATS, 
+        {RECOUNT_LEASE6_STATS, 
+        "SELECT "
+        "subnet_id, lease_type, state "
+        "FROM lease6 "
+#if 0
+        "GROUP BY subnet_id, lease_type, state "
+        "ORDER BY subnet_id"
+#endif
+    }},
+};
+
+void
+CqlLeaseStatsQuery::createBindForSelect(AnyArray& data, StatementTag) {
+    data.clear();
+    data.add(&subnet_id_);
+    if (fetch_type_) {
+        data.add(&type_);
+    }
+
+    data.add(&state_);
+}
+
+boost::any
+CqlLeaseStatsQuery::retrieve() {
+    LeaseStatsRowPtr raw_row(new LeaseStatsRow());
+    raw_row->subnet_id_ = subnet_id_;
+    if (fetch_type_) {
+        raw_row->lease_type_ = static_cast<Lease::Type>(type_);
+    } else {
+        raw_row->lease_type_ = Lease::TYPE_NA; 
+    }
+
+    raw_row->lease_state_ = state_;
+    return raw_row;
+}
+
 CqlLeaseMgr::CqlLeaseMgr(const DatabaseConnection::ParameterMap &parameters)
     : LeaseMgr(), dbconn_(parameters) {
     dbconn_.openDatabase();
     dbconn_.prepareStatements(CqlLease4Exchange::tagged_statements_);
     dbconn_.prepareStatements(CqlLease6Exchange::tagged_statements_);
     dbconn_.prepareStatements(CqlVersionExchange::tagged_statements_);
+    dbconn_.prepareStatements(CqlLeaseStatsQuery::tagged_statements_);
 }
 
 CqlLeaseMgr::~CqlLeaseMgr() {
@@ -1862,6 +2040,24 @@ CqlLeaseMgr::deleteExpiredReclaimedLeases6(const uint32_t secs) {
     return n_of_deleted_leases;
 }
 
+LeaseStatsQueryPtr
+CqlLeaseMgr::startLeaseStatsQuery4() {
+    LeaseStatsQueryPtr query(
+        new CqlLeaseStatsQuery(dbconn_, CqlLeaseStatsQuery::RECOUNT_LEASE4_STATS,
+                               false));
+    query->start();
+    return(query);
+}
+
+LeaseStatsQueryPtr
+CqlLeaseMgr::startLeaseStatsQuery6() {
+    LeaseStatsQueryPtr query(
+        new CqlLeaseStatsQuery(dbconn_, CqlLeaseStatsQuery::RECOUNT_LEASE6_STATS,
+                               true));
+    query->start();
+    return(query);
+}
+
 size_t
 CqlLeaseMgr::wipeLeases4(const SubnetID & /*subnet_id*/) {
     /// @todo: Need to implement this, so wipe leases would work.
index f8ffd82d68807983cc1a2e029f637d6db8efccb7..03c68938d024efc41700b97de2d10389a2e0ee26 100644 (file)
@@ -352,6 +352,26 @@ public:
     virtual uint64_t
     deleteExpiredReclaimedLeases6(const uint32_t secs) override;
 
+    /// @brief Creates and runs the IPv4 lease stats query
+    ///
+    /// It creates an instance of a CqlLeaseStatsQuery4 and then
+    /// invokes its start method, which fetches its statistical data
+    /// result set by executing the RECOUNT_LEASE_STATS4 query.
+    /// The query object is then returned.
+    ///
+    /// @return The populated query as a pointer to an LeaseStatsQuery
+    virtual LeaseStatsQueryPtr startLeaseStatsQuery4();
+
+    /// @brief Creates and runs the IPv6 lease stats query
+    ///
+    /// It creates an instance of a CqllLeaseStatsQuery and then
+    /// invokes its start method, which fetches its statistical data
+    /// result set by executing the RECOUNT_LEASE_STATS6 query.
+    /// The query object is then returned.
+    ///
+    /// @return The populated query as a pointer to an LeaseStatsQuery
+    virtual LeaseStatsQueryPtr startLeaseStatsQuery6();
+
     /// @brief Removes specified IPv4 leases.
     ///
     /// This rather dangerous method is able to remove all leases from specified
index 9bac9e6fc3078b2f64a08855faac6c0205728309..7ced8f2d7803d3eacbfa3aaa826ca1eb3661ca13 100644 (file)
@@ -101,6 +101,25 @@ struct LeaseStatsRow {
           lease_state_(lease_state), state_count_(state_count) {
     }
 
+    bool operator< (const LeaseStatsRow &rhs) const {
+        if (subnet_id_ < rhs.subnet_id_) {
+            return (true);
+        }
+
+        if (subnet_id_ == rhs.subnet_id_ &&
+            lease_type_ < rhs.lease_type_) {
+                return (true);
+        }
+
+        if (subnet_id_ == rhs.subnet_id_ &&
+            lease_type_ == rhs.lease_type_ &&
+            lease_state_ < rhs.lease_state_) {      
+                return (true);
+        }
+
+        return (false);
+    }
+
     /// @brief The subnet ID to which this data applies
     SubnetID subnet_id_;
     /// @brief The lease_type to which the count applies
@@ -140,9 +159,12 @@ public:
     virtual bool getNextRow(LeaseStatsRow& row);
 };
 
-/// @brief Defines a pointer to an LeaseStatsQuery.
+/// @brief Defines a pointer to a LeaseStatsQuery.
 typedef boost::shared_ptr<LeaseStatsQuery> LeaseStatsQueryPtr;
 
+/// @brief Defines a pointer to a LeaseStatsRow.
+typedef boost::shared_ptr<LeaseStatsRow> LeaseStatsRowPtr;
+
 /// @brief Abstract Lease Manager
 ///
 /// This is an abstract API for lease database backends. It provides unified
index 4696247e1dc55887e3e965a951146dda35f066a6..12685c6c3a86f550606a356debb23d8570d66601 100644 (file)
@@ -366,6 +366,7 @@ TEST(CqlOpenTest, OpenDatabase) {
                << "*** before the CQL tests will run correctly.\n";
     }
 
+
     // Check that attempting to get an instance of the lease manager when
     // none is set throws an exception.
     EXPECT_THROW(LeaseMgrFactory::instance(), NoLeaseManager);
@@ -699,17 +700,13 @@ TEST_F(CqlLeaseMgrTest, deleteExpiredReclaimedLeases4) {
     testDeleteExpiredReclaimedLeases4();
 }
 
-// Verifies that IPv4 lease statistics can be recalculated.
-/// @todo: uncomment this once stats recalculation is implemented
-/// for Cassandra (see #5487)
-TEST_F(CqlLeaseMgrTest, DISABLED_recountLeaseStats4) {
+/// @brief Verifies that IPv4 lease statistics can be recalculated.
+TEST_F(CqlLeaseMgrTest, recountLeaseStats4) {
     testRecountLeaseStats4();
 }
 
-// Verifies that IPv6 lease statistics can be recalculated.
-/// @todo: uncomment this once stats recalculation is implemented
-/// for Cassandra (see #5487)
-TEST_F(CqlLeaseMgrTest, DISABLED_recountLeaseStats6) {
+/// @brief Verifies that IPv6 lease statistics can be recalculated.
+TEST_F(CqlLeaseMgrTest, recountLeaseStats6) {
     testRecountLeaseStats6();
 }
 
@@ -728,4 +725,3 @@ TEST_F(CqlLeaseMgrTest, DISABLED_wipeLeases6) {
 }
 
 }  // namespace
-