Commit 3f3708fd4e81449d0e0005801274018afe2a068d
1 parent
f67238c5
Make QoS limits configurable
Showing
9 changed files
with
72 additions
and
6 deletions
configfileparser.cpp
| ... | ... | @@ -110,6 +110,8 @@ ConfigFileParser::ConfigFileParser(const std::string &path) : |
| 110 | 110 | validKeys.insert("expire_sessions_after_seconds"); |
| 111 | 111 | validKeys.insert("thread_count"); |
| 112 | 112 | validKeys.insert("storage_dir"); |
| 113 | + validKeys.insert("max_qos_msg_pending_per_client"); | |
| 114 | + validKeys.insert("max_qos_bytes_pending_per_client"); | |
| 113 | 115 | |
| 114 | 116 | validListenKeys.insert("port"); |
| 115 | 117 | validListenKeys.insert("protocol"); |
| ... | ... | @@ -439,6 +441,26 @@ void ConfigFileParser::loadFile(bool test) |
| 439 | 441 | } |
| 440 | 442 | tmpSettings->threadCount = newVal; |
| 441 | 443 | } |
| 444 | + | |
| 445 | + if (key == "max_qos_msg_pending_per_client") | |
| 446 | + { | |
| 447 | + int newVal = std::stoi(value); | |
| 448 | + if (newVal < 32 || newVal > 65530) | |
| 449 | + { | |
| 450 | + throw ConfigFileException(formatString("max_qos_msg_pending_per_client value '%d' is invalid. Valid values between 32 and 65530.", newVal)); | |
| 451 | + } | |
| 452 | + tmpSettings->maxQosMsgPendingPerClient = newVal; | |
| 453 | + } | |
| 454 | + | |
| 455 | + if (key == "max_qos_bytes_pending_per_client") | |
| 456 | + { | |
| 457 | + int newVal = std::stoi(value); | |
| 458 | + if (newVal < 4096) | |
| 459 | + { | |
| 460 | + throw ConfigFileException(formatString("max_qos_bytes_pending_per_client value '%d' is invalid. Valid values are 4096 or higher.", newVal)); | |
| 461 | + } | |
| 462 | + tmpSettings->maxQosBytesPendingPerClient = newVal; | |
| 463 | + } | |
| 442 | 464 | } |
| 443 | 465 | } |
| 444 | 466 | catch (std::invalid_argument &ex) // catch for the stoi() | ... | ... |
mainapp.cpp
| ... | ... | @@ -644,6 +644,8 @@ void MainApp::loadConfig() |
| 644 | 644 | confFileParser->loadFile(true); |
| 645 | 645 | confFileParser->loadFile(false); |
| 646 | 646 | settings = confFileParser->moveSettings(); |
| 647 | + settingsLocalCopy = *settings.get(); | |
| 648 | + ThreadAuth::assignSettings(&settingsLocalCopy); | |
| 647 | 649 | |
| 648 | 650 | if (settings->listeners.empty()) |
| 649 | 651 | { | ... | ... |
mainapp.h
| ... | ... | @@ -61,7 +61,11 @@ class MainApp |
| 61 | 61 | int taskEventFd = -1; |
| 62 | 62 | std::mutex eventMutex; |
| 63 | 63 | Timer timer; |
| 64 | + | |
| 65 | + // We need to keep a settings copy as well as a shared pointer, depending on threads, queueing of config reloads, etc. | |
| 64 | 66 | std::shared_ptr<Settings> settings; |
| 67 | + Settings settingsLocalCopy; | |
| 68 | + | |
| 65 | 69 | std::list<std::shared_ptr<Listener>> listeners; |
| 66 | 70 | std::mutex quitMutex; |
| 67 | 71 | std::string fuzzFilePath; | ... | ... |
session.cpp
| ... | ... | @@ -23,7 +23,9 @@ License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>. |
| 23 | 23 | |
| 24 | 24 | std::chrono::time_point<std::chrono::steady_clock> appStartTime = std::chrono::steady_clock::now(); |
| 25 | 25 | |
| 26 | -Session::Session() | |
| 26 | +Session::Session() : | |
| 27 | + maxQosMsgPending(ThreadAuth::getSettings()->maxQosMsgPendingPerClient), | |
| 28 | + maxQosBytesPending(ThreadAuth::getSettings()->maxQosBytesPendingPerClient) | |
| 27 | 29 | { |
| 28 | 30 | |
| 29 | 31 | } |
| ... | ... | @@ -181,7 +183,7 @@ void Session::writePacket(MqttPacket &packet, char max_qos, std::shared_ptr<Mqtt |
| 181 | 183 | std::unique_lock<std::mutex> locker(qosQueueMutex); |
| 182 | 184 | |
| 183 | 185 | const size_t totalQosPacketsInTransit = qosPacketQueue.size() + incomingQoS2MessageIds.size() + outgoingQoS2MessageIds.size(); |
| 184 | - if (totalQosPacketsInTransit >= MAX_QOS_MSG_PENDING_PER_CLIENT || (qosPacketQueue.getByteSize() >= MAX_QOS_BYTES_PENDING_PER_CLIENT && qosPacketQueue.size() > 0)) | |
| 186 | + if (totalQosPacketsInTransit >= maxQosMsgPending || (qosPacketQueue.getByteSize() >= maxQosBytesPending && qosPacketQueue.size() > 0)) | |
| 185 | 187 | { |
| 186 | 188 | if (QoSLogPrintedAtId != nextPacketId) |
| 187 | 189 | { | ... | ... |
session.h
| ... | ... | @@ -28,10 +28,6 @@ License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>. |
| 28 | 28 | #include "sessionsandsubscriptionsdb.h" |
| 29 | 29 | #include "qospacketqueue.h" |
| 30 | 30 | |
| 31 | -// TODO make settings. But, num of packets can't exceed 65536, because the counter is 16 bit. | |
| 32 | -#define MAX_QOS_MSG_PENDING_PER_CLIENT 32 | |
| 33 | -#define MAX_QOS_BYTES_PENDING_PER_CLIENT 4096 | |
| 34 | - | |
| 35 | 31 | class Session |
| 36 | 32 | { |
| 37 | 33 | #ifdef TESTING |
| ... | ... | @@ -52,6 +48,9 @@ class Session |
| 52 | 48 | uint16_t QoSLogPrintedAtId = 0; |
| 53 | 49 | std::chrono::time_point<std::chrono::steady_clock> lastTouched = std::chrono::steady_clock::now(); |
| 54 | 50 | Logger *logger = Logger::getInstance(); |
| 51 | + const size_t maxQosMsgPending = 0; | |
| 52 | + const size_t maxQosBytesPending = 0; | |
| 53 | + | |
| 55 | 54 | int64_t getSessionRelativeAgeInMs() const; |
| 56 | 55 | void setSessionTouch(int64_t ageInMs); |
| 57 | 56 | bool requiresPacketRetransmission() const; | ... | ... |
settings.h
| ... | ... | @@ -56,6 +56,8 @@ public: |
| 56 | 56 | int authPluginTimerPeriod = 60; |
| 57 | 57 | std::string storageDir; |
| 58 | 58 | int threadCount = 0; |
| 59 | + int maxQosMsgPendingPerClient = 512; | |
| 60 | + int maxQosBytesPendingPerClient = 65536; | |
| 59 | 61 | std::list<std::shared_ptr<Listener>> listeners; // Default one is created later, when none are defined. |
| 60 | 62 | |
| 61 | 63 | AuthOptCompatWrap &getAuthOptsCompat(); | ... | ... |
threadauth.cpp
| 1 | 1 | #include "threadauth.h" |
| 2 | 2 | |
| 3 | 3 | thread_local Authentication *ThreadAuth::auth = nullptr; |
| 4 | +thread_local ThreadData *ThreadAuth::threadData = nullptr; | |
| 5 | +thread_local Settings *ThreadAuth::settings = nullptr; | |
| 4 | 6 | |
| 5 | 7 | void ThreadAuth::assign(Authentication *auth) |
| 6 | 8 | { |
| ... | ... | @@ -11,3 +13,23 @@ Authentication *ThreadAuth::getAuth() |
| 11 | 13 | { |
| 12 | 14 | return auth; |
| 13 | 15 | } |
| 16 | + | |
| 17 | +void ThreadAuth::assignThreadData(ThreadData *threadData) | |
| 18 | +{ | |
| 19 | + ThreadAuth::threadData = threadData; | |
| 20 | +} | |
| 21 | + | |
| 22 | +ThreadData *ThreadAuth::getThreadData() | |
| 23 | +{ | |
| 24 | + return threadData; | |
| 25 | +} | |
| 26 | + | |
| 27 | +void ThreadAuth::assignSettings(Settings *settings) | |
| 28 | +{ | |
| 29 | + ThreadAuth::settings = settings; | |
| 30 | +} | |
| 31 | + | |
| 32 | +Settings *ThreadAuth::getSettings() | |
| 33 | +{ | |
| 34 | + return settings; | |
| 35 | +} | ... | ... |
threadauth.h
| 1 | 1 | #ifndef THREADAUTH_H |
| 2 | 2 | #define THREADAUTH_H |
| 3 | 3 | |
| 4 | +#include "forward_declarations.h" | |
| 5 | + | |
| 4 | 6 | class Authentication; |
| 5 | 7 | |
| 8 | +// TODO: rename, this is no longer just auth, but thread local globals. | |
| 6 | 9 | class ThreadAuth |
| 7 | 10 | { |
| 8 | 11 | static thread_local Authentication *auth; |
| 12 | + static thread_local ThreadData *threadData; | |
| 13 | + static thread_local Settings *settings; | |
| 9 | 14 | public: |
| 10 | 15 | static void assign(Authentication *auth); |
| 11 | 16 | static Authentication *getAuth(); |
| 17 | + | |
| 18 | + static void assignThreadData(ThreadData *threadData); | |
| 19 | + static ThreadData *getThreadData(); | |
| 20 | + | |
| 21 | + static void assignSettings(Settings *settings); | |
| 22 | + static Settings *getSettings(); | |
| 12 | 23 | }; |
| 13 | 24 | |
| 14 | 25 | #endif // THREADAUTH_H | ... | ... |
threadloop.cpp
| ... | ... | @@ -21,6 +21,8 @@ void do_thread_work(ThreadData *threadData) |
| 21 | 21 | { |
| 22 | 22 | int epoll_fd = threadData->epollfd; |
| 23 | 23 | ThreadAuth::assign(&threadData->authentication); |
| 24 | + ThreadAuth::assignThreadData(threadData); | |
| 25 | + ThreadAuth::assignSettings(&threadData->settingsLocalCopy); | |
| 24 | 26 | |
| 25 | 27 | struct epoll_event events[MAX_EVENTS]; |
| 26 | 28 | memset(&events, 0, sizeof (struct epoll_event)*MAX_EVENTS); | ... | ... |