3 #define TRACEMF_USE_VERBATIM 1
4 #include "otsdaq/ARTDAQSupervisor/ARTDAQSupervisor.hh"
6 #include "artdaq-core/Utilities/configureMessageFacility.hh"
7 #include "artdaq/BuildInfo/GetPackageBuildInfo.hh"
8 #include "artdaq/DAQdata/Globals.hh"
9 #include "artdaq/ExternalComms/MakeCommanderPlugin.hh"
10 #include "cetlib_except/exception.h"
11 #include "fhiclcpp/make_ParameterSet.h"
12 #include "otsdaq/ARTDAQSupervisor/ARTDAQSupervisorTRACEController.h"
14 #include "artdaq-core/Utilities/ExceptionHandler.hh"
16 #include <boost/exception/all.hpp>
17 #include <boost/filesystem.hpp>
26 #define FAKE_CONFIG_NAME "ots_config"
27 #define DAQINTERFACE_PORT \
28 std::atoi(__ENV__("ARTDAQ_BASE_PORT")) + \
29 (partition_ * std::atoi(__ENV__("ARTDAQ_PORTS_PER_PARTITION")))
32 static std::unordered_map<int, struct sigaction> old_actions =
33 std::unordered_map<int, struct sigaction>();
34 static bool sighandler_init =
false;
35 static void signal_handler(
int signum)
38 #if TRACE_REVNUM < 1459
39 TRACE_STREAMER(TLVL_ERROR, &(
"ARTDAQsupervisor")[0], 0, 0, 0)
41 TRACE_STREAMER(TLVL_ERROR, TLOG2(
"ARTDAQsupervisor", 0), 0)
43 <<
"A signal of type " << signum
44 <<
" was caught by ARTDAQSupervisor. Shutting down DAQInterface, "
45 "then proceeding with default handlers!";
51 pthread_sigmask(SIG_UNBLOCK, NULL, &set);
52 pthread_sigmask(SIG_UNBLOCK, &set, NULL);
54 #if TRACE_REVNUM < 1459
55 TRACE_STREAMER(TLVL_ERROR, &(
"ARTDAQsupervisor")[0], 0, 0, 0)
57 TRACE_STREAMER(TLVL_ERROR, TLOG2(
"ARTDAQsupervisor", 0), 0)
59 <<
"Calling default signal handler";
62 sigaction(signum, &old_actions[signum], NULL);
63 kill(getpid(), signum);
69 sigaction(SIGINT, &old_actions[SIGINT], NULL);
70 kill(getpid(), SIGINT);
76 static std::mutex sighandler_mutex;
77 std::unique_lock<std::mutex> lk(sighandler_mutex);
81 sighandler_init =
true;
83 std::vector<int> signals = {
94 for(
auto signal : signals)
96 struct sigaction old_action;
97 sigaction(signal, NULL, &old_action);
101 if(old_action.sa_handler != SIG_IGN)
103 struct sigaction action;
104 action.sa_handler = signal_handler;
105 sigemptyset(&action.sa_mask);
106 for(
auto sigblk : signals)
108 sigaddset(&action.sa_mask, sigblk);
114 sigaction(signal, &action, NULL);
115 old_actions[signal] = old_action;
122 ARTDAQSupervisor::ARTDAQSupervisor(xdaq::ApplicationStub* stub)
124 , daqinterface_ptr_(NULL)
125 , partition_(getSupervisorProperty(
"partition", 0))
126 , daqinterface_state_(
"notrunning")
127 , runner_thread_(nullptr)
129 __SUP_COUT__ <<
"Constructor." << __E__;
132 init_sighandler(
this);
139 auto settings_file = __ENV__(
"DAQINTERFACE_SETTINGS");
140 std::ofstream o(settings_file, std::ios::trunc);
142 setenv(
"DAQINTERFACE_PARTITION_NUMBER", std::to_string(partition_).c_str(), 1);
143 auto logfileName = std::string(__ENV__(
"OTSDAQ_LOG_DIR")) +
144 "/DAQInteface/DAQInterface_partition" +
145 std::to_string(partition_) +
".log";
146 setenv(
"DAQINTERFACE_LOGFILE", logfileName.c_str(), 1);
148 o <<
"log_directory: "
149 << getSupervisorProperty(
"log_directory", std::string(__ENV__(
"OTSDAQ_LOG_DIR")))
153 const std::string record_directory = getSupervisorProperty(
154 "record_directory", ARTDAQTableBase::ARTDAQ_FCL_PATH +
"/run_records/");
155 mkdir(record_directory.c_str(), 0755);
156 o <<
"record_directory: " << record_directory << std::endl;
159 o <<
"package_hashes_to_save: "
160 << getSupervisorProperty(
"package_hashes_to_save",
"[artdaq]") << std::endl;
162 o <<
"spack_root_for_bash_scripts: "
163 << getSupervisorProperty(
"spack_root_for_bash_scripts",
164 std::string(__ENV__(
"SPACK_ROOT")))
166 o <<
"boardreader timeout: " << getSupervisorProperty(
"boardreader_timeout", 30)
168 o <<
"eventbuilder timeout: " << getSupervisorProperty(
"eventbuilder_timeout", 30)
170 o <<
"datalogger timeout: " << getSupervisorProperty(
"datalogger_timeout", 30)
172 o <<
"dispatcher timeout: " << getSupervisorProperty(
"dispatcher_timeout", 30)
175 if(!getSupervisorProperty(
"advanced_memory_usage",
false))
177 o <<
"max_fragment_size_bytes: "
178 << getSupervisorProperty(
"max_fragment_size_bytes", 1048576) << std::endl;
180 o <<
"transfer_plugin_to_use: "
181 << getSupervisorProperty(
"transfer_plugin_to_use",
"TCPSocket") << std::endl;
182 if(getSupervisorProperty(
"transfer_plugin_from_brs",
"") !=
"")
184 o <<
"transfer_plugin_from_brs: "
185 << getSupervisorProperty(
"transfer_plugin_from_brs",
"") << std::endl;
187 if(getSupervisorProperty(
"transfer_plugin_from_ebs",
"") !=
"")
189 o <<
"transfer_plugin_from_ebs: "
190 << getSupervisorProperty(
"transfer_plugin_from_ebs",
"") << std::endl;
192 if(getSupervisorProperty(
"transfer_plugin_from_dls",
"") !=
"")
194 o <<
"transfer_plugin_from_dls: "
195 << getSupervisorProperty(
"transfer_plugin_from_dls",
"") << std::endl;
197 o <<
"all_events_to_all_dispatchers: " << std::boolalpha
198 << getSupervisorProperty(
"all_events_to_all_dispatchers",
true) << std::endl;
199 o <<
"data_directory_override: "
200 << getSupervisorProperty(
"data_directory_override",
201 std::string(__ENV__(
"ARTDAQ_OUTPUT_DIR")))
203 o <<
"max_configurations_to_list: "
204 << getSupervisorProperty(
"max_configurations_to_list", 10) << std::endl;
205 o <<
"disable_unique_rootfile_labels: "
206 << getSupervisorProperty(
"disable_unique_rootfile_labels",
false) << std::endl;
207 o <<
"use_messageviewer: " << std::boolalpha
208 << getSupervisorProperty(
"use_messageviewer",
false) << std::endl;
209 o <<
"use_messagefacility: " << std::boolalpha
210 << getSupervisorProperty(
"use_messagefacility",
true) << std::endl;
211 o <<
"fake_messagefacility: " << std::boolalpha
212 << getSupervisorProperty(
"fake_messagefacility",
false) << std::endl;
213 o <<
"kill_existing_processes: " << std::boolalpha
214 << getSupervisorProperty(
"kill_existing_processes",
true) << std::endl;
215 o <<
"advanced_memory_usage: " << std::boolalpha
216 << getSupervisorProperty(
"advanced_memory_usage",
false) << std::endl;
217 o <<
"strict_fragment_id_mode: " << std::boolalpha
218 << getSupervisorProperty(
"strict_fragment_id_mode",
false) << std::endl;
219 o <<
"disable_private_network_bookkeeping: " << std::boolalpha
220 << getSupervisorProperty(
"disable_private_network_bookkeeping",
false) << std::endl;
221 o <<
"allowed_processors: " << getSupervisorProperty(
"allowed_processors",
"0-255")
228 if(CorePropertySupervisorBase::theTRACEController_)
230 __SUP_COUT__ <<
"Destroying TRACE Controller..." << __E__;
231 delete CorePropertySupervisorBase::
233 CorePropertySupervisorBase::theTRACEController_ =
nullptr;
235 CorePropertySupervisorBase::theTRACEController_ =
238 ->setSupervisorPtr(
this);
240 __SUP_COUT__ <<
"Constructed." << __E__;
244 ARTDAQSupervisor::~ARTDAQSupervisor(
void)
246 __SUP_COUT__ <<
"Destructor." << __E__;
248 __SUP_COUT__ <<
"Destructed." << __E__;
252 void ARTDAQSupervisor::destroy(
void)
254 __SUP_COUT__ <<
"Destroying..." << __E__;
256 if(daqinterface_ptr_ != NULL)
258 __SUP_COUT__ <<
"Calling recover transition" << __E__;
259 std::lock_guard<std::recursive_mutex> lk(daqinterface_mutex_);
260 PyObject* pName = PyUnicode_FromString(
"do_recover");
261 PyObject_CallMethodObjArgs(
262 daqinterface_ptr_, pName, NULL);
264 __SUP_COUT__ <<
"Making sure that correct state has been reached" << __E__;
266 while(daqinterface_state_ !=
"stopped")
269 __SUP_COUT__ <<
"State is " << daqinterface_state_
270 <<
", waiting 1s and retrying..." << __E__;
274 Py_XDECREF(daqinterface_ptr_);
275 daqinterface_ptr_ = NULL;
283 __SUP_COUT__ <<
"Destroying TRACE Controller..." << __E__;
288 __SUP_COUT__ <<
"Destroyed." << __E__;
292 void ARTDAQSupervisor::init(
void)
296 __SUP_COUT__ <<
"Initializing..." << __E__;
298 std::lock_guard<std::recursive_mutex> lk(daqinterface_mutex_);
301 artdaq::configureMessageFacility(
"ARTDAQSupervisor");
302 __SUP_COUT__ <<
"artdaq MF configured." << __E__;
305 char* daqinterface_dir = getenv(
"ARTDAQ_DAQINTERFACE_DIR");
306 if(daqinterface_dir == NULL)
308 __SS__ <<
"ARTDAQ_DAQINTERFACE_DIR environment variable not set! This "
309 "means that DAQInterface has not been setup!"
315 __SUP_COUT__ <<
"Initializing Python" << __E__;
318 __SUP_COUT__ <<
"Adding DAQInterface directory to PYTHON_PATH" << __E__;
319 PyObject* sysPath = PySys_GetObject((
char*)
"path");
320 PyObject* programName = PyUnicode_FromString(daqinterface_dir);
321 PyList_Append(sysPath, programName);
322 Py_DECREF(programName);
324 __SUP_COUT__ <<
"Creating Module name" << __E__;
325 PyObject* pName = PyUnicode_FromString(
"rc.control.daqinterface");
328 __SUP_COUT__ <<
"Importing module" << __E__;
329 PyObject* pModule = PyImport_Import(pName);
335 __SS__ <<
"Failed to load rc.control.daqinterface" << __E__;
340 __SUP_COUT__ <<
"Loading python module dictionary" << __E__;
341 PyObject* pDict = PyModule_GetDict(pModule);
345 __SS__ <<
"Unable to load module dictionary" << __E__;
352 __SUP_COUT__ <<
"Getting DAQInterface object pointer" << __E__;
353 PyObject* di_obj_ptr = PyDict_GetItemString(pDict,
"DAQInterface");
355 __SUP_COUT__ <<
"Filling out DAQInterface args struct" << __E__;
356 PyObject* pArgs = PyTuple_New(0);
358 PyObject* kwargs = Py_BuildValue(
"{s:s, s:s, s:i, s:i, s:s, s:s}",
372 __SUP_COUT__ <<
"Calling DAQInterface Object Constructor" << __E__;
373 daqinterface_ptr_ = PyObject_Call(di_obj_ptr, pArgs, kwargs);
375 Py_DECREF(di_obj_ptr);
403 __SUP_COUT__ <<
"Initialized." << __E__;
407 void ARTDAQSupervisor::transitionConfiguring(toolbox::Event::Reference )
409 __SUP_COUT__ <<
"transitionConfiguring" << __E__;
412 if(RunControlStateMachine::getIterationIndex() == 0 &&
413 RunControlStateMachine::getSubIterationIndex() == 0)
415 thread_error_message_ =
"";
416 thread_progress_bar_.resetProgressBar(0);
417 last_thread_progress_update_ = time(0);
420 SOAPUtilities::translate(theStateMachine_.getCurrentMessage())
422 .getValue(
"ConfigurationTableGroupName"),
423 TableGroupKey(SOAPUtilities::translate(theStateMachine_.getCurrentMessage())
425 .getValue(
"ConfigurationTableGroupKey")));
427 __SUP_COUT__ <<
"Configuration table group name: " << theGroup.first
428 <<
" key: " << theGroup.second << __E__;
446 ConfigurationManager::LoadGroupType::ALL_TYPES,
449 catch(
const std::runtime_error& e)
451 __SS__ <<
"Error loading table group '" << theGroup.first <<
"("
452 << theGroup.second <<
")! \n"
453 << e.what() << __E__;
454 __SUP_COUT_ERR__ << ss.str();
458 theStateMachine_.setErrorMessage(ss.str());
459 throw toolbox::fsm::exception::Exception(
462 "ARTDAQSupervisor::transitionConfiguring" ,
469 __SS__ <<
"Unknown error loading table group '" << theGroup.first <<
"("
470 << theGroup.second <<
")!" << __E__;
471 __SUP_COUT_ERR__ << ss.str();
475 theStateMachine_.setErrorMessage(ss.str());
476 throw toolbox::fsm::exception::Exception(
479 "ARTDAQSupervisor::transitionConfiguring" ,
486 std::thread(&ARTDAQSupervisor::configuringThread,
this).detach();
488 __SUP_COUT__ <<
"Configuring thread started." << __E__;
490 RunControlStateMachine::
491 indicateIterationWork();
495 std::string errorMessage;
497 std::lock_guard<std::mutex> lock(
499 errorMessage = thread_error_message_;
501 int progress = thread_progress_bar_.
read();
502 __SUP_COUTV__(errorMessage);
503 __SUP_COUTV__(progress);
504 __SUP_COUTV__(thread_progress_bar_.
isComplete());
507 if(errorMessage ==
"" &&
508 time(0) - last_thread_progress_update_ > 600)
510 __SUP_SS__ <<
"There has been no update from the configuration thread for "
511 << (time(0) - last_thread_progress_update_)
512 <<
" seconds, assuming something is wrong and giving up! "
513 <<
"Last progress received was " << progress << __E__;
514 errorMessage = ss.str();
517 if(errorMessage !=
"")
519 __SUP_SS__ <<
"Error was caught in configuring thread: " << errorMessage
521 __SUP_COUT_ERR__ <<
"\n" << ss.str();
523 theStateMachine_.setErrorMessage(ss.str());
524 throw toolbox::fsm::exception::Exception(
527 "CoreSupervisorBase::transitionConfiguring" ,
535 RunControlStateMachine::
536 indicateIterationWork();
538 if(last_thread_progress_read_ != progress)
540 last_thread_progress_read_ = progress;
541 last_thread_progress_update_ = time(0);
548 __SUP_COUT_INFO__ <<
"Complete configuring transition!" << __E__;
549 __SUP_COUTV__(getProcessInfo_());
557 void ARTDAQSupervisor::configuringThread()
560 std::string uid = theConfigurationManager_
561 ->
getNode(ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME +
562 "/" + CorePropertySupervisorBase::getSupervisorUID() +
563 "/" +
"LinkToSupervisorTable")
566 __COUT__ <<
"Supervisor uid is " << uid <<
", getting supervisor table node" << __E__;
568 const std::string mfSubject_ = supervisorClassNoNamespace_ +
"-" + uid;
572 thread_progress_bar_.
step();
574 set_thread_message_(
"ConfigGen");
576 auto info = ARTDAQTableBase::extractARTDAQInfo(
580 getSupervisorProperty(
"max_fragment_size_bytes", 8888),
581 getSupervisorProperty(
"routing_timeout_ms", 1999),
582 getSupervisorProperty(
"routing_retry_count", 12),
583 &thread_progress_bar_);
586 if(info.processes.count(ARTDAQTableBase::ARTDAQAppType::BoardReader) == 0)
588 __GEN_SS__ <<
"There must be at least one enabled BoardReader!" << __E__;
592 if(info.processes.count(ARTDAQTableBase::ARTDAQAppType::EventBuilder) == 0)
594 __GEN_SS__ <<
"There must be at least one enabled EventBuilder!" << __E__;
599 thread_progress_bar_.
step();
600 set_thread_message_(
"Writing boot.txt");
602 __GEN_COUT__ <<
"Writing boot.txt" << __E__;
604 int debugLevel = theSupervisorNode.
getNode(
"DAQInterfaceDebugLevel").
getValue<
int>();
605 std::string setupScript = theSupervisorNode.
getNode(
"DAQSetupScript").
getValue();
607 std::ofstream o(ARTDAQTableBase::ARTDAQ_FCL_PATH +
"/boot.txt", std::ios::trunc);
608 o <<
"DAQ setup script: " << setupScript << std::endl;
609 o <<
"debug level: " << debugLevel << std::endl;
612 if(info.subsystems.size() > 1)
614 for(
auto& ss : info.subsystems)
618 o <<
"Subsystem id: " << ss.first << std::endl;
619 if(ss.second.destination != 0)
621 o <<
"Subsystem destination: " << ss.second.destination << std::endl;
623 for(
auto& sss : ss.second.sources)
625 o <<
"Subsystem source: " << sss << std::endl;
627 if(ss.second.eventMode)
629 o <<
"Subsystem fragmentMode: False" << std::endl;
635 for(
auto& builder : info.processes[ARTDAQTableBase::ARTDAQAppType::EventBuilder])
637 o <<
"EventBuilder host: " << builder.hostname << std::endl;
638 o <<
"EventBuilder label: " << builder.label << std::endl;
639 label_to_proc_type_map_[builder.label] =
"EventBuilder";
640 if(builder.subsystem != 1)
642 o <<
"EventBuilder subsystem: " << builder.subsystem << std::endl;
644 if(builder.allowed_processors !=
"")
646 o <<
"EventBuilder allowed_processors: " << builder.allowed_processors
651 for(
auto& logger : info.processes[ARTDAQTableBase::ARTDAQAppType::DataLogger])
653 o <<
"DataLogger host: " << logger.hostname << std::endl;
654 o <<
"DataLogger label: " << logger.label << std::endl;
655 label_to_proc_type_map_[logger.label] =
"DataLogger";
656 if(logger.subsystem != 1)
658 o <<
"DataLogger subsystem: " << logger.subsystem << std::endl;
660 if(logger.allowed_processors !=
"")
662 o <<
"DataLogger allowed_processors: " << logger.allowed_processors
667 for(
auto& dispatcher : info.processes[ARTDAQTableBase::ARTDAQAppType::Dispatcher])
669 o <<
"Dispatcher host: " << dispatcher.hostname << std::endl;
670 o <<
"Dispatcher label: " << dispatcher.label << std::endl;
671 o <<
"Dispatcher port: " << dispatcher.port << std::endl;
672 label_to_proc_type_map_[dispatcher.label] =
"Dispatcher";
673 if(dispatcher.subsystem != 1)
675 o <<
"Dispatcher subsystem: " << dispatcher.subsystem << std::endl;
677 if(dispatcher.allowed_processors !=
"")
679 o <<
"Dispatcher allowed_processors: " << dispatcher.allowed_processors
684 for(
auto& rmanager : info.processes[ARTDAQTableBase::ARTDAQAppType::RoutingManager])
686 o <<
"RoutingManager host: " << rmanager.hostname << std::endl;
687 o <<
"RoutingManager label: " << rmanager.label << std::endl;
688 label_to_proc_type_map_[rmanager.label] =
"RoutingManager";
689 if(rmanager.subsystem != 1)
691 o <<
"RoutingManager subsystem: " << rmanager.subsystem << std::endl;
693 if(rmanager.allowed_processors !=
"")
695 o <<
"RoutingManager allowed_processors: " << rmanager.allowed_processors
702 thread_progress_bar_.
step();
703 set_thread_message_(
"Writing Fhicl Files");
705 __GEN_COUT__ <<
"Building configuration directory" << __E__;
707 boost::system::error_code ignored;
708 boost::filesystem::remove_all(ARTDAQTableBase::ARTDAQ_FCL_PATH + FAKE_CONFIG_NAME,
710 mkdir((ARTDAQTableBase::ARTDAQ_FCL_PATH + FAKE_CONFIG_NAME).c_str(), 0755);
712 for(
auto& reader : info.processes[ARTDAQTableBase::ARTDAQAppType::BoardReader])
714 symlink(ARTDAQTableBase::getFlatFHICLFilename(
715 ARTDAQTableBase::ARTDAQAppType::BoardReader, reader.label)
717 (ARTDAQTableBase::ARTDAQ_FCL_PATH + FAKE_CONFIG_NAME +
"/" +
718 reader.label +
".fcl")
721 for(
auto& builder : info.processes[ARTDAQTableBase::ARTDAQAppType::EventBuilder])
723 symlink(ARTDAQTableBase::getFlatFHICLFilename(
724 ARTDAQTableBase::ARTDAQAppType::EventBuilder, builder.label)
726 (ARTDAQTableBase::ARTDAQ_FCL_PATH + FAKE_CONFIG_NAME +
"/" +
727 builder.label +
".fcl")
730 for(
auto& logger : info.processes[ARTDAQTableBase::ARTDAQAppType::DataLogger])
732 symlink(ARTDAQTableBase::getFlatFHICLFilename(
733 ARTDAQTableBase::ARTDAQAppType::DataLogger, logger.label)
735 (ARTDAQTableBase::ARTDAQ_FCL_PATH + FAKE_CONFIG_NAME +
"/" +
736 logger.label +
".fcl")
739 for(
auto& dispatcher : info.processes[ARTDAQTableBase::ARTDAQAppType::Dispatcher])
741 symlink(ARTDAQTableBase::getFlatFHICLFilename(
742 ARTDAQTableBase::ARTDAQAppType::Dispatcher, dispatcher.label)
744 (ARTDAQTableBase::ARTDAQ_FCL_PATH + FAKE_CONFIG_NAME +
"/" +
745 dispatcher.label +
".fcl")
748 for(
auto& rmanager : info.processes[ARTDAQTableBase::ARTDAQAppType::RoutingManager])
750 symlink(ARTDAQTableBase::getFlatFHICLFilename(
751 ARTDAQTableBase::ARTDAQAppType::RoutingManager, rmanager.label)
753 (ARTDAQTableBase::ARTDAQ_FCL_PATH + FAKE_CONFIG_NAME +
"/" +
754 rmanager.label +
".fcl")
758 thread_progress_bar_.
step();
760 std::lock_guard<std::recursive_mutex> lk(daqinterface_mutex_);
762 if(daqinterface_state_ !=
"stopped" && daqinterface_state_ !=
"")
764 __GEN_SS__ <<
"Cannot configure DAQInterface because it is in the wrong state"
765 <<
" (" << daqinterface_state_ <<
" != stopped)!" << __E__;
769 set_thread_message_(
"Calling setdaqcomps");
770 __GEN_COUT__ <<
"Calling setdaqcomps" << __E__;
771 __GEN_COUT__ <<
"Status before setdaqcomps: " << daqinterface_state_ << __E__;
772 PyObject* pName1 = PyUnicode_FromString(
"setdaqcomps");
774 PyObject* readerDict = PyDict_New();
775 for(
auto& reader : info.processes[ARTDAQTableBase::ARTDAQAppType::BoardReader])
777 label_to_proc_type_map_[reader.label] =
"BoardReader";
778 PyObject* readerName = PyUnicode_FromString(reader.label.c_str());
780 int list_size = reader.allowed_processors !=
"" ? 4 : 3;
782 PyObject* readerData = PyList_New(list_size);
783 PyObject* readerHost = PyUnicode_FromString(reader.hostname.c_str());
784 PyObject* readerPort = PyUnicode_FromString(
"-1");
785 PyObject* readerSubsystem =
786 PyUnicode_FromString(std::to_string(reader.subsystem).c_str());
787 PyList_SetItem(readerData, 0, readerHost);
788 PyList_SetItem(readerData, 1, readerPort);
789 PyList_SetItem(readerData, 2, readerSubsystem);
790 if(reader.allowed_processors !=
"")
792 PyObject* readerAllowedProcessors =
793 PyUnicode_FromString(reader.allowed_processors.c_str());
794 PyList_SetItem(readerData, 3, readerAllowedProcessors);
796 PyDict_SetItem(readerDict, readerName, readerData);
799 PyObject_CallMethodObjArgs(daqinterface_ptr_, pName1, readerDict, NULL);
800 Py_DECREF(readerDict);
805 __GEN_SS__ <<
"Error calling setdaqcomps transition" << __E__;
809 __GEN_COUT__ <<
"Status after setdaqcomps: " << daqinterface_state_ << __E__;
811 thread_progress_bar_.
step();
812 set_thread_message_(
"Calling do_boot");
813 __GEN_COUT__ <<
"Calling do_boot" << __E__;
814 __GEN_COUT__ <<
"Status before boot: " << daqinterface_state_ << __E__;
815 PyObject* pName2 = PyUnicode_FromString(
"do_boot");
816 PyObject* pStateArgs1 =
817 PyUnicode_FromString((ARTDAQTableBase::ARTDAQ_FCL_PATH +
"/boot.txt").c_str());
819 PyObject_CallMethodObjArgs(daqinterface_ptr_, pName2, pStateArgs1, NULL);
824 __GEN_COUT__ <<
"Error on first boost attempt, recovering and retrying" << __E__;
826 PyObject* pName = PyUnicode_FromString(
"do_recover");
827 PyObject* res = PyObject_CallMethodObjArgs(daqinterface_ptr_, pName, NULL);
832 __GEN_SS__ <<
"Error calling recover transition!!!!" << __E__;
836 thread_progress_bar_.
step();
837 set_thread_message_(
"Calling do_boot (retry)");
838 __GEN_COUT__ <<
"Calling do_boot again" << __E__;
839 __GEN_COUT__ <<
"Status before boot: " << daqinterface_state_ << __E__;
841 PyObject_CallMethodObjArgs(daqinterface_ptr_, pName2, pStateArgs1, NULL);
846 __GEN_SS__ <<
"Error calling boot transition (2nd try)" << __E__;
852 if(daqinterface_state_ !=
"booted")
854 __GEN_SS__ <<
"DAQInterface boot transition failed! "
855 <<
"Status after boot attempt: " << daqinterface_state_ << __E__;
858 __GEN_COUT__ <<
"Status after boot: " << daqinterface_state_ << __E__;
860 thread_progress_bar_.
step();
861 set_thread_message_(
"Calling do_config");
862 __GEN_COUT__ <<
"Calling do_config" << __E__;
863 __GEN_COUT__ <<
"Status before config: " << daqinterface_state_ << __E__;
864 PyObject* pName3 = PyUnicode_FromString(
"do_config");
865 PyObject* pStateArgs2 = Py_BuildValue(
"[s]", FAKE_CONFIG_NAME);
867 PyObject_CallMethodObjArgs(daqinterface_ptr_, pName3, pStateArgs2, NULL);
872 __GEN_SS__ <<
"Error calling config transition" << __E__;
876 if(daqinterface_state_ !=
"ready")
878 __GEN_SS__ <<
"DAQInterface config transition failed!" << __E__
879 <<
"Supervisor state: \"" << daqinterface_state_ <<
"\" != \"ready\" "
883 __GEN_COUT__ <<
"Status after config: " << daqinterface_state_ << __E__;
885 set_thread_message_(
"Configured");
886 __GEN_COUT__ <<
"Configured." << __E__;
889 catch(
const std::runtime_error& e)
891 set_thread_message_(
"ERROR");
892 __SS__ <<
"Error was caught while configuring: " << e.what() << __E__;
893 __COUT_ERR__ <<
"\n" << ss.str();
894 std::lock_guard<std::mutex> lock(thread_mutex_);
895 thread_error_message_ = ss.str();
899 set_thread_message_(
"ERROR");
900 __SS__ <<
"Unknown error was caught while configuring. Please checked the logs."
902 __COUT_ERR__ <<
"\n" << ss.str();
904 artdaq::ExceptionHandler(artdaq::ExceptionHandlerRethrow::no, ss.str());
906 std::lock_guard<std::mutex> lock(thread_mutex_);
907 thread_error_message_ = ss.str();
914 set_thread_message_(
"Halting");
915 __SUP_COUT__ <<
"Halting..." << __E__;
916 std::lock_guard<std::recursive_mutex> lk(daqinterface_mutex_);
918 __SUP_COUT__ <<
"Status before halt: " << daqinterface_state_ << __E__;
920 if(daqinterface_state_ ==
"running")
923 PyObject* pName = PyUnicode_FromString(
"do_stop_running");
924 PyObject* res = PyObject_CallMethodObjArgs(daqinterface_ptr_, pName, NULL);
929 __SS__ <<
"Error calling DAQ Interface stop transition." << __E__;
934 PyObject* pName = PyUnicode_FromString(
"do_command");
935 PyObject* pArg = PyUnicode_FromString(
"Shutdown");
936 PyObject* res = PyObject_CallMethodObjArgs(daqinterface_ptr_, pName, pArg, NULL);
941 __SS__ <<
"Error calling DAQ Interface halt transition." << __E__;
946 __SUP_COUT__ <<
"Status after halt: " << daqinterface_state_ << __E__;
947 __SUP_COUT__ <<
"Halted." << __E__;
948 set_thread_message_(
"Halted");
950 catch(
const std::runtime_error& e)
952 const std::string transitionName =
"Halting";
954 if(theStateMachine_.getProvenanceStateName() ==
955 RunControlStateMachine::FAILED_STATE_NAME ||
956 theStateMachine_.getProvenanceStateName() ==
957 RunControlStateMachine::HALTED_STATE_NAME)
959 __SUP_COUT_INFO__ <<
"Error was caught while halting (but ignoring because "
960 "previous state was '"
961 << RunControlStateMachine::FAILED_STATE_NAME
962 <<
"'): " << e.what() << __E__;
966 __SUP_SS__ <<
"Error was caught while " << transitionName <<
": " << e.what()
968 __SUP_COUT_ERR__ <<
"\n" << ss.str();
969 theStateMachine_.setErrorMessage(ss.str());
970 throw toolbox::fsm::exception::Exception(
973 "ARTDAQSupervisorBase::transition" + transitionName ,
981 const std::string transitionName =
"Halting";
983 if(theStateMachine_.getProvenanceStateName() ==
984 RunControlStateMachine::FAILED_STATE_NAME ||
985 theStateMachine_.getProvenanceStateName() ==
986 RunControlStateMachine::HALTED_STATE_NAME)
988 __SUP_COUT_INFO__ <<
"Unknown error was caught while halting (but ignoring "
989 "because previous state was '"
990 << RunControlStateMachine::FAILED_STATE_NAME <<
"')." << __E__;
994 __SUP_SS__ <<
"Unknown error was caught while " << transitionName
995 <<
". Please checked the logs." << __E__;
996 __SUP_COUT_ERR__ <<
"\n" << ss.str();
997 theStateMachine_.setErrorMessage(ss.str());
999 artdaq::ExceptionHandler(artdaq::ExceptionHandlerRethrow::no, ss.str());
1001 throw toolbox::fsm::exception::Exception(
1002 "Transition Error" ,
1004 "ARTDAQSupervisorBase::transition" + transitionName ,
1015 set_thread_message_(
"Initializing");
1016 __SUP_COUT__ <<
"Initializing..." << __E__;
1018 __SUP_COUT__ <<
"Initialized." << __E__;
1019 set_thread_message_(
"Initialized");
1021 catch(
const std::runtime_error& e)
1023 __SS__ <<
"Error was caught while Initializing: " << e.what() << __E__;
1028 __SS__ <<
"Unknown error was caught while Initializing. Please checked the logs."
1030 artdaq::ExceptionHandler(artdaq::ExceptionHandlerRethrow::no, ss.str());
1035 void ARTDAQSupervisor::transitionPausing(toolbox::Event::Reference )
1038 set_thread_message_(
"Pausing");
1039 __SUP_COUT__ <<
"Pausing..." << __E__;
1040 std::lock_guard<std::recursive_mutex> lk(daqinterface_mutex_);
1043 __SUP_COUT__ <<
"Status before pause: " << daqinterface_state_ << __E__;
1045 PyObject* pName = PyUnicode_FromString(
"do_command");
1046 PyObject* pArg = PyUnicode_FromString(
"Pause");
1047 PyObject* res = PyObject_CallMethodObjArgs(daqinterface_ptr_, pName, pArg, NULL);
1052 __SS__ <<
"Error calling DAQ Interface Pause transition." << __E__;
1057 __SUP_COUT__ <<
"Status after pause: " << daqinterface_state_ << __E__;
1059 __SUP_COUT__ <<
"Paused." << __E__;
1060 set_thread_message_(
"Paused");
1062 catch(
const std::runtime_error& e)
1064 __SS__ <<
"Error was caught while Pausing: " << e.what() << __E__;
1069 __SS__ <<
"Unknown error was caught while Pausing. Please checked the logs." << __E__;
1070 artdaq::ExceptionHandler(artdaq::ExceptionHandlerRethrow::no, ss.str());
1075 void ARTDAQSupervisor::transitionResuming(toolbox::Event::Reference )
1078 set_thread_message_(
"Resuming");
1079 __SUP_COUT__ <<
"Resuming..." << __E__;
1080 std::lock_guard<std::recursive_mutex> lk(daqinterface_mutex_);
1083 __SUP_COUT__ <<
"Status before resume: " << daqinterface_state_ << __E__;
1084 PyObject* pName = PyUnicode_FromString(
"do_command");
1085 PyObject* pArg = PyUnicode_FromString(
"Resume");
1086 PyObject* res = PyObject_CallMethodObjArgs(daqinterface_ptr_, pName, pArg, NULL);
1091 __SS__ <<
"Error calling DAQ Interface Resume transition." << __E__;
1095 __SUP_COUT__ <<
"Status after resume: " << daqinterface_state_ << __E__;
1096 __SUP_COUT__ <<
"Resumed." << __E__;
1097 set_thread_message_(
"Resumed");
1099 catch(
const std::runtime_error& e)
1101 __SS__ <<
"Error was caught while Resuming: " << e.what() << __E__;
1106 __SS__ <<
"Unknown error was caught while Resuming. Please checked the logs."
1108 artdaq::ExceptionHandler(artdaq::ExceptionHandlerRethrow::no, ss.str());
1113 void ARTDAQSupervisor::transitionStarting(toolbox::Event::Reference )
1116 __SUP_COUT__ <<
"transitionStarting" << __E__;
1119 if(RunControlStateMachine::getIterationIndex() == 0 &&
1120 RunControlStateMachine::getSubIterationIndex() == 0)
1122 thread_error_message_ =
"";
1123 thread_progress_bar_.resetProgressBar(0);
1124 last_thread_progress_update_ = time(0);
1127 std::thread(&ARTDAQSupervisor::startingThread,
this).detach();
1129 __SUP_COUT__ <<
"Starting thread started." << __E__;
1131 RunControlStateMachine::
1132 indicateIterationWork();
1136 std::string errorMessage;
1138 std::lock_guard<std::mutex> lock(
1140 errorMessage = thread_error_message_;
1142 int progress = thread_progress_bar_.
read();
1143 __SUP_COUTV__(errorMessage);
1144 __SUP_COUTV__(progress);
1145 __SUP_COUTV__(thread_progress_bar_.
isComplete());
1148 if(errorMessage ==
"" &&
1149 time(0) - last_thread_progress_update_ > 600)
1151 __SUP_SS__ <<
"There has been no update from the start thread for "
1152 << (time(0) - last_thread_progress_update_)
1153 <<
" seconds, assuming something is wrong and giving up! "
1154 <<
"Last progress received was " << progress << __E__;
1155 errorMessage = ss.str();
1158 if(errorMessage !=
"")
1160 __SUP_SS__ <<
"Error was caught in starting thread: " << errorMessage
1162 __SUP_COUT_ERR__ <<
"\n" << ss.str();
1164 theStateMachine_.setErrorMessage(ss.str());
1165 throw toolbox::fsm::exception::Exception(
1166 "Transition Error" ,
1168 "CoreSupervisorBase::transitionStarting" ,
1176 RunControlStateMachine::
1177 indicateIterationWork();
1179 if(last_thread_progress_read_ != progress)
1181 last_thread_progress_read_ = progress;
1182 last_thread_progress_update_ = time(0);
1189 __SUP_COUT_INFO__ <<
"Complete starting transition!" << __E__;
1190 __SUP_COUTV__(getProcessInfo_());
1197 catch(
const std::runtime_error& e)
1199 __SS__ <<
"Error was caught while Starting: " << e.what() << __E__;
1204 __SS__ <<
"Unknown error was caught while Starting. Please checked the logs."
1206 artdaq::ExceptionHandler(artdaq::ExceptionHandlerRethrow::no, ss.str());
1211 void ARTDAQSupervisor::startingThread()
1214 std::string uid = theConfigurationManager_
1215 ->
getNode(ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME +
1216 "/" + CorePropertySupervisorBase::getSupervisorUID() +
1217 "/" +
"LinkToSupervisorTable")
1220 __COUT__ <<
"Supervisor uid is " << uid <<
", getting supervisor table node" << __E__;
1221 const std::string mfSubject_ = supervisorClassNoNamespace_ +
"-" + uid;
1222 __GEN_COUT__ <<
"Starting..." << __E__;
1223 set_thread_message_(
"Starting");
1225 thread_progress_bar_.
step();
1228 std::lock_guard<std::recursive_mutex> lk(daqinterface_mutex_);
1230 __GEN_COUT__ <<
"Status before start: " << daqinterface_state_ << __E__;
1231 auto runNumber = SOAPUtilities::translate(theStateMachine_.getCurrentMessage())
1233 .getValue(
"RunNumber");
1235 thread_progress_bar_.
step();
1237 PyObject* pName = PyUnicode_FromString(
"do_start_running");
1238 int run_number = std::stoi(runNumber);
1239 PyObject* pStateArgs = PyLong_FromLong(run_number);
1241 PyObject_CallMethodObjArgs(daqinterface_ptr_, pName, pStateArgs, NULL);
1243 thread_progress_bar_.
step();
1248 __SS__ <<
"Error calling start transition" << __E__;
1253 thread_progress_bar_.
step();
1255 __GEN_COUT__ <<
"Status after start: " << daqinterface_state_ << __E__;
1256 if(daqinterface_state_ !=
"running")
1258 __SS__ <<
"DAQInterface start transition failed!" << __E__;
1262 thread_progress_bar_.
step();
1265 set_thread_message_(
"Started");
1266 thread_progress_bar_.
step();
1268 __GEN_COUT__ <<
"Started." << __E__;
1272 catch(
const std::runtime_error& e)
1274 __SS__ <<
"Error was caught while Starting: " << e.what() << __E__;
1275 __COUT_ERR__ <<
"\n" << ss.str();
1276 std::lock_guard<std::mutex> lock(thread_mutex_);
1277 thread_error_message_ = ss.str();
1281 __SS__ <<
"Unknown error was caught while Starting. Please checked the logs."
1283 __COUT_ERR__ <<
"\n" << ss.str();
1285 artdaq::ExceptionHandler(artdaq::ExceptionHandlerRethrow::no, ss.str());
1287 std::lock_guard<std::mutex> lock(thread_mutex_);
1288 thread_error_message_ = ss.str();
1292 void ARTDAQSupervisor::transitionStopping(toolbox::Event::Reference )
1295 __SUP_COUT__ <<
"Stopping..." << __E__;
1296 set_thread_message_(
"Stopping");
1297 std::lock_guard<std::recursive_mutex> lk(daqinterface_mutex_);
1299 __SUP_COUT__ <<
"Status before stop: " << daqinterface_state_ << __E__;
1300 PyObject* pName = PyUnicode_FromString(
"do_stop_running");
1301 PyObject* res = PyObject_CallMethodObjArgs(daqinterface_ptr_, pName, NULL);
1306 __SS__ <<
"Error calling DAQ Interface stop transition." << __E__;
1310 __SUP_COUT__ <<
"Status after stop: " << daqinterface_state_ << __E__;
1311 __SUP_COUT__ <<
"Stopped." << __E__;
1312 set_thread_message_(
"Stopped");
1314 catch(
const std::runtime_error& e)
1316 __SS__ <<
"Error was caught while Stopping: " << e.what() << __E__;
1321 __SS__ <<
"Unknown error was caught while Stopping. Please checked the logs."
1323 artdaq::ExceptionHandler(artdaq::ExceptionHandlerRethrow::no, ss.str());
1328 void ots::ARTDAQSupervisor::enteringError(toolbox::Event::Reference )
1330 __SUP_COUT__ <<
"Entering error recovery state" << __E__;
1331 std::lock_guard<std::recursive_mutex> lk(daqinterface_mutex_);
1333 __SUP_COUT__ <<
"Status before error: " << daqinterface_state_ << __E__;
1335 PyObject* pName = PyUnicode_FromString(
"do_recover");
1336 PyObject* res = PyObject_CallMethodObjArgs(daqinterface_ptr_, pName, NULL);
1341 __SS__ <<
"Error calling DAQ Interface recover transition." << __E__;
1345 __SUP_COUT__ <<
"Status after error: " << daqinterface_state_ << __E__;
1346 __SUP_COUT__ <<
"EnteringError DONE." << __E__;
1350 std::vector<SupervisorInfo::SubappInfo> ots::ARTDAQSupervisor::getSubappInfo(
void)
1352 auto apps = getAndParseProcessInfo_();
1353 std::vector<SupervisorInfo::SubappInfo> output;
1354 for(
auto& app : apps)
1358 info.
name = app.label;
1359 info.detail =
"Rank " + std::to_string(app.rank) +
", subsystem " +
1360 std::to_string(app.subsystem);
1361 info.lastStatusTime = time(0);
1362 info.progress = 100;
1363 info.status = artdaqStateToOtsState(app.state);
1364 info.url =
"http://" + app.host +
":" + std::to_string(app.port) +
"/RPC2";
1365 info.class_name =
"ARTDAQ " + labelToProcType_(app.label);
1367 output.push_back(info);
1373 void ots::ARTDAQSupervisor::getDAQState_()
1376 std::lock_guard<std::recursive_mutex> lk(daqinterface_mutex_);
1378 if(daqinterface_ptr_ ==
nullptr)
1380 daqinterface_state_ =
"";
1384 PyObject* pName = PyUnicode_FromString(
"state");
1385 PyObject* pArg = PyUnicode_FromString(
"DAQInterface");
1386 PyObject* res = PyObject_CallMethodObjArgs(daqinterface_ptr_, pName, pArg, NULL);
1391 __SS__ <<
"Error calling state function" << __E__;
1395 daqinterface_state_ = std::string(PyUnicode_AsUTF8(res));
1400 std::string ots::ARTDAQSupervisor::getProcessInfo_(
void)
1403 std::lock_guard<std::recursive_mutex> lk(daqinterface_mutex_);
1405 if(daqinterface_ptr_ ==
nullptr)
1410 PyObject* pName = PyUnicode_FromString(
"artdaq_process_info");
1411 PyObject* pArg = PyUnicode_FromString(
"DAQInterface");
1412 PyObject* pArg2 = PyBool_FromLong(
true);
1414 PyObject_CallMethodObjArgs(daqinterface_ptr_, pName, pArg, pArg2, NULL);
1419 __SS__ <<
"Error calling artdaq_process_info function" << __E__;
1423 return std::string(PyUnicode_AsUTF8(res));
1427 std::string ots::ARTDAQSupervisor::artdaqStateToOtsState(std::string state)
1429 if(state ==
"nonexistant")
1430 return RunControlStateMachine::INITIAL_STATE_NAME;
1431 if(state ==
"Ready")
1432 return "Configured";
1433 if(state ==
"Running")
1434 return RunControlStateMachine::RUNNING_STATE_NAME;
1435 if(state ==
"Paused")
1436 return RunControlStateMachine::PAUSED_STATE_NAME;
1437 if(state ==
"Stopped")
1438 return RunControlStateMachine::HALTED_STATE_NAME;
1440 TLOG(TLVL_WARNING) <<
"Unrecognized state name " << state;
1441 return RunControlStateMachine::FAILED_STATE_NAME;
1444 std::string ots::ARTDAQSupervisor::labelToProcType_(std::string label)
1446 if(label_to_proc_type_map_.count(label))
1448 return label_to_proc_type_map_[label];
1454 std::list<ots::ARTDAQSupervisor::DAQInterfaceProcessInfo>
1455 ots::ARTDAQSupervisor::getAndParseProcessInfo_()
1457 std::list<ots::ARTDAQSupervisor::DAQInterfaceProcessInfo> output;
1458 auto info = getProcessInfo_();
1459 auto procs = tokenize_(info);
1468 std::regex re(
"(.*?) at ([^:]*):(\\d+) \\(subsystem (\\d+), rank (\\d+)\\): (.*)");
1470 for(
auto& proc : procs)
1473 if(std::regex_match(proc, match, re))
1475 DAQInterfaceProcessInfo info;
1477 info.label = match[1];
1478 info.host = match[2];
1479 info.port = std::stoi(match[3]);
1480 info.subsystem = std::stoi(match[4]);
1481 info.rank = std::stoi(match[5]);
1482 info.state = match[6];
1484 output.push_back(info);
1492 std::unique_ptr<artdaq::CommanderInterface>>>
1493 ots::ARTDAQSupervisor::makeCommandersFromProcessInfo()
1496 std::pair<DAQInterfaceProcessInfo, std::unique_ptr<artdaq::CommanderInterface>>>
1498 auto infos = getAndParseProcessInfo_();
1500 for(
auto& info : infos)
1502 artdaq::Commandable cm;
1503 fhicl::ParameterSet ps;
1505 ps.put<std::string>(
"commanderPluginType",
"xmlrpc");
1506 ps.put<
int>(
"id", info.port);
1507 ps.put<std::string>(
"server_url", info.host);
1509 output.emplace_back(std::make_pair<DAQInterfaceProcessInfo,
1510 std::unique_ptr<artdaq::CommanderInterface>>(
1511 std::move(info), artdaq::MakeCommanderPlugin(ps, cm)));
1518 std::list<std::string> ots::ARTDAQSupervisor::tokenize_(std::string
const& input)
1521 std::list<std::string> output;
1523 while(pos != std::string::npos && pos < input.size())
1525 auto newpos = input.find(
'\n', pos);
1526 if(newpos != std::string::npos)
1528 output.emplace_back(input, pos, newpos - pos);
1534 output.emplace_back(input, pos);
1543 void ots::ARTDAQSupervisor::daqinterfaceRunner_()
1545 TLOG(TLVL_TRACE) <<
"Runner thread starting";
1546 runner_running_ =
true;
1547 while(runner_running_)
1549 if(daqinterface_ptr_ != NULL)
1551 std::unique_lock<std::recursive_mutex> lk(daqinterface_mutex_);
1553 std::string state_before = daqinterface_state_;
1555 if(daqinterface_state_ ==
"running" || daqinterface_state_ ==
"ready" ||
1556 daqinterface_state_ ==
"booted")
1560 TLOG(TLVL_TRACE) <<
"Calling DAQInterface::check_proc_heartbeats";
1561 PyObject* pName = PyUnicode_FromString(
"check_proc_heartbeats");
1563 PyObject_CallMethodObjArgs(daqinterface_ptr_, pName, NULL);
1565 <<
"Done with DAQInterface::check_proc_heartbeats call";
1569 runner_running_ =
false;
1571 __SS__ <<
"Error calling check_proc_heartbeats function" << __E__;
1576 catch(cet::exception& ex)
1578 runner_running_ =
false;
1580 __SS__ <<
"An cet::exception occurred while calling "
1581 "check_proc_heartbeats function: "
1582 << ex.explain_self() << __E__;
1586 catch(std::exception& ex)
1588 runner_running_ =
false;
1590 __SS__ <<
"An std::exception occurred while calling "
1591 "check_proc_heartbeats function: "
1592 << ex.what() << __E__;
1598 runner_running_ =
false;
1600 __SS__ <<
"An unknown Error occurred while calling runner function"
1608 if(daqinterface_state_ != state_before)
1610 runner_running_ =
false;
1612 __SS__ <<
"DAQInterface state unexpectedly changed from "
1613 << state_before <<
" to " << daqinterface_state_
1614 <<
". Check supervisor log file for more info!" << __E__;
1626 runner_running_ =
false;
1627 TLOG(TLVL_TRACE) <<
"Runner thread complete";
1631 void ots::ARTDAQSupervisor::stop_runner_()
1633 runner_running_ =
false;
1634 if(runner_thread_ && runner_thread_->joinable())
1636 runner_thread_->join();
1637 runner_thread_.reset(
nullptr);
1642 void ots::ARTDAQSupervisor::start_runner_()
1646 std::make_unique<std::thread>(&ots::ARTDAQSupervisor::daqinterfaceRunner_,
this);
virtual void transitionHalting(toolbox::Event::Reference event) override
virtual void transitionInitializing(toolbox::Event::Reference event) override
void loadTableGroup(const std::string &tableGroupName, const TableGroupKey &tableGroupKey, bool doActivate=false, std::map< std::string, TableVersion > *groupMembers=0, ProgressBar *progressBar=0, std::string *accumulateWarnings=0, std::string *groupComment=0, std::string *groupAuthor=0, std::string *groupCreateTime=0, bool doNotLoadMember=false, std::string *groupTypeString=0, std::map< std::string, std::string > *groupAliases=0, ConfigurationManager::LoadGroupType onlyLoadIfBackboneOrContext=ConfigurationManager::LoadGroupType::ALL_TYPES, bool ignoreVersionTracking=false)
ConfigurationTree getNode(const std::string &nodeString, bool doNotThrowOnBrokenUIDLinks=false) const
"root/parent/parent/"
ConfigurationTree getNode(const std::string &nodeName, bool doNotThrowOnBrokenUIDLinks=false) const
navigating between nodes
const std::string & getValueAsString(bool returnLinkTableValue=false) const
void getValue(T &value) const
ITRACEController * theTRACEController_
only define for an app that receives a command
bool isComplete()
get functions
int read()
if stepsToComplete==0, then define any progress as 50%, thread safe
void complete()
declare complete, thread safe
void INIT_MF(const char *name)
std::string name
Also key in map.