From 262e13845cd2c41abb9030b694a193ae3e30e273 Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Sun, 28 Nov 2021 20:40:52 +0400 Subject: [PATCH] Enter Library::removeBooksNotUpdatedSince() --- include/library.h | 33 ++++++++++++++++++++++++++++++++- src/library.cpp | 32 +++++++++++++++++++++++++++++++- test/library.cpp | 31 +++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 2 deletions(-) diff --git a/include/library.h b/include/library.h index 3ef7b5248..c5054dcc7 100644 --- a/include/library.h +++ b/include/library.h @@ -147,8 +147,20 @@ private: // functions */ class LibraryBase { +protected: // types + typedef uint64_t LibraryRevision; + + struct Entry : Book + { + LibraryRevision lastUpdatedRevision = 0; + + // May also keep the Archive and Reader pointers here and get + // rid of the m_readers and m_archives data members in Library + }; + protected: // data - std::map m_books; + LibraryRevision m_revision; + std::map m_books; std::map> m_readers; std::map> m_archives; std::vector m_bookmarks; @@ -172,6 +184,7 @@ class Library : private LibraryBase mutable std::mutex m_mutex; public: + typedef LibraryRevision Revision; typedef std::vector BookIdCollection; typedef std::map AttributeCounts; @@ -368,6 +381,24 @@ class Library : private LibraryBase const std::vector& tags = {}, size_t maxSize = 0) const; + /** + * Return the current revision of the library. + * + * The revision of the library is updated (incremented by one) only by + * the addBook() operation. + * + * @return Current revision of the library. + */ + LibraryRevision getRevision() const; + + /** + * Remove books that have not been updated since the specified revision. + * + * @param rev the library revision to use + * @return Count of books that were removed by this operation. + */ + uint32_t removeBooksNotUpdatedSince(LibraryRevision rev); + friend class OPDSDumper; friend class libXMLDumper; diff --git a/src/library.cpp b/src/library.cpp index 3518e2b0c..79ccbf044 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -101,6 +101,7 @@ Library::~Library() bool Library::addBook(const Book& book) { std::lock_guard lock(m_mutex); + ++m_revision; /* Try to find it */ updateBookDB(book); try { @@ -111,9 +112,12 @@ bool Library::addBook(const Book& book) oldbook.update(book); // XXX: This may have no effect if oldbook is readonly // XXX: Then m_bookDB will become out-of-sync with // XXX: the real contents of the library. + oldbook.lastUpdatedRevision = m_revision; return false; } catch (std::out_of_range&) { - m_books[book.getId()] = book; + Entry& newEntry = m_books[book.getId()]; + static_cast(newEntry) = book; + newEntry.lastUpdatedRevision = m_revision; return true; } } @@ -151,6 +155,32 @@ bool Library::removeBookById(const std::string& id) return m_books.erase(id) == 1; } +Library::Revision Library::getRevision() const +{ + std::lock_guard lock(m_mutex); + return m_revision; +} + +uint32_t Library::removeBooksNotUpdatedSince(LibraryRevision libraryRevision) +{ + BookIdCollection booksToRemove; + { + std::lock_guard lock(m_mutex); + for ( const auto& entry : m_books) { + if ( entry.second.lastUpdatedRevision <= libraryRevision ) { + booksToRemove.push_back(entry.first); + } + } + } + + uint32_t countOfRemovedBooks = 0; + for ( const auto& id : booksToRemove ) { + if ( removeBookById(id) ) + ++countOfRemovedBooks; + } + return countOfRemovedBooks; +} + const Book& Library::getBookById(const std::string& id) const { // XXX: Doesn't make sense to lock this operation since it cannot diff --git a/test/library.cpp b/test/library.cpp index e06026318..a8d99e896 100644 --- a/test/library.cpp +++ b/test/library.cpp @@ -707,4 +707,35 @@ TEST_F(LibraryTest, removeBookByIdUpdatesTheSearchDB) EXPECT_THROW(lib.getBookById("raycharles"), std::out_of_range); }; +TEST_F(LibraryTest, removeBooksNotUpdatedSince) +{ + EXPECT_FILTER_RESULTS(kiwix::Filter(), + "An example ZIM archive", + "Encyclopédie de la Tunisie", + "Granblue Fantasy Wiki", + "Géographie par Wikipédia", + "Islam Stack Exchange", + "Mathématiques", + "Movies & TV Stack Exchange", + "Mythology & Folklore Stack Exchange", + "Ray Charles", + "TED talks - Business", + "Tania Louis", + "Wikiquote" + ); + + const uint64_t rev = lib.getRevision(); + for ( const auto& id : lib.filter(kiwix::Filter().query("exchange")) ) { + lib.addBook(lib.getBookByIdThreadSafe(id)); + } + + EXPECT_EQ(9u, lib.removeBooksNotUpdatedSince(rev)); + + EXPECT_FILTER_RESULTS(kiwix::Filter(), + "Islam Stack Exchange", + "Movies & TV Stack Exchange", + "Mythology & Folklore Stack Exchange", + ); +}; + };