]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
Cassandra Host Data Source stress test
authorAndrei Pavel <andrei.pavel@qualitance.com>
Wed, 14 Dec 2016 13:59:00 +0000 (15:59 +0200)
committerAndrei Pavel <andrei.pavel@qualitance.com>
Wed, 14 Dec 2016 13:59:00 +0000 (15:59 +0200)
It is part of the generic_host_data_source_unittest.cc, able to be
implemented for other HDS as well. It executes INSERT statements and
a certain SELECT statement which Cassandra struggles in performance
with since it has to do two queries instead of a join. All statement
executions are timed and repeated on an increasingly number of hosts.
It is placed last and DISABLED_ as you don't want to run this during
a usual make check.

src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc
src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc
src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h

index 24d0ba4814f176793c126d9f3de9b7d7ecd01974..5e7e697c5bc3ac265387afc1f0f7508bd3f77da9 100644 (file)
@@ -35,10 +35,8 @@ namespace {
 
 class CqlHostDataSourceTest : public GenericHostDataSourceTest {
 public:
-    /// @brief Constructor
-    ///
-    /// Deletes everything from the database and opens it.
-    CqlHostDataSourceTest() {
+    /// @brief Clears the database and opens connection to it.
+    void initializeTest() {
         // Ensure schema is the correct one.
         destroyCqlSchema(false, true);
         createCqlSchema(false, true);
@@ -58,15 +56,27 @@ public:
         hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
     }
 
+    /// @brief Destroys the HDS and the schema.
+    void destroyTest() {
+        hdsptr_->rollback();
+        HostDataSourceFactory::destroy();
+        destroyCqlSchema(false, true);
+    }
+
+    /// @brief Constructor
+    ///
+    /// Deletes everything from the database and opens it.
+    CqlHostDataSourceTest(){
+        initializeTest();
+    }
+
     /// @brief Destructor
     ///
     /// Rolls back all pending transactions.  The deletion of myhdsptr_ will
     /// close the database.  Then reopen it and delete everything created by the
     /// test.
     virtual ~CqlHostDataSourceTest() {
-        hdsptr_->rollback();
-        HostDataSourceFactory::destroy();
-        destroyCqlSchema(false, true);
+        destroyTest();
     }
 
     /// @brief Reopen the database
@@ -475,8 +485,7 @@ TEST_F(CqlHostDataSourceTest, testAddRollback) {
     CqlConnection connection(params);
     ASSERT_NO_THROW(connection.openDatabase());
 
-    // Drop every table so we make sure host_ipv6_reservation_options doesn't
-    // exist anymore
+    // Drop every table so we make sure host_reservations doesn't exist anymore.
     destroyCqlSchema(false, true);
 
     // Create a host with a reservation.
@@ -502,4 +511,14 @@ TEST_F(CqlHostDataSourceTest, testAddRollback) {
         DbOperationError);
 }
 
-};  // anonymous namespace
+TEST_F(CqlHostDataSourceTest, DISABLED_stressTest) {
+    // Run with 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4092, 8192,
+    // 16384 & 32768 hosts.
+    for (unsigned int i = 0X0001U; i < 0xfffdU; i <<= 1) {
+        initializeTest();
+        stressTest(i);
+        destroyTest();
+    }
+}
+
+}  // namespace
index db7c494c3847681d26126a1abaabb577157c8030..ec361708d09e536c5bd697831860bd0a915c3c10 100644 (file)
@@ -149,6 +149,17 @@ HostPtr GenericHostDataSourceTest::initializeHost6(std::string address,
     return (host);
 }
 
+bool
+GenericHostDataSourceTest::reservationExists(const IPv6Resrv& resrv,
+                                             const IPv6ResrvRange& range) {
+    for (IPv6ResrvIterator it = range.first; it != range.second; ++it) {
+        if (resrv == it->second) {
+            return true;
+        }
+    }
+    return false;
+}
+
 void
 GenericHostDataSourceTest::compareHwaddrs(const ConstHostPtr& host1,
                                           const ConstHostPtr& host2,
@@ -1499,6 +1510,76 @@ GenericHostDataSourceTest::testMessageFields4() {
     ASSERT_NO_FATAL_FAILURE(compareHosts(host, from_hds));
 }
 
-}; // namespace test
-}; // namespace dhcp
-}; // namespace isc
+void
+GenericHostDataSourceTest::stressTest(unsigned int nOfHosts /* = 0xfffdU */) {
+    // Make sure we have a pointer to the host data source.
+    ASSERT_TRUE(hdsptr_);
+
+    // Make sure the variable part of the generated address fits in a 16-bit
+    // field.
+    ASSERT_LE(nOfHosts, 0xfffdU);
+
+    // Create hosts.
+    std::vector<HostPtr> hosts;
+    hosts.reserve(nOfHosts);
+    for (unsigned int i = 0x0001U; i < 0x0001U + nOfHosts; ++i) {
+        /// @todo: Check if this is written in hexadecimal format.
+        std::stringstream ss;
+        std::string n_host;
+        ss << std::hex << i;
+        ss >> n_host;
+
+        const std::string prefix = std::string("2001:db8::") + n_host;
+        hosts.push_back(initializeHost6(prefix, Host::IDENT_HWADDR, false));
+        IPv6ResrvRange range = hosts.back()->getIPv6Reservations();
+        ASSERT_EQ(1, std::distance(range.first, range.second));
+        EXPECT_TRUE(reservationExists(
+            IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress(prefix)), range));
+    }
+    const size_t hosts_size = hosts.size();
+
+    std::cout << "Starting to add hosts..." << std::endl;
+    struct timespec start, end;
+    start = (struct timespec){0, 0};
+    end = (struct timespec){0, 0};
+    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start);
+    for (std::vector<HostPtr>::const_iterator it = hosts.begin();
+         it != hosts.end(); it++) {
+        ASSERT_NO_THROW(hdsptr_->add(*it));
+    }
+    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
+    double s = static_cast<double>(end.tv_sec - start.tv_sec) +
+               static_cast<double>(end.tv_nsec - start.tv_nsec) / 1e9;
+    std::cout << "Adding " << hosts_size
+              << (hosts_size == 1 ? " host" : " hosts") << " took "
+              << std::fixed << std::setprecision(2) << s << " seconds."
+              << std::endl;
+
+    // And then try to retrieve them back.
+    std::cout << "Starting to retrieve hosts..." << std::endl;
+    start = (struct timespec){0, 0};
+    end = (struct timespec){0, 0};
+    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start);
+    for (std::vector<HostPtr>::const_iterator it = hosts.begin();
+         it != hosts.end(); it++) {
+        IPv6ResrvRange range = (*it)->getIPv6Reservations();
+        // This get6() call is particularly useful to test because it involves a
+        // subquery for MySQL and PostgreSQL and two separate queries for
+        // Cassandra.
+        ConstHostPtr from_hds =
+            hdsptr_->get6(range.first->second.getPrefix(), 128);
+        ASSERT_TRUE(from_hds);
+        compareHosts(*it, from_hds);
+    }
+    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
+    s = static_cast<double>(end.tv_sec - start.tv_sec) +
+        static_cast<double>(end.tv_nsec - start.tv_nsec) / 1e9;
+    std::cout << "Retrieving " << hosts_size
+              << (hosts_size == 1 ? " host" : " hosts") << " took "
+              << std::fixed << std::setprecision(2) << s << " seconds."
+              << std::endl;
+}
+
+}  // namespace test
+}  // namespace dhcp
+}  // namespace isc
index 7ada26279c6011f4fc87d80072e3c1f675f4d85b..fda5191ae70685347fdb4c2c952a1420d0c9978d 100644 (file)
@@ -86,6 +86,13 @@ public:
     /// @return Identifier in textual form acceptable by Host constructor
     std::vector<uint8_t> generateIdentifier(const bool new_identifier = true);
 
+    /// @brief Checks if the reservation is in the range of reservations.
+    ///
+    /// @param resrv Reservation to be searched for.
+    /// @param range Range of reservations returned by the @c Host object
+    /// in which the reservation will be searched
+    bool reservationExists(const IPv6Resrv& resrv, const IPv6ResrvRange& range);
+
     /// @brief Compares hardware addresses of the two hosts.
     ///
     /// This method compares two hwardware address and uses gtest
@@ -533,6 +540,15 @@ public:
     ///
     void testMessageFields4();
 
+    /// @brief Stress test on adding and retrieving hosts
+    ///
+    /// Rather than checking for correctness, this test gives interpretable
+    /// performance results.
+    ///
+    /// @param n_of_hosts number of hosts to insert into and retrieve from the
+    ///     database; defaults to the maximum number of allowed hosts.
+    void stressTest(uint32_t n_of_hosts /* = 0xfffdU */);
+
     /// @brief Returns DUID with identical content as specified HW address
     ///
     /// This method does not have any sense in real life and is only useful
@@ -555,8 +571,8 @@ public:
 
 };
 
-}; // namespace test
-}; // namespace dhcp
-}; // namespace isc
+}  // namespace test
+}  // namespace dhcp
+}  // namespace isc
 
 #endif