00001
00031 #ifndef LL_LLKEY_THROTTLE_H
00032 #define LL_LLKEY_THROTTLE_H
00033
00034
00035
00036
00037
00038
00039
00040 #include "linden_common.h"
00041
00042 #include "llframetimer.h"
00043 #include <map>
00044
00045
00046
00047 template <class T> class LLKeyThrottle;
00048
00049
00050
00051 template <class T>
00052 class LLKeyThrottleImpl
00053 {
00054 friend class LLKeyThrottle<T>;
00055 protected:
00056 struct Entry {
00057 U32 count;
00058 BOOL blocked;
00059
00060 Entry() : count(0), blocked(FALSE) { }
00061 };
00062
00063 typedef std::map<T, Entry> EntryMap;
00064
00065 EntryMap * prevMap;
00066 EntryMap * currMap;
00067
00068 U32 countLimit;
00069
00070
00071 U64 interval_usec;
00072
00073 U64 start_usec;
00074
00075
00076
00077 LLKeyThrottleImpl() : prevMap(0), currMap(0),
00078 countLimit(0), interval_usec(0),
00079 start_usec(0) { };
00080
00081 static U64 getTime()
00082 {
00083 return LLFrameTimer::getTotalTime();
00084 }
00085 };
00086
00087
00088 template< class T >
00089 class LLKeyThrottle
00090 {
00091 public:
00092 LLKeyThrottle(U32 limit, F32 interval)
00093 : m(* new LLKeyThrottleImpl<T>)
00094 {
00095
00096
00097 m.countLimit = limit;
00098 m.interval_usec = (U64)(interval * USEC_PER_SEC);
00099 m.start_usec = LLKeyThrottleImpl<T>::getTime();
00100
00101 m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
00102 m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
00103 }
00104
00105 ~LLKeyThrottle()
00106 {
00107 delete m.prevMap;
00108 delete m.currMap;
00109 delete &m;
00110 }
00111
00112 enum State {
00113 THROTTLE_OK,
00114 THROTTLE_NEWLY_BLOCKED,
00115 THROTTLE_BLOCKED,
00116 };
00117
00118
00119 State noteAction(const T& id, S32 weight = 1)
00120 {
00121 U64 now = LLKeyThrottleImpl<T>::getTime();
00122
00123 if (now >= (m.start_usec + m.interval_usec))
00124 {
00125 if (now < (m.start_usec + 2 * m.interval_usec))
00126 {
00127
00128 delete m.prevMap;
00129 m.prevMap = m.currMap;
00130 m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
00131
00132 m.start_usec += m.interval_usec;
00133 }
00134 else
00135 {
00136
00137 delete m.prevMap;
00138 delete m.currMap;
00139 m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
00140 m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
00141
00142 m.start_usec = now;
00143 }
00144 }
00145
00146 U32 prevCount = 0;
00147 BOOL prevBlocked = FALSE;
00148
00149 typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id);
00150 if (prev != m.prevMap->end())
00151 {
00152 prevCount = prev->second.count;
00153 prevBlocked = prev->second.blocked;
00154 }
00155
00156 typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
00157
00158 bool wereBlocked = curr.blocked || prevBlocked;
00159
00160 curr.count += weight;
00161
00162
00163
00164
00165
00166
00167
00168
00169 F64 timeInCurrent = ((F64)(now - m.start_usec) / m.interval_usec);
00170 F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent);
00171
00172 curr.blocked |= averageCount > m.countLimit;
00173
00174 bool nowBlocked = curr.blocked || prevBlocked;
00175
00176 if (!nowBlocked)
00177 {
00178 return THROTTLE_OK;
00179 }
00180 else if (!wereBlocked)
00181 {
00182 return THROTTLE_NEWLY_BLOCKED;
00183 }
00184 else
00185 {
00186 return THROTTLE_BLOCKED;
00187 }
00188 }
00189
00190
00191 void throttleAction(const T& id)
00192 {
00193 noteAction(id);
00194 typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
00195 curr.count = llmax(m.countLimit, curr.count);
00196 curr.blocked = TRUE;
00197 }
00198
00199
00200 BOOL isThrottled(const T& id) const
00201 {
00202 if (m.currMap->empty()
00203 && m.prevMap->empty())
00204 {
00205
00206 return FALSE;
00207 }
00208
00209
00210
00211
00212
00213
00214 typename LLKeyThrottleImpl<T>::EntryMap::const_iterator entry = m.currMap->find(id);
00215 if (entry != m.currMap->end())
00216 {
00217 return entry->second.blocked;
00218 }
00219 entry = m.prevMap->find(id);
00220 if (entry != m.prevMap->end())
00221 {
00222 return entry->second.blocked;
00223 }
00224 return FALSE;
00225 }
00226
00227 protected:
00228 LLKeyThrottleImpl<T>& m;
00229 };
00230
00231 #endif