From: Thomas Markwalder Date: Tue, 23 Jan 2018 18:51:19 +0000 (-0500) Subject: [5487] checkpoint commit X-Git-Tag: trac5502_base~5^2~1^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fa11dc5ce2244dcd52533c15772ec4bec03899ad;p=thirdparty%2Fkea.git [5487] checkpoint commit 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 --- diff --git a/src/lib/dhcpsrv/cql_lease_mgr.cc b/src/lib/dhcpsrv/cql_lease_mgr.cc index 5036044b75..ca87638aa8 100644 --- a/src/lib/dhcpsrv/cql_lease_mgr.cc +++ b/src/lib/dhcpsrv/cql_lease_mgr.cc @@ -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(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 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 cummulative_rows_; + + std::map::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(type_); + } else { + raw_row->lease_type_ = Lease::TYPE_NA; + } + + raw_row->lease_state_ = state_; + return raw_row; +} + CqlLeaseMgr::CqlLeaseMgr(const DatabaseConnection::ParameterMap ¶meters) : 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. diff --git a/src/lib/dhcpsrv/cql_lease_mgr.h b/src/lib/dhcpsrv/cql_lease_mgr.h index f8ffd82d68..03c68938d0 100644 --- a/src/lib/dhcpsrv/cql_lease_mgr.h +++ b/src/lib/dhcpsrv/cql_lease_mgr.h @@ -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 diff --git a/src/lib/dhcpsrv/lease_mgr.h b/src/lib/dhcpsrv/lease_mgr.h index 9bac9e6fc3..7ced8f2d78 100644 --- a/src/lib/dhcpsrv/lease_mgr.h +++ b/src/lib/dhcpsrv/lease_mgr.h @@ -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 LeaseStatsQueryPtr; +/// @brief Defines a pointer to a LeaseStatsRow. +typedef boost::shared_ptr LeaseStatsRowPtr; + /// @brief Abstract Lease Manager /// /// This is an abstract API for lease database backends. It provides unified diff --git a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc index 4696247e1d..12685c6c3a 100644 --- a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc @@ -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 -