llkeythrottle.h
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:9k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llkeythrottle.h
  3.  *
  4.  * $LicenseInfo:firstyear=2005&license=viewergpl$
  5.  * 
  6.  * Copyright (c) 2005-2010, Linden Research, Inc.
  7.  * 
  8.  * Second Life Viewer Source Code
  9.  * The source code in this file ("Source Code") is provided by Linden Lab
  10.  * to you under the terms of the GNU General Public License, version 2.0
  11.  * ("GPL"), unless you have obtained a separate licensing agreement
  12.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  13.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  14.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  15.  * 
  16.  * There are special exceptions to the terms and conditions of the GPL as
  17.  * it is applied to this Source Code. View the full text of the exception
  18.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  19.  * online at
  20.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  21.  * 
  22.  * By copying, modifying or distributing this software, you acknowledge
  23.  * that you have read and understood your obligations described above,
  24.  * and agree to abide by those obligations.
  25.  * 
  26.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  27.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  28.  * COMPLETENESS OR PERFORMANCE.
  29.  * $/LicenseInfo$
  30.  */
  31. #ifndef LL_LLKEY_THROTTLE_H
  32. #define LL_LLKEY_THROTTLE_H
  33. // LLKeyThrottle keeps track of the number of action occurences with a key value
  34. // for a type over a given time period.  If the rate set in the constructor is
  35. // exceeed, the key is considered blocked.  The transition from unblocked to
  36. // blocked is noted so the responsible agent can be informed.  This transition
  37. // takes twice the look back window to clear.
  38. #include "linden_common.h"
  39. #include "llframetimer.h"
  40. #include <map>
  41. // forward declaration so LLKeyThrottleImpl can befriend it
  42. template <class T> class LLKeyThrottle;
  43. // Implementation utility class - use LLKeyThrottle, not this
  44. template <class T>
  45. class LLKeyThrottleImpl
  46. {
  47. friend class LLKeyThrottle<T>;
  48. protected:
  49. struct Entry {
  50. U32 count;
  51. bool blocked;
  52. Entry() : count(0), blocked(false) { }
  53. };
  54. typedef std::map<T, Entry> EntryMap;
  55. EntryMap* prevMap;
  56. EntryMap* currMap;
  57. U32 countLimit;
  58. // maximum number of keys allowed per interval
  59. U64 intervalLength; // each map covers this time period (usec or frame number)
  60. U64 startTime; // start of the time period (usec or frame number)
  61. // currMap started counting at this time
  62. // prevMap covers the previous interval
  63. LLKeyThrottleImpl() :
  64. prevMap(NULL),
  65. currMap(NULL),
  66. countLimit(0),
  67. intervalLength(1),
  68. startTime(0)
  69. {}
  70. static U64 getTime()
  71. {
  72. return LLFrameTimer::getTotalTime();
  73. }
  74. static U64 getFrame() // Return the current frame number
  75. {
  76. return (U64) LLFrameTimer::getFrameCount();
  77. }
  78. };
  79. template< class T >
  80. class LLKeyThrottle
  81. {
  82. public:
  83. // @param realtime = FALSE for frame-based throttle, TRUE for usec
  84. // real-time throttle
  85. LLKeyThrottle(U32 limit, F32 interval, BOOL realtime = TRUE)
  86. : m(* new LLKeyThrottleImpl<T>)
  87. {
  88. setParameters( limit, interval, realtime );
  89. }
  90. ~LLKeyThrottle()
  91. {
  92. delete m.prevMap;
  93. delete m.currMap;
  94. delete &m;
  95. }
  96. enum State {
  97. THROTTLE_OK, // rate not exceeded, let pass
  98. THROTTLE_NEWLY_BLOCKED, // rate exceed for the first time
  99. THROTTLE_BLOCKED, // rate exceed, block key
  100. };
  101. F64 getActionCount(const T& id)
  102. {
  103. U64 now = 0;
  104. if ( mIsRealtime )
  105. {
  106. now = LLKeyThrottleImpl<T>::getTime();
  107. }
  108. else
  109. {
  110. now = LLKeyThrottleImpl<T>::getFrame();
  111. }
  112. if (now >= (m.startTime + m.intervalLength))
  113. {
  114. if (now < (m.startTime + 2 * m.intervalLength))
  115. {
  116. // prune old data
  117. delete m.prevMap;
  118. m.prevMap = m.currMap;
  119. m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
  120. m.startTime += m.intervalLength;
  121. }
  122. else
  123. {
  124. // lots of time has passed, all data is stale
  125. delete m.prevMap;
  126. delete m.currMap;
  127. m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
  128. m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
  129. m.startTime = now;
  130. }
  131. }
  132. U32 prevCount = 0;
  133. typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id);
  134. if (prev != m.prevMap->end())
  135. {
  136. prevCount = prev->second.count;
  137. }
  138. typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
  139. // curr.count is the number of keys in
  140. // this current 'time slice' from the beginning of it until now
  141. // prevCount is the number of keys in the previous
  142. // time slice scaled to be one full time slice back from the current 
  143. // (now) time.
  144. // compute current, windowed rate
  145. F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength);
  146. F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent);
  147. return averageCount;
  148. }
  149. // call each time the key wants use
  150. State noteAction(const T& id, S32 weight = 1)
  151. {
  152. U64 now = 0;
  153. if ( mIsRealtime )
  154. {
  155. now = LLKeyThrottleImpl<T>::getTime();
  156. }
  157. else
  158. {
  159. now = LLKeyThrottleImpl<T>::getFrame();
  160. }
  161. if (now >= (m.startTime + m.intervalLength))
  162. {
  163. if (now < (m.startTime + 2 * m.intervalLength))
  164. {
  165. // prune old data
  166. delete m.prevMap;
  167. m.prevMap = m.currMap;
  168. m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
  169. m.startTime += m.intervalLength;
  170. }
  171. else
  172. {
  173. // lots of time has passed, all data is stale
  174. delete m.prevMap;
  175. delete m.currMap;
  176. m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
  177. m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
  178. m.startTime = now;
  179. }
  180. }
  181. U32 prevCount = 0;
  182. bool prevBlocked = false;
  183. typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id);
  184. if (prev != m.prevMap->end())
  185. {
  186. prevCount = prev->second.count;
  187. prevBlocked = prev->second.blocked;
  188. }
  189. typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
  190. bool wereBlocked = curr.blocked || prevBlocked;
  191. curr.count += weight;
  192. // curr.count is the number of keys in
  193. // this current 'time slice' from the beginning of it until now
  194. // prevCount is the number of keys in the previous
  195. // time slice scaled to be one full time slice back from the current 
  196. // (now) time.
  197. // compute current, windowed rate
  198. F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength);
  199. F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent);
  200. curr.blocked |= averageCount > m.countLimit;
  201. bool nowBlocked = curr.blocked || prevBlocked;
  202. if (!nowBlocked)
  203. {
  204. return THROTTLE_OK;
  205. }
  206. else if (!wereBlocked)
  207. {
  208. return THROTTLE_NEWLY_BLOCKED;
  209. }
  210. else
  211. {
  212. return THROTTLE_BLOCKED;
  213. }
  214. }
  215. // call to force throttle conditions for id
  216. void throttleAction(const T& id)
  217. {
  218. noteAction(id);
  219. typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
  220. curr.count = llmax(m.countLimit, curr.count);
  221. curr.blocked = true;
  222. }
  223. // returns true if key is blocked
  224. bool isThrottled(const T& id) const
  225. {
  226. if (m.currMap->empty()
  227. && m.prevMap->empty())
  228. {
  229. // most of the time we'll fall in here
  230. return false;
  231. }
  232. // NOTE, we ignore the case where id is in the map but the map is stale.  
  233. // You might think that we'd stop throttling things in such a case, 
  234. // however it may be that a god has disabled scripts in the region or 
  235. // estate --> we probably want to report the state of the id when the 
  236. // scripting engine was paused.
  237. typename LLKeyThrottleImpl<T>::EntryMap::const_iterator entry = m.currMap->find(id);
  238. if (entry != m.currMap->end())
  239. {
  240. return entry->second.blocked;
  241. }
  242. entry = m.prevMap->find(id);
  243. if (entry != m.prevMap->end())
  244. {
  245. return entry->second.blocked;
  246. }
  247. return false;
  248. }
  249. // Get the throttling parameters
  250. void getParameters( U32 & out_limit, F32 & out_interval, BOOL & out_realtime )
  251. {
  252. out_limit = m.countLimit;
  253. out_interval = m.intervalLength;
  254. out_realtime = mIsRealtime;
  255. }
  256. // Set the throttling behavior
  257. void setParameters( U32 limit, F32 interval, BOOL realtime = TRUE )
  258. {
  259. // limit is the maximum number of keys
  260. // allowed per interval (in seconds or frames)
  261. mIsRealtime = realtime;
  262. m.countLimit = limit;
  263. if ( mIsRealtime )
  264. {
  265. m.intervalLength = (U64)(interval * USEC_PER_SEC);
  266. m.startTime = LLKeyThrottleImpl<T>::getTime();
  267. }
  268. else
  269. {
  270. m.intervalLength = (U64)interval;
  271. m.startTime = LLKeyThrottleImpl<T>::getFrame();
  272. }
  273. if ( m.intervalLength == 0 )
  274. { // Don't allow zero intervals
  275. m.intervalLength = 1;
  276. }
  277. delete m.prevMap;
  278. m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
  279. delete m.currMap;
  280. m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
  281. }
  282. protected:
  283. LLKeyThrottleImpl<T>& m;
  284. BOOL mIsRealtime; // TRUE to be time based (default), FALSE for frame based
  285. };
  286. #endif