Browse Source

[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
Thomas Markwalder 8 years ago
parent
commit
efbf437f6d

+ 2 - 2
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.

+ 135 - 3
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<SubnetID>(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<Lease::LeaseState>(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<PgSqlResult> 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<SubnetID>(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>(lease_type);
+    ++col;
+
+    // Fetch the lease state.
+    uint32_t state;
+    PgSqlExchange::getColumnValue(*result_set_, next_row_ , col, state);
+    row.lease_state_ = static_cast<Lease::LeaseState>(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()),

+ 11 - 0
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
     };
 

+ 4 - 0
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