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_request_timeout", 0xFFFFFFFF))
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";
121 void artdaq::FragmentBuffer::Reset(
bool stop)
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;
141 void artdaq::FragmentBuffer::AddFragmentsToBuffer(FragmentPtrs frags)
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: {
178 auto dataIter = type_it->second.rbegin();
179 TLOG(TLVL_TRACE) <<
"Adding Fragment with Fragment ID " << frag_id <<
", Sequence ID " << (*dataIter)->sequenceID() <<
", and Timestamp " << (*dataIter)->timestamp() <<
" to buffer";
180 dataBuffer->DataBuffer.clear();
181 dataBuffer->DataBufferDepthBytes = (*dataIter)->sizeBytes();
182 dataBuffer->DataBuffer.emplace_back(std::move(*dataIter));
183 dataBuffer->DataBufferDepthFragments = 1;
184 type_it->second.clear();
187 case RequestMode::Buffer:
188 case RequestMode::Ignored:
189 case RequestMode::Window:
190 case RequestMode::SequenceID:
192 while (!type_it->second.empty())
194 auto dataIter = type_it->second.begin();
195 TLOG(TLVL_TRACE) <<
"Adding Fragment with Fragment ID " << frag_id <<
", Sequence ID " << (*dataIter)->sequenceID() <<
", and Timestamp " << (*dataIter)->timestamp() <<
" to buffer";
197 dataBuffer->DataBufferDepthBytes += (*dataIter)->sizeBytes();
198 dataBuffer->DataBuffer.emplace_back(std::move(*dataIter));
199 type_it->second.erase(dataIter);
201 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
204 getDataBufferStats(frag_id);
207 dataCondition_.notify_all();
212 TLOG(TLVL_CHECKSTOP) <<
"CFG::check_stop: should_stop=" << should_stop_.load();
214 if (!should_stop_.load())
return false;
215 if (mode_ == RequestMode::Ignored)
return true;
217 if (requestBuffer_ !=
nullptr)
220 TLOG(TLVL_DEBUG) <<
"should_stop is true, requestBuffer_->isRunning() is " << std::boolalpha << requestBuffer_->isRunning();
221 return !requestBuffer_->isRunning();
230 case RequestMode::Single:
232 case RequestMode::Buffer:
234 case RequestMode::Window:
236 case RequestMode::Ignored:
238 case RequestMode::SequenceID:
248 for (
auto&
id : dataBuffers_) count +=
id.second->DataBufferDepthFragments;
249 count += systemFragmentCount_.load();
255 if (!dataBuffers_.count(
id))
257 TLOG(TLVL_ERROR) <<
"DataBufferError: "
258 <<
"Error in FragmentBuffer: Cannot wait for data buffer for ID " <<
id <<
" because it does not exist!";
259 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot wait for data buffer for ID " <<
id <<
" because it does not exist!";
261 auto startwait = std::chrono::steady_clock::now();
263 auto lastwaittime = 0ULL;
264 auto dataBuffer = dataBuffers_[id];
266 while (dataBufferIsTooLarge(
id))
268 if (!circularDataBufferMode_)
270 if (should_stop_.load())
272 TLOG(TLVL_DEBUG) <<
"Run ended while waiting for buffer to shrink!";
273 getDataBufferStats(
id);
274 dataCondition_.notify_all();
277 auto waittime = TimeUtils::GetElapsedTimeMilliseconds(startwait);
279 if (first || (waittime != lastwaittime && waittime % 1000 == 0))
281 TLOG(TLVL_WARNING) <<
"Bad Omen: Data Buffer has exceeded its size limits. "
282 <<
"(seq_id=" << next_sequence_id_ <<
", frag_id=" <<
id
283 <<
", frags=" << dataBuffer->DataBufferDepthFragments <<
"/" << maxDataBufferDepthFragments_
284 <<
", szB=" << dataBuffer->DataBufferDepthBytes <<
"/" << maxDataBufferDepthBytes_ <<
")"
285 <<
", timestamps=" << dataBuffer->DataBuffer.front()->timestamp() <<
"-" << dataBuffer->DataBuffer.back()->timestamp();
286 TLOG(TLVL_TRACE) <<
"Bad Omen: Possible causes include requests not getting through or Ignored-mode BR issues";
289 if (waittime % 5 && waittime != lastwaittime)
291 TLOG(TLVL_WAITFORBUFFERREADY) <<
"getDataLoop: Data Retreival paused for " << waittime <<
" ms waiting for data buffer to drain";
293 lastwaittime = waittime;
298 std::lock_guard<std::mutex> lk(dataBuffer->DataBufferMutex);
299 if (dataBufferIsTooLarge(
id))
301 auto begin = dataBuffer->DataBuffer.begin();
302 if (begin == dataBuffer->DataBuffer.end())
304 TLOG(TLVL_WARNING) <<
"Data buffer is reported as too large, but doesn't contain any Fragments! Possible corrupt memory!";
309 TLOG(TLVL_WAITFORBUFFERREADY) <<
"waitForDataBufferReady: Dropping Fragment with timestamp " << (*begin)->timestamp() <<
" from data buffer (Buffer over-size, circular data buffer mode)";
311 dataBuffer->DataBufferDepthBytes -= (*begin)->sizeBytes();
312 dataBuffer->DataBuffer.erase(begin);
313 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
314 dataBuffer->BufferFragmentKept =
false;
324 if (!dataBuffers_.count(
id))
326 TLOG(TLVL_ERROR) <<
"DataBufferError: "
327 <<
"Error in FragmentBuffer: Cannot check size of data buffer for ID " <<
id <<
" because it does not exist!";
328 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot check size of data buffer for ID " <<
id <<
" because it does not exist!";
330 auto dataBuffer = dataBuffers_[id];
331 return (maxDataBufferDepthFragments_ > 0 && dataBuffer->DataBufferDepthFragments.load() > maxDataBufferDepthFragments_) ||
332 (maxDataBufferDepthBytes_ > 0 && dataBuffer->DataBufferDepthBytes.load() > maxDataBufferDepthBytes_);
337 if (!dataBuffers_.count(
id))
339 TLOG(TLVL_ERROR) <<
"DataBufferError: "
340 <<
"Error in FragmentBuffer: Cannot get stats of data buffer for ID " <<
id <<
" because it does not exist!";
341 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot get stats of data buffer for ID " <<
id <<
" because it does not exist!";
343 auto dataBuffer = dataBuffers_[id];
347 TLOG(TLVL_GETBUFFERSTATS) <<
"getDataBufferStats: Sending Metrics";
348 metricMan->sendMetric(
"Buffer Depth Fragments", dataBuffer->DataBufferDepthFragments.load(),
"fragments", 1, MetricMode::LastPoint);
349 metricMan->sendMetric(
"Buffer Depth Bytes", dataBuffer->DataBufferDepthBytes.load(),
"bytes", 1, MetricMode::LastPoint);
351 auto bufferDepthFragmentsPercent = dataBuffer->DataBufferDepthFragments.load() * 100 /
static_cast<double>(maxDataBufferDepthFragments_);
352 auto bufferDepthBytesPercent = dataBuffer->DataBufferDepthBytes.load() * 100 /
static_cast<double>(maxDataBufferDepthBytes_);
353 metricMan->sendMetric(
"Fragment Buffer Full %Fragments", bufferDepthFragmentsPercent,
"%", 3, MetricMode::LastPoint);
354 metricMan->sendMetric(
"Fragment Buffer Full %Bytes", bufferDepthBytesPercent,
"%", 3, MetricMode::LastPoint);
355 metricMan->sendMetric(
"Fragment Buffer Full %", bufferDepthFragmentsPercent > bufferDepthBytesPercent ? bufferDepthFragmentsPercent : bufferDepthBytesPercent,
"%", 1, MetricMode::LastPoint);
357 TLOG(TLVL_GETBUFFERSTATS) <<
"getDataBufferStats: frags=" << dataBuffer->DataBufferDepthFragments.load() <<
"/" << maxDataBufferDepthFragments_
358 <<
", sz=" << dataBuffer->DataBufferDepthBytes.load() <<
"/" << maxDataBufferDepthBytes_;
363 if (!dataBuffers_.count(
id))
365 TLOG(TLVL_ERROR) <<
"DataBufferError: "
366 <<
"Error in FragmentBuffer: Cannot check data buffer for ID " <<
id <<
" because it does not exist!";
367 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot check data buffer for ID " <<
id <<
" because it does not exist!";
370 if (dataBuffers_[
id]->DataBufferDepthFragments > 0 && mode_ != RequestMode::Single && mode_ != RequestMode::Ignored)
372 auto dataBuffer = dataBuffers_[id];
373 std::lock_guard<std::mutex> lk(dataBuffer->DataBufferMutex);
376 while (dataBufferIsTooLarge(
id))
378 auto begin = dataBuffer->DataBuffer.begin();
379 TLOG(TLVL_CHECKDATABUFFER) <<
"checkDataBuffer: Dropping Fragment with timestamp " << (*begin)->timestamp() <<
" from data buffer (Buffer over-size)";
380 dataBuffer->DataBufferDepthBytes -= (*begin)->sizeBytes();
381 dataBuffer->DataBuffer.erase(begin);
382 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
383 dataBuffer->BufferFragmentKept =
false;
386 TLOG(TLVL_CHECKDATABUFFER) <<
"DataBufferDepthFragments is " << dataBuffer->DataBufferDepthFragments <<
", DataBuffer.size is " << dataBuffer->DataBuffer.size();
387 if (dataBuffer->DataBufferDepthFragments > 0)
389 TLOG(TLVL_CHECKDATABUFFER) <<
"Determining if Fragments can be dropped from data buffer";
390 Fragment::timestamp_t last = dataBuffer->DataBuffer.back()->timestamp();
391 Fragment::timestamp_t min = last > staleTimeout_ ? last - staleTimeout_ : 0;
392 for (
auto it = dataBuffer->DataBuffer.begin(); it != dataBuffer->DataBuffer.end();)
394 if ((*it)->timestamp() < min)
396 TLOG(TLVL_CHECKDATABUFFER) <<
"checkDataBuffer: Dropping Fragment with timestamp " << (*it)->timestamp() <<
" from data buffer (timeout=" << staleTimeout_ <<
", min=" << min <<
")";
397 dataBuffer->DataBufferDepthBytes -= (*it)->sizeBytes();
398 dataBuffer->BufferFragmentKept =
false;
399 it = dataBuffer->DataBuffer.erase(it);
400 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
415 TLOG(TLVL_APPLYREQUESTS) <<
"Mode is Ignored; Copying data to output";
416 for (
auto&
id : dataBuffers_)
418 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
419 std::move(
id.second->DataBuffer.begin(),
id.second->DataBuffer.end(), std::inserter(frags, frags.end()));
420 id.second->DataBufferDepthBytes = 0;
421 id.second->DataBufferDepthFragments = 0;
422 id.second->BufferFragmentKept =
false;
423 id.second->DataBuffer.clear();
430 auto requests = requestBuffer_->GetRequests();
431 while (requests.size() > 1)
434 requestBuffer_->RemoveRequest(requests.begin()->first);
435 requests.erase(requests.begin());
437 sendEmptyFragments(frags, requests);
440 if (requests.size() == 0 || !requests.count(next_sequence_id_))
return;
442 for (
auto&
id : dataBuffers_)
444 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
445 if (
id.second->DataBufferDepthFragments > 0)
447 assert(
id.second->DataBufferDepthFragments == 1);
448 TLOG(TLVL_APPLYREQUESTS) <<
"Mode is Single; Sending copy of last event";
449 for (
auto& fragptr :
id.second->DataBuffer)
452 auto frag = fragptr.get();
453 auto newfrag = std::unique_ptr<artdaq::Fragment>(
new Fragment(next_sequence_id_, frag->fragmentID()));
454 newfrag->resize(frag->size() - detail::RawFragmentHeader::num_words());
455 memcpy(newfrag->headerAddress(), frag->headerAddress(), frag->sizeBytes());
456 newfrag->setTimestamp(requests[next_sequence_id_]);
457 newfrag->setSequenceID(next_sequence_id_);
458 frags.push_back(std::move(newfrag));
463 sendEmptyFragment(frags, next_sequence_id_,
id.first,
"No data for");
466 requestBuffer_->RemoveRequest(next_sequence_id_);
473 auto requests = requestBuffer_->GetRequests();
474 while (requests.size() > 1)
477 requestBuffer_->RemoveRequest(requests.begin()->first);
478 requests.erase(requests.begin());
480 sendEmptyFragments(frags, requests);
483 if (requests.size() == 0 || !requests.count(next_sequence_id_))
return;
485 for (
auto&
id : dataBuffers_)
487 TLOG(TLVL_DEBUG) <<
"applyRequestsBufferMode: Creating ContainerFragment for Buffered Fragments";
488 frags.emplace_back(
new artdaq::Fragment(next_sequence_id_,
id.first));
489 frags.back()->setTimestamp(requests[next_sequence_id_]);
490 ContainerFragmentLoader cfl(*frags.back());
491 cfl.set_missing_data(
false);
494 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
495 if (
id.second->BufferFragmentKept &&
id.second->DataBufferDepthFragments > 1)
497 id.second->DataBufferDepthBytes -=
id.second->DataBuffer.front()->sizeBytes();
498 id.second->DataBuffer.erase(
id.second->DataBuffer.begin());
499 id.second->DataBufferDepthFragments =
id.second->DataBuffer.size();
503 FragmentPtrs fragsToAdd;
504 std::move(
id.second->DataBuffer.begin(), --
id.second->DataBuffer.end(), std::back_inserter(fragsToAdd));
505 id.second->DataBuffer.erase(
id.second->DataBuffer.begin(), --
id.second->DataBuffer.end());
507 if (fragsToAdd.size() > 0)
509 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsBufferMode: Adding " << fragsToAdd.size() <<
" Fragments to Container";
510 cfl.addFragments(fragsToAdd);
513 if (
id.second->DataBuffer.size() == 1)
515 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsBufferMode: Adding Fragment with timestamp " <<
id.second->DataBuffer.front()->timestamp() <<
" to Container with sequence ID " << next_sequence_id_;
516 cfl.addFragment(
id.second->DataBuffer.front());
517 if (bufferModeKeepLatest_)
519 id.second->BufferFragmentKept =
true;
520 id.second->DataBufferDepthBytes =
id.second->DataBuffer.front()->sizeBytes();
521 id.second->DataBufferDepthFragments =
id.second->DataBuffer.size();
525 id.second->DataBuffer.clear();
526 id.second->BufferFragmentKept =
false;
527 id.second->DataBufferDepthBytes = 0;
528 id.second->DataBufferDepthFragments = 0;
532 requestBuffer_->RemoveRequest(next_sequence_id_);
538 auto dataBuffer = dataBuffers_[id];
540 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Checking that data exists for request window " << seq;
541 Fragment::timestamp_t min = ts > windowOffset_ ? ts - windowOffset_ : 0;
542 Fragment::timestamp_t max = ts + windowWidth_ > windowOffset_ ? ts + windowWidth_ - windowOffset_ : 1;
544 TLOG(TLVL_APPLYREQUESTS) <<
"ApplyRequestsWindowsMode_CheckAndFillDataBuffer: min is " << min <<
", max is " << max
545 <<
" and first/last points in buffer are " << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.front()->timestamp() : 0)
546 <<
"/" << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.back()->timestamp() : 0)
547 <<
" (sz=" << dataBuffer->DataBufferDepthFragments <<
" [" << dataBuffer->DataBufferDepthBytes.load()
548 <<
"/" << maxDataBufferDepthBytes_ <<
"])";
549 bool windowClosed = dataBuffer->DataBufferDepthFragments > 0 && dataBuffer->DataBuffer.back()->timestamp() >= max;
550 bool windowTimeout = !windowClosed && TimeUtils::GetElapsedTimeMicroseconds(requestBuffer_->GetRequestTime(seq)) > window_close_timeout_us_;
553 TLOG(TLVL_WARNING) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: A timeout occurred waiting for data to close the request window ({" << min <<
"-" << max
554 <<
"}, buffer={" << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.front()->timestamp() : 0) <<
"-"
555 << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.back()->timestamp() : 0)
556 <<
"} ). Time waiting: "
557 << TimeUtils::GetElapsedTimeMicroseconds(requestBuffer_->GetRequestTime(seq)) <<
" us "
558 <<
"(> " << window_close_timeout_us_ <<
" us).";
560 if (windowClosed || windowTimeout)
562 TLOG(TLVL_DEBUG) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Creating ContainerFragment for Window-requested Fragments";
563 frags.emplace_back(
new artdaq::Fragment(seq,
id));
564 frags.back()->setTimestamp(ts);
565 ContainerFragmentLoader cfl(*frags.back());
579 if (!windowClosed || (dataBuffer->DataBufferDepthFragments > 0 && dataBuffer->DataBuffer.front()->timestamp() > min))
581 TLOG(TLVL_DEBUG) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Request window starts before and/or ends after the current data buffer, setting ContainerFragment's missing_data flag!"
582 <<
" (requestWindowRange=[" << min <<
"," << max <<
"], "
583 <<
"buffer={" << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.front()->timestamp() : 0) <<
"-"
584 << (dataBuffer->DataBufferDepthFragments > 0 ? dataBuffer->DataBuffer.back()->timestamp() : 0) <<
"}";
585 cfl.set_missing_data(
true);
588 auto it = dataBuffer->DataBuffer.begin();
592 it = dataBuffer->DataBuffer.end();
594 while (it != dataBuffer->DataBuffer.begin())
596 if ((*it)->timestamp() < min)
604 FragmentPtrs fragsToAdd;
606 for (; it != dataBuffer->DataBuffer.end();)
608 Fragment::timestamp_t fragT = (*it)->timestamp();
614 if (fragT > max || (fragT == max && windowWidth_ > 0))
617 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Adding Fragment with timestamp " << (*it)->timestamp() <<
" to Container";
620 dataBuffer->DataBufferDepthBytes -= (*it)->sizeBytes();
621 fragsToAdd.emplace_back(std::move(*it));
622 it = dataBuffer->DataBuffer.erase(it);
626 fragsToAdd.emplace_back(it->get());
631 if (fragsToAdd.size() > 0)
633 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode_CheckAndFillDataBuffer: Adding " << fragsToAdd.size() <<
" Fragments to Container";
634 cfl.addFragments(fragsToAdd);
639 for (
auto& frag : fragsToAdd)
647 dataBuffer->DataBufferDepthFragments = dataBuffer->DataBuffer.size();
648 dataBuffer->WindowsSent[seq] = std::chrono::steady_clock::now();
649 if (seq > dataBuffer->HighestRequestSeen) dataBuffer->HighestRequestSeen = seq;
655 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode BEGIN";
657 auto requests = requestBuffer_->GetRequests();
659 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode: Starting request processing for " << requests.size() <<
" requests";
660 for (
auto req = requests.begin(); req != requests.end();)
662 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode: processing request with sequence ID " << req->first <<
", timestamp " << req->second;
664 while (req->first < next_sequence_id_ && requests.size() > 0)
666 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsWindowMode: Clearing passed request for sequence ID " << req->first;
667 requestBuffer_->RemoveRequest(req->first);
668 req = requests.erase(req);
670 if (requests.size() == 0)
break;
672 for (
auto&
id : dataBuffers_)
674 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
675 if (!
id.second->WindowsSent.count(req->first))
677 applyRequestsWindowMode_CheckAndFillDataBuffer(frags,
id.first, req->first, req->second);
680 checkSentWindows(req->first);
685 std::set<artdaq::Fragment::sequence_id_t> seqs;
686 for (
auto&
id : dataBuffers_)
688 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
689 for (
auto& seq :
id.second->WindowsSent)
691 seqs.insert(seq.first);
694 for (
auto& seq : seqs)
696 checkSentWindows(seq);
702 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsSequenceIDMode BEGIN";
704 auto requests = requestBuffer_->GetRequests();
706 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsSequenceIDMode: Starting request processing";
707 for (
auto req = requests.begin(); req != requests.end();)
709 TLOG(TLVL_APPLYREQUESTS) <<
"applyRequestsSequenceIDMode: Checking that data exists for request SequenceID " << req->first;
711 for (
auto&
id : dataBuffers_)
713 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
714 if (!
id.second->WindowsSent.count(req->first))
716 TLOG(29) <<
"Searching id " <<
id.first <<
" for Fragments with Sequence ID " << req->first;
717 for (
auto it =
id.second->DataBuffer.begin(); it !=
id.second->DataBuffer.end();)
719 auto seq = (*it)->sequenceID();
720 TLOG(29) <<
"applyRequestsSequenceIDMode: Fragment SeqID " << seq <<
", request ID " << req->first;
721 if (seq == req->first)
723 TLOG(29) <<
"applyRequestsSequenceIDMode: Adding Fragment to output";
724 id.second->WindowsSent[req->first] = std::chrono::steady_clock::now();
725 id.second->DataBufferDepthBytes -= (*it)->sizeBytes();
726 frags.push_back(std::move(*it));
727 it =
id.second->DataBuffer.erase(it);
728 id.second->DataBufferDepthFragments =
id.second->DataBuffer.size();
736 if (req->first >
id.second->HighestRequestSeen)
id.second->HighestRequestSeen = req->first;
738 checkSentWindows(req->first);
743 std::set<artdaq::Fragment::sequence_id_t> seqs;
744 for (
auto&
id : dataBuffers_)
746 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
747 for (
auto& seq :
id.second->WindowsSent)
749 seqs.insert(seq.first);
752 for (
auto& seq : seqs)
754 checkSentWindows(seq);
766 if (mode_ == RequestMode::Ignored)
768 while (dataBufferFragmentCount_() == 0)
770 if (check_stop())
return false;
771 std::unique_lock<std::mutex> lock(dataConditionMutex_);
772 dataCondition_.wait_for(lock, std::chrono::milliseconds(10), [
this]() {
return dataBufferFragmentCount_() > 0; });
775 else if (requestBuffer_ ==
nullptr)
777 TLOG(TLVL_ERROR) <<
"Request Buffer must be set (via SetRequestBuffer) before applyRequests/getData can be called!";
782 if ((check_stop() && requestBuffer_->size() == 0))
return false;
784 std::unique_lock<std::mutex> lock(dataConditionMutex_);
785 dataCondition_.wait_for(lock, std::chrono::milliseconds(10));
792 while (requestBuffer_->size() == 0 && counter < 100)
794 if (check_stop())
return false;
798 requestBuffer_->WaitForRequests(10);
803 if (systemFragmentCount_.load() > 0)
805 std::lock_guard<std::mutex> lk(systemFragmentMutex_);
806 TLOG(TLVL_INFO) <<
"Copying " << systemFragmentCount_.load() <<
" System Fragments into output";
808 std::move(systemFragments_.begin(), systemFragments_.end(), std::inserter(frags, frags.end()));
809 systemFragments_.clear();
810 systemFragmentCount_ = 0;
815 case RequestMode::Single:
816 applyRequestsSingleMode(frags);
818 case RequestMode::Window:
819 applyRequestsWindowMode(frags);
821 case RequestMode::Buffer:
822 applyRequestsBufferMode(frags);
824 case RequestMode::SequenceID:
825 applyRequestsSequenceIDMode(frags);
827 case RequestMode::Ignored:
829 applyRequestsIgnoredMode(frags);
833 getDataBuffersStats();
835 if (frags.size() > 0)
836 TLOG(TLVL_APPLYREQUESTS) <<
"Finished Processing requests, returning " << frags.size() <<
" fragments, current ev_counter is " << next_sequence_id_;
842 TLOG(TLVL_EMPTYFRAGMENT) << desc <<
" sequence ID " << seqId <<
", sending empty fragment";
843 auto frag =
new Fragment();
844 frag->setSequenceID(seqId);
845 frag->setFragmentID(fragmentId);
846 frag->setSystemType(Fragment::EmptyFragmentType);
847 frags.emplace_back(FragmentPtr(frag));
853 if (requests.size() > 0)
855 TLOG(TLVL_SENDEMPTYFRAGMENTS) <<
"Sending Empty Fragments for Sequence IDs from " << next_sequence_id_ <<
" up to but not including " << requests.begin()->first;
856 while (requests.begin()->first > next_sequence_id_)
858 for (
auto& fid : dataBuffers_)
860 sendEmptyFragment(frags, next_sequence_id_, fid.first,
"Missed request for");
869 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Checking if request " << seq <<
" can be removed from request list";
870 bool seqComplete =
true;
871 bool seqTimeout =
false;
872 for (
auto&
id : dataBuffers_)
874 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
875 if (!
id.second->WindowsSent.count(seq) ||
id.second->HighestRequestSeen < seq)
879 if (
id.second->WindowsSent.count(seq) && TimeUtils::GetElapsedTimeMicroseconds(
id.second->WindowsSent[seq]) > missing_request_window_timeout_us_)
886 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Request " << seq <<
" is complete, removing from requestBuffer_.";
887 requestBuffer_->RemoveRequest(seq);
889 if (next_sequence_id_ == seq)
891 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Sequence ID matches ev_counter, incrementing ev_counter (" << next_sequence_id_ <<
")";
893 for (
auto&
id : dataBuffers_)
895 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
896 id.second->WindowsSent.erase(seq);
904 TLOG(TLVL_CHECKWINDOWS) <<
"checkSentWindows: Sent Window history indicates that requests between " << next_sequence_id_ <<
" and " << seq <<
" have timed out.";
905 while (next_sequence_id_ <= seq)
907 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!";
908 requestBuffer_->RemoveRequest(next_sequence_id_);
910 for (
auto&
id : dataBuffers_)
912 std::lock_guard<std::mutex> lk(
id.second->DataBufferMutex);
913 id.second->WindowsSent.erase(next_sequence_id_);
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 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.