bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
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 "BESLog.h"
34#include "BESDebug.h"
35#include "BESTimeoutError.h"
36#include "RequestServiceTimer.h"
37
38#if HAVE_UNISTD_H
39#include <unistd.h>
40#endif
41
42using std::string;
43using std::endl;
44using std::ostream;
45
46using namespace std::chrono;
47
48#define MODULE "RST"
49#define prolog string("RequestServiceTimer::").append(__func__).append("() - ")
50
51RequestServiceTimer *RequestServiceTimer::d_instance = nullptr;
52static std::once_flag d_rst_init_once;
53
60{
61 std::call_once(d_rst_init_once,RequestServiceTimer::initialize_instance);
62 return d_instance;
63}
64
65void RequestServiceTimer::initialize_instance() {
66 d_instance = new RequestServiceTimer();
67#ifdef HAVE_ATEXIT
68 atexit(delete_instance);
69#endif
70}
71
72void RequestServiceTimer::delete_instance() {
73 delete d_instance;
74 d_instance = nullptr;
75}
76
85void RequestServiceTimer::start(milliseconds timeout_ms){
86 std::lock_guard<std::recursive_mutex> lock_me(d_rst_lock_mutex);
87
88 if(timeout_ms > milliseconds{0}){
89 timeout_enabled = true;
90 d_bes_timeout = timeout_ms;
91 }
92 else {
93 timeout_enabled = false;
94 d_bes_timeout = milliseconds{0};
95 }
96 start_time = steady_clock::now();
97}
98
103milliseconds RequestServiceTimer::elapsed() const {
104 std::lock_guard<std::recursive_mutex> lock_me(d_rst_lock_mutex);
105 return duration_cast<milliseconds>(steady_clock::now() - start_time);
106}
107
115milliseconds RequestServiceTimer::remaining() const {
116 std::lock_guard<std::recursive_mutex> lock_me(d_rst_lock_mutex);
117 milliseconds remaining{0};
118 BESDEBUG(MODULE, prolog << "init remaining: " << remaining.count() << endl);
119 if (timeout_enabled) {
120 BESDEBUG(MODULE, prolog << "timeout enabled" << endl);
121 remaining = d_bes_timeout - elapsed();
122 }
123 else {
124 BESDEBUG(MODULE, prolog << "timeout disabled" << endl);
125 }
126 return remaining;
127}
128
135 std::lock_guard<std::recursive_mutex> lock_me(d_rst_lock_mutex);
136 auto dt = remaining();
137 BESDEBUG(MODULE, prolog + "remaining: " + std::to_string(dt.count()) + " ms\n");
138 return timeout_enabled && (dt <= milliseconds {0});
139}
140
145 std::lock_guard<std::recursive_mutex> lock_me(d_rst_lock_mutex);
146 timeout_enabled = false;
147}
148
149string RequestServiceTimer::dump(bool pretty) const {
150 std::stringstream ss;
151 if(!pretty){ ss<<"["; }
152 ss << "RequestServiceTimer(" << (void *)this << ") - ";
153 if(pretty){ ss << endl << " "; }
154 ss << "bes_timeout: " << d_bes_timeout.count() << "ms ";
155 if(pretty){ ss << endl << " "; }
156 ss << "start_time: " << duration_cast<seconds>(start_time.time_since_epoch()).count() << "s ";
157 if(pretty){ ss << endl << " "; }
158 ss << "is_timeout_enabled(): " << (is_timeout_enabled() ?"true ":"false ");
159 if(pretty){ ss << endl << " "; }
160 ss << "elapsed(): " << elapsed().count() << "ms ";
161 if(pretty){ ss << endl << " "; }
162 ss << "remaining(): " << remaining().count() << "ms ";
163 if(pretty){ ss << endl << " "; }
164 ss << "is_expired(): " << (is_expired()?"true":"false");
165 if(pretty){ ss << endl; }else{ ss << "]"; }
166 return ss.str();
167}
168
175void RequestServiceTimer::dump( ostream &strm ) const
176{
177 strm << dump() << endl;
178}
179
180
190void RequestServiceTimer::throw_if_timeout_expired(const string &message, const string &file, const int line)
191{
192 bool expired = is_expired();
193
194 if (expired) {
195 auto time_out_seconds = std::to_string(((double)d_bes_timeout.count())/1000.00);
196 auto elapsed_time_seconds = std::to_string(((double)elapsed().count())/1000.00);
197 ERROR_LOG(prolog + "ERROR: Time to transmit timeout expired. "+
198 "Elapsed Time: " + elapsed_time_seconds + " " +
199 "max_time_to_transmit: " + time_out_seconds +
200 "\n");
201
202 std::stringstream errMsg;
203 errMsg << "The request that you submitted timed out. The server was unable to begin transmitting" << endl;
204 errMsg << "a response in the time allowed. Requests processed by this server must begin transmitting" << endl;
205 errMsg << "the response in less than " << time_out_seconds << " seconds." << endl;
206 errMsg << "ElapsedTime: " << elapsed_time_seconds << " seconds" << endl;
207 errMsg << "Some things you can try: Reissue the request but change the amount of data requested." << endl;
208 errMsg << "You may reduce the size of the request by choosing just the variables you need and/or" << endl;
209 errMsg << "by using the DAP index based array sub-setting syntax to additionally limit the amount" << endl;
210 errMsg << "of data requested. You can also try requesting a different encoding for the response." << endl;
211 errMsg << "If you asked for the response to be encoded as a NetCDF-3 or NetCDF-4 file be aware" << endl;
212 errMsg << "that these response encodings are not streamable. In order to build these responses" << endl;
213 errMsg << "the server must write the entire response to a temporary file before it can begin to"<< endl;
214 errMsg << "send the response to the requesting client. Changing to a different encoding, such" << endl;
215 errMsg << "as DAP4 data, may allow the server to successfully respond to your request." << endl;
216 errMsg << "The service component that ran out of time said: " << endl;
217 errMsg << message << endl;
218
219 throw BESTimeoutError(errMsg.str(), file, line);
220 }
221}
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.