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 32
31 #define TLVL_CHECKSTOP 33
32 #define TLVL_WAITFORBUFFERREADY 34
33 #define TLVL_GETBUFFERSTATS 35
34 #define TLVL_CHECKDATABUFFER 36
35 #define TLVL_APPLYREQUESTS 37
36 #define TLVL_APPLYREQUESTS_VERBOSE 38
37 #define TLVL_SENDEMPTYFRAGMENTS 39
38 #define TLVL_CHECKWINDOWS 40
39 #define TLVL_EMPTYFRAGMENT 41
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 , error_on_empty_(ps.get<bool>(
"error_on_empty_fragment", false))
54 , circularDataBufferMode_(ps.get<bool>(
"circular_buffer_mode", false))
55 , maxDataBufferDepthFragments_(ps.get<int>(
"data_buffer_depth_fragments", 1000))
56 , maxDataBufferDepthBytes_(ps.get<size_t>(
"data_buffer_depth_mb", 1000) * 1024 * 1024)
57 , systemFragmentCount_(0)
60 auto fragment_ids = ps.get<std::vector<artdaq::Fragment::fragment_id_t>>(
"fragment_ids", std::vector<artdaq::Fragment::fragment_id_t>());
62 TLOG(TLVL_DEBUG + 33) <<
"artdaq::FragmentBuffer::FragmentBuffer(ps)";
65 if (fragment_id != -99)
67 if (fragment_ids.size() != 0)
69 auto report =
"Error in FragmentBuffer: can't both define \"fragment_id\" and \"fragment_ids\" in FHiCL document";
70 TLOG(TLVL_ERROR) << report;
71 throw cet::exception(
"FragmentBufferConfig") << report;
75 fragment_ids.emplace_back(fragment_id);
79 for (
auto&
id : fragment_ids)
81 dataBuffers_[id] = std::make_shared<DataBuffer>();
82 dataBuffers_[id]->DataBufferDepthBytes = 0;
83 dataBuffers_[id]->DataBufferDepthFragments = 0;
84 dataBuffers_[id]->HighestRequestSeen = 0;
85 dataBuffers_[id]->BufferFragmentKept =
false;
88 std::string modeString = ps.get<std::string>(
"request_mode",
"ignored");
89 if (modeString ==
"single" || modeString ==
"Single")
91 mode_ = RequestMode::Single;
93 else if (modeString.find(
"buffer") != std::string::npos || modeString.find(
"Buffer") != std::string::npos)
95 mode_ = RequestMode::Buffer;
97 else if (modeString ==
"window" || modeString ==
"Window")
99 mode_ = RequestMode::Window;
101 else if (modeString.find(
"ignore") != std::string::npos || modeString.find(
"Ignore") != std::string::npos)
103 mode_ = RequestMode::Ignored;
105 else if (modeString.find(
"sequence") != std::string::npos || modeString.find(
"Sequence") != std::string::npos)
107 mode_ = RequestMode::SequenceID;
109 if (mode_ != RequestMode::Ignored && !ps.get<
bool>(
"receive_requests",
false))
111 TLOG(TLVL_WARNING) <<
"Request Mode was requested as " << modeString <<
", but is being set to Ignored because \"receive_requests\" was not set to true";
112 mode_ = RequestMode::Ignored;
114 TLOG(TLVL_DEBUG + 32) <<
"Request mode is " <<
printMode_();
119 TLOG(TLVL_INFO) <<
"Fragment Buffer Destructor; Clearing data buffers";
126 next_sequence_id_ = 1;
127 for (
auto&
id : dataBuffers_)
129 std::lock_guard<std::mutex> dlk(
id.second->DataBufferMutex);
130 id.second->DataBufferDepthBytes = 0;
131 id.second->DataBufferDepthFragments = 0;
132 id.second->BufferFragmentKept =
false;
133 id.second->DataBuffer.clear();
137 std::lock_guard<std::mutex> lk(systemFragmentMutex_);
138 systemFragments_.clear();
139 systemFragmentCount_ = 0;
145 std::unordered_map<Fragment::fragment_id_t, FragmentPtrs> frags_by_id;
146 while (!frags.empty())
148 auto dataIter = frags.begin();
149 auto frag_id = (*dataIter)->fragmentID();
151 if ((*dataIter)->type() == Fragment::EndOfRunFragmentType || (*dataIter)->type() == Fragment::EndOfSubrunFragmentType || (*dataIter)->type() == Fragment::InitFragmentType)
153 std::lock_guard<std::mutex> lk(systemFragmentMutex_);
154 systemFragments_.emplace_back(std::move(*dataIter));
155 systemFragmentCount_++;
156 frags.erase(dataIter);
160 if (!dataBuffers_.count(frag_id))
162 throw cet::exception(
"FragmentIDs") <<
"Received Fragment with Fragment ID " << frag_id <<
", which is not in the declared Fragment IDs list!";
165 frags_by_id[frag_id].emplace_back(std::move(*dataIter));
166 frags.erase(dataIter);
169 auto type_it = frags_by_id.begin();
170 while (type_it != frags_by_id.end())
172 auto frag_id = type_it->first;
174 waitForDataBufferReady(frag_id);
175 auto dataBuffer = dataBuffers_[frag_id];
176 std::lock_guard<std::mutex> dlk(dataBuffer->DataBufferMutex);
179 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 + 32) <<
"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 + 32) <<
"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_DEBUG + 33) <<
"Bad Omen: Possible causes include requests not getting through or Ignored-mode BR issues";
301 metricMan->sendMetric(
"Bad Omen wait time", waittime / 1000.0,
"s", 1, MetricMode::LastPoint);
306 if (waittime % 5 && waittime != lastwaittime)
308 TLOG(TLVL_WAITFORBUFFERREADY) <<
"getDataLoop: Data Retreival paused for " << waittime <<
" ms waiting for data buffer to drain";
310 lastwaittime = waittime;
315 std::lock_guard<std::mutex> lk(dataBuffer->DataBufferMutex);
316 if (dataBufferIsTooLarge(
id))
318 auto begin = dataBuffer->DataBuffer.begin();
319 if (begin == dataBuffer->DataBuffer.end())
321 TLOG(TLVL_WARNING) <<
"Data buffer is reported as too large, but doesn't contain any Fragments! Possible corrupt memory!";
326 TLOG(TLVL_WAITFORBUFFERREADY) <<
"waitForDataBufferReady: Dropping Fragment with timestamp " << (*begin)->timestamp() <<
" from data buffer (Buffer over-size, circular data buffer mode)";
328 dataBuffer->DataBufferDepthBytes -= (*begin)->sizeBytes();
329 dataBuffer->DataBuffer.erase(begin);
330 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
331 dataBuffer->BufferFragmentKept =
false;
341 if (!dataBuffers_.count(
id))
343 TLOG(TLVL_ERROR) <<
"DataBufferError: "
344 <<
"Error in FragmentBuffer: Cannot check size of data buffer for ID " <<
id <<
" because it does not exist!";
345 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot check size of data buffer for ID " <<
id <<
" because it does not exist!";
347 auto dataBuffer = dataBuffers_[id];
348 return (maxDataBufferDepthFragments_ > 0 && dataBuffer->DataBufferDepthFragments.load() > maxDataBufferDepthFragments_) ||
349 (maxDataBufferDepthBytes_ > 0 && dataBuffer->DataBufferDepthBytes.load() > maxDataBufferDepthBytes_);
354 if (!dataBuffers_.count(
id))
356 TLOG(TLVL_ERROR) <<
"DataBufferError: "
357 <<
"Error in FragmentBuffer: Cannot get stats of data buffer for ID " <<
id <<
" because it does not exist!";
358 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot get stats of data buffer for ID " <<
id <<
" because it does not exist!";
360 auto dataBuffer = dataBuffers_[id];
364 TLOG(TLVL_GETBUFFERSTATS) <<
"getDataBufferStats: Sending Metrics";
365 metricMan->sendMetric(
"Buffer Depth Fragments", dataBuffer->DataBufferDepthFragments.load(),
"fragments", 1, MetricMode::LastPoint);
366 metricMan->sendMetric(
"Buffer Depth Bytes", dataBuffer->DataBufferDepthBytes.load(),
"bytes", 1, MetricMode::LastPoint);
368 auto bufferDepthFragmentsPercent = dataBuffer->DataBufferDepthFragments.load() * 100 /
static_cast<double>(maxDataBufferDepthFragments_);
369 auto bufferDepthBytesPercent = dataBuffer->DataBufferDepthBytes.load() * 100 /
static_cast<double>(maxDataBufferDepthBytes_);
370 metricMan->sendMetric(
"Fragment Buffer Full %Fragments", bufferDepthFragmentsPercent,
"%", 3, MetricMode::LastPoint);
371 metricMan->sendMetric(
"Fragment Buffer Full %Bytes", bufferDepthBytesPercent,
"%", 3, MetricMode::LastPoint);
372 metricMan->sendMetric(
"Fragment Buffer Full %", bufferDepthFragmentsPercent > bufferDepthBytesPercent ? bufferDepthFragmentsPercent : bufferDepthBytesPercent,
"%", 1, MetricMode::LastPoint);
374 TLOG(TLVL_GETBUFFERSTATS) <<
"getDataBufferStats: frags=" << dataBuffer->DataBufferDepthFragments.load() <<
"/" << maxDataBufferDepthFragments_
375 <<
", sz=" << dataBuffer->DataBufferDepthBytes.load() <<
"/" << maxDataBufferDepthBytes_;
380 if (!dataBuffers_.count(
id))
382 TLOG(TLVL_ERROR) <<
"DataBufferError: "
383 <<
"Error in FragmentBuffer: Cannot check data buffer for ID " <<
id <<
" because it does not exist!";
384 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot check data buffer for ID " <<
id <<
" because it does not exist!";
387 if (dataBuffers_[
id]->DataBufferDepthFragments > 0 && mode_ != RequestMode::Single && mode_ != RequestMode::Ignored)
389 auto dataBuffer = dataBuffers_[id];
390 std::lock_guard<std::mutex> lk(dataBuffer->DataBufferMutex);
393 while (dataBufferIsTooLarge(
id))
395 auto begin = dataBuffer->DataBuffer.begin();
396 TLOG(TLVL_CHECKDATABUFFER) <<
"checkDataBuffer: Dropping Fragment with timestamp " << (*begin)->timestamp() <<
" from data buffer (Buffer over-size)";
397 dataBuffer->DataBufferDepthBytes -= (*begin)->sizeBytes();
398 dataBuffer->DataBuffer.erase(begin);
399 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
400 dataBuffer->BufferFragmentKept =
false;
403 TLOG(TLVL_CHECKDATABUFFER) <<
"DataBufferDepthFragments is " << dataBuffer->DataBufferDepthFragments <<
", DataBuffer.size is " << dataBuffer->DataBuffer.size();
404 if (dataBuffer->DataBufferDepthFragments > 0 && staleTimeout_ > 0)
406 TLOG(TLVL_CHECKDATABUFFER) <<
"Determining if Fragments can be dropped from data buffer";
407 Fragment::timestamp_t last = dataBuffer->DataBuffer.back()->timestamp();
408 Fragment::timestamp_t min = last > staleTimeout_ ? last - staleTimeout_ : 0;
409 for (
auto it = dataBuffer->DataBuffer.begin(); it != dataBuffer->DataBuffer.end();)
411 if ((*it)->timestamp() < min)
413 TLOG(TLVL_CHECKDATABUFFER) <<
"checkDataBuffer: Dropping Fragment with timestamp " << (*it)->timestamp() <<
" from data buffer (timeout=" << staleTimeout_ <<
", min=" << min <<
")";
414 dataBuffer->DataBufferDepthBytes -= (*it)->sizeBytes();
415 dataBuffer->BufferFragmentKept =
false;
416 it = dataBuffer->DataBuffer.erase(it);
417 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
432 TLOG(TLVL_APPLYREQUESTS) <<
"Mode is Ignored; Copying data to output";
433 for (
auto&
id : dataBuffers_)
435 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
436 if (
id.second && !
id.second->DataBuffer.empty() &&
id.second->DataBuffer.back()->sequenceID() >= next_sequence_id_)
438 next_sequence_id_ =
id.second->DataBuffer.back()->sequenceID() + 1;
440 std::move(
id.second->DataBuffer.begin(),
id.second->DataBuffer.end(), std::inserter(frags, frags.end()));
441 id.second->DataBufferDepthBytes = 0;
442 id.second->DataBufferDepthFragments = 0;
443 id.second->BufferFragmentKept =
false;
444 id.second->DataBuffer.clear();
451 auto requests = requestBuffer_->GetRequests();
452 while (requests.size() > 1)
455 requestBuffer_->RemoveRequest(requests.begin()->first);
456 requests.erase(requests.begin());
458 sendEmptyFragments(frags, requests);
461 if (requests.size() == 0 || !requests.count(next_sequence_id_))
return;
463 for (
auto&
id : dataBuffers_)
465 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
466 if (
id.second->DataBufferDepthFragments > 0)
468 assert(
id.second->DataBufferDepthFragments == 1);
469 TLOG(TLVL_APPLYREQUESTS) <<
"Mode is Single; Sending copy of last event (SeqID " << next_sequence_id_ <<
")";
470 for (
auto& fragptr :
id.second->DataBuffer)
473 auto frag = fragptr.get();
474 auto newfrag = std::unique_ptr<artdaq::Fragment>(
new Fragment(next_sequence_id_, frag->fragmentID()));
475 newfrag->resize(frag->size() - detail::RawFragmentHeader::num_words());
476 memcpy(newfrag->headerAddress(), frag->headerAddress(), frag->sizeBytes());
477 newfrag->setTimestamp(requests[next_sequence_id_]);
478 newfrag->setSequenceID(next_sequence_id_);
479 frags.push_back(std::move(newfrag));
484 sendEmptyFragment(frags, next_sequence_id_,
id.first,
"No data for");
487 requestBuffer_->RemoveRequest(next_sequence_id_);
494 auto requests = requestBuffer_->GetRequests();
495 while (requests.size() > 1)
498 requestBuffer_->RemoveRequest(requests.begin()->first);
499 requests.erase(requests.begin());
501 sendEmptyFragments(frags, requests);
504 if (requests.size() == 0 || !requests.count(next_sequence_id_))
return;
506 for (
auto&
id : dataBuffers_)
508 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsBufferMode: Creating ContainerFragment for Buffered Fragments (SeqID " << next_sequence_id_ <<
")";
509 frags.emplace_back(
new artdaq::Fragment(next_sequence_id_,
id.first));
510 frags.back()->setTimestamp(requests[next_sequence_id_]);
511 ContainerFragmentLoader cfl(*frags.back());
512 cfl.set_missing_data(
false);
515 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
516 if (
id.second->BufferFragmentKept &&
id.second->DataBufferDepthFragments > 1)
518 id.second->DataBufferDepthBytes -=
id.second->DataBuffer.front()->sizeBytes();
519 id.second->DataBuffer.erase(
id.second->DataBuffer.begin());
520 id.second->DataBufferDepthFragments =
id.second->DataBuffer.size();
524 FragmentPtrs fragsToAdd;
525 std::move(
id.second->DataBuffer.begin(), --
id.second->DataBuffer.end(), std::back_inserter(fragsToAdd));
526 id.second->DataBuffer.erase(
id.second->DataBuffer.begin(), --
id.second->DataBuffer.end());
528 if (fragsToAdd.size() > 0)
530 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsBufferMode: Adding " << fragsToAdd.size() <<
" Fragments to Container (SeqID " << next_sequence_id_ <<
")";
531 cfl.addFragments(fragsToAdd);
535 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsBufferMode: No Fragments to add (SeqID " << next_sequence_id_ <<
")";
538 if (
id.second->DataBuffer.size() == 1)
540 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsBufferMode: Adding Fragment with timestamp " <<
id.second->DataBuffer.front()->timestamp() <<
" to Container with sequence ID " << next_sequence_id_;
541 cfl.addFragment(
id.second->DataBuffer.front());
542 if (bufferModeKeepLatest_)
544 id.second->BufferFragmentKept =
true;
545 id.second->DataBufferDepthBytes =
id.second->DataBuffer.front()->sizeBytes();
546 id.second->DataBufferDepthFragments =
id.second->DataBuffer.size();
550 id.second->DataBuffer.clear();
551 id.second->BufferFragmentKept =
false;
552 id.second->DataBufferDepthBytes = 0;
553 id.second->DataBufferDepthFragments = 0;
557 requestBuffer_->RemoveRequest(next_sequence_id_);
563 auto dataBuffer = dataBuffers_[id];
565 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Checking that data exists for request window " << seq;
566 Fragment::timestamp_t min = ts > windowOffset_ ? ts - windowOffset_ : 0;
567 Fragment::timestamp_t max = ts + windowWidth_ > windowOffset_ ? ts + windowWidth_ - windowOffset_ : 1;
569 TLOG(TLVL_APPLYREQUESTS) <<
"ApplyRequestsWindowsMode_CheckAndFillDataBuffer: min is " << min <<
", max is " << max
570 <<
" and first/last points in buffer are " << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.front()->timestamp() : 0)
571 <<
"/" << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.back()->timestamp() : 0)
572 <<
" (sz=" << dataBuffer->DataBufferDepthFragments <<
" [" << dataBuffer->DataBufferDepthBytes.load()
573 <<
"/" << maxDataBufferDepthBytes_ <<
"])";
574 bool windowClosed = dataBuffer->DataBufferDepthFragments > 0 && dataBuffer->DataBuffer.back()->timestamp() >= max;
575 bool windowTimeout = !windowClosed && TimeUtils::GetElapsedTimeMicroseconds(requestBuffer_->GetRequestTime(seq)) > window_close_timeout_us_;
578 TLOG(TLVL_WARNING) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: A timeout occurred waiting for data to close the request window ({" << min <<
"-" << max
579 <<
"}, buffer={" << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.front()->timestamp() : 0) <<
"-"
580 << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.back()->timestamp() : 0)
581 <<
"} ). Time waiting: "
582 << TimeUtils::GetElapsedTimeMicroseconds(requestBuffer_->GetRequestTime(seq)) <<
" us "
583 <<
"(> " << window_close_timeout_us_ <<
" us).";
585 if (windowClosed || windowTimeout)
587 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Creating ContainerFragment for Window-requested Fragments (SeqID " << seq <<
")";
588 frags.emplace_back(
new artdaq::Fragment(seq,
id));
589 frags.back()->setTimestamp(ts);
590 ContainerFragmentLoader cfl(*frags.back());
604 if (!windowClosed || (dataBuffer->DataBufferDepthFragments > 0 && dataBuffer->DataBuffer.front()->timestamp() > min))
606 TLOG(TLVL_DEBUG + 32) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Request window starts before and/or ends after the current data buffer, setting ContainerFragment's missing_data flag!"
607 <<
" (requestWindowRange=[" << min <<
"," << max <<
"], "
608 <<
"buffer={" << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.front()->timestamp() : 0) <<
"-"
609 << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.back()->timestamp() : 0) <<
"} (SeqID " << seq <<
")";
610 cfl.set_missing_data(
true);
613 auto it = dataBuffer->DataBuffer.begin();
617 it = dataBuffer->DataBuffer.end();
619 while (it != dataBuffer->DataBuffer.begin())
621 if ((*it)->timestamp() < min)
629 FragmentPtrs fragsToAdd;
631 for (; it != dataBuffer->DataBuffer.end();)
633 Fragment::timestamp_t fragT = (*it)->timestamp();
639 if (fragT > max || (fragT == max && windowWidth_ > 0))
644 TLOG(TLVL_APPLYREQUESTS_VERBOSE) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Adding Fragment with timestamp " << (*it)->timestamp() <<
" to Container (SeqID " << seq <<
")";
647 dataBuffer->DataBufferDepthBytes -= (*it)->sizeBytes();
648 fragsToAdd.emplace_back(std::move(*it));
649 it = dataBuffer->DataBuffer.erase(it);
653 fragsToAdd.emplace_back(it->get());
658 if (fragsToAdd.size() > 0)
660 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Adding " << fragsToAdd.size() <<
" Fragments to Container (SeqID " << seq <<
")";
661 cfl.addFragments(fragsToAdd);
666 for (
auto& frag : fragsToAdd)
675 TLOG(error_on_empty_ ? TLVL_ERROR : TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: No Fragments match request (SeqID " << seq <<
", window " << min <<
" - " << max <<
")";
678 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
679 dataBuffer->WindowsSent[seq] = std::chrono::steady_clock::now();
680 if (seq > dataBuffer->HighestRequestSeen) dataBuffer->HighestRequestSeen = seq;
686 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode BEGIN";
688 auto requests = requestBuffer_->GetRequests();
690 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode: Starting request processing for " << requests.size() <<
" requests";
691 for (
auto req = requests.begin(); req != requests.end();)
693 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode: processing request with sequence ID " << req->first <<
", timestamp " << req->second;
695 while (req->first < next_sequence_id_ && requests.size() > 0)
697 TLOG(TLVL_APPLYREQUESTS_VERBOSE) <<
"applyRequestsWindowMode: Clearing passed request for sequence ID " << req->first;
698 requestBuffer_->RemoveRequest(req->first);
699 req = requests.erase(req);
701 if (requests.size() == 0)
break;
703 auto ts = req->second;
704 if (ts == Fragment::InvalidTimestamp)
706 TLOG(TLVL_ERROR) <<
"applyRequestsWindowMode: Received InvalidTimestamp in request " << req->first <<
", cannot apply! Check that push-mode BRs are filling appropriate timestamps in their Fragments!";
707 req = requests.erase(req);
711 for (
auto&
id : dataBuffers_)
713 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
714 if (!
id.second->WindowsSent.count(req->first))
716 applyRequestsWindowMode_CheckAndFillDataBuffer(frags,
id.first, req->first, req->second);
719 checkSentWindows(req->first);
724 std::set<artdaq::Fragment::sequence_id_t> seqs;
725 for (
auto&
id : dataBuffers_)
727 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
728 for (
auto& seq :
id.second->WindowsSent)
730 seqs.insert(seq.first);
733 for (
auto& seq : seqs)
735 checkSentWindows(seq);
741 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsSequenceIDMode BEGIN";
743 auto requests = requestBuffer_->GetRequests();
745 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsSequenceIDMode: Starting request processing";
746 for (
auto req = requests.begin(); req != requests.end();)
748 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsSequenceIDMode: Checking that data exists for request SequenceID " << req->first;
750 for (
auto&
id : dataBuffers_)
752 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
753 if (!
id.second->WindowsSent.count(req->first))
755 TLOG(TLVL_APPLYREQUESTS_VERBOSE) <<
"Searching id " <<
id.first <<
" for Fragments with Sequence ID " << req->first;
756 for (
auto it =
id.second->DataBuffer.begin(); it !=
id.second->DataBuffer.end();)
758 auto seq = (*it)->sequenceID();
759 TLOG(TLVL_APPLYREQUESTS_VERBOSE) <<
"applyRequestsSequenceIDMode: Fragment SeqID " << seq <<
", request ID " << req->first;
760 if (seq == req->first)
762 TLOG(TLVL_APPLYREQUESTS_VERBOSE) <<
"applyRequestsSequenceIDMode: Adding Fragment to output";
763 id.second->WindowsSent[req->first] = std::chrono::steady_clock::now();
764 id.second->DataBufferDepthBytes -= (*it)->sizeBytes();
765 frags.push_back(std::move(*it));
766 it =
id.second->DataBuffer.erase(it);
767 id.second->DataBufferDepthFragments =
id.second->DataBuffer.size();
775 if (req->first >
id.second->HighestRequestSeen)
id.second->HighestRequestSeen = req->first;
777 checkSentWindows(req->first);
782 std::set<artdaq::Fragment::sequence_id_t> seqs;
783 for (
auto&
id : dataBuffers_)
785 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
786 for (
auto& seq :
id.second->WindowsSent)
788 seqs.insert(seq.first);
791 for (
auto& seq : seqs)
793 checkSentWindows(seq);
805 if (mode_ == RequestMode::Ignored)
807 auto start_time = std::chrono::steady_clock::now();
808 while (dataBufferFragmentCount_() == 0 && TimeUtils::GetElapsedTime(start_time) < 1.0)
810 if (check_stop())
return false;
811 std::unique_lock<std::mutex> lock(dataConditionMutex_);
812 dataCondition_.wait_for(lock, std::chrono::milliseconds(10), [
this]() {
return dataBufferFragmentCount_() > 0; });
815 else if (requestBuffer_ ==
nullptr)
817 TLOG(TLVL_ERROR) <<
"Request Buffer must be set (via SetRequestBuffer) before applyRequests/getData can be called!";
822 if ((check_stop() && requestBuffer_->size() == 0))
return false;
824 std::unique_lock<std::mutex> lock(dataConditionMutex_);
825 dataCondition_.wait_for(lock, std::chrono::milliseconds(10));
832 while (requestBuffer_->size() == 0 && counter < 100)
834 if (check_stop())
return false;
838 requestBuffer_->WaitForRequests(10);
843 if (systemFragmentCount_.load() > 0)
845 std::lock_guard<std::mutex> lk(systemFragmentMutex_);
846 TLOG(TLVL_INFO) <<
"Copying " << systemFragmentCount_.load() <<
" System Fragments into output";
848 std::move(systemFragments_.begin(), systemFragments_.end(), std::inserter(frags, frags.end()));
849 systemFragments_.clear();
850 systemFragmentCount_ = 0;
855 case RequestMode::Single:
856 applyRequestsSingleMode(frags);
858 case RequestMode::Window:
859 applyRequestsWindowMode(frags);
861 case RequestMode::Buffer:
862 applyRequestsBufferMode(frags);
864 case RequestMode::SequenceID:
865 applyRequestsSequenceIDMode(frags);
867 case RequestMode::Ignored:
869 applyRequestsIgnoredMode(frags);
873 getDataBuffersStats();
875 if (frags.size() > 0)
876 TLOG(TLVL_APPLYREQUESTS) <<
"Finished Processing requests, returning " << frags.size() <<
" fragments, current ev_counter is " << next_sequence_id_;
882 TLOG(TLVL_EMPTYFRAGMENT) << desc <<
" sequence ID " << seqId <<
", sending empty fragment";
883 auto frag =
new Fragment();
884 frag->setSequenceID(seqId);
885 frag->setFragmentID(fragmentId);
886 frag->setSystemType(Fragment::EmptyFragmentType);
887 frags.emplace_back(FragmentPtr(frag));
893 if (requests.size() > 0)
895 TLOG(TLVL_SENDEMPTYFRAGMENTS) <<
"Sending Empty Fragments for Sequence IDs from " << next_sequence_id_ <<
" up to but not including " << requests.begin()->first;
896 while (requests.begin()->first > next_sequence_id_)
898 if (sendMissingFragments_)
900 for (
auto& fid : dataBuffers_)
902 sendEmptyFragment(frags, next_sequence_id_, fid.first,
"Missed request for");
912 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Checking if request " << seq <<
" can be removed from request list";
913 bool seqComplete =
true;
914 bool seqTimeout =
false;
915 for (
auto&
id : dataBuffers_)
917 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
918 if (!
id.second->WindowsSent.count(seq) ||
id.second->HighestRequestSeen < seq)
922 if (
id.second->WindowsSent.count(seq) && TimeUtils::GetElapsedTimeMicroseconds(
id.second->WindowsSent[seq]) > missing_request_window_timeout_us_)
929 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Request " << seq <<
" is complete, removing from requestBuffer_.";
930 requestBuffer_->RemoveRequest(seq);
932 if (next_sequence_id_ == seq)
934 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Sequence ID matches ev_counter, incrementing ev_counter (" << next_sequence_id_ <<
")";
936 for (
auto&
id : dataBuffers_)
938 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
939 id.second->WindowsSent.erase(seq);
947 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Sent Window history indicates that requests between " << next_sequence_id_ <<
" and " << seq <<
" have timed out.";
948 while (next_sequence_id_ <= seq)
950 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!";
951 requestBuffer_->RemoveRequest(next_sequence_id_);
953 for (
auto&
id : dataBuffers_)
955 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
956 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.