From: Andrei Pavel Date: Wed, 14 Dec 2016 13:59:00 +0000 (+0200) Subject: Cassandra Host Data Source stress test X-Git-Tag: trac5502_base~5^2~7^2~14^2~11^2~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=86c8a50a05ea9c3439a56f580b744df3ec4f42a8;p=thirdparty%2Fkea.git Cassandra Host Data Source stress test 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. --- diff --git a/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc index 24d0ba4814..5e7e697c5b 100644 --- a/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc @@ -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 diff --git a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc index db7c494c38..ec361708d0 100644 --- a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc @@ -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 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::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(end.tv_sec - start.tv_sec) + + static_cast(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::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(end.tv_sec - start.tv_sec) + + static_cast(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 diff --git a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h index 7ada26279c..fda5191ae7 100644 --- a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h +++ b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h @@ -86,6 +86,13 @@ public: /// @return Identifier in textual form acceptable by Host constructor std::vector 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