NCBI C++ ToolKit
request_control.hpp
Go to the documentation of this file.

Go to the SVN repository for this file.

00001 #ifndef CORELIB___REQUEST_CONTROL__HPP
00002 #define CORELIB___REQUEST_CONTROL__HPP
00003 
00004 /*  $Id: request_control.hpp 57252 2013-02-20 13:16:20Z kornbluh $
00005  * ===========================================================================
00006  *
00007  *                            PUBLIC DOMAIN NOTICE
00008  *               National Center for Biotechnology Information
00009  *
00010  *  This software/database is a "United States Government Work" under the
00011  *  terms of the United States Copyright Act.  It was written as part of
00012  *  the author's official duties as a United States Government employee and
00013  *  thus cannot be copyrighted.  This software/database is freely available
00014  *  to the public for use. The National Library of Medicine and the U.S.
00015  *  Government have not placed any restriction on its use or reproduction.
00016  *
00017  *  Although all reasonable efforts have been taken to ensure the accuracy
00018  *  and reliability of the software and data, the NLM and the U.S.
00019  *  Government do not and cannot warrant the performance or results that
00020  *  may be obtained by using this software or data. The NLM and the U.S.
00021  *  Government disclaim all warranties, express or implied, including
00022  *  warranties of performance, merchantability or fitness for any particular
00023  *  purpose.
00024  *
00025  *  Please cite the author in any work or product based on this material.
00026  *
00027  * ===========================================================================
00028  *
00029  * Authors:  Denis Vakatov, Vladimir Ivanov, Victor Joukov
00030  *
00031  * File Description:
00032  *   Manage request rate to some shared resource
00033  *
00034  */
00035 
00036 #include <corelib/ncbi_limits.hpp>
00037 #include <corelib/ncbitime.hpp>
00038 #include <deque>
00039 
00040 /** @addtogroup Utility
00041  *
00042  * @{
00043  */
00044 
00045 BEGIN_NCBI_SCOPE
00046 
00047 
00048 /////////////////////////////////////////////////////////////////////////////
00049 ///
00050 /// CRequestRateControlException --
00051 ///
00052 /// Define exceptions generated by CRequestThrottler.
00053 ///
00054 /// CRequestThrottlerException inherits its basic functionality from
00055 /// CCoreException and defines additional error codes.
00056 
00057 class NCBI_XNCBI_EXPORT CRequestRateControlException : public CCoreException
00058 {
00059 public:
00060     /// Error types that CRequestRateControl can generate.
00061     enum EErrCode {
00062         eNumRequestsMax,         ///< Maximum number of requests exceeded;
00063         eNumRequestsPerPeriod,   ///< Number of requests per period exceeded;
00064         eMinTimeBetweenRequests  ///< The time between two consecutive requests
00065                                  ///< is too short;
00066     };
00067     /// Translate from the error code value to its string representation.
00068     virtual const char* GetErrCodeString(void) const;
00069 
00070     // Standard exception boilerplate code.
00071     NCBI_EXCEPTION_DEFAULT(CRequestRateControlException, CCoreException);
00072 };
00073 
00074 
00075 
00076 /////////////////////////////////////////////////////////////////////////////
00077 ///
00078 /// CRequestRateControl --
00079 ///
00080 /// Manage request rate to some shared resource, for example.
00081 
00082 class NCBI_XNCBI_EXPORT CRequestRateControl
00083 {
00084 public:
00085     /// Special value for maximum number of allowed requests per period.
00086     /// Disable any kind of request throttling.
00087     /// 
00088     /// @sa 
00089     ///   Reset
00090     static const unsigned int kNoLimit = kMax_UInt;
00091 
00092     /// What to do if exceeded the rate limits.
00093     enum EThrottleAction {
00094         eSleep,      ///< Sleep till the rate requirements are met & return
00095         eErrCode,    ///< Return immediately with err code == FALSE
00096         eException,  ///< Throw an exception
00097         eDefault     ///< in c-tor -- eSleep;  in Approve() -- value set in c-tor
00098     };
00099 
00100     /// Throttle mode.
00101     ///
00102     /// In case if number of requests and time period are specified,
00103     /// it is possible to select between two modes for request throttler.
00104     /// First mode is eContinuous. It use internal time line to check number
00105     /// of requests in the past period of time, using current time as ending
00106     /// point for that period. Starting point determinates with ordinary
00107     /// subtraction of "per_period" time, specified in object's constructor,
00108     /// from current time. So the controlled time frame moves continuously
00109     /// in time.
00110     /// Contrary to continuos mode, eDiscrete mode have fixed starting point
00111     /// for period of time, where throttler checks number of incoming
00112     /// requests. First time period starts when CRequestRateControl object
00113     /// creates. Each next period starts with interval of "per_period",
00114     /// or from first approved request in case of long period of inactivity.
00115     /// When each new period starts, the throttler drops all restrictions,
00116     /// and starts to count number of allowed requests per period from zero.
00117     /// Usually eDiscrete mode is a little bit faster and less memory consuming.
00118     enum EThrottleMode {
00119         eContinuous, ///< Uses float time frame to check number of requests
00120         eDiscrete    ///< Uses fixed time frame to check number of requests
00121     };
00122 
00123     /// Constructor.
00124     ///
00125     /// Construct class object. Run Reset() method.
00126     ///
00127     /// @sa 
00128     ///   Reset, EThrottleAction, EThrottleMode
00129     CRequestRateControl
00130               (unsigned int     num_requests_allowed,
00131                CTimeSpan        per_period                = CTimeSpan(1,0),
00132                CTimeSpan        min_time_between_requests = CTimeSpan(0,0),
00133                EThrottleAction  throttle_action           = eDefault,
00134                EThrottleMode    throttle_mode             = eContinuous);
00135 
00136     /// Set new restriction for throttling mechanism.
00137     ///
00138     /// Zero values for time spans 'per_period' or 'min_time_between_requests'
00139     /// means no rate restriction for that throttling mechanism, respectively.
00140     ///
00141     /// @param num_requests_allowed
00142     ///   Maximum number of allowed requests per 'per_period'.
00143     ///   Can be kNoLimit for unlimited number of requests (throttler is disabled,
00144     ///   Approve() always returns TRUE).
00145     /// @param per_period
00146     ///   Time span in which only 'num_requests_allowed' requests can be
00147     ///   approved.
00148     /// @param min_time_between_requests
00149     ///   Minimum time between two succesful consecutive requests.
00150     /// @param throttle_action
00151     ///   Set throttle action by default. The eDefault means eSleep here.
00152     /// @param throttle_mode
00153     ///   Set throttle action by default. The eDefault means eSleep here.
00154     /// For backward compatibility, use eContinuous mode by default.
00155     /// @sa
00156     ///   Approve, ApproveTime
00157     void Reset(unsigned int     num_requests_allowed,
00158                CTimeSpan        per_period                = CTimeSpan(1,0),
00159                CTimeSpan        min_time_between_requests = CTimeSpan(0,0),
00160                EThrottleAction  throttle_action           = eDefault,
00161                EThrottleMode    throttle_mode             = eContinuous);
00162 
00163     /// Approve a request.
00164     ///
00165     /// @param action
00166     ///   Throttle action used by this function call. If passed argument
00167     ///   equal to eDefault that use throttle action was set in 
00168     ///   the constructor.
00169     /// @return
00170     ///   Return TRUE if everything meet to established requirements.
00171     ///   Return FALSE if some requirements are not passed, or
00172     ///   throw exception if throttle action was set to eException.
00173     /// @sa
00174     ///   Reset, ApproveTime
00175     bool Approve(EThrottleAction action = eDefault);
00176 
00177     /// Get a time span in which request can be approved.
00178     ///
00179     /// You should call this method until it returns zero time span, otherwise
00180     /// you should sleep (using Sleep() method) for indicated time.
00181     ///
00182     /// @return
00183     ///   Returns time to wait until actual request, zero if can proceed
00184     ///   immediately.
00185     ///   If you use this method with absolute limitation (no time period and
00186     ///   no minimum between requests) and the limitation is exhausted it will
00187     ///   throw an exception.
00188     /// @sa
00189     ///   Reset, Approve
00190     CTimeSpan ApproveTime(void);
00191 
00192     /// Sleep for CTimeSpan.
00193     ///
00194     /// @param sleep_time
00195     ///   For how long to sleep. If it's impossible to sleep to that long in
00196     ///   millisecond range, rounds up sleep time to the whole seconds.
00197     static void Sleep(CTimeSpan sleep_time);
00198 
00199     /// Lock/unlock functions for use by generic RAII guard CGuard.
00200     /// See 'corelib/guard.hpp' for details.
00201     
00202     void Lock()   { Approve(eSleep); }
00203     void Unlock() { /* do nothing */ }
00204 
00205     /// Check if throttling is enabled.
00206     bool IsEnabled(void) const { return m_NumRequestsAllowed != kNoLimit; }
00207 
00208 private:
00209     typedef double TTime;
00210 
00211     ///
00212     bool x_Approve(EThrottleAction action, CTimeSpan *sleeptime);
00213 
00214     /// Remove from the list of approved requests all expared items.
00215     void x_CleanTimeLine(TTime now);
00216 
00217 private:
00218     // Saved parameters
00219     EThrottleMode    m_Mode;
00220     unsigned int     m_NumRequestsAllowed;
00221     TTime            m_PerPeriod;
00222     TTime            m_MinTimeBetweenRequests;
00223     EThrottleAction  m_ThrottleAction;
00224 
00225     CStopWatch       m_StopWatch;      ///< Stopwatch to measure elapsed time
00226     typedef deque<TTime> TTimeLine;
00227     TTimeLine        m_TimeLine;       ///< Vector of times of approvals
00228     TTime            m_LastApproved;   ///< Last approve time
00229     unsigned int     m_NumRequests;    ///< Num requests per period
00230 };
00231 
00232 
00233 //////////////////////////////////////////////////////////////////////////////
00234 //
00235 // Inline
00236 //
00237 
00238 inline
00239 bool CRequestRateControl::Approve(EThrottleAction action)
00240 {
00241     return x_Approve(action, 0);
00242 }
00243 
00244 inline
00245 CTimeSpan CRequestRateControl::ApproveTime()
00246 {
00247     CTimeSpan sleeptime;
00248     bool res = x_Approve(eSleep, &sleeptime);
00249     if ( !res ) {
00250         return sleeptime;
00251     }
00252     // Approve request
00253     return CTimeSpan(0, 0);
00254 }
00255 
00256 
00257 END_NCBI_SCOPE
00258 
00259 /* @} */
00260 
00261 #endif  /* CORELIB___REQUEST_CONTROL__HPP */
Modified on Fri Jul 11 17:21:23 2014 by modify_doxy.py rev. 426318