netwerk/base/src/EventTokenBucket.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #ifndef NetEventTokenBucket_h__
     8 #define NetEventTokenBucket_h__
    10 #include "nsCOMPtr.h"
    11 #include "nsDeque.h"
    12 #include "nsITimer.h"
    14 #include "mozilla/TimeStamp.h"
    16 class nsICancelable;
    18 namespace mozilla {
    19 namespace net {
    21 /* A token bucket is used to govern the maximum rate a series of events
    22    can be executed at. For instance if your event was "eat a piece of cake"
    23    then a token bucket configured to allow "1 piece per day" would spread
    24    the eating of a 8 piece cake over 8 days even if you tried to eat the
    25    whole thing up front. In a practical sense it 'costs' 1 token to execute
    26    an event and tokens are 'earned' at a particular rate as time goes by.
    28    The token bucket can be perfectly smooth or allow a configurable amount of
    29    burstiness. A bursty token bucket allows you to save up unused credits, while
    30    a perfectly smooth one would not. A smooth "1 per day" cake token bucket
    31    would require 9 days to eat that cake if you skipped a slice on day 4
    32    (use the token or lose it), while a token bucket configured with a burst
    33    of 2 would just let you eat 2 slices on day 5 (the credits for day 4 and day
    34    5) and finish the cake in the usual 8 days.
    36    EventTokenBucket(hz=20, burst=5) creates a token bucket with the following properties:
    38   + events from an infinite stream will be admitted 20 times per second (i.e.
    39     hz=20 means 1 event per 50 ms). Timers will be used to space things evenly down to
    40     5ms gaps (i.e. up to 200hz). Token buckets with rates greater than 200hz will admit
    41     multiple events with 5ms gaps between them. 10000hz is the maximum rate and 1hz is
    42     the minimum rate.
    44   + The burst size controls the limit of 'credits' that a token bucket can accumulate
    45     when idle. For our (20,5) example each event requires 50ms of credit (again, 20hz = 50ms
    46     per event). a burst size of 5 means that the token bucket can accumulate a
    47     maximum of 250ms (5 * 50ms) for this bucket. If no events have been admitted for the 
    48     last full second the bucket can still only accumulate 250ms of credit - but that credit
    49     means that 5 events can be admitted without delay. A burst size of 1 is the minimum.
    50     The EventTokenBucket is created with maximum credits already applied, but they
    51     can be cleared with the ClearCredits() method. The maximum burst size is
    52     15 minutes worth of events.
    54   + An event is submitted to the token bucket asynchronously through SubmitEvent().
    55     The OnTokenBucketAdmitted() method of the submitted event is used as a callback
    56     when the event is ready to run. A cancelable event is returned to the SubmitEvent() caller
    57     for use in the case they do not wish to wait for the callback.
    58 */
    60 class EventTokenBucket;
    62 class ATokenBucketEvent 
    63 {
    64 public:
    65   virtual void OnTokenBucketAdmitted() = 0;
    66 };
    68 class TokenBucketCancelable;
    70 class EventTokenBucket : public nsITimerCallback
    71 {
    72 public:
    73   NS_DECL_THREADSAFE_ISUPPORTS
    74   NS_DECL_NSITIMERCALLBACK
    76   // This should be constructed on the main thread
    77   EventTokenBucket(uint32_t eventsPerSecond, uint32_t burstSize);
    78   virtual ~EventTokenBucket();
    80   // These public methods are all meant to be called from the socket thread
    81   void ClearCredits();
    82   uint32_t BurstEventsAvailable();
    83   uint32_t QueuedEvents();
    85   // a paused token bucket will not process any events, but it will accumulate
    86   // credits. ClearCredits can be used before unpausing if desired.
    87   void Pause();
    88   void UnPause();
    89   void Stop() { mStopped = true; }
    91   // The returned cancelable event can only be canceled from the socket thread
    92   nsresult SubmitEvent(ATokenBucketEvent *event, nsICancelable **cancelable);
    94 private:
    95   friend class RunNotifyEvent;
    96   friend class SetTimerEvent;
    98   bool TryImmediateDispatch(TokenBucketCancelable *event);
    99   void SetRate(uint32_t eventsPerSecond, uint32_t burstSize);
   101   void DispatchEvents();
   102   void UpdateTimer();
   103   void UpdateCredits();
   105   const static uint64_t kUsecPerSec =  1000000;
   106   const static uint64_t kUsecPerMsec = 1000;
   107   const static uint64_t kMaxHz = 10000;
   109   uint64_t mUnitCost;   // usec of credit needed for 1 event (from eventsPerSecond)
   110   uint64_t mMaxCredit; // usec mCredit limit (from busrtSize)
   111   uint64_t mCredit; // usec of accumulated credit.
   113   bool     mPaused;
   114   bool     mStopped;
   115   nsDeque  mEvents;
   116   bool     mTimerArmed;
   117   TimeStamp mLastUpdate;
   119   // The timer is created on the main thread, but is armed and executes Notify()
   120   // callbacks on the socket thread in order to maintain low latency of event
   121   // delivery.
   122   nsCOMPtr<nsITimer> mTimer;
   124 #ifdef XP_WIN
   125   // Windows timers are 15ms granularity by default. When we have active events
   126   // that need to be dispatched at 50ms  or less granularity we change the OS
   127   // granularity to 1ms. 90 seconds after that need has elapsed we will change it
   128   // back
   129   const static uint64_t kCostFineGrainThreshold =  50 * kUsecPerMsec;
   131   void FineGrainTimers(); // get 1ms granularity
   132   void NormalTimers(); // reset to default granularity
   133   void WantNormalTimers(); // reset after 90 seconds if not needed in interim
   134   void FineGrainResetTimerNotify(); // delayed callback to reset
   136   TimeStamp mLastFineGrainTimerUse;
   137   bool mFineGrainTimerInUse;
   138   bool mFineGrainResetTimerArmed;
   139   nsCOMPtr<nsITimer> mFineGrainResetTimer;
   140 #endif
   141 };
   143 } // ::mozilla::net
   144 } // ::mozilla
   146 #endif

mercurial