Commit 3f3708fd4e81449d0e0005801274018afe2a068d

Authored by Wiebe Cazemier
1 parent f67238c5

Make QoS limits configurable

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 &lt;https://www.gnu.org/licenses/&gt;.
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 &amp;packet, char max_qos, std::shared_ptr&lt;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 &lt;https://www.gnu.org/licenses/&gt;.
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);
... ...