|
NCBI C++ ToolKit
|
00001 /* $Id: request_control.cpp 45743 2010-05-12 17:16:18Z ivanov $ 00002 * =========================================================================== 00003 * 00004 * PUBLIC DOMAIN NOTICE 00005 * National Center for Biotechnology Information 00006 * 00007 * This software/database is a "United States Government Work" under the 00008 * terms of the United States Copyright Act. It was written as part of 00009 * the author's official duties as a United States Government employee and 00010 * thus cannot be copyrighted. This software/database is freely available 00011 * to the public for use. The National Library of Medicine and the U.S. 00012 * Government have not placed any restriction on its use or reproduction. 00013 * 00014 * Although all reasonable efforts have been taken to ensure the accuracy 00015 * and reliability of the software and data, the NLM and the U.S. 00016 * Government do not and cannot warrant the performance or results that 00017 * may be obtained by using this software or data. The NLM and the U.S. 00018 * Government disclaim all warranties, express or implied, including 00019 * warranties of performance, merchantability or fitness for any particular 00020 * purpose. 00021 * 00022 * Please cite the author in any work or product based on this material. 00023 * 00024 * =========================================================================== 00025 * 00026 * Authors: Denis Vakatov, Vladimir Ivanov, Victor Joukov 00027 * 00028 * File Description: 00029 * Test for request test control classes. 00030 * 00031 */ 00032 00033 #include <ncbi_pch.hpp> 00034 #include <corelib/ncbi_limits.h> 00035 #include <corelib/ncbi_system.hpp> 00036 #include <corelib/request_control.hpp> 00037 00038 00039 /** @addtogroup Utility 00040 * 00041 * @{ 00042 */ 00043 00044 BEGIN_NCBI_SCOPE 00045 00046 00047 CRequestRateControl::CRequestRateControl( 00048 unsigned int num_requests_allowed, 00049 CTimeSpan per_period, 00050 CTimeSpan min_time_between_requests, 00051 EThrottleAction throttle_action, 00052 EThrottleMode throttle_mode) 00053 { 00054 Reset(num_requests_allowed, per_period, min_time_between_requests, 00055 throttle_action, throttle_mode); 00056 } 00057 00058 00059 void CRequestRateControl::Reset( 00060 unsigned int num_requests_allowed, 00061 CTimeSpan per_period, 00062 CTimeSpan min_time_between_requests, 00063 EThrottleAction throttle_action, 00064 EThrottleMode throttle_mode) 00065 { 00066 // Save parameters 00067 m_NumRequestsAllowed = num_requests_allowed; 00068 m_PerPeriod = per_period.GetAsDouble(); 00069 m_MinTimeBetweenRequests = min_time_between_requests.GetAsDouble(); 00070 if ( throttle_action == eDefault ) { 00071 m_ThrottleAction = eSleep; 00072 } else { 00073 m_ThrottleAction = throttle_action; 00074 } 00075 m_Mode = throttle_mode; 00076 00077 // Reset internal state 00078 m_NumRequests = 0; 00079 m_LastApproved = -1; 00080 m_TimeLine.clear(); 00081 m_StopWatch.Restart(); 00082 } 00083 00084 00085 bool CRequestRateControl::x_Approve(EThrottleAction action, CTimeSpan *sleeptime) 00086 { 00087 if ( sleeptime ) { 00088 *sleeptime = CTimeSpan(0,0); 00089 } 00090 // Is throttler disabled, that always approve request 00091 if ( m_NumRequests == kNoLimit ) { 00092 return true; 00093 } 00094 // Redefine default action 00095 if ( action == eDefault ) { 00096 action = m_ThrottleAction; 00097 } 00098 00099 bool empty_period = (m_PerPeriod <= 0); 00100 bool empty_between = (m_MinTimeBetweenRequests <= 0); 00101 00102 // Check maximum number of requests at all (if times not specified) 00103 if ( !m_NumRequestsAllowed || (empty_period && empty_between) ) { 00104 if ( m_NumRequests >= m_NumRequestsAllowed ) { 00105 switch(action) { 00106 case eErrCode: 00107 return false; 00108 case eSleep: 00109 // cannot sleep in this case, return FALSE 00110 if ( !sleeptime ) { 00111 return false; 00112 } 00113 // or throw exception, see ApproveTime() 00114 case eException: 00115 NCBI_THROW( 00116 CRequestRateControlException, eNumRequestsMax, 00117 "CRequestRateControl::Approve(): " 00118 "Maximum number of requests exceeded" 00119 ); 00120 case eDefault: ; 00121 } 00122 } 00123 } 00124 00125 // Special case for eDiscrete mode and empty time between requests. 00126 // We don't need to get time marks in this case, just increase number 00127 // of requests and approve it. 00128 if ( m_Mode == eDiscrete && !empty_period && empty_between && 00129 m_NumRequests < m_NumRequestsAllowed 00130 ) { 00131 if (m_TimeLine.size() == 0) { 00132 // Save only first request time, used in x_CleanTimeLine() 00133 TTime now = m_StopWatch.Elapsed(); 00134 m_TimeLine.push_back(now); 00135 // We will not update m_LastApproved except first time, 00136 // we don't needed this information in this case. 00137 m_LastApproved = now; 00138 } 00139 m_NumRequests++; 00140 // Approve request 00141 return true; 00142 } 00143 00144 // Get current time 00145 TTime now = m_StopWatch.Elapsed(); 00146 TTime x_sleeptime = 0; 00147 00148 // Check number of requests per period 00149 if ( !empty_period ) { 00150 x_CleanTimeLine(now); 00151 if ( m_Mode == eContinuous ) { 00152 m_NumRequests = (unsigned int)m_TimeLine.size(); 00153 } 00154 if ( m_NumRequests >= m_NumRequestsAllowed ) { 00155 switch(action) { 00156 case eSleep: 00157 // Get sleep time 00158 _ASSERT(m_TimeLine.size() > 0); 00159 x_sleeptime = m_TimeLine.front() + m_PerPeriod - now; 00160 break; 00161 case eErrCode: 00162 return false; 00163 case eException: 00164 NCBI_THROW( 00165 CRequestRateControlException, 00166 eNumRequestsPerPeriod, 00167 "CRequestRateControl::Approve(): " 00168 "Maximum number of requests per period exceeded" 00169 ); 00170 case eDefault: ; 00171 } 00172 } 00173 } 00174 // Check time between two consecutive requests 00175 if ( !empty_between && (m_LastApproved >= 0) ) { 00176 if ( now - m_LastApproved < m_MinTimeBetweenRequests ) { 00177 switch(action) { 00178 case eSleep: 00179 // Get sleep time 00180 {{ 00181 TTime st = m_LastApproved + m_MinTimeBetweenRequests - now; 00182 // Get max of two sleep times 00183 if ( st > x_sleeptime ) { 00184 x_sleeptime = st; 00185 } 00186 }} 00187 break; 00188 case eErrCode: 00189 return false; 00190 case eException: 00191 NCBI_THROW( 00192 CRequestRateControlException, 00193 eMinTimeBetweenRequests, 00194 "CRequestRateControl::Approve(): The time " 00195 "between two consecutive requests is too short" 00196 ); 00197 case eDefault: ; 00198 } 00199 } 00200 } 00201 00202 // eSleep case 00203 00204 if ( x_sleeptime > 0 ) { 00205 if ( sleeptime ) { 00206 // ApproveTime() -- request is not approved, 00207 // return sleeping time. 00208 if ( sleeptime ) { 00209 *sleeptime = CTimeSpan(x_sleeptime); 00210 } 00211 return false; 00212 } else { 00213 // Approve() -- sleep before approve 00214 Sleep(CTimeSpan(x_sleeptime)); 00215 now = m_StopWatch.Elapsed(); 00216 } 00217 } 00218 // Update stored information 00219 if ( !empty_period ) { 00220 m_TimeLine.push_back(now); 00221 } 00222 m_LastApproved = now; 00223 m_NumRequests++; 00224 // Approve request 00225 return true; 00226 } 00227 00228 00229 void CRequestRateControl::Sleep(CTimeSpan sleep_time) 00230 { 00231 if ( sleep_time <= CTimeSpan(0, 0) ) { 00232 return; 00233 } 00234 long sec = sleep_time.GetCompleteSeconds(); 00235 // We cannot sleep that much milliseconds, round it to seconds 00236 if (sec > long(kMax_ULong / kMicroSecondsPerSecond)) { 00237 SleepSec(sec); 00238 } else { 00239 unsigned long ms; 00240 ms = sec * kMicroSecondsPerSecond + 00241 sleep_time.GetNanoSecondsAfterSecond() / 1000; 00242 if (sleep_time.GetNanoSecondsAfterSecond() % 1000) ms++; 00243 SleepMicroSec(ms); 00244 } 00245 } 00246 00247 00248 void CRequestRateControl::x_CleanTimeLine(TTime now) 00249 { 00250 switch (m_Mode) { 00251 00252 case eContinuous: { 00253 // Find first non-expired item 00254 TTimeLine::iterator current; 00255 for ( current = m_TimeLine.begin(); current != m_TimeLine.end(); 00256 ++current) { 00257 if ( now - *current < m_PerPeriod) { 00258 break; 00259 } 00260 } 00261 // Erase all expired items 00262 m_TimeLine.erase(m_TimeLine.begin(), current); 00263 break; 00264 } 00265 case eDiscrete: { 00266 if (m_TimeLine.size() > 0) { 00267 if (now - m_TimeLine.front() > m_PerPeriod) { 00268 // Period ends, remove all restrictions 00269 m_LastApproved = -1; 00270 m_TimeLine.clear(); 00271 m_NumRequests = 0; 00272 } 00273 } 00274 break; 00275 } 00276 } // switch 00277 } 00278 00279 00280 const char* CRequestRateControlException::GetErrCodeString(void) const 00281 { 00282 switch (GetErrCode()) { 00283 case eNumRequestsMax: return "eNumRequestsMax"; 00284 case eNumRequestsPerPeriod: return "eNumRequestsPerPeriod"; 00285 case eMinTimeBetweenRequests: return "eMinTimeBetweenRequests"; 00286 default: return CException::GetErrCodeString(); 00287 } 00288 } 00289 00290 00291 /* @} */ 00292 00293 END_NCBI_SCOPE
1.7.5.1
Modified on Wed May 23 12:56:56 2012 by modify_doxy.py rev. 337098