bes  Updated for version 3.20.13
RequestServiceTimer.cc
1 // RequestServiceTimer.cc
2 
3 // This file is part of bes, A C++ back-end server implementation framework
4 // for the OPeNDAP Data Access Protocol.
5 
6 // Copyright (c) 2022 OPeNDAP, Inc
7 // Authors:
8 // ndp Nathan Potter <ndp@opendap.org>
9 // dan Dan Holloway <dholloway@opendap.org>
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 //
25 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
26 #include "config.h"
27 
28 #include <string>
29 #include <iostream>
30 #include <mutex>
31 #include <sstream>
32 
33 #include "BESDebug.h"
34 #include "BESTimeoutError.h"
35 #include "RequestServiceTimer.h"
36 
37 #if HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40 
41 using std::string;
42 using std::endl;
43 using std::ostream;
44 
45 using namespace std::chrono;
46 
47 #define MODULE "bes"
48 #define prolog string("RequestServiceTimer::").append(__func__).append("() - ")
49 
50 RequestServiceTimer *RequestServiceTimer::d_instance = nullptr;
51 static std::once_flag d_rst_init_once;
52 
59 {
60  std::call_once(d_rst_init_once,RequestServiceTimer::initialize_instance);
61  return d_instance;
62 }
63 
64 void RequestServiceTimer::initialize_instance() {
65  d_instance = new RequestServiceTimer();
66 #ifdef HAVE_ATEXIT
67  atexit(delete_instance);
68 #endif
69 }
70 
71 void RequestServiceTimer::delete_instance() {
72  delete d_instance;
73  d_instance = nullptr;
74 }
75 
84 void RequestServiceTimer::start(milliseconds timeout_ms){
85  std::lock_guard<std::recursive_mutex> lock_me(d_rst_lock_mutex);
86 
87  if(timeout_ms > milliseconds{0}){
88  timeout_enabled = true;
89  d_bes_timeout = timeout_ms;
90  }
91  else {
92  timeout_enabled = false;
93  d_bes_timeout = milliseconds{0};
94  }
95  start_time = steady_clock::now();
96 }
97 
102 milliseconds RequestServiceTimer::elapsed() const {
103  std::lock_guard<std::recursive_mutex> lock_me(d_rst_lock_mutex);
104  return duration_cast<milliseconds>(steady_clock::now() - start_time);
105 }
106 
114 milliseconds RequestServiceTimer::remaining() const {
115  std::lock_guard<std::recursive_mutex> lock_me(d_rst_lock_mutex);
116  milliseconds remaining{0};
117  BESDEBUG(MODULE, prolog << "init remaining: " << remaining.count() << endl);
118  if (timeout_enabled) {
119  BESDEBUG(MODULE, prolog << "timeout enabled" << endl);
120  remaining = d_bes_timeout - elapsed();
121  }
122  else {
123  BESDEBUG(MODULE, prolog << "timeout disabled" << endl);
124  }
125  return remaining;
126 }
127 
134  std::lock_guard<std::recursive_mutex> lock_me(d_rst_lock_mutex);
135  return timeout_enabled && (remaining() <= milliseconds {0});
136 }
137 
142  std::lock_guard<std::recursive_mutex> lock_me(d_rst_lock_mutex);
143  timeout_enabled = false;
144 }
145 
146 string RequestServiceTimer::dump(bool pretty) const {
147  std::stringstream ss;
148  if(!pretty){ ss<<"["; }
149  ss << "RequestServiceTimer(" << (void *)this << ") - ";
150  if(pretty){ ss << endl << " "; }
151  ss << "bes_timeout: " << d_bes_timeout.count() << "ms ";
152  if(pretty){ ss << endl << " "; }
153  ss << "start_time: " << duration_cast<seconds>(start_time.time_since_epoch()).count() << "s ";
154  if(pretty){ ss << endl << " "; }
155  ss << "is_timeout_enabled(): " << (is_timeout_enabled() ?"true ":"false ");
156  if(pretty){ ss << endl << " "; }
157  ss << "elapsed(): " << elapsed().count() << "ms ";
158  if(pretty){ ss << endl << " "; }
159  ss << "remaining(): " << remaining().count() << "ms ";
160  if(pretty){ ss << endl << " "; }
161  ss << "is_expired(): " << (is_expired()?"true":"false");
162  if(pretty){ ss << endl; }else{ ss << "]"; }
163  return ss.str();
164 }
165 
172 void RequestServiceTimer::dump( ostream &strm ) const
173 {
174  strm << dump() << endl;
175 }
176 
177 
187 void RequestServiceTimer::throw_if_timeout_expired(const string &message, const string &file, const int line)
188 {
189  if (is_expired()) {
190  double time_out_seconds = d_bes_timeout.count()/1000.00;
191  std::stringstream errMsg;
192  errMsg << "The request that you submitted timed out. The server was unable to begin transmitting a response in ";
193  errMsg << "the time allowed. Requests processed by this server must begin transmitting a response in less ";
194  errMsg << "than " << time_out_seconds << " seconds. ";
195 
196  errMsg << "Some things you can try: Reissue the request but change the amount of data requested. ";
197  errMsg << "You may reduce the size of the request by choosing just the variables you need and/or by ";
198  errMsg << "using the DAP index based array sub-setting syntax to additionally limit the amount of data requested. ";
199  errMsg << "You can also try requesting a different encoding for the response. If you asked for the response ";
200  errMsg << "to be encoded as a NetCDF-3 or NetCDF-4 file be aware that these response encodings are not " <<
201  "streamable. In order ";
202  errMsg << "to build these responses the server must write the entire response to a temporary file before it can ";
203  errMsg << "begin to send the response to the requesting client. Changing to a different encoding, such as DAP4 ";
204  errMsg << "data, may allow the server to successfully respond to your request. ";
205 
206  errMsg << "The service component that ran out of time said: " << message;
207 
208  throw BESTimeoutError(errMsg.str(), file, line);
209  }
210 }
error thrown if there is a user syntax error in the request or any other user error
The master request service timer for this server; a singleton.
std::chrono::milliseconds remaining() const
If the time_out is enabled returns the time remaining. If the time_out is disabled returns 0.
static RequestServiceTimer * TheTimer()
Return a pointer to a singleton timer instance. If an instance does not exist it will create and init...
std::chrono::milliseconds elapsed() const
Return the time duration in milliseconds since the timer was started.
void throw_if_timeout_expired(const std::string &message, const std::string &file, const int line)
Checks the RequestServiceTimer to determine if the time spent servicing the request at this point has...
bool is_expired() const
if the time_out is disabled return false.
void start(std::chrono::milliseconds timeout_ms)
Set/Reset the timer start_time to now().
void disable_timeout()
Set the time_out is disabled.