378 lines
9.7 KiB
C++
Executable File
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
|