1 #include "artdaq/Application/CommandableFragmentGenerator.hh"
3 #include <boost/exception/all.hpp>
4 #include <boost/throw_exception.hpp>
9 #include "canvas/Utilities/Exception.h"
10 #include "cetlib/exception.h"
11 #include "fhiclcpp/ParameterSet.h"
12 #include "artdaq-core/Utilities/SimpleLookupPolicy.hh"
13 #include "artdaq-core/Data/Fragment.hh"
14 #include "artdaq-core/Data/ContainerFragmentLoader.hh"
27 , request_addr_(
"227.128.12.26")
31 , staleTimeout_(Fragment::InvalidTimestamp)
32 , maxFragmentCount_(std::numeric_limits<size_t>::max())
33 , uniqueWindows_(true)
34 , useDataThread_(false)
35 , dataBufferDepthFragments_(0)
36 , dataBufferDepthBytes_(0)
37 , maxDataBufferDepthFragments_(1000)
38 , maxDataBufferDepthBytes_(1000)
39 , useMonitoringThread_(false)
40 , monitoringInterval_(0)
41 , lastMonitoringCall_(std::chrono::steady_clock::now())
47 , timeout_(std::numeric_limits<uint64_t>::max())
48 , timestamp_(std::numeric_limits<uint64_t>::max())
51 , latest_exception_report_(
"none")
54 , instance_name_for_metrics_(
"FragmentGenerator")
55 , sleep_on_stop_us_(0) {}
59 , request_port_(ps.get<int>(
"request_port", 3001))
60 , request_addr_(ps.get<std::string>(
"request_address",
"227.128.12.26"))
62 , windowOffset_(ps.get<Fragment::timestamp_t>(
"request_window_offset", 0))
63 , windowWidth_(ps.get<Fragment::timestamp_t>(
"request_window_width", 0))
64 , staleTimeout_(ps.get<Fragment::timestamp_t>(
"stale_request_timeout", 0xFFFFFFFF))
65 , uniqueWindows_(ps.get<bool>(
"request_windows_are_unique", true))
66 , useDataThread_(ps.get<bool>(
"separate_data_thread", false))
67 , dataBufferDepthFragments_(0)
68 , dataBufferDepthBytes_(0)
69 , maxDataBufferDepthFragments_(ps.get<int>(
"data_buffer_depth_fragments", 1000))
70 , maxDataBufferDepthBytes_(ps.get<size_t>(
"data_buffer_depth_mb", 1000) * 1024 * 1024)
71 , useMonitoringThread_(ps.get<bool>(
"separate_monitoring_thread", false))
72 , monitoringInterval_(ps.get<int64_t>(
"hardware_poll_interval_us", 0))
73 , lastMonitoringCall_(std::chrono::steady_clock::now())
79 , timeout_(std::numeric_limits<uint64_t>::max())
80 , timestamp_(std::numeric_limits<uint64_t>::max())
83 , latest_exception_report_(
"none")
86 , sleep_on_stop_us_(0)
88 board_id_ = ps.get<
int>(
"board_id");
89 instance_name_for_metrics_ =
"BoardReader." + boost::lexical_cast<std::string>(board_id_);
91 fragment_ids_ = ps.get<std::vector<artdaq::Fragment::fragment_id_t>>(
"fragment_ids", std::vector<artdaq::Fragment::fragment_id_t>());
93 TRACE(24,
"artdaq::CommandableFragmentGenerator::CommandableFragmentGenerator(ps)");
96 if (fragment_id != -99)
98 if (fragment_ids_.size() != 0)
100 latest_exception_report_ =
"Error in CommandableFragmentGenerator: can't both define \"fragment_id\" and \"fragment_ids\" in FHiCL document";
101 throw cet::exception(latest_exception_report_);
105 fragment_ids_.emplace_back(fragment_id);
109 sleep_on_stop_us_ = ps.get<
int>(
"sleep_on_stop_us", 0);
111 dataBuffer_.emplace_back(FragmentPtr(
new Fragment()));
112 (*dataBuffer_.begin())->setSystemType(Fragment::EmptyFragmentType);
114 std::string modeString = ps.get<std::string>(
"request_mode",
"ignored");
115 if (modeString ==
"single" || modeString ==
"Single")
117 TRACE(3,
"CommandableFragmentGenerator: RequestMode set to SINGLE");
118 mode_ = RequestMode::Single;
120 else if (modeString.find(
"buffer") != std::string::npos || modeString.find(
"Buffer") != std::string::npos)
122 TRACE(3,
"CommandableFragmentGenerator: RequestMode set to BUFFER");
123 mode_ = RequestMode::Buffer;
125 else if (modeString ==
"window" || modeString ==
"Window")
127 TRACE(3,
"CommandableFragmentGenerator: RequestMode set to WINDOW");
128 mode_ = RequestMode::Window;
130 else if (modeString.find(
"ignore") != std::string::npos || modeString.find(
"Ignore") != std::string::npos)
132 TRACE(3,
"CommandableFragmentGenerator: RequestMode set to IGNORE");
133 mode_ = RequestMode::Ignored;
135 TLOG_DEBUG(
"CommandableFragmentGenerator") <<
"Request mode is " <<
printMode_() << TLOG_ENDL;
137 if (mode_ != RequestMode::Ignored)
141 latest_exception_report_ =
"Error in CommandableFragmentGenerator: use_data_thread must be true when request_mode is not \"Ignored\"!";
142 throw cet::exception(latest_exception_report_);
150 request_socket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
151 if (!request_socket_)
153 throw art::Exception(art::errors::Configuration) <<
"CommandableFragmentGenerator: Error creating socket for receiving data requests!" << std::endl;
157 struct sockaddr_in si_me_request;
160 if (setsockopt(request_socket_, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(yes)) < 0)
162 throw art::Exception(art::errors::Configuration) <<
163 "RequestedFragmentGenrator: Unable to enable port reuse on request socket" << std::endl;
166 memset(&si_me_request, 0,
sizeof(si_me_request));
167 si_me_request.sin_family = AF_INET;
168 si_me_request.sin_port = htons(request_port_);
169 si_me_request.sin_addr.s_addr = htonl(INADDR_ANY);
170 if (bind(request_socket_, (
struct sockaddr *)&si_me_request,
sizeof(si_me_request)) == -1)
172 throw art::Exception(art::errors::Configuration) <<
173 "CommandableFragmentGenerator: Cannot bind request socket to port " << request_port_ << std::endl;
178 int sts =
ResolveHost(request_addr_.c_str(), mreq.imr_multiaddr);
181 throw art::Exception(art::errors::Configuration) <<
"Unable to resolve multicast request address" << std::endl;
184 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
185 if (setsockopt(request_socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
sizeof(mreq)) < 0)
187 throw art::Exception(art::errors::Configuration) <<
188 "CommandableFragmentGenerator: Unable to join multicast group" << std::endl;
195 TLOG_DEBUG(
"CommandableFragmentGenerator") <<
"Joining dataThread" << TLOG_ENDL;
196 if (dataThread_.joinable()) dataThread_.join();
197 TLOG_DEBUG(
"CommandableFragmentGenerator") <<
"Joining monitoringThread" << TLOG_ENDL;
198 if (monitoringThread_.joinable()) monitoringThread_.join();
199 TLOG_DEBUG(
"CommandableFragmentGenerator") <<
"Joining requestThread" << TLOG_ENDL;
200 if (requestThread_.joinable()) requestThread_.join();
207 if (check_stop()) usleep(sleep_on_stop_us_);
208 if (exception())
return false;
210 if (!useMonitoringThread_ && monitoringInterval_ > 0)
212 TRACE(4,
"CFG: Collecting Monitoring Data");
213 auto now = std::chrono::steady_clock::now();
214 if (std::chrono::duration_cast<std::chrono::microseconds>(now - lastMonitoringCall_).count() >= monitoringInterval_)
216 isHardwareOK_ = checkHWStatus_();
217 lastMonitoringCall_ = now;
223 std::lock_guard<std::mutex> lk(mutex_);
226 TRACE(4,
"CFG: Calling applyRequests");
227 result = applyRequests(output);
228 TRACE(4,
"CFG: Done with applyRequests");
232 TRACE(4,
"CFG: Calling getNext_ %zu", ev_counter() );
233 result = getNext_(output);
234 TRACE(4,
"CFG: Done with getNext_ %zu", ev_counter() );
237 catch (
const cet::exception& e)
239 latest_exception_report_ =
"cet::exception caught in getNext(): ";
240 latest_exception_report_.append(e.what());
241 TLOG_ERROR(
"getNext") <<
"cet::exception caught: " << e << TLOG_ENDL;
245 catch (
const boost::exception& e)
247 latest_exception_report_ =
"boost::exception caught in getNext(): ";
248 latest_exception_report_.append(boost::diagnostic_information(e));
249 TLOG_ERROR(
"getNext") <<
"boost::exception caught: " << boost::diagnostic_information(e) << TLOG_ENDL;
253 catch (
const std::exception& e)
255 latest_exception_report_ =
"std::exception caught in getNext(): ";
256 latest_exception_report_.append(e.what());
257 TLOG_ERROR(
"getNext") <<
"std::exception caught: " << e.what() << TLOG_ENDL;
263 latest_exception_report_ =
"Unknown exception caught in getNext().";
264 TLOG_ERROR(
"getNext") <<
"unknown exception caught" << TLOG_ENDL;
271 TRACE(4,
"CFG:getNext Stopped");
272 TLOG_DEBUG(
"getNext") <<
"stopped " << TLOG_ENDL;
280 TRACE(4,
"CFG::check_stop: should_stop=%i, useDataThread_=%i, requests_.size()=%zu", should_stop(), useDataThread_, requests_.size());
281 if (!should_stop())
return false;
282 if (!useDataThread_ || mode_ == RequestMode::Ignored)
return true;
284 return requests_.size() == 0;
289 if (fragment_ids_.size() != 1)
291 throw cet::exception(
"Error in CommandableFragmentGenerator: can't call fragment_id() unless member fragment_ids_ vector is length 1");
295 return fragment_ids_[0];
301 if (force || mode_ == RequestMode::Ignored)
303 return ev_counter_.fetch_add(step);
305 return ev_counter_.load();
310 if (run < 0)
throw cet::exception(
"CommandableFragmentGenerator") <<
"negative run number";
313 timestamp_ = timestamp;
314 ev_counter_.store(1);
315 should_stop_.store(
false);
316 exception_.store(
false);
319 latest_exception_report_ =
"none";
325 std::unique_lock<std::mutex> lk(mutex_);
326 if (useDataThread_) startDataThread();
327 if (useMonitoringThread_) startMonitoringThread();
328 if (mode_ != RequestMode::Ignored) startRequestReceiverThread();
333 TLOG_DEBUG(
"CommandableFragmentGenerator") <<
"Stop Command received." << TLOG_ENDL;
334 TRACE(4,
"CFG: Stop Command Received");
337 timestamp_ = timestamp;
340 should_stop_.store(
true);
341 std::unique_lock<std::mutex> lk(mutex_);
349 timestamp_ = timestamp;
352 should_stop_.store(
true);
353 std::unique_lock<std::mutex> lk(mutex_);
361 timestamp_ = timestamp;
364 should_stop_ =
false;
372 std::unique_lock<std::mutex> lk(mutex_);
373 if (useDataThread_) startDataThread();
374 if (useMonitoringThread_) startMonitoringThread();
375 if (mode_ != RequestMode::Ignored) startRequestReceiverThread();
380 std::lock_guard<std::mutex> lk(mutex_);
387 std::string childReport = reportSpecific(which);
388 if (childReport.length() > 0) {
return childReport; }
391 if (which ==
"latest_exception")
393 return latest_exception_report_;
397 childReport = report();
398 if (childReport.length() > 0) {
return childReport; }
401 std::string tmpString =
"The \"" + which +
"\" command is not ";
402 tmpString.append(
"currently supported by the ");
403 tmpString.append(metricsReportingInstanceName());
404 tmpString.append(
" fragment generator.");
409 void artdaq::CommandableFragmentGenerator::pauseNoMutex()
411 #pragma message "Using default implementation of CommandableFragmentGenerator::pauseNoMutex()"
414 void artdaq::CommandableFragmentGenerator::pause()
416 #pragma message "Using default implementation of CommandableFragmentGenerator::pause()"
419 void artdaq::CommandableFragmentGenerator::resume()
421 #pragma message "Using default implementation of CommandableFragmentGenerator::resume()"
424 std::string artdaq::CommandableFragmentGenerator::report()
426 #pragma message "Using default implementation of CommandableFragmentGenerator::report()"
430 std::string artdaq::CommandableFragmentGenerator::reportSpecific(std::string
const&)
432 #pragma message "Using default implementation of CommandableFragmentGenerator::reportSpecific(std::string)"
436 bool artdaq::CommandableFragmentGenerator::checkHWStatus_()
438 #pragma message "Using default implementation of CommandableFragmentGenerator::checkHWStatus_()"
444 if (dataThread_.joinable()) dataThread_.join();
445 TLOG_INFO(
"CommandableFragmentGenerator") <<
"Starting Data Receiver Thread" << TLOG_ENDL;
451 if (monitoringThread_.joinable()) monitoringThread_.join();
452 TLOG_INFO(
"CommandableFragmentGenerator") <<
"Starting Hardware Monitoring Thread" << TLOG_ENDL;
458 if (requestThread_.joinable()) requestThread_.join();
459 TLOG_INFO(
"CommandableFragmentGenerator") <<
"Starting Request Reception Thread" << TLOG_ENDL;
467 case RequestMode::Single:
469 case RequestMode::Buffer:
471 case RequestMode::Window:
473 case RequestMode::Ignored:
484 if (should_stop() || !isHardwareOK_)
486 TLOG_DEBUG(
"CommandableFragmentGenerator") <<
"getDataLoop: should_stop is " << std::boolalpha << should_stop() <<
", and isHardwareOK is " << isHardwareOK_ << TLOG_ENDL;
490 TRACE(4,
"CommandableFragmentGenerator::getDataLoop: calling getNext_");
491 bool data = getNext_(newDataBuffer_);
493 auto startwait = std::chrono::steady_clock::now();
495 auto lastwaittime = 0;
496 while (dataBufferIsTooLarge())
500 TLOG_DEBUG(
"CommandaleFragmentGenerator") <<
"Run ended while waiting for buffer to shrink!" << TLOG_ENDL;
501 std::unique_lock<std::mutex> lock(dataBufferMutex_);
502 getDataBufferStats();
503 dataCondition_.notify_all();
506 auto waittime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - startwait).count();
508 if (first || (waittime != lastwaittime && waittime % 1000 == 0))
510 TLOG_WARNING(
"CommandableFragmentGenerator") <<
"Bad Omen: Data Buffer has exceeded its size limits. Check the connection between the BoardReader and the EventBuilders! (seq_id=" << ev_counter() <<
")" << TLOG_ENDL;
513 if (waittime % 5 && waittime != lastwaittime)
515 TRACE(4,
"CFG::getDataLoop: Data Retreival paused for %lu ms waiting for data buffer to drain", waittime);
517 lastwaittime = waittime;
523 std::unique_lock<std::mutex> lock(dataBufferMutex_);
526 case RequestMode::Single:
528 while (newDataBuffer_.size() >= fragment_ids_.size())
531 auto it = newDataBuffer_.begin();
532 std::advance(it, fragment_ids_.size());
533 dataBuffer_.splice(dataBuffer_.end(), newDataBuffer_, newDataBuffer_.begin(), it);
536 case RequestMode::Buffer:
537 case RequestMode::Ignored:
538 case RequestMode::Window:
541 dataBuffer_.splice(dataBuffer_.end(), newDataBuffer_);
544 getDataBufferStats();
548 std::unique_lock<std::mutex> lock(dataBufferMutex_);
549 if (dataBuffer_.size() > 0)
551 dataCondition_.notify_all();
559 return (maxDataBufferDepthFragments_ > 0 && dataBufferDepthFragments_ >= maxDataBufferDepthFragments_) || (maxDataBufferDepthBytes_ > 0 && dataBufferDepthBytes_ >= maxDataBufferDepthBytes_);
565 dataBufferDepthFragments_ = dataBuffer_.size();
567 for (
auto i = dataBuffer_.begin(); i != dataBuffer_.end(); ++i)
569 acc += (*i)->sizeBytes();
571 dataBufferDepthBytes_ = acc;
575 metricMan->sendMetric(
"Buffer Depth Fragments", dataBufferDepthFragments_.load(),
"fragments", 1);
576 metricMan->sendMetric(
"Buffer Depth Bytes", dataBufferDepthBytes_.load(),
"bytes", 1);
578 TRACE(4,
"CFG::getDataBufferStats: frags=%i/%i, sz=%zd/%zd", dataBufferDepthFragments_.load(), maxDataBufferDepthFragments_, dataBufferDepthBytes_.load(), maxDataBufferDepthBytes_);
583 std::unique_lock<std::mutex> lock(dataBufferMutex_);
584 dataCondition_.wait_for(lock, std::chrono::milliseconds(10));
585 if (dataBufferDepthFragments_ > 0)
587 if ((mode_ == RequestMode::Buffer || mode_ == RequestMode::Window))
590 while (dataBufferIsTooLarge())
592 dataBuffer_.erase(dataBuffer_.begin());
593 getDataBufferStats();
595 if (dataBuffer_.size() > 0)
597 Fragment::timestamp_t last = dataBuffer_.back()->timestamp();
598 Fragment::timestamp_t min = last > staleTimeout_ ? last - staleTimeout_ : 0;
599 for (
auto it = dataBuffer_.begin(); it != dataBuffer_.end();)
601 if ((*it)->timestamp() < min)
603 it = dataBuffer_.erase(it);
610 getDataBufferStats();
613 else if (mode_ == RequestMode::Single && dataBuffer_.size() > fragment_ids_.size())
616 while (dataBuffer_.size() > fragment_ids_.size())
618 dataBuffer_.erase(dataBuffer_.begin());
628 if (should_stop() || monitoringInterval_ <= 0)
630 TLOG_DEBUG(
"CommandableFragmentGenerator") <<
"getMonitoringDataLoop: should_stop() is " << std::boolalpha << should_stop()
631 <<
" and monitoringInterval is " << monitoringInterval_ <<
", returning" << TLOG_ENDL;
634 TRACE(4,
"CFG::getMonitoringDataLoop Determining whether to call checkHWStatus_");
636 auto now = std::chrono::steady_clock::now();
637 if (std::chrono::duration_cast<std::chrono::microseconds>(now - lastMonitoringCall_).count() >= monitoringInterval_)
639 isHardwareOK_ = checkHWStatus_();
640 lastMonitoringCall_ = now;
642 usleep(monitoringInterval_ / 10);
650 if (should_stop() || !isHardwareOK_)
652 TLOG_DEBUG(
"CommandableFragmentGenerator") <<
"receiveRequestsLoop: should_stop is " << std::boolalpha << should_stop() <<
", and isHardwareOK is " << isHardwareOK_ << TLOG_ENDL;
657 if (mode_ == RequestMode::Ignored)
return;
658 TRACE(4,
"CFG::receiveRequestsLoop: Polling Request socket for new requests");
660 int ms_to_wait = 1000;
661 struct pollfd ufds[1];
662 ufds[0].fd = request_socket_;
663 ufds[0].events = POLLIN | POLLPRI;
664 int rv = poll(ufds, 1, ms_to_wait);
667 if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
669 TRACE(4,
"CFG: Recieved packet on Request channel");
671 recv(request_socket_, &hdr_buffer,
sizeof(hdr_buffer), 0);
672 TRACE(4,
"CFG: Request header word: 0x%x", (
int)hdr_buffer.
header);
675 std::vector<detail::RequestPacket> pkt_buffer(hdr_buffer.
packet_count);
678 for (
auto& buffer : pkt_buffer)
680 if (!buffer.isValid())
continue;
681 if (requests_.count(buffer.sequence_id) && requests_[buffer.sequence_id] != buffer.timestamp)
683 TLOG_ERROR(
"CommandableFragmentGenerator") <<
"Received conflicting request for SeqID "
684 << std::to_string(buffer.sequence_id) <<
"!"
685 <<
" Old ts=" << std::to_string(requests_[buffer.sequence_id])
686 <<
", new ts=" << std::to_string(buffer.timestamp) <<
". Keeping OLD!" << TLOG_ENDL;
688 else if (!requests_.count(buffer.sequence_id))
690 int delta = buffer.sequence_id - ev_counter();
691 TRACE(4,
"CFG: Recieved request for sequence ID %llu and timestamp %lu (delta: %d)", (
unsigned long long)buffer.sequence_id, (
unsigned long)buffer.timestamp, delta);
694 TRACE(4,
"CFG: Already serviced this request! Ignoring...");
698 std::unique_lock<std::mutex> tlk(request_mutex_);
699 requests_[buffer.sequence_id] = buffer.timestamp;
706 std::unique_lock<std::mutex> lock(request_mutex_);
707 requestCondition_.notify_all();
722 if (mode_ == RequestMode::Ignored)
724 while (dataBufferDepthFragments_ <= 0)
726 if (check_stop())
return false;
727 std::unique_lock<std::mutex> lock(dataBufferMutex_);
728 dataCondition_.wait_for(lock, std::chrono::milliseconds(10), [
this]() {
return dataBufferDepthFragments_ > 0; });
733 while (requests_.size() <= 0)
735 if (check_stop())
return false;
739 std::unique_lock<std::mutex> lock(request_mutex_);
740 requestCondition_.wait_for(lock, std::chrono::milliseconds(10), [
this]() {
return requests_.size() > 0; });
745 std::unique_lock<std::mutex> dlk(dataBufferMutex_);
747 if (mode_ == RequestMode::Ignored)
750 TRACE(4,
"CFG: Mode is Ignored; Copying data to output");
751 std::move(dataBuffer_.begin(), dataBuffer_.end(), std::inserter(frags, frags.end()));
754 else if (mode_ == RequestMode::Single)
757 sendEmptyFragments(frags);
759 if (dataBuffer_.size() > 0)
761 TRACE(4,
"CFG: Mode is Single; Sending copy of last event");
762 for (
auto& fragptr : dataBuffer_)
765 auto frag = fragptr.get();
766 auto newfrag = std::unique_ptr<artdaq::Fragment>(
new Fragment(ev_counter(), frag->fragmentID()));
767 newfrag->resize(frag->size() - detail::RawFragmentHeader::num_words());
768 memcpy(newfrag->headerAddress(), frag->headerAddress(), frag->sizeBytes());
769 newfrag->setTimestamp(requests_[ev_counter()]);
770 newfrag->setSequenceID(ev_counter());
771 frags.push_back(std::move(newfrag));
776 sendEmptyFragment(frags, ev_counter(),
"No data for");
779 ev_counter_inc(1,
true);
781 else if (mode_ == RequestMode::Buffer || mode_ == RequestMode::Window)
783 if (mode_ == RequestMode::Buffer)
786 sendEmptyFragments(frags);
788 for (
auto req = requests_.begin(); req != requests_.end();)
790 auto ts = req->second;
791 if (req->first < ev_counter())
793 req = requests_.erase(req);
796 if (req->first > ev_counter())
801 TRACE(5,
"CFG: ApplyRequestS: Checking that data exists for request window %llu (Buffered mode will always succeed)",(
unsigned long long)req->first);
802 Fragment::timestamp_t min = ts > windowOffset_ ? ts - windowOffset_ : 0;
803 Fragment::timestamp_t max = min + windowWidth_;
804 TRACE(5,
"CFG::ApplyRequests: min is %lu and max is %lu and last point in buffer is %lu (sz=%zu)",
805 (
unsigned long)min,(
unsigned long)max, (
unsigned long)(dataBuffer_.size() > 0 ? dataBuffer_.back()->timestamp() : 0), dataBuffer_.size());
806 bool windowClosed = mode_ != RequestMode::Window || (dataBuffer_.size() > 0 && dataBuffer_.back()->timestamp() >= max);
807 if (windowClosed || should_stop())
809 TLOG_DEBUG(
"CommandableFragmentGenerator") <<
"Creating ContainerFragment for Buffered or Window-requested Fragments" << TLOG_ENDL;
810 frags.emplace_back(
new artdaq::Fragment(ev_counter(), fragment_id()));
811 frags.back()->setTimestamp(ts);
812 ContainerFragmentLoader cfl(*frags.back());
814 if (mode_ == RequestMode::Window && should_stop() && !windowClosed) cfl.set_missing_data(
true);
815 if (mode_ == RequestMode::Window && dataBuffer_.size() > 0 && dataBuffer_.front()->timestamp() < min)
817 TLOG_DEBUG(
"CommandableFragmentGenerator") <<
"Request Window covers data that is either before data collection began or has fallen off the end of the buffer" << TLOG_ENDL;
818 cfl.set_missing_data(
true);
823 for (
auto it = dataBuffer_.begin(); it != dataBuffer_.end();)
825 if (mode_ == RequestMode::Window)
827 Fragment::timestamp_t fragT = (*it)->timestamp();
828 if (fragT < min || fragT > max)
835 TRACE(5,
"CFG::ApplyRequests: Adding Fragment with timestamp %llu to Container", (
unsigned long long)(*it)->timestamp());
836 cfl.addFragment(*it);
838 if (mode_ == RequestMode::Buffer || (mode_ == RequestMode::Window && uniqueWindows_))
840 it = dataBuffer_.erase(it);
847 req = requests_.erase(req);
848 ev_counter_inc(1,
true);
857 getDataBufferStats();
860 if (frags.size() > 0)
861 TRACE(4,
"CFG: Finished Processing Event %lu for fragment_id %i.", ev_counter() + 1, fragment_id());
867 TLOG_WARNING(
"CommandableFragmentGenerator") << desc <<
" request " << seqId <<
", sending empty fragment" << TLOG_ENDL;
868 auto frag =
new Fragment();
869 frag->setSequenceID(seqId);
870 frag->setSystemType(Fragment::EmptyFragmentType);
871 frags.emplace_back(FragmentPtr(frag));
877 auto sequence_id = Fragment::InvalidSequenceID;
878 auto timestamp = Fragment::InvalidTimestamp;
880 for (
auto it = requests_.begin(); it != requests_.end();)
882 auto seq = it->first;
883 auto ts = it->second;
886 if (++it == requests_.end())
892 if (seq < ev_counter())
continue;
895 sendEmptyFragment(frags, ev_counter(),
"Missed request for");
896 ev_counter_inc(1,
true);
900 if (sequence_id < ev_counter())
return;
901 requests_[sequence_id] = timestamp;
int fragment_id() const
Get the current Fragment ID, if there is only one.
int ResolveHost(char const *host_in, in_addr &addr)
Convert a string hostname to a in_addr suitable for socket communication.
virtual ~CommandableFragmentGenerator()
CommandableFragmentGenerator Destructor.
bool sendEmptyFragment(FragmentPtrs &frags, size_t sequenceId, std::string desc)
Send an EmptyFragmentType Fragment.
void getMonitoringDataLoop()
This function regularly calls checkHWStatus_(), and sets the isHardwareOK flag accordingly.
void startDataThread()
Function that launches the data thread (getDataLoop())
std::string ReportCmd(std::string const &which="")
Get a report about a user-specified run-time quantity.
bool dataBufferIsTooLarge()
Test the configured constraints on the data buffer.
void StopCmd(uint64_t timeout, uint64_t timestamp)
Stop the CommandableFragmentGenerator.
void StartCmd(int run, uint64_t timeout, uint64_t timestamp)
Start the CommandableFragmentGenerator.
bool check_stop()
Routine used by applyRequests to make sure that all outstanding requests have been fulfilled before r...
void ResumeCmd(uint64_t timeout, uint64_t timestamp)
Resume the CommandableFragmentGenerator.
CommandableFragmentGenerator()
CommandableFragmentGenerator default constructor.
bool getNext(FragmentPtrs &output) overridefinal
getNext calls either applyRequests or getNext_ to get any data that is ready to be sent to the EventB...
size_t ev_counter_inc(size_t step=1, bool force=false)
Increment the event counter, if the current RequestMode allows it.
void PauseCmd(uint64_t timeout, uint64_t timestamp)
Pause the CommandableFragmentGenerator.
void getDataLoop()
When separate_data_thread is set to true, this loop repeatedly calls getNext_ and adds returned Fragm...
The RequestPacket contains information about a single data request.
void startRequestReceiverThread()
Function that launches the data request receiver thread (receiveRequestsLoop())
void startMonitoringThread()
Function that launches the monitoring thread (getMonitoringDataLoop())
void checkDataBuffer()
Perform data buffer pruning operations. If the RequestMode is Single, removes all but the latest Frag...
std::string printMode_()
Return the string representation of the current RequestMode.
void sendEmptyFragments(FragmentPtrs &frags)
This function is for Buffered and Single request modes, as they can only respond to one data request ...
void getDataBufferStats()
Calculate the size of the dataBuffer and report appropriate metrics.
bool applyRequests(FragmentPtrs &output)
See if any requests have been received, and add the corresponding data Fragment objects to the output...
void receiveRequestsLoop()
This function receives data request packets, adding new requests to the request list.
void setupRequestListener()
Opens the socket used to listen for data requests.