/** * @RDE_HEADER@ * Data Plugin for InfrastructureManagement * $Id$ * $HeadURL$ * $Author$ * * Created by Mike Wille, SLSE, 2016-08-24 */ #include "ism_foreign_data_plugin.h" #include #include #include #include #include #include #include #include #include // #ifdef LTS_DEBUG # define BENCHMARK // #endif // LTS_DEBUG #ifdef BENCHMARK # define BENCHMARK_SETUP_AND_START() QElapsedTimer elapsedTimer; elapsedTimer.start(); # define BENCHMARK_RUN #else # define BENCHMARK_SETUP_AND_START() #endif namespace InfrastructureManagement { ForeignInterfaceImpl::ForeignInterfaceImpl(const std::shared_ptr &dtc, int exerciseId) : m_dtc(dtc) , m_scheduleId(-1) , m_exerciseId(exerciseId) , m_logger(getLogger("ForeignDataInterface")) { // init() ; lazy-initialisation : moved to enableIsmForeignInterface. } ForeignInterfaceImpl::~ForeignInterfaceImpl() { } void ForeignInterfaceImpl::enableIsmForeignInterface() const { BENCHMARK_SETUP_AND_START(); if (!m_mountingPoints.isEmpty()) { DEBUG_LOG(m_logger) << LOGFUNCTION << " START, ismDataDtc, m_exerciseId = " << m_exerciseId << " already initialized -> return"; return; } // cast const away: ForeignInterfaceImpl *NON_CONST_THIS = const_cast(this); NON_CONST_THIS->init(); #ifdef BENCHMARK_RUN NOTICE_LOG(m_logger) << LOGFUNCTION << " ISM::StructureElementCache / ForeignInterfaceImpl::init took " << elapsedTimer.elapsed() << " [ms]" << " - m_exerciseId = " << m_exerciseId << " - m_mountingPoints.size()=" << m_mountingPoints.size() << ", (m_mountingPointAssetMap.size()=" << m_mountingPointAssetMap.size() << ")"; #endif // BENCHMARK_RUN } bool ForeignInterfaceImpl::mountingPoints(const std::function &cb) { BENCHMARK_SETUP_AND_START(); enableIsmForeignInterface(); for (auto it = m_mountingPoints.constBegin(); it != m_mountingPoints.constEnd(); ++it) cb(it.value()); #ifdef BENCHMARK_RUN NOTICE_LOG(m_logger) << LOGFUNCTION << " - m_exerciseId = " << m_exerciseId << " - m_mountingPoints.size()=" << m_mountingPoints.size() << " took " << elapsedTimer.elapsed() << " [ms]"; #else NOTICE_LOG(m_logger) << LOGFUNCTION << " - m_exerciseId = " << m_exerciseId << " - m_mountingPoints.size()=" << m_mountingPoints.size(); #endif // BENCHMARK_RUN return true; } bool ForeignInterfaceImpl::mountingPoints(const std::function &cb) { enableIsmForeignInterface(); for (auto it = m_mountingPoints.constBegin(); it != m_mountingPoints.constEnd(); ++it) if (cb(it.value())) return true; return false; } QHash ForeignInterfaceImpl::mountingPoints() const { enableIsmForeignInterface(); return m_mountingPoints; } MountingPoint ForeignInterfaceImpl::mountingPoint(int32_t mountingPointId) const { enableIsmForeignInterface(); return m_mountingPoints.value(mountingPointId); } MainSchedule ForeignInterfaceImpl::mainSchedule(int32_t scheduleId) { enableIsmForeignInterface(); return m_dtc->mainSchedule(scheduleId); } void ForeignInterfaceImpl::setScheduleId(int32_t scheduleId) { DEBUG_LOG(m_logger) << "setScheduleId to: " << scheduleId << " (was " << m_scheduleId << ")"; enableIsmForeignInterface(); m_scheduleId = scheduleId; onMainScheduleChanged(m_dtc->mainSchedule(scheduleId), DataModification::eModified); emit scheduleIdChanged(m_scheduleId); } int32_t ForeignInterfaceImpl::scheduleId() const { return m_scheduleId; } QSet ForeignInterfaceImpl::buildingsInCurrentExercise() { enableIsmForeignInterface(); return m_bldgsInExcersise; } const QSet& ForeignInterfaceImpl::buildingsInCurrentExercise() const { enableIsmForeignInterface(); return m_bldgsInExcersise; } bool ForeignInterfaceImpl::isBuildingsInCurrentExercise(int buildingId) const { enableIsmForeignInterface(); return m_bldgsInExcersise.contains(buildingId); } void ForeignInterfaceImpl::onMainStructureElementChanged(const MainStructureElement &data, DataModification modType) { const int mseId = data.id(); switch (modType) { case DataModification::eRemoved: { QMutexLocker locker(&m_mutex); const auto &structureElements = data.elements(); for (const StructureElement ¤tStructEle : structureElements) { if (currentStructEle.structureElementTypeId() != StructureElementType::MountingPoint) continue; m_mountingPoints.remove(currentStructEle.id()); } break; } case DataModification::eAdded: case DataModification::eModified: { QVector exeIds; // read only once properties - available_in_exercise from MSE, only if exerciseId is relevant if (m_exerciseId > 0) { QJsonParseError parserError; const QByteArray &content = QByteArray::fromStdString(data.properties()); const QJsonDocument doc(QJsonDocument::fromJson(content, &parserError)); if (parserError.error != QJsonParseError::NoError) WARNING_LOG(m_logger) << "Invalid properties for MSE " << data.id() << ", " << data.name(); else { const QJsonArray exercises(QJsonObject(doc.object()).value(QStringLiteral("available_in_exercise")).toArray()); exeIds.reserve(exercises.size()); for (const auto &exercise : exercises) exeIds += exercise.toInt(); } } // update m_bldgsInExcersise { bool realChange = false; { QMutexLocker locker(&m_mutex); if (exeIds.contains(m_exerciseId) || (m_exerciseId == 0) // global -> processAll ) { if (!m_bldgsInExcersise.contains(mseId)) { m_bldgsInExcersise.insert(mseId); realChange = true; } } else { if (m_bldgsInExcersise.contains(mseId)) { m_bldgsInExcersise.remove(mseId); realChange = true; } } } // scope for mutex // Maybe an MSE/building is added/removed? if (realChange) { // ensure map object will be created DEBUG_LOG(m_logger) << LOGFUNCTION << " m_bldgsInExcersise updated." << " (mseId=" << mseId << " name=" << data.name(); emit buildingsInCurrentExerciseChanged(); } } // N. Thoden, 11.01.2022: // reduce amount of data by filtering m_exerciseId / available_in_exercise // (may otherwise took up to ~10 seconds!!) // m_exerciseId <= 0 -> process all if (m_exerciseId == 0 || (m_exerciseId > 0 && exeIds.contains(m_exerciseId))) { const auto &structureElements = data.elements(); for (const StructureElement ¤tStructEle : structureElements) { if (currentStructEle.structureElementTypeId() != StructureElementType::MountingPoint) continue; StructureElement seFloor; const std::vector &curPath = currentStructEle.path(); if (curPath.size() == 4) { // GUEZE-3258: Performance-Untersuchung der OpApp : getStructureElementById is expensive // 500 bldgs, ~25000 structure element -> init() can took 2500ms (CTCAP28) if (!m_dtc->getStructureElementById(curPath[1], seFloor)) // getStructureElementById is expensive if many buildings/structure elements WARNING_LOG(m_logger) << " getStructureElementById failed for " << curPath[1]; } const int floorId = QString::fromStdString(seFloor.name()).split(QStringLiteral("_")).value(1, QStringLiteral("-10")).toInt(); { QMutexLocker locker(&m_mutex); // GUEZE-3258: Performance-Untersuchung der OpApp const auto it = m_mountingPoints.find(currentStructEle.id()); if (it != m_mountingPoints.end()) { MountingPoint &mountingPointRef = *it; if (mountingPointRef.data() == currentStructEle) continue; mountingPointRef.updateData(currentStructEle, floorId); emit mountingPointChanged(mountingPointRef, DataModification::eModified); } else { DEBUG_LOG(m_logger) << "New Mounting point with id " << currentStructEle.id() << " and type " << currentStructEle.mountingPointTypeId() << " (type " << currentStructEle.mountingPointTypeId().underlying() << ")" << " subid: " << currentStructEle.mountingPointId() << this; MountingPoint newMountingPoint(currentStructEle, floorId); const int assetId = m_mountingPointAssetMap.value(newMountingPoint.id(), -1); newMountingPoint.setAssociatedAssetId(assetId); // newMountingPoint->setHasAssociatedAssetDefect(); // TODO m_mountingPoints.insert(newMountingPoint.id(), newMountingPoint); emit mountingPointChanged(newMountingPoint, DataModification::eAdded); } // if (it != m_mountingPoints.end()) } } } break; } } // switch } void ForeignInterfaceImpl::onMountingPointAssetChanged(const MountingPointAsset &data, DataModification modType) { const int32_t structureElementId = data.structureElementId(); DEBUG_LOG(m_logger) << "onMountingPointAssetChanged se id: " << structureElementId << ", assetId: " << data.assetId(); // [GUEZE-3494] Ressourcenverwaltung ist fehlerhaft laut Kunden // QHash: // value() -> return const T // operator[] -> return T & // // MountingPoint mp = m_mountingPoints.value(structureElementId); MountingPoint &mpRef = m_mountingPoints[structureElementId]; // default constructed value may okay if (modType == DataModification::eRemoved) { m_mountingPointAssetMap.remove(structureElementId); if (mpRef.id() > 0) { mpRef.setAssociatedAssetId(-1); mpRef.setHasAssociatedAssetDefect(false); } } else { m_mountingPointAssetMap.insert(structureElementId, data.assetId()); if (mpRef.id() > 0) { mpRef.setAssociatedAssetId(data.assetId()); mpRef.setHasAssociatedAssetDefect(m_dtc->instrumentationAsset(data.assetId()).assetStateId() == InstrumentationAssetState::Defect); } } if (mpRef.id() > 0) emit mountingPointChanged(mpRef, DataModification::eModified); } void ForeignInterfaceImpl::onMainScheduleChanged(const MainSchedule &data, DataModification modType) { if (m_scheduleId != data.id()) return; Q_UNUSED(modType); QHash mppMap; for (const auto &elem : data.elements()) mppMap[elem.structureElementId()] = elem; for (MountingPoint &mp : m_mountingPoints) { const MountingPointPlan &mpp = mppMap[mp.id()]; const MountingPointState &mps = mpp.mountingPointState(); // If there is no MPP for this Schedule if(mpp.structureElementId() != mp.id()) { // Do nothing if idle if (mp.aimState() == MountingPointState_def::Idle) continue; mp.setAimState(MountingPointState::Idle); emit mountingPointChanged(mp, DataModification::eModified); continue; } // If AimState did not change, continue if (mp.aimState() == mps) continue; mp.setAimState(mps); emit mountingPointChanged(mp, DataModification::eModified); } } void ForeignInterfaceImpl::init() { DEBUG_LOG(m_logger) << LOGFUNCTION << " START, ismDataDtc, m_exerciseId = " << m_exerciseId << " - m_mountingPoints.size()=" << m_mountingPoints.size() << ", (m_mountingPointAssetMap.size()=" << m_mountingPointAssetMap.size() << ")"; m_dtc->waitForHistoricalDataMainStructureElement(1000); // enable is implicit m_dtc->waitForHistoricalDataMainSchedule(1000); // enable is implicit m_dtc->waitForHistoricalDataMountingPointAsset(1000); // enable is implicit connect(m_dtc.get(), &Interface::Dtc::mainStructureElementChanged, this, &ForeignInterfaceImpl::onMainStructureElementChanged, Qt::UniqueConnection); connect(m_dtc.get(), &Interface::Dtc::mainScheduleChanged, this, &ForeignInterfaceImpl::onMainScheduleChanged, Qt::UniqueConnection); connect(m_dtc.get(), &Interface::Dtc::mountingPointAssetChanged, this, &ForeignInterfaceImpl::onMountingPointAssetChanged, Qt::UniqueConnection); // // #define PROCESS_MSE_SEQUENTIELL #ifdef PROCESS_MSE_SEQUENTIELL m_dtc->mainStructureElements([this](const MainStructureElement &data) { onMainStructureElementChanged(data, DataModification::eAdded); }); #else // 25.10.2022, Norbert Thoden: // ForeignInterfaceImpl::init() benoetigt ca. 5sec at CTCAP15 // Durch Parallelisierung reduziert es sich auf knapp 2sec. :-) // via std::bind: // using namespace std::placeholders; // std::function functor = // std::bind(&ForeignInterfaceImpl::onMseChangedForInitializing, this, _1); // QtConcurrent::blockingMap(mseMap, functor); // Es geht aber auch einfacher per lambda :-) const QMap &mseMap = m_dtc->mainStructureElements(); m_mountingPoints.reserve(mseMap.size()); // blockingMap -> functor will be applied to every item: QtConcurrent::blockingMap(mseMap, [this](const MainStructureElement &data) { onMainStructureElementChanged(data, DataModification::eAdded); }); #endif // PROCESS_MSE_SEQUENTIELL m_dtc->mountingPointAssets([this](const MountingPointAsset &data) { onMountingPointAssetChanged(data, DataModification::eAdded); }); m_dtc->mainSchedules([this](const MainSchedule &data) { onMainScheduleChanged(data, DataModification::eAdded); }); int firstBldg = -1; if (!m_bldgsInExcersise.isEmpty()) firstBldg = *m_bldgsInExcersise.begin(); DEBUG_LOG(m_logger) << LOGFUNCTION << ", exerciseId = " << m_exerciseId << ", bldgs in excersise = " << m_bldgsInExcersise.size() << ", firstBldg: " << firstBldg; DEBUG_LOG(m_logger) << LOGFUNCTION << "XXXXX" << m_bldgsInExcersise.size(); DEBUG_LOG(m_logger) << LOGFUNCTION << " END, ismDataDtc, m_exerciseId = " << m_exerciseId << " - m_mountingPoints.size()=" << m_mountingPoints.size() << ", (m_mountingPointAssetMap.size()=" << m_mountingPointAssetMap.size() << ")"; } } // namespace InfrastructureManagement