Commit 2a1cb43b authored by Micha Müller's avatar Micha Müller
Browse files

Pusher: Replace senor mutex with plugin specific locking method

parent 27702504
......@@ -132,12 +132,8 @@ void MQTTPusher::push() {
//for faster response
break;
}
if (!p.configurator->trylockSensors()) {
//skip this plugin if it is currently locked and try again later
continue;
}
for (const auto &g : p.configurator->getSensorGroups()) {
for (const auto &s : g->getSensors()) {
for (const auto &s : g->acquireSensors()) {
if (s->getSizeOfReadingQueue() >= g->getMinValues()) {
if (_msgCap == DISABLED || totalCount < (unsigned)_maxNumberOfMessages) {
if (sendReadings(*s, reads, totalCount) > 0) {
......@@ -148,8 +144,8 @@ void MQTTPusher::push() {
}
}
}
g->releaseSensors();
}
p.configurator->unlockSensors();
}
// Push output analytics sensors
for (auto &p : _analyticsPlugins) {
......@@ -230,9 +226,8 @@ bool MQTTPusher::sendMappings() {
unsigned int publishCtr=0;
// Performing auto-publish for sensors
for(auto& p: _plugins) {
p.configurator->lockSensors();
for(auto& g: p.configurator->getSensorGroups()) {
for(auto& s: g->getSensors()) {
for(auto& s: g->acquireSensors()) {
topic = std::string(DCDB_MAP) + s->getMqtt();
name = s->getName();
......@@ -245,8 +240,8 @@ bool MQTTPusher::sendMappings() {
else
publishCtr++;
}
g->releaseSensors();
}
p.configurator->unlockSensors();
}
// Performing auto-publish for analytics output sensors
......@@ -294,11 +289,10 @@ void MQTTPusher::computeMsgRate() {
float msgRate = 0;
bool dynWarning = false;
for(auto& p : _plugins) {
p.configurator->lockSensors();
for(const auto& g : p.configurator->getSensorGroups()) {
msgRate += (float)g->getSensors().size() * ( 1000.0f / (float)g->getInterval() ) / (float)g->getMinValues();
msgRate += (float)g->acquireSensors().size() * ( 1000.0f / (float)g->getInterval() ) / (float)g->getMinValues();
g->releaseSensors();
}
p.configurator->unlockSensors();
}
for(auto& p : _analyticsPlugins)
for(const auto& a : p.configurator->getAnalyzers()) {
......
......@@ -235,9 +235,7 @@ bool PluginManager::reloadPluginConfig(const string& id) {
for (const auto& p : _plugins) {
if (p.id == id) {
// Removing obsolete MQTT topics
p.configurator->lockSensors();
removeTopics(p);
p.configurator->unlockSensors();
if (p.configurator->reReadConfig()) {
// Perform checks on MQTT topics
if(!checkTopics(p)) {
......@@ -266,11 +264,12 @@ bool PluginManager::checkTopics(const pusherPlugin_t& p) {
if (!mqttCheck.checkGroup(g->getGroupName())) {
validTopics = false;
}
for (const auto& s : g->getSensors()) {
for (const auto& s : g->acquireSensors()) {
if (!mqttCheck.checkTopic(s->getMqtt()) || !mqttCheck.checkName(s->getName())) {
validTopics = false;
}
}
g->releaseSensors();
}
return validTopics;
......@@ -280,9 +279,10 @@ void PluginManager::removeTopics(const pusherPlugin_t& p) {
MQTTChecker& mqttCheck = MQTTChecker::getInstance();
for(const auto& g : p.configurator->getSensorGroups()) {
mqttCheck.removeGroup(g->getGroupName());
for (const auto &s : g->getSensors()) {
for (const auto &s : g->acquireSensors()) {
mqttCheck.removeTopic(s->getMqtt());
mqttCheck.removeName(s->getName());
}
g->releaseSensors();
}
}
......@@ -97,28 +97,28 @@ void RestAPI::GET_sensors(endpointArgs) {
for(const auto& p : _pluginManager->getPlugins()) {
if (p.id == plugin) {
p.configurator->lockSensors();
std::ostringstream data;
if (getQuery("json", queries) == "true") {
boost::property_tree::ptree root, sensors;
for(const auto& g : p.configurator->getSensorGroups()) {
boost::property_tree::ptree group;
for(const auto& s : g->getSensors()) {
for(const auto& s : g->acquireSensors()) {
group.push_back(boost::property_tree::ptree::value_type("", boost::property_tree::ptree(s->getMqtt())));
}
g->releaseSensors();
sensors.add_child(g->getGroupName(), group);
}
root.add_child(p.id, sensors);
boost::property_tree::write_json(data, root, true);
} else {
for(const auto& g : p.configurator->getSensorGroups()) {
for(const auto& s : g->getSensors()) {
for(const auto& s : g->acquireSensors()) {
data << g->getGroupName() << "::" << s->getMqtt() << "\n";
}
g->releaseSensors();
}
}
p.configurator->unlockSensors();
res.body() = data.str();
res.result(http::status::ok);
return;
......@@ -156,9 +156,8 @@ void RestAPI::GET_average(endpointArgs) {
for(const auto& p : _pluginManager->getPlugins()) {
if (p.id == plugin) {
res.body() = "Sensor not found!\n";
p.configurator->lockSensors();
for(const auto& g : p.configurator->getSensorGroups()) {
for(const auto& s : g->getSensors()) {
for(const auto& s : g->acquireSensors()) {
if (s->getName() == sensor && s->isInit()) {
uint64_t avg = 0;
try {
......@@ -167,16 +166,18 @@ void RestAPI::GET_average(endpointArgs) {
res.body() = "Unable to compute average: ";
res.body() += e.what();
res.result(http::status::internal_server_error);
g->releaseSensors();
return;
}
res.body() = plugin + "::" + sensor + " Average of last " +
std::to_string(time) + " seconds is " + std::to_string(avg) + "\n";
res.result(http::status::ok);
g->releaseSensors();
return;
}
}
g->releaseSensors();
}
p.configurator->unlockSensors();
}
}
......@@ -432,13 +433,13 @@ void RestAPI::reloadQueryEngine(const bool force) {
std::vector<std::string> topics;
for (const auto &p : _pluginManager->getPlugins()) {
p.configurator->lockSensors();
for (const auto &g : p.configurator->getSensorGroups())
for (const auto &s : g->getSensors()) {
for (const auto &g : p.configurator->getSensorGroups()) {
for (const auto &s : g->acquireSensors()) {
topics.push_back(s->getMqtt());
sensorMap->insert(std::make_pair(s->getName(), s));
}
p.configurator->unlockSensors();
g->releaseSensors();
}
}
// Adding data analytics sensors to the map
......
......@@ -265,9 +265,11 @@ int main(int argc, char** argv) {
std::shared_ptr <SensorNavigator> navigator = std::make_shared<SensorNavigator>();
vector <std::string> topics;
for (const auto &p : _pluginManager->getPlugins())
for (const auto &g : p.configurator->getSensorGroups())
for (const auto &s : g->getSensors())
for (const auto &g : p.configurator->getSensorGroups()) {
for (const auto &s : g->acquireSensors())
topics.push_back(s->getMqtt());
g->releaseSensors();
}
try {
navigator->setFilter(analyticsSettings.filter);
navigator->buildTree(analyticsSettings.hierarchy, &topics);
......@@ -293,9 +295,11 @@ int main(int argc, char** argv) {
std::shared_ptr <std::map<std::string, SBasePtr>> sensorMap = std::make_shared<std::map<std::string, SBasePtr>>();
for (const auto &p : _pluginManager->getPlugins())
for (const auto &g : p.configurator->getSensorGroups())
for (const auto &s : g->getSensors())
for (const auto &g : p.configurator->getSensorGroups()) {
for (const auto &s : g->acquireSensors())
sensorMap->insert(std::make_pair(s->getName(), s));
g->releaseSensors();
}
for(auto& p : _analyticsManager->getPlugins()) {
for (const auto &a : p.configurator->getAnalyzers())
......
......@@ -27,7 +27,6 @@
#ifndef SRC_CONFIGURATORINTERFACE_H_
#define SRC_CONFIGURATORINTERFACE_H_
#include <mutex>
#include <string>
#include <vector>
......@@ -118,36 +117,6 @@ public:
derivedSetGlobalSettings(pluginSettings);
}
/**
* @brief Lock access to plugin sensors for exclusive access.
*
* @details Blocks if already occupied until the lock gets available again.
*/
void lockSensors() {
return _mutex.lock();
}
/**
* @brief Try to lock access to plugin sensors for exclusive access.
*
* @details Returns immediately.
*
* @details True if locked, false if failed to lock.
*/
bool trylockSensors() {
return _mutex.try_lock();
}
/**
* @brief Unlock the previously locked access to plugin sensors.
*
* @details Causes undefined behavior if sensors were not successfully
* locked before.
*/
void unlockSensors() {
_mutex.lock();
}
/**
* @brief Get all sensor groups.
*
......@@ -320,9 +289,6 @@ protected:
std::string _cfgPath; ///< Path + name of config file to read from
std::string _mqttPrefix; ///< Global MQTT prefix
unsigned int _cacheInterval; ///< Time interval in ms all sensors should cache
//TODO lazy approach: only synchronized all source code locations which possible can interfere with caliper plugin.
// It may be necessary to sync other source code locations if this mutex is used for other purposes than for Caliper
std::mutex _mutex; ///< Allow for thread-safe modification of sensors during runtime (currently only used for Caliper plugin)
std::vector<SGroupPtr> _sensorGroupInterfaces; ///< Sensor group storage
......
......@@ -238,8 +238,10 @@ public:
//group which consists of only one sensor
SB_Ptr sensor;
//perhaps one sensor is already present because it was copied from the template group
if (group->getSensors().size() != 0) {
sensor = std::dynamic_pointer_cast<SBase>(group->getSensors()[0]);
if (group->acquireSensors().size() != 0) {
group->releaseSensors();
sensor = std::dynamic_pointer_cast<SBase>(group->acquireSensors()[0]);
group->releaseSensors();
//check if cast was successful (sensor != nullptr)
if (sensor) {
sensor->setName(val.second.data());
......@@ -254,6 +256,7 @@ public:
<< val.second.data() << " had a type mismatch when casting! Omitting";
}
} else {
group->releaseSensors();
sensor = std::make_shared<SBase>(val.second.data());
if (readSensorBase(*sensor, val.second)) {
group->pushBackSensor(sensor);
......@@ -558,8 +561,10 @@ protected:
group->setEntity(&sEntity);
SB_Ptr sensor;
//perhaps one sensor is already present because it was copied from the template group
if (group->getSensors().size() != 0) {
sensor = std::dynamic_pointer_cast<SBase>(group->getSensors()[0]);
if (group->aquireSensors().size() != 0) {
group->releaseSensors();
sensor = std::dynamic_pointer_cast<SBase>(group->acquireSensors()[0]);
group->releaseSensors();
//check if cast was successful (sensor != nullptr)
if (sensor) {
sensor->setName(val.second.data());
......@@ -642,8 +647,8 @@ protected:
*/
bool constructSensorTopics() {
// Sensor names are adjusted according to the respective MQTT topics
for(auto& g: _sensorGroups)
for(auto& s: g->getSensors()) {
for(auto& g: _sensorGroups) {
for(auto& s: g->acquireSensors()) {
s->setMqtt(MQTTChecker::formatTopic(_mqttPrefix) +
MQTTChecker::formatTopic(g->getEntity()->getMqttPart()) +
MQTTChecker::formatTopic(g->getMqttPart()) +
......@@ -652,6 +657,8 @@ protected:
if(s->getSinkPath()!="")
s->setSinkPath(MQTTChecker::topicToFile(s->getMqtt(), s->getSinkPath()));
}
g->releaseSensors();
}
return true;
}
///@}
......@@ -822,8 +829,10 @@ public:
//group which consists of only one sensor
SB_Ptr sensor;
//perhaps one sensor is already present because it was copied from the template group
if (group->getSensors().size() != 0) {
sensor = std::dynamic_pointer_cast<SBase>(group->getSensors()[0]);
if (group->acquireSensors().size() != 0) {
group->releaseSensors();
sensor = std::dynamic_pointer_cast<SBase>(group->acquireSensors()[0]);
group->releaseSensors();
//check if cast was successful (sensor != nullptr)
if (sensor) {
sensor->setName(val.second.data());
......@@ -838,6 +847,7 @@ public:
<< val.second.data() << " had a type mismatch when casting! Omitting";
}
} else {
group->releaseSensors();
sensor = std::make_shared<SBase>(val.second.data());
if (readSensorBase(*sensor, val.second)) {
group->pushBackSensor(sensor);
......@@ -1056,7 +1066,7 @@ protected:
bool constructSensorTopics() {
// Sensor names are adjusted according to the respective MQTT topics
for(auto& g: _sensorGroups)
for(auto& s: g->getSensors()) {
for(auto& s: g->acquireSensors()) {
s->setMqtt(MQTTChecker::formatTopic(_mqttPrefix) +
MQTTChecker::formatTopic(g->getMqttPart()) +
MQTTChecker::formatTopic(s->getMqtt()));
......
......@@ -149,11 +149,35 @@ public:
virtual void pushBackSensor(SBasePtr s) = 0;
/**
* @brief Retrieve all sensors of this group.
* @brief Acquire access to all sensors of this group.
*
* @details Always release sensor access via releaseSensors() afterwards to
* ensure multi-threading safety!
* acquireSensors() and releaseSensors() allow for thread-safe
* (locked) access to _baseSensors. However, as most plugins do not
* require synchronized access (and we want to avoid the induced
* lock overhead for them) the actual locking mechanism is only
* implemented in plugins actually requiring thread-safe access.
* Every caller which may require thread safe access to
* _baseSensors should use acquireSensors() and releaseSensors().
* If a plugin does not implement a locking mechanism because it
* does not require synchronized access releaseSensors() can be
* omitted.
* See the Caliper plugin for a SensorGroup which implements locked
* access to _baseSensors.
*
* @return A std::vector with shared pointers to all associated sensors.
*/
virtual std::vector<SBasePtr>& getSensors() = 0;
virtual std::vector<SBasePtr>& acquireSensors() { return _baseSensors; }
/**
* @brief Release previously acquired access to sensors of this group.
*
* @details Always acquire sensors via acquireSensors() beforehand!
* See description of acquireSensors() for an in-depth reasoning
* about this method.
*/
virtual void releaseSensors() { /* do nothing in base implementation */ }
/**
* @brief Print interface configuration.
......@@ -290,6 +314,7 @@ protected:
unsigned int _interval; ///< Reading interval cycle in milliseconds
std::atomic_uint _pendingTasks; ///< Number of currently outstanding read operations
std::unique_ptr<boost::asio::deadline_timer> _timer; ///< Time readings in a periodic interval
std::vector<SBasePtr> _baseSensors; ///< Vector with sensors associated to this group
LOGGER lg; ///< Personal logging instance
};
......
......@@ -44,6 +44,10 @@
* the SensorGroupTemplate<S, nullptr_t>. However, having two templates
* for cases with and without entities greatly reduces code duplication
* in derived plugin sensor groups.
* Internal usage of _baseSensors is not synchronized via
* acquireSensors()/releaseSensors() as it is only accessed (e.g. in
* (de-)constructor) when no other caller is expected to access
* _baseSensors.
*
* @ingroup pusherplugins
*/
......@@ -192,15 +196,6 @@ public:
}
}
/**
* @brief Retrieve all sensors of this group.
*
* @details Not intended to be overwritten.
*
* @return A std::vector with shared pointers to all associated sensors.
*/
virtual std::vector<SBasePtr>& getSensors() final override { return _baseSensors; }
/**
* @brief Print SensorGroup configuration.
*
......@@ -249,8 +244,7 @@ protected:
_pendingTasks--;
}
std::vector<S_Ptr> _sensors; ///< Sensors associated with this group
std::vector<SBasePtr> _baseSensors; ///< Maintain vector with SensorBase pointers for fast getSensors() implementation
std::vector<S_Ptr> _sensors; ///< Store pointers to actual sensor objects in addition to general sensor base pointers
E* _entity; ///< Entity this group is associated to
};
......@@ -269,6 +263,10 @@ protected:
* twice here and in SensorGroupTemplate. However, having two templates
* for cases with and without entities greatly reduces code duplication
* in derived plugin sensor groups.
* Internal usage of _baseSensors is not synchronized via
* acquireSensors()/releaseSensors() as it is only accessed (e.g. in
* (de-)constructor) when no other caller is expected to access
* _baseSensors.
*
* @ingroup pusherplugins
*/
......@@ -398,15 +396,6 @@ public:
}
}
/**
* @brief Retrieve all sensors of this group.
*
* @details Not intended to be overwritten.
*
* @return A std::vector with shared pointers to all associated sensors.
*/
virtual std::vector<SBasePtr>& getSensors() final override { return _baseSensors; }
/**
* @brief Print SensorGroup configuration.
*
......@@ -449,8 +438,7 @@ protected:
_pendingTasks--;
}
std::vector<S_Ptr> _sensors; ///< Sensors associated with this group
std::vector<SBasePtr> _baseSensors; ///< Maintain vector with SensorBase pointers for fast getSensors() implementation
std::vector<S_Ptr> _sensors; ///< Store pointers to actual sensor objects in addition to general sensor base pointers
};
#endif /* SENSORGROUPTEMPLATE_H_ */
......@@ -97,6 +97,7 @@ void CaliperSensorGroup::execOnStop() {
}
}
//TODO y not terminating?
void CaliperSensorGroup::read() {
if (_connection == -1) {
_connection = accept(_socket, NULL, NULL);
......@@ -120,6 +121,7 @@ void CaliperSensorGroup::read() {
//nrec==0 indicates that the connection was closed. Probably because Caliper terminated
if (nrec == 0) {
//TODO clean up sensors
close(_connection);
_connection = -1;
LOG(debug) << _groupName << ": Connection closed";
......@@ -156,6 +158,7 @@ void CaliperSensorGroup::read() {
s->setName(s->getMqtt());
s->initSensor(_interval);
//TODO lock access!
_sensors.push_back(s);
_baseSensors.push_back(s);
_sensorIndex.insert(std::make_pair(feName, s));
......
......@@ -41,25 +41,27 @@
class CaliperSensorGroup : public SensorGroupTemplate<CaliperSensorBase> {
public:
CaliperSensorGroup(const std::string& name);
CaliperSensorGroup(const CaliperSensorGroup& other);
virtual ~CaliperSensorGroup();
CaliperSensorGroup& operator=(const CaliperSensorGroup& other);
CaliperSensorGroup(const CaliperSensorGroup& other);
virtual ~CaliperSensorGroup();
CaliperSensorGroup& operator=(const CaliperSensorGroup& other);
bool execOnStart() final override;
void execOnStop() final override;
void printGroupConfig(LOG_LEVEL ll) final override;
bool execOnStart() final override;
void execOnStop() final override;
void setGlobalMqttPrefix(const std::string& prefix) { _globalMqttPrefix = prefix; }
//TODO overwrite acquire/release-sensors()
void printGroupConfig(LOG_LEVEL ll) final override;
void setGlobalMqttPrefix(const std::string& prefix) { _globalMqttPrefix = prefix; }
private:
void read() final override;
void read() final override;
int _socket;
int _connection;
std::string _globalMqttPrefix;
int _socket;
int _connection;
std::string _globalMqttPrefix;
std::unordered_map<std::string, S_Ptr> _sensorIndex; ///< Additional sensor storage for fast lookup
std::unordered_map<std::string, S_Ptr> _sensorIndex; ///< Additional sensor storage for fast lookup
};
#endif /* CALIPER_CALIPERSENSORGROUP_H_ */
......@@ -27,12 +27,6 @@
#include "IPMISensorGroup.h"
#include "IPMIHost.h"
#include <boost/tokenizer.hpp>
#include <boost/foreach.hpp>
#include <boost/regex.hpp>
#include <boost/bind.hpp>
#include <boost/lockfree/spsc_queue.hpp>
#include <iostream>
#include <exception>
#include <chrono>
......
......@@ -145,8 +145,8 @@ bool MSRConfigurator::readConfig(std::string cfgPath) {
//group which consists of only one sensor
SB_Ptr sensor;
//perhaps one sensor is already present because it was copied from the template group
if (group->getSensors().size() != 0) {
sensor = std::dynamic_pointer_cast<MSRSensorBase>(group->getSensors()[0]);
if (group->acquireSensors().size() != 0) {
sensor = std::dynamic_pointer_cast<MSRSensorBase>(group->acquireSensors()[0]);
//check if cast was successful (sensor != nullptr)
if (sensor) {
sensor->setName(val.second.data());
......@@ -188,7 +188,7 @@ void MSRConfigurator::customizeAndStore(SG_Ptr g) {
std::vector<SB_Ptr> original;
// Initializing the vector of "reference" sensors and configuring the first CPU
for(auto s : g->getSensors()) {
for(auto s : g->acquireSensors()) {
SB_Ptr sensor = std::dynamic_pointer_cast<MSRSensorBase>(s);
// Copying the original sensors for reference
original.push_back(std::make_shared<MSRSensorBase>(*sensor));
......
......@@ -230,8 +230,8 @@ bool PerfeventConfigurator::readConfig(std::string cfgPath) {
//group which consists of only one sensor
std::shared_ptr<PerfSensorBase> sensor;
//perhaps one sensor is already present because it was copied from the template group
if (group.getSensors().size() != 0) {
sensor = std::dynamic_pointer_cast<PerfSensorBase>(group.getSensors()[0]);
if (group.acquireSensors().size() != 0) {
sensor = std::dynamic_pointer_cast<PerfSensorBase>(group.acquireSensors()[0]);
//check if cast was successful (sensor != nullptr)
if (sensor) {
sensor->setName(val.second.data());
......
......@@ -164,7 +164,7 @@ void ProcfsConfigurator::sensorGroup(ProcfsSensorGroup& sGroup, CFG_VAL config)
int numMetrics = 0;
if(!parser->init(&derivedSensors, sGroup.getCpuSet()) || (numMetrics = parser->getNumMetrics()) == 0) {
LOG(warning) << _groupName << " " << sGroup.getGroupName() << "::" << "Unable to parse file " << filePath << ", please check your configuration!";
sGroup.getSensors().clear();
sGroup.acquireSensors().clear();
sGroup.getDerivedSensors().clear();
return; }
LOG(debug) << " Number of metrics found: " << numMetrics;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment