artdaq  v3_12_02
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 
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(TLVL_DEBUG + 36) << "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(TLVL_DEBUG + 36) << "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 
49 {
50  std::lock_guard<std::mutex> lk(request_mutex_);
51  requests_.clear();
52  request_timing_.clear();
53  highest_seen_request_ = 0;
54  last_next_request_ = 0;
55  out_of_order_requests_.clear();
56 }
57 
62 
63 std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> artdaq::RequestBuffer::GetRequests() const
64 {
65  std::lock_guard<std::mutex> lk(request_mutex_);
66  std::map<artdaq::Fragment::sequence_id_t, Fragment::timestamp_t> out;
67  for (auto& in : requests_)
68  {
69  out[in.first] = in.second;
70  }
71  return out;
72 }
73 
74 std::pair<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> artdaq::RequestBuffer::GetNextRequest()
75 {
76  std::lock_guard<std::mutex> lk(request_mutex_);
77 
78  auto it = requests_.begin();
79  while (it != requests_.end() && it->first <= last_next_request_) { ++it; }
80 
81  if (it == requests_.end())
82  {
83  return std::make_pair<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t>(0, 0);
84  }
85 
86  last_next_request_ = it->first;
87  return *it;
88 }
89 
90 void artdaq::RequestBuffer::RemoveRequest(artdaq::Fragment::sequence_id_t reqID)
91 {
92  TLOG(TLVL_DEBUG + 35) << "RemoveRequest: Removing request for id " << reqID;
93  std::lock_guard<std::mutex> lk(request_mutex_);
94  requests_.erase(reqID);
95 
96  if (reqID > highest_seen_request_)
97  {
98  TLOG(TLVL_DEBUG + 35) << "RemoveRequest: out_of_order_requests_.size() == " << out_of_order_requests_.size() << ", reqID=" << reqID << ", expected=" << highest_seen_request_ + request_increment_;
99  if (out_of_order_requests_.size() || reqID != highest_seen_request_ + request_increment_)
100  {
101  out_of_order_requests_.insert(reqID);
102 
103  auto it = out_of_order_requests_.begin();
104  while (it != out_of_order_requests_.end()) // Stop accounting for requests after stop
105  {
106  if (*it == highest_seen_request_ + request_increment_)
107  {
108  highest_seen_request_ = *it;
109  it = out_of_order_requests_.erase(it);
110  }
111  else
112  {
113  break;
114  }
115  }
116  }
117  else // no out-of-order requests and this request is highest seen + request_increment_
118  {
119  highest_seen_request_ = reqID;
120  }
121  TLOG(TLVL_DEBUG + 35) << "RemoveRequest: reqID=" << reqID << " Setting highest_seen_request_ to " << highest_seen_request_;
122  }
123  if (metricMan && request_timing_.count(reqID))
124  {
125  metricMan->sendMetric("Request Response Time", TimeUtils::GetElapsedTime(request_timing_[reqID]), "seconds", 2, MetricMode::Average);
126  }
127  request_timing_.erase(reqID);
128 }
129 
133 
135 {
136  std::lock_guard<std::mutex> lk(request_mutex_);
137  requests_.clear();
138 }
139 
144 
145 std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> artdaq::RequestBuffer::GetAndClearRequests()
146 {
147  std::lock_guard<std::mutex> lk(request_mutex_);
148  std::map<artdaq::Fragment::sequence_id_t, Fragment::timestamp_t> out;
149  for (auto& in : requests_)
150  {
151  out[in.first] = in.second;
152  }
153  if (requests_.size()) { highest_seen_request_ = requests_.rbegin()->first; }
154  out_of_order_requests_.clear();
155  requests_.clear();
156  request_timing_.clear();
157  return out;
158 }
159 
164 
166 {
167  std::lock_guard<std::mutex> tlk(request_mutex_);
168  return requests_.size();
169 }
170 
176 
178 {
179  std::unique_lock<std::mutex> lk(request_mutex_); // Lock needed by wait_for
180  // See if we have to wait at all
181  if (requests_.size() > 0) return true;
182  // If we do have to wait, check requests_.size to make sure we're not being notified spuriously
183  return request_cv_.wait_for(lk, std::chrono::milliseconds(timeout_ms), [this]() { return requests_.size() > 0; });
184 }
185 
191 
192 std::chrono::steady_clock::time_point artdaq::RequestBuffer::GetRequestTime(artdaq::Fragment::sequence_id_t reqID)
193 {
194  std::lock_guard<std::mutex> lk(request_mutex_);
195  return request_timing_.count(reqID) ? request_timing_[reqID] : std::chrono::steady_clock::now();
196 }
void push(artdaq::Fragment::sequence_id_t seq, artdaq::Fragment::timestamp_t ts)
Add a Request to the buffer.
virtual ~RequestBuffer()
RequestBuffer Destructor.
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
void reset()
Reset RequestBuffer, discarding all requests and tracking information.
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
RequestBuffer(Fragment::sequence_id_t request_increment=1)
RequestBuffer Constructor.
Definition: RequestBuffer.cc:6
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