From: Thomas Markwalder Date: Tue, 16 Aug 2016 16:01:21 +0000 (-0400) Subject: [4294] PostgreSQL now supports IPv6 lease stats recounting X-Git-Tag: trac4631_base~6^2~13 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=efbf437f6dd84a03b1a8af1d017fada9ba02a492;p=thirdparty%2Fkea.git [4294] PostgreSQL now supports IPv6 lease stats recounting src/lib/dhcpsrv/pgsql_lease_mgr.h src/lib/dhcpsrv/pgsql_lease_mgr.cc - Added TaggedStatement RECOUNT_LEASE6_STATS - PgSqlAddressStatsQuery6 - new class PgSql derivation of the IPv6 statistical lease data query - PgSqlLeaseMgr::startAddressStatsQuery6() - new virtual method which creates and runs the IPv6 lease stats query src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc TEST_F(PgSqlLeaseMgrTest, recountAddressStats6) - new test --- diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc index cda0626988..1e4d826ddf 100644 --- a/src/lib/dhcpsrv/mysql_lease_mgr.cc +++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc @@ -1379,8 +1379,8 @@ public: /// @brief Creates the IPv6 lease statistical data result set /// /// The result set is populated by executing an SQL query against the - /// lease4 table which sums the leases per lease state per subnet id. - /// The query used is the prepared statement identified by + /// lease6 table which sums the leases per lease state per lease type + /// per subnet id. The query used is the prepared statement identified by /// MySqlLeaseMgr::RECOUNT_LEASE6_STATS. This method creates the binds /// the statement to the output bind array and then executes the /// statement. diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.cc b/src/lib/dhcpsrv/pgsql_lease_mgr.cc index 174237df70..751f636004 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.cc +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.cc @@ -207,6 +207,13 @@ PgSqlTaggedStatement tagged_statements[] = { "SELECT subnet_id, state, count(state) as state_count " "FROM lease4 GROUP BY subnet_id, state ORDER BY subnet_id"}, + // RECOUNT_LEASE6_STATS, + { 0, { OID_NONE }, + "recount_lease6_stats", + "SELECT subnet_id, lease_type, state, count(state) as state_count " + "FROM lease6 GROUP BY subnet_id, lease_type, state " + "ORDER BY subnet_id"}, + // End of list sentinel { 0, { 0 }, NULL, NULL} }; @@ -778,16 +785,19 @@ PgSqlAddressStatsQuery4::getNextRow(AddressStatsRow4& row) { // Fetch the subnet id. uint32_t col = 0; uint32_t subnet_id; - PgSqlExchange::getColumnValue(*result_set_, next_row_, 0, subnet_id); + PgSqlExchange::getColumnValue(*result_set_, next_row_, col, subnet_id); row.subnet_id_ = static_cast(subnet_id); + ++col; // Fetch the lease state. uint32_t state; - PgSqlExchange::getColumnValue(*result_set_, next_row_ , 1, state); + PgSqlExchange::getColumnValue(*result_set_, next_row_ , col, state); row.lease_state_ = static_cast(state); + ++col; // Fetch the state count. - PgSqlExchange::getColumnValue(*result_set_, next_row_, 2, row.state_count_); + PgSqlExchange::getColumnValue(*result_set_, next_row_, col, + row.state_count_); // Point to the next row. ++next_row_; @@ -802,6 +812,128 @@ PgSqlLeaseMgr::startAddressStatsQuery4() { return(query); } +/// @brief PgSql derivation of the IPv6 statistical lease data query +/// +/// This class is used to recalculate IPv6 lease statistics for MySQL +/// lease storage. It does so by executing a query which returns a result +/// containining contain one row per monitored state per subnet, ordered +/// by subnet id in ascending order. +/// +class PgSqlAddressStatsQuery6 : public AddressStatsQuery6 { +public: + /// @brief Constructor + /// + /// @param conn A open connection to the database housing the lease data + PgSqlAddressStatsQuery6(PgSqlConnection& conn); + + /// @brief Destructor + virtual ~PgSqlAddressStatsQuery6() {}; + + /// @brief Creates the IPv6 lease statistical data result set + /// + /// The result set is populated by executing an SQL query against the + /// lease6 table which sums the leases per lease state per lease type + /// per subnet id. The query used is the prepared statement identified by + /// PgSqlLeaseMgr::RECOUNT_LEASE6_STATS. This method executes the + /// statement which creates the result set. + void start(); + + /// @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(AddressStatsRow6& row); + +private: + + /// @brief Analyzes the given statement outcome status + /// + /// Wrapper method around the PgSqlConnection:checkError() that is + /// used to generate the appropriate exception if the status indicates + /// an error. + //// + /// a DbOperation error + /// @param status The MySQL statement execution outcome status + /// @param what invocation context message which will be included in + /// any exception + void checkError(int status, const char* what) const; + + /// @brief Database connection to use to execute the query + PgSqlConnection& conn_; + + /// @brief The query's prepared statement + PgSqlTaggedStatement& statement_; + + /// @brief The result set returned by Postgres. + boost::shared_ptr result_set_; + + /// @brief Index of the next row to fetch + uint32_t next_row_; +}; + +PgSqlAddressStatsQuery6::PgSqlAddressStatsQuery6(PgSqlConnection& conn) + : conn_(conn), statement_(tagged_statements[PgSqlLeaseMgr + ::RECOUNT_LEASE6_STATS]), + result_set_(), next_row_(0) { +} + +void +PgSqlAddressStatsQuery6::start() { + // The query has no parameters, so we only need it's name. + result_set_.reset(new PgSqlResult(PQexecPrepared(conn_, statement_.name, + 0, NULL, NULL, NULL, 0))); + + conn_.checkStatementError(*result_set_, statement_); +} + +bool +PgSqlAddressStatsQuery6::getNextRow(AddressStatsRow6& row) { + // If we're past the end, punt. + if (next_row_ >= result_set_->getRows()) { + return (false); + } + + // Fetch the subnet id. + uint32_t col = 0; + uint32_t subnet_id; + PgSqlExchange::getColumnValue(*result_set_, next_row_, col, subnet_id); + row.subnet_id_ = static_cast(subnet_id); + ++col; + + // Fetch the lease type. + uint32_t lease_type; + PgSqlExchange::getColumnValue(*result_set_, next_row_ , col, lease_type); + row.lease_type_ = static_cast(lease_type); + ++col; + + // Fetch the lease state. + uint32_t state; + PgSqlExchange::getColumnValue(*result_set_, next_row_ , col, state); + row.lease_state_ = static_cast(state); + ++col; + + // Fetch the state count. + PgSqlExchange::getColumnValue(*result_set_, next_row_, col, row.state_count_); + + // Point to the next row. + ++next_row_; + + return (true); +} + +AddressStatsQuery6Ptr +PgSqlLeaseMgr::startAddressStatsQuery6() { + AddressStatsQuery6Ptr query(new PgSqlAddressStatsQuery6(conn_)); + query->start(); + return(query); +} PgSqlLeaseMgr::PgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters) : LeaseMgr(), exchange4_(new PgSqlLease4Exchange()), diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.h b/src/lib/dhcpsrv/pgsql_lease_mgr.h index 9511c0e237..a8a40813a5 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.h +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.h @@ -327,6 +327,16 @@ public: /// @return The populated query as a pointer to an AddressStatsQuery4 virtual AddressStatsQuery4Ptr startAddressStatsQuery4(); + /// @brief Creates and runs the IPv6 lease stats query + /// + /// It creates an instance of a PgSqlAddressStatsQuery6 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 AddressStatsQuery6 + virtual AddressStatsQuery6Ptr startAddressStatsQuery6(); + /// @brief Return backend type /// /// Returns the type of the backend (e.g. "mysql", "memfile" etc.) @@ -396,6 +406,7 @@ public: UPDATE_LEASE4, // Update a Lease4 entry UPDATE_LEASE6, // Update a Lease6 entry RECOUNT_LEASE4_STATS, // Fetch IPv4 lease statistical data + RECOUNT_LEASE6_STATS, // Fetch IPv4 lease statistical data NUM_STATEMENTS // Number of statements }; diff --git a/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc index 762d37c253..fb473a7830 100644 --- a/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc @@ -407,5 +407,9 @@ TEST_F(PgSqlLeaseMgrTest, recountAddressStats4) { testRecountAddressStats4(); } +// Verifies that IPv6 lease statistics can be recalculated. +TEST_F(PgSqlLeaseMgrTest, recountAddressStats6) { + testRecountAddressStats6(); +} }; // namespace