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 , missing_request_window_timeout_us_(ps.get<size_t>(
"missing_request_window_timeout_us", 5000000))
51 , window_close_timeout_us_(ps.get<size_t>(
"window_close_timeout_us", 2000000))
52 , circularDataBufferMode_(ps.get<bool>(
"circular_buffer_mode", false))
53 , maxDataBufferDepthFragments_(ps.get<int>(
"data_buffer_depth_fragments", 1000))
54 , maxDataBufferDepthBytes_(ps.get<size_t>(
"data_buffer_depth_mb", 1000) * 1024 * 1024)
55 , systemFragmentCount_(0)
58 auto fragment_ids = ps.get<std::vector<artdaq::Fragment::fragment_id_t>>(
"fragment_ids", std::vector<artdaq::Fragment::fragment_id_t>());
60 TLOG(TLVL_TRACE) <<
"artdaq::FragmentBuffer::FragmentBuffer(ps)";
63 if (fragment_id != -99)
65 if (fragment_ids.size() != 0)
67 auto report =
"Error in FragmentBuffer: can't both define \"fragment_id\" and \"fragment_ids\" in FHiCL document";
68 TLOG(TLVL_ERROR) << report;
69 throw cet::exception(
"FragmentBufferConfig") << report;
73 fragment_ids.emplace_back(fragment_id);
77 for (
auto&
id : fragment_ids)
79 dataBuffers_[id] = std::make_shared<DataBuffer>();
80 dataBuffers_[id]->DataBufferDepthBytes = 0;
81 dataBuffers_[id]->DataBufferDepthFragments = 0;
82 dataBuffers_[id]->HighestRequestSeen = 0;
83 dataBuffers_[id]->BufferFragmentKept =
false;
86 std::string modeString = ps.get<std::string>(
"request_mode",
"ignored");
87 if (modeString ==
"single" || modeString ==
"Single")
89 mode_ = RequestMode::Single;
91 else if (modeString.find(
"buffer") != std::string::npos || modeString.find(
"Buffer") != std::string::npos)
93 mode_ = RequestMode::Buffer;
95 else if (modeString ==
"window" || modeString ==
"Window")
97 mode_ = RequestMode::Window;
99 else if (modeString.find(
"ignore") != std::string::npos || modeString.find(
"Ignore") != std::string::npos)
101 mode_ = RequestMode::Ignored;
103 else if (modeString.find(
"sequence") != std::string::npos || modeString.find(
"Sequence") != std::string::npos)
105 mode_ = RequestMode::SequenceID;
107 if (mode_ != RequestMode::Ignored && !ps.get<
bool>(
"receive_requests",
false))
109 TLOG(TLVL_WARNING) <<
"Request Mode was requested as " << modeString <<
", but is being set to Ignored because \"receive_requests\" was not set to true";
110 mode_ = RequestMode::Ignored;
112 TLOG(TLVL_DEBUG) <<
"Request mode is " <<
printMode_();
117 TLOG(TLVL_INFO) <<
"Fragment Buffer Destructor; Clearing data buffers";
124 next_sequence_id_ = 1;
125 for (
auto&
id : dataBuffers_)
127 std::lock_guard<std::mutex> dlk(
id.second->DataBufferMutex);
128 id.second->DataBufferDepthBytes = 0;
129 id.second->DataBufferDepthFragments = 0;
130 id.second->BufferFragmentKept =
false;
131 id.second->DataBuffer.clear();
135 std::lock_guard<std::mutex> lk(systemFragmentMutex_);
136 systemFragments_.clear();
137 systemFragmentCount_ = 0;
143 std::unordered_map<Fragment::fragment_id_t, FragmentPtrs> frags_by_id;
144 while (!frags.empty())
146 auto dataIter = frags.begin();
147 auto frag_id = (*dataIter)->fragmentID();
149 if ((*dataIter)->type() == Fragment::EndOfRunFragmentType || (*dataIter)->type() == Fragment::EndOfSubrunFragmentType || (*dataIter)->type() == Fragment::InitFragmentType)
151 std::lock_guard<std::mutex> lk(systemFragmentMutex_);
152 systemFragments_.emplace_back(std::move(*dataIter));
153 systemFragmentCount_++;
154 frags.erase(dataIter);
158 if (!dataBuffers_.count(frag_id))
160 throw cet::exception(
"FragmentIDs") <<
"Received Fragment with Fragment ID " << frag_id <<
", which is not in the declared Fragment IDs list!";
163 frags_by_id[frag_id].emplace_back(std::move(*dataIter));
164 frags.erase(dataIter);
167 auto type_it = frags_by_id.begin();
168 while (type_it != frags_by_id.end())
170 auto frag_id = type_it->first;
172 waitForDataBufferReady(frag_id);
173 auto dataBuffer = dataBuffers_[frag_id];
174 std::lock_guard<std::mutex> dlk(dataBuffer->DataBufferMutex);
177 case RequestMode::Single:
179 auto dataIter = type_it->second.rbegin();
180 TLOG(TLVL_ADDFRAGMENT) <<
"Adding Fragment with Fragment ID " << frag_id <<
", Sequence ID " << (*dataIter)->sequenceID() <<
", and Timestamp " << (*dataIter)->timestamp() <<
" to buffer";
181 dataBuffer->DataBuffer.clear();
182 dataBuffer->DataBufferDepthBytes = (*dataIter)->sizeBytes();
183 dataBuffer->DataBuffer.emplace_back(std::move(*dataIter));
184 dataBuffer->DataBufferDepthFragments = 1;
185 type_it->second.clear();
188 case RequestMode::Buffer:
189 case RequestMode::Ignored:
190 case RequestMode::Window:
191 case RequestMode::SequenceID:
193 while (!type_it->second.empty())
195 auto dataIter = type_it->second.begin();
196 TLOG(TLVL_ADDFRAGMENT) <<
"Adding Fragment with Fragment ID " << frag_id <<
", Sequence ID " << (*dataIter)->sequenceID() <<
", and Timestamp " << (*dataIter)->timestamp() <<
" to buffer";
198 dataBuffer->DataBufferDepthBytes += (*dataIter)->sizeBytes();
199 dataBuffer->DataBuffer.emplace_back(std::move(*dataIter));
200 type_it->second.erase(dataIter);
202 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
205 getDataBufferStats(frag_id);
208 dataCondition_.notify_all();
213 TLOG(TLVL_CHECKSTOP) <<
"CFG::check_stop: should_stop=" << should_stop_.load();
215 if (!should_stop_.load())
return false;
216 if (mode_ == RequestMode::Ignored)
221 if (requestBuffer_ !=
nullptr)
224 TLOG(TLVL_DEBUG) <<
"should_stop is true, requestBuffer_->isRunning() is " << std::boolalpha << requestBuffer_->isRunning();
225 if (!requestBuffer_->isRunning())
237 case RequestMode::Single:
239 case RequestMode::Buffer:
241 case RequestMode::Window:
243 case RequestMode::Ignored:
245 case RequestMode::SequenceID:
255 for (
auto&
id : dataBuffers_) count +=
id.second->DataBufferDepthFragments;
256 count += systemFragmentCount_.load();
262 if (!dataBuffers_.count(
id))
264 TLOG(TLVL_ERROR) <<
"DataBufferError: "
265 <<
"Error in FragmentBuffer: Cannot wait for data buffer for ID " <<
id <<
" because it does not exist!";
266 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot wait for data buffer for ID " <<
id <<
" because it does not exist!";
268 auto startwait = std::chrono::steady_clock::now();
270 auto lastwaittime = 0ULL;
271 auto dataBuffer = dataBuffers_[id];
273 while (dataBufferIsTooLarge(
id))
275 if (!circularDataBufferMode_)
277 if (should_stop_.load())
279 TLOG(TLVL_DEBUG) <<
"Run ended while waiting for buffer to shrink!";
280 getDataBufferStats(
id);
281 dataCondition_.notify_all();
284 auto waittime = TimeUtils::GetElapsedTimeMilliseconds(startwait);
286 if (first || (waittime != lastwaittime && waittime % 1000 == 0))
288 std::lock_guard<std::mutex> lk(dataBuffer->DataBufferMutex);
289 if (dataBufferIsTooLarge(
id))
291 TLOG(TLVL_WARNING) <<
"Bad Omen: Data Buffer has exceeded its size limits. "
292 <<
"(seq_id=" << next_sequence_id_ <<
", frag_id=" <<
id
293 <<
", frags=" << dataBuffer->DataBufferDepthFragments <<
"/" << maxDataBufferDepthFragments_
294 <<
", szB=" << dataBuffer->DataBufferDepthBytes <<
"/" << maxDataBufferDepthBytes_ <<
")"
295 <<
", timestamps=" << dataBuffer->DataBuffer.front()->timestamp() <<
"-" << dataBuffer->DataBuffer.back()->timestamp();
296 TLOG(TLVL_TRACE) <<
"Bad Omen: Possible causes include requests not getting through or Ignored-mode BR issues";
300 if (waittime % 5 && waittime != lastwaittime)
302 TLOG(TLVL_WAITFORBUFFERREADY) <<
"getDataLoop: Data Retreival paused for " << waittime <<
" ms waiting for data buffer to drain";
304 lastwaittime = waittime;
309 std::lock_guard<std::mutex> lk(dataBuffer->DataBufferMutex);
310 if (dataBufferIsTooLarge(
id))
312 auto begin = dataBuffer->DataBuffer.begin();
313 if (begin == dataBuffer->DataBuffer.end())
315 TLOG(TLVL_WARNING) <<
"Data buffer is reported as too large, but doesn't contain any Fragments! Possible corrupt memory!";
320 TLOG(TLVL_WAITFORBUFFERREADY) <<
"waitForDataBufferReady: Dropping Fragment with timestamp " << (*begin)->timestamp() <<
" from data buffer (Buffer over-size, circular data buffer mode)";
322 dataBuffer->DataBufferDepthBytes -= (*begin)->sizeBytes();
323 dataBuffer->DataBuffer.erase(begin);
324 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
325 dataBuffer->BufferFragmentKept =
false;
335 if (!dataBuffers_.count(
id))
337 TLOG(TLVL_ERROR) <<
"DataBufferError: "
338 <<
"Error in FragmentBuffer: Cannot check size of data buffer for ID " <<
id <<
" because it does not exist!";
339 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot check size of data buffer for ID " <<
id <<
" because it does not exist!";
341 auto dataBuffer = dataBuffers_[id];
342 return (maxDataBufferDepthFragments_ > 0 && dataBuffer->DataBufferDepthFragments.load() > maxDataBufferDepthFragments_) ||
343 (maxDataBufferDepthBytes_ > 0 && dataBuffer->DataBufferDepthBytes.load() > maxDataBufferDepthBytes_);
348 if (!dataBuffers_.count(
id))
350 TLOG(TLVL_ERROR) <<
"DataBufferError: "
351 <<
"Error in FragmentBuffer: Cannot get stats of data buffer for ID " <<
id <<
" because it does not exist!";
352 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot get stats of data buffer for ID " <<
id <<
" because it does not exist!";
354 auto dataBuffer = dataBuffers_[id];
358 TLOG(TLVL_GETBUFFERSTATS) <<
"getDataBufferStats: Sending Metrics";
359 metricMan->sendMetric(
"Buffer Depth Fragments", dataBuffer->DataBufferDepthFragments.load(),
"fragments", 1, MetricMode::LastPoint);
360 metricMan->sendMetric(
"Buffer Depth Bytes", dataBuffer->DataBufferDepthBytes.load(),
"bytes", 1, MetricMode::LastPoint);
362 auto bufferDepthFragmentsPercent = dataBuffer->DataBufferDepthFragments.load() * 100 /
static_cast<double>(maxDataBufferDepthFragments_);
363 auto bufferDepthBytesPercent = dataBuffer->DataBufferDepthBytes.load() * 100 /
static_cast<double>(maxDataBufferDepthBytes_);
364 metricMan->sendMetric(
"Fragment Buffer Full %Fragments", bufferDepthFragmentsPercent,
"%", 3, MetricMode::LastPoint);
365 metricMan->sendMetric(
"Fragment Buffer Full %Bytes", bufferDepthBytesPercent,
"%", 3, MetricMode::LastPoint);
366 metricMan->sendMetric(
"Fragment Buffer Full %", bufferDepthFragmentsPercent > bufferDepthBytesPercent ? bufferDepthFragmentsPercent : bufferDepthBytesPercent,
"%", 1, MetricMode::LastPoint);
368 TLOG(TLVL_GETBUFFERSTATS) <<
"getDataBufferStats: frags=" << dataBuffer->DataBufferDepthFragments.load() <<
"/" << maxDataBufferDepthFragments_
369 <<
", sz=" << dataBuffer->DataBufferDepthBytes.load() <<
"/" << maxDataBufferDepthBytes_;
374 if (!dataBuffers_.count(
id))
376 TLOG(TLVL_ERROR) <<
"DataBufferError: "
377 <<
"Error in FragmentBuffer: Cannot check data buffer for ID " <<
id <<
" because it does not exist!";
378 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot check data buffer for ID " <<
id <<
" because it does not exist!";
381 if (dataBuffers_[
id]->DataBufferDepthFragments > 0 && mode_ != RequestMode::Single && mode_ != RequestMode::Ignored)
383 auto dataBuffer = dataBuffers_[id];
384 std::lock_guard<std::mutex> lk(dataBuffer->DataBufferMutex);
387 while (dataBufferIsTooLarge(
id))
389 auto begin = dataBuffer->DataBuffer.begin();
390 TLOG(TLVL_CHECKDATABUFFER) <<
"checkDataBuffer: Dropping Fragment with timestamp " << (*begin)->timestamp() <<
" from data buffer (Buffer over-size)";
391 dataBuffer->DataBufferDepthBytes -= (*begin)->sizeBytes();
392 dataBuffer->DataBuffer.erase(begin);
393 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
394 dataBuffer->BufferFragmentKept =
false;
397 TLOG(TLVL_CHECKDATABUFFER) <<
"DataBufferDepthFragments is " << dataBuffer->DataBufferDepthFragments <<
", DataBuffer.size is " << dataBuffer->DataBuffer.size();
398 if (dataBuffer->DataBufferDepthFragments > 0 && staleTimeout_ > 0)
400 TLOG(TLVL_CHECKDATABUFFER) <<
"Determining if Fragments can be dropped from data buffer";
401 Fragment::timestamp_t last = dataBuffer->DataBuffer.back()->timestamp();
402 Fragment::timestamp_t min = last > staleTimeout_ ? last - staleTimeout_ : 0;
403 for (
auto it = dataBuffer->DataBuffer.begin(); it != dataBuffer->DataBuffer.end();)
405 if ((*it)->timestamp() < min)
407 TLOG(TLVL_CHECKDATABUFFER) <<
"checkDataBuffer: Dropping Fragment with timestamp " << (*it)->timestamp() <<
" from data buffer (timeout=" << staleTimeout_ <<
", min=" << min <<
")";
408 dataBuffer->DataBufferDepthBytes -= (*it)->sizeBytes();
409 dataBuffer->BufferFragmentKept =
false;
410 it = dataBuffer->DataBuffer.erase(it);
411 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
426 TLOG(TLVL_APPLYREQUESTS) <<
"Mode is Ignored; Copying data to output";
427 for (
auto&
id : dataBuffers_)
429 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
430 if (
id.second && !
id.second->DataBuffer.empty() &&
id.second->DataBuffer.back()->sequenceID() >= next_sequence_id_)
432 next_sequence_id_ =
id.second->DataBuffer.back()->sequenceID() + 1;
434 std::move(
id.second->DataBuffer.begin(),
id.second->DataBuffer.end(), std::inserter(frags, frags.end()));
435 id.second->DataBufferDepthBytes = 0;
436 id.second->DataBufferDepthFragments = 0;
437 id.second->BufferFragmentKept =
false;
438 id.second->DataBuffer.clear();
445 auto requests = requestBuffer_->GetRequests();
446 while (requests.size() > 1)
449 requestBuffer_->RemoveRequest(requests.begin()->first);
450 requests.erase(requests.begin());
452 sendEmptyFragments(frags, requests);
455 if (requests.size() == 0 || !requests.count(next_sequence_id_))
return;
457 for (
auto&
id : dataBuffers_)
459 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
460 if (
id.second->DataBufferDepthFragments > 0)
462 assert(
id.second->DataBufferDepthFragments == 1);
463 TLOG(TLVL_APPLYREQUESTS) <<
"Mode is Single; Sending copy of last event (SeqID " << next_sequence_id_ <<
")";
464 for (
auto& fragptr :
id.second->DataBuffer)
467 auto frag = fragptr.get();
468 auto newfrag = std::unique_ptr<artdaq::Fragment>(
new Fragment(next_sequence_id_, frag->fragmentID()));
469 newfrag->resize(frag->size() - detail::RawFragmentHeader::num_words());
470 memcpy(newfrag->headerAddress(), frag->headerAddress(), frag->sizeBytes());
471 newfrag->setTimestamp(requests[next_sequence_id_]);
472 newfrag->setSequenceID(next_sequence_id_);
473 frags.push_back(std::move(newfrag));
478 sendEmptyFragment(frags, next_sequence_id_,
id.first,
"No data for");
481 requestBuffer_->RemoveRequest(next_sequence_id_);
488 auto requests = requestBuffer_->GetRequests();
489 while (requests.size() > 1)
492 requestBuffer_->RemoveRequest(requests.begin()->first);
493 requests.erase(requests.begin());
495 sendEmptyFragments(frags, requests);
498 if (requests.size() == 0 || !requests.count(next_sequence_id_))
return;
500 for (
auto&
id : dataBuffers_)
502 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsBufferMode: Creating ContainerFragment for Buffered Fragments (SeqID " << next_sequence_id_ <<
")";
503 frags.emplace_back(
new artdaq::Fragment(next_sequence_id_,
id.first));
504 frags.back()->setTimestamp(requests[next_sequence_id_]);
505 ContainerFragmentLoader cfl(*frags.back());
506 cfl.set_missing_data(
false);
509 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
510 if (
id.second->BufferFragmentKept &&
id.second->DataBufferDepthFragments > 1)
512 id.second->DataBufferDepthBytes -=
id.second->DataBuffer.front()->sizeBytes();
513 id.second->DataBuffer.erase(
id.second->DataBuffer.begin());
514 id.second->DataBufferDepthFragments =
id.second->DataBuffer.size();
518 FragmentPtrs fragsToAdd;
519 std::move(
id.second->DataBuffer.begin(), --
id.second->DataBuffer.end(), std::back_inserter(fragsToAdd));
520 id.second->DataBuffer.erase(
id.second->DataBuffer.begin(), --
id.second->DataBuffer.end());
522 if (fragsToAdd.size() > 0)
524 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsBufferMode: Adding " << fragsToAdd.size() <<
" Fragments to Container (SeqID " << next_sequence_id_ <<
")";
525 cfl.addFragments(fragsToAdd);
529 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsBufferMode: No Fragments to add (SeqID " << next_sequence_id_ <<
")";
532 if (
id.second->DataBuffer.size() == 1)
534 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsBufferMode: Adding Fragment with timestamp " <<
id.second->DataBuffer.front()->timestamp() <<
" to Container with sequence ID " << next_sequence_id_;
535 cfl.addFragment(
id.second->DataBuffer.front());
536 if (bufferModeKeepLatest_)
538 id.second->BufferFragmentKept =
true;
539 id.second->DataBufferDepthBytes =
id.second->DataBuffer.front()->sizeBytes();
540 id.second->DataBufferDepthFragments =
id.second->DataBuffer.size();
544 id.second->DataBuffer.clear();
545 id.second->BufferFragmentKept =
false;
546 id.second->DataBufferDepthBytes = 0;
547 id.second->DataBufferDepthFragments = 0;
551 requestBuffer_->RemoveRequest(next_sequence_id_);
557 auto dataBuffer = dataBuffers_[id];
559 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Checking that data exists for request window " << seq;
560 Fragment::timestamp_t min = ts > windowOffset_ ? ts - windowOffset_ : 0;
561 Fragment::timestamp_t max = ts + windowWidth_ > windowOffset_ ? ts + windowWidth_ - windowOffset_ : 1;
563 TLOG(TLVL_APPLYREQUESTS) <<
"ApplyRequestsWindowsMode_CheckAndFillDataBuffer: min is " << min <<
", max is " << max
564 <<
" and first/last points in buffer are " << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.front()->timestamp() : 0)
565 <<
"/" << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.back()->timestamp() : 0)
566 <<
" (sz=" << dataBuffer->DataBufferDepthFragments <<
" [" << dataBuffer->DataBufferDepthBytes.load()
567 <<
"/" << maxDataBufferDepthBytes_ <<
"])";
568 bool windowClosed = dataBuffer->DataBufferDepthFragments > 0 && dataBuffer->DataBuffer.back()->timestamp() >= max;
569 bool windowTimeout = !windowClosed && TimeUtils::GetElapsedTimeMicroseconds(requestBuffer_->GetRequestTime(seq)) > window_close_timeout_us_;
572 TLOG(TLVL_WARNING) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: A timeout occurred waiting for data to close the request window ({" << min <<
"-" << max
573 <<
"}, buffer={" << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.front()->timestamp() : 0) <<
"-"
574 << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.back()->timestamp() : 0)
575 <<
"} ). Time waiting: "
576 << TimeUtils::GetElapsedTimeMicroseconds(requestBuffer_->GetRequestTime(seq)) <<
" us "
577 <<
"(> " << window_close_timeout_us_ <<
" us).";
579 if (windowClosed || windowTimeout)
581 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Creating ContainerFragment for Window-requested Fragments (SeqID " << seq <<
")";
582 frags.emplace_back(
new artdaq::Fragment(seq,
id));
583 frags.back()->setTimestamp(ts);
584 ContainerFragmentLoader cfl(*frags.back());
598 if (!windowClosed || (dataBuffer->DataBufferDepthFragments > 0 && dataBuffer->DataBuffer.front()->timestamp() > min))
600 TLOG(TLVL_DEBUG) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Request window starts before and/or ends after the current data buffer, setting ContainerFragment's missing_data flag!"
601 <<
" (requestWindowRange=[" << min <<
"," << max <<
"], "
602 <<
"buffer={" << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.front()->timestamp() : 0) <<
"-"
603 << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.back()->timestamp() : 0) <<
"} (SeqID " << seq <<
")";
604 cfl.set_missing_data(
true);
607 auto it = dataBuffer->DataBuffer.begin();
611 it = dataBuffer->DataBuffer.end();
613 while (it != dataBuffer->DataBuffer.begin())
615 if ((*it)->timestamp() < min)
623 FragmentPtrs fragsToAdd;
625 for (; it != dataBuffer->DataBuffer.end();)
627 Fragment::timestamp_t fragT = (*it)->timestamp();
633 if (fragT > max || (fragT == max && windowWidth_ > 0))
636 TLOG(TLVL_APPLYREQUESTS_VERBOSE) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Adding Fragment with timestamp " << (*it)->timestamp() <<
" to Container (SeqID " << seq <<
")";
639 dataBuffer->DataBufferDepthBytes -= (*it)->sizeBytes();
640 fragsToAdd.emplace_back(std::move(*it));
641 it = dataBuffer->DataBuffer.erase(it);
645 fragsToAdd.emplace_back(it->get());
650 if (fragsToAdd.size() > 0)
652 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Adding " << fragsToAdd.size() <<
" Fragments to Container (SeqID " << seq <<
")";
653 cfl.addFragments(fragsToAdd);
658 for (
auto& frag : fragsToAdd)
667 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: No Fragments to add (SeqID " << seq <<
")";
670 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
671 dataBuffer->WindowsSent[seq] = std::chrono::steady_clock::now();
672 if (seq > dataBuffer->HighestRequestSeen) dataBuffer->HighestRequestSeen = seq;
678 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode BEGIN";
680 auto requests = requestBuffer_->GetRequests();
682 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode: Starting request processing for " << requests.size() <<
" requests";
683 for (
auto req = requests.begin(); req != requests.end();)
685 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode: processing request with sequence ID " << req->first <<
", timestamp " << req->second;
687 while (req->first < next_sequence_id_ && requests.size() > 0)
689 TLOG(TLVL_APPLYREQUESTS_VERBOSE) <<
"applyRequestsWindowMode: Clearing passed request for sequence ID " << req->first;
690 requestBuffer_->RemoveRequest(req->first);
691 req = requests.erase(req);
693 if (requests.size() == 0)
break;
695 auto ts = req->second;
696 if (ts == Fragment::InvalidTimestamp)
698 TLOG(TLVL_ERROR) <<
"applyRequestsWindowMode: Received InvalidTimestamp in request " << req->first <<
", cannot apply! Check that push-mode BRs are filling appropriate timestamps in their Fragments!";
699 req = requests.erase(req);
703 for (
auto&
id : dataBuffers_)
705 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
706 if (!
id.second->WindowsSent.count(req->first))
708 applyRequestsWindowMode_CheckAndFillDataBuffer(frags,
id.first, req->first, req->second);
711 checkSentWindows(req->first);
716 std::set<artdaq::Fragment::sequence_id_t> seqs;
717 for (
auto&
id : dataBuffers_)
719 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
720 for (
auto& seq :
id.second->WindowsSent)
722 seqs.insert(seq.first);
725 for (
auto& seq : seqs)
727 checkSentWindows(seq);
733 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsSequenceIDMode BEGIN";
735 auto requests = requestBuffer_->GetRequests();
737 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsSequenceIDMode: Starting request processing";
738 for (
auto req = requests.begin(); req != requests.end();)
740 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsSequenceIDMode: Checking that data exists for request SequenceID " << req->first;
742 for (
auto&
id : dataBuffers_)
744 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
745 if (!
id.second->WindowsSent.count(req->first))
747 TLOG(TLVL_APPLYREQUESTS_VERBOSE) <<
"Searching id " <<
id.first <<
" for Fragments with Sequence ID " << req->first;
748 for (
auto it =
id.second->DataBuffer.begin(); it !=
id.second->DataBuffer.end();)
750 auto seq = (*it)->sequenceID();
751 TLOG(TLVL_APPLYREQUESTS_VERBOSE) <<
"applyRequestsSequenceIDMode: Fragment SeqID " << seq <<
", request ID " << req->first;
752 if (seq == req->first)
754 TLOG(TLVL_APPLYREQUESTS_VERBOSE) <<
"applyRequestsSequenceIDMode: Adding Fragment to output";
755 id.second->WindowsSent[req->first] = std::chrono::steady_clock::now();
756 id.second->DataBufferDepthBytes -= (*it)->sizeBytes();
757 frags.push_back(std::move(*it));
758 it =
id.second->DataBuffer.erase(it);
759 id.second->DataBufferDepthFragments =
id.second->DataBuffer.size();
767 if (req->first >
id.second->HighestRequestSeen)
id.second->HighestRequestSeen = req->first;
769 checkSentWindows(req->first);
774 std::set<artdaq::Fragment::sequence_id_t> seqs;
775 for (
auto&
id : dataBuffers_)
777 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
778 for (
auto& seq :
id.second->WindowsSent)
780 seqs.insert(seq.first);
783 for (
auto& seq : seqs)
785 checkSentWindows(seq);
797 if (mode_ == RequestMode::Ignored)
799 auto start_time = std::chrono::steady_clock::now();
800 while (dataBufferFragmentCount_() == 0 && TimeUtils::GetElapsedTime(start_time) < 1.0)
802 if (check_stop())
return false;
803 std::unique_lock<std::mutex> lock(dataConditionMutex_);
804 dataCondition_.wait_for(lock, std::chrono::milliseconds(10), [
this]() {
return dataBufferFragmentCount_() > 0; });
807 else if (requestBuffer_ ==
nullptr)
809 TLOG(TLVL_ERROR) <<
"Request Buffer must be set (via SetRequestBuffer) before applyRequests/getData can be called!";
814 if ((check_stop() && requestBuffer_->size() == 0))
return false;
816 std::unique_lock<std::mutex> lock(dataConditionMutex_);
817 dataCondition_.wait_for(lock, std::chrono::milliseconds(10));
824 while (requestBuffer_->size() == 0 && counter < 100)
826 if (check_stop())
return false;
830 requestBuffer_->WaitForRequests(10);
835 if (systemFragmentCount_.load() > 0)
837 std::lock_guard<std::mutex> lk(systemFragmentMutex_);
838 TLOG(TLVL_INFO) <<
"Copying " << systemFragmentCount_.load() <<
" System Fragments into output";
840 std::move(systemFragments_.begin(), systemFragments_.end(), std::inserter(frags, frags.end()));
841 systemFragments_.clear();
842 systemFragmentCount_ = 0;
847 case RequestMode::Single:
848 applyRequestsSingleMode(frags);
850 case RequestMode::Window:
851 applyRequestsWindowMode(frags);
853 case RequestMode::Buffer:
854 applyRequestsBufferMode(frags);
856 case RequestMode::SequenceID:
857 applyRequestsSequenceIDMode(frags);
859 case RequestMode::Ignored:
861 applyRequestsIgnoredMode(frags);
865 getDataBuffersStats();
867 if (frags.size() > 0)
868 TLOG(TLVL_APPLYREQUESTS) <<
"Finished Processing requests, returning " << frags.size() <<
" fragments, current ev_counter is " << next_sequence_id_;
874 TLOG(TLVL_EMPTYFRAGMENT) << desc <<
" sequence ID " << seqId <<
", sending empty fragment";
875 auto frag =
new Fragment();
876 frag->setSequenceID(seqId);
877 frag->setFragmentID(fragmentId);
878 frag->setSystemType(Fragment::EmptyFragmentType);
879 frags.emplace_back(FragmentPtr(frag));
885 if (requests.size() > 0)
887 TLOG(TLVL_SENDEMPTYFRAGMENTS) <<
"Sending Empty Fragments for Sequence IDs from " << next_sequence_id_ <<
" up to but not including " << requests.begin()->first;
888 while (requests.begin()->first > next_sequence_id_)
890 for (
auto& fid : dataBuffers_)
892 sendEmptyFragment(frags, next_sequence_id_, fid.first,
"Missed request for");
901 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Checking if request " << seq <<
" can be removed from request list";
902 bool seqComplete =
true;
903 bool seqTimeout =
false;
904 for (
auto&
id : dataBuffers_)
906 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
907 if (!
id.second->WindowsSent.count(seq) ||
id.second->HighestRequestSeen < seq)
911 if (
id.second->WindowsSent.count(seq) && TimeUtils::GetElapsedTimeMicroseconds(
id.second->WindowsSent[seq]) > missing_request_window_timeout_us_)
918 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Request " << seq <<
" is complete, removing from requestBuffer_.";
919 requestBuffer_->RemoveRequest(seq);
921 if (next_sequence_id_ == seq)
923 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Sequence ID matches ev_counter, incrementing ev_counter (" << next_sequence_id_ <<
")";
925 for (
auto&
id : dataBuffers_)
927 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
928 id.second->WindowsSent.erase(seq);
936 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Sent Window history indicates that requests between " << next_sequence_id_ <<
" and " << seq <<
" have timed out.";
937 while (next_sequence_id_ <= seq)
939 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!";
940 requestBuffer_->RemoveRequest(next_sequence_id_);
942 for (
auto&
id : dataBuffers_)
944 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
945 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.