1 #include "artdaq/DAQdata/Globals.hh"
2 #define TRACE_NAME (app_name + "_FragmentBuffer").c_str() // include these 2 first -
4 #include "artdaq/DAQrate/FragmentBuffer.hh"
6 #include <boost/exception/all.hpp>
7 #include <boost/throw_exception.hpp>
12 #include "canvas/Utilities/Exception.h"
13 #include "cetlib_except/exception.h"
14 #include "fhiclcpp/ParameterSet.h"
16 #include "artdaq-core/Data/ContainerFragmentLoader.hh"
17 #include "artdaq-core/Data/Fragment.hh"
18 #include "artdaq-core/Utilities/ExceptionHandler.hh"
19 #include "artdaq-core/Utilities/SimpleLookupPolicy.hh"
20 #include "artdaq-core/Utilities/TimeUtils.hh"
30 #define TLVL_ADDFRAGMENT TLVL_TRACE + 10
31 #define TLVL_CHECKSTOP TLVL_TRACE + 11
32 #define TLVL_WAITFORBUFFERREADY TLVL_TRACE + 15
33 #define TLVL_GETBUFFERSTATS TLVL_TRACE + 16
34 #define TLVL_CHECKDATABUFFER TLVL_TRACE + 17
35 #define TLVL_APPLYREQUESTS TLVL_TRACE + 9
36 #define TLVL_APPLYREQUESTS_VERBOSE TLVL_TRACE + 23
37 #define TLVL_SENDEMPTYFRAGMENTS TLVL_TRACE + 19
38 #define TLVL_CHECKWINDOWS TLVL_TRACE + 14
39 #define TLVL_EMPTYFRAGMENT TLVL_TRACE + 22
42 : next_sequence_id_(1)
44 , bufferModeKeepLatest_(ps.get<bool>(
"buffer_mode_keep_latest", false))
45 , windowOffset_(ps.get<Fragment::timestamp_t>(
"request_window_offset", 0))
46 , windowWidth_(ps.get<Fragment::timestamp_t>(
"request_window_width", 0))
47 , staleTimeout_(ps.get<Fragment::timestamp_t>(
"stale_fragment_timeout", 0))
48 , expectedType_(ps.get<Fragment::type_t>(
"expected_fragment_type", Fragment::type_t(Fragment::EmptyFragmentType)))
49 , uniqueWindows_(ps.get<bool>(
"request_windows_are_unique", true))
50 , sendMissingFragments_(ps.get<bool>(
"send_missing_request_fragments", true))
51 , missing_request_window_timeout_us_(ps.get<size_t>(
"missing_request_window_timeout_us", 5000000))
52 , window_close_timeout_us_(ps.get<size_t>(
"window_close_timeout_us", 2000000))
53 , circularDataBufferMode_(ps.get<bool>(
"circular_buffer_mode", false))
54 , maxDataBufferDepthFragments_(ps.get<int>(
"data_buffer_depth_fragments", 1000))
55 , maxDataBufferDepthBytes_(ps.get<size_t>(
"data_buffer_depth_mb", 1000) * 1024 * 1024)
56 , systemFragmentCount_(0)
59 auto fragment_ids = ps.get<std::vector<artdaq::Fragment::fragment_id_t>>(
"fragment_ids", std::vector<artdaq::Fragment::fragment_id_t>());
61 TLOG(TLVL_TRACE) <<
"artdaq::FragmentBuffer::FragmentBuffer(ps)";
64 if (fragment_id != -99)
66 if (fragment_ids.size() != 0)
68 auto report =
"Error in FragmentBuffer: can't both define \"fragment_id\" and \"fragment_ids\" in FHiCL document";
69 TLOG(TLVL_ERROR) << report;
70 throw cet::exception(
"FragmentBufferConfig") << report;
74 fragment_ids.emplace_back(fragment_id);
78 for (
auto&
id : fragment_ids)
80 dataBuffers_[id] = std::make_shared<DataBuffer>();
81 dataBuffers_[id]->DataBufferDepthBytes = 0;
82 dataBuffers_[id]->DataBufferDepthFragments = 0;
83 dataBuffers_[id]->HighestRequestSeen = 0;
84 dataBuffers_[id]->BufferFragmentKept =
false;
87 std::string modeString = ps.get<std::string>(
"request_mode",
"ignored");
88 if (modeString ==
"single" || modeString ==
"Single")
90 mode_ = RequestMode::Single;
92 else if (modeString.find(
"buffer") != std::string::npos || modeString.find(
"Buffer") != std::string::npos)
94 mode_ = RequestMode::Buffer;
96 else if (modeString ==
"window" || modeString ==
"Window")
98 mode_ = RequestMode::Window;
100 else if (modeString.find(
"ignore") != std::string::npos || modeString.find(
"Ignore") != std::string::npos)
102 mode_ = RequestMode::Ignored;
104 else if (modeString.find(
"sequence") != std::string::npos || modeString.find(
"Sequence") != std::string::npos)
106 mode_ = RequestMode::SequenceID;
108 if (mode_ != RequestMode::Ignored && !ps.get<
bool>(
"receive_requests",
false))
110 TLOG(TLVL_WARNING) <<
"Request Mode was requested as " << modeString <<
", but is being set to Ignored because \"receive_requests\" was not set to true";
111 mode_ = RequestMode::Ignored;
113 TLOG(TLVL_DEBUG) <<
"Request mode is " <<
printMode_();
118 TLOG(TLVL_INFO) <<
"Fragment Buffer Destructor; Clearing data buffers";
125 next_sequence_id_ = 1;
126 for (
auto&
id : dataBuffers_)
128 std::lock_guard<std::mutex> dlk(
id.second->DataBufferMutex);
129 id.second->DataBufferDepthBytes = 0;
130 id.second->DataBufferDepthFragments = 0;
131 id.second->BufferFragmentKept =
false;
132 id.second->DataBuffer.clear();
136 std::lock_guard<std::mutex> lk(systemFragmentMutex_);
137 systemFragments_.clear();
138 systemFragmentCount_ = 0;
144 std::unordered_map<Fragment::fragment_id_t, FragmentPtrs> frags_by_id;
145 while (!frags.empty())
147 auto dataIter = frags.begin();
148 auto frag_id = (*dataIter)->fragmentID();
150 if ((*dataIter)->type() == Fragment::EndOfRunFragmentType || (*dataIter)->type() == Fragment::EndOfSubrunFragmentType || (*dataIter)->type() == Fragment::InitFragmentType)
152 std::lock_guard<std::mutex> lk(systemFragmentMutex_);
153 systemFragments_.emplace_back(std::move(*dataIter));
154 systemFragmentCount_++;
155 frags.erase(dataIter);
159 if (!dataBuffers_.count(frag_id))
161 throw cet::exception(
"FragmentIDs") <<
"Received Fragment with Fragment ID " << frag_id <<
", which is not in the declared Fragment IDs list!";
164 frags_by_id[frag_id].emplace_back(std::move(*dataIter));
165 frags.erase(dataIter);
168 auto type_it = frags_by_id.begin();
169 while (type_it != frags_by_id.end())
171 auto frag_id = type_it->first;
173 waitForDataBufferReady(frag_id);
174 auto dataBuffer = dataBuffers_[frag_id];
175 std::lock_guard<std::mutex> dlk(dataBuffer->DataBufferMutex);
178 case RequestMode::Single:
180 auto dataIter = type_it->second.rbegin();
181 TLOG(TLVL_ADDFRAGMENT) <<
"Adding Fragment with Fragment ID " << frag_id <<
", Sequence ID " << (*dataIter)->sequenceID() <<
", and Timestamp " << (*dataIter)->timestamp() <<
" to buffer";
182 dataBuffer->DataBuffer.clear();
183 dataBuffer->DataBufferDepthBytes = (*dataIter)->sizeBytes();
184 dataBuffer->DataBuffer.emplace_back(std::move(*dataIter));
185 dataBuffer->DataBufferDepthFragments = 1;
186 type_it->second.clear();
189 case RequestMode::Buffer:
190 case RequestMode::Ignored:
191 case RequestMode::Window:
192 case RequestMode::SequenceID:
194 while (!type_it->second.empty())
196 auto dataIter = type_it->second.begin();
197 TLOG(TLVL_ADDFRAGMENT) <<
"Adding Fragment with Fragment ID " << frag_id <<
", Sequence ID " << (*dataIter)->sequenceID() <<
", and Timestamp " << (*dataIter)->timestamp() <<
" to buffer";
199 dataBuffer->DataBufferDepthBytes += (*dataIter)->sizeBytes();
200 dataBuffer->DataBuffer.emplace_back(std::move(*dataIter));
201 type_it->second.erase(dataIter);
203 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
206 getDataBufferStats(frag_id);
209 dataCondition_.notify_all();
214 TLOG(TLVL_CHECKSTOP) <<
"CFG::check_stop: should_stop=" << should_stop_.load();
216 if (!should_stop_.load())
return false;
217 if (mode_ == RequestMode::Ignored)
222 if (requestBuffer_ !=
nullptr)
225 TLOG(TLVL_DEBUG) <<
"should_stop is true, requestBuffer_->isRunning() is " << std::boolalpha << requestBuffer_->isRunning();
226 if (!requestBuffer_->isRunning())
238 case RequestMode::Single:
240 case RequestMode::Buffer:
242 case RequestMode::Window:
244 case RequestMode::Ignored:
246 case RequestMode::SequenceID:
256 for (
auto&
id : dataBuffers_) count +=
id.second->DataBufferDepthFragments;
257 count += systemFragmentCount_.load();
263 if (!dataBuffers_.count(
id))
265 TLOG(TLVL_ERROR) <<
"DataBufferError: "
266 <<
"Error in FragmentBuffer: Cannot wait for data buffer for ID " <<
id <<
" because it does not exist!";
267 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot wait for data buffer for ID " <<
id <<
" because it does not exist!";
269 auto startwait = std::chrono::steady_clock::now();
271 auto lastwaittime = 0ULL;
272 auto dataBuffer = dataBuffers_[id];
274 while (dataBufferIsTooLarge(
id))
276 if (!circularDataBufferMode_)
278 if (should_stop_.load())
280 TLOG(TLVL_DEBUG) <<
"Run ended while waiting for buffer to shrink!";
281 getDataBufferStats(
id);
282 dataCondition_.notify_all();
285 auto waittime = TimeUtils::GetElapsedTimeMilliseconds(startwait);
287 if (first || (waittime != lastwaittime && waittime % 1000 == 0))
289 std::lock_guard<std::mutex> lk(dataBuffer->DataBufferMutex);
290 if (dataBufferIsTooLarge(
id))
292 TLOG(TLVL_WARNING) <<
"Bad Omen: Data Buffer has exceeded its size limits. "
293 <<
"(seq_id=" << next_sequence_id_ <<
", frag_id=" <<
id
294 <<
", frags=" << dataBuffer->DataBufferDepthFragments <<
"/" << maxDataBufferDepthFragments_
295 <<
", szB=" << dataBuffer->DataBufferDepthBytes <<
"/" << maxDataBufferDepthBytes_ <<
")"
296 <<
", timestamps=" << dataBuffer->DataBuffer.front()->timestamp() <<
"-" << dataBuffer->DataBuffer.back()->timestamp();
297 TLOG(TLVL_TRACE) <<
"Bad Omen: Possible causes include requests not getting through or Ignored-mode BR issues";
301 if (waittime % 5 && waittime != lastwaittime)
303 TLOG(TLVL_WAITFORBUFFERREADY) <<
"getDataLoop: Data Retreival paused for " << waittime <<
" ms waiting for data buffer to drain";
305 lastwaittime = waittime;
310 std::lock_guard<std::mutex> lk(dataBuffer->DataBufferMutex);
311 if (dataBufferIsTooLarge(
id))
313 auto begin = dataBuffer->DataBuffer.begin();
314 if (begin == dataBuffer->DataBuffer.end())
316 TLOG(TLVL_WARNING) <<
"Data buffer is reported as too large, but doesn't contain any Fragments! Possible corrupt memory!";
321 TLOG(TLVL_WAITFORBUFFERREADY) <<
"waitForDataBufferReady: Dropping Fragment with timestamp " << (*begin)->timestamp() <<
" from data buffer (Buffer over-size, circular data buffer mode)";
323 dataBuffer->DataBufferDepthBytes -= (*begin)->sizeBytes();
324 dataBuffer->DataBuffer.erase(begin);
325 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
326 dataBuffer->BufferFragmentKept =
false;
336 if (!dataBuffers_.count(
id))
338 TLOG(TLVL_ERROR) <<
"DataBufferError: "
339 <<
"Error in FragmentBuffer: Cannot check size of data buffer for ID " <<
id <<
" because it does not exist!";
340 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot check size of data buffer for ID " <<
id <<
" because it does not exist!";
342 auto dataBuffer = dataBuffers_[id];
343 return (maxDataBufferDepthFragments_ > 0 && dataBuffer->DataBufferDepthFragments.load() > maxDataBufferDepthFragments_) ||
344 (maxDataBufferDepthBytes_ > 0 && dataBuffer->DataBufferDepthBytes.load() > maxDataBufferDepthBytes_);
349 if (!dataBuffers_.count(
id))
351 TLOG(TLVL_ERROR) <<
"DataBufferError: "
352 <<
"Error in FragmentBuffer: Cannot get stats of data buffer for ID " <<
id <<
" because it does not exist!";
353 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot get stats of data buffer for ID " <<
id <<
" because it does not exist!";
355 auto dataBuffer = dataBuffers_[id];
359 TLOG(TLVL_GETBUFFERSTATS) <<
"getDataBufferStats: Sending Metrics";
360 metricMan->sendMetric(
"Buffer Depth Fragments", dataBuffer->DataBufferDepthFragments.load(),
"fragments", 1, MetricMode::LastPoint);
361 metricMan->sendMetric(
"Buffer Depth Bytes", dataBuffer->DataBufferDepthBytes.load(),
"bytes", 1, MetricMode::LastPoint);
363 auto bufferDepthFragmentsPercent = dataBuffer->DataBufferDepthFragments.load() * 100 /
static_cast<double>(maxDataBufferDepthFragments_);
364 auto bufferDepthBytesPercent = dataBuffer->DataBufferDepthBytes.load() * 100 /
static_cast<double>(maxDataBufferDepthBytes_);
365 metricMan->sendMetric(
"Fragment Buffer Full %Fragments", bufferDepthFragmentsPercent,
"%", 3, MetricMode::LastPoint);
366 metricMan->sendMetric(
"Fragment Buffer Full %Bytes", bufferDepthBytesPercent,
"%", 3, MetricMode::LastPoint);
367 metricMan->sendMetric(
"Fragment Buffer Full %", bufferDepthFragmentsPercent > bufferDepthBytesPercent ? bufferDepthFragmentsPercent : bufferDepthBytesPercent,
"%", 1, MetricMode::LastPoint);
369 TLOG(TLVL_GETBUFFERSTATS) <<
"getDataBufferStats: frags=" << dataBuffer->DataBufferDepthFragments.load() <<
"/" << maxDataBufferDepthFragments_
370 <<
", sz=" << dataBuffer->DataBufferDepthBytes.load() <<
"/" << maxDataBufferDepthBytes_;
375 if (!dataBuffers_.count(
id))
377 TLOG(TLVL_ERROR) <<
"DataBufferError: "
378 <<
"Error in FragmentBuffer: Cannot check data buffer for ID " <<
id <<
" because it does not exist!";
379 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot check data buffer for ID " <<
id <<
" because it does not exist!";
382 if (dataBuffers_[
id]->DataBufferDepthFragments > 0 && mode_ != RequestMode::Single && mode_ != RequestMode::Ignored)
384 auto dataBuffer = dataBuffers_[id];
385 std::lock_guard<std::mutex> lk(dataBuffer->DataBufferMutex);
388 while (dataBufferIsTooLarge(
id))
390 auto begin = dataBuffer->DataBuffer.begin();
391 TLOG(TLVL_CHECKDATABUFFER) <<
"checkDataBuffer: Dropping Fragment with timestamp " << (*begin)->timestamp() <<
" from data buffer (Buffer over-size)";
392 dataBuffer->DataBufferDepthBytes -= (*begin)->sizeBytes();
393 dataBuffer->DataBuffer.erase(begin);
394 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
395 dataBuffer->BufferFragmentKept =
false;
398 TLOG(TLVL_CHECKDATABUFFER) <<
"DataBufferDepthFragments is " << dataBuffer->DataBufferDepthFragments <<
", DataBuffer.size is " << dataBuffer->DataBuffer.size();
399 if (dataBuffer->DataBufferDepthFragments > 0 && staleTimeout_ > 0)
401 TLOG(TLVL_CHECKDATABUFFER) <<
"Determining if Fragments can be dropped from data buffer";
402 Fragment::timestamp_t last = dataBuffer->DataBuffer.back()->timestamp();
403 Fragment::timestamp_t min = last > staleTimeout_ ? last - staleTimeout_ : 0;
404 for (
auto it = dataBuffer->DataBuffer.begin(); it != dataBuffer->DataBuffer.end();)
406 if ((*it)->timestamp() < min)
408 TLOG(TLVL_CHECKDATABUFFER) <<
"checkDataBuffer: Dropping Fragment with timestamp " << (*it)->timestamp() <<
" from data buffer (timeout=" << staleTimeout_ <<
", min=" << min <<
")";
409 dataBuffer->DataBufferDepthBytes -= (*it)->sizeBytes();
410 dataBuffer->BufferFragmentKept =
false;
411 it = dataBuffer->DataBuffer.erase(it);
412 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
427 TLOG(TLVL_APPLYREQUESTS) <<
"Mode is Ignored; Copying data to output";
428 for (
auto&
id : dataBuffers_)
430 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
431 if (
id.second && !
id.second->DataBuffer.empty() &&
id.second->DataBuffer.back()->sequenceID() >= next_sequence_id_)
433 next_sequence_id_ =
id.second->DataBuffer.back()->sequenceID() + 1;
435 std::move(
id.second->DataBuffer.begin(),
id.second->DataBuffer.end(), std::inserter(frags, frags.end()));
436 id.second->DataBufferDepthBytes = 0;
437 id.second->DataBufferDepthFragments = 0;
438 id.second->BufferFragmentKept =
false;
439 id.second->DataBuffer.clear();
446 auto requests = requestBuffer_->GetRequests();
447 while (requests.size() > 1)
450 requestBuffer_->RemoveRequest(requests.begin()->first);
451 requests.erase(requests.begin());
453 sendEmptyFragments(frags, requests);
456 if (requests.size() == 0 || !requests.count(next_sequence_id_))
return;
458 for (
auto&
id : dataBuffers_)
460 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
461 if (
id.second->DataBufferDepthFragments > 0)
463 assert(
id.second->DataBufferDepthFragments == 1);
464 TLOG(TLVL_APPLYREQUESTS) <<
"Mode is Single; Sending copy of last event (SeqID " << next_sequence_id_ <<
")";
465 for (
auto& fragptr :
id.second->DataBuffer)
468 auto frag = fragptr.get();
469 auto newfrag = std::unique_ptr<artdaq::Fragment>(
new Fragment(next_sequence_id_, frag->fragmentID()));
470 newfrag->resize(frag->size() - detail::RawFragmentHeader::num_words());
471 memcpy(newfrag->headerAddress(), frag->headerAddress(), frag->sizeBytes());
472 newfrag->setTimestamp(requests[next_sequence_id_]);
473 newfrag->setSequenceID(next_sequence_id_);
474 frags.push_back(std::move(newfrag));
479 sendEmptyFragment(frags, next_sequence_id_,
id.first,
"No data for");
482 requestBuffer_->RemoveRequest(next_sequence_id_);
489 auto requests = requestBuffer_->GetRequests();
490 while (requests.size() > 1)
493 requestBuffer_->RemoveRequest(requests.begin()->first);
494 requests.erase(requests.begin());
496 sendEmptyFragments(frags, requests);
499 if (requests.size() == 0 || !requests.count(next_sequence_id_))
return;
501 for (
auto&
id : dataBuffers_)
503 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsBufferMode: Creating ContainerFragment for Buffered Fragments (SeqID " << next_sequence_id_ <<
")";
504 frags.emplace_back(
new artdaq::Fragment(next_sequence_id_,
id.first));
505 frags.back()->setTimestamp(requests[next_sequence_id_]);
506 ContainerFragmentLoader cfl(*frags.back());
507 cfl.set_missing_data(
false);
510 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
511 if (
id.second->BufferFragmentKept &&
id.second->DataBufferDepthFragments > 1)
513 id.second->DataBufferDepthBytes -=
id.second->DataBuffer.front()->sizeBytes();
514 id.second->DataBuffer.erase(
id.second->DataBuffer.begin());
515 id.second->DataBufferDepthFragments =
id.second->DataBuffer.size();
519 FragmentPtrs fragsToAdd;
520 std::move(
id.second->DataBuffer.begin(), --
id.second->DataBuffer.end(), std::back_inserter(fragsToAdd));
521 id.second->DataBuffer.erase(
id.second->DataBuffer.begin(), --
id.second->DataBuffer.end());
523 if (fragsToAdd.size() > 0)
525 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsBufferMode: Adding " << fragsToAdd.size() <<
" Fragments to Container (SeqID " << next_sequence_id_ <<
")";
526 cfl.addFragments(fragsToAdd);
530 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsBufferMode: No Fragments to add (SeqID " << next_sequence_id_ <<
")";
533 if (
id.second->DataBuffer.size() == 1)
535 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsBufferMode: Adding Fragment with timestamp " <<
id.second->DataBuffer.front()->timestamp() <<
" to Container with sequence ID " << next_sequence_id_;
536 cfl.addFragment(
id.second->DataBuffer.front());
537 if (bufferModeKeepLatest_)
539 id.second->BufferFragmentKept =
true;
540 id.second->DataBufferDepthBytes =
id.second->DataBuffer.front()->sizeBytes();
541 id.second->DataBufferDepthFragments =
id.second->DataBuffer.size();
545 id.second->DataBuffer.clear();
546 id.second->BufferFragmentKept =
false;
547 id.second->DataBufferDepthBytes = 0;
548 id.second->DataBufferDepthFragments = 0;
552 requestBuffer_->RemoveRequest(next_sequence_id_);
558 auto dataBuffer = dataBuffers_[id];
560 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Checking that data exists for request window " << seq;
561 Fragment::timestamp_t min = ts > windowOffset_ ? ts - windowOffset_ : 0;
562 Fragment::timestamp_t max = ts + windowWidth_ > windowOffset_ ? ts + windowWidth_ - windowOffset_ : 1;
564 TLOG(TLVL_APPLYREQUESTS) <<
"ApplyRequestsWindowsMode_CheckAndFillDataBuffer: min is " << min <<
", max is " << max
565 <<
" and first/last points in buffer are " << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.front()->timestamp() : 0)
566 <<
"/" << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.back()->timestamp() : 0)
567 <<
" (sz=" << dataBuffer->DataBufferDepthFragments <<
" [" << dataBuffer->DataBufferDepthBytes.load()
568 <<
"/" << maxDataBufferDepthBytes_ <<
"])";
569 bool windowClosed = dataBuffer->DataBufferDepthFragments > 0 && dataBuffer->DataBuffer.back()->timestamp() >= max;
570 bool windowTimeout = !windowClosed && TimeUtils::GetElapsedTimeMicroseconds(requestBuffer_->GetRequestTime(seq)) > window_close_timeout_us_;
573 TLOG(TLVL_WARNING) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: A timeout occurred waiting for data to close the request window ({" << min <<
"-" << max
574 <<
"}, buffer={" << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.front()->timestamp() : 0) <<
"-"
575 << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.back()->timestamp() : 0)
576 <<
"} ). Time waiting: "
577 << TimeUtils::GetElapsedTimeMicroseconds(requestBuffer_->GetRequestTime(seq)) <<
" us "
578 <<
"(> " << window_close_timeout_us_ <<
" us).";
580 if (windowClosed || windowTimeout)
582 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Creating ContainerFragment for Window-requested Fragments (SeqID " << seq <<
")";
583 frags.emplace_back(
new artdaq::Fragment(seq,
id));
584 frags.back()->setTimestamp(ts);
585 ContainerFragmentLoader cfl(*frags.back());
599 if (!windowClosed || (dataBuffer->DataBufferDepthFragments > 0 && dataBuffer->DataBuffer.front()->timestamp() > min))
601 TLOG(TLVL_DEBUG) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Request window starts before and/or ends after the current data buffer, setting ContainerFragment's missing_data flag!"
602 <<
" (requestWindowRange=[" << min <<
"," << max <<
"], "
603 <<
"buffer={" << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.front()->timestamp() : 0) <<
"-"
604 << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.back()->timestamp() : 0) <<
"} (SeqID " << seq <<
")";
605 cfl.set_missing_data(
true);
608 auto it = dataBuffer->DataBuffer.begin();
612 it = dataBuffer->DataBuffer.end();
614 while (it != dataBuffer->DataBuffer.begin())
616 if ((*it)->timestamp() < min)
624 FragmentPtrs fragsToAdd;
626 for (; it != dataBuffer->DataBuffer.end();)
628 Fragment::timestamp_t fragT = (*it)->timestamp();
634 if (fragT > max || (fragT == max && windowWidth_ > 0))
637 TLOG(TLVL_APPLYREQUESTS_VERBOSE) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Adding Fragment with timestamp " << (*it)->timestamp() <<
" to Container (SeqID " << seq <<
")";
640 dataBuffer->DataBufferDepthBytes -= (*it)->sizeBytes();
641 fragsToAdd.emplace_back(std::move(*it));
642 it = dataBuffer->DataBuffer.erase(it);
646 fragsToAdd.emplace_back(it->get());
651 if (fragsToAdd.size() > 0)
653 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Adding " << fragsToAdd.size() <<
" Fragments to Container (SeqID " << seq <<
")";
654 cfl.addFragments(fragsToAdd);
659 for (
auto& frag : fragsToAdd)
668 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: No Fragments to add (SeqID " << seq <<
")";
671 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
672 dataBuffer->WindowsSent[seq] = std::chrono::steady_clock::now();
673 if (seq > dataBuffer->HighestRequestSeen) dataBuffer->HighestRequestSeen = seq;
679 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode BEGIN";
681 auto requests = requestBuffer_->GetRequests();
683 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode: Starting request processing for " << requests.size() <<
" requests";
684 for (
auto req = requests.begin(); req != requests.end();)
686 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode: processing request with sequence ID " << req->first <<
", timestamp " << req->second;
688 while (req->first < next_sequence_id_ && requests.size() > 0)
690 TLOG(TLVL_APPLYREQUESTS_VERBOSE) <<
"applyRequestsWindowMode: Clearing passed request for sequence ID " << req->first;
691 requestBuffer_->RemoveRequest(req->first);
692 req = requests.erase(req);
694 if (requests.size() == 0)
break;
696 auto ts = req->second;
697 if (ts == Fragment::InvalidTimestamp)
699 TLOG(TLVL_ERROR) <<
"applyRequestsWindowMode: Received InvalidTimestamp in request " << req->first <<
", cannot apply! Check that push-mode BRs are filling appropriate timestamps in their Fragments!";
700 req = requests.erase(req);
704 for (
auto&
id : dataBuffers_)
706 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
707 if (!
id.second->WindowsSent.count(req->first))
709 applyRequestsWindowMode_CheckAndFillDataBuffer(frags,
id.first, req->first, req->second);
712 checkSentWindows(req->first);
717 std::set<artdaq::Fragment::sequence_id_t> seqs;
718 for (
auto&
id : dataBuffers_)
720 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
721 for (
auto& seq :
id.second->WindowsSent)
723 seqs.insert(seq.first);
726 for (
auto& seq : seqs)
728 checkSentWindows(seq);
734 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsSequenceIDMode BEGIN";
736 auto requests = requestBuffer_->GetRequests();
738 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsSequenceIDMode: Starting request processing";
739 for (
auto req = requests.begin(); req != requests.end();)
741 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsSequenceIDMode: Checking that data exists for request SequenceID " << req->first;
743 for (
auto&
id : dataBuffers_)
745 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
746 if (!
id.second->WindowsSent.count(req->first))
748 TLOG(TLVL_APPLYREQUESTS_VERBOSE) <<
"Searching id " <<
id.first <<
" for Fragments with Sequence ID " << req->first;
749 for (
auto it =
id.second->DataBuffer.begin(); it !=
id.second->DataBuffer.end();)
751 auto seq = (*it)->sequenceID();
752 TLOG(TLVL_APPLYREQUESTS_VERBOSE) <<
"applyRequestsSequenceIDMode: Fragment SeqID " << seq <<
", request ID " << req->first;
753 if (seq == req->first)
755 TLOG(TLVL_APPLYREQUESTS_VERBOSE) <<
"applyRequestsSequenceIDMode: Adding Fragment to output";
756 id.second->WindowsSent[req->first] = std::chrono::steady_clock::now();
757 id.second->DataBufferDepthBytes -= (*it)->sizeBytes();
758 frags.push_back(std::move(*it));
759 it =
id.second->DataBuffer.erase(it);
760 id.second->DataBufferDepthFragments =
id.second->DataBuffer.size();
768 if (req->first >
id.second->HighestRequestSeen)
id.second->HighestRequestSeen = req->first;
770 checkSentWindows(req->first);
775 std::set<artdaq::Fragment::sequence_id_t> seqs;
776 for (
auto&
id : dataBuffers_)
778 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
779 for (
auto& seq :
id.second->WindowsSent)
781 seqs.insert(seq.first);
784 for (
auto& seq : seqs)
786 checkSentWindows(seq);
798 if (mode_ == RequestMode::Ignored)
800 auto start_time = std::chrono::steady_clock::now();
801 while (dataBufferFragmentCount_() == 0 && TimeUtils::GetElapsedTime(start_time) < 1.0)
803 if (check_stop())
return false;
804 std::unique_lock<std::mutex> lock(dataConditionMutex_);
805 dataCondition_.wait_for(lock, std::chrono::milliseconds(10), [
this]() {
return dataBufferFragmentCount_() > 0; });
808 else if (requestBuffer_ ==
nullptr)
810 TLOG(TLVL_ERROR) <<
"Request Buffer must be set (via SetRequestBuffer) before applyRequests/getData can be called!";
815 if ((check_stop() && requestBuffer_->size() == 0))
return false;
817 std::unique_lock<std::mutex> lock(dataConditionMutex_);
818 dataCondition_.wait_for(lock, std::chrono::milliseconds(10));
825 while (requestBuffer_->size() == 0 && counter < 100)
827 if (check_stop())
return false;
831 requestBuffer_->WaitForRequests(10);
836 if (systemFragmentCount_.load() > 0)
838 std::lock_guard<std::mutex> lk(systemFragmentMutex_);
839 TLOG(TLVL_INFO) <<
"Copying " << systemFragmentCount_.load() <<
" System Fragments into output";
841 std::move(systemFragments_.begin(), systemFragments_.end(), std::inserter(frags, frags.end()));
842 systemFragments_.clear();
843 systemFragmentCount_ = 0;
848 case RequestMode::Single:
849 applyRequestsSingleMode(frags);
851 case RequestMode::Window:
852 applyRequestsWindowMode(frags);
854 case RequestMode::Buffer:
855 applyRequestsBufferMode(frags);
857 case RequestMode::SequenceID:
858 applyRequestsSequenceIDMode(frags);
860 case RequestMode::Ignored:
862 applyRequestsIgnoredMode(frags);
866 getDataBuffersStats();
868 if (frags.size() > 0)
869 TLOG(TLVL_APPLYREQUESTS) <<
"Finished Processing requests, returning " << frags.size() <<
" fragments, current ev_counter is " << next_sequence_id_;
875 TLOG(TLVL_EMPTYFRAGMENT) << desc <<
" sequence ID " << seqId <<
", sending empty fragment";
876 auto frag =
new Fragment();
877 frag->setSequenceID(seqId);
878 frag->setFragmentID(fragmentId);
879 frag->setSystemType(Fragment::EmptyFragmentType);
880 frags.emplace_back(FragmentPtr(frag));
886 if (requests.size() > 0)
888 TLOG(TLVL_SENDEMPTYFRAGMENTS) <<
"Sending Empty Fragments for Sequence IDs from " << next_sequence_id_ <<
" up to but not including " << requests.begin()->first;
889 while (requests.begin()->first > next_sequence_id_)
891 if (sendMissingFragments_)
893 for (
auto& fid : dataBuffers_)
895 sendEmptyFragment(frags, next_sequence_id_, fid.first,
"Missed request for");
905 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Checking if request " << seq <<
" can be removed from request list";
906 bool seqComplete =
true;
907 bool seqTimeout =
false;
908 for (
auto&
id : dataBuffers_)
910 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
911 if (!
id.second->WindowsSent.count(seq) ||
id.second->HighestRequestSeen < seq)
915 if (
id.second->WindowsSent.count(seq) && TimeUtils::GetElapsedTimeMicroseconds(
id.second->WindowsSent[seq]) > missing_request_window_timeout_us_)
922 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Request " << seq <<
" is complete, removing from requestBuffer_.";
923 requestBuffer_->RemoveRequest(seq);
925 if (next_sequence_id_ == seq)
927 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Sequence ID matches ev_counter, incrementing ev_counter (" << next_sequence_id_ <<
")";
929 for (
auto&
id : dataBuffers_)
931 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
932 id.second->WindowsSent.erase(seq);
940 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Sent Window history indicates that requests between " << next_sequence_id_ <<
" and " << seq <<
" have timed out.";
941 while (next_sequence_id_ <= seq)
943 if (next_sequence_id_ < seq) TLOG(TLVL_CHECKWINDOWS) <<
"Missed request for sequence ID " << next_sequence_id_ <<
"! Will not send any data for this sequence ID!";
944 requestBuffer_->RemoveRequest(next_sequence_id_);
946 for (
auto&
id : dataBuffers_)
948 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
949 id.second->WindowsSent.erase(next_sequence_id_);
void AddFragmentsToBuffer(FragmentPtrs frags)
Add Fragments to the FragmentBuffer.
size_t dataBufferFragmentCount_()
Get the total number of Fragments in all data buffers.
std::string printMode_()
Return the string representation of the current RequestMode.
bool applyRequests(FragmentPtrs &frags)
See if any requests have been received, and add the corresponding data Fragment objects to the output...
FragmentBuffer(const fhicl::ParameterSet &ps)
FragmentBuffer Constructor.
bool waitForDataBufferReady(Fragment::fragment_id_t id)
Wait for the data buffer to drain (dataBufferIsTooLarge returns false), periodically reporting status...
void applyRequestsIgnoredMode(artdaq::FragmentPtrs &frags)
Create fragments using data buffer for request mode Ignored. Precondition: dataBufferMutex_ and reque...
void applyRequestsWindowMode_CheckAndFillDataBuffer(artdaq::FragmentPtrs &frags, artdaq::Fragment::fragment_id_t id, artdaq::Fragment::sequence_id_t seq, artdaq::Fragment::timestamp_t ts)
bool check_stop()
Routine used by applyRequests to make sure that all outstanding requests have been fulfilled before r...
void Reset(bool stop)
Reset the FragmentBuffer (flushes all Fragments from buffers)
void checkSentWindows(Fragment::sequence_id_t seq)
Check the windows_sent_ooo_ map for sequence IDs that may be removed.
artdaq::Fragment::fragment_id_t fragment_id() const
Get the Fragment ID of this Fragment generator.
void checkDataBuffer(Fragment::fragment_id_t id)
Perform data buffer pruning operations for the given buffer. If the RequestMode is Single...
bool dataBufferIsTooLarge(Fragment::fragment_id_t id)
Test the configured constraints on the data buffer.
bool sendEmptyFragment(FragmentPtrs &frags, size_t sequenceId, Fragment::fragment_id_t fragmentId, std::string desc)
Send an EmptyFragmentType Fragment.
void applyRequestsBufferMode(artdaq::FragmentPtrs &frags)
Create fragments using data buffer for request mode Buffer. Precondition: dataBufferMutex_ and reques...
void applyRequestsWindowMode(artdaq::FragmentPtrs &frags)
Create fragments using data buffer for request mode Window. Precondition: dataBufferMutex_ and reques...
virtual ~FragmentBuffer()
FragmentBuffer Destructor.
void sendEmptyFragments(FragmentPtrs &frags, std::map< Fragment::sequence_id_t, Fragment::timestamp_t > &requests)
This function is for Buffered and Single request modes, as they can only respond to one data request ...
void applyRequestsSequenceIDMode(artdaq::FragmentPtrs &frags)
Create fragments using data buffer for request mode SequenceID. Precondition: dataBufferMutex_ and re...
void applyRequestsSingleMode(artdaq::FragmentPtrs &frags)
Create fragments using data buffer for request mode Single. Precondition: dataBufferMutex_ and reques...
void getDataBufferStats(Fragment::fragment_id_t id)
Calculate the size of the dataBuffer and report appropriate metrics.