LCOV - code coverage report
Current view: top level - netwerk/base - EventTokenBucket.h (source / functions) Hit Total Coverage
Test: output.info Lines: 1 1 100.0 %
Date: 2017-07-14 16:53:18 Functions: 1 1 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13