diff --git a/daemon/table/cs-policy-priority-fifo.hpp b/daemon/table/cs-policy-priority-fifo.hpp index 436afd9a..4ac5a63d 100644 --- a/daemon/table/cs-policy-priority-fifo.hpp +++ b/daemon/table/cs-policy-priority-fifo.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2014-2016, Regents of the University of California, +/* + * Copyright (c) 2014-2018, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -23,8 +23,8 @@ * NFD, e.g., in COPYING.md file. If not, see . */ -#ifndef NFD_DAEMON_TABLE_CS_POLICY_FIFO_HPP -#define NFD_DAEMON_TABLE_CS_POLICY_FIFO_HPP +#ifndef NFD_DAEMON_TABLE_CS_POLICY_PRIORITY_FIFO_HPP +#define NFD_DAEMON_TABLE_CS_POLICY_PRIORITY_FIFO_HPP #include "cs-policy.hpp" #include "core/scheduler.hpp" @@ -61,13 +61,17 @@ struct EntryItComparator typedef std::map EntryInfoMapFifo; -/** \brief Priority Fifo cs replacement policy +/** \brief Priority FIFO replacement policy * - * The entries that get removed first are unsolicited Data packets, - * which are the Data packets that got cached opportunistically without preceding - * forwarding of the corresponding Interest packet. - * Next, the Data packets with expired freshness are removed. - * Last, the Data packets are removed from the Content Store on a pure FIFO basis. + * This policy maintains a set of cleanup queues to decide the eviction order of CS entries. + * The cleanup queues are three doubly linked lists that store Table iterators. + * The three queues keep track of unsolicited, stale, and fresh Data packet, respectively. + * Table iterator is placed into, removed from, and moved between suitable queues + * whenever an Entry is added, removed, or has other attribute changes. + * The Table iterator of an Entry should be in exactly one queue at any moment. + * Within each queue, the iterators are kept in first-in-first-out order. + * Eviction procedure exhausts the first queue before moving onto the next queue, + * in the order of unsolicited, stale, and fresh queue. */ class PriorityFifoPolicy : public Policy { @@ -81,19 +85,19 @@ public: static const std::string POLICY_NAME; private: - virtual void + void doAfterInsert(iterator i) override; - virtual void + void doAfterRefresh(iterator i) override; - virtual void + void doBeforeErase(iterator i) override; - virtual void + void doBeforeUse(iterator i) override; - virtual void + void evictEntries() override; private: @@ -132,4 +136,4 @@ using priority_fifo::PriorityFifoPolicy; } // namespace cs } // namespace nfd -#endif // NFD_DAEMON_TABLE_CS_POLICY_FIFO_HPP +#endif // NFD_DAEMON_TABLE_CS_POLICY_PRIORITY_FIFO_HPP diff --git a/daemon/table/cs.cpp b/daemon/table/cs.cpp index 81b3fd63..54466ed7 100644 --- a/daemon/table/cs.cpp +++ b/daemon/table/cs.cpp @@ -88,6 +88,29 @@ Cs::insert(const Data& data, bool isUnsolicited) } } +void +Cs::erase(const Name& prefix, size_t limit, const AfterEraseCallback& cb) +{ + BOOST_ASSERT(static_cast(cb)); + + iterator first = m_table.lower_bound(prefix); + iterator last = m_table.end(); + if (prefix.size() > 0) { + last = m_table.lower_bound(prefix.getSuccessor()); + } + + size_t nErased = 0; + while (first != last && nErased < limit) { + m_policy->beforeErase(first); + first = m_table.erase(first); + ++nErased; + } + + if (cb) { + cb(nErased); + } +} + void Cs::find(const Interest& interest, const HitCallback& hitCallback, diff --git a/daemon/table/cs.hpp b/daemon/table/cs.hpp index 5a60fefc..fc161c53 100644 --- a/daemon/table/cs.hpp +++ b/daemon/table/cs.hpp @@ -23,28 +23,6 @@ * NFD, e.g., in COPYING.md file. If not, see . */ -/** \file - * - * \brief implements the ContentStore - * - * This ContentStore implementation consists of two data structures, - * a Table, and a set of cleanup queues. - * - * The Table is a container (std::set) sorted by full Names of stored Data packets. - * Data packets are wrapped in Entry objects. - * Each Entry contain the Data packet itself, - * and a few addition attributes such as the staleness of the Data packet. - * - * The cleanup queues are three doubly linked lists which stores Table iterators. - * The three queues keep track of unsolicited, stale, and fresh Data packet, respectively. - * Table iterator is placed into, removed from, and moved between suitable queues - * whenever an Entry is added, removed, or has other attribute changes. - * The Table iterator of an Entry should be in exactly one queue at any moment. - * Within each queue, the iterators are kept in first-in-first-out order. - * Eviction procedure exhausts the first queue before moving onto the next queue, - * in the order of unsolicited, stale, and fresh queue. - */ - #ifndef NFD_DAEMON_TABLE_CS_HPP #define NFD_DAEMON_TABLE_CS_HPP @@ -57,7 +35,15 @@ namespace nfd { namespace cs { -/** \brief represents the ContentStore +/** \brief implements the Content Store + * + * This Content Store implementation consists of a Table and a replacement policy. + * + * The Table is a container ( \c std::set ) sorted by full Names of stored Data packets. + * Data packets are wrapped in Entry objects. Each Entry contains the Data packet itself, + * and a few additional attributes such as when the Data becomes non-fresh. + * + * The replacement policy is implemented in a subclass of \c Policy. */ class Cs : noncopyable { @@ -70,8 +56,19 @@ public: void insert(const Data& data, bool isUnsolicited = false); - typedef std::function HitCallback; - typedef std::function MissCallback; + using AfterEraseCallback = std::function; + + /** \brief asynchronously erases entries under \p prefix + * \param prefix name prefix of entries + * \param limit max number of entries to erase + * \param cb callback to receive the actual number of erased entries; it may be empty; + * it may be invoked either before or after erase() returns + */ + void + erase(const Name& prefix, size_t limit, const AfterEraseCallback& cb); + + using HitCallback = std::function; + using MissCallback = std::function; /** \brief finds the best matching Data packet * \param interest the Interest for lookup diff --git a/tests/daemon/table/cs.t.cpp b/tests/daemon/table/cs.t.cpp index f63cec7d..66b7e95e 100644 --- a/tests/daemon/table/cs.t.cpp +++ b/tests/daemon/table/cs.t.cpp @@ -85,10 +85,21 @@ protected: check(0); })); - // current Cs::find implementation performs lookup synchronously + // current Cs::find implementation is synchronous BOOST_CHECK(hasResult); } + size_t + erase(const Name& prefix, size_t limit) + { + ndn::optional nErased; + m_cs.erase(prefix, limit, [&] (size_t nErased1) { nErased = nErased1; }); + + // current Cs::erase implementation is synchronous + // if callback was not invoked, bad_optional_access would occur + return *nErased; + } + protected: Cs m_cs; shared_ptr m_interest; @@ -364,6 +375,38 @@ BOOST_AUTO_TEST_CASE(DigestExclude) BOOST_AUTO_TEST_SUITE_END() // Find +BOOST_FIXTURE_TEST_CASE(Erase, FindFixture) +{ + insert(1, "/A/B/1"); + insert(2, "/A/B/2"); + insert(3, "/A/C/3"); + insert(4, "/A/C/4"); + insert(5, "/D/5"); + insert(6, "/E/6"); + BOOST_CHECK_EQUAL(m_cs.size(), 6); + + BOOST_CHECK_EQUAL(erase("/A", 3), 3); + BOOST_CHECK_EQUAL(m_cs.size(), 3); + int nDataUnderA = 0; + startInterest("/A/B/1"); + find([&] (uint32_t found) { nDataUnderA += static_cast(found > 0); }); + startInterest("/A/B/2"); + find([&] (uint32_t found) { nDataUnderA += static_cast(found > 0); }); + startInterest("/A/C/3"); + find([&] (uint32_t found) { nDataUnderA += static_cast(found > 0); }); + startInterest("/A/C/4"); + find([&] (uint32_t found) { nDataUnderA += static_cast(found > 0); }); + BOOST_CHECK_EQUAL(nDataUnderA, 1); + + BOOST_CHECK_EQUAL(erase("/D", 2), 1); + BOOST_CHECK_EQUAL(m_cs.size(), 2); + startInterest("/D/5"); + CHECK_CS_FIND(0); + + BOOST_CHECK_EQUAL(erase("/F", 2), 0); + BOOST_CHECK_EQUAL(m_cs.size(), 2); +} + // When the capacity limit is set to zero, Data cannot be inserted; // this test case covers this situation. // The behavior of non-zero capacity limit depends on the eviction policy,