Skip to content

Commit 49b4ae8

Browse files
committed
Add support for reloading bridges without restart
1 parent d08f376 commit 49b4ae8

9 files changed

+230
-46
lines changed

bridgeconfig.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ bool BridgeTopicPath::isValidQos() const
1313
return qos < 3;
1414
}
1515

16+
bool BridgeTopicPath::operator==(const BridgeTopicPath &other) const
17+
{
18+
return this->topic == other.topic && this->qos == other.qos;
19+
}
20+
1621

1722
BridgeState::BridgeState(const BridgeConfig &config) :
1823
c(config)
@@ -177,4 +182,23 @@ void BridgeConfig::isValid()
177182
setClientId();
178183
}
179184

185+
bool BridgeConfig::operator ==(const BridgeConfig &other) const
186+
{
187+
return this->address == other.address && this->port == other.port && this->inet_protocol == other.inet_protocol && this->tlsMode == other.tlsMode
188+
&& this->caFile == other.caFile && this->caDir == other.caDir && this->protocolVersion == other.protocolVersion
189+
&& this->bridgeProtocolBit == other.bridgeProtocolBit && this->keepalive == other.keepalive && this->clientidPrefix == other.clientidPrefix
190+
&& this->publishes == other.publishes && this->subscribes == other.subscribes && this->local_username == other.local_username
191+
&& this->remote_username == other.remote_username && this->remote_password == other.remote_password && this->remoteCleanStart == other.remoteCleanStart
192+
&& this->localCleanStart == other.localCleanStart && this->remoteSessionExpiryInterval == other.remoteSessionExpiryInterval
193+
&& this->localSessionExpiryInterval == other.localSessionExpiryInterval && this->remoteRetainAvailable == other.remoteRetainAvailable
194+
&& this->useSavedClientId == other.useSavedClientId && this->maxOutgoingTopicAliases == other.maxOutgoingTopicAliases
195+
&& this->maxIncomingTopicAliases == other.maxIncomingTopicAliases;
196+
}
197+
198+
bool BridgeConfig::operator !=(const BridgeConfig &other) const
199+
{
200+
bool r = *this == other;
201+
return !r;
202+
}
203+
180204

bridgeconfig.h

+6
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ struct BridgeTopicPath
2323
uint8_t qos = 0;
2424

2525
bool isValidQos() const;
26+
bool operator==(const BridgeTopicPath &other) const;
2627
};
2728

2829
class BridgeConfig
@@ -55,10 +56,15 @@ class BridgeConfig
5556
bool remoteRetainAvailable = true;
5657
std::vector<BridgeTopicPath> subscribes;
5758
std::vector<BridgeTopicPath> publishes;
59+
std::weak_ptr<ThreadData> owner;
60+
bool queueForDelete = false;
5861

5962
void setClientId(const std::string &prefix, const std::string &id);
6063
const std::string &getClientid() const;
6164
void isValid();
65+
66+
bool operator ==(const BridgeConfig &other) const;
67+
bool operator !=(const BridgeConfig &other) const;
6268
};
6369

6470
class BridgeState

bridgeinfodb.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ BridgeInfoForSerializing::BridgeInfoForSerializing(const std::shared_ptr<BridgeC
77

88
}
99

10-
std::list<BridgeInfoForSerializing> BridgeInfoForSerializing::getBridgeInfosForSerializing(const std::list<std::shared_ptr<BridgeConfig>> input)
10+
std::list<BridgeInfoForSerializing> BridgeInfoForSerializing::getBridgeInfosForSerializing(const std::unordered_map<std::string, std::shared_ptr<BridgeConfig>> &input)
1111
{
1212
std::list<BridgeInfoForSerializing> result;
1313

14-
for (const std::shared_ptr<BridgeConfig> &bridge : input)
14+
for (auto &pair : input)
1515
{
16+
const std::shared_ptr<BridgeConfig> &bridge = pair.second;
17+
1618
if (!bridge)
1719
continue;
1820

bridgeinfodb.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ struct BridgeInfoForSerializing
1717
BridgeInfoForSerializing() = default;
1818
BridgeInfoForSerializing(const std::shared_ptr<BridgeConfig> bridge);
1919

20-
static std::list<BridgeInfoForSerializing> getBridgeInfosForSerializing(const std::list<std::shared_ptr<BridgeConfig>> input);
20+
static std::list<BridgeInfoForSerializing> getBridgeInfosForSerializing(const std::unordered_map<std::string, std::shared_ptr<BridgeConfig>> &input);
2121
};
2222

2323
class BridgeInfoDb : private PersistenceFile

dnsresolver.h

+3
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ class DnsResolver
4545
void freeStuff();
4646
public:
4747
DnsResolver();
48+
DnsResolver(const DnsResolver &other) = delete;
49+
DnsResolver(DnsResolver &&other) = delete;
50+
DnsResolver &operator=(const DnsResolver &other) = delete;
4851
~DnsResolver();
4952

5053
void query(const std::string &text, ListenerProtocol protocol, std::chrono::milliseconds timeout);

mainapp.cpp

+104-33
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ void MainApp::queuePublishStatsOnDollarTopic()
276276
*/
277277
void MainApp::saveStateInThread()
278278
{
279-
std::list<BridgeInfoForSerializing> bridgeInfos = BridgeInfoForSerializing::getBridgeInfosForSerializing(this->bridges);
279+
std::list<BridgeInfoForSerializing> bridgeInfos = BridgeInfoForSerializing::getBridgeInfosForSerializing(this->bridgeConfigs);
280280

281281
auto f = std::bind(&MainApp::saveState, this->settings, bridgeInfos, true);
282282
this->bgWorker.addTask(f);
@@ -334,12 +334,54 @@ void MainApp::queueRetainedMessageExpiration()
334334
}
335335
}
336336

