diff --git a/src/common/lookups/PeerListLookup.cpp b/src/common/lookups/PeerListLookup.cpp index eac7e77e..60044ef0 100644 --- a/src/common/lookups/PeerListLookup.cpp +++ b/src/common/lookups/PeerListLookup.cpp @@ -23,6 +23,26 @@ using namespace lookups; // --------------------------------------------------------------------------- std::mutex PeerListLookup::m_mutex; +bool PeerListLookup::m_locked = false; + +// --------------------------------------------------------------------------- +// Macros +// --------------------------------------------------------------------------- + +// Lock the table. +#define __LOCK_TABLE() \ + std::lock_guard lock(m_mutex); \ + m_locked = true; + +// Unlock the table. +#define __UNLOCK_TABLE() m_locked = false; + +// Spinlock wait for table to be released. +#define __SPINLOCK() \ + if (m_locked) { \ + while (m_locked) \ + Thread::sleep(2U); \ + } // --------------------------------------------------------------------------- // Public Class Members @@ -40,8 +60,11 @@ PeerListLookup::PeerListLookup(const std::string& filename, Mode mode, uint32_t void PeerListLookup::clear() { - std::lock_guard lock(m_mutex); + __LOCK_TABLE(); + m_table.clear(); + + __UNLOCK_TABLE(); } /* Adds a new entry to the list. */ @@ -50,7 +73,8 @@ void PeerListLookup::addEntry(uint32_t id, const std::string& alias, const std:: { PeerId entry = PeerId(id, alias, password, peerLink, canRequestKeys, false); - std::lock_guard lock(m_mutex); + __LOCK_TABLE(); + try { PeerId _entry = m_table.at(id); // if either the alias or the enabled flag doesn't match, update the entry @@ -61,13 +85,16 @@ void PeerListLookup::addEntry(uint32_t id, const std::string& alias, const std:: } catch (...) { m_table[id] = entry; } + + __UNLOCK_TABLE(); } /* Removes an existing entry from the list. */ void PeerListLookup::eraseEntry(uint32_t id) { - std::lock_guard lock(m_mutex); + __LOCK_TABLE(); + try { PeerId entry = m_table.at(id); // this value will get discarded (void)entry; // but some variants of C++ mark the unordered_map<>::at as nodiscard @@ -75,6 +102,8 @@ void PeerListLookup::eraseEntry(uint32_t id) } catch (...) { /* stub */ } + + __UNLOCK_TABLE(); } /* Finds a table entry in this lookup table. */ @@ -83,7 +112,8 @@ PeerId PeerListLookup::find(uint32_t id) { PeerId entry; - std::lock_guard lock(m_mutex); + __SPINLOCK(); + try { entry = m_table.at(id); } catch (...) { @@ -111,7 +141,8 @@ bool PeerListLookup::getACL() const bool PeerListLookup::isPeerInList(uint32_t id) const { - std::lock_guard lock(m_mutex); + __SPINLOCK(); + if (m_table.find(id) != m_table.end()) { return true; } @@ -141,8 +172,11 @@ bool PeerListLookup::isPeerAllowed(uint32_t id) const void PeerListLookup::setMode(Mode mode) { - std::lock_guard lock(m_mutex); + __LOCK_TABLE(); + m_mode = mode; + + __UNLOCK_TABLE(); } /* Gets the current mode. */ @@ -158,11 +192,13 @@ std::vector PeerListLookup::tableAsList() const { std::vector ret = std::vector(); - std::lock_guard lock(m_mutex); + __LOCK_TABLE(); + for (auto entry : m_table) { ret.push_back(entry.second); } + __UNLOCK_TABLE(); return ret; } @@ -184,8 +220,9 @@ bool PeerListLookup::load() return false; } - m_table.clear(); - std::lock_guard lock(m_mutex); + clear(); + + __LOCK_TABLE(); // read lines from file std::string line; @@ -249,6 +286,7 @@ bool PeerListLookup::load() } file.close(); + __UNLOCK_TABLE(); size_t size = m_table.size(); if (size == 0U) @@ -331,4 +369,4 @@ bool PeerListLookup::save() LogInfoEx(LOG_HOST, "Saved %u entries to lookup table file %s", lines, m_filename.c_str()); return true; -} \ No newline at end of file +} diff --git a/src/common/lookups/PeerListLookup.h b/src/common/lookups/PeerListLookup.h index fb8af519..527102a1 100644 --- a/src/common/lookups/PeerListLookup.h +++ b/src/common/lookups/PeerListLookup.h @@ -263,7 +263,8 @@ namespace lookups private: Mode m_mode; - static std::mutex m_mutex; + static std::mutex m_mutex; //! Mutex used for hard locking. + static bool m_locked; //! Flag used for soft locking (prevents find lookups), should be used when atomic operations (add/erase/etc) are being used. }; } // namespace lookups diff --git a/src/common/lookups/RadioIdLookup.cpp b/src/common/lookups/RadioIdLookup.cpp index e823407b..b0c0f84c 100644 --- a/src/common/lookups/RadioIdLookup.cpp +++ b/src/common/lookups/RadioIdLookup.cpp @@ -5,7 +5,7 @@ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright (C) 2016 Jonathan Naylor, G4KLX - * Copyright (C) 2017-2022 Bryan Biedenkapp, N2PLL + * Copyright (C) 2017-2022,2025 Bryan Biedenkapp, N2PLL * Copyright (c) 2024 Patrick McDonnell, W3AXL * */ @@ -25,6 +25,26 @@ using namespace lookups; // --------------------------------------------------------------------------- std::mutex RadioIdLookup::m_mutex; +bool RadioIdLookup::m_locked = false; + +// --------------------------------------------------------------------------- +// Macros +// --------------------------------------------------------------------------- + +// Lock the table. +#define __LOCK_TABLE() \ + std::lock_guard lock(m_mutex); \ + m_locked = true; + +// Unlock the table. +#define __UNLOCK_TABLE() m_locked = false; + +// Spinlock wait for table to be released. +#define __SPINLOCK() \ + if (m_locked) { \ + while (m_locked) \ + Thread::sleep(2U); \ + } // --------------------------------------------------------------------------- // Public Class Members @@ -42,8 +62,11 @@ RadioIdLookup::RadioIdLookup(const std::string& filename, uint32_t reloadTime, b void RadioIdLookup::clear() { - std::lock_guard lock(m_mutex); + __LOCK_TABLE(); + m_table.clear(); + + __UNLOCK_TABLE(); } /* Toggles the specified radio ID enabled or disabled. */ @@ -64,7 +87,8 @@ void RadioIdLookup::addEntry(uint32_t id, bool enabled, const std::string& alias RadioId entry = RadioId(enabled, false, alias, ipAddress); - std::lock_guard lock(m_mutex); + __LOCK_TABLE(); + try { RadioId _entry = m_table.at(id); // if either the alias or the enabled flag doesn't match, update the entry @@ -79,20 +103,26 @@ void RadioIdLookup::addEntry(uint32_t id, bool enabled, const std::string& alias //LogDebug(LOG_HOST, "Adding new RID %d (%s) to ACL", id, alias.c_str()); m_table[id] = entry; } + + __UNLOCK_TABLE(); } /* Erases an existing entry from the lookup table by the specified unique ID. */ void RadioIdLookup::eraseEntry(uint32_t id) { - std::lock_guard lock(m_mutex); + __LOCK_TABLE(); + try { RadioId entry = m_table.at(id); // this value will get discarded (void)entry; // but some variants of C++ mark the unordered_map<>::at as nodiscard m_table.erase(id); - } catch (...) { + } + catch (...) { /* stub */ } + + __UNLOCK_TABLE(); } /* Finds a table entry in this lookup table. */ @@ -105,7 +135,8 @@ RadioId RadioIdLookup::find(uint32_t id) return RadioId(true, false); } - std::lock_guard lock(m_mutex); + __SPINLOCK(); + try { entry = m_table.at(id); } catch (...) { @@ -150,7 +181,7 @@ bool RadioIdLookup::load() // clear table clear(); - std::lock_guard lock(m_mutex); + __LOCK_TABLE(); // read lines from file std::string line; @@ -199,6 +230,7 @@ bool RadioIdLookup::load() } file.close(); + __UNLOCK_TABLE(); size_t size = m_table.size(); if (size == 0U) @@ -274,4 +306,4 @@ bool RadioIdLookup::save() LogInfoEx(LOG_HOST, "Saved %u entries to lookup table file %s", lines, m_filename.c_str()); return true; -} \ No newline at end of file +} diff --git a/src/common/lookups/RadioIdLookup.h b/src/common/lookups/RadioIdLookup.h index 32058be3..2c859f2d 100644 --- a/src/common/lookups/RadioIdLookup.h +++ b/src/common/lookups/RadioIdLookup.h @@ -5,7 +5,7 @@ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright (C) 2016 Jonathan Naylor, G4KLX - * Copyright (C) 2017-2022,2024 Bryan Biedenkapp, N2PLL + * Copyright (C) 2017-2022,2024,2025 Bryan Biedenkapp, N2PLL * Copyright (c) 2024 Patrick McDonnell, W3AXL * */ @@ -208,7 +208,8 @@ namespace lookups bool save() override; private: - static std::mutex m_mutex; + static std::mutex m_mutex; //! Mutex used for hard locking. + static bool m_locked; //! Flag used for soft locking (prevents find lookups), should be used when atomic operations (add/erase/etc) are being used. }; } // namespace lookups diff --git a/src/common/lookups/TalkgroupRulesLookup.cpp b/src/common/lookups/TalkgroupRulesLookup.cpp index 239c6b35..f85c6df0 100644 --- a/src/common/lookups/TalkgroupRulesLookup.cpp +++ b/src/common/lookups/TalkgroupRulesLookup.cpp @@ -4,7 +4,7 @@ * GPLv2 Open Source. Use is subject to license terms. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * Copyright (C) 2023,2024 Bryan Biedenkapp, N2PLL + * Copyright (C) 2023,2024,2025 Bryan Biedenkapp, N2PLL * Copyright (C) 2024 Patrick McDonnell, W3AXL * */ @@ -23,6 +23,26 @@ using namespace lookups; // --------------------------------------------------------------------------- std::mutex TalkgroupRulesLookup::m_mutex; +bool TalkgroupRulesLookup::m_locked = false; + +// --------------------------------------------------------------------------- +// Macros +// --------------------------------------------------------------------------- + +// Lock the table. +#define __LOCK_TABLE() \ + std::lock_guard lock(m_mutex); \ + m_locked = true; + +// Unlock the table. +#define __UNLOCK_TABLE() m_locked = false; + +// Spinlock wait for table to be released. +#define __SPINLOCK() \ + if (m_locked) { \ + while (m_locked) \ + Thread::sleep(2U); \ + } // --------------------------------------------------------------------------- // Public Class Members @@ -101,8 +121,11 @@ bool TalkgroupRulesLookup::read() void TalkgroupRulesLookup::clear() { - std::lock_guard lock(m_mutex); + __LOCK_TABLE(); + m_groupVoice.clear(); + + __UNLOCK_TABLE(); } /* Adds a new entry to the lookup table by the specified unique ID. */ @@ -117,7 +140,8 @@ void TalkgroupRulesLookup::addEntry(uint32_t id, uint8_t slot, bool enabled, boo config.affiliated(affiliated); config.nonPreferred(nonPreferred); - std::lock_guard lock(m_mutex); + __LOCK_TABLE(); + auto it = std::find_if(m_groupVoice.begin(), m_groupVoice.end(), [&](TalkgroupRuleGroupVoice x) { @@ -150,6 +174,8 @@ void TalkgroupRulesLookup::addEntry(uint32_t id, uint8_t slot, bool enabled, boo m_groupVoice.push_back(entry); } + + __UNLOCK_TABLE(); } /* Adds a new entry to the lookup table by the specified unique ID. */ @@ -163,7 +189,8 @@ void TalkgroupRulesLookup::addEntry(TalkgroupRuleGroupVoice groupVoice) uint32_t id = entry.source().tgId(); uint8_t slot = entry.source().tgSlot(); - std::lock_guard lock(m_mutex); + __LOCK_TABLE(); + auto it = std::find_if(m_groupVoice.begin(), m_groupVoice.end(), [&](TalkgroupRuleGroupVoice x) { @@ -179,17 +206,22 @@ void TalkgroupRulesLookup::addEntry(TalkgroupRuleGroupVoice groupVoice) else { m_groupVoice.push_back(entry); } + + __UNLOCK_TABLE(); } /* Erases an existing entry from the lookup table by the specified unique ID. */ void TalkgroupRulesLookup::eraseEntry(uint32_t id, uint8_t slot) { - std::lock_guard lock(m_mutex); + __LOCK_TABLE(); + auto it = std::find_if(m_groupVoice.begin(), m_groupVoice.end(), [&](TalkgroupRuleGroupVoice x) { return x.source().tgId() == id && x.source().tgSlot() == slot; }); if (it != m_groupVoice.end()) { m_groupVoice.erase(it); } + + __UNLOCK_TABLE(); } /* Finds a table entry in this lookup table. */ @@ -198,7 +230,8 @@ TalkgroupRuleGroupVoice TalkgroupRulesLookup::find(uint32_t id, uint8_t slot) { TalkgroupRuleGroupVoice entry; - std::lock_guard lock(m_mutex); + __SPINLOCK(); + auto it = std::find_if(m_groupVoice.begin(), m_groupVoice.end(), [&](TalkgroupRuleGroupVoice x) { @@ -223,7 +256,8 @@ TalkgroupRuleGroupVoice TalkgroupRulesLookup::findByRewrite(uint32_t peerId, uin { TalkgroupRuleGroupVoice entry; - std::lock_guard lock(m_mutex); + __SPINLOCK(); + auto it = std::find_if(m_groupVoice.begin(), m_groupVoice.end(), [&](TalkgroupRuleGroupVoice x) { @@ -295,11 +329,13 @@ bool TalkgroupRulesLookup::load() // clear table clear(); - std::lock_guard lock(m_mutex); + __LOCK_TABLE(); + yaml::Node& groupVoiceList = m_rules["groupVoice"]; if (groupVoiceList.size() == 0U) { ::LogError(LOG_HOST, "No group voice rules list defined!"); + m_locked = false; return false; } @@ -332,9 +368,12 @@ bool TalkgroupRulesLookup::load() ::LogInfoEx(LOG_HOST, "Talkgroup NAME: %s SRC_TGID: %u SRC_TS: %u ACTIVE: %u PARROT: %u AFFILIATED: %u INCLUSIONS: %u EXCLUSIONS: %u REWRITES: %u ALWAYS: %u PREFERRED: %u PERMITTED RIDS: %u", groupName.c_str(), tgId, tgSlot, active, parrot, affil, incCount, excCount, rewrCount, alwyCount, prefCount, permRIDCount); } + __UNLOCK_TABLE(); + size_t size = m_groupVoice.size(); - if (size == 0U) + if (size == 0U) { return false; + } LogInfoEx(LOG_HOST, "Loaded %lu entries into talkgroup rules table", size); diff --git a/src/common/lookups/TalkgroupRulesLookup.h b/src/common/lookups/TalkgroupRulesLookup.h index 0bbb5f97..66f3c455 100644 --- a/src/common/lookups/TalkgroupRulesLookup.h +++ b/src/common/lookups/TalkgroupRulesLookup.h @@ -4,7 +4,7 @@ * GPLv2 Open Source. Use is subject to license terms. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * Copyright (C) 2023,2024 Bryan Biedenkapp, N2PLL + * Copyright (C) 2023,2024,2025 Bryan Biedenkapp, N2PLL * Copyright (C) 2024 Patrick McDonnell, W3AXL * */ @@ -643,7 +643,8 @@ namespace lookups bool m_acl; bool m_stop; - static std::mutex m_mutex; + static std::mutex m_mutex; //! Mutex used for hard locking. + static bool m_locked; //! Flag used for soft locking (prevents find lookups), should be used when atomic operations (add/erase/etc) are being used. /** * @brief Loads the table from the passed lookup table file. diff --git a/src/fne/network/influxdb/InfluxDB.h b/src/fne/network/influxdb/InfluxDB.h index 7c36ffcd..ef909a65 100644 --- a/src/fne/network/influxdb/InfluxDB.h +++ b/src/fne/network/influxdb/InfluxDB.h @@ -63,7 +63,7 @@ namespace network // Constants // --------------------------------------------------------------------------- - #define MAX_INFLUXQL_THREAD_CNT 75 // this is a really extreme number of pending queries... + #define MAX_INFLUXQL_THREAD_CNT 125 // Extreme maximum number of pending Flux queries // --------------------------------------------------------------------------- // Class Declaration