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
41using std::string;
42using std::endl;
43using std::ostream;
44
45using namespace std::chrono;
46
47#define MODULE "bes"
48#define prolog string("RequestServiceTimer::").append(__func__).append("() - ")
49
50RequestServiceTimer *RequestServiceTimer::d_instance = nullptr;
51static 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
64void RequestServiceTimer::initialize_instance() {
65 d_instance = new RequestServiceTimer();
66#ifdef HAVE_ATEXIT
67 atexit(delete_instance);
68#endif
69}
70
71void RequestServiceTimer::delete_instance() {
72 delete d_instance;
73 d_instance = nullptr;
74}
75
84void 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
102milliseconds 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
114milliseconds 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
146string 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
172void RequestServiceTimer::dump( ostream &strm ) const
173{
174 strm << dump() << endl;
175}
176
177
187void 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.