artdaq  v3_09_00
RequestBuffer.cc
1 #include "artdaq/DAQdata/Globals.hh"
2 #define TRACE_NAME (app_name + "_RequestBuffer").c_str() // include these 2 first -
3 
4 #include "artdaq/DAQrate/RequestBuffer.hh"
5 
6 artdaq::RequestBuffer::RequestBuffer(artdaq::Fragment::sequence_id_t request_increment)
7 
8  : requests_()
9  , request_timing_()
10  , highest_seen_request_(0)
11  , last_next_request_(0)
12  , out_of_order_requests_()
13  , request_increment_(request_increment)
14  , receiver_running_(false)
15 {
16 }
17 
18 artdaq::RequestBuffer::~RequestBuffer() {}
19 
20 void artdaq::RequestBuffer::push(artdaq::Fragment::sequence_id_t seq, artdaq::Fragment::timestamp_t ts)
21 {
22  std::lock_guard<std::mutex> tlk(request_mutex_);
23  if (requests_.count(seq) && requests_[seq] != ts)
24  {
25  TLOG(TLVL_ERROR) << "Received conflicting request for SeqID "
26  << seq << "!"
27  << " Old ts=" << requests_[seq]
28  << ", new ts=" << ts << ". Keeping OLD!";
29  }
30  else if (!requests_.count(seq))
31  {
32  int delta = seq - highest_seen_request_;
33  TLOG(11) << "Received request for sequence ID " << seq
34  << " and timestamp " << ts << " (delta: " << delta << ")";
35  if (delta <= 0 || out_of_order_requests_.count(seq))
36  {
37  TLOG(11) << "Already serviced this request ( sequence ID " << seq << ")! Ignoring...";
38  }
39  else
40  {
41  requests_[seq] = ts;
42  request_timing_[seq] = std::chrono::steady_clock::now();
43  }
44  }
45  request_cv_.notify_all();
46 }
47 
48 void artdaq::RequestBuffer::reset()
49 {
50  requests_.clear();
51  request_timing_.clear();
52  highest_seen_request_ = 0;
53  last_next_request_ = 0;
54  out_of_order_requests_.clear();
55 }
56 
61 
62 std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> artdaq::RequestBuffer::GetRequests() const
63 {
64  std::lock_guard<std::mutex> lk(request_mutex_);
65  std::map<artdaq::Fragment::sequence_id_t, Fragment::timestamp_t> out;
66  for (auto& in : requests_)
67  {
68  out[in.first] = in.second;
69  }
70  return out;
71 }
72 
73 std::pair<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> artdaq::RequestBuffer::GetNextRequest()
74 {
75  std::lock_guard<std::mutex> lk(request_mutex_);
76 
77  auto it = requests_.begin();
78  while (it != requests_.end() && it->first <= last_next_request_) { ++it; }
79 
80  if (it == requests_.end())
81  {
82  return std::make_pair<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t>(0, 0);
83  }
84 
85  last_next_request_ = it->first;
86  return *it;
87 }
88 
89 void artdaq::RequestBuffer::RemoveRequest(artdaq::Fragment::sequence_id_t reqID)
90 {
91  TLOG(10) << "RemoveRequest: Removing request for id " << reqID;
92  std::lock_guard<std::mutex> lk(request_mutex_);
93  requests_.erase(reqID);
94 
95  if (reqID > highest_seen_request_)
96  {
97  TLOG(10) << "RemoveRequest: out_of_order_requests_.size() == " << out_of_order_requests_.size() << ", reqID=" << reqID << ", expected=" << highest_seen_request_ + request_increment_;
98  if (out_of_order_requests_.size() || reqID != highest_seen_request_ + request_increment_)
99  {
100  out_of_order_requests_.insert(reqID);
101 
102  auto it = out_of_order_requests_.begin();
103  while (it != out_of_order_requests_.end()) // Stop accounting for requests after stop
104  {
105  if (*it == highest_seen_request_ + request_increment_)
106  {
107  highest_seen_request_ = *it;
108  it = out_of_order_requests_.erase(it);
109  }
110  else
111  {
112  break;
113  }
114  }
115  }
116  else // no out-of-order requests and this request is highest seen + request_increment_
117  {
118  highest_seen_request_ = reqID;
119  }
120  TLOG(10) << "RemoveRequest: reqID=" << reqID << " Setting highest_seen_request_ to " << highest_seen_request_;
121  }
122  if (metricMan && request_timing_.count(reqID))
123  {
124  metricMan->sendMetric("Request Response Time", TimeUtils::GetElapsedTime(request_timing_[reqID]), "seconds", 2, MetricMode::Average);
125  }
126  request_timing_.erase(reqID);
127 }
128 
132 
134 {
135  std::lock_guard<std::mutex> lk(request_mutex_);
136  requests_.clear();
137 }
138 
143 
144 std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> artdaq::RequestBuffer::GetAndClearRequests()
145 {
146  std::lock_guard<std::mutex> lk(request_mutex_);
147  std::map<artdaq::Fragment::sequence_id_t, Fragment::timestamp_t> out;
148  for (auto& in : requests_)
149  {
150  out[in.first] = in.second;
151  }
152  if (requests_.size()) { highest_seen_request_ = requests_.rbegin()->first; }
153  out_of_order_requests_.clear();
154  requests_.clear();
155  request_timing_.clear();
156  return out;
157 }
158 
163 
165 {
166  std::lock_guard<std::mutex> tlk(request_mutex_);
167  return requests_.size();
168 }
169 
175 
177 {
178  std::unique_lock<std::mutex> lk(request_mutex_); // Lock needed by wait_for
179  // See if we have to wait at all
180  if (requests_.size() > 0) return true;
181  // If we do have to wait, check requests_.size to make sure we're not being notified spuriously
182  return request_cv_.wait_for(lk, std::chrono::milliseconds(timeout_ms), [this]() { return requests_.size() > 0; });
183 }
184 
190 
191 std::chrono::steady_clock::time_point artdaq::RequestBuffer::GetRequestTime(artdaq::Fragment::sequence_id_t reqID)
192 {
193  std::lock_guard<std::mutex> lk(request_mutex_);
194  return request_timing_.count(reqID) ? request_timing_[reqID] : std::chrono::steady_clock::now();
195 }
void ClearRequests()
Clear all requests from the map
std::map< artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t > GetAndClearRequests()
Get the current requests, then clear the map
std::pair< artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t > GetNextRequest()
Get the &quot;next&quot; request, i.e. the first unsatisfied request that has not already been returned by GetN...
std::map< artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t > GetRequests() const
Get the current requests
std::chrono::steady_clock::time_point GetRequestTime(artdaq::Fragment::sequence_id_t reqID)
Get the time a given request was received
bool WaitForRequests(int timeout_ms)
Wait for a new request message, up to the timeout given
void RemoveRequest(artdaq::Fragment::sequence_id_t reqID)
Remove the request with the given sequence ID from the request map
size_t size()
Get the number of requests currently stored in the RequestReceiver