/** * 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 #include #include #include #include #include "group_handler.h" #include "service_handler.h" #include "service_process.h" #include "service_donator.h" #include namespace ServiceManagement { int32_t Group::s_idCounter = 0; Group::Group(const std::shared_ptr &ddsHandler, const std::shared_ptr &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=" <start(); } // waiting 15 secs for EXM startup m_completeCoreTimeout = QDateTime::currentMSecsSinceEpoch() + 15000; onCompleteCoreTick(); } } } int Group::getNextPrio(QList &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 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 Group::serviceProcs() const { return m_serviceProcs; } void Group::onNewServiceInfo() { if (m_elapsedTimer.elapsed() < 2 * 1000) return; m_elapsedTimer.start(); std::vector 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 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