From: Thomas Markwalder Date: Tue, 30 Jul 2013 18:24:25 +0000 (-0400) Subject: [3052] Added peekAt and dequeueAt methods to D2QueueMgr. X-Git-Tag: bind10-1.2.0beta1-release~292^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f964dbc5497ea2aef884251c708007e97185df2e;p=thirdparty%2Fkea.git [3052] Added peekAt and dequeueAt methods to D2QueueMgr. In order to add some flexibility in manipulating queue contents these two methods provide access to queue entries based on their ordinal position. --- diff --git a/src/bin/d2/d2_queue_mgr.cc b/src/bin/d2/d2_queue_mgr.cc index aeb7ead691..9fe4ebb9e0 100644 --- a/src/bin/d2/d2_queue_mgr.cc +++ b/src/bin/d2/d2_queue_mgr.cc @@ -142,17 +142,39 @@ D2QueueMgr::removeListener() { const dhcp_ddns::NameChangeRequestPtr& D2QueueMgr::peek() const { if (getQueueSize() == 0) { - isc_throw(D2QueueMgrQueEmpty, + isc_throw(D2QueueMgrQueueEmpty, "D2QueueMgr peek attempted on an empty queue"); } return (ncr_queue_.front()); } +const dhcp_ddns::NameChangeRequestPtr& +D2QueueMgr::peekAt(size_t index) const { + if (index >= getQueueSize()) { + isc_throw(D2QueueMgrInvalidIndex, + "D2QueueMgr peek beyond end of queue attempted"); + } + + return (ncr_queue_.at(index)); +} + +void +D2QueueMgr::dequeueAt(size_t index) { + if (index >= getQueueSize()) { + isc_throw(D2QueueMgrInvalidIndex, + "D2QueueMgr dequeue beyond end of queue attempted"); + } + + RequestQueue::iterator pos = ncr_queue_.begin() + index; + ncr_queue_.erase(pos); +} + + void D2QueueMgr::dequeue() { if (getQueueSize() == 0) { - isc_throw(D2QueueMgrQueEmpty, + isc_throw(D2QueueMgrQueueEmpty, "D2QueueMgr dequeue attempted on an empty queue"); } diff --git a/src/bin/d2/d2_queue_mgr.h b/src/bin/d2/d2_queue_mgr.h index d47fc775b5..01b33ffbce 100644 --- a/src/bin/d2/d2_queue_mgr.h +++ b/src/bin/d2/d2_queue_mgr.h @@ -49,19 +49,27 @@ public: /// @brief Thrown if the request queue is full when an enqueue is attempted. -class D2QueueMgrQueFull : public isc::Exception { +class D2QueueMgrQueueFull : public isc::Exception { public: - D2QueueMgrQueFull(const char* file, size_t line, const char* what) : + D2QueueMgrQueueFull(const char* file, size_t line, const char* what) : isc::Exception(file, line, what) { }; }; /// @brief Thrown if the request queue empty and a read is attempted. -class D2QueueMgrQueEmpty : public isc::Exception { +class D2QueueMgrQueueEmpty : public isc::Exception { public: - D2QueueMgrQueEmpty(const char* file, size_t line, const char* what) : + D2QueueMgrQueueEmpty(const char* file, size_t line, const char* what) : isc::Exception(file, line, what) { }; }; +/// @brief Thrown if a queue index is beyond the end of the queue +class D2QueueMgrInvalidIndex : public isc::Exception { +public: + D2QueueMgrInvalidIndex(const char* file, size_t line, const char* what) : + isc::Exception(file, line, what) { }; +}; + + /// @brief D2QueueMgr creates and manages a queue of DNS update requests. /// /// D2QueueMgr is class specifically designed as an integral part of DHCP-DDNS. @@ -216,7 +224,7 @@ public: /// /// @param stop_state is one of the three stopped state values. /// - /// @throw Throws D2QueueMgrError if stop_state is a valid stop state. + /// @throw D2QueueMgrError if stop_state is a valid stop state. void stopListening(const State stop_state = STOPPED); /// @brief Deletes the current listener @@ -242,7 +250,7 @@ public: /// /// @param max_queue_size is the new maximum size of the queue. /// - /// @throw Throws D2QueueMgrError if the new value is less than one or if + /// @throw D2QueueMgrError if the new value is less than one or if /// the new value is less than the number of entries currently in the /// queue. void setMaxQueueSize(const size_t max_queue_size); @@ -258,12 +266,35 @@ public: /// approach to task selection. Note, the entry is not removed from the /// queue. /// - /// @throw Throws D2QueueMgrQueEmpty if there are no entries in the queue. + /// @return Pointer reference to the queue entry. + /// + /// @throw D2QueueMgrQueEmpty if there are no entries in the queue. const dhcp_ddns::NameChangeRequestPtr& peek() const; + /// @brief Returns the entry at a given position in the queue. + /// + /// Note that the entry is not removed from the queue. + /// @param index the index of the entry in the queue to fetch. + /// Valid values are 0 (front of the queue) to (queue size - 1). + /// + /// @return Pointer reference to the queue entry. + /// + /// @throw D2QueueMgrInvalidIndex if the given index is beyond the + /// end of the queue. + const dhcp_ddns::NameChangeRequestPtr& peekAt(size_t index) const; + + /// @brief Removes the entry at a given position in the queue. + /// + /// @param index the index of the entry in the queue to remove. + /// Valid values are 0 (front of the queue) to (queue size - 1). + /// + /// @throw D2QueueMgrInvalidIndex if the given index is beyond the + /// end of the queue. + void dequeueAt(size_t index); + /// @brief Removes the entry at the front of the queue. /// - /// @throw Throws D2QueueMgrQueEmpty if there are no entries in the queue. + /// @throw D2QueueMgrQueEmpty if there are no entries in the queue. void dequeue(); /// @brief Adds a request to the end of the queue. diff --git a/src/bin/d2/tests/d2_queue_mgr_unittests.cc b/src/bin/d2/tests/d2_queue_mgr_unittests.cc index 29062de05a..0fccf9b518 100644 --- a/src/bin/d2/tests/d2_queue_mgr_unittests.cc +++ b/src/bin/d2/tests/d2_queue_mgr_unittests.cc @@ -84,7 +84,7 @@ const long TEST_TIMEOUT = 5 * 1000; TEST(D2QueueMgrBasicTest, constructionTests) { isc::asiolink::IOService io_service; - // Verify that constructing with max queue size of zero is not allowed. + // Verify that constructing with max queue size of zero is not allowed. EXPECT_THROW(D2QueueMgr(io_service, 0), D2QueueMgrError); // Verify that valid constructor works. @@ -104,7 +104,7 @@ TEST(D2QueueMgrBasicTest, constructionTests) { /// 1. Following construction queue is empty /// 2. Attempting to peek at an empty queue is not allowed /// 3. Attempting to dequeue an empty queue is not allowed -/// 4. Peek returns the first entry on the queue without altering queue content +/// 4. Peek returns the first entry on the queue without altering queue content /// 5. Dequeue removes the first entry on the queue TEST(D2QueueMgrBasicTest, basicQueueTests) { isc::asiolink::IOService io_service; @@ -119,19 +119,19 @@ TEST(D2QueueMgrBasicTest, basicQueueTests) { EXPECT_EQ(0, queue_mgr->getQueueSize()); // Verify that peek and dequeue both throw when queue is empty. - EXPECT_THROW(queue_mgr->peek(), D2QueueMgrQueEmpty); - EXPECT_THROW(queue_mgr->dequeue(), D2QueueMgrQueEmpty); + EXPECT_THROW(queue_mgr->peek(), D2QueueMgrQueueEmpty); + EXPECT_THROW(queue_mgr->dequeue(), D2QueueMgrQueueEmpty); // Vector to keep track of the NCRs we que. std::vectorref_msgs; - NameChangeRequestPtr ncr; + NameChangeRequestPtr ncr; // Iterate over the list of requests and add each to the queue. for (int i = 0; i < VALID_MSG_CNT; i++) { // Create the ncr and add to our reference list. - ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(valid_msgs[i])); + ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(valid_msgs[i])); ref_msgs.push_back(ncr); - + // Verify that the request can be added to the queue and queue // size increments accordingly. EXPECT_NO_THROW(queue_mgr->enqueue(ncr)); @@ -139,7 +139,7 @@ TEST(D2QueueMgrBasicTest, basicQueueTests) { } // Loop through and verify that the queue contents match the - // reference list. + // reference list. for (int i = 0; i < VALID_MSG_CNT; i++) { // Verify that peek on a non-empty queue returns first entry // without altering queue content. @@ -154,10 +154,36 @@ TEST(D2QueueMgrBasicTest, basicQueueTests) { // Verify the dequeueing from non-empty queue works EXPECT_NO_THROW(queue_mgr->dequeue()); - - // Verify queue size decrements following dequeue. + + // Verify queue size decrements following dequeue. EXPECT_EQ(VALID_MSG_CNT-(i+1), queue_mgr->getQueueSize()); } + + // Iterate over the list of requests and add each to the queue. + for (int i = 0; i < VALID_MSG_CNT; i++) { + // Create the ncr and add to our reference list. + ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(valid_msgs[i])); + ref_msgs.push_back(ncr); + EXPECT_NO_THROW(queue_mgr->enqueue(ncr)); + } + + // Verify queue count is correct. + EXPECT_EQ(VALID_MSG_CNT, queue_mgr->getQueueSize()); + + // Verfiy that peekAt returns the correct entry. + EXPECT_NO_THROW(ncr = queue_mgr->peekAt(1)); + EXPECT_TRUE (*(ref_msgs[1]) == *ncr); + + // Verfiy that dequeueAt removes the correct entry. + // Removing it, this should shift the queued entries forward by one. + EXPECT_NO_THROW(queue_mgr->dequeueAt(1)); + EXPECT_NO_THROW(ncr = queue_mgr->peekAt(1)); + EXPECT_TRUE (*(ref_msgs[2]) == *ncr); + + // Verify the peekAt and dequeueAt throw when given indexes beyond the end. + EXPECT_THROW(queue_mgr->peekAt(VALID_MSG_CNT + 1), D2QueueMgrInvalidIndex); + EXPECT_THROW(queue_mgr->dequeueAt(VALID_MSG_CNT + 1), + D2QueueMgrInvalidIndex); } /// @brief Compares two NameChangeRequests for equality. @@ -178,14 +204,14 @@ public: isc::asiolink::IntervalTimer test_timer_; D2QueueMgrPtr queue_mgr_; - NameChangeSender::Result send_result_; + NameChangeSender::Result send_result_; std::vector sent_ncrs_; std::vector received_ncrs_; QueueMgrUDPTest() : io_service_(), test_timer_(io_service_) { isc::asiolink::IOAddress addr(TEST_ADDRESS); // Create our sender instance. Note that reuse_address is true. - sender_.reset(new NameChangeUDPSender(addr, SENDER_PORT, + sender_.reset(new NameChangeUDPSender(addr, SENDER_PORT, addr, LISTENER_PORT, FMT_JSON, *this, 100, true)); @@ -218,11 +244,11 @@ public: }; /// @brief Tests D2QueueMgr's state model. -/// This test verifies that: +/// This test verifies that: /// 1. Upon construction, initial state is NOT_INITTED. /// 2. Cannot start listening from while state is NOT_INITTED. /// 3. Successful listener initialization transitions from NOT_INITTED -/// to INITTED. +/// to INITTED. /// 4. Attempting to initialize the listener from INITTED state is not /// allowed. /// 5. Starting listener from INITTED transitions to RUNNING. @@ -230,7 +256,7 @@ public: /// 7. Starting listener from STOPPED transitions to RUNNING. TEST_F (QueueMgrUDPTest, stateModelTest) { // Create the queue manager. - EXPECT_NO_THROW(queue_mgr_.reset(new D2QueueMgr(io_service_, + EXPECT_NO_THROW(queue_mgr_.reset(new D2QueueMgr(io_service_, VALID_MSG_CNT))); // Verify that the initial state is NOT_INITTED. @@ -248,9 +274,9 @@ TEST_F (QueueMgrUDPTest, stateModelTest) { // Verify that attempting to initialize the listener, from INITTED // is not allowed. EXPECT_THROW(queue_mgr_->initUDPListener(addr, LISTENER_PORT, - FMT_JSON, true), + FMT_JSON, true), D2QueueMgrError); - + // Verify that we can enter the RUNNING from INITTED by starting the // listener. EXPECT_NO_THROW(queue_mgr_->startListening()); @@ -279,8 +305,8 @@ TEST_F (QueueMgrUDPTest, stateModelTest) { EXPECT_EQ(D2QueueMgr::NOT_INITTED, queue_mgr_->getMgrState()); } -/// @brief Tests D2QueueMgr's ability to manage received requests -/// This test verifies that: +/// @brief Tests D2QueueMgr's ability to manage received requests +/// This test verifies that: /// 1. Requests can be received, queued, and dequeued /// 2. Once the queue is full, a subsequent request transitions /// manager to STOPPED_QUEUE_FULL state. @@ -295,7 +321,7 @@ TEST_F (QueueMgrUDPTest, liveFeedTest) { NameChangeRequestPtr received_ncr; // Create the queue manager and start listening.. - ASSERT_NO_THROW(queue_mgr_.reset(new D2QueueMgr(io_service_, + ASSERT_NO_THROW(queue_mgr_.reset(new D2QueueMgr(io_service_, VALID_MSG_CNT))); ASSERT_EQ(D2QueueMgr::NOT_INITTED, queue_mgr_->getMgrState()); @@ -319,7 +345,7 @@ TEST_F (QueueMgrUDPTest, liveFeedTest) { // each one. Verify and dequeue as they arrive. for (int i = 0; i < VALID_MSG_CNT; i++) { // Create the ncr and add to our reference list. - ASSERT_NO_THROW(send_ncr = NameChangeRequest::fromJSON(valid_msgs[i])); + ASSERT_NO_THROW(send_ncr = NameChangeRequest::fromJSON(valid_msgs[i])); ASSERT_NO_THROW(sender_->sendRequest(send_ncr)); // running two should do the send then the receive @@ -343,7 +369,7 @@ TEST_F (QueueMgrUDPTest, liveFeedTest) { // each one. Allow them to accumulate in the queue. for (int i = 0; i < VALID_MSG_CNT; i++) { // Create the ncr and add to our reference list. - ASSERT_NO_THROW(send_ncr = NameChangeRequest::fromJSON(valid_msgs[i])); + ASSERT_NO_THROW(send_ncr = NameChangeRequest::fromJSON(valid_msgs[i])); ASSERT_NO_THROW(sender_->sendRequest(send_ncr)); // running two should do the send then the receive @@ -364,11 +390,11 @@ TEST_F (QueueMgrUDPTest, liveFeedTest) { EXPECT_NO_THROW(io_service_.run_one()); EXPECT_EQ(D2QueueMgr::STOPPED_QUEUE_FULL, queue_mgr_->getMgrState()); - // Verify queue size did not increase beyond max. + // Verify queue size did not increase beyond max. EXPECT_EQ(VALID_MSG_CNT, queue_mgr_->getQueueSize()); // Verify that setting max queue size to a value less than current size of - // the queue is not allowed. + // the queue is not allowed. EXPECT_THROW(queue_mgr_->setMaxQueueSize(VALID_MSG_CNT-1), D2QueueMgrError); EXPECT_EQ(VALID_MSG_CNT, queue_mgr_->getQueueSize());