Commit 20b1d0a002b6ffa1d113020dc66b9ab2309a52c8
Committed by
Wiebe Cazemier
1 parent
c5f8e527
Use ordered map for session removals
This is way faster.
Showing
2 changed files
with
20 additions
and
55 deletions
subscriptionstore.cpp
| ... | ... | @@ -666,19 +666,23 @@ void SubscriptionStore::removeExpiredSessionsClients() |
| 666 | 666 | auto it = queuedSessionRemovals.begin(); |
| 667 | 667 | while (it != queuedSessionRemovals.end()) |
| 668 | 668 | { |
| 669 | - QueuedSessionRemoval &qsr = *it; | |
| 670 | - std::shared_ptr<Session> session = (*it).getSession(); | |
| 671 | - if (session) | |
| 669 | + const std::chrono::time_point<std::chrono::steady_clock> &removeAt = it->first; | |
| 670 | + | |
| 671 | + if (removeAt > now) | |
| 672 | 672 | { |
| 673 | - if (qsr.getExpiresAt() > now) | |
| 674 | - { | |
| 675 | - break; | |
| 676 | - } | |
| 673 | + break; | |
| 674 | + } | |
| 675 | + | |
| 676 | + std::vector<std::weak_ptr<Session>> &sessionsFromSlot = it->second; | |
| 677 | + | |
| 678 | + for (std::weak_ptr<Session> ses : sessionsFromSlot) | |
| 679 | + { | |
| 680 | + std::shared_ptr<Session> lockedSession = ses.lock(); | |
| 677 | 681 | |
| 678 | 682 | // A session could have been picked up again, so we have to verify its expiration status. |
| 679 | - if (!session->hasActiveClient()) | |
| 683 | + if (lockedSession && !lockedSession->hasActiveClient()) | |
| 680 | 684 | { |
| 681 | - removeSession(session); | |
| 685 | + removeSession(lockedSession); | |
| 682 | 686 | removedSessions++; |
| 683 | 687 | } |
| 684 | 688 | } |
| ... | ... | @@ -690,7 +694,7 @@ void SubscriptionStore::removeExpiredSessionsClients() |
| 690 | 694 | queuedRemovalsLeft = queuedSessionRemovals.size(); |
| 691 | 695 | } |
| 692 | 696 | |
| 693 | - logger->logf(LOG_DEBUG, "Processed %d queued session removals, resuling in %d deleted expired sessions. %d queued removals in the future.", | |
| 697 | + logger->logf(LOG_DEBUG, "Processed %d queued session removals, resulting in %d deleted expired sessions. %d queued removals in the future.", | |
| 694 | 698 | processedRemovals, removedSessions, queuedRemovalsLeft); |
| 695 | 699 | |
| 696 | 700 | if (lastTreeCleanup + std::chrono::minutes(30) < now) |
| ... | ... | @@ -705,7 +709,7 @@ void SubscriptionStore::removeExpiredSessionsClients() |
| 705 | 709 | } |
| 706 | 710 | |
| 707 | 711 | /** |
| 708 | - * @brief SubscriptionStore::queueSessionRemoval places session efficiently in a sorted list that is periodically dequeued. | |
| 712 | + * @brief SubscriptionStore::queueSessionRemoval places session efficiently in a sorted map that is periodically dequeued. | |
| 709 | 713 | * @param session |
| 710 | 714 | */ |
| 711 | 715 | void SubscriptionStore::queueSessionRemoval(const std::shared_ptr<Session> &session) |
| ... | ... | @@ -713,18 +717,11 @@ void SubscriptionStore::queueSessionRemoval(const std::shared_ptr<Session> &sess |
| 713 | 717 | if (!session) |
| 714 | 718 | return; |
| 715 | 719 | |
| 716 | - QueuedSessionRemoval qsr(session); | |
| 717 | - | |
| 718 | - auto comp = [](const QueuedSessionRemoval &a, const QueuedSessionRemoval &b) | |
| 719 | - { | |
| 720 | - return a.getExpiresAt() < b.getExpiresAt(); | |
| 721 | - }; | |
| 722 | - | |
| 720 | + std::chrono::time_point<std::chrono::steady_clock> removeAt = std::chrono::steady_clock::now() + std::chrono::seconds(session->getSessionExpiryInterval()); | |
| 723 | 721 | session->setQueuedRemovalAt(); |
| 724 | 722 | |
| 725 | 723 | std::lock_guard<std::mutex>(this->queuedSessionRemovalsMutex); |
| 726 | - auto pos = std::upper_bound(this->queuedSessionRemovals.begin(), this->queuedSessionRemovals.end(), qsr, comp); | |
| 727 | - this->queuedSessionRemovals.insert(pos, qsr); | |
| 724 | + queuedSessionRemovals[removeAt].push_back(session); | |
| 728 | 725 | } |
| 729 | 726 | |
| 730 | 727 | int64_t SubscriptionStore::getRetainedMessageCount() const |
| ... | ... | @@ -1026,23 +1023,6 @@ RetainedMessageNode *RetainedMessageNode::getChildren(const std::string &subtopi |
| 1026 | 1023 | return nullptr; |
| 1027 | 1024 | } |
| 1028 | 1025 | |
| 1029 | -QueuedSessionRemoval::QueuedSessionRemoval(const std::shared_ptr<Session> &session) : | |
| 1030 | - session(session), | |
| 1031 | - expiresAt(std::chrono::steady_clock::now() + std::chrono::seconds(session->getSessionExpiryInterval())) | |
| 1032 | -{ | |
| 1033 | - | |
| 1034 | -} | |
| 1035 | - | |
| 1036 | -std::chrono::time_point<std::chrono::steady_clock> QueuedSessionRemoval::getExpiresAt() const | |
| 1037 | -{ | |
| 1038 | - return this->expiresAt; | |
| 1039 | -} | |
| 1040 | - | |
| 1041 | -std::shared_ptr<Session> QueuedSessionRemoval::getSession() const | |
| 1042 | -{ | |
| 1043 | - return session.lock(); | |
| 1044 | -} | |
| 1045 | - | |
| 1046 | 1026 | QueuedWill::QueuedWill(const std::shared_ptr<WillPublish> &will, const std::shared_ptr<Session> &session) : |
| 1047 | 1027 | will(will), |
| 1048 | 1028 | session(session), | ... | ... |
subscriptionstore.h
| ... | ... | @@ -22,6 +22,8 @@ License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>. |
| 22 | 22 | #include <forward_list> |
| 23 | 23 | #include <list> |
| 24 | 24 | #include <mutex> |
| 25 | +#include <map> | |
| 26 | +#include <vector> | |
| 25 | 27 | #include <pthread.h> |
| 26 | 28 | |
| 27 | 29 | #include "forward_declarations.h" |
| ... | ... | @@ -84,23 +86,6 @@ class RetainedMessageNode |
| 84 | 86 | RetainedMessageNode *getChildren(const std::string &subtopic) const; |
| 85 | 87 | }; |
| 86 | 88 | |
| 87 | -/** | |
| 88 | - * @brief A QueuedSessionRemoval is a sort of delayed request for removal. They are kept in a sorted list for fast insertion, | |
| 89 | - * and fast dequeueing of expired entries from the start. | |
| 90 | - * | |
| 91 | - * You can have multiple of these in the pending list. If a client has picked up the session again, the removal is not executed. | |
| 92 | - */ | |
| 93 | -class QueuedSessionRemoval | |
| 94 | -{ | |
| 95 | - std::weak_ptr<Session> session; | |
| 96 | - std::chrono::time_point<std::chrono::steady_clock> expiresAt; | |
| 97 | - | |
| 98 | -public: | |
| 99 | - QueuedSessionRemoval(const std::shared_ptr<Session> &session); | |
| 100 | - std::chrono::time_point<std::chrono::steady_clock> getExpiresAt() const; | |
| 101 | - std::shared_ptr<Session> getSession() const; | |
| 102 | -}; | |
| 103 | - | |
| 104 | 89 | class QueuedWill |
| 105 | 90 | { |
| 106 | 91 | std::weak_ptr<WillPublish> will; |
| ... | ... | @@ -128,7 +113,7 @@ class SubscriptionStore |
| 128 | 113 | const std::unordered_map<std::string, std::shared_ptr<Session>> &sessionsByIdConst; |
| 129 | 114 | |
| 130 | 115 | std::mutex queuedSessionRemovalsMutex; |
| 131 | - std::list<QueuedSessionRemoval> queuedSessionRemovals; | |
| 116 | + std::map<std::chrono::time_point<std::chrono::steady_clock>, std::vector<std::weak_ptr<Session>>> queuedSessionRemovals; | |
| 132 | 117 | |
| 133 | 118 | pthread_rwlock_t retainedMessagesRwlock = PTHREAD_RWLOCK_INITIALIZER; |
| 134 | 119 | RetainedMessageNode retainedMessagesRoot; | ... | ... |