From b492203429af1da799addae76999e835ebd2d57c Mon Sep 17 00:00:00 2001 From: Ruud Overeem <overeem@astron.nl> Date: Fri, 17 Jan 2014 11:04:09 +0000 Subject: [PATCH] Task #4480: MACScheduler calls 'free' of the claimmanager when an observation finishes or aborts. --- .gitattributes | 2 + .../MainCU/src/MACScheduler/CMakeLists.txt | 4 + .../MainCU/src/MACScheduler/MACScheduler.cc | 15 +- MAC/APL/MainCU/src/MACScheduler/ObsClaimer.cc | 35 +++- MAC/APL/MainCU/src/MACScheduler/ObsClaimer.h | 7 + MAC/APL/MainCU/src/MACScheduler/claimTest.cc | 156 ++++++++++++++++++ MAC/APL/MainCU/src/MACScheduler/claimTest.h | 70 ++++++++ .../include/APL/RTDBCommon/ClaimMgrTask.h | 3 + MAC/APL/RTDBCommon/src/ClaimMgrTask.cc | 77 +++++++-- 9 files changed, 347 insertions(+), 22 deletions(-) create mode 100644 MAC/APL/MainCU/src/MACScheduler/claimTest.cc create mode 100644 MAC/APL/MainCU/src/MACScheduler/claimTest.h diff --git a/.gitattributes b/.gitattributes index 8758b67450e..f1656326586 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2589,6 +2589,8 @@ MAC/APL/MainCU/src/CRTriggerControl/TriggerControl.h -text MAC/APL/MainCU/src/CRTriggerControl/TriggerControlMain.cc -text MAC/APL/MainCU/src/CRTriggerControl/crctl.cc -text MAC/APL/MainCU/src/CRTriggerControl/crctl.h -text +MAC/APL/MainCU/src/MACScheduler/claimTest.cc -text +MAC/APL/MainCU/src/MACScheduler/claimTest.h -text MAC/APL/MainCU/src/ObservationControl/ObservationControl.conf.in -text MAC/APL/PAC/Cal_Server/src/CS010C_HALF_positions.dat -text MAC/APL/PAC/Cal_Server/src/CS010C_positions.dat -text diff --git a/MAC/APL/MainCU/src/MACScheduler/CMakeLists.txt b/MAC/APL/MainCU/src/MACScheduler/CMakeLists.txt index 76a5c790621..cb70cfd7ff9 100644 --- a/MAC/APL/MainCU/src/MACScheduler/CMakeLists.txt +++ b/MAC/APL/MainCU/src/MACScheduler/CMakeLists.txt @@ -5,6 +5,10 @@ lofar_add_bin_program(MACScheduler MACScheduler.cc ObsClaimer.cc) +lofar_add_bin_program(claimTest + claimTest.cc + ObsClaimer.cc) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/MACScheduler.conf.in ${CMAKE_CURRENT_BINARY_DIR}/MACScheduler.conf) diff --git a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc index a49d30918a9..120af530645 100644 --- a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc +++ b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc @@ -195,7 +195,7 @@ GCFEvent::TResult MACScheduler::initial_state(GCFEvent& event, GCFPortInterface& case F_ENTRY: { // Get access to my own propertyset. - LOG_DEBUG_STR ("Activating my propertySet(" << PSN_MAC_SCHEDULER << ")"); + LOG_INFO_STR ("Activating my propertySet(" << PSN_MAC_SCHEDULER << ")"); itsPropertySet = new RTDBPropertySet(PSN_MAC_SCHEDULER, PST_MAC_SCHEDULER, PSAT_CW, @@ -234,7 +234,7 @@ GCFEvent::TResult MACScheduler::initial_state(GCFEvent& event, GCFPortInterface& string password = pParamSet->getString("OTDBpassword"); string hostname = pParamSet->getString("OTDBhostname"); - LOG_DEBUG_STR ("Trying to connect to the OTDB on " << hostname); + LOG_INFO_STR ("Trying to connect to the OTDB on " << hostname); itsOTDBconnection= new OTDBconnection(username, password, DBname, hostname); ASSERTSTR (itsOTDBconnection, "Memory allocation error (OTDB)"); ASSERTSTR (itsOTDBconnection->connect(), @@ -430,7 +430,7 @@ GCFEvent::TResult MACScheduler::active_state(GCFEvent& event, GCFPortInterface& case CONTROL_CONNECTED: { // The observationController has registered itself at childControl. CONTROLConnectedEvent conEvent(event); - LOG_DEBUG_STR(conEvent.cntlrName << " is connected, updating SAS)"); + LOG_INFO_STR(conEvent.cntlrName << " is connected, updating SAS)"); // Ok, controller is really up, update SAS so that obs will not appear in // in the SAS list again. @@ -494,6 +494,9 @@ GCFEvent::TResult MACScheduler::active_state(GCFEvent& event, GCFPortInterface& tm.setTreeState(theObs->second, tsc.get("aborted")); } + // free claimed observation in PVSS + itsClaimerTask->freeObservation(observationName(theObs->second)); + // update our administration LOG_INFO_STR("Removing observation " << quitedEvent.cntlrName << " from activeList"); itsControllerMap.erase(quitedEvent.cntlrName); @@ -658,7 +661,7 @@ void MACScheduler::_updatePlannedList() } else { // Claim a DP in PVSS and write obssettings to it so the operator can see it. - LOG_DEBUG_STR("Requesting preparation of PVSS for " << obsName); + LOG_INFO_STR("Requesting preparation of PVSS for " << obsName); itsClaimerTask->prepareObservation(obsName); itsPreparedObs[obsID] = schedInfo(modTime, false); // requested claim but no answer yet. } @@ -674,7 +677,7 @@ void MACScheduler::_updatePlannedList() // LOG_DEBUG_STR(obsName << " starts over " << timeBeforeStart << " seconds"); if (timeBeforeStart > 0 && timeBeforeStart <= (int)itsQueuePeriod) { if (itsPreparedObs[obsID].prepReady == false) { - LOG_ERROR_STR("Observation " << obsID << " must be started but is not claimed yet."); + LOG_INFO_STR("Observation " << obsID << " must be started but is not claimed yet."); } else { // starttime of observation lays in queuePeriod. Start the controller-chain, @@ -683,7 +686,7 @@ void MACScheduler::_updatePlannedList() // the observation will not be returned in the 'plannedDBlist' anymore. string cntlrName(controllerName(CNTLRTYPE_OBSERVATIONCTRL, 0, obsID)); if (itsControllerMap.find(cntlrName) == itsControllerMap.end()) { - LOG_DEBUG_STR("Requesting start of " << cntlrName); + LOG_INFO_STR("Requesting start of " << cntlrName); itsChildControl->startChild(CNTLRTYPE_OBSERVATIONCTRL, obsID, 0, // instanceNr diff --git a/MAC/APL/MainCU/src/MACScheduler/ObsClaimer.cc b/MAC/APL/MainCU/src/MACScheduler/ObsClaimer.cc index e85eb66dafe..35d7ad030bd 100644 --- a/MAC/APL/MainCU/src/MACScheduler/ObsClaimer.cc +++ b/MAC/APL/MainCU/src/MACScheduler/ObsClaimer.cc @@ -97,7 +97,7 @@ ObsClaimer::~ObsClaimer() } -// -------------------- The only public function -------------------- +// -------------------- The only two public function -------------------- // // prepareObservation(const string& observationName); // @@ -122,6 +122,29 @@ void ObsClaimer::prepareObservation(const string& observationName) itsHeartBeat->setTimer(0.0); } +// +// freeObservation(const string& observationName); +// +// Just add the observationname to our freeList and trigger main-loop. +void ObsClaimer::freeObservation(const string& observationName) +{ + OMiter iter = itsFreeMap.find(observationName); + if (iter == itsFreeMap.end()) { // new? + obsInfo* oldObs = new obsInfo(); + oldObs->obsName = observationName; + oldObs->state = OS_NEW; + itsFreeMap["LOFAR_ObsSW_"+observationName] = oldObs; + LOG_DEBUG_STR("Added observation " << observationName << " to the freeList"); + } + else { + LOG_DEBUG_STR("Observation " << observationName << " already in the freeList with state " << iter->second->state); + } + + // Wake up state-machine asap. + itsHeartBeat->cancelAllTimers(); + itsHeartBeat->setTimer(0.0); +} + // @@ -154,6 +177,16 @@ GCFEvent::TResult ObsClaimer::idle_state (GCFEvent& event, GCFPortInterface& por } ++iter; } + if (iter == end) { // nothing to claim. Something to free? + FMiter FreeIter = itsFreeMap.begin(); + FMiter FreeEnd = itsFreeMap.end(); + while (FreeIter != FreeEnd) { + itsClaimMgrTask->freeObject("Observation", "LOFAR_ObsSW_"+FreeIter->second->obsName); + // will not result in an event + ++FreeIter; + } + itsFreeMap.clear(); + } } break; diff --git a/MAC/APL/MainCU/src/MACScheduler/ObsClaimer.h b/MAC/APL/MainCU/src/MACScheduler/ObsClaimer.h index 4b2efec4dca..2d82212d08f 100644 --- a/MAC/APL/MainCU/src/MACScheduler/ObsClaimer.h +++ b/MAC/APL/MainCU/src/MACScheduler/ObsClaimer.h @@ -60,6 +60,9 @@ public: // ask the ObsClaimer to prepare the PVSS database for the given observation. void prepareObservation(const string& observationName); + // ask the ObsClaimer to release the claim on this observation DP + void freeObservation(const string& observationName); + private: // Connect to the PS of the claimManager GCFEvent::TResult connect2claimMgr_state (GCFEvent& e, GCFPortInterface& p); @@ -92,9 +95,13 @@ private: // ----- DATAMEMBERS ----- // admin for observations + // queue for claiming map<string, obsInfo*> itsObsMap; typedef map<string, obsInfo*>::iterator OMiter; OMiter itsCurrentObs; // Obs currently handled by claimMgr. + // queue for freeing + map<string, obsInfo*> itsFreeMap; + typedef map<string, obsInfo*>::iterator FMiter; ClaimMgrTask* itsClaimMgrTask; // Pointer to claimMgr. GCFITCPort* itsITCPort; // Answer back from CMtask. diff --git a/MAC/APL/MainCU/src/MACScheduler/claimTest.cc b/MAC/APL/MainCU/src/MACScheduler/claimTest.cc new file mode 100644 index 00000000000..03123f6e762 --- /dev/null +++ b/MAC/APL/MainCU/src/MACScheduler/claimTest.cc @@ -0,0 +1,156 @@ +//# claimtest.cc: tool for manually testing the obsClaimer task. +//# +//# Copyright (C) 2004-2012 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# $Id: claimTest.cc 27513 2013-11-26 14:49:20Z overeem $ +#include <lofar_config.h> +#include <Common/LofarLogger.h> +#include <Common/SystemUtil.h> +#include <Common/StringUtil.h> + +#include <GCF/TM/GCF_Protocols.h> +#include <MACIO/MACServiceInfo.h> +#include <GCF/PVSS/GCF_PVTypes.h> +#include <APL/APLCommon/APL_Defines.h> +#include <APL/APLCommon/ControllerDefines.h> +#include <GCF/RTDB/DP_Protocol.ph> +#include <APL/RTDBCommon/CM_Protocol.ph> +#include <signal.h> + +#include "claimTest.h" + +using namespace LOFAR::GCF::PVSS; +using namespace LOFAR::GCF::TM; +using namespace LOFAR::GCF::RTDB; +using namespace std; + +namespace LOFAR { + using namespace APLCommon; + namespace MainCU { + +// Global vars +bool gClaimIt; +string gObsName; + +// +// claimTest() +// +claimTest::claimTest() : + GCFTask ((State)&claimTest::initial_state,string("claimTest")), + itsClaimerTask (0), + itsClaimerPort (0), + itsTimerPort (0) +{ + // create an PVSSprepare Task + itsClaimerTask = new ObsClaimer(this); + ASSERTSTR(itsClaimerTask, "Cannot construct a ObsClaimerTask"); + itsClaimerPort = new GCFITCPort (*this, *itsClaimerTask, "ObsClaimerPort", GCFPortInterface::SAP, CM_PROTOCOL); + + // need port for timers + itsTimerPort = new GCFTimerPort(*this, "Timerport"); +} + + +// +// ~claimTest() +// +claimTest::~claimTest() +{ +} + +// +// initial_state(event, port) +// +// Setup all connections. +// +GCFEvent::TResult claimTest::initial_state(GCFEvent& event, GCFPortInterface& /*port*/) +{ + LOG_DEBUG_STR ("initial_state:" << eventName(event)); + + GCFEvent::TResult status = GCFEvent::HANDLED; + + switch (event.signal) { + case F_INIT: + break; + + case F_ENTRY: { + itsTimerPort->setTimer(5.0); + if (gClaimIt) { + itsClaimerTask->prepareObservation(gObsName); + } + else { + itsClaimerTask->freeObservation(gObsName); + } + } break; + + case CM_CLAIM_RESULT: { + // some observation was claimed by the claimMgr. Update our prepare_list. + CMClaimResultEvent cmEvent(event); + ltrim(cmEvent.nameInAppl, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"); + int obsID = atoi(cmEvent.nameInAppl.c_str()); + // claim was successful, update admin + cout << "Observation " << obsID << " is mapped to " << cmEvent.DPname << endl; + GCFScheduler::instance()->stop(); + } break; + + case F_TIMER: + cout << "TIMEOUT" << endl; + GCFScheduler::instance()->stop(); + break; + + default: + LOG_DEBUG("claimTest::active, default"); + status = GCFEvent::NOT_HANDLED; + break; + } + + return (status); +} + +}; // namespace MainCU +}; // namespace LOFAR + + +using namespace LOFAR::GCF::TM; +using namespace LOFAR::MainCU; +using namespace LOFAR::APLCommon; +using namespace LOFAR; + +int main(int argc, char* argv[]) +{ + if (argc != 3) { + cout << "Syntax: claimTest action name" << endl; + cout << " action: claim | free" << endl; + cout << " name: observationname" << endl; + return(-1); + } + cout << "######" << argv[1] << "#######" << endl; + gClaimIt = (strcmp(argv[1],"claim")==0); + gObsName = argv[2]; + + GCFScheduler::instance()->init(argc, argv, "claimTest"); + + claimTest cT; + cT.start(); // make initial transition + + GCFScheduler::instance()->run(); + + return 0; +} + diff --git a/MAC/APL/MainCU/src/MACScheduler/claimTest.h b/MAC/APL/MainCU/src/MACScheduler/claimTest.h new file mode 100644 index 00000000000..1019fcf30ed --- /dev/null +++ b/MAC/APL/MainCU/src/MACScheduler/claimTest.h @@ -0,0 +1,70 @@ +//# claimTest.h: Interface between MAC and SAS. +//# +//# Copyright (C) 2002-2004 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# $Id: claimTest.h 23213 2012-12-07 13:00:09Z loose $ + +#ifndef claimTest_H +#define claimTest_H + +//# GCF Includes +#include <MACIO/GCF_Event.h> +#include <GCF/TM/GCF_Control.h> + +//# Common Includes +#include <Common/lofar_string.h> +#include <Common/lofar_vector.h> +#include <Common/LofarLogger.h> + +#include "ObsClaimer.h" + +// forward declaration + +namespace LOFAR { + using MACIO::GCFEvent; + using GCF::TM::GCFTimerPort; + using GCF::TM::GCFITCPort; + using GCF::TM::GCFPort; + using GCF::TM::GCFPortInterface; + using GCF::TM::GCFTask; + namespace MainCU { + +class claimTest : public GCFTask +{ +public: + claimTest(); + ~claimTest(); + + // During the initial state all connections with the other programs are made. + GCFEvent::TResult initial_state (GCFEvent& e, GCFPortInterface& p); + +private: + // avoid copying + claimTest(const claimTest&); + claimTest& operator=(const claimTest&); + + // ----- DATA MEMBERS ----- + ObsClaimer* itsClaimerTask; + GCFITCPort* itsClaimerPort; + GCFTimerPort* itsTimerPort; // for timers +}; + + };//MainCU +};//LOFAR +#endif diff --git a/MAC/APL/RTDBCommon/include/APL/RTDBCommon/ClaimMgrTask.h b/MAC/APL/RTDBCommon/include/APL/RTDBCommon/ClaimMgrTask.h index 2fb9d8e2118..ad8bf96deeb 100644 --- a/MAC/APL/RTDBCommon/include/APL/RTDBCommon/ClaimMgrTask.h +++ b/MAC/APL/RTDBCommon/include/APL/RTDBCommon/ClaimMgrTask.h @@ -56,6 +56,9 @@ public: const string& nameInAppl, GCFPortInterface& replyPort); + // Ask the claimManager to flee an object. + void freeObject (const string& objectType, + const string& nameInAppl); private: enum { RO_UNDEFINED = 0, diff --git a/MAC/APL/RTDBCommon/src/ClaimMgrTask.cc b/MAC/APL/RTDBCommon/src/ClaimMgrTask.cc index 1c0cd0e14a7..93dc5009e2f 100644 --- a/MAC/APL/RTDBCommon/src/ClaimMgrTask.cc +++ b/MAC/APL/RTDBCommon/src/ClaimMgrTask.cc @@ -138,6 +138,38 @@ void ClaimMgrTask::claimObject(const string& objectType, // else: some other timer must be active. } +// +// freeObject(objectype, nameInAppl) +// +void ClaimMgrTask::freeObject(const string& objectType, + const string& nameInAppl) +{ + // not yet started yet? (user called us directly after creation) + if (itsResolveState==RO_UNDEFINED) { + itsRequestPool.push(cmRequest_t(objectType,nameInAppl,0)); + LOG_INFO_STR("freerequest '" << nameInAppl << "' queued because manager is still starting up"); + return; + } + + // are we in an idle state? + if (!itsObjectType.empty() || !itsNameInAppl.empty()) { + itsRequestPool.push(cmRequest_t(objectType,nameInAppl,0)); + LOG_INFO_STR("freerequest '" << nameInAppl << "' queued because manager is still busy with " << itsNameInAppl); + return; + } + + // save info + itsObjectType = objectType; + itsNameInAppl = nameInAppl; + itsReplyPort = 0; + LOG_INFO_STR("freerequest '" << nameInAppl << "' will be handled immediately"); + if (itsResolveState == RO_READY) { + itsTimerPort->setTimer(0.1); // wake up FSM + } + // else: some other timer must be active. +} + + // -------------------- INTERNAL FUNCTIONS -------------------- @@ -187,7 +219,7 @@ GCFEvent::TResult ClaimMgrTask::operational(GCFEvent& event, GCFPortInterface& p case RO_READY: // 4 if (itsObjectType.empty() || itsNameInAppl.empty()) { if (itsRequestPool.empty()) { - LOG_DEBUG_STR("Nothing to claim"); + LOG_DEBUG_STR("Nothing to claim or free"); break; } // continue with requests on the stack @@ -197,20 +229,35 @@ GCFEvent::TResult ClaimMgrTask::operational(GCFEvent& event, GCFPortInterface& p itsReplyPort = newRequest.replyPort; itsRequestPool.pop(); } - // request a DPname - LOG_INFO_STR("ClaimObject(" << itsObjectType << "," << itsNameInAppl << ")"); - itsClaimMgrPS->setValue("request.typeName", GCFPVString(itsObjectType), 0.0, false); - itsClaimMgrPS->setValue("request.newObjectName", GCFPVString(itsNameInAppl), 0.0, false); - // clear the answer also otherwise we will not be notified when asking the same question twice. - itsClaimMgrPS->setValue("response.DPName", GCFPVString(""), 0.0, false); - itsClaimMgrPS->setValue("response.newObjectName", GCFPVString(""), 0.0, false); - itsClaimMgrPS->flush(); - itsResolveState = RO_ASKED; // 3 - // clear result fields - itsFieldsReceived = 0; - itsResultDPname.clear(); - itsTimerPort->cancelAllTimers(); - itsTimerPort->setTimer(3.0); // don't wait forever. + // free request? + if (itsReplyPort == 0) { + LOG_INFO_STR("FreeObject(" << itsObjectType << "," << itsNameInAppl << ")"); + itsClaimMgrPS->setValue("reset.typeName", GCFPVString(itsObjectType), 0.0, false); + itsClaimMgrPS->setValue("reset.objectName", GCFPVString(itsNameInAppl), 0.0, false); + itsClaimMgrPS->flush(); + // stay in current (idle) mode + itsObjectType.clear(); + itsNameInAppl.clear(); + itsResultDPname.clear(); + itsTimerPort->cancelAllTimers(); + itsTimerPort->setTimer(0.1); // hop to next request. + } + else { + // request a DPname + LOG_INFO_STR("ClaimObject(" << itsObjectType << "," << itsNameInAppl << ")"); + itsClaimMgrPS->setValue("request.typeName", GCFPVString(itsObjectType), 0.0, false); + itsClaimMgrPS->setValue("request.newObjectName", GCFPVString(itsNameInAppl), 0.0, false); + // clear the answer also otherwise we will not be notified when asking the same question twice. + itsClaimMgrPS->setValue("response.DPName", GCFPVString(""), 0.0, false); + itsClaimMgrPS->setValue("response.newObjectName", GCFPVString(""), 0.0, false); + itsClaimMgrPS->flush(); + itsResolveState = RO_ASKED; // 3 + // clear result fields + itsFieldsReceived = 0; + itsResultDPname.clear(); + itsTimerPort->cancelAllTimers(); + itsTimerPort->setTimer(3.0); // don't wait forever. + } break; case RO_ASKED: // 3 -- GitLab