Files
qt5-legatus-legacy/Lts/Services/ServiceManagement/group.cpp
T
2026-08-13 18:33:10 +02:00

378 lines
9.7 KiB
C++
Executable File

/**
* The Group class represents a group which was already startet.
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2016-02-15
*/
#include "group.h"
#include <QtCore/QDateTime>
#include <QtCore/QThread>
#include <QtCore/QTimer>
#include <QtAlgorithms>
#include <vector>
#include "group_handler.h"
#include "service_handler.h"
#include "service_process.h"
#include "service_donator.h"
#include <ServiceManagement/scm.hpp>
namespace ServiceManagement
{
int32_t Group::s_idCounter = 0;
Group::Group(const std::shared_ptr<DdsHandler> &ddsHandler,
const std::shared_ptr<ServiceDonator> &serviceDonator,
const GroupRequest &groupData,
GroupScheme *scheme,
QObject *parent)
: QObject(parent)
, m_ddsHandler(ddsHandler)
, m_serviceDonator(serviceDonator)
, m_scheme(scheme)
, m_groupId(s_idCounter++)
, m_groupData(groupData)
, m_completeCoreTimeout(0)
, m_logger(getLogger("Group"))
{
INFO_LOG(m_logger) << "Group "
<< m_scheme->groupType
<< " for partition "
<< groupData
<< " created.";
m_elapsedTimer.start();
}
Group::~Group()
{
setRunningState(Core::RunningState::StoppedNormally);
for (ServiceProcess *serviceProc :qAsConst(m_serviceProcs))
m_ddsHandler->dts()->removeServiceInformationByKey(serviceProc->serviceProcessId());
qDeleteAll(m_serviceProcs); // in Service they are removed via ServiceProcess::destroyed signal
m_ddsHandler->dts()->removeGroupInformationByKey(m_groupId);
}
void Group::init()
{
for (int serviceId : qAsConst(m_scheme->services))
{
if (m_serviceProcs.contains(serviceId))
continue;
ServiceProcess *proc = m_serviceDonator->getProcess(serviceId, m_groupData);
if (proc != nullptr)
{
connect(proc, &ServiceProcess::newServiceInformation,
this, &Group::onNewServiceInfo);
m_serviceProcs.insert(serviceId, proc);
}
}
}
bool Group::setRunningState(Core::RunningState newState)
{
INFO_LOG(m_logger) << "Setting RunningState of group "
<< m_scheme->groupType
<< " in exercisePartition "
<< m_groupData.exercisePartitionId()
<< ", replayPartition "
<< m_groupData.replayPartitionId()
<< " to "
<< newState;
switch (newState.underlying())
{
case Core::RunningState::Running:
case Core::RunningState::Starting:
// make sure all services are there
init();
for (ServiceProcess *serviceProc : qAsConst(m_serviceProcs))
serviceProc->start();
return true;
case Core::RunningState::StoppedNormally:
for (ServiceProcess *serviceProc : qAsConst(m_serviceProcs))
serviceProc->terminate();
return true;
default:
break;
}
return false;
}
void Group::startCore()
{
if (m_scheme->groupType != Core::ServiceGroupType::Core)
{
ERROR_LOG(m_logger) << "startCore() was invoked on a non Core Group object";
return;
}
DEBUG_LOG(m_logger) << "Starting Core";
// make sure all services are there
init();
// ExerciseManagement must be started ...
for (ServiceProcess *proc : qAsConst(m_serviceProcs))
{
if (proc->serviceName() == QLatin1String("ExerciseManagement"))
{
if ( proc->prio() == m_actPrio)
{
DEBUG_LOG(m_logger) << "startCore proc->start() "
<< proc->serviceName()
<< " prio=" << proc->prio()
<< " m_actPrio=" <<m_actPrio;
proc->start();
}
// waiting 15 secs for EXM startup
m_completeCoreTimeout = QDateTime::currentMSecsSinceEpoch() + 15000;
onCompleteCoreTick();
}
}
}
int Group::getNextPrio(QList <int> &prioList)
{
if ( m_actPrio == 0)
return -1;
std::sort(prioList.begin(), prioList.end());
for ( int i = 0; i < prioList.size(); i++)
{
if ( m_actPrio < prioList.at(i))
return prioList.at(i);
}
return 0;
}
void Group::start()
{
QList <int> prioList;
DEBUG_LOG(m_logger) << "Group::start() m_actPrio=" << m_actPrio
<< " groupId=" << m_groupId;
// make sure all services are there
init();
// get list of prio
for (ServiceProcess *proc : qAsConst(m_serviceProcs))
{
if ( !prioList.contains(proc->prio()))
{
DEBUG_LOG(m_logger) << "prioList.append " << proc->prio()
<< " m_actPrio=" << m_actPrio
<< " groupId=" << m_groupId;
prioList.append(proc->prio());
}
}
//if ( !prioList.contains(m_actPrio))
//{
// m_actPrio = getNextPrio(prioList);
//}
for (ServiceProcess *proc : qAsConst(m_serviceProcs))
{
if ( m_actPrio == proc->prio())
{
DEBUG_LOG(m_logger) << "Group::start(): proc->start() "
<< proc->serviceName()
<< " prio=" << proc->prio()
<< " m_actPrio=" << m_actPrio
<< " exId=" << proc->exercisePartitionId()
<< " lastHeartbeat=" << proc->lastHeartbeatMSec();
proc->start();
}
}
if ( m_actPrio > 0)
{
m_actPrio= getNextPrio(prioList);
QTimer::singleShot(1000, this, &Group::start);
}
}
void Group::stop()
{
for (ServiceProcess *proc : qAsConst(m_serviceProcs))
{
if (proc->state() != QProcess::NotRunning)
proc->stopFromRequest();
}
}
void Group::restart()
{
// make sure all services are there
init();
for (ServiceProcess *proc : qAsConst(m_serviceProcs))
proc->restart();
}
void Group::takeServicesFromGroup(Group *otherGroup)
{
auto otherServiceProcs = otherGroup->m_serviceProcs;
for (auto it = otherServiceProcs.begin(); it != otherServiceProcs.end(); ++it)
{
int serviceId = it.key();
// already there? -> skip
if (m_serviceProcs.contains(serviceId))
continue;
// not in our scheme? -> skip
if (!m_scheme->services.contains(serviceId))
continue;
ServiceProcess *proc = it.value();
// remove from otherGroup
otherGroup->m_serviceProcs.remove(serviceId);
proc->disconnect(otherGroup);
// add to ourself
m_serviceProcs.insert(serviceId, proc);
connect(proc, &ServiceProcess::newServiceInformation,
this, &Group::onNewServiceInfo);
}
}
Core::ServiceGroupType Group::type() const
{
return m_scheme->groupType;
}
qint64 Group::lastHeartbeatMSec() const
{
qint64 result = 0;
for (ServiceProcess *proc : m_serviceProcs)
{
if (proc->lastHeartbeatMSec() > result)
result = proc->lastHeartbeatMSec();
}
return result;
}
QMap<int, ServiceProcess *> Group::serviceProcs() const
{
return m_serviceProcs;
}
void Group::onNewServiceInfo()
{
if (m_elapsedTimer.elapsed() < 2 * 1000)
return;
m_elapsedTimer.start();
std::vector<int32_t> serviceIds;
serviceIds.reserve(m_serviceProcs.size());
for (ServiceProcess *proc : qAsConst(m_serviceProcs))
serviceIds.push_back(proc->serviceProcessId());
GroupInformation info(m_groupId,
lastHeartbeatMSec(),
m_scheme->groupType,
m_groupData.domainId(),
m_groupData.exercisePartitionId(),
m_groupData.replayPartitionId(),
serviceIds);
TRACE_LOG(m_logger) << "Publishing new GroupInformation: " << info;
m_ddsHandler->dts()->publish(info);
}
void Group::onCompleteCoreTick()
{
QList <int> prioList;
if (QDateTime::currentMSecsSinceEpoch() > m_completeCoreTimeout)
{
ERROR_LOG(m_logger) << "Could not start group Core, because no Heartbeat for EXM with RunningState 'Running' was received.";
return;
}
ServiceProcess *exmProc = nullptr;
// get EXM proc
for (ServiceProcess *proc : qAsConst(m_serviceProcs))
{
if (proc->serviceName() == QLatin1String("ExerciseManagement"))
{
exmProc = proc;
break;
}
}
if (exmProc == nullptr)
{
ERROR_LOG(m_logger) << "Could not find Process for EXM";
return;
}
// check if EXM got RunningState from Heartbeat
if (exmProc->runningState() == Core::RunningState::Running)
{
// get list of prio
for (ServiceProcess *proc : qAsConst(m_serviceProcs))
{
if ( !prioList.contains(proc->prio()))
{
DEBUG_LOG(m_logger) << "prioList.append " << proc->prio()
<< " m_actPrio=" << m_actPrio
<< " groupId=" << m_groupId;
prioList.append(proc->prio());
}
}
// start rest of group core
for (ServiceProcess *proc : qAsConst(m_serviceProcs))
{
if (proc->state() != QProcess::Running && proc->prio() == m_actPrio)
{
DEBUG_LOG(m_logger) << "onCompleteCoreTick proc->start() "
<< proc->serviceName()
<< " prio=" << proc->prio();
proc->start();
}
}
m_actPrio = getNextPrio(prioList);
if (-1 != m_actPrio)
{
QTimer::singleShot(1000, this, &Group::onCompleteCoreTick);
}
return;
}
else
DEBUG_LOG(m_logger) << "EXM has runningState " << exmProc->runningState();
// start next completion attemp
QTimer::singleShot(1000, this, &Group::onCompleteCoreTick);
}
ServiceProcess *Group::procFromPid(Q_PID pid)
{
for (ServiceProcess *proc :qAsConst(m_serviceProcs))
{
if (proc->pid() == pid)
return proc;
}
DEBUG_LOG(m_logger) << "Searched for not existing process with PID "
<< pid;
return nullptr;
}
bool Group::allProcsStopped() const
{
for (ServiceProcess *proc : m_serviceProcs)
{
if (proc->state() != QProcess::NotRunning)
return false;
}
return true;
}
} // namespace ServiceManagement