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_GETNEXT 10
31 #define TLVL_GETNEXT_VERBOSE 20
32 #define TLVL_CHECKSTOP 11
33 #define TLVL_EVCOUNTERINC 12
34 #define TLVL_GETDATALOOP 13
35 #define TLVL_GETDATALOOP_DATABUFFWAIT 21
36 #define TLVL_GETDATALOOP_VERBOSE 20
37 #define TLVL_WAITFORBUFFERREADY 15
38 #define TLVL_GETBUFFERSTATS 16
39 #define TLVL_CHECKDATABUFFER 17
40 #define TLVL_GETMONITORINGDATA 18
41 #define TLVL_APPLYREQUESTS 9
42 #define TLVL_SENDEMPTYFRAGMENTS 19
43 #define TLVL_CHECKWINDOWS 14
44 #define TLVL_EMPTYFRAGMENT 22
47 : next_sequence_id_(1)
49 , bufferModeKeepLatest_(ps.get<bool>(
"buffer_mode_keep_latest", false))
50 , windowOffset_(ps.get<Fragment::timestamp_t>(
"request_window_offset", 0))
51 , windowWidth_(ps.get<Fragment::timestamp_t>(
"request_window_width", 0))
52 , staleTimeout_(ps.get<Fragment::timestamp_t>(
"stale_fragment_timeout", 0))
53 , expectedType_(ps.get<Fragment::type_t>(
"expected_fragment_type", Fragment::type_t(Fragment::EmptyFragmentType)))
54 , uniqueWindows_(ps.get<bool>(
"request_windows_are_unique", true))
55 , missing_request_window_timeout_us_(ps.get<size_t>(
"missing_request_window_timeout_us", 5000000))
56 , window_close_timeout_us_(ps.get<size_t>(
"window_close_timeout_us", 2000000))
57 , circularDataBufferMode_(ps.get<bool>(
"circular_buffer_mode", false))
58 , maxDataBufferDepthFragments_(ps.get<int>(
"data_buffer_depth_fragments", 1000))
59 , maxDataBufferDepthBytes_(ps.get<size_t>(
"data_buffer_depth_mb", 1000) * 1024 * 1024)
60 , systemFragmentCount_(0)
63 auto fragment_ids = ps.get<std::vector<artdaq::Fragment::fragment_id_t>>(
"fragment_ids", std::vector<artdaq::Fragment::fragment_id_t>());
65 TLOG(TLVL_TRACE) <<
"artdaq::FragmentBuffer::FragmentBuffer(ps)";
68 if (fragment_id != -99)
70 if (fragment_ids.size() != 0)
72 auto report =
"Error in FragmentBuffer: can't both define \"fragment_id\" and \"fragment_ids\" in FHiCL document";
73 TLOG(TLVL_ERROR) << report;
74 throw cet::exception(report);
78 fragment_ids.emplace_back(fragment_id);
82 for (
auto&
id : fragment_ids)
84 dataBuffers_[id] = std::make_shared<DataBuffer>();
85 dataBuffers_[id]->DataBufferDepthBytes = 0;
86 dataBuffers_[id]->DataBufferDepthFragments = 0;
87 dataBuffers_[id]->HighestRequestSeen = 0;
88 dataBuffers_[id]->BufferFragmentKept =
false;
91 std::string modeString = ps.get<std::string>(
"request_mode",
"ignored");
92 if (modeString ==
"single" || modeString ==
"Single")
94 mode_ = RequestMode::Single;
96 else if (modeString.find(
"buffer") != std::string::npos || modeString.find(
"Buffer") != std::string::npos)
98 mode_ = RequestMode::Buffer;
100 else if (modeString ==
"window" || modeString ==
"Window")
102 mode_ = RequestMode::Window;
104 else if (modeString.find(
"ignore") != std::string::npos || modeString.find(
"Ignore") != std::string::npos)
106 mode_ = RequestMode::Ignored;
108 else if (modeString.find(
"sequence") != std::string::npos || modeString.find(
"Sequence") != std::string::npos)
110 mode_ = RequestMode::SequenceID;
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_TRACE) <<
"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_TRACE) <<
"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 TLOG(TLVL_WARNING) <<
"Bad Omen: Data Buffer has exceeded its size limits. "
289 <<
"(seq_id=" << next_sequence_id_ <<
", frag_id=" <<
id
290 <<
", frags=" << dataBuffer->DataBufferDepthFragments <<
"/" << maxDataBufferDepthFragments_
291 <<
", szB=" << dataBuffer->DataBufferDepthBytes <<
"/" << maxDataBufferDepthBytes_ <<
")"
292 <<
", timestamps=" << dataBuffer->DataBuffer.front()->timestamp() <<
"-" << dataBuffer->DataBuffer.back()->timestamp();
293 TLOG(TLVL_TRACE) <<
"Bad Omen: Possible causes include requests not getting through or Ignored-mode BR issues";
296 if (waittime % 5 && waittime != lastwaittime)
298 TLOG(TLVL_WAITFORBUFFERREADY) <<
"getDataLoop: Data Retreival paused for " << waittime <<
" ms waiting for data buffer to drain";
300 lastwaittime = waittime;
305 std::lock_guard<std::mutex> lk(dataBuffer->DataBufferMutex);
306 if (dataBufferIsTooLarge(
id))
308 auto begin = dataBuffer->DataBuffer.begin();
309 if (begin == dataBuffer->DataBuffer.end())
311 TLOG(TLVL_WARNING) <<
"Data buffer is reported as too large, but doesn't contain any Fragments! Possible corrupt memory!";
316 TLOG(TLVL_WAITFORBUFFERREADY) <<
"waitForDataBufferReady: Dropping Fragment with timestamp " << (*begin)->timestamp() <<
" from data buffer (Buffer over-size, circular data buffer mode)";
318 dataBuffer->DataBufferDepthBytes -= (*begin)->sizeBytes();
319 dataBuffer->DataBuffer.erase(begin);
320 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
321 dataBuffer->BufferFragmentKept =
false;
331 if (!dataBuffers_.count(
id))
333 TLOG(TLVL_ERROR) <<
"DataBufferError: "
334 <<
"Error in FragmentBuffer: Cannot check size of data buffer for ID " <<
id <<
" because it does not exist!";
335 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot check size of data buffer for ID " <<
id <<
" because it does not exist!";
337 auto dataBuffer = dataBuffers_[id];
338 return (maxDataBufferDepthFragments_ > 0 && dataBuffer->DataBufferDepthFragments.load() > maxDataBufferDepthFragments_) ||
339 (maxDataBufferDepthBytes_ > 0 && dataBuffer->DataBufferDepthBytes.load() > maxDataBufferDepthBytes_);
344 if (!dataBuffers_.count(
id))
346 TLOG(TLVL_ERROR) <<
"DataBufferError: "
347 <<
"Error in FragmentBuffer: Cannot get stats of data buffer for ID " <<
id <<
" because it does not exist!";
348 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot get stats of data buffer for ID " <<
id <<
" because it does not exist!";
350 auto dataBuffer = dataBuffers_[id];
354 TLOG(TLVL_GETBUFFERSTATS) <<
"getDataBufferStats: Sending Metrics";
355 metricMan->sendMetric(
"Buffer Depth Fragments", dataBuffer->DataBufferDepthFragments.load(),
"fragments", 1, MetricMode::LastPoint);
356 metricMan->sendMetric(
"Buffer Depth Bytes", dataBuffer->DataBufferDepthBytes.load(),
"bytes", 1, MetricMode::LastPoint);
358 auto bufferDepthFragmentsPercent = dataBuffer->DataBufferDepthFragments.load() * 100 /
static_cast<double>(maxDataBufferDepthFragments_);
359 auto bufferDepthBytesPercent = dataBuffer->DataBufferDepthBytes.load() * 100 /
static_cast<double>(maxDataBufferDepthBytes_);
360 metricMan->sendMetric(
"Fragment Buffer Full %Fragments", bufferDepthFragmentsPercent,
"%", 3, MetricMode::LastPoint);
361 metricMan->sendMetric(
"Fragment Buffer Full %Bytes", bufferDepthBytesPercent,
"%", 3, MetricMode::LastPoint);
362 metricMan->sendMetric(
"Fragment Buffer Full %", bufferDepthFragmentsPercent > bufferDepthBytesPercent ? bufferDepthFragmentsPercent : bufferDepthBytesPercent,
"%", 1, MetricMode::LastPoint);
364 TLOG(TLVL_GETBUFFERSTATS) <<
"getDataBufferStats: frags=" << dataBuffer->DataBufferDepthFragments.load() <<
"/" << maxDataBufferDepthFragments_
365 <<
", sz=" << dataBuffer->DataBufferDepthBytes.load() <<
"/" << maxDataBufferDepthBytes_;
370 if (!dataBuffers_.count(
id))
372 TLOG(TLVL_ERROR) <<
"DataBufferError: "
373 <<
"Error in FragmentBuffer: Cannot check data buffer for ID " <<
id <<
" because it does not exist!";
374 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot check data buffer for ID " <<
id <<
" because it does not exist!";
377 if (dataBuffers_[
id]->DataBufferDepthFragments > 0 && mode_ != RequestMode::Single && mode_ != RequestMode::Ignored)
379 auto dataBuffer = dataBuffers_[id];
380 std::lock_guard<std::mutex> lk(dataBuffer->DataBufferMutex);
383 while (dataBufferIsTooLarge(
id))
385 auto begin = dataBuffer->DataBuffer.begin();
386 TLOG(TLVL_CHECKDATABUFFER) <<
"checkDataBuffer: Dropping Fragment with timestamp " << (*begin)->timestamp() <<
" from data buffer (Buffer over-size)";
387 dataBuffer->DataBufferDepthBytes -= (*begin)->sizeBytes();
388 dataBuffer->DataBuffer.erase(begin);
389 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
390 dataBuffer->BufferFragmentKept =
false;
393 TLOG(TLVL_CHECKDATABUFFER) <<
"DataBufferDepthFragments is " << dataBuffer->DataBufferDepthFragments <<
", DataBuffer.size is " << dataBuffer->DataBuffer.size();
394 if (dataBuffer->DataBufferDepthFragments > 0 && staleTimeout_ > 0)
396 TLOG(TLVL_CHECKDATABUFFER) <<
"Determining if Fragments can be dropped from data buffer";
397 Fragment::timestamp_t last = dataBuffer->DataBuffer.back()->timestamp();
398 Fragment::timestamp_t min = last > staleTimeout_ ? last - staleTimeout_ : 0;
399 for (
auto it = dataBuffer->DataBuffer.begin(); it != dataBuffer->DataBuffer.end();)
401 if ((*it)->timestamp() < min)
403 TLOG(TLVL_CHECKDATABUFFER) <<
"checkDataBuffer: Dropping Fragment with timestamp " << (*it)->timestamp() <<
" from data buffer (timeout=" << staleTimeout_ <<
", min=" << min <<
")";
404 dataBuffer->DataBufferDepthBytes -= (*it)->sizeBytes();
405 dataBuffer->BufferFragmentKept =
false;
406 it = dataBuffer->DataBuffer.erase(it);
407 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
422 TLOG(TLVL_APPLYREQUESTS) <<
"Mode is Ignored; Copying data to output";
423 for (
auto&
id : dataBuffers_)
425 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
426 if (
id.second && !
id.second->DataBuffer.empty() &&
id.second->DataBuffer.back()->sequenceID() >= next_sequence_id_)
428 next_sequence_id_ =
id.second->DataBuffer.back()->sequenceID() + 1;
430 std::move(
id.second->DataBuffer.begin(),
id.second->DataBuffer.end(), std::inserter(frags, frags.end()));
431 id.second->DataBufferDepthBytes = 0;
432 id.second->DataBufferDepthFragments = 0;
433 id.second->BufferFragmentKept =
false;
434 id.second->DataBuffer.clear();
441 auto requests = requestBuffer_->GetRequests();
442 while (requests.size() > 1)
445 requestBuffer_->RemoveRequest(requests.begin()->first);
446 requests.erase(requests.begin());
448 sendEmptyFragments(frags, requests);
451 if (requests.size() == 0 || !requests.count(next_sequence_id_))
return;
453 for (
auto&
id : dataBuffers_)
455 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
456 if (
id.second->DataBufferDepthFragments > 0)
458 assert(
id.second->DataBufferDepthFragments == 1);
459 TLOG(TLVL_APPLYREQUESTS) <<
"Mode is Single; Sending copy of last event";
460 for (
auto& fragptr :
id.second->DataBuffer)
463 auto frag = fragptr.get();
464 auto newfrag = std::unique_ptr<artdaq::Fragment>(
new Fragment(next_sequence_id_, frag->fragmentID()));
465 newfrag->resize(frag->size() - detail::RawFragmentHeader::num_words());
466 memcpy(newfrag->headerAddress(), frag->headerAddress(), frag->sizeBytes());
467 newfrag->setTimestamp(requests[next_sequence_id_]);
468 newfrag->setSequenceID(next_sequence_id_);
469 frags.push_back(std::move(newfrag));
474 sendEmptyFragment(frags, next_sequence_id_,
id.first,
"No data for");
477 requestBuffer_->RemoveRequest(next_sequence_id_);
484 auto requests = requestBuffer_->GetRequests();
485 while (requests.size() > 1)
488 requestBuffer_->RemoveRequest(requests.begin()->first);
489 requests.erase(requests.begin());
491 sendEmptyFragments(frags, requests);
494 if (requests.size() == 0 || !requests.count(next_sequence_id_))
return;
496 for (
auto&
id : dataBuffers_)
498 TLOG(TLVL_DEBUG) <<
"applyRequestsBufferMode: Creating ContainerFragment for Buffered Fragments";
499 frags.emplace_back(
new artdaq::Fragment(next_sequence_id_,
id.first));
500 frags.back()->setTimestamp(requests[next_sequence_id_]);
501 ContainerFragmentLoader cfl(*frags.back());
502 cfl.set_missing_data(
false);
505 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
506 if (
id.second->BufferFragmentKept &&
id.second->DataBufferDepthFragments > 1)
508 id.second->DataBufferDepthBytes -=
id.second->DataBuffer.front()->sizeBytes();
509 id.second->DataBuffer.erase(
id.second->DataBuffer.begin());
510 id.second->DataBufferDepthFragments =
id.second->DataBuffer.size();
514 FragmentPtrs fragsToAdd;
515 std::move(
id.second->DataBuffer.begin(), --
id.second->DataBuffer.end(), std::back_inserter(fragsToAdd));
516 id.second->DataBuffer.erase(
id.second->DataBuffer.begin(), --
id.second->DataBuffer.end());
518 if (fragsToAdd.size() > 0)
520 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsBufferMode: Adding " << fragsToAdd.size() <<
" Fragments to Container";
521 cfl.addFragments(fragsToAdd);
524 if (
id.second->DataBuffer.size() == 1)
526 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsBufferMode: Adding Fragment with timestamp " <<
id.second->DataBuffer.front()->timestamp() <<
" to Container with sequence ID " << next_sequence_id_;
527 cfl.addFragment(
id.second->DataBuffer.front());
528 if (bufferModeKeepLatest_)
530 id.second->BufferFragmentKept =
true;
531 id.second->DataBufferDepthBytes =
id.second->DataBuffer.front()->sizeBytes();
532 id.second->DataBufferDepthFragments =
id.second->DataBuffer.size();
536 id.second->DataBuffer.clear();
537 id.second->BufferFragmentKept =
false;
538 id.second->DataBufferDepthBytes = 0;
539 id.second->DataBufferDepthFragments = 0;
543 requestBuffer_->RemoveRequest(next_sequence_id_);
549 auto dataBuffer = dataBuffers_[id];
551 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Checking that data exists for request window " << seq;
552 Fragment::timestamp_t min = ts > windowOffset_ ? ts - windowOffset_ : 0;
553 Fragment::timestamp_t max = ts + windowWidth_ > windowOffset_ ? ts + windowWidth_ - windowOffset_ : 1;
555 TLOG(TLVL_APPLYREQUESTS) <<
"ApplyRequestsWindowsMode_CheckAndFillDataBuffer: min is " << min <<
", max is " << max
556 <<
" and first/last points in buffer are " << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.front()->timestamp() : 0)
557 <<
"/" << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.back()->timestamp() : 0)
558 <<
" (sz=" << dataBuffer->DataBufferDepthFragments <<
" [" << dataBuffer->DataBufferDepthBytes.load()
559 <<
"/" << maxDataBufferDepthBytes_ <<
"])";
560 bool windowClosed = dataBuffer->DataBufferDepthFragments > 0 && dataBuffer->DataBuffer.back()->timestamp() >= max;
561 bool windowTimeout = !windowClosed && TimeUtils::GetElapsedTimeMicroseconds(requestBuffer_->GetRequestTime(seq)) > window_close_timeout_us_;
564 TLOG(TLVL_WARNING) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: A timeout occurred waiting for data to close the request window ({" << min <<
"-" << max
565 <<
"}, buffer={" << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.front()->timestamp() : 0) <<
"-"
566 << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.back()->timestamp() : 0)
567 <<
"} ). Time waiting: "
568 << TimeUtils::GetElapsedTimeMicroseconds(requestBuffer_->GetRequestTime(seq)) <<
" us "
569 <<
"(> " << window_close_timeout_us_ <<
" us).";
571 if (windowClosed || windowTimeout)
573 TLOG(TLVL_DEBUG) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Creating ContainerFragment for Window-requested Fragments";
574 frags.emplace_back(
new artdaq::Fragment(seq,
id));
575 frags.back()->setTimestamp(ts);
576 ContainerFragmentLoader cfl(*frags.back());
590 if (!windowClosed || (dataBuffer->DataBufferDepthFragments > 0 && dataBuffer->DataBuffer.front()->timestamp() > min))
592 TLOG(TLVL_DEBUG) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Request window starts before and/or ends after the current data buffer, setting ContainerFragment's missing_data flag!"
593 <<
" (requestWindowRange=[" << min <<
"," << max <<
"], "
594 <<
"buffer={" << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.front()->timestamp() : 0) <<
"-"
595 << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.back()->timestamp() : 0) <<
"}";
596 cfl.set_missing_data(
true);
599 auto it = dataBuffer->DataBuffer.begin();
603 it = dataBuffer->DataBuffer.end();
605 while (it != dataBuffer->DataBuffer.begin())
607 if ((*it)->timestamp() < min)
615 FragmentPtrs fragsToAdd;
617 for (; it != dataBuffer->DataBuffer.end();)
619 Fragment::timestamp_t fragT = (*it)->timestamp();
625 if (fragT > max || (fragT == max && windowWidth_ > 0))
628 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Adding Fragment with timestamp " << (*it)->timestamp() <<
" to Container";
631 dataBuffer->DataBufferDepthBytes -= (*it)->sizeBytes();
632 fragsToAdd.emplace_back(std::move(*it));
633 it = dataBuffer->DataBuffer.erase(it);
637 fragsToAdd.emplace_back(it->get());
642 if (fragsToAdd.size() > 0)
644 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Adding " << fragsToAdd.size() <<
" Fragments to Container";
645 cfl.addFragments(fragsToAdd);
650 for (
auto& frag : fragsToAdd)
658 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
659 dataBuffer->WindowsSent[seq] = std::chrono::steady_clock::now();
660 if (seq > dataBuffer->HighestRequestSeen) dataBuffer->HighestRequestSeen = seq;
666 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode BEGIN";
668 auto requests = requestBuffer_->GetRequests();
670 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode: Starting request processing for " << requests.size() <<
" requests";
671 for (
auto req = requests.begin(); req != requests.end();)
673 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode: processing request with sequence ID " << req->first <<
", timestamp " << req->second;
675 while (req->first < next_sequence_id_ && requests.size() > 0)
677 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode: Clearing passed request for sequence ID " << req->first;
678 requestBuffer_->RemoveRequest(req->first);
679 req = requests.erase(req);
681 if (requests.size() == 0)
break;
683 for (
auto&
id : dataBuffers_)
685 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
686 if (!
id.second->WindowsSent.count(req->first))
688 applyRequestsWindowMode_CheckAndFillDataBuffer(frags,
id.first, req->first, req->second);
691 checkSentWindows(req->first);
696 std::set<artdaq::Fragment::sequence_id_t> seqs;
697 for (
auto&
id : dataBuffers_)
699 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
700 for (
auto& seq :
id.second->WindowsSent)
702 seqs.insert(seq.first);
705 for (
auto& seq : seqs)
707 checkSentWindows(seq);
713 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsSequenceIDMode BEGIN";
715 auto requests = requestBuffer_->GetRequests();
717 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsSequenceIDMode: Starting request processing";
718 for (
auto req = requests.begin(); req != requests.end();)
720 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsSequenceIDMode: Checking that data exists for request SequenceID " << req->first;
722 for (
auto&
id : dataBuffers_)
724 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
725 if (!
id.second->WindowsSent.count(req->first))
727 TLOG(29) <<
"Searching id " <<
id.first <<
" for Fragments with Sequence ID " << req->first;
728 for (
auto it =
id.second->DataBuffer.begin(); it !=
id.second->DataBuffer.end();)
730 auto seq = (*it)->sequenceID();
731 TLOG(29) <<
"applyRequestsSequenceIDMode: Fragment SeqID " << seq <<
", request ID " << req->first;
732 if (seq == req->first)
734 TLOG(29) <<
"applyRequestsSequenceIDMode: Adding Fragment to output";
735 id.second->WindowsSent[req->first] = std::chrono::steady_clock::now();
736 id.second->DataBufferDepthBytes -= (*it)->sizeBytes();
737 frags.push_back(std::move(*it));
738 it =
id.second->DataBuffer.erase(it);
739 id.second->DataBufferDepthFragments =
id.second->DataBuffer.size();
747 if (req->first >
id.second->HighestRequestSeen)
id.second->HighestRequestSeen = req->first;
749 checkSentWindows(req->first);
754 std::set<artdaq::Fragment::sequence_id_t> seqs;
755 for (
auto&
id : dataBuffers_)
757 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
758 for (
auto& seq :
id.second->WindowsSent)
760 seqs.insert(seq.first);
763 for (
auto& seq : seqs)
765 checkSentWindows(seq);
777 if (mode_ == RequestMode::Ignored)
779 auto start_time = std::chrono::steady_clock::now();
780 while (dataBufferFragmentCount_() == 0 && TimeUtils::GetElapsedTime(start_time) < 1.0)
782 if (check_stop())
return false;
783 std::unique_lock<std::mutex> lock(dataConditionMutex_);
784 dataCondition_.wait_for(lock, std::chrono::milliseconds(10), [
this]() {
return dataBufferFragmentCount_() > 0; });
787 else if (requestBuffer_ ==
nullptr)
789 TLOG(TLVL_ERROR) <<
"Request Buffer must be set (via SetRequestBuffer) before applyRequests/getData can be called!";
794 if ((check_stop() && requestBuffer_->size() == 0))
return false;
796 std::unique_lock<std::mutex> lock(dataConditionMutex_);
797 dataCondition_.wait_for(lock, std::chrono::milliseconds(10));
804 while (requestBuffer_->size() == 0 && counter < 100)
806 if (check_stop())
return false;
810 requestBuffer_->WaitForRequests(10);
815 if (systemFragmentCount_.load() > 0)
817 std::lock_guard<std::mutex> lk(systemFragmentMutex_);
818 TLOG(TLVL_INFO) <<
"Copying " << systemFragmentCount_.load() <<
" System Fragments into output";
820 std::move(systemFragments_.begin(), systemFragments_.end(), std::inserter(frags, frags.end()));
821 systemFragments_.clear();
822 systemFragmentCount_ = 0;
827 case RequestMode::Single:
828 applyRequestsSingleMode(frags);
830 case RequestMode::Window:
831 applyRequestsWindowMode(frags);
833 case RequestMode::Buffer:
834 applyRequestsBufferMode(frags);
836 case RequestMode::SequenceID:
837 applyRequestsSequenceIDMode(frags);
839 case RequestMode::Ignored:
841 applyRequestsIgnoredMode(frags);
845 getDataBuffersStats();
847 if (frags.size() > 0)
848 TLOG(TLVL_APPLYREQUESTS) <<
"Finished Processing requests, returning " << frags.size() <<
" fragments, current ev_counter is " << next_sequence_id_;
854 TLOG(TLVL_EMPTYFRAGMENT) << desc <<
" sequence ID " << seqId <<
", sending empty fragment";
855 auto frag =
new Fragment();
856 frag->setSequenceID(seqId);
857 frag->setFragmentID(fragmentId);
858 frag->setSystemType(Fragment::EmptyFragmentType);
859 frags.emplace_back(FragmentPtr(frag));
865 if (requests.size() > 0)
867 TLOG(TLVL_SENDEMPTYFRAGMENTS) <<
"Sending Empty Fragments for Sequence IDs from " << next_sequence_id_ <<
" up to but not including " << requests.begin()->first;
868 while (requests.begin()->first > next_sequence_id_)
870 for (
auto& fid : dataBuffers_)
872 sendEmptyFragment(frags, next_sequence_id_, fid.first,
"Missed request for");
881 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Checking if request " << seq <<
" can be removed from request list";
882 bool seqComplete =
true;
883 bool seqTimeout =
false;
884 for (
auto&
id : dataBuffers_)
886 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
887 if (!
id.second->WindowsSent.count(seq) ||
id.second->HighestRequestSeen < seq)
891 if (
id.second->WindowsSent.count(seq) && TimeUtils::GetElapsedTimeMicroseconds(
id.second->WindowsSent[seq]) > missing_request_window_timeout_us_)
898 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Request " << seq <<
" is complete, removing from requestBuffer_.";
899 requestBuffer_->RemoveRequest(seq);
901 if (next_sequence_id_ == seq)
903 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Sequence ID matches ev_counter, incrementing ev_counter (" << next_sequence_id_ <<
")";
905 for (
auto&
id : dataBuffers_)
907 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
908 id.second->WindowsSent.erase(seq);
916 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Sent Window history indicates that requests between " << next_sequence_id_ <<
" and " << seq <<
" have timed out.";
917 while (next_sequence_id_ <= seq)
919 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!";
920 requestBuffer_->RemoveRequest(next_sequence_id_);
922 for (
auto&
id : dataBuffers_)
924 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
925 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.