Currently job artifacts in CI/CD pipelines on LRZ GitLab never expire. Starting from Wed 26.1.2022 the default expiration time will be 30 days (GitLab default). Currently existing artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

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

Pusher SensorGroupTemplate: Also replace partial template specialization with...

Pusher SensorGroupTemplate: Also replace partial template specialization with derived SensorGroupTemplate for entities
parent 1b2b109a
......@@ -28,7 +28,6 @@
#ifndef SENSORGROUPTEMPLATE_H_
#define SENSORGROUPTEMPLATE_H_
#include "EntityInterface.h"
#include "SensorGroupInterface.h"
#include "timestamp.h"
......@@ -37,251 +36,10 @@
#include <vector>
/**
* @brief Interface template for sensor group implementations with entities.
* @brief Interface template for sensor group implementations without entities.
*
* @details There is a partial template specialization for E = nullptr_t, i.e.
* for groups without entities, see SensorGroupTemplate<S, nullptr_t>.
* Common code has to be duplicated and maintained twice here and in
* 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
*/
template <class S, class E = nullptr_t>
class SensorGroupTemplate : public SensorGroupInterface {
//the template shall only be instantiated for classes which derive from SensorBase and EntityInterface respectively
static_assert(std::is_base_of<SensorBase, S>::value, "S must derive from SensorBase!");
static_assert(std::is_base_of<EntityInterface, E>::value, "E must derive from EntityInterface!");
protected:
using S_Ptr = std::shared_ptr<S>;
public:
SensorGroupTemplate(const std::string groupName)
: SensorGroupInterface(groupName),
_entity(nullptr) {}
SensorGroupTemplate(const SensorGroupTemplate &other)
: SensorGroupInterface(other),
_entity(other._entity) {
for (auto s : other._sensors) {
S_Ptr sensor = std::make_shared<S>(*s);
_sensors.push_back(sensor);
_baseSensors.push_back(sensor);
}
}
virtual ~SensorGroupTemplate() {
if (_keepRunning) {
stop();
}
_sensors.clear();
_baseSensors.clear();
}
SensorGroupTemplate &operator=(const SensorGroupTemplate &other) {
SensorGroupInterface::operator=(other);
_sensors.clear();
_baseSensors.clear();
for (auto s : other._sensors) {
S_Ptr sensor = std::make_shared<S>(*s);
_sensors.push_back(sensor);
_baseSensors.push_back(sensor);
}
_entity = other._entity;
return *this;
}
void setEntity(E *entity) { _entity = entity; }
E *const getEntity() const { return _entity; }
/**
* @brief Initialize the sensor group.
*
* @details This method must not be overwritten. See execOnInit() if custom
* actions are required during initialization. Initializes
* associated sensors and entity.
*
* @param io IO service to initialize the timer with.
*/
virtual void init(boost::asio::io_service &io) final override {
if (!_entity) {
LOG(error) << "No entity set for group " << _groupName << "! Cannot initialize group";
return;
}
SensorGroupInterface::init(io);
for (auto s : _sensors) {
s->initSensor(_interval);
}
_entity->init(io);
this->execOnInit();
}
/**
* @brief Does a busy wait until all dispatched handlers are finished
* (_pendingTasks == 0).
*
* @details If the wait takes longer than a reasonable amount of time we
* return anyway, to not block termination of dcdbpusher.
*/
virtual void wait() final override {
uint64_t sleepms = 10, i = 0;
uint64_t timeout = _interval < 10000 ? 10000 : _interval;
while (sleepms * i++ < timeout) {
if (_pendingTasks)
std::this_thread::sleep_for(std::chrono::milliseconds(sleepms));
else {
this->execOnStop();
LOG(info) << "Sensorgroup " << _groupName << " stopped.";
return;
}
}
LOG(warning) << "Group " << _groupName << " will not finish! Skipping it";
}
/**
* @brief Start the sensor group (i.e. start collecting data).
*
* @details This method must not be overwritten. See execOnStart() if custom
* actions are required during startup.
*/
virtual void start() final override {
if (_disabled) {
return;
}
if (_keepRunning) {
//we have been started already
LOG(info) << "Sensorgroup " << _groupName << " already running.";
return;
}
if (!this->execOnStart()) {
LOG(error) << "Sensorgroup " << _groupName << ": Startup failed.";
return;
}
if (_entity) {
if (!_entity->isDisabled()) {
_keepRunning = true;
_pendingTasks++;
_timer->async_wait(_entity->getStrand()->wrap(std::bind(&SensorGroupTemplate::readAsync, this)));
LOG(info) << "Sensorgroup " << _groupName << " started.";
}
} else {
LOG(error) << "No entity set for group " << _groupName << "! Cannot start polling.";
}
}
/**
* @brief Stop the sensor group (i.e. stop collecting data).
*
* @details This method must not be overwritten. See execOnStop() if custom
* actions are required during shutdown.
*/
virtual void stop() final override {
if (!_keepRunning) {
LOG(debug) << "Sensorgroup " << _groupName << " already stopped.";
return;
}
_keepRunning = false;
//cancel any outstanding readAsync()
_timer->cancel();
}
/**
* @brief Add a sensor to this group.
*
* @details Not intended to be overwritten.
*
* @param s Shared pointer to the sensor.
*/
virtual void pushBackSensor(SBasePtr s) final override {
//check if dynamic cast returns nullptr
if (S_Ptr dSensor = std::dynamic_pointer_cast<S>(s)) {
_sensors.push_back(dSensor);
_baseSensors.push_back(s);
} else {
LOG(warning) << "Group " << _groupName << ": Type mismatch when storing sensor! Sensor omitted";
}
}
/**
* @brief Print SensorGroup configuration.
*
* @details Always call %SensorGroupTemplate::printConfig() to print
* complete configuration of a sensor group. This method takes
* care of calling SensorGroupInterface::printConfig() and
* derived %printConfig() methods in correct order.
*
* @param ll Log severity level to be used from logger.
*/
virtual void printConfig(LOG_LEVEL ll, unsigned leadingSpaces = 8) final override {
//print common base attributes
SensorGroupInterface::printConfig(ll, leadingSpaces);
//print plugin specific group attributes
this->printGroupConfig(ll, leadingSpaces + 4);
//print associated sensors
std::string leading(leadingSpaces + 4, ' ');
LOG_VAR(ll) << leading << "Sensors:";
for (auto s : _sensors) {
s->SensorBase::printConfig(ll, lg, leadingSpaces + 8);
s->printConfig(ll, lg, leadingSpaces + 8);
}
}
protected:
/**
* @brief Asynchronous callback if _timer expires.
*
* @details Issues a read() and sets the timer again if _keepRunning is true.
*/
void readAsync() {
this->read();
if (_timer && _keepRunning && !_disabled && !_entity->isDisabled()) {
_timer->expires_at(timestamp2ptime(nextReadingTime()));
_pendingTasks++;
_timer->async_wait(_entity->getStrand()->wrap(std::bind(&SensorGroupTemplate::readAsync, this)));
}
_pendingTasks--;
}
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
};
////////////////////////////////////////////////////////////////////////////////
// Partial template specialization for E = nullptr_t
////////////////////////////////////////////////////////////////////////////////
/**
* @brief Interface partial template specialization for sensor group
* implementations without entities.
*
* @details There is a general template for groups with entities, see
* SensorGroupTemplate. Common code has to be duplicated and maintained
* twice here and in SensorGroupTemplate. However, having two templates
* for cases with and without entities greatly reduces code duplication
* in derived plugin sensor groups.
* @details There is a derived template for groups with entities, see
* SensorGroupTemplateEntity.
* 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
......@@ -290,7 +48,7 @@ class SensorGroupTemplate : public SensorGroupInterface {
* @ingroup pusherplugins
*/
template <class S>
class SensorGroupTemplate<S, nullptr_t> : public SensorGroupInterface {
class SensorGroupTemplate : public SensorGroupInterface {
//the template shall only be instantiated for classes which derive from SensorBase
static_assert(std::is_base_of<SensorBase, S>::value, "S must derive from SensorBase!");
......@@ -337,13 +95,13 @@ class SensorGroupTemplate<S, nullptr_t> : public SensorGroupInterface {
/**
* @brief Initialize the sensor group.
*
* @details This method must not be overwritten. See execOnInit() if custom
* actions are required during initialization. Initializes
* associated sensors and entity.
* @details This method must not be overwritten by plugins. See execOnInit()
* if custom actions are required during initialization.
* Initializes associated sensors.
*
* @param io IO service to initialize the timer with.
*/
virtual void init(boost::asio::io_service &io) final override {
virtual void init(boost::asio::io_service &io) override {
SensorGroupInterface::init(io);
for (auto s : _sensors) {
......@@ -380,10 +138,10 @@ class SensorGroupTemplate<S, nullptr_t> : public SensorGroupInterface {
/**
* @brief Start the sensor group (i.e. start collecting data).
*
* @details This method must not be overwritten. See execOnStart() if custom
* actions are required during startup.
* @details This method must not be overwritten by plugins. See
* execOnStart() if custom actions are required during startup.
*/
virtual void start() final override {
virtual void start() override {
if (_disabled) {
return;
}
......@@ -471,7 +229,7 @@ class SensorGroupTemplate<S, nullptr_t> : public SensorGroupInterface {
*
* @details Issues a read() and sets the timer again if _keepRunning is true.
*/
void readAsync() {
virtual void readAsync() {
this->read();
if (_timer && _keepRunning && !_disabled) {
_timer->expires_at(timestamp2ptime(nextReadingTime()));
......
//================================================================================
// Name : SensorGroupTemplateEntity.h
// Author : Micha Mueller
// Contact : info@dcdb.it
// Copyright : Leibniz Supercomputing Centre
// Description : Interface template for sensor group functionality with entities.
//================================================================================
//================================================================================
// This file is part of DCDB (DataCenter DataBase)
// Copyright (C) 2019-2019 Leibniz Supercomputing Centre
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//================================================================================
#ifndef DCDBPUSHER_INCLUDES_SENSORGROUPTEMPLATEENTITY_H_
#define DCDBPUSHER_INCLUDES_SENSORGROUPTEMPLATEENTITY_H_
#include "SensorGroupTemplate.h"
#include "EntityInterface.h"
/**
* @brief Interface template for sensor group implementations with entities.
*
* @details This is a derived template of SensorGroupTemplate.
* 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
*/
template <class S, class E>
class SensorGroupTemplateEntity : public SensorGroupTemplate<S> {
//the template shall only be instantiated for classes which derive from EntityInterface
static_assert(std::is_base_of<EntityInterface, E>::value, "E must derive from EntityInterface!");
protected:
//mention all required parent attributes and functions here to avoid compiler errors
using SensorGroupInterface::_disabled;
using SensorGroupInterface::_groupName;
using SensorGroupInterface::_interval;
using SensorGroupInterface::_keepRunning;
using SensorGroupInterface::_pendingTasks;
using SensorGroupInterface::_timer;
using SensorGroupInterface::lg;
using SensorGroupInterface::nextReadingTime;
using SensorGroupTemplate<S>::_sensors;
public:
SensorGroupTemplateEntity(const std::string groupName)
: SensorGroupTemplate<S>(groupName),
_entity(nullptr) {}
SensorGroupTemplateEntity(const SensorGroupTemplateEntity &other)
: SensorGroupTemplate<S>(other),
_entity(other._entity) {}
virtual ~SensorGroupTemplateEntity() {}
SensorGroupTemplateEntity &operator=(const SensorGroupTemplateEntity &other) {
SensorGroupTemplate<S>::operator=(other);
_entity = other._entity;
return *this;
}
void setEntity(E *entity) { _entity = entity; }
E *const getEntity() const { return _entity; }
/**
* @brief Initialize the sensor group.
*
* @details This method must not be overwritten. See execOnInit() if custom
* actions are required during initialization. Initializes
* associated sensors and entity.
*
* @param io IO service to initialize the timer with.
*/
virtual void init(boost::asio::io_service &io) final override {
if (!_entity) {
LOG(error) << "No entity set for group " << _groupName << "! Cannot initialize group";
return;
}
SensorGroupInterface::init(io);
for (auto s : _sensors) {
s->initSensor(_interval);
}
_entity->init(io);
this->execOnInit();
}
/**
* @brief Start the sensor group (i.e. start collecting data).
*
* @details This method must not be overwritten. See execOnStart() if custom
* actions are required during startup.
*/
virtual void start() final override {
if (_disabled) {
return;
}
if (_keepRunning) {
//we have been started already
LOG(info) << "Sensorgroup " << _groupName << " already running.";
return;
}
if (!this->execOnStart()) {
LOG(error) << "Sensorgroup " << _groupName << ": Startup failed.";
return;
}
if (_entity) {
if (!_entity->isDisabled()) {
_keepRunning = true;
_pendingTasks++;
_timer->async_wait(_entity->getStrand()->wrap(std::bind(&SensorGroupTemplateEntity::readAsync, this)));
LOG(info) << "Sensorgroup " << _groupName << " started.";
}
} else {
LOG(error) << "No entity set for group " << _groupName << "! Cannot start polling.";
}
}
protected:
/**
* @brief Asynchronous callback if _timer expires.
*
* @details Issues a read() and sets the timer again if _keepRunning is true.
*/
void readAsync() final override {
this->read();
if (_timer && _keepRunning && !_disabled && !_entity->isDisabled()) {
_timer->expires_at(timestamp2ptime(nextReadingTime()));
_pendingTasks++;
_timer->async_wait(_entity->getStrand()->wrap(std::bind(&SensorGroupTemplateEntity::readAsync, this)));
}
_pendingTasks--;
}
E *_entity; ///< Entity this group is associated to
};
#endif /* DCDBPUSHER_INCLUDES_SENSORGROUPTEMPLATEENTITY_H_ */
......@@ -35,7 +35,16 @@ cat << EOF > ${PLUGIN_NAME}SensorGroup.cpp
#include "timestamp.h"
${PLUGIN_NAME}SensorGroup::${PLUGIN_NAME}SensorGroup(const std::string& name) :
SensorGroupTemplate(name) {
EOF
if [ "$enableEntities" = true ]
then
echo " SensorGroupTemplateEntity(name) {" >> ${PLUGIN_NAME}SensorGroup.cpp
else
echo " SensorGroupTemplate(name) {" >> ${PLUGIN_NAME}SensorGroup.cpp
fi
cat << EOF >> ${PLUGIN_NAME}SensorGroup.cpp
/*
* TODO
* Construct attributes
......@@ -43,7 +52,16 @@ ${PLUGIN_NAME}SensorGroup::${PLUGIN_NAME}SensorGroup(const std::string& name) :
}
${PLUGIN_NAME}SensorGroup::${PLUGIN_NAME}SensorGroup(const ${PLUGIN_NAME}SensorGroup& other) :
SensorGroupTemplate(other) {
EOF
if [ "$enableEntities" = true ]
then
echo " SensorGroupTemplateEntity(other) {" >> ${PLUGIN_NAME}SensorGroup.cpp
else
echo " SensorGroupTemplate(other) {" >> ${PLUGIN_NAME}SensorGroup.cpp
fi
cat << EOF >> ${PLUGIN_NAME}SensorGroup.cpp
/*
* TODO
* Copy construct attributes
......
......@@ -33,8 +33,16 @@ cat << EOF > ${PLUGIN_NAME}SensorGroup.h
#ifndef ${PLUGIN_NAME_UPC}_${PLUGIN_NAME_UPC}SENSORGROUP_H_
#define ${PLUGIN_NAME_UPC}_${PLUGIN_NAME_UPC}SENSORGROUP_H_
#include "../../includes/SensorGroupTemplate.h"
EOF
if [ "$enableEntities" = true ]
then
echo "#include \"../../includes/SensorGroupTemplateEntity.h\"" >> ${PLUGIN_NAME}SensorGroup.h
else
echo "#include \"../../includes/SensorGroupTemplate.h\"" >> ${PLUGIN_NAME}SensorGroup.h
fi
cat << EOF >> ${PLUGIN_NAME}SensorGroup.h
#include "${PLUGIN_NAME}SensorBase.h"
/**
......@@ -46,7 +54,7 @@ EOF
if [ "$enableEntities" = true ]
then
echo "class ${PLUGIN_NAME}SensorGroup : public SensorGroupTemplate<${PLUGIN_NAME}SensorBase, ${PLUGIN_NAME}${ENTITY_NAME}> {" >> ${PLUGIN_NAME}SensorGroup.h
echo "class ${PLUGIN_NAME}SensorGroup : public SensorGroupTemplateEntity<${PLUGIN_NAME}SensorBase, ${PLUGIN_NAME}${ENTITY_NAME}> {" >> ${PLUGIN_NAME}SensorGroup.h
else
echo "class ${PLUGIN_NAME}SensorGroup : public SensorGroupTemplate<${PLUGIN_NAME}SensorBase> {" >> ${PLUGIN_NAME}SensorGroup.h
fi
......
......@@ -30,11 +30,11 @@
#include <functional>
BACnetSensorGroup::BACnetSensorGroup(const std::string &name)
: SensorGroupTemplate(name), _deviceInstance(0) {
: SensorGroupTemplateEntity(name), _deviceInstance(0) {
}
BACnetSensorGroup::BACnetSensorGroup(const BACnetSensorGroup &other)
: SensorGroupTemplate(other),
: SensorGroupTemplateEntity(other),
_deviceInstance(other._deviceInstance) {}
BACnetSensorGroup::~BACnetSensorGroup() {}
......
......@@ -28,7 +28,7 @@
#ifndef BACNETSENSORGROUP_H_
#define BACNETSENSORGROUP_H_
#include "../../includes/SensorGroupTemplate.h"
#include "../../includes/SensorGroupTemplateEntity.h"
#include "BACnetSensorBase.h"
/**
......@@ -36,7 +36,7 @@
*
* @ingroup bacnet
*/
class BACnetSensorGroup : public SensorGroupTemplate<BACnetSensorBase, BACnetClient> {
class BACnetSensorGroup : public SensorGroupTemplateEntity<BACnetSensorBase, BACnetClient> {
public:
BACnetSensorGroup(const std::string &name);
......
......@@ -34,11 +34,11 @@
#include <iostream>
IPMISensorGroup::IPMISensorGroup(const std::string &name)
: SensorGroupTemplate(name) {
: SensorGroupTemplateEntity(name) {
}
IPMISensorGroup::IPMISensorGroup(const IPMISensorGroup &other)
: SensorGroupTemplate(other) {
: SensorGroupTemplateEntity(other) {
}
IPMISensorGroup::~IPMISensorGroup() {}
......
......@@ -28,7 +28,7 @@
#ifndef IPMISENSORGROUP_H_
#define IPMISENSORGROUP_H_
#include "../../includes/SensorGroupTemplate.h"
#include "../../includes/SensorGroupTemplateEntity.h"
#include "IPMISensorBase.h"
/**
......@@ -36,7 +36,7 @@
*
* @ingroup ipmi
*/
class IPMISensorGroup : public SensorGroupTemplate<IPMISensorBase, IPMIHost> {
class IPMISensorGroup : public SensorGroupTemplateEntity<IPMISensorBase, IPMIHost> {
public:
IPMISensorGroup(const std::string &name);
......
......@@ -33,11 +33,11 @@
#include <boost/property_tree/xml_parser.hpp>
PDUSensorGroup::PDUSensorGroup(const std::st