337-
void MainApp::createBridge(std::shared_ptr<ThreadData> &thread, const std::shared_ptr<BridgeConfig> &bridgeConfig)
337+
void MainApp::sendBridgesToThreads()
338338
{
339-
std::shared_ptr<BridgeState> bridgeState = std::make_shared<BridgeState>(*bridgeConfig);
339+
if (threads.empty())
340+
return;
341+
342+
int i = 0;
343+
auto bridge_pos = this->bridgeConfigs.begin();
344+
while (bridge_pos != this->bridgeConfigs.end())
345+
{
346+
auto cur = bridge_pos;
347+
bridge_pos++;
348+
349+
std::shared_ptr<BridgeConfig> bridge = cur->second;
350+
351+
if (!bridge)
352+
continue;
353+
354+
std::shared_ptr<ThreadData> owner = bridge->owner.lock();
340355

341-
bridgeState->threadData = thread;
342-
thread->giveBridge(bridgeState);
356+
if (!owner)
357+
{
358+
owner = threads.at(i++ % threads.size());
359+
bridge->owner = owner;
360+
}
361+
362+
if (bridge->queueForDelete)
363+
{
364+
owner->removeBridgeQueued(bridge, "Bridge disappeared from config");
365+
this->bridgeConfigs.erase(cur);
366+
}
367+
else
368+
{
369+
std::shared_ptr<BridgeState> bridgeState = std::make_shared<BridgeState>(*bridge);
370+
bridgeState->threadData = owner;
371+
owner->giveBridge(bridgeState);
372+
}
373+
}
374+
}
375+
376+
void MainApp::queueSendBridgesToThreads()
377+
{
378+
{
379+
std::lock_guard<std::mutex> locker(eventMutex);
380+
auto f = std::bind(&MainApp::sendBridgesToThreads, this);
381+
taskQueue.push_back(f);
382+
}
383+
384+
wakeUpThread();
343385
}
344386

345387
void MainApp::queueBridgeReconnectAllThreads(bool alsoQueueNexts)
@@ -409,12 +451,13 @@ void MainApp::saveBridgeInfo(const std::string &filePath, const std::list<Bridge
409451
bridgeInfoDb.saveInfo(bridgeInfos);
410452
}
411453

412-
void MainApp::loadBridgeInfo()
454+
std::list<std::shared_ptr<BridgeConfig>> MainApp::loadBridgeInfo(Settings &settings)
413455
{
414-
this->bridges = settings.stealBridges();
456+
Logger *logger = Logger::getInstance();
457+
std::list<std::shared_ptr<BridgeConfig>> bridges = settings.stealBridges();
415458

416459
if (settings.storageDir.empty())
417-
return;
460+
return bridges;
418461

419462
const std::string filePath = settings.getBridgeNamesDBFile();
420463

@@ -428,7 +471,7 @@ void MainApp::loadBridgeInfo()
428471

429472
for(const BridgeInfoForSerializing &info : bridgeInfos)
430473
{
431-
for(std::shared_ptr<BridgeConfig> &bridgeConfig : this->bridges)
474+
for(std::shared_ptr<BridgeConfig> &bridgeConfig : bridges)
432475
{
433476
if (!bridgeConfig->useSavedClientId)
434477
continue;
@@ -447,7 +490,7 @@ void MainApp::loadBridgeInfo()
447490
logger->logf(LOG_WARNING, "File '%s' is not there (yet)", filePath.c_str());
448491
}
449492

450-
493+
return bridges;
451494
}
452495

453496
void MainApp::initMainApp(int argc, char *argv[])
@@ -671,17 +714,10 @@ void MainApp::start()
671714

672715
timer.start();
673716

674-
uint next_thread_index = 0;
717+
sendBridgesToThreads();
718+
queueBridgeReconnectAllThreads(true);
675719

676-
{
677-
for(std::shared_ptr<BridgeConfig> &bridge : this->bridges)
678-
{
679-
std::shared_ptr<ThreadData> &thread = threads[next_thread_index++ % threads.size()];
680-
createBridge(thread, bridge);
681-
}
682-
683-
queueBridgeReconnectAllThreads(true);
684-
}
720+
uint next_thread_index = 0;
685721

686722
this->bgWorker.start();
687723

@@ -858,7 +894,7 @@ void MainApp::start()
858894

859895
this->bgWorker.waitForStop();
860896

861-
std::list<BridgeInfoForSerializing> bridgeInfos = BridgeInfoForSerializing::getBridgeInfosForSerializing(this->bridges);
897+
std::list<BridgeInfoForSerializing> bridgeInfos = BridgeInfoForSerializing::getBridgeInfosForSerializing(this->bridgeConfigs);
862898
saveState(this->settings, bridgeInfos, false);
863899
}
864900

@@ -966,20 +1002,55 @@ void MainApp::loadConfig(bool reload)
9661002
}
9671003
}
9681004

969-
// We are not reloading bridges, because it's hard to figure out what to do. This does mean we need to
970-
// validate the config of existing ones, because they may have their certificate paths changed.
971-
if (this->bridges.empty())
9721005
{
973-
if (!reload)
974-
loadBridgeInfo();
975-
}
976-
else
977-
{
978-
// Note that this checks the certificate paths of how the briges came from the config file, not the actual bridges. But, at least
979-
// for now, they must be the same, because bridges aren't changed after they are created.
980-
for (auto &bridge : this->bridges)
1006+
for (auto &pair : bridgeConfigs)
1007+
{
1008+
pair.second->queueForDelete = true;
1009+
}
1010+
1011+
std::list<std::shared_ptr<BridgeConfig>> bridges = loadBridgeInfo(this->settings);
1012+
1013+
for (std::shared_ptr<BridgeConfig> &bridge : bridges)
1014+
{
1015+
if (!bridge)
1016+
continue;
1017+
1018+
auto pos = this->bridgeConfigs.find(bridge->clientidPrefix);
1019+
if (pos != this->bridgeConfigs.end())
1020+
{
1021+
logger->log(LOG_NOTICE) << "Assing new config to bridge '" << bridge->clientidPrefix << "' and reconnect if needed.";
1022+
1023+
std::shared_ptr<BridgeConfig> &cur = pos->second;
1024+
1025+
if (!cur)
1026+
continue;
1027+
1028+
std::shared_ptr<ThreadData> owner = cur->owner.lock();
1029+
std::string clientid = cur->getClientid();
1030+
cur = bridge;
1031+
cur->owner = owner;
1032+
cur->setClientId(cur->clientidPrefix, clientid);
1033+
}
1034+
else
1035+
{
1036+
logger->log(LOG_NOTICE) << "Adding bridge '" << bridge->clientidPrefix << "'.";
1037+
this->bridgeConfigs[bridge->clientidPrefix] = bridge;
1038+
}
1039+
}
1040+
1041+
for (auto &pair : bridgeConfigs)
1042+
{
1043+
if (pair.second->queueForDelete)
1044+
{
1045+
logger->log(LOG_NOTICE) << "Queueing bridge '" << pair.first << "' for removal, because it disappeared from config.";
1046+
}
1047+
}
1048+
1049+
// On first load, the start() function will take care of it.
1050+
if (reload)
9811051
{
982-
bridge->isValid();
1052+
sendBridgesToThreads();
1053+
queueBridgeReconnectAllThreads(false);
9831054
}
9841055
}
9851056

mainapp.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class MainApp
6262
std::list<std::shared_ptr<Listener>> listeners;
6363
std::unordered_map<int, ScopedSocket> activeListenSockets;
6464

65-
std::list<std::shared_ptr<BridgeConfig>> bridges;
65+
std::unordered_map<std::string, std::shared_ptr<BridgeConfig>> bridgeConfigs;
6666
std::mutex quitMutex;
6767
std::string fuzzFilePath;
6868
OneInstanceLock oneInstanceLock;
@@ -87,14 +87,15 @@ class MainApp
8787
void queuePublishStatsOnDollarTopic();
8888
static void saveState(const Settings &settings, const std::list<BridgeInfoForSerializing> &bridgeInfos, bool sleep_after_limit);
8989
static void saveBridgeInfo(const std::string &filePath, const std::list<BridgeInfoForSerializing> &bridgeInfos);
90-
void loadBridgeInfo();
90+
static std::list<std::shared_ptr<BridgeConfig>> loadBridgeInfo(Settings &settings);
9191
void saveStateInThread();
9292
void queueSaveStateInThread();
9393
void queueSendQueuedWills();
9494
void waitForWillsQueued();
9595
void waitForDisconnectsInitiated();
9696
void queueRetainedMessageExpiration();
97-
void createBridge(std::shared_ptr<ThreadData> &thread, const std::shared_ptr<BridgeConfig> &bridgeConfig);
97+
void sendBridgesToThreads();
98+
void queueSendBridgesToThreads();
9899
void queueBridgeReconnectAllThreads(bool alsoQueueNexts);
99100

100101
MainApp(const std::string &configFilePath);

0 commit comments

Comments
 (0)